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
34// JSON error codes
35#define ERR_JSON_INVTYPE -1
36#define ERR_JSON_TOOMANY -2
37#define ERR_JSON_ITERTYPE -3
38#define ERR_JSON_ITERPOS -4
39#define ERR_JSON_INPUT -5
40#define ERR_JSON_SIZE -7
41#define ERR_JSON_MISSING -8
42
44mlib::errfac& Errors ();
45
47void Errors (mlib::errfac& facility);
48
50enum class type
51{
52 null,
53 object,
54 array,
55 numeric,
56 string,
57 boolean
58};
59
61class node
62{
63public:
64 using pnode = std::unique_ptr<node>;
65 using nodes_map = std::map<const std::string, pnode>;
66 using nodes_array = std::vector<pnode>;
67
68 // Constructors
69 node (type t = type::null);
70 node (const std::string& s);
71 node (const char* s);
72 node (double d);
73 node (int d);
74 node (bool b);
75
76 template <typename T>
77 node (const std::vector<T>& vec);
78
79 template <class T>
80 node (const T& t, decltype (&T::to_json)* = nullptr);
81
82 node (const node& other);
83 node (node&& other);
84 ~node ();
85
87 template <bool C_>
89 {
90 public:
92 // Following typedefs must exist to allow instantiation of std::iterator_traits
93 using difference_type = std::ptrdiff_t;
94 using value_type = node;
95 using reference = typename std::conditional_t<C_, node const&, node&>;
96 using pointer = typename std::conditional_t<C_, const node*, node*>;
97 using obj_iter =
98 typename std::conditional_t<C_, nodes_map::const_iterator, nodes_map::iterator>;
99 using arr_iter =
100 typename std::conditional_t<C_, nodes_array::const_iterator, nodes_array::iterator>;
101 using iterator_category = std::bidirectional_iterator_tag;
105 : target (other.target)
106 {
107 if (target.t == type::object)
108 new (&objit) obj_iter (other.objit);
109 else if (target.t == type::array)
110 new (&arrit) arr_iter (other.arrit);
111 else
112 at_end = other.at_end;
113 }
114
117 {
118 if (target.t == type::object)
119 (&objit)->~obj_iter ();
120 else if (target.t == type::array)
121 (&arrit)->~arr_iter ();
122 }
123
125 reference operator* () const
126 {
127 if (target.t == type::object)
128 {
129 if (objit == target.obj.end ())
131 return *objit->second;
132 }
133 else if (target.t == type::array)
134 {
135 if (arrit == target.arr.end ())
137 return **arrit;
138 }
139 else if (at_end)
141
142 return const_cast<json::node&> (target);
143 }
144
146 pointer operator->() const
147 {
148 if (target.t == type::object)
149 {
150 if (objit == target.obj.end ())
152 return objit->second.get ();
153 }
154 else if (target.t == type::array)
155 {
156 if (arrit == target.arr.end ())
158 return arrit->get ();
159 }
160 else if (at_end)
162 return const_cast<json::node*> (&target);
163 }
164
166 const std::string& name () const
167 {
168 if (target.t != type::object)
170 if (objit == target.obj.end ())
172 return objit->first;
173 }
174
177 {
178 iterator_type<C_> tmp = *this;
179 if (target.t == type::object)
180 objit.operator++ ();
181 else if (target.t == type::array)
182 arrit.operator++ ();
183 else if (!at_end)
184 at_end = true;
185 else
187 return tmp;
188 }
189
192 {
193 if (target.t == type::object)
194 objit.operator++ ();
195 else if (target.t == type::array)
196 arrit.operator++ ();
197 else if (!at_end)
198 at_end = true;
199 else
201
202 return *this;
203 }
204
207 {
208 iterator_type<C_> tmp = *this;
209 if (target.t == type::object)
210 objit.operator-- ();
211 else if (target.t == type::array)
212 arrit.operator-- ();
213 else if (at_end)
214 at_end = false;
215 else
217 return tmp;
218 }
219
222 {
223 if (target.t == type::object)
224 objit.operator-- ();
225 else if (target.t == type::array)
226 arrit.operator-- ();
227 else if (at_end)
228 at_end = false;
229 else
231 return *this;
232 }
233
235 bool operator== (const iterator_type<C_>& other) const
236 {
237 if (&target != &other.target)
238 return false;
239 else if (target.t == type::object)
240 return (objit == other.objit);
241 else if (target.t == type::array)
242 return (arrit == other.arrit);
243 else
244 return (at_end == other.at_end);
245 }
246
248 bool operator!= (const iterator_type<C_>& other) const
249 {
250 return !operator== (other);
251 }
252
253 private:
254 iterator_type (const node& n, bool end)
255 : target (n)
256 , at_end (end)
257 {}
258
259 iterator_type (const node& n, const arr_iter& it)
260 : target (n)
261 , arrit (it)
262 {}
263
264 iterator_type (const node& n, const obj_iter& it)
265 : target (n)
266 , objit (it)
267 {}
268
269 union {
270 obj_iter objit;
271 arr_iter arrit;
272 bool at_end;
273 };
274
275 const node& target;
276 friend class node;
277 };
278
279 typedef iterator_type<false> iterator;
280 typedef iterator_type<true> const_iterator;
281
282 // ------------------ Assignments -------------------------------------------
283 // principal assignment operator
284 node& operator= (const node& rhs);
285
286 // move assignment operator
287 node& operator= (node&& rhs);
288
290 template <class T, typename B = decltype (&T::to_json)>
291 node& operator= (const T& t)
292 {
293 clear ();
294 t.to_json (*this);
295 return *this;
296 }
297
300 {
301 clear (type::boolean);
302 logic = b;
303 return *this;
304 }
305
307 template <typename T, typename B = std::enable_if_t<std::is_arithmetic_v<T>>>
309 {
310 clear (type::numeric);
311 num = n;
312 return *this;
313 }
314
316 node& operator= (const std::string& s)
317 {
318 clear (type::string);
319 str = s;
320 return *this;
321 }
322
324 node& operator= (const char* s)
325 {
326 clear (type::string);
327 str = s;
328 return *this;
329 }
330
331 // type conversions
332 explicit operator std::string () const;
333 explicit operator const char* () const;
334 explicit operator double () const;
335 explicit operator float () const;
336 explicit operator int () const;
337 explicit operator bool () const;
338
339 double to_num () const;
340 std::string to_str () const;
341 bool to_bool () const;
342
343 // indexing
344 node& operator[] (const std::string& name);
345 const node& operator[] (const std::string& name) const;
346 node& at (const std::string& name);
347 const node& at (const std::string& name) const;
348
349 node& operator[] (size_t index);
350 const node& operator[] (size_t index) const;
351 node& at (size_t index);
352 const node& at (size_t index) const;
353 void push_back (const node& n);
354
355 const_iterator begin () const;
356 iterator begin ();
357 const_iterator end () const;
358 iterator end ();
359
360 //(in)equality operators
361 bool operator== (const node& other) const;
362 bool operator!= (const node& other) const;
363
364 // streaming (encoding/decoding)
365 mlib::erc read (std::istream& s);
366 mlib::erc read (const std::string& s);
367 mlib::erc write (std::string& s, int flags=0, int spaces=0) const;
368
369 // other operations
370 bool has (const std::string& name) const;
371 const node* find (const std::string& name) const;
372 node* find (const std::string& name);
373
374 void erase (const std::string& name);
375 void clear (type t = type::null);
376 type kind () const;
377 int size () const;
378 void format (const std::string& f);
379 const std::string_view format () const;
380
381private:
382 mlib::erc write (std::ostream& os, int flags, int spaces, int level,
383 const std::string_view format) const;
384 type t;
385 union {
386 nodes_map obj;
387 nodes_array arr;
388 std::string str;
389 double num;
390 bool logic;
391 };
392 std::unique_ptr <std::string> fmt;
393
394 friend std::ostream& operator<< (std::ostream& os, const node& n);
395};
396
398inline node::node (const std::string& s)
399 : t (type::string)
400 , str (s)
401{}
402
404inline node::node (const char* s)
405 : t (type::string)
406 , str (s)
407{}
408
410inline node::node (double d)
411 : t (type::numeric)
412 , num (d)
413{}
414
416inline node::node (int d)
417 : t (type::numeric)
418 , num (d)
419{}
420
422inline node::node (bool b)
423 : t (type::boolean)
424 , logic (b)
425{}
426
428template <typename T>
429node::node (const std::vector<T>& vec)
430 : t (type::array)
431{
432 new (&obj) nodes_array ();
433 for (size_t i = 0; i < vec.size (); ++i)
434 arr.emplace_back (std::make_unique<node> (vec[i]));
435}
436
438template <class T>
439node::node (const T& t, decltype (&T::to_json)*)
440 : t (type::object)
441{
442 new (&obj) nodes_map ();
443 t.to_json (*this);
444}
445
447inline node::const_iterator node::begin () const
448{
449 if (t == type::object)
450 return const_iterator (*this, obj.begin ());
451 else if (t == type::array)
452 return const_iterator (*this, arr.begin ());
453 else
454 return const_iterator (*this, false);
455}
456
458inline node::iterator node::begin ()
459{
460 if (t == type::object)
461 return iterator (*this, obj.begin ());
462 else if (t == type::array)
463 return iterator (*this, arr.begin ());
464 else
465 return iterator (*this, false);
466}
467
469inline node::const_iterator node::end () const
470{
471 if (t == type::object)
472 return const_iterator (*this, obj.end ());
473 else if (t == type::array)
474 return const_iterator (*this, arr.end ());
475 else
476 return const_iterator (*this, true);
477}
478
480inline node::iterator node::end ()
481{
482 if (t == type::object)
483 return iterator (*this, obj.end ());
484 else if (t == type::array)
485 return iterator (*this, arr.end ());
486 else
487 return iterator (*this, true);
488}
489
491inline node::operator std::string () const
492{
493 return to_str ();
494}
495
496/*
497 Return a pointer to node's string value.
498 Any assignment to node invalidates the pointer
499*/
500inline node::operator const char* () const
501{
502 if (t != type::string)
504 return str.c_str ();
505}
506
508inline node::operator double () const
509{
510 return to_num ();
511}
512
514inline node::operator float () const
515{
516 return (float)to_num ();
517}
518
519inline node::operator int () const
520{
521 return (int)to_num ();
522}
523
525inline node::operator bool () const
526{
527 return to_bool ();
528}
529
531inline void node::clear (type t_)
532{
533 // clear previous content
534 switch (t)
535 {
536 case type::object:
537 (&obj)->~nodes_map ();
538 break;
539 case type::array:
540 (&arr)->~nodes_array ();
541 break;
542 case type::string:
543 (&str)->~basic_string ();
544 break;
545 }
546
547 t = t_;
548 // initialize new type
549 switch (t)
550 {
551 case type::object:
552 new (&obj) nodes_map ();
553 break;
554 case type::array:
555 new (&arr) nodes_array ();
556 break;
557 case type::string:
558 new (&str) std::string ();
559 break;
560 case type::numeric:
561 num = 0.;
562 break;
563 case type::boolean:
564 logic = false;
565 break;
566 }
567}
568
570inline type node::kind () const
571{
572 return t;
573}
574
576inline int node::size () const
577{
578 return (t == type::object) ? (int)obj.size ()
579 : (t == type::array) ? (int)arr.size ()
580 : (t != type::null) ? 1
581 : 0;
582}
583
585inline void node::format (const std::string& f)
586{
587 fmt.reset (f.empty () ? nullptr : new std::string(f));
588}
589
591inline const std::string_view node::format () const
592{
593 return fmt? *fmt : std::string_view();
594}
595
597inline bool node::operator!= (const node& other) const
598{
599 return !operator== (other);
600}
601
607inline node& node::at (const std::string& name)
608{
609 return const_cast<node&> (static_cast<const node&> (*this).at (name));
610}
611
617inline node& node::at (size_t index)
618{
619 return const_cast<node&> (static_cast<const node&> (*this).at (index));
620}
621
623struct omanip
624{
625 omanip (void (*fn)(std::ios_base&, int), int val) : pfun(fn), arg(val) {}
626 void (* pfun)(std::ios_base&, int);
627 int arg;
628
629 friend std::ostream& operator << (std::ostream& strm, const omanip& manip) {
630 (*manip.pfun) (strm, manip.arg);
631 return strm;
632 }
633};
634
635// manipulators
636void indenter (std::ios_base& os, int spaces);
637
638inline omanip spaces (int nspc)
639{
640 return omanip (&indenter, nspc);
641}
642
643inline std::ostream& indent (std::ostream& os)
644{
645 indenter (os, 2);
646 return os;
647};
648inline std::ostream& tabs (std::ostream& os)
649{
650 indenter (os, 0);
651 return os;
652};
653
654std::ostream& noindent (std::ostream& os);
655
656std::ostream& utf8 (std::ostream& os);
657
658std::ostream& noutf8 (std::ostream& os);
659
661
663std::ostream& operator<< (std::ostream& os, const node& n);
664
666std::istream& operator>> (std::istream& is, node& n);
667
669template <typename T>
670void to_json (node& n, const std::vector<T>& vec)
671{
672 n.clear (type::array);
673 for (int i = 0; i < vec.size (); ++i)
674 n[i] = vec[i];
675}
676
677} // 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:89
pointer operator->() const
Value pointer.
Definition json.h:146
iterator_type< C_ > operator--()
Decrement operator (prefix)
Definition json.h:221
~iterator_type()
Destructor.
Definition json.h:116
reference operator*() const
Dereference value.
Definition json.h:125
iterator_type(const iterator_type &other)
Copy constructor.
Definition json.h:104
bool operator!=(const iterator_type< C_ > &other) const
Inequality operator.
Definition json.h:248
iterator_type< C_ > & operator++()
Increment operator (prefix)
Definition json.h:191
bool operator==(const iterator_type< C_ > &other) const
Equality operator.
Definition json.h:235
const std::string & name() const
Object name.
Definition json.h:166
Representation of a JSON node.
Definition json.h:62
bool operator!=(const node &other) const
inequality operator
Definition json.h:597
void erase(const std::string &name)
Erase the child with that name, if it exists.
Definition json.cpp:339
void clear(type t=type::null)
Remove previous node content.
Definition json.h:531
int size() const
Return number of direct descendants.
Definition json.h:576
bool operator==(const node &other) const
Equality operator.
Definition json.cpp:299
type kind() const
Return the type of node.
Definition json.h:570
bool has(const std::string &name) const
Return true if node is an object and has a child with that name.
Definition json.cpp:331
void push_back(const node &n)
Append an element at the end of an array.
Definition json.cpp:288
mlib::erc read(std::istream &s)
Deserialize the node from an input stream.
Definition json.cpp:590
bool to_bool() const
Conversion to boolean value.
Definition json.cpp:959
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:353
mlib::erc write(std::string &s, int flags=0, int spaces=0) const
Write node to a string.
Definition json.cpp:887
const_iterator end() const
End iterator (const variant)
Definition json.h:469
node & at(const std::string &name)
Return value of an object node element.
Definition json.h:607
const_iterator begin() const
Begin iterator (const variant)
Definition json.h:447
std::string to_str() const
String conversion function.
Definition json.cpp:923
node & operator=(const node &rhs)
Principal assignment operator.
Definition json.cpp:110
operator std::string() const
Return node value as a string (if possible)
Definition json.h:491
const std::string_view format() const
Return output format for numerical values.
Definition json.h:591
node & operator[](const std::string &name)
Return value of an object node element.
Definition json.cpp:159
friend std::ostream & operator<<(std::ostream &os, const node &n)
Insertion operator serializes a JSON node to an output stream.
Definition json.cpp:1003
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:35
#define ERR_JSON_ITERTYPE
invalid iterator type
Definition json.h:37
#define ERR_JSON_ITERPOS
invalid iterator position
Definition json.h:38
void to_json(node &n, const std::vector< T > &vec)
Assign array value to a node.
Definition json.h:670
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:51