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* () const
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->() const
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 const node* find (const std::string& name) const;
371 node* find (const std::string& name);
372
373 void erase (const std::string& name);
374 void clear (type t = type::null);
375 type kind () const;
376 int size () const;
377
378private:
379 type t;
380 union {
381 nodes_map obj;
382 nodes_array arr;
383 std::string str;
384 double num;
385 bool logic;
386 };
387};
388
390inline node::node (const std::string& s)
391 : t (type::string)
392 , str (s)
393{}
394
396inline node::node (const char* s)
397 : t (type::string)
398 , str (s)
399{}
400
402inline node::node (double d)
403 : t (type::numeric)
404 , num (d)
405{}
406
408inline node::node (int d)
409 : t (type::numeric)
410 , num (d)
411{}
412
414inline node::node (bool b)
415 : t (type::boolean)
416 , logic (b)
417{}
418
420template <typename T>
421node::node (const std::vector<T>& vec)
422 : t (type::array)
423{
424 new (&obj) nodes_array ();
425 for (size_t i = 0; i < vec.size (); ++i)
426 arr.emplace_back (std::make_unique<node> (vec[i]));
427}
428
430template <class T>
431node::node (const T& t, decltype (&T::to_json)*)
432 : t (type::object)
433{
434 new (&obj) nodes_map ();
435 t.to_json (*this);
436}
437
439inline node::const_iterator node::begin () const
440{
441 if (t == type::object)
442 return const_iterator (*this, obj.begin ());
443 else if (t == type::array)
444 return const_iterator (*this, arr.begin ());
445 else
446 return const_iterator (*this, false);
447}
448
450inline node::iterator node::begin ()
451{
452 if (t == type::object)
453 return iterator (*this, obj.begin ());
454 else if (t == type::array)
455 return iterator (*this, arr.begin ());
456 else
457 return iterator (*this, false);
458}
459
461inline node::const_iterator node::end () const
462{
463 if (t == type::object)
464 return const_iterator (*this, obj.end ());
465 else if (t == type::array)
466 return const_iterator (*this, arr.end ());
467 else
468 return const_iterator (*this, true);
469}
470
472inline node::iterator node::end ()
473{
474 if (t == type::object)
475 return iterator (*this, obj.end ());
476 else if (t == type::array)
477 return iterator (*this, arr.end ());
478 else
479 return iterator (*this, true);
480}
481
483inline node::operator std::string () const
484{
485 return to_str ();
486}
487
488/*
489 Return a pointer to node's string value.
490 Any assignment to node invalidates the pointer
491*/
492inline node::operator const char* () const
493{
494 if (t != type::string)
496 return str.c_str ();
497}
498
500inline node::operator double () const
501{
502 return to_num ();
503}
504
506inline node::operator float () const
507{
508 return (float)to_num ();
509}
510
511inline node::operator int () const
512{
513 return (int)to_num ();
514}
515
517inline node::operator bool () const
518{
519 return to_bool ();
520}
521
523inline void node::clear (type t_)
524{
525 // clear previous content
526 switch (t)
527 {
528 case type::object:
529 (&obj)->~nodes_map ();
530 break;
531 case type::array:
532 (&arr)->~nodes_array ();
533 break;
534 case type::string:
535 (&str)->~basic_string ();
536 break;
537 }
538
539 t = t_;
540 // initialize new type
541 switch (t)
542 {
543 case type::object:
544 new (&obj) nodes_map ();
545 break;
546 case type::array:
547 new (&arr) nodes_array ();
548 break;
549 case type::string:
550 new (&str) std::string ();
551 break;
552 case type::numeric:
553 num = 0.;
554 break;
555 case type::boolean:
556 logic = false;
557 break;
558 }
559}
560
562inline type node::kind () const
563{
564 return t;
565}
566
568inline int node::size () const
569{
570 return (t == type::object) ? (int)obj.size ()
571 : (t == type::array) ? (int)arr.size ()
572 : (t != type::null) ? 1
573 : 0;
574}
575
577inline bool node::operator!= (const node& other) const
578{
579 return !operator== (other);
580}
581
587inline node& node::at (const std::string& name)
588{
589 return const_cast<node&> (static_cast<const node&> (*this).at (name));
590}
591
597inline node& node::at (size_t index)
598{
599 return const_cast<node&> (static_cast<const node&> (*this).at (index));
600}
601
603struct omanip
604{
605 omanip (void (*fn)(std::ios_base&, int), int val) : pfun(fn), arg(val) {}
606 void (* pfun)(std::ios_base&, int);
607 int arg;
608
609 friend std::ostream& operator << (std::ostream& strm, const omanip& manip) {
610 (*manip.pfun) (strm, manip.arg);
611 return strm;
612 }
613};
614
615// manipulators
616void indenter (std::ios_base& os, int spaces);
617
618inline omanip spaces (int nspc)
619{
620 return omanip (&indenter, nspc);
621}
622
623inline std::ostream& indent (std::ostream& os)
624{
625 indenter (os, 2);
626 return os;
627};
628inline std::ostream& tabs (std::ostream& os)
629{
630 indenter (os, 0);
631 return os;
632};
633
634std::ostream& noindent (std::ostream& os);
635
636std::ostream& utf8 (std::ostream& os);
637
638std::ostream& noutf8 (std::ostream& os);
639
641
643std::ostream& operator<< (std::ostream& os, const node& n);
644
646std::istream& operator>> (std::istream& is, node& n);
647
649template <typename T>
650void to_json (node& n, const std::vector<T>& vec)
651{
652 n.clear (type::array);
653 for (int i = 0; i < vec.size (); ++i)
654 n[i] = vec[i];
655}
656
657} // 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
pointer operator->() const
Value pointer.
Definition json.h:145
iterator_type< C_ > operator--()
Decrement operator (prefix)
Definition json.h:220
~iterator_type()
Destructor.
Definition json.h:115
reference operator*() const
Dereference value.
Definition json.h:124
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
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:577
void erase(const std::string &name)
Erase the child with that name, if it exists.
Definition json.cpp:322
void clear(type t=type::null)
Remove previous node content.
Definition json.h:523
int size() const
Return number of direct descendants.
Definition json.h:568
bool operator==(const node &other) const
Equality operator.
Definition json.cpp:282
type kind() const
Return the type of node.
Definition json.h:562
bool has(const std::string &name) const
Return true if node is an object and has a child with that name.
Definition json.cpp:314
mlib::erc read(std::istream &s)
Deserialize the node from an input stream.
Definition json.cpp:573
bool to_bool() const
Conversion to boolean value.
Definition json.cpp:897
const node * find(const std::string &name) const
If node is an object and has a child with the given name, returns a pointer to child node.
Definition json.cpp:336
const_iterator end() const
End iterator (const variant)
Definition json.h:461
mlib::erc write(std::ostream &os, int flags=0, int spaces=0, int level=0) const
Write node to a stream.
Definition json.cpp:772
node & at(const std::string &name)
Return value of an object node element.
Definition json.h:587
const_iterator begin() const
Begin iterator (const variant)
Definition json.h:439
std::string to_str() const
String conversion function.
Definition json.cpp:882
node & operator=(const node &rhs)
Principal assignment operator.
Definition json.cpp:108
operator std::string() const
Return node value as a string (if possible)
Definition json.h:483
node & operator[](const std::string &name)
Return value of an object node element.
Definition json.cpp:155
node(type t=type::null)
Constructor for an empty node.
Definition json.cpp:34
Definition of mlib::erc and mlib::errfac classes.
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:650
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