Project
Loading...
Searching...
No Matches
VariantJSONHelpers.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 FRAMEWORK_VARIANTJSONHELPERS_H
12#define FRAMEWORK_VARIANTJSONHELPERS_H
13
14#include "Framework/Variant.h"
15
16#include <rapidjson/reader.h>
17#include <rapidjson/prettywriter.h>
18#include <rapidjson/istreamwrapper.h>
19#include <rapidjson/ostreamwrapper.h>
20#include <rapidjson/error/en.h>
21
22#include <stack>
23#include <iostream>
24#include <sstream>
25
26namespace o2::framework
27{
28namespace
29{
30template <VariantType V>
31struct VariantReader : public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, VariantReader<V>> {
32 using Ch = rapidjson::UTF8<>::Ch;
33 using SizeType = rapidjson::SizeType;
34
35 enum struct State {
37 IN_STOP,
38 IN_DATA,
39 IN_KEY,
40 IN_ARRAY,
41 IN_ROW,
43 };
44
45 VariantReader()
46 : states{},
47 rows{0},
48 cols{0}
49 {
50 debug << "Start" << std::endl;
51 states.push(State::IN_START);
52 }
53
54 bool Null()
55 {
56 debug << "Null value encountered" << std::endl;
57 return true;
58 }
59
60 bool Int(int i)
61 {
62 debug << "Int(" << i << ")" << std::endl;
63 if (states.top() == State::IN_ERROR) {
64 debug << "In ERROR state" << std::endl;
65 return false;
66 }
67 if constexpr (!std::is_same_v<int, variant_array_element_type_t<V>>) {
68 states.push(State::IN_ERROR);
69 return true;
70 } else {
71 if (states.top() == State::IN_ARRAY || states.top() == State::IN_ROW) {
72 debug << "added to array" << std::endl;
73 accumulatedData.push_back(i);
74 return true;
75 }
76 }
77 states.push(State::IN_ERROR);
78 return true;
79 }
80
81 bool Uint(unsigned i)
82 {
83 debug << "Uint -> Int" << std::endl;
84 return Int(static_cast<int>(i));
85 }
86
87 bool Int64(int64_t i)
88 {
89 debug << "Int64 -> Int" << std::endl;
90 return Int(static_cast<int>(i));
91 }
92
93 bool Uint64(uint64_t i)
94 {
95 debug << "Uint64 -> Int" << std::endl;
96 return Int(static_cast<int>(i));
97 }
98
99 bool Double(double d)
100 {
101 debug << "Double(" << d << ")" << std::endl;
102 if (states.top() == State::IN_ERROR) {
103 debug << "In ERROR state" << std::endl;
104 return false;
105 }
106 if constexpr (!(std::is_same_v<float, variant_array_element_type_t<V>> || std::is_same_v<double, variant_array_element_type_t<V>>)) {
107 states.push(State::IN_ERROR);
108 return true;
109 }
110 if (states.top() == State::IN_ARRAY || states.top() == State::IN_ROW) {
111 if constexpr (std::is_same_v<double, variant_array_element_type_t<V>>) {
112 debug << "added to array as double" << std::endl;
113 accumulatedData.push_back(d);
114 return true;
115 } else if constexpr (std::is_same_v<float, variant_array_element_type_t<V>>) {
116 debug << "added to array as float" << std::endl;
117 accumulatedData.push_back(static_cast<float>(d));
118 return true;
119 }
120 }
121 states.push(State::IN_ERROR);
122 return true;
123 }
124
125 bool Bool(bool b)
126 {
127 debug << "Bool(" << b << ")" << std::endl;
128 if (states.top() == State::IN_ERROR) {
129 debug << "In ERROR state" << std::endl;
130 return false;
131 }
132 if constexpr (!std::is_same_v<bool, variant_array_element_type_t<V>>) {
133 states.push(State::IN_ERROR);
134 return false;
135 } else {
136 if (states.top() == State::IN_ARRAY) {
137 debug << "added to array" << std::endl;
138 accumulatedData.push_back(b);
139 return true;
140 }
141 states.push(State::IN_ERROR);
142 return true;
143 }
144 }
145
146 bool String(const Ch* str, SizeType, bool)
147 {
148 debug << "String(" << str << ")" << std::endl;
149 if (states.top() == State::IN_ERROR) {
150 debug << "In ERROR state" << std::endl;
151 return false;
152 }
153 if constexpr (!(V == VariantType::ArrayString || isLabeledArray<V>())) {
154 states.push(State::IN_ERROR);
155 return true;
156 } else {
157 if (states.top() == State::IN_ARRAY || states.top() == State::IN_ROW) {
158 debug << "added to array" << std::endl;
159 if constexpr (isLabeledArray<V>()) {
160 if (currentKey == labels_rows_str) {
161 labels_rows.push_back(str);
162 return true;
163 }
164 if (currentKey == labels_cols_str) {
165 labels_cols.push_back(str);
166 return true;
167 }
168 }
169 if (currentKey == "values") {
170 if constexpr (std::is_same_v<std::string, variant_array_element_type_t<V>>) {
171 accumulatedData.push_back(str);
172 } else {
173 states.push(State::IN_ERROR);
174 }
175 return true;
176 }
177 return true;
178 }
179 states.push(State::IN_ERROR);
180 return true;
181 }
182 }
183
184 bool StartObject()
185 {
186 debug << "StartObject()" << std::endl;
187 if (states.top() == State::IN_ERROR) {
188 debug << "In ERROR state" << std::endl;
189 return false;
190 }
191 if (states.top() == State::IN_START) {
192 states.push(State::IN_DATA);
193 return true;
194 }
195 states.push(State::IN_ERROR);
196 return true;
197 }
198
199 bool Key(const Ch* str, SizeType, bool)
200 {
201 debug << "Key(" << str << ")" << std::endl;
202 if (states.top() == State::IN_ERROR) {
203 debug << "In ERROR state" << std::endl;
204 currentKey = str;
205 return false;
206 }
207 if (states.top() == State::IN_DATA) {
208 // no previous keys
209 states.push(State::IN_KEY);
210 currentKey = str;
211 return true;
212 }
213 if (states.top() == State::IN_KEY) {
214 currentKey = str;
215 if constexpr (!isLabeledArray<V>()) {
216 debug << "extra keys in a single-key variant" << std::endl;
217 states.push(State::IN_ERROR);
218 return true;
219 }
220 return true;
221 }
222 currentKey = str;
223 states.push(State::IN_ERROR);
224 return true;
225 }
226
227 bool EndObject(SizeType)
228 {
229 debug << "EndObject()" << std::endl;
230 if (states.top() == State::IN_ERROR) {
231 debug << "In ERROR state" << std::endl;
232 return false;
233 }
234 if (states.top() == State::IN_KEY) {
235 if constexpr (isArray<V>()) {
236 debug << "creating 1d-array variant" << std::endl;
237 result = Variant(accumulatedData);
238 } else if constexpr (isArray2D<V>()) {
239 debug << "creating 2d-array variant" << std::endl;
240 assert(accumulatedData.size() == rows * cols);
241 result = Variant(Array2D{accumulatedData, rows, cols});
242 } else if constexpr (isLabeledArray<V>()) {
243 debug << "creating labeled array variant" << std::endl;
244 assert(accumulatedData.size() == rows * cols);
245 if (labels_rows.empty() == false) {
246 assert(labels_rows.size() == rows);
247 }
248 if (labels_cols.empty() == false) {
249 assert(labels_cols.size() == cols);
250 }
251 result = Variant(LabeledArray{Array2D{accumulatedData, rows, cols}, labels_rows, labels_cols});
252 }
253 states.push(State::IN_STOP);
254 return true;
255 }
256 states.push(State::IN_ERROR);
257 return true;
258 }
259
260 bool StartArray()
261 {
262 debug << "StartArray()" << std::endl;
263 if (states.top() == State::IN_ERROR) {
264 debug << "In ERROR state" << std::endl;
265 return false;
266 }
267 if (states.top() == State::IN_KEY) {
268 states.push(State::IN_ARRAY);
269 return true;
270 } else if (states.top() == State::IN_ARRAY) {
271 if constexpr (isArray2D<V>() || isLabeledArray<V>()) {
272 states.push(State::IN_ROW);
273 return true;
274 }
275 }
276 states.push(State::IN_ERROR);
277 return true;
278 }
279
280 bool EndArray(SizeType elementCount)
281 {
282 debug << "EndArray()" << std::endl;
283 if (states.top() == State::IN_ERROR) {
284 debug << "In ERROR state" << std::endl;
285 return false;
286 }
287 if (states.top() == State::IN_ARRAY) {
288 // finish up array
289 states.pop();
290 if constexpr (isArray2D<V>() || isLabeledArray<V>()) {
291 rows = elementCount;
292 }
293 return true;
294 } else if (states.top() == State::IN_ROW) {
295 // finish up row
296 states.pop();
297 if constexpr (isArray2D<V>() || isLabeledArray<V>()) {
298 cols = elementCount;
299 }
300 return true;
301 }
302 states.push(State::IN_ERROR);
303 return true;
304 }
305
306 std::stack<State> states;
307 std::ostringstream debug;
308
309 uint32_t rows;
310 uint32_t cols;
311 std::string currentKey;
312 std::vector<variant_array_element_type_t<V>> accumulatedData;
313 std::vector<std::string> labels_rows;
314 std::vector<std::string> labels_cols;
315 Variant result;
316};
317
318template <VariantType V>
319void writeVariant(std::ostream& o, Variant const& v)
320{
321 if constexpr (isArray<V>() || isArray2D<V>() || isLabeledArray<V>()) {
322 using type = variant_array_element_type_t<V>;
323 rapidjson::OStreamWrapper osw(o);
324 rapidjson::Writer<rapidjson::OStreamWrapper> w(osw);
325
326 auto writeArray = [&](auto* values, size_t size) {
327 using T = std::remove_pointer_t<decltype(values)>;
328 w.StartArray();
329 for (auto i = 0u; i < size; ++i) {
330 if constexpr (std::is_same_v<int, T>) {
331 w.Int(values[i]);
332 } else if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>) {
333 w.Double(values[i]);
334 } else if constexpr (std::is_same_v<bool, T>) {
335 w.Bool(values[i]);
336 } else if constexpr (std::is_same_v<std::string, T>) {
337 w.String(values[i].c_str());
338 }
339 }
340 w.EndArray();
341 };
342
343 auto writeVector = [&](auto&& vector) {
344 return writeArray(vector.data(), vector.size());
345 };
346
347 auto writeArray2D = [&](auto&& array2d) {
348 using T = typename std::decay_t<decltype(array2d)>::element_t;
349 w.StartArray();
350 for (auto i = 0u; i < array2d.rows; ++i) {
351 w.StartArray();
352 for (auto j = 0u; j < array2d.cols; ++j) {
353 if constexpr (std::is_same_v<int, T>) {
354 w.Int(array2d(i, j));
355 } else if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>) {
356 w.Double(array2d(i, j));
357 } else if constexpr (std::is_same_v<std::string, T>) {
358 w.String(array2d(i, j).c_str());
359 }
360 }
361 w.EndArray();
362 }
363 w.EndArray();
364 };
365
366 auto writeLabeledArray = [&](auto&& array) {
367 w.Key(labels_rows_str);
368 writeVector(array.getLabelsRows());
369 w.Key(labels_cols_str);
370 writeVector(array.getLabelsCols());
371 w.Key("values");
372 writeArray2D(array.getData());
373 };
374
375 w.StartObject();
376 if constexpr (isArray<V>()) {
377 w.Key("values");
378 writeArray(v.get<type*>(), v.size());
379 } else if constexpr (isArray2D<V>()) {
380 w.Key("values");
381 writeArray2D(v.get<Array2D<type>>());
382 } else if constexpr (isLabeledArray<V>()) {
383 writeLabeledArray(v.get<LabeledArray<type>>());
384 } else if constexpr (V == VariantType::Dict) {
385 // nothing to do for dicts
386 }
387 w.EndObject();
388 }
389}
390} // namespace
391
393 template <VariantType V>
394 static Variant read(std::istream& s)
395 {
396 rapidjson::Reader reader;
397 rapidjson::IStreamWrapper isw(s);
398 VariantReader<V> vreader;
399 bool ok = reader.Parse(isw, vreader);
400
401 if (ok == false) {
402 std::stringstream error;
403 error << "Cannot parse serialized Variant, error: " << rapidjson::GetParseError_En(reader.GetParseErrorCode()) << " at offset: " << reader.GetErrorOffset();
404 throw std::runtime_error(error.str());
405 }
406 return vreader.result;
407 }
408
409 static void write(std::ostream& o, Variant const& v)
410 {
411 switch (v.type()) {
413 writeVariant<VariantType::ArrayInt>(o, v);
414 break;
416 writeVariant<VariantType::ArrayFloat>(o, v);
417 break;
419 writeVariant<VariantType::ArrayDouble>(o, v);
420 break;
422 throw std::runtime_error("Bool vectors not implemented yet");
423 // writeVariant<VariantType::ArrayBool>(o, v);
424 break;
426 writeVariant<VariantType::ArrayString>(o, v);
427 break;
429 writeVariant<VariantType::Array2DInt>(o, v);
430 break;
432 writeVariant<VariantType::Array2DFloat>(o, v);
433 break;
435 writeVariant<VariantType::Array2DDouble>(o, v);
436 break;
438 writeVariant<VariantType::LabeledArrayInt>(o, v);
439 break;
441 writeVariant<VariantType::LabeledArrayFloat>(o, v);
442 break;
444 writeVariant<VariantType::LabeledArrayDouble>(o, v);
445 break;
447 writeVariant<VariantType::LabeledArrayString>(o, v);
448 break;
450 writeVariant<VariantType::Dict>(o, v);
451 default:
452 break;
453 }
454 }
455};
456} // namespace o2::framework
457
458#endif // FRAMEWORK_VARIANTJSONHELPERS_H
o2::monitoring::tags::Key Key
int32_t i
bool o
uint32_t j
Definition RawData.h:0
std::vector< variant_array_element_type_t< V > > accumulatedData
uint32_t cols
std::vector< std::string > labels_rows
std::string currentKey
std::ostringstream debug
std::vector< std::string > labels_cols
Variant for configuration parameter storage. Owns stored data.
Definition Variant.h:307
GLuint64EXT * result
Definition glcorearb.h:5662
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLenum array
Definition glcorearb.h:4274
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLenum GLsizei GLsizei GLint * values
Definition glcorearb.h:1576
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLuint * states
Definition glcorearb.h:4932
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
AbstractArray2D< T, TPCMapMemoryLayout< T > > Array2D
Definition Array2D.h:122
std::vector< T, o2::pmr::polymorphic_allocator< T > > vector
static Variant read(std::istream &s)
static void write(std::ostream &o, Variant const &v)
std::vector< ReadoutWindowData > rows
const std::string str