Project
Loading...
Searching...
No Matches
DataAllocator.h
Go to the documentation of this file.
1// Copyright 2019-2026 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_DATAALLOCATOR_H_
12#define O2_FRAMEWORK_DATAALLOCATOR_H_
13
17#include "Framework/Output.h"
18#include "Framework/OutputRef.h"
20#include "Framework/DataChunk.h"
24#include "Framework/Traits.h"
29
30#include "Headers/DataHeader.h"
31#include <TClass.h>
32
33#include <memory>
34#include <ranges>
35#include <vector>
36#include <map>
37#include <string>
38#include <utility>
39#include <type_traits>
40#include <utility>
41#include <cstddef>
42
43// Do not change this for a full inclusion of fair::mq::Device.
44#include <fairmq/FwdDecls.h>
45#include <fairmq/Version.h>
46#include <fairmq/shmem/Message.h>
47
48namespace arrow
49{
50class Schema;
51class Table;
52
53namespace ipc
54{
55class RecordBatchWriter;
56} // namespace ipc
57} // namespace arrow
58
59namespace o2::framework
60{
61struct ServiceRegistry;
62
68template <typename T>
70 using type = T;
71 T* ptr = nullptr;
72 std::function<void(T&)> callback = nullptr;
73 LifetimeHolder(T* ptr_) : ptr(ptr_),
74 callback(nullptr)
75 {
76 }
77 LifetimeHolder() = delete;
78 // Never copy it, because there is only one LifetimeHolder pointer
79 // created object.
83 {
84 this->ptr = other.ptr;
85 other.ptr = nullptr;
86 if (other.callback) {
87 this->callback = std::move(other.callback);
88 } else {
89 this->callback = nullptr;
90 }
91 other.callback = nullptr;
92 }
94 {
95 this->ptr = other.ptr;
96 other.ptr = nullptr;
97 if (other.callback) {
98 this->callback = std::move(other.callback);
99 } else {
100 this->callback = nullptr;
101 }
102 other.callback = nullptr;
103 return *this;
104 }
105
106 // On deletion we invoke the callback and then delete the object,
107 // when prensent.
109 {
110 release();
111 }
112
113 T* operator->() { return ptr; }
114 T& operator*() { return *ptr; }
115
116 // release the owned object, if any. This allows to
117 // invoke the callback early (e.g. for the Product<> case)
118 void release()
119 {
120 if (!ptr) {
121 return;
122 }
123
124 std::unique_ptr<T> released{ptr};
125 ptr = nullptr;
126 auto releaseCallback = std::move(callback);
127 if (!releaseCallback) {
128 return;
129 }
130 releaseCallback(*released);
131 }
132
133 // Delete the owned object without invoking the release callback. This is used
134 // when a partially filled object must be abandoned.
135 void discard()
136 {
137 if (!ptr) {
138 return;
139 }
140
141 callback = nullptr;
142 delete ptr;
143 ptr = nullptr;
144 }
145};
146
147template <typename T>
148concept VectorOfMessageableTypes = is_specialization_v<T, std::vector> &&
149 is_messageable<typename T::value_type>::value;
150
151template <typename T>
152concept ContiguousMessageablesRange = std::ranges::contiguous_range<T> &&
153 is_messageable<typename T::value_type>::value;
154
160{
161 public:
163 using AllowedOutputRoutes = std::vector<OutputRoute>;
168
169 template <typename T>
170 requires std::is_fundamental_v<T>
172 using value_type = T;
173 };
174
176
177 DataChunk& newChunk(const Output&, size_t);
178
179 inline DataChunk& newChunk(OutputRef&& ref, size_t size) { return newChunk(getOutputByBind(std::move(ref)), size); }
180
181 void adoptChunk(const Output&, char*, size_t, fair::mq::FreeFn*, void*);
182
183 // This method can be used to send a 0xdeadbeef message associated to a given
184 // output. The @a spec will be used to determine the channel to which the
185 // output will need to be sent, however the actual message will be empty
186 // and with subspecification 0xdeadbeef.
187 void cookDeadBeef(const Output& spec);
188
189 template <typename T, typename... Args>
190 requires is_specialization_v<T, o2::framework::DataAllocator::UninitializedVector>
191 decltype(auto) make(const Output& spec, Args... args)
192 {
193 auto& timingInfo = mRegistry.get<TimingInfo>();
194 auto& context = mRegistry.get<MessageContext>();
195
196 auto routeIndex = matchDataHeader(spec, timingInfo.timeslice);
197 // plain buffer as polymorphic spectator std::vector, which does not run constructors / destructors
198 using ValueType = typename T::value_type;
199
200 // Note: initial payload size is 0 and will be set by the context before sending
201 fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodNone, 0);
203 std::move(headerMessage), routeIndex, 0, std::forward<Args>(args)...)
204 .get();
205 }
206
207 template <typename T, typename... Args>
209 decltype(auto) make(const Output& spec, Args... args)
210 {
211 auto& timingInfo = mRegistry.get<TimingInfo>();
212 auto& context = mRegistry.get<MessageContext>();
213
214 auto routeIndex = matchDataHeader(spec, timingInfo.timeslice);
215 // this catches all std::vector objects with messageable value type before checking if is also
216 // has a root dictionary, so non-serialized transmission is preferred
217 using ValueType = typename T::value_type;
218
219 // Note: initial payload size is 0 and will be set by the context before sending
220 fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodNone, 0);
221 return context.add<MessageContext::VectorObject<ValueType>>(std::move(headerMessage), routeIndex, 0, std::forward<Args>(args)...).get();
222 }
223
224 template <typename T, typename... Args>
225 requires(!VectorOfMessageableTypes<T> && has_root_dictionary<T>::value == true && is_messageable<T>::value == false)
226 decltype(auto) make(const Output& spec, Args... args)
227 {
228 auto& timingInfo = mRegistry.get<TimingInfo>();
229 auto& context = mRegistry.get<MessageContext>();
230
231 auto routeIndex = matchDataHeader(spec, timingInfo.timeslice);
232 // Extended support for types implementing the Root ClassDef interface, both TObject
233 // derived types and others
235 fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodROOT, 0);
236
237 return context.add<typename enable_root_serialization<T>::object_type>(std::move(headerMessage), routeIndex, std::forward<Args>(args)...).get();
238 } else {
239 static_assert(enable_root_serialization<T>::value, "Please make sure you include RootMessageContext.h");
240 }
241 }
242
243 template <typename T, typename... Args>
244 requires std::is_base_of_v<std::string, T>
245 decltype(auto) make(const Output& spec, Args... args)
246 {
247 auto* s = new std::string(args...);
248 adopt(spec, s);
249 return *s;
250 }
251
252 template <typename T, typename... Args>
253 requires(requires { static_cast<struct TableBuilder>(std::declval<std::decay_t<T>>()); })
254 decltype(auto) make(const Output& spec, Args... args)
255 {
256 auto tb = std::move(LifetimeHolder<TableBuilder>(new std::decay_t<T>(args...)));
257 adopt(spec, tb);
258 return tb;
259 }
260
261 template <typename T, typename... Args>
262 requires(requires { static_cast<struct FragmentToBatch>(std::declval<std::decay_t<T>>()); })
263 decltype(auto) make(const Output& spec, Args... args)
264 {
265 auto f2b = std::move(LifetimeHolder<FragmentToBatch>(new std::decay_t<T>(args...)));
266 adopt(spec, f2b);
267 return f2b;
268 }
269
270 template <typename T>
271 requires is_messageable<T>::value && (!is_specialization_v<T, UninitializedVector>)
272 decltype(auto) make(const Output& spec)
273 {
274 return *reinterpret_cast<T*>(newChunk(spec, sizeof(T)).data());
275 }
276
277 template <typename T>
278 requires is_messageable<T>::value && (!is_specialization_v<T, UninitializedVector>)
279 decltype(auto) make(const Output& spec, std::integral auto nElements)
280 {
281 auto& timingInfo = mRegistry.get<TimingInfo>();
282 auto& context = mRegistry.get<MessageContext>();
283 auto routeIndex = matchDataHeader(spec, timingInfo.timeslice);
284
285 fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, o2::header::gSerializationMethodNone, nElements * sizeof(T));
286 return context.add<MessageContext::SpanObject<T>>(std::move(headerMessage), routeIndex, 0, nElements).get();
287 }
288
289 template <typename T, typename Arg>
290 decltype(auto) make(const Output& spec, std::same_as<std::shared_ptr<arrow::Schema>> auto schema)
291 {
292 std::shared_ptr<arrow::ipc::RecordBatchWriter> writer;
293 create(spec, &writer, schema);
294 return writer;
295 }
296
299 void
300 adopt(const Output& spec, std::string*);
301
304 void
306
309 void
311
313 void
314 adopt(const Output& spec, std::shared_ptr<class arrow::Table>);
315
336 template <typename T>
337 requires(!std::ranges::contiguous_range<T> && is_messageable<T>::value)
338 void snapshot(const Output& spec, T const& object)
339 {
340 return snapshot(spec, std::span<T const>(&object, &object + 1));
341 }
342
343 void snapshot(const Output& spec, std::string_view const& object)
344 {
345 return snapshot(spec, std::span<char const>(object.data(), object.size()));
346 }
347
348 // This is for snapshotting a range of contiguous messageable types
349 template <typename T>
350 requires(ContiguousMessageablesRange<T> && !std::is_pointer_v<typename T::value_type>)
351 void snapshot(const Output& spec, T const& object)
352 {
353 auto& proxy = mRegistry.get<MessageContext>().proxy();
354 RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get<TimingInfo>().timeslice);
355 using ElementType = typename std::remove_pointer<typename T::value_type>::type;
356 // Serialize a snapshot of a std::vector of trivially copyable, non-polymorphic elements
357 // Note: in most cases it is better to use the `make` function und work with the provided
358 // reference object
359 constexpr auto elementSizeInBytes = sizeof(ElementType);
360 auto sizeInBytes = elementSizeInBytes * object.size();
361 fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes);
362
363 // vector of elements
364 if (object.data() && sizeInBytes) {
365 memcpy(payloadMessage->GetData(), object.data(), sizeInBytes);
366 }
367
368 addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodNone);
369 }
370
371 // A random access range of pointers we can serialise by storing the contens one after the other.
372 // On the receiving side you will have to retrieve it via a span
373 template <typename T>
374 requires(std::ranges::random_access_range<T> && is_messageable<typename std::remove_pointer_t<typename T::value_type>>::value && std::is_pointer_v<typename T::value_type>)
375 void snapshot(const Output& spec, T const& object)
376 {
377 auto& proxy = mRegistry.get<MessageContext>().proxy();
378 RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get<TimingInfo>().timeslice);
379 using ElementType = typename std::remove_pointer_t<typename T::value_type>;
380 // Serialize a snapshot of a std::vector of trivially copyable, non-polymorphic elements
381 // Note: in most cases it is better to use the `make` function und work with the provided
382 // reference object
383 constexpr auto elementSizeInBytes = sizeof(ElementType);
384 auto sizeInBytes = elementSizeInBytes * object.size();
385 fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes);
386
387 // serialize vector of pointers to elements
388 auto target = reinterpret_cast<unsigned char*>(payloadMessage->GetData());
389 for (auto const& pointer : object) {
390 memcpy(target, pointer, elementSizeInBytes);
391 target += elementSizeInBytes;
392 }
393
394 addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodNone);
395 }
396
397 // This is for a range where we can know upfront how many elements there are,
398 // so that we can preallocate the final size by simply multipling sizeof(T) x N elements
399 template <typename T>
400 requires(!std::ranges::contiguous_range<T> && std::ranges::sized_range<T> && has_messageable_value_type<T>::value)
401 void snapshot(const Output& spec, T const& object)
402 {
403 auto& proxy = mRegistry.get<MessageContext>().proxy();
404 RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get<TimingInfo>().timeslice);
405 // Serialize a snapshot of a std::container of trivially copyable, non-polymorphic elements
406 // Note: in most cases it is better to use the `make` function und work with the provided
407 // reference object
408 constexpr auto elementSizeInBytes = sizeof(typename T::value_type);
409 auto sizeInBytes = elementSizeInBytes * object.size();
410 fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes);
411
412 // serialize vector of pointers to elements
413 auto target = reinterpret_cast<unsigned char*>(payloadMessage->GetData());
414 for (auto const& entry : object) {
415 memcpy(target, (void*)&entry, elementSizeInBytes);
416 target += elementSizeInBytes;
417 }
418 addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodNone);
419 }
420
421 template <typename T>
422 requires(is_specialization_v<T, ROOTSerialized>)
423 void snapshot(const Output& spec, T const& object)
424 {
425 auto& proxy = mRegistry.get<MessageContext>().proxy();
426 RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get<TimingInfo>().timeslice);
427 // Serialize a snapshot of an object with root dictionary
428 fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex);
429 payloadMessage->Rebuild(4096, {64});
430 const TClass* cl = nullptr;
431 // Explicitely ROOT serialize a snapshot of object.
432 // An object wrapped into type `ROOTSerialized` is explicitely marked to be ROOT serialized
433 // and is expected to have a ROOT dictionary. Availability can not be checked at compile time
434 // for all cases.
435 using WrappedType = typename T::wrapped_type;
436
437 if (object.getHint() == nullptr) {
438 // get TClass info by wrapped type
439 cl = TClass::GetClass(typeid(WrappedType));
440 } else if (std::is_same<typename T::hint_type, TClass>::value) {
441 // the class info has been passed directly
442 cl = reinterpret_cast<const TClass*>(object.getHint());
443 } else if (std::is_same<typename T::hint_type, const char>::value) {
444 // get TClass info by optional name
445 cl = TClass::GetClass(reinterpret_cast<const char*>(object.getHint()));
446 }
447 if (has_root_dictionary<WrappedType>::value == false && cl == nullptr) {
448 if (std::is_same<typename T::hint_type, const char>::value) {
449 throw runtime_error_f("ROOT serialization not supported, dictionary not found for type %s",
450 reinterpret_cast<const char*>(object.getHint()));
451 } else {
452 throw runtime_error_f("ROOT serialization not supported, dictionary not found for type %s",
453 typeid(WrappedType).name());
454 }
455 }
456 typename root_serializer<T>::serializer().Serialize(*payloadMessage, &object(), cl);
457 addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodROOT);
458 }
459
460 template <typename T>
461 requires(!is_messageable<T>::value && !ContiguousMessageablesRange<T> && has_root_dictionary<T>::value && !is_specialization_v<T, ROOTSerialized>)
462 void snapshot(const Output& spec, T const& object)
463 {
464 auto& proxy = mRegistry.get<MessageContext>().proxy();
465 RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get<TimingInfo>().timeslice);
466 // Serialize a snapshot of an object with root dictionary
467 fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex);
468 payloadMessage->Rebuild(4096, {64});
469 typename root_serializer<T>::serializer().Serialize(*payloadMessage, &object, TClass::GetClass(typeid(T)));
470 addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodROOT);
471 }
472
476 void snapshot(const Output& spec, const char* payload, size_t payloadSize,
478
481 void forwardPayload(const Output& spec, fair::mq::Message& inputPayload,
483
489 template <typename T, typename... Args>
490 decltype(auto) make(OutputRef&& ref, Args&&... args)
491 {
492 return make<T>(getOutputByBind(std::move(ref)), std::forward<Args>(args)...);
493 }
494
500 template <typename T>
501 void adopt(OutputRef&& ref, T* obj)
502 {
503 return adopt(getOutputByBind(std::move(ref)), obj);
504 }
505
506 // get the memory resource associated with an output
508 {
509 auto& timingInfo = mRegistry.get<TimingInfo>();
510 auto& proxy = mRegistry.get<FairMQDeviceProxy>();
511 RouteIndex routeIndex = matchDataHeader(spec, timingInfo.timeslice);
512 return *proxy.getOutputTransport(routeIndex);
513 }
514
515 // make a stl (pmr) vector
516 template <typename T, typename... Args>
517 o2::pmr::vector<T> makeVector(const Output& spec, Args&&... args)
518 {
519 o2::pmr::FairMQMemoryResource* targetResource = getMemoryResource(spec);
520 return o2::pmr::vector<T>{targetResource, std::forward<Args>(args)...};
521 }
522
523 struct CacheId {
524 int64_t value;
525 int64_t handle;
526 int64_t segment;
527 };
528
529 enum struct CacheStrategy : int {
530 Never = 0,
531 Always = 1
532 };
533
534 template <typename ContainerT>
535 CacheId adoptContainer(const Output& /*spec*/, ContainerT& /*container*/, CacheStrategy /* cache = false */, o2::header::SerializationMethod /* method = header::gSerializationMethodNone*/)
536 {
537 static_assert(always_static_assert_v<ContainerT>, "Container cannot be moved. Please make sure it is backed by a o2::pmr::FairMQMemoryResource");
538 return {0, 0, 0};
539 }
540
550 template <typename ContainerT>
552
555
558 void pruneFromCache(CacheId id);
559
565 template <typename... Args>
566 auto snapshot(OutputRef&& ref, Args&&... args)
567 {
568 return snapshot(getOutputByBind(std::move(ref)), std::forward<Args>(args)...);
569 }
570
572 bool isAllowed(Output const& query);
573
575 {
576 return mRegistry.get<MessageContext>().findMessageHeader(spec);
577 }
578
580 {
581 return mRegistry.get<MessageContext>().findMessageHeader(getOutputByBind(std::move(ref)));
582 }
583
585 {
586 return mRegistry.get<MessageContext>().findMessageHeaderStack(spec);
587 }
588
590 {
591 return mRegistry.get<MessageContext>().findMessageHeaderStack(getOutputByBind(std::move(ref)));
592 }
593
594 int countDeviceOutputs(bool excludeDPLOrigin = false)
595 {
596 return mRegistry.get<MessageContext>().countDeviceOutputs(excludeDPLOrigin);
597 }
598
599 private:
600 ServiceRegistryRef mRegistry;
601
602 RouteIndex matchDataHeader(const Output& spec, size_t timeframeId);
603 fair::mq::MessagePtr headerMessageFromOutput(Output const& spec, //
604 RouteIndex index, //
605 o2::header::SerializationMethod serializationMethod, //
606 size_t payloadSize); //
607
608 Output getOutputByBind(OutputRef&& ref);
609 void addPartToContext(RouteIndex routeIndex, fair::mq::MessagePtr&& payload,
610 const Output& spec,
611 o2::header::SerializationMethod serializationMethod);
612};
613
614template <typename ContainerT>
616{
617 // Find a matching channel, extract the message for it form the container
618 // and put it in the queue to be sent at the end of the processing
619 auto& timingInfo = mRegistry.get<TimingInfo>();
620 auto routeIndex = matchDataHeader(spec, timingInfo.timeslice);
621
622 auto& context = mRegistry.get<MessageContext>();
623 auto* transport = mRegistry.get<FairMQDeviceProxy>().getOutputTransport(routeIndex);
624 fair::mq::MessagePtr payloadMessage = o2::pmr::getMessage(std::forward<ContainerT>(container), *transport);
625 fair::mq::MessagePtr headerMessage = headerMessageFromOutput(spec, routeIndex, //
626 method, //
627 payloadMessage->GetSize() //
628 );
629
630 CacheId cacheId{0, 0, 0}; //
631 if (cache == CacheStrategy::Always) {
632 // The message will be shallow cloned in the cache. Since the
633 // clone is indistinguishable from the original, we can keep sending
634 // the original.
635 cacheId.value = context.addToCache(payloadMessage);
636 auto meta = dynamic_cast<fair::mq::shmem::Message*>(payloadMessage.get())->GetMeta();
637 cacheId.handle = meta.fHandle;
638 cacheId.segment = meta.fSegmentId;
639 }
640
641 context.add<MessageContext::TrivialObject>(std::move(headerMessage), std::move(payloadMessage), routeIndex);
642 return cacheId;
643}
644
645} // namespace o2::framework
646
647#endif // O2_FRAMEWORK_DATAALLOCATOR_H_
std::shared_ptr< arrow::Schema > schema
Type wrappers for enfording a specific serialization method.
static constexpr ServiceKind service_kind
::value &&!is_specialization_v< T, UninitializedVector > decltype(auto) make(const Output &spec, std::integral auto nElements)
void adopt(const Output &spec, std::string *)
o2::pmr::vector< T > makeVector(const Output &spec, Args &&... args)
void snapshot(const Output &spec, T const &object)
o2::pmr::FairMQMemoryResource * getMemoryResource(const Output &spec)
decltype(auto) make(OutputRef &&ref, Args &&... args)
DataChunk & newChunk(const Output &, size_t)
o2::header::DataHeader::SubSpecificationType SubSpecificationType
o2::header::Stack * findMessageHeaderStack(const Output &spec)
decltype(auto) make(const Output &spec, Args... args)
::value &&!is_specialization_v< T, UninitializedVector > decltype(auto) make(const Output &spec)
void snapshot(const Output &spec, std::string_view const &object)
decltype(auto) make(const Output &spec, Args... args)
auto snapshot(OutputRef &&ref, Args &&... args)
void adopt(const Output &spec, std::shared_ptr< class arrow::Table >)
Adopt an Arrow table and send it to all consumers of spec.
int countDeviceOutputs(bool excludeDPLOrigin=false)
o2::header::DataHeader * findMessageHeader(OutputRef &&ref)
void adoptFromCache(Output const &spec, CacheId id, header::SerializationMethod method=header::gSerializationMethodNone)
Adopt an already cached message, using an already provided CacheId.
decltype(auto) make(const Output &spec, Args... args)
std::vector< OutputRoute > AllowedOutputRoutes
decltype(auto) make(const Output &spec, Args... args)
void snapshot(const Output &spec, T const &object)
CacheId adoptContainer(const Output &, ContainerT &, CacheStrategy, o2::header::SerializationMethod)
void forwardPayload(const Output &spec, fair::mq::Message &inputPayload, o2::header::SerializationMethod serializationMethod=o2::header::gSerializationMethodNone)
void adoptChunk(const Output &, char *, size_t, fair::mq::FreeFn *, void *)
void snapshot(const Output &spec, T const &object)
bool isAllowed(Output const &query)
check if a certain output is allowed
void cookDeadBeef(const Output &spec)
o2::header::Stack * findMessageHeaderStack(OutputRef &&ref)
DataChunk & newChunk(OutputRef &&ref, size_t size)
decltype(auto) make(const Output &spec, Args... args)
decltype(auto) make(const Output &spec, std::same_as< std::shared_ptr< arrow::Schema > > auto schema)
void adopt(OutputRef &&ref, T *obj)
decltype(auto) make(const Output &spec, Args... args)
o2::header::DataHeader * findMessageHeader(const Output &spec)
void snapshot(const Output &spec, T const &object)
void snapshot(const Output &spec, T const &object)
void snapshot(const Output &spec, T const &object)
TrivialObject handles a message object.
GLenum void ** pointer
Definition glcorearb.h:805
GLuint entry
Definition glcorearb.h:5735
GLsizeiptr size
Definition glcorearb.h:659
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum target
Definition glcorearb.h:1641
GLboolean * data
Definition glcorearb.h:298
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint object
Definition glcorearb.h:4041
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
ServiceKind
The kind of service we are asking for.
RuntimeErrorRef runtime_error_f(const char *,...)
Descriptor< gSizeDataDescriptionString > DataDescription
Definition DataHeader.h:551
constexpr o2::header::SerializationMethod gSerializationMethodROOT
Definition DataHeader.h:328
constexpr o2::header::SerializationMethod gSerializationMethodNone
Definition DataHeader.h:327
Descriptor< gSizeDataOriginString > DataOrigin
Definition DataHeader.h:550
fair::mq::MessagePtr getMessage(ContainerT &&container, FairMQMemoryResource *targetResource=nullptr)
std::vector< T, fair::mq::pmr::polymorphic_allocator< T > > vector
fair::mq::MemoryResource FairMQMemoryResource
LifetimeHolder(const LifetimeHolder &)=delete
LifetimeHolder & operator=(LifetimeHolder &&other)
LifetimeHolder & operator=(const LifetimeHolder &)=delete
LifetimeHolder(LifetimeHolder &&other)
std::function< void(T &)> callback
the main header struct
Definition DataHeader.h:620
uint32_t SubSpecificationType
Definition DataHeader.h:622
a move-only header stack with serialized headers This is the flat buffer where all the headers in a m...
Definition Stack.h:33
VectorOfTObjectPtrs other