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