Project
Loading...
Searching...
No Matches
ExpressionJSONHelpers.cxx
Go to the documentation of this file.
1// Copyright 2019-2025 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.
12
13#include <rapidjson/reader.h>
14#include <rapidjson/prettywriter.h>
15#include <rapidjson/istreamwrapper.h>
16#include <rapidjson/ostreamwrapper.h>
17#include <rapidjson/error/en.h>
18
19#include <stack>
20#include <iostream>
22
23namespace o2::framework
24{
25namespace
26{
27using nodes = expressions::Node::self_t;
28enum struct Nodes : int {
29 NLITERAL = 0,
30 NBINDING = 1,
31 NOP = 2,
32 NNPH = 3,
33 NCOND = 4,
34 NPAR = 5
35};
36
37enum struct ToWrite {
38 FULL,
39 LEFT,
40 RIGHT,
41 COND,
42 POP
43};
44
45struct Entry {
46 expressions::Node* ptr = nullptr;
47 ToWrite toWrite = ToWrite::FULL;
48};
49
50std::array<std::string_view, 11> validKeys{
51 "projectors",
52 "kind",
53 "binding",
54 "index",
55 "arrow_type",
56 "value",
57 "hash",
58 "operation",
59 "left",
60 "right",
61 "condition"};
62
63struct ExpressionReader : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, ExpressionReader> {
64 using Ch = rapidjson::UTF8<>::Ch;
65 using SizeType = rapidjson::SizeType;
66
67 enum struct State {
68 IN_START, // global start
69 IN_LIST, // opening brace of the list
70 IN_ROOT, // after encountering the opening of the expression object
71 IN_LEFT, // in "left" key - subexpression
72 IN_RIGHT, // in "right" key - subexpression
73 IN_COND, // in "condition" key - subexpression
74 IN_NODE_LITERAL, // in literal node
75 IN_NODE_BINDING, // in binding node
76 IN_NODE_OP, // in operation node
77 IN_NODE_CONDITIONAL, // in conditional node
78 IN_ERROR // generic error state
79 };
80
81 std::stack<State> states;
82 std::stack<Entry> path;
83 std::ostringstream debug;
84
85 std::vector<expressions::Projector> result;
86
87 std::unique_ptr<expressions::Node> rootNode = nullptr;
88 std::unique_ptr<expressions::Node> node = nullptr;
90 atype::type type;
91 Nodes kind;
92 std::string binding;
94 uint32_t hash;
95 size_t index;
96
97 std::string previousKey;
98 std::string currentKey;
99
100 ExpressionReader()
101 {
102 debug << ">>> Start" << std::endl;
103 states.push(State::IN_START);
104 }
105
106 bool StartArray()
107 {
108 debug << "StartArray()" << std::endl;
109 if (states.top() == State::IN_START) {
110 states.push(State::IN_LIST);
111 return true;
112 }
113 states.push(State::IN_ERROR);
114 return false;
115 }
116
117 bool EndArray(SizeType)
118 {
119 debug << "EndArray()" << std::endl;
120 if (states.top() == State::IN_LIST) {
121 states.pop();
122 return true;
123 }
124 states.push(State::IN_ERROR);
125 return false;
126 }
127
128 bool Key(const Ch* str, SizeType, bool)
129 {
130 debug << "Key(" << str << ")" << std::endl;
132 currentKey = str;
133 if (std::find(validKeys.begin(), validKeys.end(), currentKey) == validKeys.end()) {
134 states.push(State::IN_ERROR);
135 return false;
136 }
137
138 if (states.top() == State::IN_START) {
139 if (currentKey.compare("projectors") == 0) {
140 return true;
141 }
142 }
143
144 if (states.top() == State::IN_ROOT) {
145 if (currentKey.compare("kind") == 0) {
146 return true;
147 } else {
148 states.push(State::IN_ERROR); // should start from root node
149 return false;
150 }
151 }
152
153 if (states.top() == State::IN_LEFT || states.top() == State::IN_RIGHT || states.top() == State::IN_COND) {
154 if (currentKey.compare("kind") == 0) {
155 return true;
156 }
157 }
158
159 if (states.top() == State::IN_NODE_LITERAL || states.top() == State::IN_NODE_OP || states.top() == State::IN_NODE_BINDING || states.top() == State::IN_NODE_CONDITIONAL) {
160 if (currentKey.compare("index") == 0) {
161 return true;
162 }
163 if (currentKey.compare("left") == 0) {
164 // this is the point where the node header is parsed and we can create it
165 // create a new node instance here and set a pointer to it in a parent (current stack top), based on its state
166 // push the new node into the stack with LEFT state
167 switch (states.top()) {
168 case State::IN_NODE_LITERAL:
169 node = std::make_unique<expressions::Node>(expressions::LiteralNode{value, type});
170 break;
171 case State::IN_NODE_BINDING:
172 node = std::make_unique<expressions::Node>(expressions::BindingNode{hash, type}, binding);
173 break;
174 case State::IN_NODE_OP:
175 node = std::make_unique<expressions::Node>(expressions::OpNode{operation}, expressions::LiteralNode{-1});
176 break;
177 case State::IN_NODE_CONDITIONAL:
178 node = std::make_unique<expressions::Node>(expressions::ConditionalNode{}, expressions::LiteralNode{-1}, expressions::LiteralNode{-1}, expressions::LiteralNode{true});
179 break;
180 default:
181 states.push(State::IN_ERROR);
182 return false;
183 }
184
185 if (path.empty()) {
186 rootNode = std::move(node);
187 path.emplace(rootNode.get(), ToWrite::LEFT);
188 } else {
189 auto* n = path.top().ptr;
190 switch (path.top().toWrite) {
191 case ToWrite::LEFT:
192 n->left = std::move(node);
193 path.top().toWrite = ToWrite::RIGHT;
194 path.emplace(n->left.get(), ToWrite::LEFT);
195 break;
196 case ToWrite::RIGHT:
197 n->right = std::move(node);
198 path.top().toWrite = ToWrite::COND;
199 path.emplace(n->right.get(), ToWrite::LEFT);
200 break;
201 case ToWrite::COND:
202 n->condition = std::move(node);
203 path.pop();
204 path.emplace(n->condition.get(), ToWrite::LEFT);
205 break;
206 default:
207 states.push(State::IN_ERROR);
208 return false;
209 }
210 }
211
212 states.push(State::IN_LEFT);
213 return true;
214 }
215 if (currentKey.compare("right") == 0) {
216 if (states.top() == State::IN_LEFT) {
217 states.pop();
218 }
219 // move the stack state of the node to RIGHT state
220 path.top().toWrite = ToWrite::RIGHT;
221 states.push(State::IN_RIGHT);
222 return true;
223 }
224 if (currentKey.compare("condition") == 0) {
225 if (states.top() == State::IN_RIGHT) {
226 states.pop();
227 }
228 // move the stack state of the node to COND state
229 path.top().toWrite = ToWrite::COND;
230 states.push(State::IN_COND);
231 return true;
232 }
233 }
234
235 if (states.top() == State::IN_NODE_LITERAL) {
236 if (currentKey.compare("arrow_type") == 0 || currentKey.compare("value") == 0) {
237 return true;
238 }
239 }
240
241 if (states.top() == State::IN_NODE_BINDING) {
242 if (currentKey.compare("binding") == 0 || currentKey.compare("hash") == 0 || currentKey.compare("arrow_type") == 0) {
243 return true;
244 }
245 }
246
247 if (states.top() == State::IN_NODE_OP) {
248 if (currentKey.compare("operation") == 0) {
249 return true;
250 }
251 }
252
253 debug << ">>> Unrecognized" << std::endl;
254 states.push(State::IN_ERROR);
255 return false;
256 }
257
258 bool StartObject()
259 {
260 // opening brace encountered
261 debug << "StartObject()" << std::endl;
262 // the first opening brace in the input
263 if (states.top() == State::IN_START) {
264 return true;
265 }
266 // the opening of an expression
267 if (states.top() == State::IN_LIST) {
268 states.push(State::IN_ROOT);
269 return true;
270 }
271 // if we are looking at subexpression
272 if (states.top() == State::IN_LEFT || states.top() == State::IN_RIGHT || states.top() == State::IN_COND) { // ready to start a new node
273 return true;
274 }
275 // no other object starts are expected
276 states.push(State::IN_ERROR);
277 return false;
278 }
279
280 bool EndObject(SizeType)
281 {
282 // closing brace encountered
283 debug << "EndObject()" << std::endl;
284 // we are closing up an expression
285 if (states.top() == State::IN_NODE_LITERAL || states.top() == State::IN_NODE_OP || states.top() == State::IN_NODE_BINDING || states.top() == State::IN_NODE_CONDITIONAL) { // finalize node
286 // finalize the current node and pop it from the stack (the pointers should be already set
287 states.pop();
288 // subexpression
289 if (states.top() == State::IN_LEFT || states.top() == State::IN_RIGHT || states.top() == State::IN_COND) {
290 states.pop();
291 return true;
292 }
293
294 // expression
295 if (states.top() == State::IN_ROOT) {
296 result.emplace_back(std::move(rootNode));
297 states.pop();
298 return true;
299 }
300 }
301
302 // we are closing the list
303 if (states.top() == State::IN_START) {
304 return true;
305 }
306 // no other object ends are expectedd
307 states.push(State::IN_ERROR);
308 return false;
309 }
310
311 bool Null()
312 {
313 // null value
314 debug << "Null()" << std::endl;
315 // the subexpression can be empty
316 if (states.top() == State::IN_LEFT || states.top() == State::IN_RIGHT || states.top() == State::IN_COND) {
317 // empty node, nothing to do
318 // move the path state to the next
319 if (path.top().toWrite == ToWrite::LEFT) {
320 path.top().toWrite = ToWrite::RIGHT;
321 } else if (path.top().toWrite == ToWrite::RIGHT) {
322 path.top().toWrite = ToWrite::COND;
323 } else if (path.top().toWrite == ToWrite::COND) {
324 path.pop();
325 }
326
327 states.pop();
328 return true;
329 }
330 states.push(State::IN_ERROR); // no other contexts allow null
331 return false;
332 }
333
334 bool Bool(bool b)
335 {
336 debug << "Bool(" << b << ")" << std::endl;
337 // can be a value in a literal node
338 if (states.top() == State::IN_NODE_LITERAL && currentKey.compare("value") == 0) {
339 value = b;
340 return true;
341 }
342 states.push(State::IN_ERROR); // no other contexts allow booleans
343 return false;
344 }
345
346 bool Int(int i)
347 {
348 debug << "Int(" << i << ")" << std::endl;
349 // can be a value in a literal node
350 if (states.top() == State::IN_NODE_LITERAL && currentKey.compare("value") == 0) { // literal
351 switch (type) {
352 case atype::INT8:
353 value = (int8_t)i;
354 break;
355 case atype::INT16:
356 value = (int16_t)i;
357 break;
358 case atype::INT32:
359 value = i;
360 break;
361 case atype::UINT8:
362 value = (uint8_t)i;
363 break;
364 case atype::UINT16:
365 value = (uint16_t)i;
366 break;
367 case atype::UINT32:
368 value = (uint32_t)i;
369 break;
370 default:
371 states.push(State::IN_ERROR);
372 return false;
373 }
374 return true;
375 }
376 // can be a node kind designator
377 if (states.top() == State::IN_ROOT || states.top() == State::IN_LEFT || states.top() == State::IN_RIGHT || states.top() == State::IN_COND) {
378 if (currentKey.compare("kind") == 0) {
379 kind = (Nodes)i;
380 switch (kind) {
381 case Nodes::NLITERAL:
382 case Nodes::NNPH:
383 case Nodes::NPAR: {
384 states.push(State::IN_NODE_LITERAL);
385 debug << ">>> Literal node" << std::endl;
386 return true;
387 }
388 case Nodes::NBINDING: {
389 states.push(State::IN_NODE_BINDING);
390 debug << ">>> Binding node" << std::endl;
391 return true;
392 }
393 case Nodes::NOP: {
394 states.push(State::IN_NODE_OP);
395 debug << ">>> Operation node" << std::endl;
396 return true;
397 }
398 case Nodes::NCOND: {
399 states.push(State::IN_NODE_CONDITIONAL);
400 debug << ">>> Conditional node" << std::endl;
401 return true;
402 }
403 }
404 }
405 }
406 // can be node index
407 if (states.top() == State::IN_NODE_BINDING || states.top() == State::IN_NODE_CONDITIONAL || states.top() == State::IN_NODE_LITERAL || states.top() == State::IN_NODE_OP) {
408 if (currentKey.compare("index") == 0) {
409 index = (size_t)i;
410 return true;
411 }
412 }
413 // can be a node type designator
414 if (states.top() == State::IN_NODE_LITERAL || states.top() == State::IN_NODE_BINDING) {
415 if (currentKey.compare("arrow_type") == 0) {
416 type = (atype::type)i;
417 return true;
418 }
419 }
420 // can be a node operation designato
421 if (states.top() == State::IN_NODE_OP && currentKey.compare("operation") == 0) {
423 return true;
424 }
425 states.push(State::IN_ERROR); // no other contexts allow ints
426 return false;
427 }
428
429 bool Uint(unsigned i)
430 {
431 debug << "Uint(" << i << ")" << std::endl;
432 // can be node hash
433 if (states.top() == State::IN_NODE_BINDING && currentKey.compare("hash") == 0) {
434 hash = i;
435 return true;
436 }
437 // any positive value will be first read as unsigned, however the actual type is determined by node's arrow_type
438 debug << ">> falling back to Int" << std::endl;
439 return Int(i);
440 }
441
442 bool Int64(int64_t i)
443 {
444 debug << "Int64(" << i << ")" << std::endl;
445 // can only be a literal node value
446 if (states.top() == State::IN_NODE_LITERAL && currentKey.compare("value") == 0) {
447 switch (type) {
448 case atype::UINT64:
449 value = (uint64_t)i;
450 break;
451 case atype::INT64:
452 value = (int64_t)i;
453 break;
454 default:
455 states.push(State::IN_ERROR);
456 return false;
457 }
458 return true;
459 }
460 states.push(State::IN_ERROR); // no other contexts allow int64s
461 return false;
462 }
463
464 bool Uint64(uint64_t i)
465 {
466 debug << "Uint64(" << i << ")" << std::endl;
467 // any positive value will be first read as unsigned, however the actual type is determined by node's arrow_type
468 debug << ">> falling back to Int64" << std::endl;
469 return Int64(i);
470 }
471
472 bool Double(double d)
473 {
474 debug << "Double(" << d << ")" << std::endl;
475 // can only be a literal node value
476 if (states.top() == State::IN_NODE_LITERAL) {
477 switch (type) {
478 case atype::FLOAT:
479 value = (float)d;
480 break;
481 case atype::DOUBLE:
482 value = d;
483 break;
484 default:
485 states.push(State::IN_ERROR);
486 return false;
487 }
488 return true;
489 }
490 states.push(State::IN_ERROR); // no other contexts allow doubles
491 return false;
492 }
493
494 bool String(const Ch* str, SizeType, bool)
495 {
496 debug << "String(" << str << ")" << std::endl;
497 // can only be a binding node
498 if (states.top() == State::IN_NODE_BINDING && currentKey.compare("binding") == 0) {
499 binding = str;
500 return true;
501 }
502 states.push(State::IN_ERROR); // no strings are expected
503 return false;
504 }
505};
506} // namespace
507
508std::vector<expressions::Projector> o2::framework::ExpressionJSONHelpers::read(std::istream& s)
509{
510 rapidjson::Reader reader;
511 rapidjson::IStreamWrapper isw(s);
512 ExpressionReader ereader;
513 bool ok = reader.Parse(isw, ereader);
514
515 if (!ok) {
516 throw framework::runtime_error_f("Cannot parse serialized Expression, error: %s at offset: %d", rapidjson::GetParseError_En(reader.GetParseErrorCode()), reader.GetErrorOffset());
517 }
518 return std::move(ereader.result);
519}
520
521namespace
522{
523void writeNodeHeader(rapidjson::Writer<rapidjson::OStreamWrapper>& w, expressions::Node const* node)
524{
525 w.Key("kind");
526 w.Int((int)node->self.index());
527 w.Key("index");
528 w.Uint64(node->index);
529 std::visit(overloaded{
530 [&w](expressions::LiteralNode const& node) {
531 w.Key("arrow_type");
532 w.Int(node.type);
533 w.Key("value");
534 std::visit(overloaded{
535 [&w](bool v) { w.Bool(v); },
536 [&w](float v) { w.Double(v); },
537 [&w](double v) { w.Double(v); },
538 [&w](uint8_t v) { w.Uint(v); },
539 [&w](uint16_t v) { w.Uint(v); },
540 [&w](uint32_t v) { w.Uint(v); },
541 [&w](uint64_t v) { w.Uint64(v); },
542 [&w](int8_t v) { w.Int(v); },
543 [&w](int16_t v) { w.Int(v); },
544 [&w](int v) { w.Int(v); },
545 [&w](int64_t v) { w.Int64(v); }},
546 node.value);
547 },
548 [&w](expressions::BindingNode const& node) {
549 w.Key("binding");
550 w.String(node.name);
551 w.Key("hash");
552 w.Uint(node.hash);
553 w.Key("arrow_type");
554 w.Int(node.type);
555 },
556 [&w](expressions::OpNode const& node) {
557 w.Key("operation");
558 w.Int(node.op);
559 },
560 [](expressions::ConditionalNode const&) {
561 }},
562 node->self);
563}
564
565void writeExpression(rapidjson::Writer<rapidjson::OStreamWrapper>& w, expressions::Node* n)
566{
567 std::stack<Entry> path;
568 path.emplace(n, ToWrite::FULL);
569 while (!path.empty()) {
570 auto& top = path.top();
571
572 if (top.toWrite == ToWrite::FULL) {
573 w.StartObject();
574 writeNodeHeader(w, top.ptr);
575 top.toWrite = ToWrite::LEFT;
576 continue;
577 }
578
579 if (top.toWrite == ToWrite::LEFT) {
580 w.Key("left");
581 top.toWrite = ToWrite::RIGHT;
582 auto* left = top.ptr->left.get();
583 if (left != nullptr) {
584 path.emplace(left, ToWrite::FULL);
585 } else {
586 w.Null();
587 }
588 continue;
589 }
590
591 if (top.toWrite == ToWrite::RIGHT) {
592 w.Key("right");
593 top.toWrite = ToWrite::COND;
594 auto* right = top.ptr->right.get();
595 if (right != nullptr) {
596 path.emplace(right, ToWrite::FULL);
597 } else {
598 w.Null();
599 }
600 continue;
601 }
602
603 if (top.toWrite == ToWrite::COND) {
604 w.Key("condition");
605 top.toWrite = ToWrite::POP;
606 auto* cond = top.ptr->condition.get();
607 if (cond != nullptr) {
608 path.emplace(cond, ToWrite::FULL);
609 } else {
610 w.Null();
611 }
612 continue;
613 }
614
615 if (top.toWrite == ToWrite::POP) {
616 w.EndObject();
617 path.pop();
618 continue;
619 }
620 }
621}
622} // namespace
623
624void o2::framework::ExpressionJSONHelpers::write(std::ostream& o, std::vector<o2::framework::expressions::Projector>& projectors)
625{
626 rapidjson::OStreamWrapper osw(o);
627 rapidjson::Writer<rapidjson::OStreamWrapper> w(osw);
628 w.StartObject();
629 w.Key("projectors");
630 w.StartArray();
631 for (auto& p : projectors) {
632 writeExpression(w, p.node.get());
633 }
634 w.EndArray();
635 w.EndObject();
636}
637
638namespace
639{
640struct SchemaReader : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, SchemaReader> {
641 using Ch = rapidjson::UTF8<>::Ch;
642 using SizeType = rapidjson::SizeType;
643
644 enum struct State {
645 IN_START,
646 IN_LIST,
647 IN_FIELD,
649 };
650
651 std::stack<State> states;
652 std::ostringstream debug;
653
654 std::shared_ptr<arrow::Schema> schema = nullptr;
655 std::vector<std::shared_ptr<arrow::Field>> fields;
656
657 std::string currentKey;
658
659 std::string name;
660 atype::type type;
661
662 SchemaReader()
663 {
664 debug << ">>> Start" << std::endl;
665 states.push(State::IN_START);
666 }
667
668 bool StartArray()
669 {
670 debug << "Starting array" << std::endl;
671 if (states.top() == State::IN_START && currentKey.compare("fields") == 0) {
672 states.push(State::IN_LIST);
673 return true;
674 }
675 states.push(State::IN_ERROR);
676 return false;
677 }
678
679 bool EndArray(SizeType)
680 {
681 debug << "Ending array" << std::endl;
682 if (states.top() == State::IN_LIST) {
683 // finalize schema
684 schema = std::make_shared<arrow::Schema>(fields);
685 states.pop();
686 return true;
687 }
688 states.push(State::IN_ERROR);
689 return false;
690 }
691
692 bool Key(const Ch* str, SizeType, bool)
693 {
694 debug << "Key(" << str << ")" << std::endl;
695 currentKey = str;
696 if (states.top() == State::IN_START) {
697 if (currentKey.compare("fields") == 0) {
698 return true;
699 }
700 }
701
702 if (states.top() == State::IN_FIELD) {
703 if (currentKey.compare("name") == 0) {
704 return true;
705 }
706 if (currentKey.compare("type") == 0) {
707 return true;
708 }
709 }
710
711 states.push(State::IN_ERROR);
712 return false;
713 }
714
715 bool StartObject()
716 {
717 debug << "StartObject()" << std::endl;
718 if (states.top() == State::IN_START) {
719 return true;
720 }
721
722 if (states.top() == State::IN_LIST) {
723 states.push(State::IN_FIELD);
724 return true;
725 }
726
727 states.push(State::IN_ERROR);
728 return false;
729 }
730
731 bool EndObject(SizeType)
732 {
733 debug << "EndObject()" << std::endl;
734 if (states.top() == State::IN_FIELD) {
735 states.pop();
736 // add a field
737 fields.emplace_back(std::make_shared<arrow::Field>(name, expressions::concreteArrowType(type)));
738 return true;
739 }
740
741 if (states.top() == State::IN_START) {
742 return true;
743 }
744
745 states.push(State::IN_ERROR);
746 return false;
747 }
748
749 bool Uint(unsigned i)
750 {
751 debug << "Uint(" << i << ")" << std::endl;
752 if (states.top() == State::IN_FIELD) {
753 if (currentKey.compare("type") == 0) {
754 type = (atype::type)i;
755 return true;
756 }
757 }
758
759 states.push(State::IN_ERROR);
760 return false;
761 }
762
763 bool String(const Ch* str, SizeType, bool)
764 {
765 debug << "String(" << str << ")" << std::endl;
766 if (states.top() == State::IN_FIELD) {
767 if (currentKey.compare("name") == 0) {
768 name = str;
769 return true;
770 }
771 }
772
773 states.push(State::IN_ERROR);
774 return false;
775 }
776
777 bool Int(int i)
778 {
779 debug << "Int(" << i << ")" << std::endl;
780 return Uint(i);
781 }
782};
783} // namespace
784
785std::shared_ptr<arrow::Schema> o2::framework::ArrowJSONHelpers::read(std::istream& s)
786{
787 rapidjson::Reader reader;
788 rapidjson::IStreamWrapper isw(s);
789 SchemaReader sreader;
790
791 bool ok = reader.Parse(isw, sreader);
792
793 if (!ok) {
794 throw framework::runtime_error_f("Cannot parse serialized Expression, error: %s at offset: %d", rapidjson::GetParseError_En(reader.GetParseErrorCode()), reader.GetErrorOffset());
795 }
796 return sreader.schema;
797}
798
799namespace
800{
801void writeSchema(rapidjson::Writer<rapidjson::OStreamWrapper>& w, arrow::Schema* schema)
802{
803 for (auto& f : schema->fields()) {
804 w.StartObject();
805 w.Key("name");
806 w.String(f->name().c_str());
807 w.Key("type");
808 w.Int(f->type()->id());
809 w.EndObject();
810 }
811}
812} // namespace
813
814void o2::framework::ArrowJSONHelpers::write(std::ostream& o, std::shared_ptr<arrow::Schema>& schema)
815{
816 rapidjson::OStreamWrapper osw(o);
817 rapidjson::Writer<rapidjson::OStreamWrapper> w(osw);
818 w.StartObject();
819 w.Key("fields");
820 w.StartArray();
821 writeSchema(w, schema.get());
822 w.EndArray();
823 w.EndObject();
824}
825
826} // namespace o2::framework
std::shared_ptr< arrow::Schema > schema
std::vector< expressions::Projector > projectors
std::string binding
o2::monitoring::tags::Key Key
uint32_t hash
std::string previousKey
std::string currentKey
ToWrite toWrite
std::unique_ptr< expressions::Node > rootNode
BasicOp operation
std::vector< std::shared_ptr< arrow::Field > > fields
std::ostringstream debug
std::unique_ptr< expressions::Node > node
int32_t i
TBranch * ptr
GLdouble n
Definition glcorearb.h:1982
GLuint64EXT * result
Definition glcorearb.h:5662
const GLdouble * v
Definition glcorearb.h:832
GLuint index
Definition glcorearb.h:781
GLdouble GLdouble GLdouble GLdouble top
Definition glcorearb.h:4077
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble GLdouble right
Definition glcorearb.h:4077
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLuint * states
Definition glcorearb.h:4932
uint8_t itsSharedClusterMap uint8_t
std::shared_ptr< arrow::DataType > concreteArrowType(atype::type type)
Defining PrimaryVertex explicitly as messageable.
RuntimeErrorRef runtime_error_f(const char *,...)
static void write(std::ostream &o, std::shared_ptr< arrow::Schema > &schema)
static std::shared_ptr< arrow::Schema > read(std::istream &s)
static std::vector< expressions::Projector > read(std::istream &s)
static void write(std::ostream &o, std::vector< expressions::Projector > &projectors)
An expression tree node corresponding to a literal value.
From https://en.cppreference.com/w/cpp/utility/variant/visit.
const std::string str