The Gaudi Framework  master (29688f1e)
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 template <template <typename> class Handle, typename I>
37 class HandleVector;
38
39 inline std::vector<DataObjID> to_DataObjID( const std::vector<std::string>& in ) {
40 std::vector<DataObjID> out;
41 out.reserve( in.size() );
42 std::transform( in.begin(), in.end(), std::back_inserter( out ),
43 []( const std::string& i ) { return DataObjID{ i }; } );
44 return out;
45 }
46
48 template <typename T>
49 concept is_optional = requires( T const& t ) {
50 t.has_value();
51 t.value();
52 typename T::value_type;
53 };
54
55 namespace details2 {
56
57 template <typename T>
59 using type = T;
60 };
61
62 template <is_optional T>
63 struct value_type_of<T> {
64 using type = T::value_type;
65 };
66
67 } // namespace details2
68
69 template <typename T>
71
72 constexpr struct invoke_optionally_t {
73 template <typename F, typename Arg>
74 requires( !is_optional<Arg> )
75 decltype( auto ) operator()( F&& f, Arg&& arg ) const {
76 return std::invoke( std::forward<F>( f ), std::forward<Arg>( arg ) );
77 }
78 template <typename F, is_optional Arg>
79 void operator()( F&& f, Arg&& arg ) const {
80 if ( arg ) std::invoke( std::forward<F>( f ), *std::forward<Arg>( arg ) );
81 }
82 } invoke_optionally{};
84#if 0
85 template <typename Value, auto>
86 using repeat_t = Value;
87 template <typename Value, auto N>
88 using RepeatValues_ =
89 decltype( []<std::size_t... I>( std::index_sequence<I...> ) -> std::tuple<repeat_t<Value, I>...> {
90 }( std::make_index_sequence<N>{} ) );
91#else
92 template <typename Value, std::size_t... I>
93 auto get_values_helper( std::index_sequence<I...> ) {
94 return std::make_tuple( ( (void)I, Value{} )... );
95 }
96
97 template <typename Value, auto N>
98 using RepeatValues_ = decltype( get_values_helper<Value>( std::make_index_sequence<N>() ) );
99#endif
100
102 template <std::derived_from<DataObject> Out1, std::convertible_to<Out1> Out2>
103 auto put( const DataObjectHandle<Out1>& out_handle, Out2&& out ) {
104 return out_handle.put( std::make_unique<Out1>( std::forward<Out2>( out ) ) );
105 }
106
107 template <typename Out1, std::convertible_to<Out1> Out2>
108 auto put( const DataObjectHandle<AnyDataWrapper<Out1>>& out_handle, Out2&& out ) {
109 return out_handle.put( std::forward<Out2>( out ) );
110 }
111
112 template <template <typename> class Handle, typename Out, typename Value>
113 auto put( const HandleVector<Handle, Out>& out_handle, Value&& out ) {
114 return out_handle.put( std::forward<Value>( out ) );
115 }
116
117 // optional put
118 template <typename OutHandle, typename OptOut>
119 requires( is_optional<OptOut> )
120 void put( const OutHandle& out_handle, OptOut&& out ) {
121 if ( out ) put( out_handle, *std::forward<OptOut>( out ) );
122 }
123
125 // adapt to differences between eg. std::vector (which has push_back) and KeyedContainer (which has insert)
126 // adapt to getting a T, and a container wanting T* by doing new T{ std::move(out) }
127 // adapt to getting a optional<T>
128
129 constexpr struct insert_t {
130 // for Container<T*>, return T
131 template <typename Container>
132 using c_remove_ptr_t = std::remove_pointer_t<typename Container::value_type>;
133
134 template <typename Container, typename Value>
135 auto operator()( Container& c, Value&& v ) const -> decltype( c.push_back( v ) ) {
136 return c.push_back( std::forward<Value>( v ) );
137 }
138
139 template <typename Container, typename Value>
140 auto operator()( Container& c, Value&& v ) const -> decltype( c.insert( v ) ) {
141 return c.insert( std::forward<Value>( v ) );
142 }
143
144 // Container<T*> with T&& as argument
145 template <typename Container, typename Value>
146 requires( std::is_pointer_v<typename Container::value_type> &&
147 std::is_convertible_v<Value, c_remove_ptr_t<Container>> )
148 auto operator()( Container& c, Value&& v ) const {
149 return operator()( c, new c_remove_ptr_t<Container>{ std::forward<Value>( v ) } );
150 }
151
152 } insert{};
153
155
156 constexpr struct deref_t {
157 template <typename In>
158 requires( !std::is_pointer_v<In> )
159 const In& operator()( const In& in ) const {
160 return in;
161 }
162
163 template <typename In>
164 requires( !std::is_pointer_v<std::decay_t<In>> )
165 In operator()( In&& in ) const {
166 return std::forward<In>( in );
167 }
168
169 template <typename In>
170 const In& operator()( const In* in ) const {
171 assert( in != nullptr );
172 return *in;
173 }
174 } deref{};
175
177 // if Container is a pointer, then we're optional items
178 namespace details2 {
179 template <typename T>
180 constexpr static bool is_gaudi_range_v = false;
181
182 template <typename T>
183 constexpr static bool is_gaudi_range_v<Gaudi::Range_<T>> = true;
184
185 template <typename T>
186 constexpr static bool is_gaudi_range_v<Gaudi::NamedRange_<T>> = true;
187
188 template <typename T>
189 constexpr static bool is_gaudi_range_v<std::optional<Gaudi::NamedRange_<T>>> = true;
190
191 template <typename In>
193 template <template <typename> class Handle, std::convertible_to<In> I>
194 auto operator()( const Handle<I>& h ) -> const In& {
195 return *h.get();
196 }
197 template <template <typename> class Handle, typename I>
198 auto operator()( const Handle<Gaudi::Range_<I>>& h ) -> In {
199 return h.get();
200 }
201 template <template <typename> class Handle, typename I>
202 auto operator()( const Handle<Gaudi::NamedRange_<I>>& h ) -> In {
203 return h.get();
204 }
205 template <template <typename> class Handle, typename I>
206 auto operator()( const Handle<std::optional<Gaudi::NamedRange_<I>>>& h ) -> In {
207 return h.get();
208 }
209 template <template <typename> class Handle, typename I>
210 requires( std::is_convertible_v<I*, In> )
211 auto operator()( const Handle<I>& h ) -> In {
212 return h.getIfExists();
213 } // In is-a pointer
214 };
215
216 template <typename Iterator>
218 using traits = std::iterator_traits<Iterator>;
220
221 public:
222 using iterator_category [[maybe_unused]] = typename traits::iterator_category;
223 using difference_type [[maybe_unused]] = typename traits::difference_type;
224 using reference = decltype( **m_iter );
225 using value_type [[maybe_unused]] = std::remove_reference_t<reference>;
226 using pointer [[maybe_unused]] = std::add_pointer_t<value_type>;
227
228 indirect_iterator() = default;
229 constexpr explicit indirect_iterator( Iterator i ) : m_iter( std::move( i ) ) {}
230
231 constexpr reference operator*() const { return **m_iter; }
232
233 constexpr bool operator==( const indirect_iterator& rhs ) const { return m_iter == rhs.m_iter; }
234
236 ++m_iter;
237 return *this;
238 }
239 constexpr indirect_iterator operator++( int ) {
240 auto i = *this;
241 ++*this;
242 return i;
243 }
244
245 // bidirectional iterator operations (if possible)
247 requires std::bidirectional_iterator<Iterator>
248 {
249 --m_iter;
250 return *this;
251 }
253 requires std::bidirectional_iterator<Iterator>
254 {
255 auto i = *this;
256 --*this;
257 return i;
258 }
259
260 // random access iterator operations (if possible)
261 constexpr indirect_iterator& operator+=( difference_type n )
262 requires std::random_access_iterator<Iterator>
263 {
264 m_iter += n;
265 return *this;
266 }
267 constexpr indirect_iterator operator+( difference_type n ) const
268 requires std::random_access_iterator<Iterator>
269 {
270 auto i = *this;
271 return i += n;
272 }
273 constexpr indirect_iterator& operator-=( difference_type n )
274 requires std::random_access_iterator<Iterator>
275 {
276 m_iter -= n;
277 return *this;
278 }
279 constexpr indirect_iterator operator-( difference_type n ) const
280 requires std::random_access_iterator<Iterator>
281 {
282 auto i = *this;
283 return i -= n;
284 }
285 constexpr difference_type operator-( const indirect_iterator& other ) const
286 requires std::random_access_iterator<Iterator>
287 {
288 return m_iter - other.m_iter;
289 }
290 constexpr reference operator[]( difference_type n ) const
291 requires std::random_access_iterator<Iterator>
292 {
293 return **( m_iter + n );
294 }
295 };
296
297 } // namespace details2
298
299 template <typename Container>
301 static constexpr bool is_pointer = std::is_pointer_v<Container>;
302 static constexpr bool is_range = details2::is_gaudi_range_v<Container>;
303 template <typename C>
304 using borrowed_value_t = std::add_const_t<std::remove_pointer_t<C>>;
305 // TODO: refuse pointer to a range... range must always be by value
307 using ptr_t = std::add_pointer_t<val_t>;
308 using ContainerVector = std::vector<std::conditional_t<is_range, std::remove_const_t<val_t>, ptr_t>>;
310
311 constexpr static decltype( auto ) wrap( ContainerVector::const_reference t ) {
312 if constexpr ( is_pointer || is_range ) {
313 return t;
314 } else {
315 return *t;
316 }
317 }
318 constexpr static auto wrap( ContainerVector::const_iterator i ) {
319 if constexpr ( is_pointer || is_range ) {
320 return i;
321 } else {
322 return details2::indirect_iterator{ i };
323 }
324 }
325
326 public:
327 using value_type = std::conditional_t<is_pointer, ptr_t, val_t>;
328 using size_type = typename ContainerVector::size_type;
329
330 vector_of_const_() = default;
331 void reserve( size_type size ) { m_containers.reserve( size ); }
332 template <typename T>
333 requires( is_pointer || is_range )
334 void push_back( T&& container ) {
335 m_containers.push_back( container );
336 }
337 template <typename C = Container>
338 requires( !std::is_pointer_v<C> && !details2::is_gaudi_range_v<C> )
339 void push_back( borrowed_value_t<C>& container ) {
340 // note: does not copy its argument, so we're not really a container...
341 m_containers.push_back( &container );
342 }
343 template <typename C = Container>
344 requires( !std::is_pointer_v<C> && !details2::is_gaudi_range_v<C> )
345 void push_back( borrowed_value_t<C>&& ) = delete;
346
347 auto begin() const { return wrap( m_containers.begin() ); }
348 auto end() const { return wrap( m_containers.end() ); }
349 decltype( auto ) front() const { return wrap( m_containers.front() ); }
350 decltype( auto ) back() const { return wrap( m_containers.back() ); }
351 decltype( auto ) operator[]( size_type i ) const { return wrap( m_containers[i] ); }
352 decltype( auto ) at( size_type i ) const { return wrap( m_containers.at( i ) ); }
353 size_type size() const { return m_containers.size(); }
354 };
355
356 template <template <typename> class Handle, typename I>
358 struct Payload {
359 std::vector<Handle<I>> handles;
361
362 template <typename Algorithm>
363 Payload( Algorithm* parent, std::pair<std::string, std::vector<std::string>> const& keys )
364 : property{ parent, keys.first, details::to_DataObjID( keys.second ),
365 [ptr = &handles, parent]( auto& self_ ) {
366 auto& self = dynamic_cast<Gaudi::Property<std::vector<DataObjID>>&>( self_ );
367 ptr->clear();
368 ptr->reserve( self.value().size() );
369 std::ranges::transform( self.value(), std::back_inserter( *ptr ),
370 [&]( const auto& location ) -> Handle<I> {
371 return { location, parent };
372 } );
373 },
375
376 Payload( Payload&& ) = delete;
377 Payload& operator=( Payload&& ) = delete;
378 Payload( Payload const& ) = delete;
379 Payload& operator=( Payload const& ) = delete;
380 };
381 std::unique_ptr<Payload> m_payload; // need a stable rendez-vous for the callback & property to work
382
383 public:
384 template <typename Algorithm>
385 HandleVector( Algorithm* parent, std::pair<std::string, std::vector<std::string>> const& keys )
386 : m_payload{ std::make_unique<Payload>( parent, keys ) } {}
387
388 // allow construction by DataHandleMixin
389 template <typename A, typename K>
390 HandleVector( std::tuple<A, K>&& tup ) : HandleVector{ std::get<0>( tup ), std::get<1>( tup ) } {}
391 template <typename A, typename Name, typename Keys>
392 HandleVector( std::tuple<A, Name, Keys>&& tup )
393 : HandleVector{ std::get<0>( tup ),
394 std::pair<std::string, std::vector<std::string>>{ std::get<1>( tup ), std::get<2>( tup ) } } {}
395
398 ins.reserve( m_payload->handles.size() );
399 std::ranges::transform( m_payload->handles, std::back_inserter( ins ), details2::get_from_handle<I>{} );
400 return ins;
401 }
402 template <typename Out>
403 void put( Out&& out ) const {
404 auto const n = size();
405 if ( out.size() != n ) {
406 throw GaudiException( "Error during transform in " +
407 std::string{ std::source_location::current().function_name() } + ": expected " +
408 std::to_string( n ) + " containers, got " + std::to_string( out.size() ) + " instead",
409 "Gaudi::Functional::details::HandleVector::put", StatusCode::FAILURE );
410 }
411 for ( std::size_t i = 0; i != n; ++i ) details::put( handles()[i], std::move( out[i] ) );
412 }
413
414 std::vector<Handle<I>> const& handles() const { return m_payload->handles; }
415 std::vector<DataObjID> const& locations() const { return m_payload->property.value(); }
416 DataObjID const& at( size_t i ) const { return m_payload->property.value().at( i ); }
417 auto size() const { return m_payload->handles.size(); }
418 };
419
420 template <typename T>
422 template <typename T>
424
425 template <typename Arg>
427 using type = Arg;
428 static constexpr bool is_range = false;
429 };
430 template <typename T>
433 static constexpr bool is_range = true;
434 };
435 template <typename Arg>
437 template <typename Arg>
439 template <typename... Args>
441
442 template <typename... T>
443 struct type_list {};
444
445 template <typename H>
446 concept location_vector_handle = requires( H const& h ) {
447 h.at( 0U ).key();
448 h.size();
449 };
450
451 template <typename Vectors>
452 decltype( auto ) getLocations( Vectors const& vectors, unsigned int i ) {
453 return std::apply(
454 [i]( auto const&... elems ) -> decltype( auto ) { return *std::array{ &elems.locations()... }.at( i ); },
455 vectors );
456 }
457
458 template <typename F>
460 try {
461 return std::forward<F>( f )();
462 } catch ( GaudiException& e ) {
463 if ( e.code().isFailure() ) alg.error() << e.tag() << " : " << e.message() << endmsg;
464 return e.code();
465 }
466 }
467
470 template <typename Algo>
471 EventContextHandle( std::tuple<Algo> ) {}
472 };
473
474 namespace detail2 { // utilities for detected_or_t{,_} usage
475
476 // keep only for backwards compatibility... for now.
477 template <typename Tr>
478 using BaseClass_t = typename Tr::BaseClass;
479
480 template <typename Tr, typename Default>
481 struct BaseClass {
482 using type = Default;
483 };
484 template <typename Tr, typename Default>
485 requires requires { typename Tr::BaseClass; }
486 struct BaseClass<Tr, Default> {
487 using type = Tr::BaseClass;
488 };
489
490 template <typename T, typename Tr, template <typename...> typename Default>
492 using type = Default<T>;
493 };
494 template <typename T, typename Tr, template <typename...> typename Default>
495 requires requires { typename Tr::template OutputHandle<T>; }
496 struct OutputHandle<T, Tr, Default> {
497 using type = Tr::template OutputHandle<T>;
498 };
499 template <typename Tr, template <typename...> typename Default>
501 template <typename T>
503 };
504 template <typename T, typename Tr, template <typename...> typename Default>
508
509 template <typename T, typename Tr, template <typename...> typename Default>
510 struct InputHandle {
511 using type = Default<T>;
512 };
513 template <typename T, typename Tr, template <typename...> typename Default>
514 requires requires { typename Tr::template InputHandle<T>; }
515 struct InputHandle<T, Tr, Default> {
516 using type = Tr::template InputHandle<T>;
517 };
518 template <typename Tr, template <typename...> typename Default>
520 template <typename T>
522 };
523 template <typename T, typename Tr, template <typename...> typename Default>
527
528 template <typename T>
529 concept algtool_interface = std::derived_from<std::decay_t<T>, IAlgTool>;
530
531 template <typename T>
535 template <algtool_interface T>
539 template <>
543 template <typename T>
545 } // namespace detail2
546
547 // check whether Tr::BaseClass is a valid type,
548 // if so, define BaseClass_t<Tr> as being Tr::BaseClass
549 // else define as being Gaudi::Algorithm
550 template <typename Tr, typename Default = Gaudi::Algorithm>
552
553 // check whether Traits::{Input,Output}Handle<T> is a valid type,
554 // if so, define {Input,Output}Handle_t<Traits,T> as being Traits::{Input,Output}Handle<T>
555 // else define as being DataObject{Read,,Write}Handle<T>
556 template <typename Tr, typename T>
558
559 template <typename Tr, typename T>
561
562 template <typename T>
563 inline constexpr bool is_event_context_v = std::is_same_v<std::remove_cvref_t<T>, EventContext>;
564
566 using KeyValue = std::pair<std::string, std::string>;
567 using KeyValues = std::pair<std::string, std::vector<std::string>>;
568
570 bool is_vector = false;
571
572 LocationSpec( std::string name_, std::string location_ )
573 : value{ std::move( name_ ), { std::move( location_ ) } } {}
574 LocationSpec( std::string name_, const char* location_ )
575 : LocationSpec{ std::move( name_ ), std::string{ location_ } } {}
576 LocationSpec( std::string name_, std::vector<std::string> locations_ )
577 : value{ std::move( name_ ), std::move( locations_ ) }, is_vector{ true } {}
578 LocationSpec( std::string name_, std::initializer_list<std::string> locations_ )
579 : LocationSpec{ std::move( name_ ), std::vector<std::string>{ locations_ } } {}
580
581 operator KeyValue() const {
582 if ( is_vector ) {
583 throw GaudiException( "Expected a scalar location specification", "Gaudi::Functional::details::LocationSpec",
585 }
586 return { value.first, value.second.front() };
587 }
588 operator KeyValues() const { return value; }
589 };
590
591 template <typename Arg>
595 template <>
597 using type = std::tuple<>;
598 };
599 template <typename T>
603 template <typename T>
607 template <typename Arg>
609
610 template <typename... Args>
611 using LocationSpecs_t = std::tuple<LocationSpec_t<Args>...>;
612
613 template <typename... Args>
615 using type = std::tuple<>;
616 };
617 template <typename First, typename... Rest>
618 struct TailLocationSpecs<First, Rest...> {
619 using type = LocationSpecs_t<Rest...>;
620 };
621 template <typename... Args>
622 using TailLocationSpecs_t = typename TailLocationSpecs<Args...>::type;
623
624 template <typename Tuple>
626 using type = std::tuple<>;
627 };
628 template <typename First, typename... Rest>
629 struct first_or_empty<std::tuple<First, Rest...>> {
630 using type = First;
631 };
632 template <typename Tuple>
634
635 template <typename Tuple, typename T>
636 inline constexpr bool tuple_elements_are_v = false;
637 template <typename T, typename... Elements>
638 inline constexpr bool tuple_elements_are_v<std::tuple<Elements...>, T> = ( std::same_as<Elements, T> && ... );
639
640 template <typename Tuple, typename T>
641 inline constexpr bool tuple_elements_constructible_from_v = false;
642 template <typename T, typename... Elements>
643 inline constexpr bool tuple_elements_constructible_from_v<std::tuple<Elements...>, T> =
644 ( std::constructible_from<Elements, T> && ... );
645
646 template <typename... Args>
647 inline constexpr bool first_is_event_context_v = false;
648 template <typename First, typename... Rest>
649 inline constexpr bool first_is_event_context_v<First, Rest...> = is_event_context_v<First>;
650
651 template <bool starts_with_event_context, typename InputSpecTuple>
652 inline constexpr auto empty_input_specs =
653 std::conditional_t<starts_with_event_context, InputSpecTuple, std::tuple<>>{};
654
655 template <typename Tuple, typename Spec, std::size_t... I>
656 Tuple location_specs_tuple( std::initializer_list<Spec> specs, std::index_sequence<I...>, const char* component ) {
657 if constexpr ( sizeof...( I ) == 1 ) {
658 if ( specs.size() == 0 ) return Tuple{ Spec{} };
659 }
660 if ( specs.size() != sizeof...( I ) ) {
661 throw GaudiException( "Wrong number of location specifications", component, StatusCode::FAILURE );
662 }
663 return Tuple{ *std::next( specs.begin(), I )... };
664 }
665
666 template <typename Tuple>
669
670 public:
671 static constexpr auto indices = std::make_index_sequence<std::tuple_size_v<Tuple>>{};
672
674 requires( std::tuple_size_v<Tuple> == 0 )
675 = default;
676 LocationSpecs( Tuple specs ) : m_specs{ std::move( specs ) } {}
677 template <typename... Specs>
678 LocationSpecs( Specs&&... specs )
679 requires( sizeof...( Specs ) > 0 && std::constructible_from<Tuple, Specs...> )
680 : m_specs{ std::forward<Specs>( specs )... } {}
681 template <typename... Args>
682 LocationSpecs( Args&&... args )
683 requires( sizeof...( Args ) > 1 && std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, Args...> )
684 : LocationSpecs{ First{ std::forward<Args>( args )... } } {}
685 LocationSpecs( std::string name, std::string loc )
686 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::string> )
687 : LocationSpecs{ First{ std::move( name ), std::move( loc ) } } {}
688 LocationSpecs( std::string name, std::vector<std::string> locs )
689 requires( std::tuple_size_v<Tuple> == 1 && std::constructible_from<First, std::string, std::vector<std::string>> )
690 : LocationSpecs{ First{ std::move( name ), std::move( locs ) } } {}
691 LocationSpecs( std::initializer_list<First> specs )
692 requires( std::tuple_size_v<Tuple> > 0 && tuple_elements_are_v<Tuple, First> )
693 : m_specs{ location_specs_tuple<Tuple>( specs, indices, "Gaudi::Functional::details::LocationSpecs" ) } {}
694 LocationSpecs( std::initializer_list<LocationSpec> specs )
695 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
699 Tuple const& tuple() const { return m_specs; }
700 auto with_context() const { return std::tuple_cat( std::tuple<std::tuple<>>{}, m_specs ); }
701
702 private:
703 Tuple m_specs{};
704 };
705
706 template <typename Traits>
707 inline constexpr bool isLegacy =
708 std::is_base_of_v<Gaudi::details::LegacyAlgorithmAdapter, details::BaseClass_t<Traits>>;
709
711
712 template <typename Handle, typename Algo>
713 auto get( const Handle& handle, const Algo&,
714 const EventContext& ) -> decltype( details::deref( handle.get() ) ) // make it SFINAE friendly...
715 {
716 return details::deref( handle.get() );
717 }
718
719 template <typename Algo>
720 const EventContext& get( const EventContextHandle&, const Algo&, const EventContext& ctx ) {
721 return ctx;
722 }
723
724 template <template <typename> class Handle, typename In, typename Algo>
725 auto get( const HandleVector<Handle, In>& handle, const Algo&, const EventContext& ctx ) {
726 return handle.get( ctx );
727 }
728
729 template <typename IFace, typename Algo>
730 auto get( const ToolHandle<Gaudi::Interface::Bind::IBinder<IFace>>& handle, const Algo&, const EventContext& ctx ) {
731 return handle.bind( ctx );
732 }
733
734 template <typename Handle>
735 auto getKey( const Handle& h ) -> decltype( h.objKey() ) {
736 return h.objKey();
737 }
738
739 template <template <typename> class Handle, typename T>
740 auto getKey( const HandleVector<Handle, T>& h ) -> decltype( h.locations() ) {
741 return h.locations();
742 }
743
744 template <typename OutputSpec, typename InputSpec, typename Traits_>
745 class DataHandleMixin;
746
747 template <typename Outputs, typename Traits_, typename... Args>
749
750 template <typename... Out, typename... In, typename Traits_>
751 requires( std::derived_from<BaseClass_t<Traits_>, Algorithm> && !std::disjunction_v<std::is_void<Out>...> )
753
754 public:
755 constexpr static std::size_t N_in = sizeof...( In );
756 constexpr static std::size_t N_out = sizeof...( Out );
757
758 private:
759 template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
760 DataHandleMixin( std::string name, ISvcLocator* pSvcLocator, const IArgs& inputs, std::index_sequence<I...>,
761 const OArgs& outputs, std::index_sequence<J...> )
762 : BaseClass_t<Traits_>( std::move( name ), pSvcLocator )
763 , m_inputs{ std::tuple_cat( std::forward_as_tuple( this ), std::get<I>( inputs ) )... }
764 , m_outputs{ std::tuple_cat( std::forward_as_tuple( this ), std::get<J>( outputs ) )... } {
765 // make sure this algorithm is seen as reentrant by Gaudi
766 this->setProperty( "Cardinality", 0 ).ignore();
767 }
768
769 using InputHandles = std::tuple<details::InputHandle_t<Traits_, In>...>;
770 using OutputHandles = std::tuple<details::OutputHandle_t<Traits_, Out>...>;
778 constexpr static std::size_t input_location_offset = starts_with_event_context ? 1 : 0;
779 constexpr static std::size_t N_input_locations = N_in - input_location_offset;
780 template <std::size_t N>
781 constexpr static std::size_t input_handle_index = N + input_location_offset;
782 template <std::size_t N>
783 using InputLocationHandle = std::tuple_element_t<input_handle_index<N>, InputHandles>;
784 template <std::size_t... I>
785 constexpr static bool input_locations_are_vectors( std::index_sequence<I...> ) {
787 }
788 constexpr static bool all_input_locations_are_vectors =
789 input_locations_are_vectors( std::make_index_sequence<N_input_locations>{} );
790
791 template <std::size_t... I>
792 auto input_location_handles( std::index_sequence<I...> ) const {
793 return std::forward_as_tuple( std::get<input_handle_index<I>>( m_inputs )... );
794 }
795
796 public:
799
800 // 0 -> 0, with the historic optional empty tuple arguments.
801 DataHandleMixin( std::string name, ISvcLocator* locator, std::tuple<> = {}, std::tuple<> = {} )
802 requires( N_in == 0 && N_out == 0 )
803 : DataHandleMixin( std::move( name ), locator, std::tuple<>{}, InputSpecs::indices, std::tuple<>{},
804 OutputSpecs::indices ) {}
805
806 // EventContext -> 0, where the context has no location argument.
807 DataHandleMixin( std::string name, ISvcLocator* locator )
808 requires( starts_with_event_context && N_in == 1 && N_out == 0 )
810 InputSpecs::indices, std::tuple<>{}, OutputSpecs::indices ) {}
811
812 // N -> 0
813 DataHandleMixin( std::string name, ISvcLocator* locator, InputSpecs const& inputs )
814 requires( N_in != 0 && N_out == 0 && !( starts_with_event_context && N_in == 1 ) )
815 : DataHandleMixin( std::move( name ), locator, inputs.tuple(), inputs.indices, std::tuple<>{},
816 OutputSpecs::indices ) {}
817
818 // Context-first backwards compatibility: the EventContext slot used to consume no input location argument.
819 DataHandleMixin( std::string name, ISvcLocator* locator, LegacyInputSpecs const& inputs )
820 requires( starts_with_event_context && N_in > 1 && N_out == 0 )
821 : DataHandleMixin( std::move( name ), locator, inputs.with_context(), InputSpecs::indices, std::tuple<>{},
822 OutputSpecs::indices ) {}
823
824 // 0 -> N and EventContext -> N
825 DataHandleMixin( std::string name, ISvcLocator* locator, OutputSpecs const& outputs )
826 requires( N_out != 0 && ( N_in == 0 || ( starts_with_event_context && N_in == 1 ) ) )
828 InputSpecs::indices, outputs.tuple(), outputs.indices ) {}
829
830 // N -> M, including EventContext-first legacy input syntax and explicit empty input tuple for 0 -> M.
831 DataHandleMixin( std::string name, ISvcLocator* locator, InputSpecs const& inputs, OutputSpecs const& outputs )
832 requires( N_out != 0 )
833 : DataHandleMixin( std::move( name ), locator, inputs.tuple(), inputs.indices, outputs.tuple(),
834 outputs.indices ) {}
835
836 DataHandleMixin( std::string name, ISvcLocator* locator, LegacyInputSpecs const& inputs,
837 OutputSpecs const& outputs )
838 requires( starts_with_event_context && N_in > 1 && N_out != 0 )
839 : DataHandleMixin( std::move( name ), locator, inputs.with_context(), InputSpecs::indices, outputs.tuple(),
840 outputs.indices ) {}
841
842 template <std::size_t N = 0>
843 decltype( auto ) inputLocation() const
844 requires( N_input_locations > N )
845 {
846 return getKey( std::get<input_handle_index<N>>( m_inputs ) );
847 }
848 template <typename T>
849 decltype( auto ) inputLocation() const
850 requires( N_input_locations > 0 && !is_event_context_v<T> )
851 {
852 return getKey( std::get<details::InputHandle_t<Traits_, std::decay_t<T>>>( m_inputs ) );
853 }
854 template <std::size_t N = 0>
855 decltype( auto ) inputLocation( unsigned int n ) const
857 {
858 return std::get<input_handle_index<N>>( m_inputs ).at( n ).key();
859 }
860 decltype( auto ) inputLocation( unsigned int i, unsigned int j ) const
862 {
863 return getLocations( input_location_handles( std::make_index_sequence<N_input_locations>{} ), i ).at( j ).key();
864 }
865 unsigned int inputLocationSize( unsigned int i ) const
866 requires( N_input_locations > 0 )
867 {
868 auto size = []( const auto& handle ) {
869 if constexpr ( location_vector_handle<std::decay_t<decltype( handle )>> ) {
870 return static_cast<unsigned int>( handle.size() );
871 } else {
872 return 1U;
873 }
874 };
875 return std::apply( [i = i + input_location_offset,
876 size]( const auto&... handles ) { return std::array{ size( handles )... }.at( i ); },
877 m_inputs );
878 }
879 // to remain backwards compatible (!), this has to return
880 // -- for non-merging transformers, the # of input _arguments_...
881 // -- for merging transformers, which only had _one_ input argument, which was not EventContext, the number of
882 // inputs of the first argument...
883 // FIXME: to be(come) unambiguous, this should be deprecated at some point, and replaced with a better named
884 // alternatives...
885 unsigned int inputLocationSize() const {
886 if constexpr ( !starts_with_event_context && N_input_locations == 1 &&
888 return inputLocationSize( 0 );
889 } else {
890 return N_input_locations;
891 }
892 }
893
894 template <std::size_t N = 0>
895 decltype( auto ) outputLocation() const
896 requires( N_out > 0 )
897 {
898 return getKey( std::get<N>( m_outputs ) );
899 }
900 template <typename T>
901 decltype( auto ) outputLocation() const
902 requires( N_out > 0 )
903 {
904 return getKey( std::get<details::OutputHandle_t<Traits_, std::decay_t<T>>>( m_outputs ) );
905 }
906 template <std::size_t N = 0>
907 decltype( auto ) outputLocation( unsigned int n ) const
909 {
910 return std::get<N>( m_outputs ).at( n ).key();
911 }
912 unsigned int outputLocationSize() const {
914 return std::get<0>( m_outputs ).size();
915 } else {
916 return N_out;
917 }
918 }
919
920 template <typename Algorithm>
921 decltype( auto ) invoke( const Algorithm& algo, const EventContext& ctx ) const {
922 return std::apply(
923 [&]( const auto&... handle ) -> decltype( auto ) { return algo( get( handle, algo, ctx )... ); }, m_inputs );
924 }
925
926 private:
928 bool isReEntrant() const override { return true; }
929
930 protected:
932 };
933
934 template <typename InputSpec, typename Traits_>
935 class DataHandleMixin<type_list<void>, InputSpec, Traits_> : public DataHandleMixin<type_list<>, InputSpec, Traits_> {
936 public:
937 using DataHandleMixin<type_list<>, InputSpec, Traits_>::DataHandleMixin;
938 };
939
940 template <typename OutHandles, typename Outputs>
941 void put_results( const OutHandles& out_handles, Outputs&& outputs ) {
942 [&]<std::size_t... I>( std::index_sequence<I...> ) {
943 ( put( std::get<I>( out_handles ), std::get<I>( std::forward<Outputs>( outputs ) ) ), ... );
944 }( std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Outputs>>>{} );
945 }
946
947 template <typename Algorithm, typename OutHandles = std::tuple<>>
948 StatusCode execute_single_output( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles = {} )
949 requires( std::tuple_size_v<OutHandles> <= 1 )
950 {
951 return execute( algo, [&] {
952 if constexpr ( std::tuple_size_v<OutHandles> == 0 ) {
953 algo.invoke( algo, ctx );
954 } else {
955 put( std::get<0>( out_handles ), algo.invoke( algo, ctx ) );
956 }
957 return FilterDecision::PASSED;
958 } );
959 }
960
961 template <typename Algorithm, typename OutHandles>
962 StatusCode execute_outputs( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles ) {
963 return execute( algo, [&] {
964 put_results( out_handles, algo.invoke( algo, ctx ) );
966 } );
967 }
968
969 template <typename Algorithm, typename OutHandles>
970 StatusCode execute_filtered_outputs( const Algorithm& algo, const EventContext& ctx, const OutHandles& out_handles ) {
971 return execute( algo, [&] {
972 return std::apply(
973 [&]( bool passed, auto&&... data ) {
974 put_results( out_handles, std::forward_as_tuple( std::forward<decltype( data )>( data )... ) );
975 return passed;
976 },
977 algo.invoke( algo, ctx ) )
980 } );
981 }
982
983} // namespace Gaudi::Functional::details
984
985#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:760
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs)
Definition details.h:819
DataHandleMixin(std::string name, ISvcLocator *locator, LegacyInputSpecs const &inputs, OutputSpecs const &outputs)
Definition details.h:836
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs)
Definition details.h:813
DataHandleMixin(std::string name, ISvcLocator *locator, InputSpecs const &inputs, OutputSpecs const &outputs)
Definition details.h:831
DataHandleMixin(std::string name, ISvcLocator *locator, OutputSpecs const &outputs)
Definition details.h:825
decltype(auto) invoke(const Algorithm &algo, const EventContext &ctx) const
Definition details.h:921
std::tuple_element_t< input_handle_index< N >, InputHandles > InputLocationHandle
Definition details.h:783
DataHandleMixin(std::string name, ISvcLocator *locator, std::tuple<>={}, std::tuple<>={})
Definition details.h:801
HandleVector(std::tuple< A, K > &&tup)
Definition details.h:390
DataObjID const & at(size_t i) const
Definition details.h:416
HandleVector(Algorithm *parent, std::pair< std::string, std::vector< std::string > > const &keys)
Definition details.h:385
std::vector< DataObjID > const & locations() const
Definition details.h:415
HandleVector(std::tuple< A, Name, Keys > &&tup)
Definition details.h:392
std::vector< OutputHandleFor< Tr, Default >::template type< T > > const & handles() const
Definition details.h:414
LocationSpecs(std::string name, std::string loc)
Definition details.h:685
first_or_empty_t< Tuple > First
Definition details.h:668
LocationSpecs(std::string name, std::vector< std::string > locs)
Definition details.h:688
LocationSpecs(std::initializer_list< LocationSpec > specs)
Definition details.h:694
LocationSpecs(std::initializer_list< First > specs)
Definition details.h:691
constexpr indirect_iterator & operator+=(difference_type n)
Definition details.h:261
constexpr indirect_iterator operator--(int)
Definition details.h:252
constexpr indirect_iterator & operator-=(difference_type n)
Definition details.h:273
constexpr indirect_iterator operator+(difference_type n) const
Definition details.h:267
constexpr bool operator==(const indirect_iterator &rhs) const
Definition details.h:233
constexpr indirect_iterator operator-(difference_type n) const
Definition details.h:279
constexpr difference_type operator-(const indirect_iterator &other) const
Definition details.h:285
constexpr reference operator[](difference_type n) const
Definition details.h:290
constexpr indirect_iterator operator++(int)
Definition details.h:239
static constexpr decltype(auto) wrap(ContainerVector::const_reference t)
Definition details.h:311
static constexpr auto wrap(ContainerVector::const_iterator i)
Definition details.h:318
std::add_pointer_t< val_t > ptr_t
Definition details.h:307
void push_back(borrowed_value_t< C > &&)=delete
std::add_const_t< std::remove_pointer_t< C > > borrowed_value_t
Definition details.h:304
void push_back(borrowed_value_t< C > &container)
Definition details.h:339
typename ContainerVector::size_type size_type
Definition details.h:328
std::vector< std::conditional_t< is_range, std::remove_const_t< val_t >, ptr_t > > ContainerVector
Definition details.h:308
std::conditional_t< is_pointer, ptr_t, val_t > value_type
Definition details.h:327
borrowed_value_t< Container > val_t
Definition details.h:306
decltype(auto) at(size_type i) const
Definition details.h:352
Implementation of property with value of concrete type.
Definition Property.h:35
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.
Gaudi::tagged_bool< class ImmediatelyInvokeHandler_tag > ImmediatelyInvokeHandler
Definition Property.h:23
typename Tr::BaseClass BaseClass_t
Definition details.h:478
typename DefaultInputHandle< T >::type DefaultInputHandle_t
Definition details.h:544
StatusCode execute_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
Definition details.h:962
typename detail2::InputHandle< T, Tr, detail2::DefaultInputHandle_t >::type InputHandle_t
Definition details.h:560
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
Definition details.h:713
decltype(auto) getLocations(Vectors const &vectors, unsigned int i)
Definition details.h:452
typename first_or_empty< Tuple >::type first_or_empty_t
Definition details.h:633
auto getKey(const Handle &h) -> decltype(h.objKey())
Definition details.h:735
constexpr auto empty_input_specs
Definition details.h:652
constexpr bool isLegacy
Definition details.h:707
typename TailLocationSpecs< Args... >::type TailLocationSpecs_t
Definition details.h:622
std::vector< DataObjID > to_DataObjID(const std::vector< std::string > &in)
Definition details.h:39
typename handle_vector_input< Arg >::type handle_vector_input_t
Definition details.h:436
auto put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
Definition details.h:103
constexpr bool tuple_elements_are_v
Definition details.h:636
std::tuple< LocationSpec_t< Args >... > LocationSpecs_t
Definition details.h:611
typename detail2::OutputHandle< T, Tr, DataObjectWriteHandle >::type OutputHandle_t
Definition details.h:557
StatusCode execute_single_output(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles={})
Definition details.h:948
constexpr bool first_is_event_context_v
Definition details.h:647
constexpr struct Gaudi::Functional::details::deref_t deref
constexpr bool is_handle_vector_input_v
Definition details.h:438
typename LocationSpecFor< std::remove_cvref_t< Arg > >::type LocationSpec_t
Definition details.h:608
typename details2::value_type_of< T >::type remove_optional_t
Definition details.h:70
constexpr bool is_event_context_v
Definition details.h:563
detail2::BaseClass< Tr, Default >::type BaseClass_t
Definition details.h:551
decltype(get_values_helper< Value >(std::make_index_sequence< N >())) RepeatValues_
Definition details.h:98
StatusCode execute_filtered_outputs(const Algorithm &algo, const EventContext &ctx, const OutHandles &out_handles)
Definition details.h:970
auto get_values_helper(std::index_sequence< I... >)
Definition details.h:93
DataHandleMixin< Outputs, type_list< handle_vector_input_t< Args >... >, Traits_ > DataHandleVectorMixin
Definition details.h:748
StatusCode execute(CommonMessagingBase const &alg, F &&f)
Definition details.h:459
void put_results(const OutHandles &out_handles, Outputs &&outputs)
Definition details.h:941
Tuple location_specs_tuple(std::initializer_list< Spec > specs, std::index_sequence< I... >, const char *component)
Definition details.h:656
constexpr bool tuple_elements_constructible_from_v
Definition details.h:641
STL namespace.
Payload & operator=(Payload const &)=delete
Gaudi::Property< std::vector< DataObjID > > property
Definition details.h:360
Payload(Algorithm *parent, std::pair< std::string, std::vector< std::string > > const &keys)
Definition details.h:363
LocationSpec(std::string name_, std::vector< std::string > locations_)
Definition details.h:576
std::pair< std::string, std::string > KeyValue
Definition details.h:566
std::pair< std::string, std::vector< std::string > > KeyValues
Definition details.h:567
LocationSpec(std::string name_, std::initializer_list< std::string > locations_)
Definition details.h:578
LocationSpec(std::string name_, const char *location_)
Definition details.h:574
LocationSpec(std::string name_, std::string location_)
Definition details.h:572
const In & operator()(const In *in) const
Definition details.h:170
ToolHandle< Gaudi::Interface::Bind::IBinder< std::decay_t< T > > > type
Definition details.h:537
HandleVector< InputHandleFor< Tr, Default >::template type, T > type
Definition details.h:525
typename InputHandle< std::remove_pointer_t< T >, Tr, Default >::type type
Definition details.h:521
HandleVector< OutputHandleFor< Tr, Default >::template type, T > type
Definition details.h:506
typename OutputHandle< remove_optional_t< T >, Tr, Default >::type type
Definition details.h:502
auto operator()(const Handle< std::optional< Gaudi::NamedRange_< I > > > &h) -> In
Definition details.h:206
auto operator()(const Handle< I > &h) -> const In &
Definition details.h:194
auto operator()(const Handle< Gaudi::NamedRange_< I > > &h) -> In
Definition details.h:202
auto operator()(const Handle< Gaudi::Range_< I > > &h) -> In
Definition details.h:198
std::remove_pointer_t< typename Container::value_type > c_remove_ptr_t
Definition details.h:132
auto operator()(Container &c, Value &&v) const -> decltype(c.push_back(v))
Definition details.h:135
auto operator()(Container &c, Value &&v) const -> decltype(c.insert(v))
Definition details.h:140
void operator()(F &&f, Arg &&arg) const
Definition details.h:79
decltype(auto) operator()(F &&f, Arg &&arg) const
Definition details.h:75