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