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;
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{
640std::shared_ptr<arrow::DataType> arrowDataTypeFromId(atype::type type, int list_size = 1, atype::type element = atype::NA)
641{
642 switch (list_size) {
643 case -1:
644 return arrow::list(expressions::concreteArrowType(element));
645 case 1:
647 default:
648 return arrow::fixed_size_list(expressions::concreteArrowType(element), list_size);
649 }
650}
651
652struct SchemaReader : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, SchemaReader> {
653 using Ch = rapidjson::UTF8<>::Ch;
654 using SizeType = rapidjson::SizeType;
655
656 enum struct State {
657 IN_START,
658 IN_LIST,
659 IN_FIELD,
661 };
662
663 std::stack<State> states;
664 std::ostringstream debug;
665
666 std::shared_ptr<arrow::Schema> schema = nullptr;
667 std::vector<std::shared_ptr<arrow::Field>> fields;
668
669 std::string currentKey;
670
671 std::string name;
672 atype::type type;
673 atype::type element;
674 int list_size = 1;
675
676 SchemaReader()
677 {
678 debug << ">>> Start" << std::endl;
679 states.push(State::IN_START);
680 }
681
682 bool StartArray()
683 {
684 debug << "StartArray()" << std::endl;
685 if (states.top() == State::IN_START && currentKey.compare("fields") == 0) {
686 states.push(State::IN_LIST);
687 return true;
688 }
689 states.push(State::IN_ERROR);
690 return false;
691 }
692
693 bool EndArray(SizeType)
694 {
695 debug << "EndArray()" << std::endl;
696 if (states.top() == State::IN_LIST) {
697 // finalize schema
698 schema = std::make_shared<arrow::Schema>(fields);
699 states.pop();
700 return true;
701 }
702 states.push(State::IN_ERROR);
703 return false;
704 }
705
706 bool Key(const Ch* str, SizeType, bool)
707 {
708 debug << "Key(" << str << ")" << std::endl;
709 currentKey = str;
710 if (states.top() == State::IN_START) {
711 if (currentKey.compare("fields") == 0) {
712 return true;
713 }
714 }
715
716 if (states.top() == State::IN_FIELD) {
717 if (currentKey.compare("name") == 0) {
718 return true;
719 }
720 if (currentKey.compare("type") == 0) {
721 return true;
722 }
723 if (currentKey.compare("size") == 0) {
724 return true;
725 }
726 if (currentKey.compare("element") == 0) {
727 return true;
728 }
729 }
730
731 states.push(State::IN_ERROR);
732 return false;
733 }
734
735 bool StartObject()
736 {
737 debug << "StartObject()" << std::endl;
738 if (states.top() == State::IN_START) {
739 return true;
740 }
741
742 if (states.top() == State::IN_LIST) {
743 states.push(State::IN_FIELD);
744 list_size = 1;
745 element = atype::NA;
746 type = atype::NA;
747 return true;
748 }
749
750 states.push(State::IN_ERROR);
751 return false;
752 }
753
754 bool EndObject(SizeType)
755 {
756 debug << "EndObject()" << std::endl;
757 if (states.top() == State::IN_FIELD) {
758 states.pop();
759 // add a field
760 fields.emplace_back(std::make_shared<arrow::Field>(name, arrowDataTypeFromId(type, list_size, element)));
761 return true;
762 }
763
764 if (states.top() == State::IN_START) {
765 return true;
766 }
767
768 states.push(State::IN_ERROR);
769 return false;
770 }
771
772 bool Uint(unsigned i)
773 {
774 debug << "Uint(" << i << ")" << std::endl;
775 if (states.top() == State::IN_FIELD) {
776 if (currentKey.compare("type") == 0) {
777 type = (atype::type)i;
778 return true;
779 }
780 if (currentKey.compare("element") == 0) {
781 element = (atype::type)i;
782 return true;
783 }
784 if (currentKey.compare("size") == 0) {
785 list_size = i;
786 return true;
787 }
788 }
789
790 states.push(State::IN_ERROR);
791 return false;
792 }
793
794 bool String(const Ch* str, SizeType, bool)
795 {
796 debug << "String(" << str << ")" << std::endl;
797 if (states.top() == State::IN_FIELD) {
798 if (currentKey.compare("name") == 0) {
799 name = str;
800 return true;
801 }
802 }
803
804 states.push(State::IN_ERROR);
805 return false;
806 }
807
808 bool Int(int i)
809 {
810 debug << "Int(" << i << ")" << std::endl;
811 if (states.top() == State::IN_FIELD && currentKey.compare("size") == 0) {
812 list_size = i;
813 return true;
814 }
815 return Uint(i);
816 }
817};
818} // namespace
819
820std::shared_ptr<arrow::Schema> o2::framework::ArrowJSONHelpers::read(std::istream& s)
821{
822 rapidjson::Reader reader;
823 rapidjson::IStreamWrapper isw(s);
824 SchemaReader sreader;
825
826 bool ok = reader.Parse(isw, sreader);
827
828 if (!ok) {
829 throw framework::runtime_error_f("Cannot parse serialized Schema, error: %s at offset: %d", rapidjson::GetParseError_En(reader.GetParseErrorCode()), reader.GetErrorOffset());
830 }
831 return sreader.schema;
832}
833
834namespace
835{
836void writeSchema(rapidjson::Writer<rapidjson::OStreamWrapper>& w, arrow::Schema* schema)
837{
838 for (auto& f : schema->fields()) {
839 w.StartObject();
840 w.Key("name");
841 w.String(f->name().c_str());
842 auto fixedList = dynamic_cast<arrow::FixedSizeListType*>(f->type().get());
843 if (fixedList != nullptr) {
844 w.Key("size");
845 w.Int(fixedList->list_size());
846 w.Key("element");
847 w.Int(fixedList->field(0)->type()->id());
848 }
849 auto varList = dynamic_cast<arrow::ListType*>(f->type().get());
850 if (varList != nullptr) {
851 w.Key("size");
852 w.Int(-1);
853 w.Key("element");
854 w.Int(varList->field(0)->type()->id());
855 }
856 w.Key("type");
857 w.Int(f->type()->id());
858 w.EndObject();
859 }
860}
861} // namespace
862
863void o2::framework::ArrowJSONHelpers::write(std::ostream& o, std::shared_ptr<arrow::Schema>& schema)
864{
865 rapidjson::OStreamWrapper osw(o);
866 rapidjson::Writer<rapidjson::OStreamWrapper> w(osw);
867 w.StartObject();
868 w.Key("fields");
869 w.StartArray();
870 writeSchema(w, schema.get());
871 w.EndArray();
872 w.EndObject();
873}
874
875} // namespace o2::framework
std::vector< expressions::Projector > projectors
std::string binding
o2::monitoring::tags::Key Key
uint32_t hash
std::string previousKey
std::shared_ptr< arrow::Schema > schema
std::string currentKey
ToWrite toWrite
atype::type element
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
unsigned char uint8_t
unsigned short int uint16_t
unsigned int uint32_t
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events d
configStandalone Reconstruction rec_tpc float
TBranch * ptr
GLdouble n
Definition glcorearb.h:1982
GLuint64EXT * result
Definition glcorearb.h:5662
const GLdouble * v
Definition glcorearb.h:832
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
GLint left
Definition glcorearb.h:1979
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
std::shared_ptr< arrow::DataType > concreteArrowType(atype::type type)
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
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