File indexing completed on 2025-09-13 08:56:39
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #pragma once
0012
0013 #include <Gaudi/Algorithm.h>
0014 #include <GaudiKernel/Algorithm.h>
0015 #include <GaudiKernel/DataObjectHandle.h>
0016 #include <GaudiKernel/GaudiException.h>
0017 #include <GaudiKernel/IBinder.h>
0018 #include <GaudiKernel/ThreadLocalContext.h>
0019 #include <GaudiKernel/detected.h>
0020 #include <cassert>
0021 #include <range/v3/version.hpp>
0022 #include <range/v3/view/const.hpp>
0023 #include <range/v3/view/zip.hpp>
0024 #include <sstream>
0025 #include <type_traits>
0026
0027
0028 #if RANGE_V3_VERSION < 900
0029 namespace ranges::views {
0030 using namespace ranges::view;
0031 }
0032 #endif
0033
0034 #if defined( __clang__ ) && ( __clang_major__ < 11 ) || defined( __APPLE__ ) && ( __clang_major__ < 12 )
0035 # define GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN \
0036 _Pragma( "clang diagnostic push" ) _Pragma( "clang diagnostic ignored \"-Wunused-lambda-capture\"" )
0037 # define GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END _Pragma( "clang diagnostic pop" )
0038 #else
0039 # define GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN
0040 # define GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END
0041 #endif
0042
0043
0044
0045 #define GAUDI_FUNCTIONAL_CONSTRUCTOR_USES_TUPLE
0046
0047 namespace Gaudi::Functional::details {
0048
0049
0050 namespace zip {
0051
0052
0053 template <typename OS, typename Arg>
0054 void printSizes( OS& out, Arg&& arg ) {
0055 out << "SizeOf'" << System::typeinfoName( typeid( Arg ) ) << "'=" << std::forward<Arg>( arg ).size();
0056 }
0057
0058
0059 template <typename OS, typename Arg, typename... Args>
0060 void printSizes( OS& out, Arg&& arg, Args&&... args ) {
0061 printSizes( out, arg );
0062 out << ", ";
0063 printSizes( out, args... );
0064 }
0065
0066
0067 template <typename A>
0068 inline bool check_sizes( const A& ) noexcept {
0069 return true;
0070 }
0071
0072
0073 template <typename A, typename B>
0074 inline bool check_sizes( const A& a, const B& b ) noexcept {
0075 return a.size() == b.size();
0076 }
0077
0078
0079 template <typename A, typename B, typename... C>
0080 inline bool check_sizes( const A& a, const B& b, const C&... c ) noexcept {
0081 return ( check_sizes( a, b ) && check_sizes( b, c... ) );
0082 }
0083
0084
0085 template <typename... Args>
0086 inline decltype( auto ) verifySizes( Args&... args ) {
0087 if ( !check_sizes( args... ) ) {
0088 std::ostringstream mess;
0089 mess << "Zipped containers have different sizes : ";
0090 printSizes( mess, args... );
0091 throw GaudiException( mess.str(), "Gaudi::Functional::details::zip::verifySizes", StatusCode::FAILURE );
0092 }
0093 }
0094
0095
0096 template <typename... Args>
0097 inline decltype( auto ) range( Args&&... args ) {
0098 #ifndef NDEBUG
0099 verifySizes( args... );
0100 #endif
0101 return ranges::views::zip( std::forward<Args>( args )... );
0102 }
0103
0104
0105 template <typename... Args>
0106 inline decltype( auto ) const_range( Args&&... args ) {
0107 #ifndef NDEBUG
0108 verifySizes( args... );
0109 #endif
0110 return ranges::views::const_( ranges::views::zip( std::forward<Args>( args )... ) );
0111 }
0112 }
0113
0114 inline std::vector<DataObjID> to_DataObjID( const std::vector<std::string>& in ) {
0115 std::vector<DataObjID> out;
0116 out.reserve( in.size() );
0117 std::transform( in.begin(), in.end(), std::back_inserter( out ),
0118 []( const std::string& i ) { return DataObjID{ i }; } );
0119 return out;
0120 }
0121
0122
0123 namespace details2 {
0124 template <typename T>
0125 using is_optional_ = decltype( std::declval<T>().has_value(), std::declval<T>().value() );
0126
0127 template <typename T>
0128 using value_type_of_t = typename T::value_type;
0129
0130 }
0131 template <typename Arg>
0132 constexpr bool is_optional_v = Gaudi::cpp17::is_detected_v<details2::is_optional_, Arg>;
0133
0134 template <typename T>
0135 using remove_optional_t =
0136 std::conditional_t<is_optional_v<T>, Gaudi::cpp17::detected_t<details2::value_type_of_t, T>, T>;
0137
0138 constexpr struct invoke_optionally_t {
0139 template <typename F, typename Arg>
0140 requires( !is_optional_v<Arg> )
0141 decltype( auto ) operator()( F&& f, Arg&& arg ) const {
0142 return std::invoke( std::forward<F>( f ), std::forward<Arg>( arg ) );
0143 }
0144 template <typename F, typename Arg>
0145 requires( is_optional_v<Arg> )
0146 void operator()( F&& f, Arg&& arg ) const {
0147 if ( arg ) std::invoke( std::forward<F>( f ), *std::forward<Arg>( arg ) );
0148 }
0149 } invoke_optionally{};
0150
0151
0152 template <typename Value, std::size_t... I>
0153 auto get_values_helper( std::index_sequence<I...> ) {
0154 return std::make_tuple( ( (void)I, Value{} )... );
0155 }
0156
0157 template <typename Value, auto N>
0158 using RepeatValues_ = decltype( get_values_helper<Value>( std::make_index_sequence<N>() ) );
0159
0160
0161 template <std::derived_from<DataObject> Out1, std::convertible_to<Out1> Out2>
0162 auto put( const DataObjectHandle<Out1>& out_handle, Out2&& out ) {
0163 return out_handle.put( std::make_unique<Out1>( std::forward<Out2>( out ) ) );
0164 }
0165
0166 template <typename Out1, std::convertible_to<Out1> Out2>
0167 auto put( const DataObjectHandle<AnyDataWrapper<Out1>>& out_handle, Out2&& out ) {
0168 return out_handle.put( std::forward<Out2>( out ) );
0169 }
0170
0171
0172 template <typename OutHandle, typename OptOut>
0173 requires( is_optional_v<OptOut> )
0174 void put( const OutHandle& out_handle, OptOut&& out ) {
0175 if ( out ) put( out_handle, *std::forward<OptOut>( out ) );
0176 }
0177
0178
0179
0180
0181
0182
0183 constexpr struct insert_t {
0184
0185 template <typename Container>
0186 using c_remove_ptr_t = std::remove_pointer_t<typename Container::value_type>;
0187
0188 template <typename Container, typename Value>
0189 auto operator()( Container& c, Value&& v ) const -> decltype( c.push_back( v ) ) {
0190 return c.push_back( std::forward<Value>( v ) );
0191 }
0192
0193 template <typename Container, typename Value>
0194 auto operator()( Container& c, Value&& v ) const -> decltype( c.insert( v ) ) {
0195 return c.insert( std::forward<Value>( v ) );
0196 }
0197
0198
0199 template <typename Container, typename Value>
0200 requires( std::is_pointer_v<typename Container::value_type> &&
0201 std::is_convertible_v<Value, c_remove_ptr_t<Container>> )
0202 auto operator()( Container& c, Value&& v ) const {
0203 return operator()( c, new c_remove_ptr_t<Container>{ std::forward<Value>( v ) } );
0204 }
0205
0206 } insert{};
0207
0208
0209
0210 constexpr struct deref_t {
0211 template <typename In>
0212 requires( !std::is_pointer_v<In> )
0213 const In& operator()( const In& in ) const {
0214 return in;
0215 }
0216
0217 template <typename In>
0218 requires( !std::is_pointer_v<std::decay_t<In>> )
0219 In operator()( In&& in ) const {
0220 return std::forward<In>( in );
0221 }
0222
0223 template <typename In>
0224 const In& operator()( const In* in ) const {
0225 assert( in != nullptr );
0226 return *in;
0227 }
0228 } deref{};
0229
0230
0231
0232 namespace details2 {
0233 template <typename T>
0234 constexpr static bool is_gaudi_range_v = false;
0235
0236 template <typename T>
0237 constexpr static bool is_gaudi_range_v<Gaudi::Range_<T>> = true;
0238
0239 template <typename T>
0240 constexpr static bool is_gaudi_range_v<Gaudi::NamedRange_<T>> = true;
0241
0242 template <typename T>
0243 constexpr static bool is_gaudi_range_v<std::optional<Gaudi::NamedRange_<T>>> = true;
0244
0245 template <typename Container, typename Value>
0246 void push_back( Container& c, const Value& v, std::true_type ) {
0247 c.push_back( v );
0248 }
0249 template <typename Container, typename Value>
0250 void push_back( Container& c, const Value& v, std::false_type ) {
0251 c.push_back( &v );
0252 }
0253
0254 template <typename In>
0255 struct get_from_handle {
0256 template <template <typename> class Handle, std::convertible_to<In> I>
0257 auto operator()( const Handle<I>& h ) -> const In& {
0258 return *h.get();
0259 }
0260 template <template <typename> class Handle, typename I>
0261 auto operator()( const Handle<Gaudi::Range_<I>>& h ) -> const In {
0262 return h.get();
0263 }
0264 template <template <typename> class Handle, typename I>
0265 auto operator()( const Handle<Gaudi::NamedRange_<I>>& h ) -> const In {
0266 return h.get();
0267 }
0268 template <template <typename> class Handle, typename I>
0269 auto operator()( const Handle<std::optional<Gaudi::NamedRange_<I>>>& h ) -> const In {
0270 return h.get();
0271 }
0272 template <template <typename> class Handle, typename I>
0273 requires( std::is_convertible_v<I*, In> )
0274 auto operator()( const Handle<I>& h ) -> const In {
0275 return h.getIfExists();
0276 }
0277 };
0278
0279 template <typename T>
0280 T* deref_if( T* const t, std::false_type ) {
0281 return t;
0282 }
0283 template <typename T>
0284 T& deref_if( T* const t, std::true_type ) {
0285 return *t;
0286 }
0287 }
0288
0289 template <typename Container>
0290 class vector_of_const_ {
0291 static constexpr bool is_pointer = std::is_pointer_v<Container>;
0292 static constexpr bool is_range = details2::is_gaudi_range_v<Container>;
0293 using val_t = std::add_const_t<std::remove_pointer_t<Container>>;
0294 using ptr_t = std::add_pointer_t<val_t>;
0295 using ref_t = std::add_lvalue_reference_t<val_t>;
0296 using ContainerVector = std::vector<std::conditional_t<is_range, std::remove_const_t<val_t>, ptr_t>>;
0297 ContainerVector m_containers;
0298
0299 public:
0300 using value_type = std::conditional_t<is_pointer, ptr_t, val_t>;
0301 using size_type = typename ContainerVector::size_type;
0302 class iterator {
0303 using it_t = typename ContainerVector::const_iterator;
0304 it_t m_i;
0305 friend class vector_of_const_;
0306 iterator( it_t iter ) : m_i( iter ) {}
0307 using ret_t = std::conditional_t<is_pointer, ptr_t, ref_t>;
0308
0309 public:
0310 using iterator_category = typename it_t::iterator_category;
0311 using value_type = typename it_t::iterator_category;
0312 using reference = typename it_t::reference;
0313 using pointer = typename it_t::pointer;
0314 using difference_type = typename it_t::difference_type;
0315
0316 friend bool operator!=( const iterator& lhs, const iterator& rhs ) { return lhs.m_i != rhs.m_i; }
0317 friend bool operator==( const iterator& lhs, const iterator& rhs ) { return lhs.m_i == rhs.m_i; }
0318 friend auto operator-( const iterator& lhs, const iterator& rhs ) { return lhs.m_i - rhs.m_i; }
0319 ret_t operator*() const {
0320 if constexpr ( is_range ) {
0321 return *m_i;
0322 } else {
0323 return details2::deref_if( *m_i, std::bool_constant<!is_pointer>{} );
0324 }
0325 }
0326 iterator& operator++() {
0327 ++m_i;
0328 return *this;
0329 }
0330 iterator& operator--() {
0331 --m_i;
0332 return *this;
0333 }
0334 bool is_null() const { return !*m_i; }
0335 explicit operator bool() const { return !is_null(); }
0336 };
0337 vector_of_const_() = default;
0338 void reserve( size_type size ) { m_containers.reserve( size ); }
0339 template <typename T>
0340 void push_back( T&& container ) {
0341 details2::push_back( m_containers, std::forward<T>( container ),
0342 std::bool_constant < is_pointer || is_range > {} );
0343 }
0344 iterator begin() const { return m_containers.begin(); }
0345 iterator end() const { return m_containers.end(); }
0346 size_type size() const { return m_containers.size(); }
0347
0348 template <typename X = Container>
0349 requires( !std::is_pointer_v<X> )
0350 ref_t front() const {
0351 return *m_containers.front();
0352 }
0353
0354 template <typename X = Container>
0355 requires( std::is_pointer_v<X> )
0356 ptr_t front() const {
0357 return m_containers.front();
0358 }
0359
0360 template <typename X = Container>
0361 requires( !std::is_pointer_v<X> )
0362 ref_t back() const {
0363 return *m_containers.back();
0364 }
0365
0366 template <typename X = Container>
0367 requires( std::is_pointer_v<X> )
0368 ptr_t back() const {
0369 return m_containers.back();
0370 }
0371
0372 template <typename X = Container>
0373 requires( !std::is_pointer_v<X> )
0374 ref_t operator[]( size_type i ) const {
0375 return *m_containers[i];
0376 }
0377
0378 template <typename X = Container>
0379 requires( std::is_pointer_v<X> )
0380 ptr_t operator[]( size_type i ) const {
0381 return m_containers[i];
0382 }
0383
0384 template <typename X = Container>
0385 requires( !std::is_pointer_v<X> )
0386 ref_t at( size_type i ) const {
0387 return *m_containers[i];
0388 }
0389
0390 template <typename X = Container>
0391 requires( std::is_pointer_v<X> )
0392 ptr_t at( size_type i ) const {
0393 return m_containers[i];
0394 }
0395
0396 bool is_null( size_type i ) const { return !m_containers[i]; }
0397 };
0398
0399
0400 namespace detail2 {
0401 template <typename Tr>
0402 using BaseClass_t = typename Tr::BaseClass;
0403 template <typename Tr, typename T>
0404 using OutputHandle_t = typename Tr::template OutputHandle<T>;
0405 template <typename Tr, typename T>
0406 using InputHandle_t = typename Tr::template InputHandle<T>;
0407
0408 template <typename T>
0409 constexpr auto is_tool_v = std::is_base_of_v<IAlgTool, std::decay_t<T>>;
0410
0411 template <typename T>
0412 using ToolHandle_t = ToolHandle<Gaudi::Interface::Bind::IBinder<std::decay_t<T>>>;
0413
0414 template <typename T>
0415 using DefaultInputHandle = std::conditional_t<is_tool_v<T>, ToolHandle_t<T>, DataObjectReadHandle<T>>;
0416 }
0417
0418
0419
0420
0421 template <typename Tr, typename Base = Gaudi::Algorithm>
0422 using BaseClass_t = Gaudi::cpp17::detected_or_t<Base, detail2::BaseClass_t, Tr>;
0423
0424
0425
0426
0427
0428 template <typename Tr, typename T>
0429 using OutputHandle_t = Gaudi::cpp17::detected_or_t<DataObjectWriteHandle<T>, detail2::OutputHandle_t, Tr, T>;
0430 template <typename Tr, typename T>
0431 using InputHandle_t = Gaudi::cpp17::detected_or_t<detail2::DefaultInputHandle<T>, detail2::InputHandle_t, Tr, T>;
0432
0433 template <typename Traits>
0434 inline constexpr bool isLegacy =
0435 std::is_base_of_v<Gaudi::details::LegacyAlgorithmAdapter, details::BaseClass_t<Traits>>;
0436
0437
0438 #define GAUDI_FUNCTIONAL_MAKE_VECTOR_OF_HANDLES_USES_DATAOBJID
0439
0440 template <typename Handles>
0441 Handles make_vector_of_handles( IDataHandleHolder* owner, const std::vector<DataObjID>& init ) {
0442 Handles handles;
0443 handles.reserve( init.size() );
0444 std::transform( init.begin(), init.end(), std::back_inserter( handles ),
0445 [&]( const auto& loc ) -> typename Handles::value_type {
0446 return { loc, owner };
0447 } );
0448 return handles;
0449 }
0450
0451 template <typename Handle, typename Algo>
0452 auto get( const Handle& handle, const Algo&, const EventContext& )
0453 -> decltype( details::deref( handle.get() ) )
0454 {
0455 return details::deref( handle.get() );
0456 }
0457
0458 template <typename IFace, typename Algo>
0459 auto get( const ToolHandle<Gaudi::Interface::Bind::IBinder<IFace>>& handle, const Algo&, const EventContext& ctx ) {
0460 return handle.bind( ctx );
0461 }
0462
0463 template <typename Handle>
0464 auto getKey( const Handle& h ) -> decltype( h.objKey() ) {
0465 return h.objKey();
0466 }
0467
0468
0469
0470 template <typename... In>
0471 struct filter_evtcontext_t {
0472 using type = std::tuple<In...>;
0473
0474 static_assert( !std::disjunction_v<std::is_same<EventContext, In>...>,
0475 "EventContext can only appear as first argument" );
0476
0477 template <typename Algorithm, typename Handles>
0478 static auto apply( const Algorithm& algo, Handles& handles ) {
0479 return std::apply(
0480 [&]( const auto&... handle ) { return algo( get( handle, algo, Gaudi::Hive::currentContext() )... ); },
0481 handles );
0482 }
0483 template <typename Algorithm, typename Handles>
0484 static auto apply( const Algorithm& algo, const EventContext& ctx, Handles& handles ) {
0485 return std::apply( [&]( const auto&... handle ) { return algo( get( handle, algo, ctx )... ); }, handles );
0486 }
0487 };
0488
0489
0490 template <typename... In>
0491 struct filter_evtcontext_t<EventContext, In...> {
0492 using type = std::tuple<In...>;
0493
0494 static_assert( !std::disjunction_v<std::is_same<EventContext, In>...>,
0495 "EventContext can only appear as first argument" );
0496
0497 template <typename Algorithm, typename Handles>
0498 static auto apply( const Algorithm& algo, const EventContext& ctx, Handles& handles ) {
0499 return std::apply( [&]( const auto&... handle ) { return algo( ctx, get( handle, algo, ctx )... ); }, handles );
0500 }
0501
0502 template <typename Algorithm, typename Handles>
0503 static auto apply( const Algorithm& algo, Handles& handles ) {
0504 return apply( algo, Gaudi::Hive::currentContext(), handles );
0505 }
0506 };
0507
0508 template <typename... In>
0509 using filter_evtcontext = typename filter_evtcontext_t<In...>::type;
0510
0511 template <typename OutputSpec, typename InputSpec, typename Traits_>
0512 class DataHandleMixin;
0513
0514 template <typename Out, typename In, typename Tr>
0515 void updateHandleLocation( DataHandleMixin<Out, In, Tr>& parent, const std::string& prop,
0516 const std::string& newLoc ) {
0517 auto sc = parent.setProperty( prop, newLoc );
0518 if ( sc.isFailure() ) throw GaudiException( "Could not set Property", prop + " -> " + newLoc, sc );
0519 }
0520
0521 template <typename Out, typename In, typename Tr>
0522 void updateHandleLocations( DataHandleMixin<Out, In, Tr>& parent, const std::string& prop,
0523 const std::vector<std::string>& newLocs ) {
0524 std::ostringstream ss;
0525 GaudiUtils::details::ostream_joiner( ss << '[', newLocs, ", ", []( std::ostream& os, const auto& i ) -> auto& {
0526 return os << "'" << i << "'";
0527 } ) << ']';
0528 auto sc = parent.setProperty( prop, ss.str() );
0529 if ( sc.isFailure() ) throw GaudiException( "Could not set Property", prop + " -> " + ss.str(), sc );
0530 }
0531
0532 template <typename... Out, typename... In, typename Traits_>
0533 class DataHandleMixin<std::tuple<Out...>, std::tuple<In...>, Traits_> : public BaseClass_t<Traits_> {
0534 static_assert( std::is_base_of_v<Algorithm, BaseClass_t<Traits_>>, "BaseClass must inherit from Algorithm" );
0535
0536 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0537 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, const IArgs& inputs, std::index_sequence<I...>,
0538 const OArgs& outputs, std::index_sequence<J...> )
0539 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator )
0540 , m_inputs( std::tuple_cat( std::forward_as_tuple( this ), std::get<I>( inputs ) )... )
0541 , m_outputs( std::tuple_cat( std::forward_as_tuple( this ), std::get<J>( outputs ) )... ) {
0542
0543 this->setProperty( "Cardinality", 0 ).ignore();
0544 }
0545
0546 public:
0547 constexpr static std::size_t N_in = sizeof...( In );
0548 constexpr static std::size_t N_out = sizeof...( Out );
0549
0550 using KeyValue = std::pair<std::string, std::string>;
0551 using KeyValues = std::pair<std::string, std::vector<std::string>>;
0552
0553
0554 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, RepeatValues_<KeyValue, N_in> const& inputs,
0555 RepeatValues_<KeyValue, N_out> const& outputs )
0556 : DataHandleMixin( std::move( name ), pSvcLocator, inputs, std::index_sequence_for<In...>{}, outputs,
0557 std::index_sequence_for<Out...>{} ) {}
0558
0559
0560
0561 DataHandleMixin( std::string name, ISvcLocator* locator, const KeyValue& input, const KeyValue& output )
0562 : DataHandleMixin( std::move( name ), locator, std::forward_as_tuple( input ),
0563 std::forward_as_tuple( output ) ) {}
0564
0565 DataHandleMixin( std::string name, ISvcLocator* locator, const KeyValue& input,
0566 RepeatValues_<KeyValue, N_out> const& outputs )
0567 : DataHandleMixin( std::move( name ), locator, std::forward_as_tuple( input ), outputs ) {}
0568
0569 DataHandleMixin( std::string name, ISvcLocator* locator, RepeatValues_<KeyValue, N_in> const& inputs,
0570 const KeyValue& output )
0571 : DataHandleMixin( std::move( name ), locator, inputs, std::forward_as_tuple( output ) ) {}
0572
0573 template <std::size_t N = 0>
0574 decltype( auto ) inputLocation() const {
0575 return getKey( std::get<N>( m_inputs ) );
0576 }
0577 template <typename T>
0578 decltype( auto ) inputLocation() const {
0579 return getKey( std::get<details::InputHandle_t<Traits_, std::decay_t<T>>>( m_inputs ) );
0580 }
0581 constexpr unsigned int inputLocationSize() const { return N_in; }
0582
0583 template <std::size_t N = 0>
0584 decltype( auto ) outputLocation() const {
0585 return getKey( std::get<N>( m_outputs ) );
0586 }
0587 template <typename T>
0588 decltype( auto ) outputLocation() const {
0589 return getKey( std::get<details::OutputHandle_t<Traits_, std::decay_t<T>>>( m_outputs ) );
0590 }
0591 constexpr unsigned int outputLocationSize() const { return N_out; }
0592
0593 protected:
0594 bool isReEntrant() const override { return true; }
0595
0596 std::tuple<details::InputHandle_t<Traits_, In>...> m_inputs;
0597 std::tuple<details::OutputHandle_t<Traits_, Out>...> m_outputs;
0598 };
0599
0600 template <typename Traits_>
0601 class DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> : public BaseClass_t<Traits_> {
0602 static_assert( std::is_base_of_v<Algorithm, BaseClass_t<Traits_>>, "BaseClass must inherit from Algorithm" );
0603
0604 public:
0605 using KeyValue = std::pair<std::string, std::string>;
0606 using KeyValues = std::pair<std::string, std::vector<std::string>>;
0607 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, std::tuple<> = {}, std::tuple<> = {} )
0608 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator ) {
0609
0610 this->setProperty( "Cardinality", 0 ).ignore();
0611 }
0612
0613 protected:
0614 bool isReEntrant() const override { return true; }
0615
0616 std::tuple<> m_inputs;
0617 };
0618
0619 template <typename... In, typename Traits_>
0620 class DataHandleMixin<std::tuple<>, std::tuple<In...>, Traits_> : public BaseClass_t<Traits_> {
0621 static_assert( std::is_base_of_v<Algorithm, BaseClass_t<Traits_>>, "BaseClass must inherit from Algorithm" );
0622
0623 template <typename IArgs, std::size_t... I>
0624 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, const IArgs& inputs, std::index_sequence<I...> )
0625 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator )
0626 , m_inputs( std::tuple_cat( std::forward_as_tuple( this ), std::get<I>( inputs ) )... ) {
0627
0628 this->setProperty( "Cardinality", 0 ).ignore();
0629 }
0630
0631 public:
0632 using KeyValue = std::pair<std::string, std::string>;
0633 using KeyValues = std::pair<std::string, std::vector<std::string>>;
0634 constexpr static std::size_t N_in = sizeof...( In );
0635
0636
0637 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, RepeatValues_<KeyValue, N_in> const& inputs )
0638 : DataHandleMixin( std::move( name ), pSvcLocator, inputs, std::index_sequence_for<In...>{} ) {}
0639
0640
0641
0642 DataHandleMixin( std::string name, ISvcLocator* locator, const KeyValue& input )
0643 : DataHandleMixin( std::move( name ), locator, std::forward_as_tuple( input ) ) {}
0644
0645 template <std::size_t N = 0>
0646 decltype( auto ) inputLocation() const {
0647 return getKey( std::get<N>( m_inputs ) );
0648 }
0649 template <typename T>
0650 decltype( auto ) inputLocation() const {
0651 return getKey( std::get<details::InputHandle_t<Traits_, std::decay_t<T>>>( m_inputs ) );
0652 }
0653 constexpr unsigned int inputLocationSize() const { return N_in; }
0654
0655 protected:
0656 bool isReEntrant() const override { return true; }
0657
0658 std::tuple<details::InputHandle_t<Traits_, In>...> m_inputs;
0659 };
0660
0661 template <typename Traits_>
0662 class DataHandleMixin<std::tuple<void>, std::tuple<>, Traits_>
0663 : public DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0664 public:
0665 using DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0666 };
0667
0668 template <typename... Out, typename Traits_>
0669 class DataHandleMixin<std::tuple<Out...>, std::tuple<>, Traits_> : public BaseClass_t<Traits_> {
0670 static_assert( std::is_base_of_v<Algorithm, BaseClass_t<Traits_>>, "BaseClass must inherit from Algorithm" );
0671
0672 template <typename OArgs, std::size_t... J>
0673 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, const OArgs& outputs, std::index_sequence<J...> )
0674 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator )
0675 , m_outputs( std::tuple_cat( std::forward_as_tuple( this ), std::get<J>( outputs ) )... ) {
0676
0677 this->setProperty( "Cardinality", 0 ).ignore();
0678 }
0679
0680 public:
0681 constexpr static std::size_t N_out = sizeof...( Out );
0682 using KeyValue = std::pair<std::string, std::string>;
0683 using KeyValues = std::pair<std::string, std::vector<std::string>>;
0684
0685
0686 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, RepeatValues_<KeyValue, N_out> const& outputs )
0687 : DataHandleMixin( std::move( name ), pSvcLocator, outputs, std::index_sequence_for<Out...>{} ) {}
0688
0689
0690 DataHandleMixin( std::string name, ISvcLocator* locator, const KeyValue& output )
0691 : DataHandleMixin( std::move( name ), locator, std::forward_as_tuple( output ) ) {}
0692
0693 template <std::size_t N = 0>
0694 decltype( auto ) outputLocation() const {
0695 return getKey( std::get<N>( m_outputs ) );
0696 }
0697 constexpr unsigned int outputLocationSize() const { return N_out; }
0698
0699 protected:
0700 bool isReEntrant() const override { return true; }
0701
0702 std::tuple<details::OutputHandle_t<Traits_, Out>...> m_outputs;
0703 };
0704
0705
0706 template <typename Fun, typename Container, typename... Args>
0707 constexpr void applyPostProcessing( const Fun&, Container&, Args... ) {
0708 static_assert( sizeof...( Args ) == 0, "Args should not be used!" );
0709 }
0710
0711 template <typename Fun, typename Container>
0712 auto applyPostProcessing( const Fun& fun, Container& c ) -> decltype( fun.postprocess( c ), void() ) {
0713 fun.postprocess( c );
0714 }
0715
0716 }