Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /*****************************************************************************\
0002 * (c) Copyright 2022-2023 CERN for the benefit of the LHCb Collaboration      *
0003 *                                                                             *
0004 * This software is distributed under the terms of the GNU General Public      *
0005 * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
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 <GaudiKernel/FunctionalFilterDecision.h>
0016 #include <functional>
0017 #include <optional>
0018 #include <string>
0019 #include <vector>
0020 
0021 namespace Gaudi::Functional {
0022   template <typename Container>
0023   using vector_of_ = std::vector<Container>;
0024   template <typename Container>
0025   using vector_of_optional_ = std::vector<std::optional<Container>>;
0026   using details::vector_of_const_;
0027 
0028   namespace details {
0029 
0030     template <typename Signature, typename Traits_, bool isLegacy>
0031     class SplittingMergingTransformer;
0032 
0033     template <typename Out, typename In, typename Traits_>
0034     class SplittingMergingTransformer<vector_of_<Out>( const vector_of_const_<In>& ), Traits_, false>
0035         : public BaseClass_t<Traits_> {
0036       using base_class = BaseClass_t<Traits_>;
0037       static_assert( std::is_base_of_v<Algorithm, base_class>, "BaseClass must inherit from Algorithm" );
0038 
0039     public:
0040       using KeyValues = std::pair<std::string, std::vector<std::string>>;
0041 
0042       SplittingMergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs,
0043                                    const KeyValues& outputs )
0044           : base_class( std::move( name ), locator )
0045           , m_inputLocations{ this, inputs.first, details::to_DataObjID( inputs.second ),
0046                               [this]( Gaudi::Details::PropertyBase& ) {
0047                                 this->m_inputs =
0048                                     make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
0049                                 if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
0050                                                                // optional flag... so do it
0051                                                                // explicitly here...
0052                                   std::for_each( this->m_inputs.begin(), this->m_inputs.end(),
0053                                                  []( auto& h ) { h.setOptional( true ); } );
0054                                 }
0055                               },
0056                               Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } }
0057           , m_outputLocations(
0058                 this, outputs.first, details::to_DataObjID( outputs.second ),
0059                 [this]( Gaudi::Details::PropertyBase& ) {
0060                   this->m_outputs =
0061                       details::make_vector_of_handles<decltype( this->m_outputs )>( this, m_outputLocations );
0062                   if constexpr ( details::is_optional_v<Out> ) { // handle constructor does not (yet) allow to
0063                                                                  // set optional flag... so
0064                                                                  // do it explicitly here...
0065                     std::for_each( this->m_outputs.begin(), this->m_outputs.end(),
0066                                    []( auto& h ) { h.setOptional( true ); } );
0067                   }
0068                 },
0069                 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } ) {}
0070 
0071       // accessor to output Locations
0072       const std::string& outputLocation( unsigned int n ) const { return m_outputLocations.value()[n].key(); }
0073       unsigned int       outputLocationSize() const { return m_outputLocations.value().size(); }
0074 
0075       // accessor to input Locations
0076       const std::string& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n].key(); }
0077       unsigned int       inputLocationSize() const { return m_inputLocations.value().size(); }
0078 
0079       // derived classes can NOT implement execute
0080       StatusCode execute( const EventContext& ) const override final {
0081         try {
0082           vector_of_const_<In> ins;
0083           ins.reserve( m_inputs.size() );
0084           std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ),
0085                           details2::get_from_handle<In>{} );
0086           // TODO:FIXME: how does operator() know the number and order of expected outputs?
0087           auto out = ( *this )( std::as_const( ins ) );
0088           if ( out.size() != m_outputs.size() ) {
0089             throw GaudiException( "Error during transform: expected " + std::to_string( m_outputs.size() ) +
0090                                       " containers, got " + std::to_string( out.size() ) + " instead",
0091                                   this->name(), StatusCode::FAILURE );
0092           }
0093           for ( unsigned i = 0; i != out.size(); ++i ) details::put( m_outputs[i], std::move( out[i] ) );
0094           return FilterDecision::PASSED;
0095         } catch ( GaudiException& e ) {
0096           if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0097           return e.code();
0098         }
0099       }
0100 
0101       // TODO/FIXME: how does the callee know in which order to produce the outputs?
0102       //             (note: 'missing' items can be specified by making Out an std::optional<Out>,
0103       //              and only those entries which contain an Out are stored)
0104       virtual vector_of_<Out> operator()( const vector_of_const_<In>& ) const = 0;
0105 
0106     private:
0107       // if In is a pointer, it signals optional (as opposed to mandatory) input
0108       template <typename T>
0109       using InputHandle_t = InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0110       std::vector<InputHandle_t<In>>          m_inputs;         //   and make the handles properties instead...
0111       Gaudi::Property<std::vector<DataObjID>> m_inputLocations; // TODO/FIXME: remove this duplication...
0112       // TODO/FIXME: replace vector of DataObjID property + call-back with a
0113       //             vector<handle> property ... as soon as declareProperty can deal with that.
0114       template <typename T>
0115       using OutputHandle = details::OutputHandle_t<Traits_, details::remove_optional_t<T>>;
0116       std::vector<OutputHandle<Out>>          m_outputs;
0117       Gaudi::Property<std::vector<DataObjID>> m_outputLocations; // TODO/FIXME  for now: use a call-back to update the
0118                                                                  // actual handles!
0119     };
0120 
0121   } // namespace details
0122 
0123   template <typename Signature, typename Traits_ = Traits::useDefaults>
0124   using SplittingMergingTransformer =
0125       details::SplittingMergingTransformer<Signature, Traits_, false>; // details::isLegacy<Traits_>>;
0126 
0127 } // namespace Gaudi::Functional