11#ifndef FRAMEWORK_VARIANTJSONHELPERS_H
12#define FRAMEWORK_VARIANTJSONHELPERS_H
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>
30template <VariantType V>
31struct VariantReader :
public rapidjson::BaseReaderHandler<rapidjson::UTF8<>, VariantReader<V>> {
32 using Ch = rapidjson::UTF8<>::Ch;
33 using SizeType = rapidjson::SizeType;
50 debug <<
"Start" << std::endl;
51 states.push(State::IN_START);
56 debug <<
"Null value encountered" << std::endl;
62 debug <<
"Int(" <<
i <<
")" << std::endl;
63 if (
states.top() == State::IN_ERROR) {
64 debug <<
"In ERROR state" << std::endl;
67 if constexpr (!std::is_same_v<int, variant_array_element_type_t<V>>) {
68 states.push(State::IN_ERROR);
71 if (
states.top() == State::IN_ARRAY ||
states.top() == State::IN_ROW) {
72 debug <<
"added to array" << std::endl;
77 states.push(State::IN_ERROR);
83 debug <<
"Uint -> Int" << std::endl;
84 return Int(
static_cast<int>(
i));
89 debug <<
"Int64 -> Int" << std::endl;
90 return Int(
static_cast<int>(
i));
95 debug <<
"Uint64 -> Int" << std::endl;
96 return Int(
static_cast<int>(
i));
101 debug <<
"Double(" << d <<
")" << std::endl;
102 if (
states.top() == State::IN_ERROR) {
103 debug <<
"In ERROR state" << std::endl;
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);
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;
115 }
else if constexpr (std::is_same_v<float, variant_array_element_type_t<V>>) {
116 debug <<
"added to array as float" << std::endl;
121 states.push(State::IN_ERROR);
127 debug <<
"Bool(" <<
b <<
")" << std::endl;
128 if (
states.top() == State::IN_ERROR) {
129 debug <<
"In ERROR state" << std::endl;
132 if constexpr (!std::is_same_v<bool, variant_array_element_type_t<V>>) {
133 states.push(State::IN_ERROR);
136 if (
states.top() == State::IN_ARRAY) {
137 debug <<
"added to array" << std::endl;
141 states.push(State::IN_ERROR);
146 bool String(
const Ch*
str, SizeType,
bool)
148 debug <<
"String(" <<
str <<
")" << std::endl;
149 if (
states.top() == State::IN_ERROR) {
150 debug <<
"In ERROR state" << std::endl;
154 states.push(State::IN_ERROR);
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) {
164 if (currentKey == labels_cols_str) {
169 if (currentKey ==
"values") {
170 if constexpr (std::is_same_v<std::string, variant_array_element_type_t<V>>) {
173 states.push(State::IN_ERROR);
179 states.push(State::IN_ERROR);
186 debug <<
"StartObject()" << std::endl;
187 if (
states.top() == State::IN_ERROR) {
188 debug <<
"In ERROR state" << std::endl;
191 if (
states.top() == State::IN_START) {
192 states.push(State::IN_DATA);
195 states.push(State::IN_ERROR);
199 bool Key(
const Ch*
str, SizeType,
bool)
201 debug <<
"Key(" <<
str <<
")" << std::endl;
202 if (
states.top() == State::IN_ERROR) {
203 debug <<
"In ERROR state" << std::endl;
207 if (
states.top() == State::IN_DATA) {
209 states.push(State::IN_KEY);
213 if (
states.top() == State::IN_KEY) {
215 if constexpr (!isLabeledArray<V>()) {
216 debug <<
"extra keys in a single-key variant" << std::endl;
217 states.push(State::IN_ERROR);
223 states.push(State::IN_ERROR);
227 bool EndObject(SizeType)
229 debug <<
"EndObject()" << std::endl;
230 if (
states.top() == State::IN_ERROR) {
231 debug <<
"In ERROR state" << std::endl;
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;
242 }
else if constexpr (isLabeledArray<V>()) {
243 debug <<
"creating labeled array variant" << std::endl;
253 states.push(State::IN_STOP);
256 states.push(State::IN_ERROR);
262 debug <<
"StartArray()" << std::endl;
263 if (
states.top() == State::IN_ERROR) {
264 debug <<
"In ERROR state" << std::endl;
267 if (
states.top() == State::IN_KEY) {
268 states.push(State::IN_ARRAY);
270 }
else if (
states.top() == State::IN_ARRAY) {
271 if constexpr (isArray2D<V>() || isLabeledArray<V>()) {
272 states.push(State::IN_ROW);
276 states.push(State::IN_ERROR);
280 bool EndArray(SizeType elementCount)
282 debug <<
"EndArray()" << std::endl;
283 if (
states.top() == State::IN_ERROR) {
284 debug <<
"In ERROR state" << std::endl;
287 if (
states.top() == State::IN_ARRAY) {
290 if constexpr (isArray2D<V>() || isLabeledArray<V>()) {
294 }
else if (
states.top() == State::IN_ROW) {
297 if constexpr (isArray2D<V>() || isLabeledArray<V>()) {
302 states.push(State::IN_ERROR);
318template <VariantType V>
319void writeVariant(std::ostream&
o, Variant
const&
v)
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);
326 auto writeArray = [&](
auto*
values,
size_t size) {
327 using T = std::remove_pointer_t<
decltype(
values)>;
329 for (
auto i = 0u;
i <
size; ++
i) {
330 if constexpr (std::is_same_v<int, T>) {
332 }
else if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>) {
334 }
else if constexpr (std::is_same_v<bool, T>) {
336 }
else if constexpr (std::is_same_v<std::string, T>) {
343 auto writeVector = [&](
auto&&
vector) {
347 auto writeArray2D = [&](
auto&& array2d) {
348 using T =
typename std::decay_t<
decltype(array2d)>::element_t;
350 for (
auto i = 0u;
i < array2d.rows; ++
i) {
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());
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());
372 writeArray2D(
array.getData());
376 if constexpr (isArray<V>()) {
378 writeArray(
v.get<
type*>(),
v.size());
379 }
else if constexpr (isArray2D<V>()) {
381 writeArray2D(
v.get<Array2D<type>>());
382 }
else if constexpr (isLabeledArray<V>()) {
383 writeLabeledArray(
v.get<LabeledArray<type>>());
393 template <VariantType V>
396 rapidjson::Reader reader;
397 rapidjson::IStreamWrapper isw(s);
398 VariantReader<V> vreader;
399 bool ok = reader.Parse(isw, vreader);
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());
406 return vreader.result;
413 writeVariant<VariantType::ArrayInt>(
o,
v);
416 writeVariant<VariantType::ArrayFloat>(
o,
v);
419 writeVariant<VariantType::ArrayDouble>(
o,
v);
422 throw std::runtime_error(
"Bool vectors not implemented yet");
426 writeVariant<VariantType::ArrayString>(
o,
v);
429 writeVariant<VariantType::Array2DInt>(
o,
v);
432 writeVariant<VariantType::Array2DFloat>(
o,
v);
435 writeVariant<VariantType::Array2DDouble>(
o,
v);
438 writeVariant<VariantType::LabeledArrayInt>(
o,
v);
441 writeVariant<VariantType::LabeledArrayFloat>(
o,
v);
444 writeVariant<VariantType::LabeledArrayDouble>(
o,
v);
447 writeVariant<VariantType::LabeledArrayString>(
o,
v);
450 writeVariant<VariantType::Dict>(
o,
v);
o2::monitoring::tags::Key Key
std::vector< variant_array_element_type_t< V > > accumulatedData
std::vector< std::string > labels_rows
std::vector< std::string > labels_cols
Variant for configuration parameter storage. Owns stored data.
GLboolean GLboolean GLboolean b
GLint GLint GLsizei GLint GLenum GLenum type
GLenum GLsizei GLsizei GLint * values
GLubyte GLubyte GLubyte GLubyte w
Defining PrimaryVertex explicitly as messageable.
AbstractArray2D< T, TPCMapMemoryLayout< T > > Array2D
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