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