Project
Loading...
Searching...
No Matches
DataDescriptorMatcher.cxx
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
18#include "Headers/DataHeader.h"
19#include "Headers/Stack.h"
20#include <array>
21#include <iostream>
22#include <memory_resource>
23
25{
26
28{
29 // First we check if there is any pending update
30 for (size_t i = 0; i < mPerformedUpdates; ++i) {
31 if (mUpdates[i].position == pos) {
32 return mUpdates[i].newValue;
33 }
34 }
35 // Otherwise we return the element.
36 return mElements.at(pos).value;
37}
38
39void VariableContext::publish(void (*callback)(VariableContext const&, TimesliceSlot slot, void*), void* context, TimesliceSlot slot)
40{
41 bool anyPublish = false;
42 for (size_t i = 0; i < MAX_MATCHING_VARIABLE; i++) {
43 auto& element = mElements[i];
44
45 if (element.commitVersion == element.publishVersion) {
46 continue;
47 }
48 element.publishVersion = element.commitVersion;
49 anyPublish = true;
50 }
51 if (anyPublish) {
52 callback(*this, slot, context);
53 }
54}
55
57{
58 for (size_t i = 0; i < mPerformedUpdates; ++i) {
59 auto& element = mElements[mUpdates[i].position];
60 element.value = mUpdates[i].newValue;
61 element.commitVersion++;
62 }
63 mPerformedUpdates = 0;
64}
65
67{
68 mPerformedUpdates = 0;
69 for (auto& element : mElements) {
70 element.value = None{};
71 }
72}
73
75{
76 if (auto ref = std::get_if<ContextRef>(&mValue)) {
77 auto& variable = context.get(ref->index);
78 if (auto value = std::get_if<std::string>(&variable)) {
79 return strncmp(header.dataOrigin.str, value->c_str(), header::DataOrigin::size) == 0;
80 }
81 auto maxSize = strnlen(header.dataOrigin.str, header::DataOrigin::size);
82 context.put({ref->index, std::string(header.dataOrigin.str, maxSize)});
83 return true;
84 } else if (auto s = std::get_if<std::string>(&mValue)) {
85 return strncmp(header.dataOrigin.str, s->c_str(), header::DataOrigin::size) == 0;
86 }
87 throw runtime_error("Mismatching type for variable");
88}
89
91{
92 if (auto ref = std::get_if<ContextRef>(&mValue)) {
93 auto& variable = context.get(ref->index);
94 if (auto value = std::get_if<std::string>(&variable)) {
95 return strncmp(header.dataDescription.str, value->c_str(), header::DataDescription::size) == 0;
96 }
97 auto maxSize = strnlen(header.dataDescription.str, header::DataDescription::size);
98 context.put({ref->index, std::string(header.dataDescription.str, maxSize)});
99 return true;
100 } else if (auto s = std::get_if<std::string>(&this->mValue)) {
101 return strncmp(header.dataDescription.str, s->c_str(), header::DataDescription::size) == 0;
102 }
103 throw runtime_error("Mismatching type for variable");
104}
105
107{
108 if (auto ref = std::get_if<ContextRef>(&mValue)) {
109 auto& variable = context.get(ref->index);
110 if (auto value = std::get_if<header::DataHeader::SubSpecificationType>(&variable)) {
111 return header.subSpecification == *value;
112 }
113 context.put({ref->index, header.subSpecification});
114 return true;
115 } else if (auto v = std::get_if<header::DataHeader::SubSpecificationType>(&mValue)) {
116 return header.subSpecification == *v;
117 }
118 throw runtime_error("Mismatching type for variable");
119}
120
125{
126 if (auto ref = std::get_if<ContextRef>(&mValue)) {
127 auto& variable = context.get(ref->index);
128 if (auto value = std::get_if<uint64_t>(&variable)) {
129 return (dph.startTime / mScale) == *value;
130 }
131 context.put({ref->index, dph.startTime / mScale});
132 // We always put in 12 the creation time
133 context.put({CREATIONTIME_POS, dph.creation});
134 // We always put in 13 the runNumber
135 context.put({RUNNUMBER_POS, dh.runNumber});
136 // We always put in 14 the tfCounter
137 context.put({TFCOUNTER_POS, dh.tfCounter});
138 // We always put in 15 the firstTForbit
139 context.put({FIRSTTFORBIT_POS, dh.firstTForbit});
140 return true;
141 } else if (auto v = std::get_if<uint64_t>(&mValue)) {
142 return (dph.startTime / mScale) == *v;
143 }
144 throw runtime_error("Mismatching type for variable");
145}
146
148 : mOp{other.mOp},
149 mLeft{ConstantValueMatcher{false}},
150 mRight{ConstantValueMatcher{false}}
151{
152 if (auto pval0 = std::get_if<OriginValueMatcher>(&other.mLeft)) {
153 mLeft = *pval0;
154 } else if (auto pval1 = std::get_if<DescriptionValueMatcher>(&other.mLeft)) {
155 mLeft = *pval1;
156 } else if (auto pval2 = std::get_if<SubSpecificationTypeValueMatcher>(&other.mLeft)) {
157 mLeft = *pval2;
158 } else if (auto pval3 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&other.mLeft)) {
159 // A moved-from node keeps the unique_ptr alternative, only null.
160 mLeft = *pval3 ? std::make_unique<DataDescriptorMatcher>(**pval3) : nullptr;
161 } else if (auto pval4 = std::get_if<ConstantValueMatcher>(&other.mLeft)) {
162 mLeft = *pval4;
163 } else if (auto pval5 = std::get_if<StartTimeValueMatcher>(&other.mLeft)) {
164 mLeft = *pval5;
165 } else {
166 std::cerr << (other.mLeft.index() == std::variant_npos) << std::endl;
168 }
169
170 if (auto pval0 = std::get_if<OriginValueMatcher>(&other.mRight)) {
171 mRight = *pval0;
172 } else if (auto pval1 = std::get_if<DescriptionValueMatcher>(&other.mRight)) {
173 mRight = *pval1;
174 } else if (auto pval2 = std::get_if<SubSpecificationTypeValueMatcher>(&other.mRight)) {
175 mRight = *pval2;
176 } else if (auto pval3 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&other.mRight)) {
177 // A moved-from node keeps the unique_ptr alternative, only null.
178 mRight = *pval3 ? std::make_unique<DataDescriptorMatcher>(**pval3) : nullptr;
179 } else if (auto pval4 = std::get_if<ConstantValueMatcher>(&other.mRight)) {
180 mRight = *pval4;
181 } else if (auto pval5 = std::get_if<StartTimeValueMatcher>(&other.mRight)) {
182 mRight = *pval5;
183 } else {
185 }
186}
187
192
195 : mOp{op},
196 mLeft{std::move(lhs)},
197 mRight{std::move(rhs)}
198{
199}
200
204{
206 dh.dataOrigin = matcher.origin;
207 dh.dataDescription = matcher.description;
208 dh.subSpecification = matcher.subSpec;
209 DataProcessingHeader dph{0, 0, 0};
210 alignas(std::max_align_t) std::array<std::byte, sizeof(header::DataHeader) + sizeof(DataProcessingHeader) + alignof(std::max_align_t)> buffer;
211 std::pmr::monotonic_buffer_resource resource{buffer.data(), buffer.size(), std::pmr::null_memory_resource()};
212 header::Stack s{header::Stack::allocator_type{&resource}, dh, dph};
213
214 return this->match(reinterpret_cast<char const*>(s.data()), context);
215}
216
220{
222 dh.dataOrigin = matcher.origin;
223 dh.dataDescription = matcher.description;
224 dh.subSpecification = 0;
225 DataProcessingHeader dph{0, 0, 0};
226 alignas(std::max_align_t) std::array<std::byte, sizeof(header::DataHeader) + sizeof(DataProcessingHeader) + alignof(std::max_align_t)> buffer;
227 std::pmr::monotonic_buffer_resource resource{buffer.data(), buffer.size(), std::pmr::null_memory_resource()};
228 header::Stack s{header::Stack::allocator_type{&resource}, dh, dph};
229
230 return this->match(reinterpret_cast<char const*>(s.data()), context);
231}
232
234{
235 return this->match(reinterpret_cast<char const*>(&header), context);
236}
237
239{
240 return this->match(reinterpret_cast<char const*>(stack.data()), context);
241}
242
243// actual polymorphic matcher which is able to cast the pointer to the correct
244// kind of header.
245bool DataDescriptorMatcher::match(char const* d, VariableContext& context) const
246{
247 bool leftValue = false, rightValue = false;
248
249 // FIXME: Using std::visit is not API compatible due to a new
250 // exception being thrown. This is the ABI compatible version.
251 // Replace with:
252 //
253 // auto eval = [&d](auto&& arg) -> bool {
254 // using T = std::decay_t<decltype(arg)>;
255 // if constexpr (std::is_same_v<T, std::unique_ptr<DataDescriptorMatcher>>) {
256 // return arg->match(d, context);
257 // if constexpr (std::is_same_v<T, ConstantValueMatcher>) {
258 // return arg->match(d);
259 // } else {
260 // return arg.match(d, context);
261 // }
262 // };
263 // switch (mOp) {
264 // case Op::Or:
265 // return std::visit(eval, mLeft) || std::visit(eval, mRight);
266 // case Op::And:
267 // return std::visit(eval, mLeft) && std::visit(eval, mRight);
268 // case Op::Xor:
269 // return std::visit(eval, mLeft) ^ std::visit(eval, mRight);
270 // case Op::Just:
271 // return std::visit(eval, mLeft);
272 // case Op::Not:
273 // return !std::visit(eval, mLeft);
274 // }
275 // When we drop support for macOS 10.13
276 if (auto pval0 = std::get_if<OriginValueMatcher>(&mLeft)) {
277 auto dh = o2::header::get<header::DataHeader*>(d);
278 if (dh == nullptr) {
279 throw runtime_error("Cannot find DataHeader");
280 }
281 leftValue = pval0->match(*dh, context);
282 } else if (auto pval1 = std::get_if<DescriptionValueMatcher>(&mLeft)) {
283 auto dh = o2::header::get<header::DataHeader*>(d);
284 if (dh == nullptr) {
285 throw runtime_error("Cannot find DataHeader");
286 }
287 leftValue = pval1->match(*dh, context);
288 } else if (auto pval2 = std::get_if<SubSpecificationTypeValueMatcher>(&mLeft)) {
289 auto dh = o2::header::get<header::DataHeader*>(d);
290 if (dh == nullptr) {
291 throw runtime_error("Cannot find DataHeader");
292 }
293 leftValue = pval2->match(*dh, context);
294 } else if (auto pval3 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&mLeft)) {
295 leftValue = (*pval3)->match(d, context);
296 } else if (auto pval4 = std::get_if<ConstantValueMatcher>(&mLeft)) {
297 leftValue = pval4->match();
298 } else if (auto pval5 = std::get_if<StartTimeValueMatcher>(&mLeft)) {
299 auto dh = o2::header::get<header::DataHeader*>(d);
300 auto dph = o2::header::get<DataProcessingHeader*>(d);
301 if (dph == nullptr) {
302 throw runtime_error("Cannot find DataProcessingHeader");
303 }
304 leftValue = pval5->match(*dh, *dph, context);
305 } else {
306 throw runtime_error("Bad parsing tree");
307 }
308 // Common speedup.
309 if (mOp == Op::And && leftValue == false) {
310 return false;
311 }
312 if (mOp == Op::Or && leftValue == true) {
313 return true;
314 }
315 if (mOp == Op::Just) {
316 return leftValue;
317 }
318 if (mOp == Op::Not) {
319 return !leftValue;
320 }
321
322 if (auto pval0 = std::get_if<OriginValueMatcher>(&mRight)) {
323 auto dh = o2::header::get<header::DataHeader*>(d);
324 rightValue = pval0->match(*dh, context);
325 } else if (auto pval1 = std::get_if<DescriptionValueMatcher>(&mRight)) {
326 auto dh = o2::header::get<header::DataHeader*>(d);
327 rightValue = pval1->match(*dh, context);
328 } else if (auto pval2 = std::get_if<SubSpecificationTypeValueMatcher>(&mRight)) {
329 auto dh = o2::header::get<header::DataHeader*>(d);
330 rightValue = pval2->match(*dh, context);
331 } else if (auto pval3 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&mRight)) {
332 rightValue = (*pval3)->match(d, context);
333 } else if (auto pval4 = std::get_if<ConstantValueMatcher>(&mRight)) {
334 rightValue = pval4->match();
335 } else if (auto pval5 = std::get_if<StartTimeValueMatcher>(&mRight)) {
336 auto dh = o2::header::get<header::DataHeader*>(d);
337 auto dph = o2::header::get<DataProcessingHeader*>(d);
338 rightValue = pval5->match(*dh, *dph, context);
339 }
340 // There are cases in which not having a rightValue might be legitimate,
341 // so we do not throw an exception.
342 switch (mOp) {
343 case Op::Or:
344 return leftValue || rightValue;
345 case Op::And:
346 return leftValue && rightValue;
347 case Op::Xor:
348 return leftValue ^ rightValue;
349 case Op::Just:
350 return leftValue;
351 case Op::Not:
352 return !leftValue;
353 }
354 throw runtime_error("Bad parsing tree");
355};
356
358{
359 if (other.mOp != this->mOp) {
360 return false;
361 }
362
363 bool leftValue = false;
364
365 {
366 auto v1 = std::get_if<OriginValueMatcher>(&this->mLeft);
367 auto v2 = std::get_if<OriginValueMatcher>(&other.mLeft);
368 if (v1 && v2 && *v1 == *v2) {
369 leftValue = true;
370 }
371 }
372
373 {
374 auto v1 = std::get_if<DescriptionValueMatcher>(&this->mLeft);
375 auto v2 = std::get_if<DescriptionValueMatcher>(&other.mLeft);
376 if (v1 && v2 && *v1 == *v2) {
377 leftValue = true;
378 }
379 }
380
381 {
382 auto v1 = std::get_if<SubSpecificationTypeValueMatcher>(&this->mLeft);
383 auto v2 = std::get_if<SubSpecificationTypeValueMatcher>(&other.mLeft);
384 if (v1 && v2 && *v1 == *v2) {
385 leftValue = true;
386 }
387 }
388
389 {
390 auto v1 = std::get_if<ConstantValueMatcher>(&this->mLeft);
391 auto v2 = std::get_if<ConstantValueMatcher>(&other.mLeft);
392 if (v1 && v2 && *v1 == *v2) {
393 leftValue = true;
394 }
395 }
396
397 {
398 auto v1 = std::get_if<StartTimeValueMatcher>(&this->mLeft);
399 auto v2 = std::get_if<StartTimeValueMatcher>(&other.mLeft);
400 if (v1 && v2 && *v1 == *v2) {
401 leftValue = true;
402 }
403 }
404
405 {
406 auto v1 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&this->mLeft);
407 auto v2 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&other.mLeft);
408 if (v1 && v2 && v1->get() && v2->get() && (**v1 == **v2)) {
409 leftValue = true;
410 }
411 }
412
413 // Shortcut the fact that the left side is different.
414 if (leftValue == false) {
415 return false;
416 }
417
418 if (mOp == Op::Just) {
419 return leftValue;
420 }
421
422 if (mOp == Op::Not) {
423 return leftValue;
424 }
425
426 {
427 auto v1 = std::get_if<OriginValueMatcher>(&this->mRight);
428 auto v2 = std::get_if<OriginValueMatcher>(&other.mRight);
429 if (v1 && v2 && *v1 == *v2) {
430 return true;
431 }
432 }
433
434 {
435 auto v1 = std::get_if<DescriptionValueMatcher>(&this->mRight);
436 auto v2 = std::get_if<DescriptionValueMatcher>(&other.mRight);
437 if (v1 && v2 && *v1 == *v2) {
438 return true;
439 }
440 }
441
442 {
443 auto v1 = std::get_if<SubSpecificationTypeValueMatcher>(&this->mRight);
444 auto v2 = std::get_if<SubSpecificationTypeValueMatcher>(&other.mRight);
445 if (v1 && v2 && *v1 == *v2) {
446 return true;
447 }
448 }
449
450 {
451 auto v1 = std::get_if<ConstantValueMatcher>(&this->mRight);
452 auto v2 = std::get_if<ConstantValueMatcher>(&other.mRight);
453 if (v1 && v2 && *v1 == *v2) {
454 return true;
455 }
456 }
457
458 {
459 auto v1 = std::get_if<StartTimeValueMatcher>(&this->mRight);
460 auto v2 = std::get_if<StartTimeValueMatcher>(&other.mRight);
461 if (v1 && v2 && *v1 == *v2) {
462 return true;
463 }
464 }
465
466 {
467 auto v1 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&this->mRight);
468 auto v2 = std::get_if<std::unique_ptr<DataDescriptorMatcher>>(&other.mRight);
469 if (v1 && v2 && v1->get() && v2->get() && (**v1 == **v2)) {
470 return true;
471 }
472 }
473 // We alredy know the left side is true.
474 return false;
475}
476
477std::ostream& operator<<(std::ostream& os, DataDescriptorMatcher const& matcher)
478{
479 auto edgeWalker = overloaded{
480 [&os](EdgeActions::EnterNode action) {
481 os << "(" << action.node->mOp;
482 if (action.node->mOp == DataDescriptorMatcher::Op::Just ||
483 action.node->mOp == DataDescriptorMatcher::Op::Not) {
485 }
487 },
488 [&os](EdgeActions::EnterLeft) { os << " "; },
489 [&os](EdgeActions::ExitLeft) { os << " "; },
490 [&os](EdgeActions::EnterRight) { os << " "; },
491 [&os](EdgeActions::ExitRight) { os << " "; },
492 [&os](EdgeActions::ExitNode) { os << ")"; },
493 [&os](auto) {}};
494 auto leafWalker = overloaded{
495 [&os](OriginValueMatcher const& origin) { os << "origin:" << origin; },
496 [&os](DescriptionValueMatcher const& description) { os << "description:" << description; },
497 [&os](SubSpecificationTypeValueMatcher const& subSpec) { os << "subSpec:" << subSpec; },
498 [&os](StartTimeValueMatcher const& startTime) { os << "startTime:" << startTime; },
499 [&os](ConstantValueMatcher const& constant) {},
500 [&os](auto t) { os << "not implemented " << typeid(decltype(t)).name(); }};
502 edgeWalker,
503 leafWalker);
504
505 return os;
506}
507
508std::ostream& operator<<(std::ostream& os, DataDescriptorMatcher::Op const& op)
509{
510 switch (op) {
512 os << "and";
513 break;
515 os << "or";
516 break;
518 os << "just";
519 break;
521 os << "not";
522 break;
524 os << "xor";
525 break;
526 }
527 return os;
528}
529
530} // namespace o2::framework::data_matcher
header::DataOrigin origin
header::DataDescription description
size_t maxSize
#define O2_BUILTIN_UNREACHABLE
atype::type element
std::vector< std::string > header
int32_t i
uint32_t op
uint16_t pos
Definition RawData.h:3
uint32_t stack
Definition RawData.h:1
bool match(ConcreteDataMatcher const &matcher, VariableContext &context) const
bool operator==(DataDescriptorMatcher const &other) const
DataDescriptorMatcher & operator=(DataDescriptorMatcher const &other)
DataDescriptorMatcher(DataDescriptorMatcher const &other)
Something which can be matched against a header::DataDescription.
bool match(header::DataHeader const &header, VariableContext &context) const
Something which can be matched against a header::DataOrigin.
bool match(header::DataHeader const &header, VariableContext &context) const
Matcher on actual time, as reported in the DataProcessingHeader.
bool match(header::DataHeader const &dh, DataProcessingHeader const &dph, VariableContext &context) const
Something which can be matched against a header::SubSpecificationType.
bool match(header::DataHeader const &header, VariableContext &context) const
void publish(void(*callback)(VariableContext const &, TimesliceSlot slot, void *context), void *context, TimesliceSlot slot)
ContextElement::Value const & get(size_t pos) const
GLuint buffer
Definition glcorearb.h:655
const GLdouble * v
Definition glcorearb.h:832
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLfloat GLfloat v1
Definition glcorearb.h:812
GLint ref
Definition glcorearb.h:291
GLfloat GLfloat GLfloat v2
Definition glcorearb.h:813
std::variant< OriginValueMatcher, DescriptionValueMatcher, SubSpecificationTypeValueMatcher, std::unique_ptr< DataDescriptorMatcher >, ConstantValueMatcher, StartTimeValueMatcher > Node
std::ostream & operator<<(std::ostream &os, DataDescriptorMatcher const &matcher)
@ CREATIONTIME_POS
The DataHeader::runNumber associated to the timeslice.
@ FIRSTTFORBIT_POS
The DataHeader::tfCounter associated to the timeslice.
@ TFCOUNTER_POS
The DataProcessingHeader::startTime associated to the timeslice.
@ RUNNUMBER_POS
The DataHeader::firstTForbit associated to the timeslice.
RuntimeErrorRef runtime_error(const char *)
header::DataHeader::SubSpecificationType subSpec
std::variant< uint32_t, uint64_t, std::string, None > Value
static void walk(DataDescriptorMatcher const &top, EDGEWALKER edgeWalker, LEAFWALKER leafWalker)
Marks an empty item in the context.
From https://en.cppreference.com/w/cpp/utility/variant/visit.
const std::byte * data() const noexcept
Definition DataHeader.h:425
the main header struct
Definition DataHeader.h:623
TFCounterType tfCounter
Definition DataHeader.h:684
TForbitType firstTForbit
Definition DataHeader.h:679
DataDescription dataDescription
Definition DataHeader.h:641
SubSpecificationType subSpecification
Definition DataHeader.h:661
RunNumberType runNumber
Definition DataHeader.h:689
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