The Gaudi Framework  v28r3 (cc1cf868)
FunctionalDetails.h
Go to the documentation of this file.
1 #ifndef FUNCTIONAL_DETAILS_H
2 #define FUNCTIONAL_DETAILS_H
3 
4 #include <type_traits>
5 #include <stdexcept>
6 #include <cassert>
7 #include <sstream>
8 
9 // TODO: fwd declare instead?
13 #include "GaudiKernel/Algorithm.h"
15 
16 // Boost
17 #include "boost/optional.hpp"
18 
19 // Range V3
20 #include <range/v3/view/zip.hpp>
21 #include <range/v3/view/const.hpp>
22 
23 namespace Gaudi { namespace Functional { namespace details {
24 
25  // CRJ : Stuff for zipping
26  namespace zip
27  {
28 
30  template <typename OS, typename Arg>
31  void printSizes(OS& out, Arg&& arg)
32  {
33  out << "SizeOf'" << System::typeinfoName(typeid(Arg))
34  << "'=" << std::forward<Arg>(arg).size();
35  }
36 
38  template <typename OS, typename Arg, typename... Args>
39  void printSizes(OS& out, Arg&& arg, Args&&... args)
40  {
41  printSizes(out,arg); out << ", "; printSizes(out,args...);
42  }
43 
45  template < typename A >
46  inline bool check_sizes( const A& ) noexcept { return true; }
47 
49  template < typename A, typename B >
50  inline bool check_sizes( const A& a, const B& b ) noexcept
51  {
52  return a.size() == b.size();
53  }
54 
56  template < typename A, typename B, typename... C >
57  inline bool check_sizes( const A& a, const B& b, const C& ... c ) noexcept
58  {
59  return ( check_sizes(a,b) && check_sizes(b,c...) );
60  }
61 
63  template< typename... Args >
64  inline decltype(auto) verifySizes( Args&... args )
65  {
66  if ( UNLIKELY( !check_sizes( args... ) ) )
67  {
68  std::ostringstream mess;
69  mess << "Zipped containers have different sizes : ";
70  printSizes(mess,args...);
71  throw GaudiException( mess.str(),
72  "Gaudi::Functional::details::zip::verifySizes",
74  }
75  }
76 
78  template< typename... Args >
79  inline decltype(auto) range( Args&& ... args )
80  {
81  //assert( check_sizes( args... ) );
82  verifySizes( args... );
83  return ranges::view::zip( std::forward<Args>(args)... );
84  }
85 
87  template< typename... Args >
88  inline decltype(auto) const_range( Args&& ... args )
89  {
90  //assert( check_sizes( args... ) );
91  verifySizes( args... );
92  return ranges::view::const_( ranges::view::zip( std::forward<Args>(args)... ) );
93  }
94 
95  }
96 
97  // implementation of C++17 std::as_const, see http://en.cppreference.com/w/cpp/utility/as_const
98  template <typename T>
99  constexpr typename std::add_const<T>::type& as_const(T& t) noexcept
100  { return t; }
101 
102  template <typename T>
103  void as_const(T&& t) = delete;
104 
106 
107  template <typename Out1, typename Out2,
109  Out1* put( DataObjectHandle<Out1>& out_handle, Out2&& out ) {
110  return out_handle.put( new Out1( std::forward<Out2>(out) ) );
111  }
112 
113  template <typename Out1, typename Out2,
115  void put( AnyDataHandle<Out1>& out_handle, Out2&& out ) {
116  out_handle.put( std::forward<Out2>(out) );
117  }
118 
119  // optional put
120  template <typename OutHandle, typename Out>
121  void put( OutHandle& out_handle, boost::optional<Out>&& out) {
122  if (out) put(out_handle,std::move(*out));
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 boost::optional<T>
128 
129  constexpr struct insert_t {
130  // for Container<T*>, return T
131  template <typename Container>
133 
134  template <typename Container, typename Value>
135  auto operator()(Container& c, Value&& v) const -> decltype( c.push_back(v) ) { return c.push_back( std::forward<Value>(v) ); }
136 
137  template <typename Container, typename Value>
138  auto operator()(Container& c, Value&& v) const -> decltype( c.insert(v) ) { return c.insert( std::forward<Value>(v) ); }
139 
140  // Container<T*> with T&& as argument
141  template <typename Container, typename = typename std::enable_if< std::is_pointer<typename Container::value_type>::value >::type >
142  auto operator()(Container& c, c_remove_ptr_t<Container>&& v) const
143  { return operator()( c, new c_remove_ptr_t<Container>{ std::move(v) } ); }
144 
145  template <typename Container, typename Value>
146  void operator()(Container& c, boost::optional<Value>&& v) const { if (v) operator()(c,std::move(*v)); }
147  } insert {};
148 
150 
151  constexpr struct deref_t {
152  template <typename In, typename = typename std::enable_if< !std::is_pointer<In>::value>::type>
153  In& operator()( In& in ) const { return in; }
154 
155  template <typename In>
156  In& operator()( In* in ) const { assert(in!=nullptr); return *in; }
157  } deref {};
158 
160 
161  namespace details2 {
162  template< typename T > struct remove_optional {typedef T type;};
163  template< typename T > struct remove_optional< boost::optional<T> > {typedef T type;};
164  // template< typename T > struct remove_optional< std::optional<T> > {typedef T type;};
165 
166  }
167  template <typename T> using remove_optional_t = typename details2::remove_optional<T>::type;
168  template< typename T> struct is_optional : std::false_type {};
169  template< typename T> struct is_optional< boost::optional<T> > : std::true_type {};
170  // C++17: template <typename T> constexpr bool is_optional_v = is_optional<T>::value;
171 
173  // if Container is a pointer, then we're optional items
174  namespace details2 {
175  template <typename Container, typename Value>
176  void push_back(Container& c, const Value& v, std::true_type) { c.push_back(v); }
177  template <typename Container, typename Value>
178  void push_back(Container& c, const Value& v, std::false_type) { c.push_back(&v); }
179 
180  template <typename In>
182  template <template <typename> class Handle, typename I, typename = typename std::enable_if< std::is_convertible<I,In>::value >::type >
183  auto operator()( const Handle<I>& h ) -> const In& { return *h.get(); }
184  template <template <typename> class Handle, typename I, typename = typename std::enable_if<std::is_convertible<I*,In>::value>::type >
185  auto operator()( const Handle<I>& h ) -> const In { return h.getIfExists(); } // In is-a pointer
186  };
187 
188  template <typename T> T* deref_if(T* const t,std::false_type) { return t; }
189  template <typename T> T& deref_if(T* const t,std::true_type) { return *t; }
190  }
191 
192  template <typename Container>
195  using val_t = std::add_const_t<std::remove_pointer_t<Container>>;
196  using ptr_t = std::add_pointer_t<val_t>;
197  using ref_t = std::add_lvalue_reference_t<val_t>;
200  public:
201  using value_type = std::conditional_t<is_optional,ptr_t,val_t>;
202  using size_type = typename ContainerVector::size_type;
203  class iterator {
204  typename ContainerVector::const_iterator m_i;
205  friend class vector_of_const_;
206  iterator(typename ContainerVector::const_iterator iter) : m_i(iter) {}
207  using ret_t = std::conditional_t<is_optional,ptr_t,ref_t>;
208  public:
209  friend bool operator!=(const iterator& lhs, const iterator& rhs) { return lhs.m_i != rhs.m_i; }
211  iterator& operator++() { ++m_i; return *this; }
212  iterator& operator--() { --m_i; return *this; }
213  bool is_null() const { return !*m_i; }
214  explicit operator bool() const { return !is_null(); }
215  };
216  vector_of_const_() = default;
217  void reserve(size_type size) { m_containers.reserve(size); }
218  template <typename T> // , typename = std::is_convertible<T,std::conditional_t<is_optional,ptr_t,val_t>>
219  void push_back(T&& container) { details2::push_back(m_containers,std::forward<T>(container), std::integral_constant<bool,is_optional>{});} // note: does not copy its argument, so we're not really a container...
220  iterator begin() const { return m_containers.begin(); }
221  iterator end() const { return m_containers.end(); }
222  size_type size() const { return m_containers.size(); }
223  const Container& operator[](size_type i) const { return *m_containers[i]; }
224  const Container& at(size_type i) const { if (i>=size()) throw std::out_of_range{"vector_of_const_::at"} ; return *m_containers[i]; }
225  bool is_null(size_type i) const { return !m_containers[i]; }
226  };
227 
229 
230  // detect whether a traits class defines the requested type,
231  // if so, use it,
232  // otherwise use the default
233  //
234  // based on http://en.cppreference.com/w/cpp/experimental/is_detected
235  // and the libstdc++ source, specificially libstdc++-v3/include/std/type_traits
236 
237  namespace detail2 {
238 #ifdef HAVE_CPP17
239  template<typename...> using void_t = void;
240 #else
241  template <typename...> struct void_t_ { using type = void; };
242  template <typename... T> using void_t = typename void_t_<T...>::type;
243 #endif
244 
246  template<typename Default, typename AlwaysVoid,
247  template<typename...> class Op, typename... Args>
248  struct detector {
249  using type = Default;
250  };
251 
253  template<typename Default,
254  template<typename...> class Op, typename... Args>
255  struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
256  using type = Op<Args...>;
257  };
258  }
259 
260  // Op<Args...> if that is a valid type, otherwise Default.
261  template<typename Default,
262  template<typename...> class Op, typename... Args>
263  using detected_or_t = typename detail2::detector<Default, void, Op, Args...>::type;
264 
265  // Op<Args...> if that is a valid type, otherwise Default<Args...>.
266  template<template<typename...> class Default,
267  template<typename...> class Op,
268  typename Tr, typename T>
270 
272  namespace detail2 { // utilities for detected_or_t{,_} usage
273 
274  template <typename Tr> using BaseClass_ = typename Tr::BaseClass;
275  template <typename Tr, typename T> using defaultHandle_ = typename std::conditional< std::is_base_of<DataObject,T>::value,
278  template <typename Tr, typename T> using OutputHandle_ = typename Tr::template OutputHandle<T>;
279  template <typename Tr, typename T> using InputHandle_ = typename Tr::template InputHandle<T>;
280  }
281 
282  // check whether Traits::BaseClass is a valid type,
283  // if so, define BaseClass_t<Traits> as being Traits::BaseClass
284  // else define as being GaudiAlgorithm
286 
287  // check whether Traits::{Input,Output}Handle<T> is a valid type,
288  // if so, define {Input,Output}Handle_t<Traits,T> as being Traits::{Input,Output}Handle<T>
289  // else define as being DataObjectHandle<T> if T derives from DataObject, else AnyDataHandle<T>
292 
294 
295  namespace details2 {
296  template <std::size_t N, typename Tuple >
298 
299  template <typename Tuple, typename KeyValues, std::size_t... I>
300  Tuple make_tuple_of_handles_helper( IDataHandleHolder* o, const KeyValues& initvalue, Gaudi::DataHandle::Mode m, std::index_sequence<I...> ) {
301  return std::make_tuple( element_t<I,Tuple>{std::get<I>(initvalue).second, m, o} ... );
302  }
303  template <typename KeyValues, typename Properties, std::size_t... I>
304  void declare_tuple_of_properties_helper(Algorithm& owner, const KeyValues& inputs, Properties& props, std::index_sequence<I...>) {
306  ( owner.declareProperty( std::get<I>(inputs).first,
307  std::get<I>(props) ),0)...
308  };
309  }
310  }
311 
312  template <typename Tuple, typename KeyValues >
314  return details2::make_tuple_of_handles_helper<Tuple>( owner, initvalue, mode, std::make_index_sequence<std::tuple_size<Tuple>::value>{} );
315  }
316 
317  template <typename KeyValues, typename Properties>
319  constexpr auto N = std::tuple_size<KeyValues>::value;
320  static_assert( N == std::tuple_size<Properties>::value, "Inconsistent lengths" );
321  details2::declare_tuple_of_properties_helper( owner, inputs, props, std::make_index_sequence<N>{} );
322  }
323 
324  template <typename Handles>
326  Handles handles; handles.reserve(init.size());
327  std::transform( init.begin(), init.end(), std::back_inserter(handles),
328  [&](const std::string& loc) -> typename Handles::value_type
329  { return {loc,mode, owner}; });
330  return handles;
331  }
332 
334 
335 
336  template <typename OutputSpec, typename InputSpec, typename Traits_> class DataHandleMixin;
337 
338  template <typename... Out, typename... In, typename Traits_>
339  class DataHandleMixin<std::tuple<Out...>, std::tuple<In...>,Traits_> : public BaseClass_t<Traits_> {
340  static_assert( std::is_base_of<Algorithm, BaseClass_t<Traits_>>::value,
341  "BaseClass must inherit from Algorithm");
342  public:
344  constexpr static std::size_t N_in = sizeof...(In);
345  constexpr static std::size_t N_out = sizeof...(Out);
346 
347  // generic constructor: N -> M
350  const std::array<KeyValue,N_out>& outputs)
351  : BaseClass_t<Traits_>( name , pSvcLocator ),
352  m_inputs( make_tuple_of_handles<decltype(m_inputs)>( this, inputs, Gaudi::DataHandle::Reader ) ),
353  m_outputs( make_tuple_of_handles<decltype(m_outputs)>( this, outputs, Gaudi::DataHandle::Writer ) )
354  {
355  declare_tuple_of_properties( *this, inputs, m_inputs );
356  declare_tuple_of_properties( *this, outputs, m_outputs );
357  // make sure this algorithm is seen as reentrant by Gaudi
358  BaseClass_t<Traits_>::setProperty("Cardinality", 0);
359  }
360 
361  // special cases: forward to the generic case...
362  // 1 -> 1
364  const KeyValue& input,
365  const KeyValue& output)
366  : DataHandleMixin( name, locator, std::array<KeyValue,1>{ input }, std::array<KeyValue,1>{ output } )
367  { }
368  // 1 -> N
370  const KeyValue& input,
371  const std::array<KeyValue,N_out>& outputs)
372  : DataHandleMixin( name, locator, std::array<KeyValue,1>{ input }, outputs )
373  { }
374  // N -> 1
377  const KeyValue& output )
378  : DataHandleMixin( name, locator, inputs, std::array<KeyValue,1>{ output } )
379  { }
380 
381  template <std::size_t N=0>
382  const std::string& inputLocation() const { return std::get<N>(m_inputs).objKey(); }
383  unsigned int inputLocationSize() const { return std::tuple_size<decltype(m_inputs)>::value; }
384 
385  template <std::size_t N=0>
386  const std::string& outputLocation() const { return std::get<N>(m_outputs).objKey(); }
387  unsigned int outputLocationSize() const { return std::tuple_size<decltype(m_outputs)>::value; }
388 
389  protected:
392  };
393 
394  template <typename... In, typename Traits_>
395  class DataHandleMixin<void, std::tuple<In...>,Traits_> : public BaseClass_t<Traits_> {
396  static_assert( std::is_base_of<Algorithm, BaseClass_t<Traits_>>::value,
397  "BaseClass must inherit from Algorithm");
398  public:
400  constexpr static std::size_t N_in = sizeof...(In);
401 
402  // generic constructor: N -> 0
405  : BaseClass_t<Traits_>( name , pSvcLocator ),
406  m_inputs( make_tuple_of_handles<decltype(m_inputs)>( this, inputs, Gaudi::DataHandle::Reader ) )
407  {
408  declare_tuple_of_properties( *this, inputs, m_inputs );
409  // make sure this algorithm is seen as reentrant by Gaudi
410  BaseClass_t<Traits_>::setProperty("Cardinality", 0);
411  }
412 
413  // special cases: forward to the generic case...
414  // 1 -> 0
416  const KeyValue& input )
417  : DataHandleMixin( name, locator, std::array<KeyValue,1>{ input } )
418  { }
419 
420  template <std::size_t N=0>
421  const std::string& inputLocation() const { return std::get<N>(m_inputs).objKey(); }
422  unsigned int inputLocationSize() const { return std::tuple_size<decltype(m_inputs)>::value; }
423 
424  protected:
426  };
427 
428  template <typename... Out, typename Traits_>
429  class DataHandleMixin<std::tuple<Out...>, void,Traits_> : public BaseClass_t<Traits_> {
430  static_assert( std::is_base_of<Algorithm, BaseClass_t<Traits_>>::value,
431  "BaseClass must inherit from Algorithm");
432  public:
434  constexpr static std::size_t N_out = sizeof...(Out);
435 
436  // generic constructor: 0 -> N
438  const std::array<KeyValue,N_out>& outputs)
439  : BaseClass_t<Traits_>( name , pSvcLocator ),
440  m_outputs( make_tuple_of_handles<decltype(m_outputs)>( this, outputs, Gaudi::DataHandle::Writer ) )
441  {
442  declare_tuple_of_properties( *this, outputs, m_outputs );
443  // make sure this algorithm is seen as reentrant by Gaudi
444  BaseClass_t<Traits_>::setProperty("Cardinality", 0);
445  }
446 
447  // 0 -> 1
449  const KeyValue& output)
450  : DataHandleMixin( name, locator, std::array<KeyValue,1>{ output } )
451  { }
452 
453  template <std::size_t N=0>
454  const std::string& outputLocation() const { return std::get<N>(m_outputs).objKey(); }
455  unsigned int outputLocationSize() const { return std::tuple_size<decltype(m_outputs)>::value; }
456 
457  protected:
459  };
460 
462  template <typename Fun, typename Container, typename... Args >
463  constexpr void applyPostProcessing(const Fun&, Container&, Args... )
464  { static_assert(sizeof...(Args)==0,"Args should not be used!");}
465 
466  template <typename Fun, typename Container>
467  auto applyPostProcessing(const Fun& fun, Container& c) -> decltype(fun.postprocess(c),void())
468  { fun.postprocess(c); }
469 
471 
472 } } }
473 
474 #endif
DataHandleMixin(const std::string &name, ISvcLocator *pSvcLocator, const std::array< KeyValue, N_out > &outputs)
DataHandleMixin(const std::string &name, ISvcLocator *pSvcLocator, const std::array< KeyValue, N_in > &inputs)
StatusCode setProperty(IProperty *component, const std::string &name, const TYPE &value, const std::string &doc)
simple function to set the property of the given object from the value
Definition: Property.h:1174
Tuple make_tuple_of_handles_helper(IDataHandleHolder *o, const KeyValues &initvalue, Gaudi::DataHandle::Mode m, std::index_sequence< I... >)
constexpr std::add_const< T >::type & as_const(T &t) noexcept
Define general base for Gaudi exception.
DataHandleMixin(const std::string &name, ISvcLocator *locator, const std::array< KeyValue, N_in > &inputs, const KeyValue &output)
detected_or_t< GaudiAlgorithm, detail2::BaseClass_, Tr > BaseClass_t
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
auto operator()(const Handle< I > &h) -> const In &
Handles make_vector_of_handles(IDataHandleHolder *owner, const std::vector< std::string > &init, Gaudi::DataHandle::Mode mode)
The namespace threadpool contains a thread pool and related utility classes.
Definition: iter_pos.hpp:13
friend bool operator!=(const iterator &lhs, const iterator &rhs)
void declare_tuple_of_properties(Algorithm &owner, const KeyValues &inputs, Properties &props)
std::tuple< details::OutputHandle_t< Traits_, Out >... > m_outputs
GAUDI_API const std::string typeinfoName(const std::type_info &)
Get platform independent information about the class type.
Definition: System.cpp:299
void declare_tuple_of_properties_helper(Algorithm &owner, const KeyValues &inputs, Properties &props, std::index_sequence< I... >)
decltype(auto) verifySizes(Args &...args)
Verify the data container sizes have the same sizes.
decltype(auto) range(Args &&...args)
Zips multiple containers together to form a single range.
auto operator()(Container &c, c_remove_ptr_t< Container > &&v) const
void printSizes(OS &out, Arg &&arg)
Print the parameter.
constexpr struct Gaudi::Functional::details::insert_t insert
DataHandleMixin(const std::string &name, ISvcLocator *pSvcLocator, const std::array< KeyValue, N_in > &inputs, const std::array< KeyValue, N_out > &outputs)
typename Tr::template InputHandle< T > InputHandle_
Header file for class GaudiAlgorithm.
DataHandleMixin(const std::string &name, ISvcLocator *locator, const KeyValue &input, const KeyValue &output)
std::add_const_t< std::remove_pointer_t< Container >> val_t
#define UNLIKELY(x)
Definition: Kernel.h:126
typename std::remove_pointer< typename Container::value_type >::type c_remove_ptr_t
STL namespace.
class MergingTransformer< Out(const vector_of_const_< In > void
T make_tuple(T...args)
T end(T...args)
void push_back(Container &c, const Value &v, std::true_type)
std::vector< Gaudi::Details::PropertyBase * > Properties
Definition: PropertyMgr.h:139
iterator(typename ContainerVector::const_iterator iter)
std::add_lvalue_reference_t< val_t > ref_t
T * deref_if(T *const t, std::false_type)
typename void_t_< T... >::type void_t
const Container & operator[](size_type i) const
constexpr struct Gaudi::Functional::details::deref_t deref
const T * put(T &&object)
Register object in transient store.
Definition: AnyDataHandle.h:41
typename std::conditional< std::is_base_of< DataObject, T >::value, DataObjectHandle< T >, AnyDataHandle< T >>::type defaultHandle_
constexpr double second
STL class.
DataObjectHandle.h GaudiKernel/DataObjectHandle.h.
Definition: AlgTool.h:27
Implementation of the detection idiom (negative case).
int N
Definition: IOTest.py:90
detected_or_t_< detail2::defaultHandle_, detail2::InputHandle_, Tr, T > InputHandle_t
constexpr void applyPostProcessing(const Fun &, Container &, Args...)
DataHandleMixin(const std::string &name, ISvcLocator *locator, const KeyValue &input, const std::array< KeyValue, N_out > &outputs)
class MergingTransformer< Out(const vector_of_const_< In > Traits_
constexpr double m
Definition: SystemOfUnits.h:93
T * put(T *object)
Register object in transient store.
typename details2::remove_optional< T >::type remove_optional_t
DataHandleMixin(const std::string &name, ISvcLocator *locator, const KeyValue &output)
Tuple make_tuple_of_handles(IDataHandleHolder *owner, const KeyValues &initvalue, Gaudi::DataHandle::Mode mode)
auto operator()(Container &c, Value &&v) const -> decltype(c.insert(v))
T move(T...args)
detected_or_t_< detail2::defaultHandle_, detail2::OutputHandle_, Tr, T > OutputHandle_t
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:78
T size(T...args)
std::conditional_t< is_optional, ptr_t, val_t > value_type
std::vector< InputHandle_t< In > > m_inputs
struct GAUDI_API array
Parametrisation class for redirection array - like implementation.
virtual Out operator()(const vector_of_const_< In > &inputs) const =0
detected_or_t< Default< Tr, T >, Op, Tr, T > detected_or_t_
void operator()(Container &c, boost::optional< Value > &&v) const
std::conditional_t< is_optional, ptr_t, ref_t > ret_t
T begin(T...args)
bool check_sizes(const A &) noexcept
Resolve case there is only one container in the range.
auto operator()(Container &c, Value &&v) const -> decltype(c.push_back(v))
T back_inserter(T...args)
const Container & at(size_type i) const
typename std::tuple_element< N, Tuple >::type element_t
double fun(const std::vector< double > &x)
Definition: PFuncTest.cpp:26
decltype(auto) const_range(Args &&...args)
Zips multiple containers together to form a single const range.
STL class.
DataHandleMixin(const std::string &name, ISvcLocator *locator, const KeyValue &input)
typename Tr::template OutputHandle< T > OutputHandle_
Gaudi::Details::PropertyBase * declareProperty(const std::string &name, ToolHandle< T > &hndl, const std::string &doc="none")
Definition: Algorithm.h:369
T transform(T...args)
T & deref_if(T *const t, std::true_type)
auto operator()(const Handle< I > &h) -> const In
Helper functions to set/get the application return code.
Definition: __init__.py:1
def Reader(readerType, filename, qacross, qToEngine)
Out1 * put(DataObjectHandle< Out1 > &out_handle, Out2 &&out)
void push_back(Container &c, const Value &v, std::false_type)
typename detail2::detector< Default, void, Op, Args... >::type detected_or_t
std::pair< std::string, std::vector< std::string >> KeyValues
T reserve(T...args)
typename ContainerVector::size_type size_type