The Gaudi Framework  master (e98cfcff)
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
34// TODO: migrate downstream users to include `zip.h` directly, instead of transitively,
35// and then drop this include here...
36#include "zip.h"
37
39
40 template <template <typename> class Handle, typename I>
41 class HandleVector;
42
43 inline std::vector<DataObjID> to_DataObjID( const std::vector<std::string>& in ) {
44 std::vector<DataObjID> out;
45 out.reserve( in.size() );
46 std::transform( in.begin(), in.end(), std::back_inserter( out ),
47 []( const std::string& i ) { return DataObjID{ i }; } );
48 return out;
49 }
50
52 template <typename T>
53 concept is_optional = requires( T const& t ) {
54 t.has_value();
55 t.value();
56 typename T::value_type;
57 };
58
59 namespace details2 {
60
61 template <typename T>
63 using type = T;
64 };
65
66 template <is_optional T>
67 struct value_type_of<T> {
68 using type = T::value_type;
69 };
70
71 } // namespace details2
72
73 template <typename T>
75
76 constexpr struct invoke_optionally_t {
77 template <typename F, typename Arg>
78 requires( !is_optional<Arg> )
79 decltype( auto ) operator()( F&& f, Arg&& arg ) const {
80 return std::invoke( std::forward<F>( f ), std::forward<Arg>( arg ) );
81 }
82 template <typename F, is_optional Arg>
83 void operator()( F&& f, Arg&& arg ) const {
84 if ( arg ) std::invoke( std::forward<F>( f ), *std::forward<Arg>( arg ) );
85 }
86 } invoke_optionally{};
88#if 0
89 template <typename Value, auto>
90 using repeat_t = Value;
91 template <typename Value, auto N>
92 using RepeatValues_ =
93 decltype( []<std::size_t... I>( std::index_sequence<I...> ) -> std::tuple<repeat_t<Value, I>...> {
94 }( std::make_index_sequence<N>{} ) );
95#else
96 template <typename Value, std::size_t... I>
97 auto get_values_helper( std::index_sequence<I...> ) {
98 return std::make_tuple( ( (void)I, Value{} )... );
99 }
100
101 template <typename Value, auto N>
102 using RepeatValues_ = decltype( get_values_helper<Value>( std::make_index_sequence<N>() ) );
103#endif
104
106 template <std::derived_from<DataObject> Out1, std::convertible_to<Out1> Out2>
107 auto put( const DataObjectHandle<Out1>& out_handle, Out2&& out ) {
108 return out_handle.put( std::make_unique<Out1>( std::forward<Out2>( out ) ) );
109 }
110
111 template <typename Out1, std::convertible_to<Out1> Out2>
112 auto put( const DataObjectHandle<AnyDataWrapper<Out1>>& out_handle, Out2&& out ) {
113 return out_handle.put( std::forward<Out2>( out ) );
114 }
115
116 template <template <typename> class Handle, typename Out, typename Value>
117 auto put( const HandleVector<Handle, Out>& out_handle, Value&& out ) {
118 return out_handle.put( std::forward<Value>( out ) );
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)
265 constexpr indirect_iterator& operator+=( difference_type n )
266 requires std::random_access_iterator<Iterator>
267 {
268 m_iter += n;
269 return *this;
270 }
271 constexpr indirect_iterator operator+( difference_type n ) const
272 requires std::random_access_iterator<Iterator>
273 {
274 auto i = *this;
275 return i += n;
276 }
277 constexpr indirect_iterator& operator-=( difference_type n )
278 requires std::random_access_iterator<Iterator>
279 {
280 m_iter -= n;
281 return *this;
282 }
283 constexpr indirect_iterator operator-( difference_type n ) const
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 }
294 constexpr reference operator[]( difference_type n ) const
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 <template <typename> class Handle, typename I>
362 struct Payload {
363 std::vector<Handle<I>> handles;
365
366 template <typename Algorithm>
367 Payload( Algorithm* parent, std::pair<std::string, std::vector<std::string>> const& keys )
368 : property{ parent, keys.first, details::to_DataObjID( keys.second ),
369 [ptr = &handles, parent]( auto& self_ ) {
370 auto& self = dynamic_cast<Gaudi::Property<std::vector<DataObjID>>&>( self_ );
371 ptr->clear();
372 ptr->reserve( self.value().size() );
373 std::ranges::transform( self.value(), std::back_inserter( *ptr ),
374 [&]( const auto& location ) -> Handle<I> {
375 return { location, parent };
376 } );
377 },
379
380 Payload( Payload&& ) = delete;
381 Payload& operator=( Payload&& ) = delete;
382 Payload( Payload const& ) = delete;
383 Payload& operator=( Payload const& ) = delete;
384 };
385 std::unique_ptr<Payload> m_payload; // need a stable rendez-vous for the callback & property to work
386
387 public:
388 template <typename Algorithm>
389 HandleVector( Algorithm* parent, std::pair<std::string, std::vector<std::string>> const& keys )
390 : m_payload{ std::make_unique<Payload>( parent, keys ) } {}
391
392 // allow construction by DataHandleMixin
393 template <typename A, typename K>
394 HandleVector( std::tuple<A, K>&& tup ) : HandleVector{ std::get<0>( tup ), std::get<1>( tup ) } {}
395 template <typename A, typename Name, typename Keys>
396 HandleVector( std::tuple<A, Name, Keys>&& tup )
397 : HandleVector{ std::get<0>( tup ),
398 std::pair<std::string, std::vector<std::string>>{ std::get<1>( tup ), std::get<2>( tup ) } } {}
399
402 ins.reserve( m_payload->handles.size() );
403 std::ranges::transform( m_payload->handles, std::back_inserter( ins ), details2::get_from_handle<I>{} );
404 return ins;
405 }
406 template <typename Out>
407 void put( Out&& out ) const {
408 auto const n = size();
409 if ( out.size() != n ) {
410 throw GaudiException( "Error during transform in " +
411 std::string{ std::source_location::current().function_name() } + ": expected " +
412 std::to_string( n ) + " containers, got " + std::to_string( out.size() ) + " instead",
413 "Gaudi::Functional::details::HandleVector::put", StatusCode::FAILURE );
414 }
415 for ( std::size_t i = 0; i != n; ++i ) details::put( handles()[i], std::move( out[i] ) );
416 }
417
418 std::vector<Handle<I>> const& handles() const { return m_payload->handles; }
419 std::vector<DataObjID> const& locations() const { return m_payload->property.value(); }
420 DataObjID const& at( size_t i ) const { return m_payload->property.value().at( i ); }
421 auto size() const { return m_payload->handles.size(); }
422 };
423
424 template <typename T>
426 template <typename T>
428
429 template <typename Arg>
431 using type = Arg;
432 static constexpr bool is_range = false;
433 };
434 template <typename T>
437 static constexpr bool is_range = true;
438 };
439 template <typename Arg>
441 template <typename Arg>
443 template <typename... Args>
445
446 template <typename... T>
447 struct type_list {};
448
449 template <typename H>
450 concept location_vector_handle = requires( H const& h ) {
451 h.at( 0U ).key();
452 h.size();
453 };
454
455 template <typename Vectors>
456 decltype( auto ) getLocations( Vectors const& vectors, unsigned int i ) {
457 return std::apply(
458 [i]( auto const&... elems ) -> decltype( auto ) { return *std::array{ &elems.locations()... }.at( i ); },
459 vectors );
460 }
461
462 template <typename F>
464 try {
465 return std::forward<F>( f )();
466 } catch ( GaudiException& e ) {
467 if ( e.code().isFailure() ) alg.error() << e.tag() << " : " << e.message() << endmsg;
468 return e.code();
469 }
470 }
471
474 template <typename Algo>
475 EventContextHandle( std::tuple<Algo> ) {}
476 };
477
478 namespace detail2 { // utilities for detected_or_t{,_} usage
479
480 // keep only for backwards compatibility... for now.
481 template <typename Tr>
482 using BaseClass_t = typename Tr::BaseClass;
483
484 template <typename Tr, typename Default>
485 struct BaseClass {
486 using type = Default;
487 };
488 template <typename Tr, typename Default>
489 requires requires { typename Tr::BaseClass; }
490 struct BaseClass<Tr, Default> {
491 using type = Tr::BaseClass;
492 };
493
494 template <typename T, typename Tr, template <typename...> typename Default>
496 using type = Default<T>;
497 };
498 template <typename T, typename Tr, template <typename...> typename Default>
499 requires requires { typename Tr::template OutputHandle<T>; }
500 struct OutputHandle<T, Tr, Default> {
501 using type = Tr::template OutputHandle<T>;
502 };
503 template <typename Tr, template <typename...> typename Default>
505 template <typename T>
507 };
508 template <typename T, typename Tr, template <typename...> typename Default>
512
513 template <typename T, typename Tr, template <typename...> typename Default>
514 struct InputHandle {
515 using type = Default<T>;
516 };
517 template <typename T, typename Tr, template <typename...> typename Default>
518 requires requires { typename Tr::template InputHandle<T>; }
519 struct InputHandle<T, Tr, Default> {
520 using type = Tr::template InputHandle<T>;
521 };
522 template <typename Tr, template <typename...> typename Default>
524 template <typename T>
526 };
527 template <typename T, typename Tr, template <typename...> typename Default>
531
532 template <typename T>
533 concept algtool_interface = std::derived_from<std::decay_t<T>, IAlgTool>;
534
535 template <typename T>
539 template <algtool_interface T>
543 template <>
547 template <typename T>
549 } // namespace detail2
550
551 // check whether Tr::BaseClass is a valid type,
552 // if so, define BaseClass_t<Tr> as being Tr::BaseClass
553 // else define as being Gaudi::Algorithm
554 template <typename Tr, typename Default = Gaudi::Algorithm>
556
557 // check whether Traits::{Input,Output}Handle<T> is a valid type,
558 // if so, define {Input,Output}Handle_t<Traits,T> as being Traits::{Input,Output}Handle<T>
559 // else define as being DataObject{Read,,Write}Handle<T>
560 template <typename Tr, typename T>
562
563 template <typename Tr, typename T>
565
566 template <typename T>
567 inline constexpr bool is_event_context_v = std::is_same_v<std::remove_cvref_t<T>, EventContext>;
568
570 using KeyValue = std::pair<std::string, std::string>;
571 using KeyValues = std::pair<std::string, std::vector<std::string>>;
572
574 bool is_vector = false;
575
576 LocationSpec( std::string name_, std::string location_ )
577 : value{ std::move( name_ ), { std::move( location_ ) } } {}
578 LocationSpec( std::string name_, const char* location_ )
579 : LocationSpec{ std::move( name_ ), std::string{ location_ } } {}
580 LocationSpec( std::string name_, std::vector<std::string> locations_ )
581 : value{ std::move( name_ ), std::move( locations_ ) }, is_vector{ true } {}
582 LocationSpec( std::string name_, std::initializer_list<std::string> locations_ )
583 : LocationSpec{ std::move( name_ ), std::vector<std::string>{ locations_ } } {}
584
585 operator KeyValue() const {
586 if ( is_vector ) {
587 throw GaudiException( "Expected a scalar location specification", "Gaudi::Functional::details::LocationSpec",
589 }
590 return { value.first, value.second.front() };
591 }
592 operator KeyValues() const { return value; }
593 };
594
595 template <typename Arg>
599 template <>
601 using type = std::tuple<>;
602 };
603 template <typename T>
607 template <typename T>
611 template <typename Arg>
613
614 template <typename... Args>
615 using LocationSpecs_t = std::tuple<LocationSpec_t<Args>...>;
616
617 template <typename... Args>
619 using type = std::tuple<>;
620 };
621 template <typename First, typename... Rest>
622 struct TailLocationSpecs<First, Rest...> {
623 using type = LocationSpecs_t<Rest...>;
624 };
625 template <typename... Args>
626 using TailLocationSpecs_t = typename TailLocationSpecs<Args...>::type;
627
628 template <typename Tuple>
630 using type = std::tuple<>;
631 };
632 template <typename First, typename... Rest>
633 struct first_or_empty<std::tuple<First, Rest...>> {
634 using type = First;
635 };
636 template <typename Tuple>
638
639 template <typename Tuple, typename T>
640 inline constexpr bool tuple_elements_are_v = false;
641 template <typename T, typename... Elements>
642 inline constexpr bool tuple_elements_are_v<std::tuple<Elements...>, T> = ( std::same_as<Elements, T> && ... );
643
644 template <typename Tuple, typename T>
645 inline constexpr bool tuple_elements_constructible_from_v = false;
646 template <typename T, typename... Elements>
647 inline constexpr bool tuple_elements_constructible_from_v<std::tuple<Elements...>, T> =
648 ( std::constructible_from<Elements, T> && ... );
649
650 template <typename... Args>
651 inline constexpr bool first_is_event_context_v = false;
652 template <typename First, typename... Rest>
653 inline constexpr bool first_is_event_context_v<First, Rest...> = is_event_context_v<First>;
654
655 template <bool starts_with_event_context, typename InputSpecTuple>
656 inline constexpr auto empty_input_specs =
657 std::conditional_t<starts_with_event_context, InputSpecTuple, std::tuple<>>{};
658
659 template <typename Tuple, typename Spec, std::size_t... I>
660 Tuple location_specs_tuple( std::initializer_list<Spec> specs, std::index_sequence<I...>, const char* component ) {
661 if constexpr ( sizeof...( I ) == 1 ) {
662 if ( specs.size() == 0 ) return Tuple{ Spec{} };
663 }
664 if ( specs.size() != sizeof...( I ) ) {
665 throw GaudiException( "Wrong number of location specifications", component, StatusCode::FAILURE );
666 }
667 return Tuple{ *std::next( specs.begin(), I )... };
668 }
669
670 template <typename Tuple>
673
674 public:
675 static constexpr auto indices = std::make_index_sequence<std::tuple_size_v<Tuple>>{};
676
678 requires( std::tuple_size_v<Tuple> == 0 )
679 = default;
680 LocationSpecs( Tuple specs ) : m_specs{ std::move( specs ) } {}
681 template <typename... Specs>
682 LocationSpecs( Specs&&... specs )
683 requires( sizeof...( Specs ) > 0 && std::constructible_from<Tuple, Specs...> )
684 : m_specs{ std::forward<Specs>( specs )... } {}
685 template <typename... Args>
686 LocationSpecs( Args&&... args )
687 requires( sizeof...( Args ) > 1 && std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, Args...> )
688 : LocationSpecs{ First{ std::forward<Args>( args )... } } {}
689 LocationSpecs( std::string name, std::string loc )
690 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::string> )
691 : LocationSpecs{ First{ std::move( name ), std::move( loc ) } } {}
692 LocationSpecs( std::string name, std::vector<std::string> locs )
693 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::vector<std::string>> )
694 : LocationSpecs{ First{ std::move( name ), std::move( locs ) } } {}
695 LocationSpecs( std::initializer_list<First> specs )
696 requires( std::tuple_size_v<Tuple> > 0 && tuple_elements_are_v<Tuple, First> )
697 : m_specs{ location_specs_tuple<Tuple>( specs, indices, "Gaudi::Functional::details::LocationSpecs" ) } {}
698 LocationSpecs( std::initializer_list<LocationSpec> specs )
699 requires( std::tuple_size_v<Tuple> > 0 && !tuple_elements_are_v<Tuple, First> &&
701 : m_specs{ location_specs_tuple<Tuple>( specs, indices, "Gaudi::Functional::details::LocationSpecs" ) } {}
702
703 Tuple const& tuple() const { return m_specs; }
704 auto with_context() const { return std::tuple_cat( std::tuple<std::tuple<>>{}, m_specs ); }
705
706 private:
707 Tuple m_specs{};
708 };
709
710 template <typename Traits>
711 inline constexpr bool isLegacy =
712 std::is_base_of_v<Gaudi::details::LegacyAlgorithmAdapter, details::BaseClass_t<Traits>>;
713
715
716 template <typename Handle, typename Algo>
717 auto get( const Handle& handle, const Algo&,
718 const EventContext& ) -> decltype( details::deref( handle.get() ) ) // make it SFINAE friendly...
719 {
720 return details::deref( handle.get() );
721 }
722
723 template <typename Algo>
724 const EventContext& get( const EventContextHandle&, const Algo&, const EventContext& ctx ) {
725 return ctx;
726 }
727
728 template <template <typename> class Handle, typename In, typename Algo>
729 auto get( const HandleVector<Handle, In>& handle, const Algo&, const EventContext& ctx ) {
730 return handle.get( ctx );
731 }
732
733 template <typename IFace, typename Algo>
734 auto get( const ToolHandle<Gaudi::Interface::Bind::IBinder<IFace>>& handle, const Algo&, const EventContext& ctx ) {
735 return handle.bind( ctx );
736 }
737
738 template <typename Handle>
739 auto getKey( const Handle& h ) -> decltype( h.objKey() ) {
740 return h.objKey();
741 }
742
743 template <template <typename> class Handle, typename T>
744 auto getKey( const HandleVector<Handle, T>& h ) -> decltype( h.locations() ) {
745 return h.locations();
746 }
747
748 template <typename OutputSpec, typename InputSpec, typename Traits_>
750
751 template <typename Outputs, typename Traits_, typename... Args>
753
754 template <typename... Out, typename... In, typename Traits_>
755 requires( std::derived_from<BaseClass_t<Traits_>, Algorithm> && !std::disjunction_v<std::is_void<Out>...> )
757
758 public:
759 constexpr static std::size_t N_in = sizeof...( In );
760 constexpr static std::size_t N_out = sizeof...( Out );
761
762 private:
763 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
764 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, const IArgs& inputs, std::index_sequence<I...>,
765 const OArgs& outputs, std::index_sequence<J...> )
766 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator )
767 , m_inputs{ std::tuple_cat( std::forward_as_tuple( this ), std::get<I>( inputs ) )... }
768 , m_outputs{ std::tuple_cat( std::forward_as_tuple( this ), std::get<J>( outputs ) )... } {
769 // make sure this algorithm is seen as reentrant by Gaudi
770 this->setProperty( "Cardinality", 0 ).ignore();
771 }
772
773 using InputHandles = std::tuple<details::InputHandle_t<Traits_, In>...>;
774 using OutputHandles = std::tuple<details::OutputHandle_t<Traits_, Out>...>;
782 constexpr static std::size_t input_location_offset = starts_with_event_context ? 1 : 0;
783 constexpr static std::size_t N_input_locations = N_in - input_location_offset;
784 template <std::size_t N>
785 constexpr static std::size_t input_handle_index = N + input_location_offset;
786 template <std::size_t N>
787 using InputLocationHandle = std::tuple_element_t<input_handle_index<N>, InputHandles>;
788 template <std::size_t... I>
789 constexpr static bool input_locations_are_vectors( std::index_sequence<I...> ) {
791 }
792 constexpr static bool all_input_locations_are_vectors =
793 input_locations_are_vectors( std::make_index_sequence<N_input_locations>{} );
794
795 template <std::size_t... I>
796 auto input_location_handles( std::index_sequence<I...> ) const {
797 return std::forward_as_tuple( std::get<input_handle_index<I>>( m_inputs )... );
798 }
799
800 public:
803
804 // 0 -> 0, with the historic optional empty tuple arguments.
805 DataHandleMixin( std::string name, ISvcLocator* locator, std::tuple<> = {}, std::tuple<> = {} )
806 requires( N_in == 0 && N_out == 0 )
807 : DataHandleMixin( std::move( name ), locator, std::tuple<>{}, InputSpecs::indices, std::tuple<>{},
808 OutputSpecs::indices ) {}
809
810 // EventContext -> 0, where the context has no location argument.
811 DataHandleMixin( std::string name, ISvcLocator* locator )
812 requires( starts_with_event_context && N_in == 1 && N_out == 0 )
814 InputSpecs::indices, std::tuple<>{}, OutputSpecs::indices ) {}
815
816 // N -> 0
817 DataHandleMixin( std::string name, ISvcLocator* locator, InputSpecs const& inputs )
818 requires( N_in != 0 && N_out == 0 && !( starts_with_event_context && N_in == 1 ) )
819 : DataHandleMixin( std::move( name ), locator, inputs.tuple(), inputs.indices, std::tuple<>{},
820 OutputSpecs::indices ) {}
821
822 // Context-first backwards compatibility: the EventContext slot used to consume no input location argument.
823 DataHandleMixin( std::string name, ISvcLocator* locator, LegacyInputSpecs const& inputs )
824 requires( starts_with_event_context && N_in > 1 && N_out == 0 )
825 : DataHandleMixin( std::move( name ), locator, inputs.with_context(), InputSpecs::indices, std::tuple<>{},
826 OutputSpecs::indices ) {}
827
828 // 0 -> N and EventContext -> N
829 DataHandleMixin( std::string name, ISvcLocator* locator, OutputSpecs const& outputs )
830 requires( N_out != 0 && ( N_in == 0 || ( starts_with_event_context && N_in == 1 ) ) )
832 InputSpecs::indices, outputs.tuple(), outputs.indices ) {}
833
834 // N -> M, including EventContext-first legacy input syntax and explicit empty input tuple for 0 -> M.
835 DataHandleMixin( std::string name, ISvcLocator* locator, InputSpecs const& inputs, OutputSpecs const& outputs )
836 requires( N_out != 0 )
837 : DataHandleMixin( std::move( name ), locator, inputs.tuple(), inputs.indices, outputs.tuple(),
838 outputs.indices ) {}
839
840 DataHandleMixin( std::string name, ISvcLocator* locator, LegacyInputSpecs const& inputs,
841 OutputSpecs const& outputs )
842 requires( starts_with_event_context && N_in > 1 && N_out != 0 )
843 : DataHandleMixin( std::move( name ), locator, inputs.with_context(), InputSpecs::indices, outputs.tuple(),
844 outputs.indices ) {}
845
846 template <std::size_t N = 0>
847 decltype( auto ) inputLocation() const
848 requires( N_input_locations > N )
849 {
850 return getKey( std::get<input_handle_index<N>>( m_inputs ) );
851 }
852 template <typename T>
853 decltype( auto ) inputLocation() const
854 requires( N_input_locations > 0 && !is_event_context_v<T> )
855 {
856 return getKey( std::get<details::InputHandle_t<Traits_, std::decay_t<T>>>( m_inputs ) );
857 }
858 template <std::size_t N = 0>
859 decltype( auto ) inputLocation( unsigned int n ) const
861 {
862 return std::get<input_handle_index<N>>( m_inputs ).at( n ).key();
863 }
864 decltype( auto ) inputLocation( unsigned int i, unsigned int j ) const
866 {
867 return getLocations( input_location_handles( std::make_index_sequence<N_input_locations>{} ), i ).at( j ).key();
868 }
869 unsigned int inputLocationSize( unsigned int i ) const
870 requires( N_input_locations > 0 )
871 {
872 auto size = []( const auto& handle ) {
873 if constexpr ( location_vector_handle<std::decay_t<decltype( handle )>> ) {
874 return static_cast<unsigned int>( handle.size() );
875 } else {
876 return 1U;
877 }
878 };
879 return std::apply( [i = i + input_location_offset,
880 size]( const auto&... handles ) { return std::array{ size( handles )... }.at( i ); },
881 m_inputs );
882 }
883 // to remain backwards compatible (!), this has to return
884 // -- for non-merging transformers, the # of input _arguments_...
885 // -- for merging transformers, which only had _one_ input argument, which was not EventContext, the number of
886 // inputs of the first argument...
887 // FIXME: to be(come) unambiguous, this should be deprecated at some point, and replaced with a better named
888 // alternatives...
889 unsigned int inputLocationSize() const {
890 if constexpr ( !starts_with_event_context && N_input_locations == 1 &&
892 return inputLocationSize( 0 );
893 } else {
894 return N_input_locations;
895 }
896 }
897
898 template <std::size_t N = 0>
899 decltype( auto ) outputLocation() const
900 requires( N_out > 0 )
901 {
902 return getKey( std::get<N>( m_outputs ) );
903 }
904 template <typename T>
905 decltype( auto ) outputLocation() const
906 requires( N_out > 0 )
907 {
908 return getKey( std::get<details::OutputHandle_t<Traits_, std::decay_t<T>>>( m_outputs ) );
909 }
910 template <std::size_t N = 0>
911 decltype( auto ) outputLocation( unsigned int n ) const
913 {
914 return std::get<N>( m_outputs ).at( n ).key();
915 }
916 unsigned int outputLocationSize() const {
918 return std::get<0>( m_outputs ).size();
919 } else {
920 return N_out;
921 }
922 }
923
924 template <typename Algorithm>
925 decltype( auto ) invoke( const Algorithm& algo, const EventContext& ctx ) const {
926 return std::apply(
927 [&]( const auto&... handle ) -> decltype( auto ) { return algo( get( handle, algo, ctx )... ); }, m_inputs );
928 }
929
930 private:
932 bool isReEntrant() const override { return true; }
933
934 protected:
936 };
937
938 template <typename InputSpec, typename Traits_>
939 class DataHandleMixin<type_list<void>, InputSpec, Traits_> : public DataHandleMixin<type_list<>, InputSpec, Traits_> {
940 public:
941 using DataHandleMixin<type_list<>, InputSpec, Traits_>::DataHandleMixin;
942 };
943
944 template <typename OutHandles, typename Outputs>
945 void put_results( const OutHandles& out_handles, Outputs&& outputs ) {
946 [&]<std::size_t... I>( std::index_sequence<I...> ) {
947 ( put( std::get<I>( out_handles ), std::get<I>( std::forward<Outputs>( outputs ) ) ), ... );
948 }( std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Outputs>>>{} );
949 }
950
951 template <typename Algorithm, typename OutHandles = std::tuple<>>
952 StatusCode execute_single_output( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles = {} )
953 requires( std::tuple_size_v<OutHandles> <= 1 )
954 {
955 return execute( algo, [&] {
956 if constexpr ( std::tuple_size_v<OutHandles> == 0 ) {
957 algo.invoke( algo, ctx );
958 } else {
959 put( std::get<0>( out_handles ), algo.invoke( algo, ctx ) );
960 }
961 return FilterDecision::PASSED;
962 } );
963 }
964
965 template <typename Algorithm, typename OutHandles>
966 StatusCode execute_outputs( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles ) {
967 return execute( algo, [&] {
968 put_results( out_handles, algo.invoke( algo, ctx ) );
970 } );
971 }
972
973 template <typename Algorithm, typename OutHandles>
974 StatusCode execute_filtered_outputs( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles ) {
975 return execute( algo, [&] {
976 return std::apply(
977 [&]( bool passed, auto&&... data ) {
978 put_results( out_handles, std::forward_as_tuple( std::forward<decltype( data )>( data )... ) );
979 return passed;
980 },
981 algo.invoke( algo, ctx ) )
984 } );
985 }
986
987} // namespace Gaudi::Functional::details
988
989#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
DataHandleMixin(std::string name, ISvcLocator *pSvcLocator, const IArgs &inputs, std::index_sequence< I... >, const OArgs &outputs, std::index_sequence< J... >)
Definition details.h:764
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs)
Definition details.h:823
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs, OutputSpecs const &outputs)
Definition details.h:840
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs)
Definition details.h:817
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs, OutputSpecs const &outputs)
Definition details.h:835
DataHandleMixin(std::string name, ISvcLocator *locator, OutputSpecs const &outputs)
Definition details.h:829
decltype(auto) invoke(const Algorithm &algo, const EventContext &ctx) const
Definition details.h:925
std::tuple_element_t< input_handle_index< N >, InputHandles > InputLocationHandle
Definition details.h:787
DataHandleMixin(std::string name, ISvcLocator *locator, std::tuple<>={}, std::tuple<>={})
Definition details.h:805
HandleVector(std::tuple< A, K > &&tup)
Definition details.h:394
DataObjID const & at(size_t i) const
Definition details.h:420
HandleVector(Algorithm *parent, std::pair< std::string, std::vector< std::string > > const &keys)
Definition details.h:389
std::vector< DataObjID > const & locations() const
Definition details.h:419
HandleVector(std::tuple< A, Name, Keys > &&tup)
Definition details.h:396
std::vector< OutputHandleFor< Tr, Default >::template type< T > > const & handles() const
Definition details.h:418
LocationSpecs(std::string name, std::string loc)
Definition details.h:689
first_or_empty_t< Tuple > First
Definition details.h:672
LocationSpecs(std::string name, std::vector< std::string > locs)
Definition details.h:692
LocationSpecs(std::initializer_list< LocationSpec > specs)
Definition details.h:698
LocationSpecs(std::initializer_list< First > specs)
Definition details.h:695
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
constexpr reference operator[](difference_type n) const
Definition details.h:294
constexpr indirect_iterator operator++(int)
Definition details.h:243
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
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
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:129
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.
Gaudi::tagged_bool< class ImmediatelyInvokeHandler_tag > ImmediatelyInvokeHandler
Definition Property.h:23
typename Tr::BaseClass BaseClass_t
Definition details.h:482
typename DefaultInputHandle< T >::type DefaultInputHandle_t
Definition details.h:548
StatusCode execute_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
Definition details.h:966
typename detail2::InputHandle< T, Tr, detail2::DefaultInputHandle_t >::type InputHandle_t
Definition details.h:564
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
Definition details.h:717
decltype(auto) getLocations(Vectors const &vectors, unsigned int i)
Definition details.h:456
typename first_or_empty< Tuple >::type first_or_empty_t
Definition details.h:637
auto getKey(const Handle &h) -> decltype(h.objKey())
Definition details.h:739
constexpr auto empty_input_specs
Definition details.h:656
constexpr bool isLegacy
Definition details.h:711
typename TailLocationSpecs< Args... >::type TailLocationSpecs_t
Definition details.h:626
std::vector< DataObjID > to_DataObjID(const std::vector< std::string > &in)
Definition details.h:43
typename handle_vector_input< Arg >::type handle_vector_input_t
Definition details.h:440
auto put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
Definition details.h:107
constexpr bool tuple_elements_are_v
Definition details.h:640
std::tuple< LocationSpec_t< Args >... > LocationSpecs_t
Definition details.h:615
typename detail2::OutputHandle< T, Tr, DataObjectWriteHandle >::type OutputHandle_t
Definition details.h:561
StatusCode execute_single_output(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles={})
Definition details.h:952
constexpr bool first_is_event_context_v
Definition details.h:651
constexpr struct Gaudi::Functional::details::deref_t deref
constexpr bool is_handle_vector_input_v
Definition details.h:442
typename LocationSpecFor< std::remove_cvref_t< Arg > >::type LocationSpec_t
Definition details.h:612
typename details2::value_type_of< T >::type remove_optional_t
Definition details.h:74
constexpr bool is_event_context_v
Definition details.h:567
detail2::BaseClass< Tr, Default >::type BaseClass_t
Definition details.h:555
decltype(get_values_helper< Value >(std::make_index_sequence< N >())) RepeatValues_
Definition details.h:102
StatusCode execute_filtered_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
Definition details.h:974
auto get_values_helper(std::index_sequence< I... >)
Definition details.h:97
DataHandleMixin< Outputs, type_list< handle_vector_input_t< Args >... >, Traits_ > DataHandleVectorMixin
Definition details.h:752
StatusCode execute(CommonMessagingBase const &alg, F &&f)
Definition details.h:463
void put_results(const OutHandles &out_handles, Outputs &&outputs)
Definition details.h:945
Tuple location_specs_tuple(std::initializer_list< Spec > specs, std::index_sequence< I... >, const char *component)
Definition details.h:660
constexpr bool tuple_elements_constructible_from_v
Definition details.h:645
STL namespace.
Payload & operator=(Payload const &)=delete
Gaudi::Property< std::vector< DataObjID > > property
Definition details.h:364
Payload(Algorithm *parent, std::pair< std::string, std::vector< std::string > > const &keys)
Definition details.h:367
LocationSpec(std::string name_, std::vector< std::string > locations_)
Definition details.h:580
std::pair< std::string, std::string > KeyValue
Definition details.h:570
std::pair< std::string, std::vector< std::string > > KeyValues
Definition details.h:571
LocationSpec(std::string name_, std::initializer_list< std::string > locations_)
Definition details.h:582
LocationSpec(std::string name_, const char *location_)
Definition details.h:578
LocationSpec(std::string name_, std::string location_)
Definition details.h:576
const In & operator()(const In *in) const
Definition details.h:174
ToolHandle< Gaudi::Interface::Bind::IBinder< std::decay_t< T > > > type
Definition details.h:541
typename InputHandle< std::remove_pointer_t< T >, Tr, Default >::type type
Definition details.h:525
HandleVector< InputHandleFor< Tr, Default >::template type, T > type
Definition details.h:529
typename OutputHandle< remove_optional_t< T >, Tr, Default >::type type
Definition details.h:506
HandleVector< OutputHandleFor< Tr, Default >::template type, T > type
Definition details.h:510
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:79
void operator()(F &&f, Arg &&arg) const
Definition details.h:83