MLIB
Loading...
Searching...
No Matches
json.h
Go to the documentation of this file.
1#pragma once
8#include <functional>
9#include <map>
10#include <memory>
11#include <mlib/errorcode.h>
12#include <iomanip>
13#include <string>
14#include <vector>
15
16namespace json {
17
19constexpr int max_array_size = 8192;
20
22constexpr int max_object_names = 8192;
23
25constexpr int max_string_length = 8192;
26
27// Formatting flags
28#define JSON_FMT_INDENT 0x01
29#define JSON_FMT_QUOTESLASH 0x02
30
31// JSON error codes
32#define ERR_JSON_INVTYPE -1
33#define ERR_JSON_TOOMANY -2
34#define ERR_JSON_ITERTYPE -3
35#define ERR_JSON_ITERPOS -4
36#define ERR_JSON_INPUT -5
37#define ERR_JSON_SIZE -7
38#define ERR_JSON_MISSING -8
39
41mlib::errfac& Errors ();
42
44void Errors (mlib::errfac& facility);
45
47enum class type
48{
49 null,
50 object,
51 array,
52 numeric,
53 string,
54 boolean
55};
56
58class node
59{
60public:
61 using pnode = std::unique_ptr<node>;
62 using nodes_map = std::map<const std::string, pnode>;
63 using nodes_array = std::vector<pnode>;
64
65 // Constructors
66 node (type t = type::null);
67 node (const std::string& s);
68 node (const char* s);
69 node (double d);
70 node (int d);
71 node (bool b);
72
73 template <typename T>
74 node (const std::vector<T>& vec);
75
76 template <class T>
77 node (const T& t, decltype (&T::to_json)* = nullptr);
78
79 node (const node& other);
80 node (node&& other);
81 ~node ();
82
84 template <bool C_>
86 {
87 public:
88 // Following typedefs must exist to allow instantiation of std::iterator_traits
89 using difference_type = std::ptrdiff_t;
90 using value_type = node;
91 using reference = typename std::conditional_t<C_, node const&, node&>;
92 using pointer = typename std::conditional_t<C_, const node*, node*>;
93 using obj_iter =
94 typename std::conditional_t<C_, nodes_map::const_iterator, nodes_map::iterator>;
95 using arr_iter =
96 typename std::conditional_t<C_, nodes_array::const_iterator, nodes_array::iterator>;
97 using iterator_category = std::bidirectional_iterator_tag;
98
99 // Copy constructor
100 iterator_type (const iterator_type& other)
101 : target (other.target)
102 {
103 if (target.t == type::object)
104 new (&objit) obj_iter (other.objit);
105 else if (target.t == type::array)
106 new (&arrit) arr_iter (other.arrit);
107 else
108 at_end = other.at_end;
109 }
110
111 // Destructor
113 {
114 if (target.t == type::object)
115 (&objit)->~obj_iter ();
116 else if (target.t == type::array)
117 (&arrit)->~arr_iter ();
118 }
119
121 reference operator* ()
122 {
123 if (target.t == type::object)
124 {
125 if (objit == target.obj.end ())
127 return *objit->second;
128 }
129 else if (target.t == type::array)
130 {
131 if (arrit == target.arr.end ())
133 return **arrit;
134 }
135 else if (at_end)
137
138 return const_cast<json::node&> (target);
139 }
140
142 pointer operator->()
143 {
144 if (target.t == type::object)
145 {
146 if (objit == target.obj.end ())
148 return objit->second.get ();
149 }
150 else if (target.t == type::array)
151 {
152 if (arrit == target.arr.end ())
154 return arrit->get ();
155 }
156 else if (at_end)
158 return const_cast<json::node*> (&target);
159 }
160
162 const std::string& name () const
163 {
164 if (target.t != type::object)
166 if (objit == target.obj.end ())
168 return objit->first;
169 }
170
173 {
174 iterator_type<C_> tmp = *this;
175 if (target.t == type::object)
176 objit.operator++ ();
177 else if (target.t == type::array)
178 arrit.operator++ ();
179 else if (!at_end)
180 at_end = true;
181 else
183 return tmp;
184 }
185
188 {
189 if (target.t == type::object)
190 objit.operator++ ();
191 else if (target.t == type::array)
192 arrit.operator++ ();
193 else if (!at_end)
194 at_end = true;
195 else
197
198 return *this;
199 }
200
203 {
204 iterator_type<C_> tmp = *this;
205 if (target.t == type::object)
206 objit.operator-- ();
207 else if (target.t == type::array)
208 arrit.operator-- ();
209 else if (at_end)
210 at_end = false;
211 else
213 return tmp;
214 }
215
218 {
219 if (target.t == type::object)
220 objit.operator-- ();
221 else if (target.t == type::array)
222 arrit.operator-- ();
223 else if (at_end)
224 at_end = false;
225 else
227 return *this;
228 }
229
231 bool operator== (const iterator_type<C_>& other) const
232 {
233 if (&target != &other.target)
234 return false;
235 else if (target.t == type::object)
236 return (objit == other.objit);
237 else if (target.t == type::array)
238 return (arrit == other.arrit);
239 else
240 return (at_end == other.at_end);
241 }
242
244 bool operator!= (const iterator_type<C_>& other) const
245 {
246 return !operator== (other);
247 }
248
249 private:
250 iterator_type (const node& n, bool end)
251 : target (n)
252 , at_end (end)
253 {}
254
255 iterator_type (const node& n, const arr_iter& it)
256 : target (n)
257 , arrit (it)
258 {}
259
260 iterator_type (const node& n, const obj_iter& it)
261 : target (n)
262 , objit (it)
263 {}
264
265 union {
266 obj_iter objit;
267 arr_iter arrit;
268 bool at_end;
269 };
270
271 const node& target;
272 friend class node;
273 };
274
275 typedef iterator_type<false> iterator;
276 typedef iterator_type<true> const_iterator;
277
278 // ------------------ Assignments -------------------------------------------
279 // principal assignment operator
280 node& operator= (const node& rhs);
281
282 // move assignment operator
283 node& operator= (node&& rhs);
284
286 template <class T, typename B = decltype (&T::to_json)>
287 node& operator= (const T& t)
288 {
289 clear ();
290 t.to_json (*this);
291 return *this;
292 }
293
296 {
297 clear (type::boolean);
298 logic = b;
299 return *this;
300 }
301
303 template <typename T, typename B = std::enable_if_t<std::is_arithmetic_v<T>>>
305 {
306 clear (type::numeric);
307 num = n;
308 return *this;
309 }
310
312 node& operator= (const std::string& s)
313 {
314 clear (type::string);
315 str = s;
316 return *this;
317 }
318
320 node& operator= (const char* s)
321 {
322 clear (type::string);
323 str = s;
324 return *this;
325 }
326
327 // type conversions
328 explicit operator std::string () const;
329 explicit operator const char* () const;
330 explicit operator double () const;
331 explicit operator float () const;
332 explicit operator int () const;
333 explicit operator bool () const;
334
335 double to_num () const;
336 std::string to_str () const;
337 bool to_bool () const;
338
339 // indexing
340 node& operator[] (const std::string& name);
341 const node& operator[] (const std::string& name) const;
342 node& at (const std::string& name);
343 const node& at (const std::string& name) const;
344
345 node& operator[] (size_t index);
346 const node& operator[] (size_t index) const;
347 node& at (size_t index);
348 const node& at (size_t index) const;
349
350 const_iterator begin () const;
351 iterator begin ();
352 const_iterator end () const;
353 iterator end ();
354
355 //(in)equality operators
356 bool operator== (const node& other) const;
357 bool operator!= (const node& other) const;
358
359 // streaming (encoding/decoding)
360 mlib::erc read (std::istream& s);
361 mlib::erc read (const std::string& s);
362 mlib::erc write (std::ostream& os, int flags = 0, int spaces = 0, int level = 0) const;
363 mlib::erc write (std::string& s, int flags = 0, int spaces = 0) const;
364
365 // other operations
366 bool has (const std::string& name) const;
367 void erase (const std::string& name);
368 void clear (type t = type::null);
369 type kind () const;
370 int size () const;
371
372private:
373 type t;
374 union {
375 nodes_map obj;
376 nodes_array arr;
377 std::string str;
378 double num;
379 bool logic;
380 };
381};
382
384inline node::node (const std::string& s)
385 : t (type::string)
386 , str (s)
387{}
388
390inline node::node (const char* s)
391 : t (type::string)
392 , str (s)
393{}
394
396inline node::node (double d)
397 : t (type::numeric)
398 , num (d)
399{}
400
402inline node::node (int d)
403 : t (type::numeric)
404 , num (d)
405{}
406
408inline node::node (bool b)
409 : t (type::boolean)
410 , logic (b)
411{}
412
414template <typename T>
415node::node (const std::vector<T>& vec)
416 : t (type::array)
417{
418 new (&obj) nodes_array ();
419 for (size_t i = 0; i < vec.size (); ++i)
420 arr.emplace_back (std::make_unique<node> (vec[i]));
421}
422
424template <class T>
425node::node (const T& t, decltype (&T::to_json)*)
426 : t (type::object)
427{
428 new (&obj) nodes_map ();
429 t.to_json (*this);
430}
431
434{
435 if (t == type::object)
436 return const_iterator (*this, obj.begin ());
437 else if (t == type::array)
438 return const_iterator (*this, arr.begin ());
439 else
440 return const_iterator (*this, false);
441}
442
445{
446 if (t == type::object)
447 return iterator (*this, obj.begin ());
448 else if (t == type::array)
449 return iterator (*this, arr.begin ());
450 else
451 return iterator (*this, false);
452}
453
456{
457 if (t == type::object)
458 return const_iterator (*this, obj.end ());
459 else if (t == type::array)
460 return const_iterator (*this, arr.end ());
461 else
462 return const_iterator (*this, true);
463}
464
467{
468 if (t == type::object)
469 return iterator (*this, obj.end ());
470 else if (t == type::array)
471 return iterator (*this, arr.end ());
472 else
473 return iterator (*this, true);
474}
475
477inline node::operator std::string () const
478{
479 return to_str ();
480}
481
482/*
483 Return a pointer to node's string value.
484 Any assignment to node invalidates the pointer
485*/
486inline node::operator const char* () const
487{
488 if (t != type::string)
490 return str.c_str ();
491}
492
494inline node::operator double () const
495{
496 return to_num ();
497}
498
500inline node::operator float () const
501{
502 return (float)to_num ();
503}
504
505inline node::operator int () const
506{
507 return (int)to_num ();
508}
509
511inline node::operator bool () const
512{
513 return to_bool ();
514}
515
517inline void node::clear (type t_)
518{
519 // clear previous content
520 switch (t)
521 {
522 case type::object:
523 (&obj)->~nodes_map ();
524 break;
525 case type::array:
526 (&arr)->~nodes_array ();
527 break;
528 case type::string:
529 (&str)->~basic_string ();
530 break;
531 }
532
533 t = t_;
534 // initialize new type
535 switch (t)
536 {
537 case type::object:
538 new (&obj) nodes_map ();
539 break;
540 case type::array:
541 new (&arr) nodes_array ();
542 break;
543 case type::string:
544 new (&str) std::string ();
545 break;
546 case type::numeric:
547 num = 0.;
548 break;
549 case type::boolean:
550 logic = false;
551 break;
552 }
553}
554
556inline type node::kind () const
557{
558 return t;
559}
560
562inline int node::size () const
563{
564 return (t == type::object) ? (int)obj.size ()
565 : (t == type::array) ? (int)arr.size ()
566 : (t != type::null) ? 1
567 : 0;
568}
569
571inline bool node::operator!= (const node& other) const
572{
573 return !operator== (other);
574}
575
581inline node& node::at (const std::string& name)
582{
583 return const_cast<node&> (static_cast<const node&> (*this).at (name));
584}
585
591inline node& node::at (size_t index)
592{
593 return const_cast<node&> (static_cast<const node&> (*this).at (index));
594}
595
596struct omanip
597{
598 omanip (void (*fn)(std::ios_base&, int), int val) : pfun(fn), arg(val) {}
599 void (* pfun)(std::ios_base&, int);
600 int arg;
601
602 friend std::ostream& operator << (std::ostream& strm, const omanip& manip) {
603 (*manip.pfun) (strm, manip.arg);
604 return strm;
605 }
606};
607
608// manipulators
609void indenter (std::ios_base& os, int spaces);
610
611inline omanip spaces (int nspc)
612{
613 return omanip (&indenter, nspc);
614}
615
616inline std::ostream& indent (std::ostream& os)
617{
618 indenter (os, 2);
619 return os;
620};
621inline std::ostream& tabs (std::ostream& os)
622{
623 indenter (os, 0);
624 return os;
625};
626std::ostream& noindent (std::ostream& os);
627
628std::ostream& operator<< (std::ostream& os, const node& n);
629std::istream& operator>> (std::istream& is, node& n);
630
632template <typename T>
633void to_json (node& n, const std::vector<T>& vec)
634{
635 n.clear (type::array);
636 for (int i = 0; i < vec.size (); ++i)
637 n[i] = vec[i];
638}
639
640} // namespace json
node iterator
Definition json.h:86
pointer operator->()
Value pointer.
Definition json.h:142
iterator_type< C_ > & operator++()
Increment operator (prefix)
Definition json.h:187
const std::string & name() const
Object name.
Definition json.h:162
iterator_type< C_ > operator--()
Decrement operator (prefix)
Definition json.h:217
bool operator==(const iterator_type< C_ > &other) const
Equality operator.
Definition json.h:231
reference operator*()
Dereference value.
Definition json.h:121
bool operator!=(const iterator_type< C_ > &other) const
Inequality operator.
Definition json.h:244
Representation of a JSON node.
Definition json.h:59
node & operator[](const std::string &name)
Return value of an object node element.
Definition json.cpp:158
bool has(const std::string &name) const
Return true if node is an object and has a child with that name.
Definition json.cpp:317
node & operator=(const node &rhs)
Principal assignment operator.
Definition json.cpp:111
void clear(type t=type::null)
Remove previous node content.
Definition json.h:517
node & at(const std::string &name)
Return value of an object node element.
Definition json.h:581
const_iterator end() const
End iterator (const variant)
Definition json.h:455
bool to_bool() const
Conversion to boolean value.
Definition json.cpp:854
mlib::erc read(std::istream &s)
Deserialize the node from an input stream.
Definition json.cpp:524
bool operator==(const node &other) const
Equality operator.
Definition json.cpp:285
int size() const
Return number of direct descendants.
Definition json.h:562
type kind() const
Return the type of node.
Definition json.h:556
bool operator!=(const node &other) const
inequality operator
Definition json.h:571
void erase(const std::string &name)
Erase the child with that name, if it exists.
Definition json.cpp:325
std::string to_str() const
String conversion function.
Definition json.cpp:839
mlib::erc write(std::ostream &os, int flags=0, int spaces=0, int level=0) const
Write node to a stream.
Definition json.cpp:721
node(type t=type::null)
Constructor for an empty node.
Definition json.cpp:36
const_iterator begin() const
Begin iterator (const variant)
Definition json.h:433
objects returned as a function result or thrown directly.
Definition errorcode.h:68
void raise() const
Definition errorcode.h:598
An error facility routes a group of errors handled in a similar manner.
Definition errorcode.h:136
Definition of erc and erfac classes.
mlib::errfac & Errors()
Return error facility used for JSON errors.
Definition json.cpp:23
#define ERR_JSON_INVTYPE
invalid node type
Definition json.h:32
#define ERR_JSON_ITERTYPE
invalid iterator type
Definition json.h:34
#define ERR_JSON_ITERPOS
invalid iterator position
Definition json.h:35
constexpr int max_array_size
Maximum number of array elements in a JSON node.
Definition json.h:19
void to_json(node &n, const std::vector< T > &vec)
Assign array value to a node.
Definition json.h:633
type
JSON node types.
Definition json.h:48
constexpr int max_string_length
Maximum string length.
Definition json.h:25
constexpr int max_object_names
Maximum number of properties for a node.
Definition json.h:22
Definition json.h:597