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