The Gaudi Framework  v30r4 (9b837755)
HandleDetail.h
Go to the documentation of this file.
1 #ifndef GAUDIKERNEL_HANDLEDETAIL
2 #define GAUDIKERNEL_HANDLEDETAIL 1
3 
7 #include <memory>
8 #include <stdexcept>
9 #include <type_traits>
10 #include <utility>
11 
12 //---------------------------------------------------------------------------
13 
22 //---------------------------------------------------------------------------
23 
24 class DataObject;
25 
27 namespace Gaudi
28 {
29  namespace HandleDetail
30  {
31  // === FACTORING OUT SOME SFINAE BOILERPLATE ===
32 
34  template <typename T>
35  constexpr bool isDataObject()
36  {
38  }
39 
41  template <typename T>
42  constexpr bool isRange()
43  {
44  // FIXME: Implement this
45  return false;
46  }
47 
48 // This will need to be undef'd later, but brings so much fresh air...
49 #define ENABLE_IF( condition ) std::enable_if_t<condition>* = nullptr
50 
51  // === DECODING OF A DATAOBJECT* FROM THE TES ===
52 
53  // In the ReadHandle<T> implementation, we want to abstract away a
54  // number of storage implementation scenarios:
55  // - T is a subclass of DataObject, stored as-is in the TES.
56  // - T is stored as an AnyDataWrapper<T> in the TES: must unwrap it.
57  // - T = Range<U> and the TES holds a Range<U>: copy it and return it.
58  // - T = Range<U> and the TES holds a T::underlying container: build a
59  // Range<U> that covers the whole container and return it.
60  //
61  // These various cases are resolved via the unwrapDataObject<T> method.
62 
65  template <typename T, ENABLE_IF( isDataObject<T>() && !isRange<T>() )>
66  const T& unwrapDataObject( const DataObject& rawObject )
67  {
68  // FIXME: Dynamic casting on every access is expensive, but the only way
69  // to retain type safety if other code is allowed to perform
70  // arbitrary operations on the TES. The more we restrict what
71  // code other than handles is allowed to do with the TES, the
72  // further away from the hot code path we can push these checks.
73  return dynamic_cast<const T&>( rawObject );
74  }
75 
78  template <typename T, ENABLE_IF( !isDataObject<T>() && !isRange<T>() )>
79  const T& unwrapDataObject( const DataObject& rawObject )
80  {
81  // FIXME: See comment above.
82  return dynamic_cast<const AnyDataWrapper<T>&>( rawObject ).getData();
83  }
84 
87  template <typename RangeT, ENABLE_IF( isRange<RangeT>() )>
88  const RangeT unwrapDataObject( const DataObject& /* rawObject */ )
89  {
90  // FIXME: Now that we know we're dealing with a range, we need to figure
91  // out whether the thing that lies in the event store is a RangeT
92  // or a container of RangeT::underlying.
93  // - If it's a RangeT, decode it as appropriate and copy it
94  // - If it's a container, create a suitable RangeT & return it
95  throw std::runtime_error( "Not implemented yet!" );
96  }
97 
98  // === WRAPPING DATA INTO A DATAOBJECT* FOR THE TES ===
99 
100  // The TES will only accept as input pointers to heap-allocated objects
101  // that inherit from DataObject. We will manipulate those as unique_ptrs.
103 
104  // In the process of producing a DataObjectPtr from arbitrary data, we may
105  // need to perform heap allocation and move stuff around. Our client wants
106  // a const-reference to the final object after all this has been done.
107  template <typename T>
109 
110  // We received a heap-allocated DataObject. The TES is fine with that.
111  template <typename T>
113  {
114  const T& ref = static_cast<const T&>( *ptr );
115  return {std::move( ptr ), ref};
116  }
117 
118  // We received a DataObject rvalue. It must be moved to the heap first.
119  template <typename T>
121  {
122  return wrapDataObject<T>( std::make_unique<T>( static_cast<T&&>( data ) ) );
123  }
124 
125  // This is not a DataObject, we must wrap it and move it to the heap.
126  template <typename T, ENABLE_IF( !isDataObject<T>() )>
128  {
129  auto ptr = std::make_unique<AnyDataWrapper<T>>( std::forward<T>( data ) );
130  const T& ref = ptr->getData();
131  return {std::move( ptr ), ref};
132  }
133 
134 // Better not keep this macro around now that we're done...
135 #undef ENABLE_IF
136  }
137 }
138 
139 #endif
constexpr bool isDataObject()
Tells whether type T is a subclass of DataObject.
Definition: HandleDetail.h:35
constexpr bool isRange()
Tells whether there is a parameter pack U... such as T = Range<U...>
Definition: HandleDetail.h:42
DataObjectAndRef< T > wrapDataObject(DataObjectPtr &&ptr)
Definition: HandleDetail.h:112
const T & unwrapDataObject(const DataObject &rawObject)
T is a subclass of DataObject, and is not a range: we can just cast the pointer provided by the TES a...
Definition: HandleDetail.h:66
T move(T...args)
STL class.
A DataObject is the base class of any identifiable object on any data store.
Definition: DataObject.h:30
Helper functions to set/get the application return code.
Definition: __init__.py:1