Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:30

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2023 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     struct is_void_fun : std::false_type {};
0042     template <typename... Args>
0043     struct is_void_fun<void( Args... )> : std::true_type {};
0044     template <typename Sig>
0045     inline constexpr bool is_void_fun_v = is_void_fun<Sig>::value;
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{ 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{ 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 <typename Signature, typename Traits_ = Traits::useDefaults,
0238             typename = std::enable_if_t<details::is_void_fun_v<Signature>>>
0239   using MergingConsumer = details::MergingTransformer<Signature, Traits_, details::isLegacy<Traits_>>;
0240 
0241   // M vectors of the same -> N
0242   template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
0243   struct MergingMultiTransformer;
0244 
0245   template <typename... Outs, typename... Ins, typename Traits_>
0246   struct MergingMultiTransformer<std::tuple<Outs...>( vector_of_const_<Ins> const&... ), Traits_>
0247       : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
0248 
0249   private:
0250     using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
0251 
0252   public:
0253     using KeyValue                 = typename base_class::KeyValue;
0254     using KeyValues                = typename base_class::KeyValues;
0255     using InKeys                   = details::RepeatValues_<KeyValues, sizeof...( Ins )>;
0256     using OutKeys                  = details::RepeatValues_<KeyValue, sizeof...( Outs )>;
0257     static constexpr size_t n_args = sizeof...( Ins );
0258 
0259     MergingMultiTransformer( std::string const& name, ISvcLocator* pSvcLocator, InKeys inputs, OutKeys outputs )
0260         : base_class{ name, pSvcLocator, std::move( outputs ) }
0261         , m_inputLocations{ details::for_<n_args>( [&]( auto I ) {
0262           constexpr auto i   = decltype( I )::value;
0263           auto&          ins = std::get<i>( inputs );
0264           return Gaudi::Property<std::vector<DataObjID>>{
0265               this, ins.first, details::to_DataObjID( ins.second ),
0266               [this]( auto&& ) {
0267                 auto& handles = std::get<i>( this->m_inputs );
0268                 auto& ins     = std::get<i>( this->m_inputLocations );
0269                 using In      = typename std::decay_t<decltype( handles )>::value_type;
0270                 handles       = details::make_vector_of_handles<std::decay_t<decltype( handles )>>( this, ins );
0271                 if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
0272                                                // optional flag... so do it
0273                                                // explicitly here...
0274                   std::for_each( handles.begin(), handles.end(), []( auto& h ) { h.setOptional( true ); } );
0275                 }
0276               },
0277               Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } };
0278         } ) } {}
0279 
0280     MergingMultiTransformer( std::string const& name, ISvcLocator* pSvcLocator, KeyValues inputs, OutKeys outputs )
0281         : MergingMultiTransformer{ name, pSvcLocator, InKeys{ std::move( inputs ) }, std::move( outputs ) } {
0282       static_assert( sizeof...( Ins ) == 1 );
0283     }
0284 
0285     // accessor to input Locations
0286     std::string const& inputLocation( unsigned int i, unsigned int j ) const {
0287       return m_inputLocations.at( i ).value().at( j ).key();
0288     }
0289     std::string const& inputLocation( unsigned int j ) const {
0290       static_assert( n_args == 1 );
0291       return inputLocation( 0, j );
0292     }
0293     unsigned int inputLocationSize( int i = 0 ) const { return m_inputLocations.at( i ).value().size(); }
0294 
0295     // derived classes can NOT implement execute
0296     StatusCode execute( EventContext const& ) const override final {
0297       std::tuple<vector_of_const_<Ins>...> inss;
0298       details::for_<sizeof...( Ins )>( [&]( auto I ) {
0299         constexpr size_t i       = decltype( I )::value;
0300         auto&            ins     = std::get<i>( inss );
0301         auto&            handles = std::get<i>( m_inputs );
0302         ins.reserve( handles.size() );
0303         std::transform( handles.begin(), handles.end(), std::back_inserter( ins ),
0304                         details::details2::get_from_handle<typename std::decay_t<decltype( ins )>::value_type>{} );
0305       } );
0306       try {
0307         std::apply(
0308             [&]( auto&... outhandle ) {
0309               GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN
0310               std::apply(
0311                   [&outhandle...]( auto&&... data ) {
0312                     ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
0313                   },
0314                   std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); },
0315                               inss ) );
0316               GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END
0317             },
0318             this->m_outputs );
0319         return FilterDecision::PASSED;
0320       } catch ( GaudiException& e ) {
0321         if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0322         return e.code();
0323       }
0324     }
0325 
0326     virtual std::tuple<Outs...> operator()( const vector_of_const_<Ins>&... inputs ) const = 0;
0327 
0328   private:
0329     // if In is a pointer, it signals optional (as opposed to mandatory) input
0330     template <typename T>
0331     using InputHandle_t = details::InputHandle_t<Traits_, typename std::remove_pointer<T>::type>;
0332     std::tuple<std::vector<InputHandle_t<Ins>>...> m_inputs; //   and make the handles properties instead...
0333     std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations; // TODO/FIXME: remove this
0334                                                                                             // duplication...
0335     // TODO/FIXME: replace vector of string property + call-back with a
0336     //             vector<handle> property ... as soon as declareProperty can deal with that.
0337   };
0338 
0339   // Many of the same -> N with filter functionality
0340   template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
0341   struct MergingMultiTransformerFilter;
0342 
0343   template <typename... Outs, typename In, typename Traits_>
0344   struct MergingMultiTransformerFilter<std::tuple<Outs...>( vector_of_const_<In> const& ), Traits_>
0345       : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
0346 
0347   private:
0348     using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
0349 
0350   public:
0351     using KeyValue  = typename base_class::KeyValue;
0352     using KeyValues = typename base_class::KeyValues;
0353     using OutKeys   = details::RepeatValues_<KeyValue, sizeof...( Outs )>;
0354 
0355     MergingMultiTransformerFilter( std::string const& name, ISvcLocator* locator, KeyValues const& inputs,
0356                                    OutKeys const& outputs );
0357 
0358     // accessor to input Locations
0359     std::string const& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n].key(); }
0360     unsigned int       inputLocationSize() const { return m_inputLocations.value().size(); }
0361 
0362     // derived classes can NOT implement execute
0363     StatusCode execute( EventContext const& ) const override final {
0364       vector_of_const_<In> ins;
0365       ins.reserve( m_inputs.size() );
0366       std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ),
0367                       details::details2::get_from_handle<In>{} );
0368       try {
0369         return std::apply(
0370                    [&]( auto&... outhandle ) {
0371                      GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN
0372                      return std::apply(
0373                          [&outhandle...]( bool passed, auto&&... data ) {
0374                            ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
0375                            return passed;
0376                          },
0377                          ( *this )( std::as_const( ins ) ) );
0378                      GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END
0379                    },
0380                    this->m_outputs )
0381                    ? FilterDecision::PASSED
0382                    : FilterDecision::FAILED;
0383       } catch ( GaudiException& e ) {
0384         if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0385         return e.code();
0386       }
0387     }
0388 
0389     virtual std::tuple<bool, Outs...> operator()( const vector_of_const_<In>& inputs ) const = 0;
0390 
0391   private:
0392     // if In is a pointer, it signals optional (as opposed to mandatory) input
0393     template <typename T>
0394     using InputHandle_t = details::InputHandle_t<Traits_, typename std::remove_pointer<T>::type>;
0395     std::vector<InputHandle_t<In>>          m_inputs;         //   and make the handles properties instead...
0396     Gaudi::Property<std::vector<DataObjID>> m_inputLocations; // TODO/FIXME: remove this duplication...
0397     // TODO/FIXME: replace vector of string property + call-back with a
0398     //             vector<handle> property ... as soon as declareProperty can deal with that.
0399   };
0400 
0401   template <typename... Outs, typename In, typename Traits_>
0402   MergingMultiTransformerFilter<std::tuple<Outs...>( const vector_of_const_<In>& ),
0403                                 Traits_>::MergingMultiTransformerFilter( std::string const& name,
0404                                                                          ISvcLocator*       pSvcLocator,
0405                                                                          KeyValues const&   inputs,
0406                                                                          OutKeys const&     outputs )
0407       : base_class( name, pSvcLocator, outputs )
0408       , m_inputLocations{
0409             this, inputs.first, details::to_DataObjID( inputs.second ),
0410             [this]( Gaudi::Details::PropertyBase& ) {
0411               this->m_inputs = details::make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
0412               if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
0413                                              // optional flag... so do it
0414                                              // explicitly here...
0415                 std::for_each( this->m_inputs.begin(), this->m_inputs.end(), []( auto& h ) { h.setOptional( true ); } );
0416               }
0417             },
0418             Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } } {}
0419 
0420 } // namespace Gaudi::Functional