Project
Loading...
Searching...
No Matches
InputRecord.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_INPUTRECORD_H_
12#define O2_FRAMEWORK_INPUTRECORD_H_
13
14#include "Framework/DataRef.h"
19#include "Framework/Traits.h"
21#include "Framework/Logger.h"
24
25#include "Headers/DataHeader.h"
26
27#include <gsl/gsl>
28
29#include <iterator>
30#include <string>
31#include <vector>
32#include <cstring>
33#include <cassert>
34#include <memory>
35#include <type_traits>
36#include <concepts>
37
38#include <fairmq/FwdDecls.h>
39
40namespace o2::framework
41{
42
43// Wrapper class to get CCDB metadata
46
47struct InputSpec;
48class InputSpan;
49class CallbackService;
50
102{
103 public:
105
106 // Typesafe position inside a record of an input.
107 // Multiple routes by which the input gets in this
108 // position are multiplexed.
109 struct InputPos {
110 size_t index;
111 constexpr static size_t INVALID = -1LL;
112 };
113
114 InputRecord(std::vector<InputRoute> const& inputs,
117
129 template <typename T>
130 class Deleter : public std::default_delete<T>
131 {
132 public:
133 enum struct OwnershipProperty : short {
134 Unknown = -1,
135 NotOwning = 0,
136 Owning = 1
137 };
138
139 using base = std::default_delete<T>;
141 // using pointer = typename base::pointer;
142
143 constexpr Deleter() = default;
144 constexpr Deleter(bool isOwning)
145 : base::default_delete(), mProperty(isOwning ? OwnershipProperty::Owning : OwnershipProperty::NotOwning)
146 {
147 }
148
149 // copy constructor is needed in the setup of unique_ptr
150 // check that assignments happen only to uninitialized instances
151 constexpr Deleter(const self_type& other) : base::default_delete(other), mProperty{OwnershipProperty::Unknown}
152 {
153 if (mProperty == OwnershipProperty::Unknown) {
154 mProperty = other.mProperty;
155 } else if (mProperty != other.mProperty) {
156 throw runtime_error("Attemp to change resource control");
157 }
158 }
159
160 // copy constructor for the default delete which simply sets the
161 // resource ownership control to 'Owning'
162 constexpr Deleter(const base& other) : base::default_delete(other), mProperty{OwnershipProperty::Owning} {}
163
164 // allow assignment operator only for pristine or matching resource control property
166 {
167 // the default_deleter does not have any state, so this could be skipped, but keep the call to
168 // the base for completeness, and the (small) chance for changing the base
169 base::operator=(other);
170 if (mProperty == OwnershipProperty::Unknown) {
171 mProperty = other.mProperty;
172 } else if (mProperty != other.mProperty) {
173 throw runtime_error("Attemp to change resource control");
174 }
175 return *this;
176 }
177
178 void operator()(T* ptr) const
179 {
180 if (mProperty == OwnershipProperty::NotOwning) {
181 // nothing done if resource is not owned
182 return;
183 }
184 base::operator()(ptr);
185 }
186
187 private:
189 };
190
191 int getPos(const char* name) const;
192 int getPos(ConcreteDataMatcher matcher) const;
193 [[nodiscard]] static InputPos getPos(std::vector<InputRoute> const& routes, ConcreteDataMatcher matcher);
194 [[nodiscard]] static DataRef getByPos(std::vector<InputRoute> const& routes, InputSpan const& span, int pos, int part = 0);
195
196 [[nodiscard]] int getPos(const std::string& name) const;
197
198 [[nodiscard]] DataRef getByPos(int pos, int part = 0) const;
199
201 [[nodiscard]] DataRef getFirstValid(bool throwOnFailure = false) const;
202
203 [[nodiscard]] size_t getNofParts(int pos) const;
204
205 // Given a binding by string, return the associated DataRef
206 DataRef getDataRefByString(const char* bindingName, int part = 0) const
207 {
208 int pos = getPos(bindingName);
209 if (pos < 0) {
210 auto msg = describeAvailableInputs();
211 throw runtime_error_f("InputRecord::get: no input with binding %s found. %s", bindingName, msg.c_str());
212 }
213 return this->getByPos(pos, part);
214 }
215
216 template <typename R>
217 requires std::is_convertible_v<R, char const*>
218 DataRef getRef(R binding, int part = 0) const
219 {
220 return getDataRefByString(binding, part);
221 }
222
223 template <typename R>
224 requires requires(R r) { r.c_str(); }
225 DataRef getRef(R binding, int part = 0) const
226 {
227 return getDataRefByString(binding.c_str(), part);
228 }
229
230 template <typename R>
231 requires std::is_convertible_v<R, DataRef>
232 DataRef getRef(R ref, int part = 0) const
233 {
234 return ref;
235 }
236
248 template <typename T = DataRef, typename R>
249 decltype(auto) get(R binding, int part = 0) const
250 {
251 DataRef ref = getRef(binding, part);
252
253 using PointerLessValueT = std::remove_pointer_t<T>;
254
255 if constexpr (std::is_same_v<std::decay_t<T>, DataRef>) {
256 return ref;
257 } else if constexpr (std::is_same<T, std::string>::value) {
258 // substitution for std::string
259 // If we ask for a string, we need to duplicate it because we do not want
260 // the buffer to be deleted when it goes out of scope. The string is built
261 // from the data and its lengh, null-termination is not necessary.
262 // return std::string object
263 return std::string(ref.payload, DataRefUtils::getPayloadSize(ref));
264
265 // implementation (c)
266 } else if constexpr (std::is_same<T, char const*>::value) {
267 // substitution for const char*
268 // If we ask for a char const *, we simply point to the payload. Notice this
269 // is meant for C-style strings which are expected to be null terminated.
270 // If you want to actually get hold of the buffer, use gsl::span<char> as that will
271 // give you the size as well.
272 // return pointer to payload content
273 return reinterpret_cast<char const*>(ref.payload);
274
275 // implementation (d)
276 } else if constexpr (std::is_same<T, TableConsumer>::value) {
277 // substitution for TableConsumer
278 // For the moment this is dummy, as it requires proper support to
279 // create the RDataSource from the arrow buffer.
280 auto data = reinterpret_cast<uint8_t const*>(ref.payload);
281 return std::make_unique<TableConsumer>(data, DataRefUtils::getPayloadSize(ref));
282
283 // implementation (f)
284 } else if constexpr (is_span<T>::value) {
285 // substitution for span of messageable objects
286 // FIXME: there will be std::span in C++20
287 static_assert(is_messageable<typename T::value_type>::value, "span can only be created for messageable types");
288 auto header = DataRefUtils::getHeader<header::DataHeader*>(ref);
289 assert(header);
290 if (sizeof(typename T::value_type) > 1 && header->payloadSerializationMethod != o2::header::gSerializationMethodNone) {
291 throw runtime_error("Inconsistent serialization method for extracting span");
292 }
293 using ValueT = typename T::value_type;
294 auto payloadSize = DataRefUtils::getPayloadSize(ref);
295 if (payloadSize % sizeof(ValueT)) {
296 throw runtime_error(("Inconsistent type and payload size at " + std::string(ref.spec->binding) + "(" + DataSpecUtils::describe(*ref.spec) + ")" +
297 ": type size " + std::to_string(sizeof(ValueT)) +
298 " payload size " + std::to_string(payloadSize))
299 .c_str());
300 }
301 return gsl::span<ValueT const>(reinterpret_cast<ValueT const*>(ref.payload), payloadSize / sizeof(ValueT));
302
303 // implementation (g)
304 } else if constexpr (is_container<T>::value) {
305 // currently implemented only for vectors
306 if constexpr (is_specialization_v<std::remove_const_t<T>, std::vector>) {
307 auto header = DataRefUtils::getHeader<header::DataHeader*>(ref);
308 auto payloadSize = DataRefUtils::getPayloadSize(ref);
309 auto method = header->payloadSerializationMethod;
311 // TODO: construct a vector spectator
312 // this is a quick solution now which makes a copy of the plain vector data
313 auto* start = reinterpret_cast<typename T::value_type const*>(ref.payload);
314 auto* end = start + payloadSize / sizeof(typename T::value_type);
315 T result(start, end);
316 return result;
317 } else if (method == o2::header::gSerializationMethodROOT) {
323 using NonConstT = typename std::remove_const<T>::type;
324 if constexpr (is_specialization_v<T, ROOTSerialized> == true || has_root_dictionary<T>::value == true) {
325 // we expect the unique_ptr to hold an object, exception should have been thrown
326 // otherwise
327 auto object = DataRefUtils::as<NonConstT>(ref);
328 // need to swap the content of the deserialized container to a local variable to force return
329 // value optimization
330 T container;
331 std::swap(const_cast<NonConstT&>(container), *object);
332 return container;
333 } else {
334 throw runtime_error("No supported conversion function for ROOT serialized message");
335 }
336 } else {
337 throw runtime_error("Attempt to extract object from message with unsupported serialization type");
338 }
339 } else {
340 static_assert(always_static_assert_v<T>, "unsupported code path");
341 }
342
343 // implementation (h)
344 } else if constexpr (is_messageable<T>::value) {
345 // extract a messageable type by reference
346 // Cast content of payload bound by @a binding to known type.
347 // we need to check the serialization type, the cast makes only sense for
348 // unserialized objects
349
350 auto header = DataRefUtils::getHeader<header::DataHeader*>(ref);
351 auto method = header->payloadSerializationMethod;
353 // FIXME: we could in principle support serialized content here as well if we
354 // store all extracted objects internally and provide cleanup
355 throw runtime_error("Can not extract a plain object from serialized message");
356 }
357 return *reinterpret_cast<T const*>(ref.payload);
358
359 // implementation (i)
360 } else if constexpr (std::is_pointer_v<T> &&
361 (is_messageable<PointerLessValueT>::value ||
363 (is_specialization_v<PointerLessValueT, std::vector> && has_messageable_value_type<PointerLessValueT>::value) ||
365 // extract a messageable type or object with ROOT dictionary by pointer
366 // return unique_ptr to message content with custom deleter
367 using ValueT = PointerLessValueT;
368
369 auto header = DataRefUtils::getHeader<header::DataHeader*>(ref);
370 auto payloadSize = DataRefUtils::getPayloadSize(ref);
371 auto method = header->payloadSerializationMethod;
373 if constexpr (is_messageable<ValueT>::value) {
374 auto const* ptr = reinterpret_cast<ValueT const*>(ref.payload);
375 // return type with non-owning Deleter instance
376 std::unique_ptr<ValueT const, Deleter<ValueT const>> result(ptr, Deleter<ValueT const>(false));
377 return result;
378 } else if constexpr (is_specialization_v<ValueT, std::vector> && has_messageable_value_type<ValueT>::value) {
379 // TODO: construct a vector spectator
380 // this is a quick solution now which makes a copy of the plain vector data
381 auto* start = reinterpret_cast<typename ValueT::value_type const*>(ref.payload);
382 auto* end = start + payloadSize / sizeof(typename ValueT::value_type);
383 auto container = std::make_unique<ValueT>(start, end);
384 std::unique_ptr<ValueT const, Deleter<ValueT const>> result(container.release(), Deleter<ValueT const>(true));
385 return result;
386 }
387 throw runtime_error("unsupported code path");
388 } else if (method == o2::header::gSerializationMethodROOT) {
389 // This supports the common case of retrieving a root object and getting pointer.
390 // Notice that this will return a copy of the actual contents of the buffer, because
391 // the buffer is actually serialised, for this reason we return a unique_ptr<T>.
392 // FIXME: does it make more sense to keep ownership of all the deserialised
393 // objects in a single place so that we can avoid duplicate deserializations?
394 // explicitely specify serialization method to ROOT-serialized because type T
395 // is messageable and a different method would be deduced in DataRefUtils
396 // return type with owning Deleter instance, forwarding to default_deleter
397 std::unique_ptr<ValueT const, Deleter<ValueT const>> result(DataRefUtils::as<ROOTSerialized<ValueT>>(ref).release());
398 return result;
399 } else if (method == o2::header::gSerializationMethodCCDB) {
400 // This is to support deserialising objects from CCDB. Contrary to what happens for
401 // other objects, those objects are most likely long lived, so we
402 // keep around an instance of the associated object and deserialise it only when
403 // it's updated.
404 // FIXME: add ability to apply callbacks to deserialised objects.
405 auto id = ObjectCache::Id::fromRef(ref);
406 ConcreteDataMatcher matcher{header->dataOrigin, header->dataDescription, header->subSpecification};
407 // If the matcher does not have an entry in the cache, deserialise it
408 // and cache the deserialised object at the given id.
409 auto path = fmt::format("{}", DataSpecUtils::describe(matcher));
410 LOGP(debug, "{}", path);
411 auto& cache = mRegistry.get<ObjectCache>();
412 auto& callbacks = mRegistry.get<CallbackService>();
413 auto cacheEntry = cache.matcherToId.find(path);
414 if (cacheEntry == cache.matcherToId.end()) {
415 cache.matcherToId.insert(std::make_pair(path, id));
416 std::unique_ptr<ValueT const, Deleter<ValueT const>> result(DataRefUtils::as<CCDBSerialized<ValueT>>(ref).release(), false);
417 void* obj = (void*)result.get();
418 callbacks.call<CallbackService::Id::CCDBDeserialised>((ConcreteDataMatcher&)matcher, (void*)obj);
419 cache.idToObject[id] = obj;
420 LOGP(info, "Caching in {} ptr to {} ({})", id.value, path, obj);
421 return result;
422 }
423 auto& oldId = cacheEntry->second;
424 // The id in the cache is the same, let's simply return it.
425 if (oldId.value == id.value) {
426 std::unique_ptr<ValueT const, Deleter<ValueT const>> result((ValueT const*)cache.idToObject[id], false);
427 LOGP(debug, "Returning cached entry {} for {} ({})", id.value, path, (void*)result.get());
428 return result;
429 }
430 // The id in the cache is different. Let's destroy the old cached entry
431 // and create a new one.
432 delete reinterpret_cast<ValueT*>(cache.idToObject[oldId]);
433 std::unique_ptr<ValueT const, Deleter<ValueT const>> result(DataRefUtils::as<CCDBSerialized<ValueT>>(ref).release(), false);
434 void* obj = (void*)result.get();
435 callbacks.call<CallbackService::Id::CCDBDeserialised>((ConcreteDataMatcher&)matcher, (void*)obj);
436 cache.idToObject[id] = obj;
437 LOGP(info, "Replacing cached entry {} with {} for {} ({})", oldId.value, id.value, path, obj);
438 oldId.value = id.value;
439 return result;
440 } else {
441 throw runtime_error("Attempt to extract object from message with unsupported serialization type");
442 }
443 } else if constexpr (std::is_pointer_v<T>) {
444 static_assert(always_static_assert<T>::value, "T is not a supported type");
445 } else if constexpr (has_root_dictionary<T>::value) {
446 // retrieving ROOT objects follows the pointer approach, i.e. T* has to be specified
447 // as template parameter and a unique_ptr will be returned, std vectors of ROOT serializable
448 // objects can be retrieved by move, this is handled above in the "container" code branch
449 static_assert(always_static_assert_v<T>, "ROOT objects need to be retrieved by pointer");
450 } else {
451 // non-messageable objects for which serialization method can not be derived by type,
452 // the operation depends on the transmitted serialization method
453 auto header = DataRefUtils::getHeader<header::DataHeader*>(ref);
454 auto method = header->payloadSerializationMethod;
456 // this code path is only selected if the type is non-messageable
457 throw runtime_error(
458 "Type mismatch: attempt to extract a non-messagable object "
459 "from message with unserialized data");
460 } else if (method == o2::header::gSerializationMethodROOT) {
461 // explicitely specify serialization method to ROOT-serialized because type T
462 // is messageable and a different method would be deduced in DataRefUtils
463 // return type with owning Deleter instance, forwarding to default_deleter
464 std::unique_ptr<T const, Deleter<T const>> result(DataRefUtils::as<ROOTSerialized<T>>(ref).release());
465 return result;
466 } else {
467 throw runtime_error("Attempt to extract object from message with unsupported serialization type");
468 }
469 }
470 }
471
472 template <typename T = DataRef, typename R>
473 std::map<std::string, std::string>& get(R binding, int part = 0) const
474 requires std::same_as<T, CCDBMetadataExtractor>
475 {
476 auto ref = getRef(binding, part);
477 auto header = DataRefUtils::getHeader<header::DataHeader*>(ref);
478 auto payloadSize = DataRefUtils::getPayloadSize(ref);
479 auto method = header->payloadSerializationMethod;
480 if (method != header::gSerializationMethodCCDB) {
481 throw runtime_error("Attempt to extract metadata from a non-CCDB serialised message");
482 }
483 // This is to support deserialising objects from CCDB. Contrary to what happens for
484 // other objects, those objects are most likely long lived, so we
485 // keep around an instance of the associated object and deserialise it only when
486 // it's updated.
487 auto id = ObjectCache::Id::fromRef(ref);
488 ConcreteDataMatcher matcher{header->dataOrigin, header->dataDescription, header->subSpecification};
489 // If the matcher does not have an entry in the cache, deserialise it
490 // and cache the deserialised object at the given id.
491 auto path = fmt::format("{}", DataSpecUtils::describe(matcher));
492 LOGP(debug, "{}", path);
493 auto& cache = mRegistry.get<ObjectCache>();
494 auto cacheEntry = cache.matcherToMetadataId.find(path);
495 if (cacheEntry == cache.matcherToMetadataId.end()) {
496 cache.matcherToMetadataId.insert(std::make_pair(path, id));
497 cache.idToMetadata[id] = DataRefUtils::extractCCDBHeaders(ref);
498 LOGP(info, "Caching CCDB metadata {}: {}", id.value, path);
499 return cache.idToMetadata[id];
500 }
501 auto& oldId = cacheEntry->second;
502 // The id in the cache is the same, let's simply return it.
503 if (oldId.value == id.value) {
504 LOGP(debug, "Returning cached CCDB metatada {}: {}", id.value, path);
505 return cache.idToMetadata[id];
506 }
507 // The id in the cache is different. Let's destroy the old cached entry
508 // and create a new one.
509 LOGP(info, "Replacing cached entry {} with {} for {}", oldId.value, id.value, path);
510 cache.idToMetadata[id] = DataRefUtils::extractCCDBHeaders(ref);
511 oldId.value = id.value;
512 return cache.idToMetadata[id];
513 }
514
515 template <typename T>
516 requires(std::same_as<T, DataRef>)
517 decltype(auto) get(ConcreteDataMatcher matcher, int part = 0)
518 {
519 auto pos = getPos(matcher);
520 if (pos < 0) {
521 auto msg = describeAvailableInputs();
522 throw runtime_error_f("InputRecord::get: no input with binding %s found. %s", DataSpecUtils::describe(matcher).c_str(), msg.c_str());
523 }
524 return getByPos(pos, part);
525 }
526
527 template <typename T>
528 requires(std::same_as<T, TableConsumer>)
529 decltype(auto) get(ConcreteDataMatcher matcher, int part = 0)
530 {
531 auto ref = get<DataRef>(matcher, part);
532 auto data = reinterpret_cast<uint8_t const*>(ref.payload);
533 return std::make_unique<TableConsumer>(data, DataRefUtils::getPayloadSize(ref));
534 }
535
537 [[nodiscard]] bool isValid(std::string const& s) const
538 {
539 return isValid(s.c_str());
540 }
541
543 bool isValid(char const* s) const;
544 [[nodiscard]] bool isValid(int pos) const;
545
549 [[nodiscard]] size_t size() const;
550
554 [[nodiscard]] size_t countValidInputs() const;
555
556 template <typename ParentT, typename T>
558 {
559 public:
560 using ParentType = ParentT;
562 using iterator_category = std::forward_iterator_tag;
563 using value_type = T;
564 using reference = T&;
565 using pointer = T*;
566 using difference_type = std::ptrdiff_t;
567 using ElementType = typename std::remove_const<value_type>::type;
568
569 Iterator() = delete;
570
571 Iterator(ParentType const* parent, size_t position = 0, size_t size = 0)
572 : mPosition(position), mSize(size > position ? size : position), mParent(parent), mElement{nullptr, nullptr, nullptr}
573 {
574 if (mPosition < mSize) {
575 if (mParent->isValid(mPosition)) {
576 mElement = mParent->getByPos(mPosition);
577 } else {
578 ++(*this);
579 }
580 }
581 }
582
583 ~Iterator() = default;
584
585 // prefix increment
587 {
588 while (mPosition < mSize && ++mPosition < mSize) {
589 if (!mParent->isValid(mPosition)) {
590 continue;
591 }
592 mElement = mParent->getByPos(mPosition);
593 break;
594 }
595 if (mPosition >= mSize) {
596 // reset the element to the default value of the type
597 mElement = ElementType{};
598 }
599 return *this;
600 }
601 // postfix increment
602 SelfType operator++(int /*unused*/)
603 {
604 SelfType copy(*this);
605 operator++();
606 return copy;
607 }
608 // return reference
610 {
611 return mElement;
612 }
613 // comparison
614 bool operator==(const SelfType& rh) const
615 {
616 return mPosition == rh.mPosition;
617 }
618 // comparison
619 bool operator!=(const SelfType& rh) const
620 {
621 return mPosition != rh.mPosition;
622 }
623
624 [[nodiscard]] bool matches(o2::header::DataHeader matcher) const
625 {
626 if (mPosition >= mSize || mElement.header == nullptr) {
627 return false;
628 }
629 // at this point there must be a DataHeader, this has been checked by the DPL
630 // input cache
631 const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(mElement);
632 return *dh == matcher;
633 }
634
636 {
637 if (mPosition >= mSize || mElement.header == nullptr) {
638 return false;
639 }
640 // at this point there must be a DataHeader, this has been checked by the DPL
641 // input cache
642 const auto* dh = DataRefUtils::getHeader<o2::header::DataHeader*>(mElement);
643 return dh->dataOrigin == origin && (description == o2::header::gDataDescriptionInvalid || dh->dataDescription == description);
644 }
645
650
651 [[nodiscard]] ParentType const* parent() const
652 {
653 return mParent;
654 }
655
656 [[nodiscard]] size_t position() const
657 {
658 return mPosition;
659 }
660
661 private:
662 size_t mPosition;
663 size_t mSize;
664 ParentType const* mParent;
665 ElementType mElement;
666 };
667
671 template <typename T>
672 class InputRecordIterator : public Iterator<InputRecord, T>
673 {
674 public:
679 using pointer = typename BaseType::pointer;
680 using ElementType = typename std::remove_const<value_type>::type;
683
684 InputRecordIterator(InputRecord const* parent, size_t position = 0, size_t size = 0)
686 {
687 }
688
690 [[nodiscard]] ElementType getByPos(size_t pos) const
691 {
692 return this->parent()->getByPos(this->position(), pos);
693 }
694
696 [[nodiscard]] bool isValid(size_t = 0) const
697 {
698 if (this->position() < this->parent()->size()) {
699 return this->parent()->isValid(this->position());
700 }
701 return false;
702 }
703
705 [[nodiscard]] size_t size() const
706 {
707 return this->parent()->getNofParts(this->position());
708 }
709
710 [[nodiscard]] const_iterator begin() const
711 {
712 return const_iterator(this, 0, size());
713 }
714
715 [[nodiscard]] const_iterator end() const
716 {
717 return const_iterator(this, size());
718 }
719 };
720
723
724 [[nodiscard]] const_iterator begin() const
725 {
726 return {this, 0, size()};
727 }
728
729 [[nodiscard]] const_iterator end() const
730 {
731 return {this, size()};
732 }
733
735 {
736 return mSpan;
737 }
738
739 private:
740 // Produce a string describing the available inputs.
741 [[nodiscard]] std::string describeAvailableInputs() const;
742
743 ServiceRegistryRef mRegistry;
744 std::vector<InputRoute> const& mInputsSchema;
745 InputSpan& mSpan;
746};
747
748} // namespace o2::framework
749
750#endif // O2_FRAMEWORK_INPUTREGISTRY_H_
header::DataOrigin origin
header::DataDescription description
std::string binding
std::vector< OutputRoute > routes
std::ostringstream debug
uint16_t pos
Definition RawData.h:3
TBranch * ptr
std::default_delete< T > base
constexpr Deleter(const self_type &other)
@ Owning
don't delete the underlying buffer
constexpr Deleter(bool isOwning)
self_type & operator=(const self_type &other)
constexpr Deleter(const base &other)
typename std::remove_const< value_type >::type ElementType
InputRecordIterator(InputRecord const *parent, size_t position=0, size_t size=0)
size_t size() const
Get number of parts in input slot.
ElementType getByPos(size_t pos) const
Get element at {slotindex, partindex}.
typename BaseType::value_type value_type
Iterator< SelfType, const T > const_iterator
bool isValid(size_t=0) const
Check if slot is valid, index of part is not used.
typename std::remove_const< value_type >::type ElementType
bool operator!=(const SelfType &rh) const
bool matches(o2::header::DataOrigin origin, o2::header::DataDescription description=o2::header::gDataDescriptionInvalid) const
std::forward_iterator_tag iterator_category
Iterator(ParentType const *parent, size_t position=0, size_t size=0)
bool matches(o2::header::DataOrigin origin, o2::header::DataDescription description, o2::header::DataHeader::SubSpecificationType subspec) const
bool operator==(const SelfType &rh) const
ParentType const * parent() const
bool matches(o2::header::DataHeader matcher) const
The input API of the Data Processing Layer This class holds the inputs which are valid for processing...
int getPos(const char *name) const
decltype(auto) get(ConcreteDataMatcher matcher, int part=0)
DataRef getRef(R binding, int part=0) const
const_iterator begin() const
bool isValid(std::string const &s) const
Helper method to be used to check if a given part of the InputRecord is present.
decltype(auto) get(R binding, int part=0) const
const_iterator end() const
DataRef getRef(R binding, int part=0) const
DataRef getDataRefByString(const char *bindingName, int part=0) const
size_t countValidInputs() const
static DataRef getByPos(std::vector< InputRoute > const &routes, InputSpan const &span, int pos, int part=0)
decltype(auto) get(ConcreteDataMatcher matcher, int part=0)
std::map< std::string, std::string > & get(R binding, int part=0) const
size_t getNofParts(int pos) const
DataRef getFirstValid(bool throwOnFailure=false) const
Get the ref of the first valid input. If requested, throw an error if none is found.
DataRef getRef(R ref, int part=0) const
GLuint64EXT * result
Definition glcorearb.h:5662
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLboolean * data
Definition glcorearb.h:298
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLboolean r
Definition glcorearb.h:1233
GLuint start
Definition glcorearb.h:469
GLint ref
Definition glcorearb.h:291
GLuint id
Definition glcorearb.h:650
constexpr o2::header::DataDescription gDataDescriptionInvalid
Definition DataHeader.h:597
Defining PrimaryVertex explicitly as messageable.
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
constexpr o2::header::SerializationMethod gSerializationMethodCCDB
Definition DataHeader.h:329
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
static o2::header::DataHeader::PayloadSizeType getPayloadSize(const DataRef &ref)
static std::map< std::string, std::string > extractCCDBHeaders(DataRef const &ref)
static auto as(DataRef const &ref)
static std::string describe(InputSpec const &spec)
static constexpr size_t INVALID
static Id fromRef(DataRef &ref)
Definition ObjectCache.h:26
std::unordered_map< Id, void *, Id::hash_fn > idToObject
Definition ObjectCache.h:49
std::unordered_map< std::string, Id > matcherToMetadataId
Definition ObjectCache.h:54
the main header struct
Definition DataHeader.h:619
uint32_t SubSpecificationType
Definition DataHeader.h:621
VectorOfTObjectPtrs other
uint64_t const void const *restrict const msg
Definition x9.h:153