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 <GaudiKernel/FunctionalFilterDecision.h>
0016 #include <functional>
0017 #include <optional>
0018 #include <string>
0019 #include <vector>
0020 
0021 namespace Gaudi::Functional {
0022 
0023   template <typename Container>
0024   using vector_of_ = std::vector<Container>;
0025   template <typename Container>
0026   using vector_of_optional_ = std::vector<std::optional<Container>>;
0027 
0028   namespace details {
0029 
0030     template <typename Signature, typename Traits_, bool isLegacy>
0031     class SplittingTransformer;
0032 
0033     ////// N -> Many of the same one (value of Many not known at compile time, but known at configuration time)
0034     template <typename Out, typename... In, typename Traits_>
0035     class SplittingTransformer<vector_of_<Out>( const In&... ), Traits_, true>
0036         : public details::DataHandleMixin<std::tuple<>, filter_evtcontext<In...>, Traits_> {
0037       using base_class = details::DataHandleMixin<std::tuple<>, filter_evtcontext<In...>, Traits_>;
0038 
0039     public:
0040       constexpr static std::size_t N = base_class::N_in;
0041       using KeyValue                 = typename base_class::KeyValue;
0042       using KeyValues                = typename base_class::KeyValues;
0043 
0044       SplittingTransformer( std::string name, ISvcLocator* locator, const RepeatValues_<KeyValue, N>& inputs,
0045                             const KeyValues& outputs )
0046           : base_class( std::move( name ), locator, inputs )
0047           , m_outputLocations(
0048                 this, outputs.first, details::to_DataObjID( outputs.second ),
0049                 [this]( Gaudi::Details::PropertyBase& ) {
0050                   this->m_outputs =
0051                       details::make_vector_of_handles<decltype( this->m_outputs )>( this, m_outputLocations );
0052                   if constexpr ( details::is_optional_v<Out> ) { // handle constructor does not (yet) allow to
0053                                                                  // set optional flag... so
0054                                                                  // do it explicitly here...
0055                     std::for_each( this->m_outputs.begin(), this->m_outputs.end(),
0056                                    []( auto& h ) { h.setOptional( true ); } );
0057                   }
0058                 },
0059                 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } ) {}
0060 
0061       SplittingTransformer( std::string name, ISvcLocator* locator, const KeyValue& input, const KeyValues& output )
0062           : SplittingTransformer( std::move( name ), locator, std::forward_as_tuple( input ), output ) {
0063         static_assert( N == 1, "single input argument requires single input signature" );
0064       }
0065 
0066       // accessor to output Locations
0067       const std::string& outputLocation( unsigned int n ) const { return m_outputLocations.value()[n].key(); }
0068       unsigned int       outputLocationSize() const { return m_outputLocations.value().size(); }
0069 
0070       // derived classes can NOT implement execute
0071       StatusCode execute() override final {
0072         try {
0073           // TODO:FIXME: how does operator() know the number and order of expected outputs?
0074           auto out = details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs );
0075           if ( out.size() != m_outputs.size() ) {
0076             throw GaudiException( "Error during transform: expected " + std::to_string( m_outputs.size() ) +
0077                                       " containers, got " + std::to_string( out.size() ) + " instead",
0078                                   this->name(), StatusCode::FAILURE );
0079           }
0080           for ( unsigned i = 0; i != out.size(); ++i ) details::put( m_outputs[i], std::move( out[i] ) );
0081           return FilterDecision::PASSED;
0082         } catch ( GaudiException& e ) {
0083           if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0084           return e.code();
0085         }
0086       }
0087 
0088       // TODO/FIXME: how does the callee know in which order to produce the outputs?
0089       //             (note: 'missing' items can be specified by making Out an std::optional<Out>,
0090       //              and only those entries which contain an Out are stored)
0091       virtual vector_of_<Out> operator()( const In&... ) const = 0;
0092 
0093     private:
0094       template <typename T>
0095       using OutputHandle = details::OutputHandle_t<Traits_, details::remove_optional_t<T>>;
0096       std::vector<OutputHandle<Out>>          m_outputs;
0097       Gaudi::Property<std::vector<DataObjID>> m_outputLocations; // TODO/FIXME  for now: use a call-back to update the
0098                                                                  // actual handles!
0099     };
0100 
0101     template <typename Out, typename... In, typename Traits_>
0102     class SplittingTransformer<vector_of_<Out>( const In&... ), Traits_, false>
0103         : public details::DataHandleMixin<std::tuple<>, filter_evtcontext<In...>, Traits_> {
0104       using base_class = details::DataHandleMixin<std::tuple<>, filter_evtcontext<In...>, Traits_>;
0105 
0106     public:
0107       constexpr static std::size_t N = base_class::N_in;
0108       using KeyValue                 = typename base_class::KeyValue;
0109       using KeyValues                = typename base_class::KeyValues;
0110 
0111       SplittingTransformer( std::string name, ISvcLocator* locator, const RepeatValues_<KeyValue, N>& inputs,
0112                             const KeyValues& outputs )
0113           : base_class( std::move( name ), locator, inputs )
0114           , m_outputLocations(
0115                 this, outputs.first, details::to_DataObjID( outputs.second ),
0116                 [this]( Gaudi::Details::PropertyBase& ) {
0117                   this->m_outputs =
0118                       details::make_vector_of_handles<decltype( this->m_outputs )>( this, m_outputLocations );
0119                   if constexpr ( details::is_optional_v<Out> ) { // handle constructor does not (yet) allow to
0120                                                                  // set optional flag... so
0121                                                                  // do it explicitly here...
0122                     std::for_each( this->m_outputs.begin(), this->m_outputs.end(),
0123                                    []( auto& h ) { h.setOptional( true ); } );
0124                   }
0125                 },
0126                 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } ) {}
0127 
0128       SplittingTransformer( std::string name, ISvcLocator* locator, const KeyValue& input, const KeyValues& output )
0129           : SplittingTransformer( std::move( name ), locator, std::forward_as_tuple( input ), output ) {
0130         static_assert( N == 1, "single input argument requires single input signature" );
0131       }
0132 
0133       // accessor to output Locations
0134       const std::string& outputLocation( unsigned int n ) const { return m_outputLocations.value()[n].key(); }
0135       unsigned int       outputLocationSize() const { return m_outputLocations.value().size(); }
0136 
0137       // derived classes can NOT implement execute
0138       StatusCode execute( const EventContext& ctx ) const override final {
0139         try {
0140           // TODO:FIXME: how does operator() know the number and order of expected outputs?
0141           auto out = details::filter_evtcontext_t<In...>::apply( *this, ctx, this->m_inputs );
0142           if ( out.size() != m_outputs.size() ) {
0143             throw GaudiException( "Error during transform: expected " + std::to_string( m_outputs.size() ) +
0144                                       " containers, got " + std::to_string( out.size() ) + " instead",
0145                                   this->name(), StatusCode::FAILURE );
0146           }
0147           for ( unsigned i = 0; i != out.size(); ++i ) details::put( m_outputs[i], std::move( out[i] ) );
0148           return FilterDecision::PASSED;
0149         } catch ( GaudiException& e ) {
0150           if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0151           return e.code();
0152         }
0153       }
0154 
0155       // TODO/FIXME: how does the callee know in which order to produce the outputs?
0156       //             (note: 'missing' items can be specified by making Out an std::optional<Out>,
0157       //              and only those entries which contain an Out are stored)
0158       virtual vector_of_<Out> operator()( const In&... ) const = 0;
0159 
0160     private:
0161       template <typename T>
0162       using OutputHandle = details::OutputHandle_t<Traits_, details::remove_optional_t<T>>;
0163       std::vector<OutputHandle<Out>>          m_outputs;
0164       Gaudi::Property<std::vector<DataObjID>> m_outputLocations; // TODO/FIXME  for now: use a call-back to update the
0165                                                                  // actual handles!
0166     };
0167 
0168   } // namespace details
0169 
0170   template <typename Signature, typename Traits_ = Traits::useDefaults>
0171   using SplittingTransformer = details::SplittingTransformer<Signature, Traits_, details::isLegacy<Traits_>>;
0172 
0173 } // namespace Gaudi::Functional