Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
JSONParser.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Carsten D. Burgard, DESY/ATLAS, Dec 2021
5 *
6 * Copyright (c) 2022, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
13#include "JSONParser.h"
14
15#include <sstream>
16
17#include <nlohmann/json.hpp>
18
19namespace {
20inline nlohmann::json parseWrapper(std::istream &is)
21{
22 try {
23 return nlohmann::json::parse(is);
24 } catch (const nlohmann::json::exception &ex) {
25 throw std::runtime_error(ex.what());
26 }
27}
28} // namespace
29
30// TJSONTree methods
31
33
34TJSONTree::TJSONTree(std::istream &is) : root(this, is) {};
35
40
42{
43 _nodecache.push_back(n);
44 return _nodecache.back();
45}
46
48{
49 return *node;
50}
51
56
61
62// TJSONTree::Node implementation
63
65public:
66 std::string _key;
67 std::string const &key() const { return _key; }
68 virtual nlohmann::json &get() = 0;
69 virtual const nlohmann::json &get() const = 0;
70 class BaseNode;
71 class NodeRef;
72 Impl(const std::string &k) : _key(k) {}
73 virtual ~Impl() = default;
74 static TJSONTree::Node &mkNode(TJSONTree *t, const std::string &k, nlohmann::json &n);
75 static const TJSONTree::Node &mkNode(const TJSONTree *t, const std::string &k, const nlohmann::json &n);
76};
77
79 nlohmann::json node;
80
81public:
82 nlohmann::json &get() override { return node; }
83 const nlohmann::json &get() const override { return node; }
84 BaseNode(std::istream &is) : Impl(""), node(parseWrapper(is)) {}
85 BaseNode() : Impl("") {}
86};
87
89 nlohmann::json &node;
90
91public:
92 nlohmann::json &get() override { return node; }
93 const nlohmann::json &get() const override { return node; }
94 NodeRef(const std::string &k, nlohmann::json &n) : Impl(k), node(n) {}
96};
97
98TJSONTree::Node &TJSONTree::Node::Impl::mkNode(TJSONTree *t, const std::string &k, nlohmann::json &n)
99{
101 return t->incache(Node(t, ref));
102}
103
104const TJSONTree::Node &TJSONTree::Node::Impl::mkNode(const TJSONTree *t, const std::string &k, const nlohmann::json &n)
105{
106 // not so nice to use const_cast here, but the non-const version will only live in the cache
107 Node::Impl::NodeRef ref(k, const_cast<nlohmann::json &>(n));
108 return const_cast<TJSONTree *>(t)->incache(Node(const_cast<TJSONTree *>(t), ref));
109}
110
111TJSONTree::Node::Node(TJSONTree *t, std::istream &is) : tree(t), node(std::make_unique<Impl::BaseNode>(is)) {}
112
113TJSONTree::Node::Node(TJSONTree *t) : tree(t), node(std::make_unique<Impl::BaseNode>()) {}
114
116 : tree(t), node(std::make_unique<Impl::NodeRef>(other.key(), other.get()))
117{
118}
119
121
122TJSONTree::Node::~Node() = default;
123
124// TJSONNode interface
125
126void TJSONTree::Node::writeJSON(std::ostream &os) const
127{
128 os << node->get();
129}
130
132{
133 node->get() = s;
134 return *this;
135}
136
138{
139 node->get() = i;
140 return *this;
141}
142
144{
145 node->get() = d;
146 return *this;
147}
148
150{
151 node->get() = b;
152 return *this;
153}
154
156{
157 v = node->get().get<std::string>();
158 return *this;
159}
160
162{
163 return Impl::mkNode(tree, k, node->get()[k]);
164}
165
166const TJSONTree::Node &TJSONTree::Node::operator[](std::string const &k) const
167{
168 return Impl::mkNode(tree, k, node->get()[k]);
169}
170
172{
173 return node->get().is_array() || node->get().is_object();
174}
175
177{
178 return node->get().is_object();
179}
180
182{
183 return node->get().is_array();
184}
185
187{
188 return node->get().is_null();
189}
190
191namespace {
192
193// To check whether it's allowed to reset the type of an object. We allow
194// this for nodes that have no type yet, or nodes with an empty string.
195bool isResettingPossible(nlohmann::json const &node)
196{
197
198 if (node.type() == nlohmann::json::value_t::null) {
199 return true;
200 }
201
202 if (node.type() == nlohmann::json::value_t::string) {
203 if (node.get<std::string>().empty()) {
204 return true;
205 }
206 }
207 return false;
208}
209} // namespace
210
212{
213 if (node->get().type() == nlohmann::json::value_t::object)
214 return *this;
215
216 if (isResettingPossible(node->get())) {
217 node->get() = nlohmann::json::object();
218 } else {
219 throw std::runtime_error("cannot declare \"" + this->key() + "\" to be of map - type, already of type " +
220 node->get().type_name());
221 }
222 return *this;
223}
224
226{
227 if (node->get().type() == nlohmann::json::value_t::array)
228 return *this;
229
230 if (isResettingPossible(node->get())) {
231 node->get() = nlohmann::json::array();
232 } else {
233 throw std::runtime_error("cannot declare \"" + this->key() + "\" to be of seq - type, already of type " +
234 node->get().type_name());
235 }
236 return *this;
237}
238
240{
241 node->get() = nullptr;
242 return *this;
243}
244
246{
247 node->get().clear();
248}
249
250std::string TJSONTree::Node::key() const
251{
252 return node->key();
253}
254
255std::string TJSONTree::Node::val() const
256{
257 switch (node->get().type()) {
258 case nlohmann::json::value_t::string: return node->get().get<std::string>();
259 case nlohmann::json::value_t::boolean: return node->get().get<bool>() ? "true" : "false";
260 case nlohmann::json::value_t::number_integer: return std::to_string(node->get().get<int>());
261 case nlohmann::json::value_t::number_unsigned: return std::to_string(node->get().get<unsigned int>());
262 case nlohmann::json::value_t::number_float: {
263 std::stringstream ss;
264 ss << node->get().get<double>();
265 return ss.str();
266 }
267 default:
268 throw std::runtime_error("node \"" + node->key() + "\": implicit string conversion for type " +
269 node->get().type_name() + " not supported!");
270 }
271}
272
274{
275 return node->get().get<int>();
276}
278{
279 return node->get().get<double>();
280}
282{
283 auto const &nd = node->get();
284
285 // Attempting to convert zeroes and ones to bools.
286 if (nd.type() == nlohmann::json::value_t::number_unsigned) {
287 auto val = nd.get<unsigned int>();
288 if (val == 0)
289 return false;
290 if (val == 1)
291 return true;
292 }
293
294 return nd.get<bool>();
295}
296
298{
299 return !node->key().empty();
300}
301
303{
304 return node->get().is_primitive();
305}
306
307bool TJSONTree::Node::has_child(std::string const &c) const
308{
309 return node->get().find(c) != node->get().end();
310}
311
313{
314 node->get().push_back("");
315 return Impl::mkNode(tree, "", node->get().back());
316}
317
319{
320 return node->get().size();
321}
322
324{
325 return Impl::mkNode(tree, "", node->get().at(pos));
326}
327
329{
330 return Impl::mkNode(tree, "", node->get().at(pos));
331}
332
335
336template <class Nd, class NdType, class json_it>
338public:
339 enum class POS {
340 BEGIN,
341 END
342 };
344 : node(n), iter(p == POS::BEGIN ? n.get_node().get().begin() : n.get_node().get().end()) {};
345 ChildItImpl(NdType &n, json_it it) : node(n), iter(it) {}
348 std::unique_ptr<typename child_iterator::Impl> clone() const override
349 {
350 return std::make_unique<ChildItImpl>(node, iter);
351 }
352 void forward() override { ++iter; }
353 void backward() override { --iter; }
354 Nd &current() override
355 {
356 if (node.is_seq()) {
357 return TJSONTree::Node::Impl::mkNode(node.get_tree(), "", iter.value());
358 } else {
359 return TJSONTree::Node::Impl::mkNode(node.get_tree(), iter.key(), iter.value());
360 }
361 }
362 bool equal(const typename child_iterator::Impl &other) const override
363 {
364 // We can use static_cast here because we never compare Iterators for
365 // different JSON node types.
366 auto it = static_cast<const ChildItImpl<Nd, NdType, json_it> *>(&other);
367 return it && it->iter == this->iter;
368 }
369
370private:
372 json_it iter;
373};
374
376{
378 return {child_iterator(std::make_unique<childIt>(*this, childIt::POS::BEGIN)),
379 child_iterator(std::make_unique<childIt>(*this, childIt::POS::END))};
380}
382{
383 using childConstIt =
385 return {const_child_iterator(std::make_unique<childConstIt>(*this, childConstIt::POS::BEGIN)),
386 const_child_iterator(std::make_unique<childConstIt>(*this, childConstIt::POS::END))};
387}
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
JSONNode & get(std::string const &key)
std::unique_ptr< typename child_iterator::Impl > clone() const override
ChildItImpl(NdType &n, POS p)
ChildItImpl(const ChildItImpl &other)
bool equal(const typename child_iterator::Impl &other) const override
ChildItImpl(NdType &n, json_it it)
const nlohmann::json & get() const override
nlohmann::json & get() override
NodeRef(const std::string &k, nlohmann::json &n)
NodeRef(const NodeRef &other)
const nlohmann::json & get() const override
nlohmann::json & get() override
Impl(const std::string &k)
virtual const nlohmann::json & get() const =0
static TJSONTree::Node & mkNode(TJSONTree *t, const std::string &k, nlohmann::json &n)
virtual nlohmann::json & get()=0
std::string const & key() const
virtual ~Impl()=default
bool is_container() const override
bool has_child(std::string const &) const override
bool val_bool() const override
Node & child(size_t pos) override
const Node & operator>>(std::string &v) const override
Node & operator[](std::string const &k) override
Node & set_null() override
Node & append_child() override
void clear() override
size_t num_children() const override
std::string val() const override
void writeJSON(std::ostream &os) const override
bool has_key() const override
std::string key() const override
Node & set_map() override
double val_double() const override
bool is_seq() const override
std::unique_ptr< Impl > node
Definition JSONParser.h:31
Node & set_seq() override
bool has_val() const override
virtual ~Node()
Node(TJSONTree *t, std::istream &is)
const Impl & get_node() const
bool is_map() const override
children_view children() override
Node & operator<<(std::string const &s) override
int val_int() const override
bool is_null() const override
TJSONTree::Node & incache(const TJSONTree::Node &n)
std::list< Node > _nodecache
Definition JSONParser.h:80
void clearcache()
~TJSONTree() override
const Int_t n
Definition legend1.C:16
Double_t ex[n]
Definition legend1.C:17