Project
Loading...
Searching...
No Matches
DataRefUtils.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11#ifndef O2_FRAMEWORK_DATAREFUTILS_H_
12#define O2_FRAMEWORK_DATAREFUTILS_H_
13
14#include "Framework/DataRef.h"
19#include "Headers/DataHeader.h"
22
23#include <gsl/gsl>
24
25#include <type_traits>
26#include <typeinfo>
27
28namespace o2::conf
29{
30class ConfigurableParam;
31}
32
33namespace o2::framework
34{
35
36// FIXME: Should enforce the fact that DataRefs are read only...
38
39 template <typename T>
40 static auto as(DataRef const& ref)
41 {
42 auto payloadSize = DataRefUtils::getPayloadSize(ref);
43 // SFINAE makes this available only for the case we are using
44 // trivially copyable type, this is to distinguish it from the
45 // alternative below, which works for TObject (which are serialised).
46 if constexpr (is_messageable<T>::value == true) {
48 auto header = o2::header::get<const DataHeader*>(ref.header);
49 if (header->payloadSerializationMethod != o2::header::gSerializationMethodNone) {
50 throw runtime_error("Attempt to extract a POD from a wrong message kind");
51 }
52 if ((payloadSize % sizeof(T)) != 0) {
53 throw runtime_error("Cannot extract POD from message as size do not match");
54 }
55 //FIXME: provide a const collection
56 return gsl::span<T>(reinterpret_cast<T*>(const_cast<char*>(ref.payload)), payloadSize / sizeof(T));
57 } else if constexpr (has_root_dictionary<T>::value == true &&
58 is_messageable<T>::value == false) {
59 std::unique_ptr<T> result;
60 static_assert(is_type_complete_v<struct RootSerializationSupport>, "Framework/RootSerializationSupport.h not included");
61 call_if_defined<struct RootSerializationSupport>([&](auto* p) {
62 // Classes using the ROOT ClassDef/ClassImp macros can be detected automatically
63 // and the serialization method can be deduced. If the class is also
64 // messageable, gSerializationMethodNone is used by default. This substitution
65 // does not apply for such types, the serialization method needs to be specified
66 // explicitely using type wrapper @a ROOTSerialized.
67 using RSS = std::decay_t<decltype(*p)>;
69 auto header = o2::header::get<const DataHeader*>(ref.header);
70 if (header->payloadSerializationMethod != o2::header::gSerializationMethodROOT) {
71 throw runtime_error("Attempt to extract a TMessage from non-ROOT serialised message");
72 }
73
74 typename RSS::FairInputTBuffer ftm(const_cast<char*>(ref.payload), payloadSize);
75 auto* requestedClass = RSS::TClass::GetClass(typeid(T));
76 ftm.InitMap();
77 auto* storedClass = ftm.ReadClass();
78 // should always have the class description if has_root_dictionary is true
79 assert(requestedClass != nullptr);
80
81 ftm.SetBufferOffset(0);
82 ftm.ResetMap();
83 auto* object = ftm.ReadObjectAny(storedClass);
84 if (object == nullptr) {
85 throw runtime_error_f("Failed to read object with name %s from message using ROOT serialization.",
86 (storedClass != nullptr ? storedClass->GetName() : "<unknown>"));
87 }
88
89 if constexpr (std::is_base_of<typename RSS::TObject, T>::value) { // compile time switch
90 // if the type to be extracted inherits from TObject, the class descriptions
91 // do not need to match exactly, only the dynamic_cast has to work
92 // FIXME: could probably try to extend this to arbitrary types T being a base
93 // to the stored type, but this would require to cast the extracted object to
94 // the actual type. This requires this information to be available as a type
95 // in the ROOT dictionary, check if this is the case or if TClass::DynamicCast
96 // can be used for the test. Right now, this case was and is not covered and
97 // not yet checked in the unit test either.
98 auto* r = dynamic_cast<T*>(static_cast<typename RSS::TObject*>(object));
99 if (r) {
100 result.reset(r);
101 }
102 // This check includes the case: storedClass == requestedClass
103 } else if (storedClass->InheritsFrom(requestedClass)) {
104 result.reset(static_cast<T*>(object));
105 }
106 if (result == nullptr) {
107 // did not manage to cast the pointer to result
108 // delete object via the class info if available, not the case for all types,
109 // e.g. for standard containers of ROOT objects apparently this is not always
110 // the case
111 auto* delfunc = storedClass->GetDelete();
112 if (delfunc) {
113 (*delfunc)(object);
114 }
115
116 throw runtime_error_f("Attempting to extract a %s but a %s is actually stored which cannot be casted to the requested one.",
117 (requestedClass != nullptr ? requestedClass->GetName() : "<unknown>"),
118 (storedClass != nullptr ? storedClass->GetName() : "<unknown>"));
119 }
120 // collections in ROOT can be non-owning or owning and the proper cleanup depends on
121 // this flag. Be it a bug or a feature in ROOT, but the owning flag of the extracted
122 // object only depends on the state at serialization of the original object. However,
123 // all objects created during deserialization are new and must be owned by the collection
124 // to avoid memory leak. So we call SetOwner if it is available for the type.
125 if constexpr (requires(T t) { t.SetOwner(true); }) {
126 result->SetOwner(true);
127 }
128 });
129
130 return std::move(result);
131 } else if constexpr (is_specialization_v<T, ROOTSerialized> == true) {
132 // See above. SFINAE allows us to use this to extract a ROOT-serialized object
133 // with a somewhat uniform API. ROOT serialization method is enforced by using
134 // type wrapper @a ROOTSerialized
135 static_assert(is_type_complete_v<struct RootSerializationSupport>, "Framework/RootSerializationSupport.h not included");
136 using wrapped = typename T::wrapped_type;
138 std::unique_ptr<wrapped> result;
139
140 call_if_defined<struct RootSerializationSupport>([&](auto* p) {
141 using RSS = std::decay_t<decltype(*p)>;
142
143 auto header = o2::header::get<const DataHeader*>(ref.header);
144 if (header->payloadSerializationMethod != o2::header::gSerializationMethodROOT) {
145 throw runtime_error("Attempt to extract a TMessage from non-ROOT serialised message");
146 }
147 auto* cl = RSS::TClass::GetClass(typeid(wrapped));
148 if (has_root_dictionary<wrapped>::value == false && cl == nullptr) {
149 throw runtime_error("ROOT serialization not supported, dictionary not found for data type");
150 }
151
152 typename RSS::FairInputTBuffer ftm(const_cast<char*>(ref.payload), payloadSize);
153 ftm.InitMap();
154 auto* classInfo = ftm.ReadClass();
155 ftm.SetBufferOffset(0);
156 ftm.ResetMap();
157 result.reset(static_cast<wrapped*>(ftm.ReadObjectAny(cl)));
158 if (result.get() == nullptr) {
159 throw runtime_error_f("Unable to extract class %s", cl == nullptr ? "<name not available>" : cl->GetName());
160 }
161 // workaround for ROOT feature, see above
162 if constexpr (requires(T t) { t.SetOwner(true); }) {
163 result->SetOwner(true);
164 }
165 });
166 return std::move(result);
167 } else if constexpr (is_specialization_v<T, CCDBSerialized> == true) {
168 using wrapped = typename T::wrapped_type;
170 auto* ptr = DataRefUtils::decodeCCDB(ref, typeid(wrapped));
171 if constexpr (std::is_base_of<o2::conf::ConfigurableParam, wrapped>::value) {
172 auto& param = const_cast<typename std::remove_const<wrapped&>::type>(wrapped::Instance());
173 param.syncCCDBandRegistry(ptr);
174 ptr = &param;
175 }
176 std::unique_ptr<wrapped> result(static_cast<wrapped*>(ptr));
177 return std::move(result);
178 }
179 }
180 // Decode a CCDB object using the CcdbApi.
181 static void* decodeCCDB(DataRef const& ref, std::type_info const& info);
182 static std::map<std::string, std::string> extractCCDBHeaders(DataRef const& ref);
183
185 {
187 auto* header = o2::header::get<const DataHeader*>(ref.header);
188 if (!header) {
189 return 0;
190 }
191 // in case of an O2 message with multiple payloads, the size of the message stored
192 // in DataRef is returned,
193 // as a prototype solution we are using splitPayloadIndex == splitPayloadParts to
194 // indicate that there are splitPayloadParts payloads following the header
195 if (header->splitPayloadParts > 1 && header->splitPayloadIndex == header->splitPayloadParts) {
196 return ref.payloadSize;
197 }
198 return header->payloadSize < ref.payloadSize || ref.payloadSize == 0 ? header->payloadSize : ref.payloadSize;
199 }
200
201 template <typename T>
202 static auto getHeader(const DataRef& ref)
203 {
204 using HeaderT = typename std::remove_pointer<T>::type;
205 static_assert(std::is_pointer<T>::value && std::is_base_of<o2::header::BaseHeader, HeaderT>::value,
206 "pointer to BaseHeader-derived type required");
207 return o2::header::get<T>(ref.header);
208 }
209
210 static bool isValid(DataRef const& ref)
211 {
212 return ref.header != nullptr;
213 }
214
218 static bool match(DataRef const& ref, const char* binding)
219 {
220 return ref.spec != nullptr && ref.spec->binding == binding;
221 }
222
226 static bool match(DataRef const& ref, InputSpec const& spec)
227 {
228 auto dh = DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
229 if (dh == nullptr) {
230 return false;
231 }
232 return DataSpecUtils::match(spec, dh->dataOrigin, dh->dataDescription, dh->subSpecification);
233 }
234};
235
236} // namespace o2::framework
237
238#endif // O2_FRAMEWORK_DATAREFUTILS_H_
Type wrappers for enfording a specific serialization method.
TBranch * ptr
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint object
Definition glcorearb.h:4041
GLboolean r
Definition glcorearb.h:1233
GLenum GLfloat param
Definition glcorearb.h:271
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
RuntimeErrorRef runtime_error(const char *)
RuntimeErrorRef runtime_error_f(const char *,...)
constexpr o2::header::SerializationMethod gSerializationMethodROOT
Definition DataHeader.h:328
constexpr o2::header::SerializationMethod gSerializationMethodNone
Definition DataHeader.h:327
static o2::header::DataHeader::PayloadSizeType getPayloadSize(const DataRef &ref)
static std::map< std::string, std::string > extractCCDBHeaders(DataRef const &ref)
static void * decodeCCDB(DataRef const &ref, std::type_info const &info)
static bool match(DataRef const &ref, const char *binding)
static auto getHeader(const DataRef &ref)
static auto as(DataRef const &ref)
static bool match(DataRef const &ref, InputSpec const &spec)
static bool isValid(DataRef const &ref)
static bool match(InputSpec const &spec, ConcreteDataMatcher const &target)
the main header struct
Definition DataHeader.h:618