The Gaudi Framework  master (1a7a3838)
Loading...
Searching...
No Matches
details.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2026 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#pragma once
12#include <Gaudi/Algorithm.h>
17#include <GaudiKernel/IBinder.h>
18#include <algorithm>
19#include <array>
20#include <cassert>
21#include <concepts>
22#include <functional>
23#include <initializer_list>
24#include <iterator>
25#include <memory>
26#include <optional>
27#include <source_location>
28#include <string>
29#include <tuple>
30#include <type_traits>
31#include <utility>
32#include <vector>
33
35
36 inline std::vector<DataObjID> to_DataObjID( const std::vector<std::string>& in ) {
37 std::vector<DataObjID> out;
38 out.reserve( in.size() );
39 std::transform( in.begin(), in.end(), std::back_inserter( out ),
40 []( const std::string& i ) { return DataObjID{ i }; } );
41 return out;
42 }
43
45 template <typename T>
46 concept is_optional = requires( T const& t ) {
47 t.has_value();
48 t.value();
49 typename T::value_type;
50 };
51
52 namespace details2 {
53
54 template <typename T>
56 using type = T;
57 };
58
59 template <is_optional T>
60 struct value_type_of<T> {
61 using type = T::value_type;
62 };
63
64 } // namespace details2
65
66 template <typename T>
68
69 constexpr struct invoke_optionally_t {
70 template <typename F, typename Arg>
71 requires( !is_optional<Arg> )
72 decltype( auto ) operator()( F&& f, Arg&& arg ) const {
73 return std::invoke( std::forward<F>( f ), std::forward<Arg>( arg ) );
74 }
75 template <typename F, is_optional Arg>
76 void operator()( F&& f, Arg&& arg ) const {
77 if ( arg ) std::invoke( std::forward<F>( f ), *std::forward<Arg>( arg ) );
78 }
79 } invoke_optionally{};
81#if 0
82 template <typename Value, auto>
83 using repeat_t = Value;
84 template <typename Value, auto N>
85 using RepeatValues_ =
86 decltype( []<std::size_t... I>( std::index_sequence<I...> ) -> std::tuple<repeat_t<Value, I>...> {
87 }( std::make_index_sequence<N>{} ) );
88#else
89 template <typename Value, std::size_t... I>
90 auto get_values_helper( std::index_sequence<I...> ) {
91 return std::make_tuple( ( (void)I, Value{} )... );
92 }
93
94 template <typename Value, auto N>
95 using RepeatValues_ = decltype( get_values_helper<Value>( std::make_index_sequence<N>() ) );
96#endif
97
99 template <std::derived_from<DataObject> Out1, std::convertible_to<Out1> Out2>
100 auto put( const DataObjectHandle<Out1>& out_handle, Out2&& out ) {
101 return out_handle.put( std::make_unique<Out1>( std::forward<Out2>( out ) ) );
102 }
103
104 template <typename Out1, std::convertible_to<Out1> Out2>
105 auto put( const DataObjectHandle<AnyDataWrapper<Out1>>& out_handle, Out2&& out ) {
106 return out_handle.put( std::forward<Out2>( out ) );
107 }
108
109 template <template <typename> class Handle, typename Out, typename Value>
110 void put( const Gaudi::DataHandleVector<Handle, Out>& out_handle, Value&& out ) {
111 auto const n = out_handle.size();
112 if ( out.size() != n ) {
113 throw GaudiException( "Error during transform in " +
114 std::string{ std::source_location::current().function_name() } + ": expected " +
115 std::to_string( n ) + " containers, got " + std::to_string( out.size() ) + " instead",
116 "Gaudi::Functional::details::put", StatusCode::FAILURE );
117 }
118 for ( std::size_t i = 0; i != n; ++i ) details::put( out_handle.handles()[i], std::move( out[i] ) );
119 }
120
121 // optional put
122 template <typename OutHandle, typename OptOut>
123 requires( is_optional<OptOut> )
124 void put( const OutHandle& out_handle, OptOut&& out ) {
125 if ( out ) put( out_handle, *std::forward<OptOut>( out ) );
126 }
127
129 // adapt to differences between eg. std::vector (which has push_back) and KeyedContainer (which has insert)
130 // adapt to getting a T, and a container wanting T* by doing new T{ std::move(out) }
131 // adapt to getting a optional<T>
132
133 constexpr struct insert_t {
134 // for Container<T*>, return T
135 template <typename Container>
136 using c_remove_ptr_t = std::remove_pointer_t<typename Container::value_type>;
137
138 template <typename Container, typename Value>
139 auto operator()( Container& c, Value&& v ) const -> decltype( c.push_back( v ) ) {
140 return c.push_back( std::forward<Value>( v ) );
141 }
142
143 template <typename Container, typename Value>
144 auto operator()( Container& c, Value&& v ) const -> decltype( c.insert( v ) ) {
145 return c.insert( std::forward<Value>( v ) );
146 }
147
148 // Container<T*> with T&& as argument
149 template <typename Container, typename Value>
150 requires( std::is_pointer_v<typename Container::value_type> &&
151 std::is_convertible_v<Value, c_remove_ptr_t<Container>> )
152 auto operator()( Container& c, Value&& v ) const {
153 return operator()( c, new c_remove_ptr_t<Container>{ std::forward<Value>( v ) } );
154 }
155
156 } insert{};
157
159
160 constexpr struct deref_t {
161 template <typename In>
162 requires( !std::is_pointer_v<In> )
163 const In& operator()( const In& in ) const {
164 return in;
165 }
166
167 template <typename In>
168 requires( !std::is_pointer_v<std::decay_t<In>> )
169 In operator()( In&& in ) const {
170 return std::forward<In>( in );
171 }
172
173 template <typename In>
174 const In& operator()( const In* in ) const {
175 assert( in != nullptr );
176 return *in;
177 }
178 } deref{};
179
181 // if Container is a pointer, then we're optional items
182 namespace details2 {
183 template <typename T>
184 constexpr static bool is_gaudi_range_v = false;
185
186 template <typename T>
187 constexpr static bool is_gaudi_range_v<Gaudi::Range_<T>> = true;
188
189 template <typename T>
190 constexpr static bool is_gaudi_range_v<Gaudi::NamedRange_<T>> = true;
191
192 template <typename T>
193 constexpr static bool is_gaudi_range_v<std::optional<Gaudi::NamedRange_<T>>> = true;
194
195 template <typename In>
197 template <template <typename> class Handle, std::convertible_to<In> I>
198 auto operator()( const Handle<I>& h ) -> const In& {
199 return *h.get();
200 }
201 template <template <typename> class Handle, typename I>
202 auto operator()( const Handle<Gaudi::Range_<I>>& h ) -> In {
203 return h.get();
204 }
205 template <template <typename> class Handle, typename I>
206 auto operator()( const Handle<Gaudi::NamedRange_<I>>& h ) -> In {
207 return h.get();
208 }
209 template <template <typename> class Handle, typename I>
210 auto operator()( const Handle<std::optional<Gaudi::NamedRange_<I>>>& h ) -> In {
211 return h.get();
212 }
213 template <template <typename> class Handle, typename I>
214 requires( std::is_convertible_v<I*, In> )
215 auto operator()( const Handle<I>& h ) -> In {
216 return h.getIfExists();
217 } // In is-a pointer
218 };
219
220 template <typename Iterator>
222 using traits = std::iterator_traits<Iterator>;
224
225 public:
226 using iterator_category [[maybe_unused]] = typename traits::iterator_category;
227 using difference_type [[maybe_unused]] = typename traits::difference_type;
228 using reference = decltype( **m_iter );
229 using value_type [[maybe_unused]] = std::remove_reference_t<reference>;
230 using pointer [[maybe_unused]] = std::add_pointer_t<value_type>;
231
232 indirect_iterator() = default;
233 constexpr explicit indirect_iterator( Iterator i ) : m_iter( std::move( i ) ) {}
234
235 constexpr reference operator*() const { return **m_iter; }
236
237 constexpr bool operator==( const indirect_iterator& rhs ) const { return m_iter == rhs.m_iter; }
238
240 ++m_iter;
241 return *this;
242 }
243 constexpr indirect_iterator operator++( int ) {
244 auto i = *this;
245 ++*this;
246 return i;
247 }
248
249 // bidirectional iterator operations (if possible)
251 requires std::bidirectional_iterator<Iterator>
252 {
253 --m_iter;
254 return *this;
255 }
257 requires std::bidirectional_iterator<Iterator>
258 {
259 auto i = *this;
260 --*this;
261 return i;
262 }
263
264 // random access iterator operations (if possible)
266 requires std::random_access_iterator<Iterator>
267 {
268 m_iter += n;
269 return *this;
270 }
272 requires std::random_access_iterator<Iterator>
273 {
274 auto i = *this;
275 return i += n;
276 }
278 requires std::random_access_iterator<Iterator>
279 {
280 m_iter -= n;
281 return *this;
282 }
284 requires std::random_access_iterator<Iterator>
285 {
286 auto i = *this;
287 return i -= n;
288 }
289 constexpr difference_type operator-( const indirect_iterator& other ) const
290 requires std::random_access_iterator<Iterator>
291 {
292 return m_iter - other.m_iter;
293 }
295 requires std::random_access_iterator<Iterator>
296 {
297 return **( m_iter + n );
298 }
299 };
300
301 } // namespace details2
302
303 template <typename Container>
305 static constexpr bool is_pointer = std::is_pointer_v<Container>;
306 static constexpr bool is_range = details2::is_gaudi_range_v<Container>;
307 template <typename C>
308 using borrowed_value_t = std::add_const_t<std::remove_pointer_t<C>>;
309 // TODO: refuse pointer to a range... range must always be by value
311 using ptr_t = std::add_pointer_t<val_t>;
312 using ContainerVector = std::vector<std::conditional_t<is_range, std::remove_const_t<val_t>, ptr_t>>;
314
315 constexpr static decltype( auto ) wrap( ContainerVector::const_reference t ) {
316 if constexpr ( is_pointer || is_range ) {
317 return t;
318 } else {
319 return *t;
320 }
321 }
322 constexpr static auto wrap( ContainerVector::const_iterator i ) {
323 if constexpr ( is_pointer || is_range ) {
324 return i;
325 } else {
326 return details2::indirect_iterator{ i };
327 }
328 }
329
330 public:
331 using value_type = std::conditional_t<is_pointer, ptr_t, val_t>;
332 using size_type = typename ContainerVector::size_type;
333
334 vector_of_const_() = default;
335 void reserve( size_type size ) { m_containers.reserve( size ); }
336 template <typename T>
337 requires( is_pointer || is_range )
338 void push_back( T&& container ) {
339 m_containers.push_back( container );
340 }
341 template <typename C = Container>
342 requires( !std::is_pointer_v<C> && !details2::is_gaudi_range_v<C> )
343 void push_back( borrowed_value_t<C>& container ) {
344 // note: does not copy its argument, so we're not really a container...
345 m_containers.push_back( &container );
346 }
347 template <typename C = Container>
348 requires( !std::is_pointer_v<C> && !details2::is_gaudi_range_v<C> )
349 void push_back( borrowed_value_t<C>&& ) = delete;
350
351 auto begin() const { return wrap( m_containers.begin() ); }
352 auto end() const { return wrap( m_containers.end() ); }
353 decltype( auto ) front() const { return wrap( m_containers.front() ); }
354 decltype( auto ) back() const { return wrap( m_containers.back() ); }
355 decltype( auto ) operator[]( size_type i ) const { return wrap( m_containers[i] ); }
356 decltype( auto ) at( size_type i ) const { return wrap( m_containers.at( i ) ); }
357 size_type size() const { return m_containers.size(); }
358 };
359
360 template <typename T>
362 template <typename T>
364
365 template <typename Arg>
367 using type = Arg;
368 static constexpr bool is_range = false;
369 };
370 template <typename T>
373 static constexpr bool is_range = true;
374 };
375 template <typename Arg>
377 template <typename Arg>
379 template <typename... Args>
381
382 template <typename... T>
383 struct type_list {};
384
385 template <typename H>
386 concept location_vector_handle = requires( H const& h ) {
387 h.at( 0U ).key();
388 h.size();
389 };
390
391 template <typename Vectors>
392 decltype( auto ) getKeys( Vectors const& vectors, unsigned int i ) {
393 return std::apply(
394 [i]( auto const&... elems ) -> decltype( auto ) { return *std::array{ &elems.keys()... }.at( i ); }, vectors );
395 }
396
397 template <typename F>
399 try {
400 return std::forward<F>( f )();
401 } catch ( GaudiException& e ) {
402 if ( e.code().isFailure() ) alg.error() << e.tag() << " : " << e.message() << endmsg;
403 return e.code();
404 }
405 }
406
409 template <typename Algo>
410 EventContextHandle( std::tuple<Algo> ) {}
411 };
412
413 namespace detail2 { // utilities for detected_or_t{,_} usage
414
415 // keep only for backwards compatibility... for now.
416 template <typename Tr>
417 using BaseClass_t = typename Tr::BaseClass;
418
419 template <typename Tr, typename Default>
420 struct BaseClass {
421 using type = Default;
422 };
423 template <typename Tr, typename Default>
424 requires requires { typename Tr::BaseClass; }
425 struct BaseClass<Tr, Default> {
426 using type = Tr::BaseClass;
427 };
428
429 template <typename T, typename Tr, template <typename...> typename Default>
431 using type = Default<T>;
432 };
433 template <typename T, typename Tr, template <typename...> typename Default>
434 requires requires { typename Tr::template OutputHandle<T>; }
435 struct OutputHandle<T, Tr, Default> {
436 using type = Tr::template OutputHandle<T>;
437 };
438 template <typename Tr, template <typename...> typename Default>
440 template <typename T>
442 };
443 template <typename T, typename Tr, template <typename...> typename Default>
447
448 template <typename T, typename Tr, template <typename...> typename Default>
449 struct InputHandle {
450 using type = Default<T>;
451 };
452 template <typename T, typename Tr, template <typename...> typename Default>
453 requires requires { typename Tr::template InputHandle<T>; }
454 struct InputHandle<T, Tr, Default> {
455 using type = Tr::template InputHandle<T>;
456 };
457 template <typename Tr, template <typename...> typename Default>
459 template <typename T>
461 };
462 template <typename T, typename Tr, template <typename...> typename Default>
466
467 template <typename T>
468 concept algtool_interface = std::derived_from<std::decay_t<T>, IAlgTool>;
469
470 template <typename T>
474 template <algtool_interface T>
478 template <>
482 template <typename T>
484 } // namespace detail2
485
486 // check whether Tr::BaseClass is a valid type,
487 // if so, define BaseClass_t<Tr> as being Tr::BaseClass
488 // else define as being Gaudi::Algorithm
489 template <typename Tr, typename Default = Gaudi::Algorithm>
491
492 // check whether Traits::{Input,Output}Handle<T> is a valid type,
493 // if so, define {Input,Output}Handle_t<Traits,T> as being Traits::{Input,Output}Handle<T>
494 // else define as being DataObject{Read,,Write}Handle<T>
495 template <typename Tr, typename T>
497
498 template <typename Tr, typename T>
500
501 template <typename T>
502 inline constexpr bool is_event_context_v = std::is_same_v<std::remove_cvref_t<T>, EventContext>;
503
505 using KeyValue = std::pair<std::string, std::string>;
506 using KeyValues = std::pair<std::string, std::vector<std::string>>;
507
509 bool is_vector = false;
510
511 LocationSpec( std::string name_, std::string location_ )
512 : value{ std::move( name_ ), { std::move( location_ ) } } {}
513 LocationSpec( std::string name_, const char* location_ )
514 : LocationSpec{ std::move( name_ ), std::string{ location_ } } {}
515 LocationSpec( std::string name_, std::vector<std::string> locations_ )
516 : value{ std::move( name_ ), std::move( locations_ ) }, is_vector{ true } {}
517 LocationSpec( std::string name_, std::initializer_list<std::string> locations_ )
518 : LocationSpec{ std::move( name_ ), std::vector<std::string>{ locations_ } } {}
519
520 operator KeyValue() const {
521 if ( is_vector ) {
522 throw GaudiException( "Expected a scalar location specification", "Gaudi::Functional::details::LocationSpec",
524 }
525 return { value.first, value.second.front() };
526 }
527 operator KeyValues() const { return value; }
528 };
529
530 template <typename Arg>
534 template <>
536 using type = std::tuple<>;
537 };
538 template <typename T>
542 template <typename T>
546 template <typename Arg>
548
549 template <typename... Args>
550 using LocationSpecs_t = std::tuple<LocationSpec_t<Args>...>;
551
552 template <typename... Args>
554 using type = std::tuple<>;
555 };
556 template <typename First, typename... Rest>
557 struct TailLocationSpecs<First, Rest...> {
558 using type = LocationSpecs_t<Rest...>;
559 };
560 template <typename... Args>
561 using TailLocationSpecs_t = typename TailLocationSpecs<Args...>::type;
562
563 template <typename Tuple>
565 using type = std::tuple<>;
566 };
567 template <typename First, typename... Rest>
568 struct first_or_empty<std::tuple<First, Rest...>> {
569 using type = First;
570 };
571 template <typename Tuple>
573
574 template <typename Tuple, typename T>
575 inline constexpr bool tuple_elements_are_v = false;
576 template <typename T, typename... Elements>
577 inline constexpr bool tuple_elements_are_v<std::tuple<Elements...>, T> = ( std::same_as<Elements, T> && ... );
578
579 template <typename Tuple, typename T>
580 inline constexpr bool tuple_elements_constructible_from_v = false;
581 template <typename T, typename... Elements>
582 inline constexpr bool tuple_elements_constructible_from_v<std::tuple<Elements...>, T> =
583 ( std::constructible_from<Elements, T> && ... );
584
585 template <typename... Args>
586 inline constexpr bool first_is_event_context_v = false;
587 template <typename First, typename... Rest>
588 inline constexpr bool first_is_event_context_v<First, Rest...> = is_event_context_v<First>;
589
590 template <bool starts_with_event_context, typename InputSpecTuple>
591 inline constexpr auto empty_input_specs =
592 std::conditional_t<starts_with_event_context, InputSpecTuple, std::tuple<>>{};
593
594 template <typename Tuple, typename Spec, std::size_t... I>
595 Tuple location_specs_tuple( std::initializer_list<Spec> specs, std::index_sequence<I...>, const char* component ) {
596 if constexpr ( sizeof...( I ) == 1 ) {
597 if ( specs.size() == 0 ) return Tuple{ Spec{} };
598 }
599 if ( specs.size() != sizeof...( I ) ) {
600 throw GaudiException( "Wrong number of location specifications", component, StatusCode::FAILURE );
601 }
602 return Tuple{ *std::next( specs.begin(), I )... };
603 }
604
605 template <typename Tuple>
608
609 public:
610 static constexpr auto indices = std::make_index_sequence<std::tuple_size_v<Tuple>>{};
611
613 requires( std::tuple_size_v<Tuple> == 0 )
614 = default;
615 LocationSpecs( Tuple specs ) : m_specs{ std::move( specs ) } {}
616 template <typename... Specs>
617 LocationSpecs( Specs&&... specs )
618 requires( sizeof...( Specs ) > 0 && std::constructible_from<Tuple, Specs...> )
619 : m_specs{ std::forward<Specs>( specs )... } {}
620 template <typename... Args>
621 LocationSpecs( Args&&... args )
622 requires( sizeof...( Args ) > 1 && std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, Args...> )
623 : LocationSpecs{ First{ std::forward<Args>( args )... } } {}
624 LocationSpecs( std::string name, std::string loc )
625 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::string> )
626 : LocationSpecs{ First{ std::move( name ), std::move( loc ) } } {}
627 LocationSpecs( std::string name, std::vector<std::string> locs )
628 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::vector<std::string>> )
629 : LocationSpecs{ First{ std::move( name ), std::move( locs ) } } {}
630 LocationSpecs( std::initializer_list<First> specs )
631 requires( std::tuple_size_v<Tuple> > 0 && tuple_elements_are_v<Tuple, First> )
632 : m_specs{ location_specs_tuple<Tuple>( specs, indices, "Gaudi::Functional::details::LocationSpecs" ) } {}
633 LocationSpecs( std::initializer_list<LocationSpec> specs )
634 requires( std::tuple_size_v<Tuple> > 0 && !tuple_elements_are_v<Tuple, First> &&
636 : m_specs{ location_specs_tuple<Tuple>( specs, indices, "Gaudi::Functional::details::LocationSpecs" ) } {}
637
638 Tuple const& tuple() const { return m_specs; }
639 auto with_context() const { return std::tuple_cat( std::tuple<std::tuple<>>{}, m_specs ); }
640
641 private:
642 Tuple m_specs{};
643 };
644
645 template <typename Traits>
646 inline constexpr bool isLegacy =
647 std::is_base_of_v<Gaudi::details::LegacyAlgorithmAdapter, details::BaseClass_t<Traits>>;
648
650
651 template <typename Handle, typename Algo>
652 auto get( const Handle& handle, const Algo&,
653 const EventContext& ) -> decltype( details::deref( handle.get() ) ) // make it SFINAE friendly...
654 {
655 return details::deref( handle.get() );
656 }
657
658 template <typename Algo>
659 const EventContext& get( const EventContextHandle&, const Algo&, const EventContext& ctx ) {
660 return ctx;
661 }
662
663 template <template <typename> class Handle, typename In, typename Algo>
664 auto get( const Gaudi::DataHandleVector<Handle, In>& handle, const Algo&, const EventContext& ) {
666 ins.reserve( handle.handles().size() );
667 std::ranges::transform( handle.handles(), std::back_inserter( ins ), details2::get_from_handle<In>{} );
668 return ins;
669 }
670
671 template <typename IFace, typename Algo>
672 auto get( const ToolHandle<Gaudi::Interface::Bind::IBinder<IFace>>& handle, const Algo&, const EventContext& ctx ) {
673 return handle.bind( ctx );
674 }
675
676 template <typename Handle>
677 auto getKey( const Handle& h ) -> decltype( h.objKey() ) {
678 return h.objKey();
679 }
680
681 template <template <typename> class Handle, typename T>
682 auto getKey( const Gaudi::DataHandleVector<Handle, T>& h ) -> decltype( h.keys() ) {
683 return h.keys();
684 }
685
686 template <typename OutputSpec, typename InputSpec, typename Traits_>
687 class DataHandleMixin;
688
689 template <typename Outputs, typename Traits_, typename... Args>
691
692 template <typename... Out, typename... In, typename Traits_>
693 requires( std::derived_from<BaseClass_t<Traits_>, Algorithm> && !std::disjunction_v<std::is_void<Out>...> )
695
696 public:
697 constexpr static std::size_t N_in = sizeof...( In );
698 constexpr static std::size_t N_out = sizeof...( Out );
699
700 private:
701 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
702 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, const IArgs& inputs, std::index_sequence<I...>,
703 const OArgs& outputs, std::index_sequence<J...> )
704 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator )
705 , m_inputs{ std::tuple_cat( std::forward_as_tuple( this ), std::get<I>( inputs ) )... }
706 , m_outputs{ std::tuple_cat( std::forward_as_tuple( this ), std::get<J>( outputs ) )... } {
707 // make sure this algorithm is seen as reentrant by Gaudi
708 this->setProperty( "Cardinality", 0 ).ignore();
709 }
710
711 using InputHandles = std::tuple<details::InputHandle_t<Traits_, In>...>;
712 using OutputHandles = std::tuple<details::OutputHandle_t<Traits_, Out>...>;
720 constexpr static std::size_t input_location_offset = starts_with_event_context ? 1 : 0;
721 constexpr static std::size_t N_input_locations = N_in - input_location_offset;
722 template <std::size_t N>
723 constexpr static std::size_t input_handle_index = N + input_location_offset;
724 template <std::size_t N>
725 using InputLocationHandle = std::tuple_element_t<input_handle_index<N>, InputHandles>;
726 template <std::size_t... I>
727 constexpr static bool input_locations_are_vectors( std::index_sequence<I...> ) {
729 }
730 constexpr static bool all_input_locations_are_vectors =
731 input_locations_are_vectors( std::make_index_sequence<N_input_locations>{} );
732
733 template <std::size_t... I>
734 auto input_location_handles( std::index_sequence<I...> ) const {
735 return std::forward_as_tuple( std::get<input_handle_index<I>>( m_inputs )... );
736 }
737
738 public:
741
742 // 0 -> 0, with the historic optional empty tuple arguments.
743 DataHandleMixin( std::string name, ISvcLocator* locator, std::tuple<> = {}, std::tuple<> = {} )
744 requires( N_in == 0 && N_out == 0 )
745 : DataHandleMixin( std::move( name ), locator, std::tuple<>{}, InputSpecs::indices, std::tuple<>{},
746 OutputSpecs::indices ) {}
747
748 // EventContext -> 0, where the context has no location argument.
749 DataHandleMixin( std::string name, ISvcLocator* locator )
750 requires( starts_with_event_context && N_in == 1 && N_out == 0 )
752 InputSpecs::indices, std::tuple<>{}, OutputSpecs::indices ) {}
753
754 // N -> 0
755 DataHandleMixin( std::string name, ISvcLocator* locator, InputSpecs const& inputs )
756 requires( N_in != 0 && N_out == 0 && !( starts_with_event_context && N_in == 1 ) )
757 : DataHandleMixin( std::move( name ), locator, inputs.tuple(), inputs.indices, std::tuple<>{},
758 OutputSpecs::indices ) {}
759
760 // Context-first backwards compatibility: the EventContext slot used to consume no input location argument.
761 DataHandleMixin( std::string name, ISvcLocator* locator, LegacyInputSpecs const& inputs )
762 requires( starts_with_event_context && N_in > 1 && N_out == 0 )
763 : DataHandleMixin( std::move( name ), locator, inputs.with_context(), InputSpecs::indices, std::tuple<>{},
764 OutputSpecs::indices ) {}
765
766 // 0 -> N and EventContext -> N
767 DataHandleMixin( std::string name, ISvcLocator* locator, OutputSpecs const& outputs )
768 requires( N_out != 0 && ( N_in == 0 || ( starts_with_event_context && N_in == 1 ) ) )
770 InputSpecs::indices, outputs.tuple(), outputs.indices ) {}
771
772 // N -> M, including EventContext-first legacy input syntax and explicit empty input tuple for 0 -> M.
773 DataHandleMixin( std::string name, ISvcLocator* locator, InputSpecs const& inputs, OutputSpecs const& outputs )
774 requires( N_out != 0 )
775 : DataHandleMixin( std::move( name ), locator, inputs.tuple(), inputs.indices, outputs.tuple(),
776 outputs.indices ) {}
777
778 DataHandleMixin( std::string name, ISvcLocator* locator, LegacyInputSpecs const& inputs,
779 OutputSpecs const& outputs )
780 requires( starts_with_event_context && N_in > 1 && N_out != 0 )
781 : DataHandleMixin( std::move( name ), locator, inputs.with_context(), InputSpecs::indices, outputs.tuple(),
782 outputs.indices ) {}
783
784 template <std::size_t N = 0>
785 decltype( auto ) inputLocation() const
786 requires( N_input_locations > N )
787 {
788 return getKey( std::get<input_handle_index<N>>( m_inputs ) );
789 }
790 template <typename T>
791 decltype( auto ) inputLocation() const
792 requires( N_input_locations > 0 && !is_event_context_v<T> )
793 {
794 return getKey( std::get<details::InputHandle_t<Traits_, std::decay_t<T>>>( m_inputs ) );
795 }
796 template <std::size_t N = 0>
797 decltype( auto ) inputLocation( unsigned int n ) const
799 {
800 return std::get<input_handle_index<N>>( m_inputs ).at( n ).key();
801 }
802 decltype( auto ) inputLocation( unsigned int i, unsigned int j ) const
804 {
805 return getKeys( input_location_handles( std::make_index_sequence<N_input_locations>{} ), i ).at( j ).key();
806 }
807 unsigned int inputLocationSize( unsigned int i ) const
808 requires( N_input_locations > 0 )
809 {
810 auto size = []( const auto& handle ) {
811 if constexpr ( location_vector_handle<std::decay_t<decltype( handle )>> ) {
812 return static_cast<unsigned int>( handle.size() );
813 } else {
814 return 1U;
815 }
816 };
817 return std::apply( [i = i + input_location_offset,
818 size]( const auto&... handles ) { return std::array{ size( handles )... }.at( i ); },
819 m_inputs );
820 }
821 // to remain backwards compatible (!), this has to return
822 // -- for non-merging transformers, the # of input _arguments_...
823 // -- for merging transformers, which only had _one_ input argument, which was not EventContext, the number of
824 // inputs of the first argument...
825 // FIXME: to be(come) unambiguous, this should be deprecated at some point, and replaced with a better named
826 // alternatives...
827 unsigned int inputLocationSize() const {
828 if constexpr ( !starts_with_event_context && N_input_locations == 1 &&
830 return inputLocationSize( 0 );
831 } else {
832 return N_input_locations;
833 }
834 }
835
836 template <std::size_t N = 0>
837 decltype( auto ) outputLocation() const
838 requires( N_out > 0 )
839 {
840 return getKey( std::get<N>( m_outputs ) );
841 }
842 template <typename T>
843 decltype( auto ) outputLocation() const
844 requires( N_out > 0 )
845 {
846 return getKey( std::get<details::OutputHandle_t<Traits_, std::decay_t<T>>>( m_outputs ) );
847 }
848 template <std::size_t N = 0>
849 decltype( auto ) outputLocation( unsigned int n ) const
851 {
852 return std::get<N>( m_outputs ).at( n ).key();
853 }
854 unsigned int outputLocationSize() const {
856 return std::get<0>( m_outputs ).size();
857 } else {
858 return N_out;
859 }
860 }
861
862 template <typename Algorithm>
863 decltype( auto ) invoke( const Algorithm& algo, const EventContext& ctx ) const {
864 return std::apply(
865 [&]( const auto&... handle ) -> decltype( auto ) { return algo( get( handle, algo, ctx )... ); }, m_inputs );
866 }
867
868 protected:
869 bool isReEntrant() const override { return true; }
872 };
873
874 template <typename InputSpec, typename Traits_>
875 class DataHandleMixin<type_list<void>, InputSpec, Traits_> : public DataHandleMixin<type_list<>, InputSpec, Traits_> {
876 public:
877 using DataHandleMixin<type_list<>, InputSpec, Traits_>::DataHandleMixin;
878 };
879
880 template <typename OutHandles, typename Outputs>
881 void put_results( const OutHandles& out_handles, Outputs&& outputs ) {
882 [&]<std::size_t... I>( std::index_sequence<I...> ) {
883 ( put( std::get<I>( out_handles ), std::get<I>( std::forward<Outputs>( outputs ) ) ), ... );
884 }( std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Outputs>>>{} );
885 }
886
887 template <typename Algorithm, typename OutHandles = std::tuple<>>
888 StatusCode execute_single_output( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles = {} )
889 requires( std::tuple_size_v<OutHandles> <= 1 )
890 {
891 return execute( algo, [&] {
892 if constexpr ( std::tuple_size_v<OutHandles> == 0 ) {
893 algo.invoke( algo, ctx );
894 } else {
895 put( std::get<0>( out_handles ), algo.invoke( algo, ctx ) );
896 }
897 return FilterDecision::PASSED;
898 } );
899 }
900
901 template <typename Algorithm, typename OutHandles>
902 StatusCode execute_outputs( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles ) {
903 return execute( algo, [&] {
904 put_results( out_handles, algo.invoke( algo, ctx ) );
906 } );
907 }
908
909 template <typename Algorithm, typename OutHandles>
910 StatusCode execute_filtered_outputs( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles ) {
911 return execute( algo, [&] {
912 return std::apply(
913 [&]( bool passed, auto&&... data ) {
914 put_results( out_handles, std::forward_as_tuple( std::forward<decltype( data )>( data )... ) );
915 return passed;
916 },
917 algo.invoke( algo, ctx ) )
920 } );
921 }
922
923} // namespace Gaudi::Functional::details
924
925#include "deprecated.h"
bool PyHelper setProperty(IInterface *p, char *name, char *value)
boost::spirit::classic::position_iterator2< ForwardIterator > Iterator
Definition Iterator.h:18
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
DataObjectHandle.h GaudiKernel/DataObjectHandle.h.
T * put(std::unique_ptr< T > object) const
Register object in transient store.
This class represents an entry point to all the event specific data.
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:87
A configurable, dynamically sized sequence of homogeneous data handles.
Definition DataHandle.h:132
const std::vector< Handle< T > > & handles() const
Typed handles, in property order.
Definition DataHandle.h:193
auto size() const
Number of configured handles.
Definition DataHandle.h:197
DataHandleMixin(std::string name, ISvcLocator *pSvcLocator, const IArgs &inputs, std::index_sequence< I... >, const OArgs &outputs, std::index_sequence< J... >)
Definition details.h:702
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs)
Definition details.h:761
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs, OutputSpecs const &outputs)
Definition details.h:778
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs)
Definition details.h:755
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs, OutputSpecs const &outputs)
Definition details.h:773
DataHandleMixin(std::string name, ISvcLocator *locator, OutputSpecs const &outputs)
Definition details.h:767
decltype(auto) invoke(const Algorithm &algo, const EventContext &ctx) const
Definition details.h:863
std::tuple_element_t< input_handle_index< N >, InputHandles > InputLocationHandle
Definition details.h:725
DataHandleMixin(std::string name, ISvcLocator *locator, std::tuple<>={}, std::tuple<>={})
Definition details.h:743
LocationSpecs(std::string name, std::string loc)
Definition details.h:624
first_or_empty_t< Tuple > First
Definition details.h:607
LocationSpecs(std::string name, std::vector< std::string > locs)
Definition details.h:627
LocationSpecs(std::initializer_list< LocationSpec > specs)
Definition details.h:633
LocationSpecs(std::initializer_list< First > specs)
Definition details.h:630
constexpr indirect_iterator & operator+=(difference_type n)
Definition details.h:265
constexpr indirect_iterator operator--(int)
Definition details.h:256
constexpr indirect_iterator & operator-=(difference_type n)
Definition details.h:277
constexpr indirect_iterator operator+(difference_type n) const
Definition details.h:271
constexpr bool operator==(const indirect_iterator &rhs) const
Definition details.h:237
constexpr indirect_iterator operator-(difference_type n) const
Definition details.h:283
constexpr difference_type operator-(const indirect_iterator &other) const
Definition details.h:289
typename traits::difference_type difference_type
constexpr reference operator[](difference_type n) const
Definition details.h:294
constexpr indirect_iterator operator++(int)
Definition details.h:243
typename traits::iterator_category iterator_category
std::remove_reference_t< reference > value_type
static constexpr decltype(auto) wrap(ContainerVector::const_reference t)
Definition details.h:315
static constexpr auto wrap(ContainerVector::const_iterator i)
Definition details.h:322
std::add_pointer_t< val_t > ptr_t
Definition details.h:311
void push_back(borrowed_value_t< C > &&)=delete
std::add_const_t< std::remove_pointer_t< C > > borrowed_value_t
Definition details.h:308
typename ContainerVector::size_type size_type
Definition details.h:332
std::vector< std::conditional_t< is_range, std::remove_const_t< val_t >, ptr_t > > ContainerVector
Definition details.h:312
std::conditional_t< is_pointer, ptr_t, val_t > value_type
Definition details.h:331
borrowed_value_t< Container > val_t
Definition details.h:310
decltype(auto) at(size_type i) const
Definition details.h:356
void push_back(borrowed_value_t< C > &container)
Definition details.h:343
Useful class for representation of "sequence" of the objects through the range of valid iterators.
Definition Range.h:81
Define general base for Gaudi exception.
virtual const std::string & message() const
error message to be printed
virtual const StatusCode & code() const
StatusCode for Exception.
virtual const std::string & tag() const
name tag for the exception, or exception type
The interface implemented by the AlgTool base class.
Definition IAlgTool.h:29
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition ISvcLocator.h:42
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:118
constexpr static const auto FAILURE
Definition StatusCode.h:100
Handle to be used in lieu of naked pointers to tools.
Definition ToolHandle.h:132
STL class.
STL class.
typename Tr::BaseClass BaseClass_t
Definition details.h:417
typename DefaultInputHandle< T >::type DefaultInputHandle_t
Definition details.h:483
StatusCode execute_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
Definition details.h:902
typename detail2::InputHandle< T, Tr, detail2::DefaultInputHandle_t >::type InputHandle_t
Definition details.h:499
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
Definition details.h:652
typename first_or_empty< Tuple >::type first_or_empty_t
Definition details.h:572
auto getKey(const Handle &h) -> decltype(h.objKey())
Definition details.h:677
constexpr auto empty_input_specs
Definition details.h:591
constexpr bool isLegacy
Definition details.h:646
typename TailLocationSpecs< Args... >::type TailLocationSpecs_t
Definition details.h:561
std::vector< DataObjID > to_DataObjID(const std::vector< std::string > &in)
Definition details.h:36
typename handle_vector_input< Arg >::type handle_vector_input_t
Definition details.h:376
auto put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
Definition details.h:100
constexpr bool tuple_elements_are_v
Definition details.h:575
decltype(auto) getKeys(Vectors const &vectors, unsigned int i)
Definition details.h:392
std::tuple< LocationSpec_t< Args >... > LocationSpecs_t
Definition details.h:550
typename detail2::OutputHandle< T, Tr, DataObjectWriteHandle >::type OutputHandle_t
Definition details.h:496
StatusCode execute_single_output(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles={})
Definition details.h:888
constexpr bool first_is_event_context_v
Definition details.h:586
constexpr struct Gaudi::Functional::details::deref_t deref
constexpr bool is_handle_vector_input_v
Definition details.h:378
typename LocationSpecFor< std::remove_cvref_t< Arg > >::type LocationSpec_t
Definition details.h:547
typename details2::value_type_of< T >::type remove_optional_t
Definition details.h:67
constexpr bool is_event_context_v
Definition details.h:502
detail2::BaseClass< Tr, Default >::type BaseClass_t
Definition details.h:490
decltype(get_values_helper< Value >(std::make_index_sequence< N >())) RepeatValues_
Definition details.h:95
StatusCode execute_filtered_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
Definition details.h:910
auto get_values_helper(std::index_sequence< I... >)
Definition details.h:90
DataHandleMixin< Outputs, type_list< handle_vector_input_t< Args >... >, Traits_ > DataHandleVectorMixin
Definition details.h:690
StatusCode execute(CommonMessagingBase const &alg, F &&f)
Definition details.h:398
void put_results(const OutHandles &out_handles, Outputs &&outputs)
Definition details.h:881
Tuple location_specs_tuple(std::initializer_list< Spec > specs, std::index_sequence< I... >, const char *component)
Definition details.h:595
constexpr bool tuple_elements_constructible_from_v
Definition details.h:580
STL namespace.
LocationSpec(std::string name_, std::vector< std::string > locations_)
Definition details.h:515
std::pair< std::string, std::string > KeyValue
Definition details.h:505
std::pair< std::string, std::vector< std::string > > KeyValues
Definition details.h:506
LocationSpec(std::string name_, std::initializer_list< std::string > locations_)
Definition details.h:517
LocationSpec(std::string name_, const char *location_)
Definition details.h:513
LocationSpec(std::string name_, std::string location_)
Definition details.h:511
const In & operator()(const In *in) const
Definition details.h:174
ToolHandle< Gaudi::Interface::Bind::IBinder< std::decay_t< T > > > type
Definition details.h:476
Gaudi::DataHandleVector< InputHandleFor< Tr, Default >::template type, T > type
Definition details.h:464
typename InputHandle< std::remove_pointer_t< T >, Tr, Default >::type type
Definition details.h:460
Gaudi::DataHandleVector< OutputHandleFor< Tr, Default >::template type, T > type
Definition details.h:445
typename OutputHandle< remove_optional_t< T >, Tr, Default >::type type
Definition details.h:441
auto operator()(const Handle< std::optional< Gaudi::NamedRange_< I > > > &h) -> In
Definition details.h:210
auto operator()(const Handle< I > &h) -> const In &
Definition details.h:198
auto operator()(const Handle< Gaudi::NamedRange_< I > > &h) -> In
Definition details.h:206
auto operator()(const Handle< Gaudi::Range_< I > > &h) -> In
Definition details.h:202
std::remove_pointer_t< typename Container::value_type > c_remove_ptr_t
Definition details.h:136
auto operator()(Container &c, Value &&v) const -> decltype(c.push_back(v))
Definition details.h:139
auto operator()(Container &c, Value &&v) const -> decltype(c.insert(v))
Definition details.h:144
decltype(auto) operator()(F &&f, Arg &&arg) const
Definition details.h:72
void operator()(F &&f, Arg &&arg) const
Definition details.h:76