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