Mercurial > irccd
comparison common/json.h @ 0:1158cffe5a5e
Initial import
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 08 Feb 2016 16:43:14 +0100 |
parents | |
children | 03068f5ed79d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1158cffe5a5e |
---|---|
1 /* | |
2 * json.h -- C++14 JSON manipulation using jansson parser | |
3 * | |
4 * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #ifndef _JSON_H_ | |
20 #define _JSON_H_ | |
21 | |
22 /** | |
23 * @file json.h | |
24 * @brief Jansson C++14 wrapper | |
25 * | |
26 * These classes can be used to build or parse JSON documents using jansson library. It is designed to be safe | |
27 * and explicit. It does not implement implicit sharing like jansson so when you access (e.g. Value::toObject) values | |
28 * you get real copies, thus when you read big documents it can has a performance cost. | |
29 */ | |
30 | |
31 #include <cassert> | |
32 #include <exception> | |
33 #include <initializer_list> | |
34 #include <map> | |
35 #include <string> | |
36 #include <utility> | |
37 #include <vector> | |
38 | |
39 namespace irccd { | |
40 | |
41 /** | |
42 * Json namespace. | |
43 */ | |
44 namespace json { | |
45 | |
46 /** | |
47 * @enum Type | |
48 * @brief Type of Value. | |
49 */ | |
50 enum class Type { | |
51 Array, //!< Value is an array [] | |
52 Boolean, //!< Value is boolean | |
53 Int, //!< Value is integer | |
54 Null, //!< Value is defined to null | |
55 Object, //!< Value is object {} | |
56 Real, //!< Value is float | |
57 String //!< Value is unicode string | |
58 }; | |
59 | |
60 /** | |
61 * @class Error | |
62 * @brief Error description. | |
63 */ | |
64 class Error : public std::exception { | |
65 private: | |
66 std::string m_text; | |
67 std::string m_source; | |
68 int m_line; | |
69 int m_column; | |
70 int m_position; | |
71 | |
72 public: | |
73 /** | |
74 * Create the error. | |
75 * | |
76 * @param text the text message | |
77 * @param source the source (e.g. file name) | |
78 * @param line the line number | |
79 * @param column the column number | |
80 * @param position the position | |
81 */ | |
82 inline Error(std::string text, std::string source, int line, int column, int position) noexcept | |
83 : m_text{std::move(text)} | |
84 , m_source{std::move(source)} | |
85 , m_line{line} | |
86 , m_column{column} | |
87 , m_position{position} | |
88 { | |
89 } | |
90 | |
91 /** | |
92 * Get the error message. | |
93 * | |
94 * @return the text | |
95 */ | |
96 inline const std::string &text() const noexcept | |
97 { | |
98 return m_text; | |
99 } | |
100 | |
101 /** | |
102 * Get the source (e.g. a file name). | |
103 * | |
104 * @return the source | |
105 */ | |
106 inline const std::string &source() const noexcept | |
107 { | |
108 return m_source; | |
109 } | |
110 | |
111 /** | |
112 * Get the line. | |
113 * | |
114 * @return the line | |
115 */ | |
116 inline int line() const noexcept | |
117 { | |
118 return m_line; | |
119 } | |
120 | |
121 /** | |
122 * Get the column. | |
123 * | |
124 * @return the column | |
125 */ | |
126 inline int column() const noexcept | |
127 { | |
128 return m_column; | |
129 } | |
130 | |
131 /** | |
132 * Get the position. | |
133 * | |
134 * @return the position | |
135 */ | |
136 inline int position() const noexcept | |
137 { | |
138 return m_position; | |
139 } | |
140 | |
141 /** | |
142 * Get the error message. | |
143 * | |
144 * @return the message | |
145 */ | |
146 const char *what() const noexcept override | |
147 { | |
148 return m_text.c_str(); | |
149 } | |
150 }; | |
151 | |
152 /** | |
153 * @class Buffer | |
154 * @brief Open JSON document from text. | |
155 */ | |
156 class Buffer { | |
157 public: | |
158 std::string text; //!< The JSON text | |
159 }; | |
160 | |
161 /** | |
162 * @class File | |
163 * @brief Open JSON document from a file. | |
164 */ | |
165 class File { | |
166 public: | |
167 std::string path; //!< The path to the file | |
168 }; | |
169 | |
170 /** | |
171 * @class Value | |
172 * @brief Generic JSON value wrapper. | |
173 */ | |
174 class Value { | |
175 private: | |
176 Type m_type{Type::Null}; | |
177 | |
178 union { | |
179 double m_number; | |
180 bool m_boolean; | |
181 int m_integer; | |
182 std::string m_string; | |
183 std::vector<Value> m_array; | |
184 std::map<std::string, Value> m_object; | |
185 }; | |
186 | |
187 void copy(const Value &); | |
188 void move(Value &&); | |
189 std::string toJson(int indent, int current) const; | |
190 | |
191 /** | |
192 * @class BaseIterator | |
193 * @brief This is the base class for iterator and const_iterator | |
194 * | |
195 * This iterator works for both arrays and objects. Because of that purpose, it is only available | |
196 * as forward iterator. | |
197 * | |
198 * When iterator comes from an object, you can use key() otherwise you can use index(). | |
199 */ | |
200 template <typename ValueType, typename ArrayIteratorType, typename ObjectIteratorType> | |
201 class BaseIterator : public std::iterator<std::forward_iterator_tag, ValueType> { | |
202 private: | |
203 friend class Value; | |
204 | |
205 ValueType &m_value; | |
206 ArrayIteratorType m_ita; | |
207 ObjectIteratorType m_itm; | |
208 | |
209 inline void increment() | |
210 { | |
211 if (m_value.isObject()) { | |
212 m_itm++; | |
213 } else { | |
214 m_ita++; | |
215 } | |
216 } | |
217 | |
218 BaseIterator(ValueType &value, ObjectIteratorType it) | |
219 : m_value(value) | |
220 , m_itm(it) | |
221 { | |
222 } | |
223 | |
224 BaseIterator(ValueType &value, ArrayIteratorType it) | |
225 : m_value(value) | |
226 , m_ita(it) | |
227 { | |
228 } | |
229 | |
230 public: | |
231 /** | |
232 * Get the iterator key (for objects). | |
233 * | |
234 * @pre iterator must be dereferenceable | |
235 * @pre iterator must come from object | |
236 * @return the key | |
237 */ | |
238 inline const std::string &key() const noexcept | |
239 { | |
240 assert(m_value.isObject()); | |
241 assert(m_itm != m_value.m_object.end()); | |
242 | |
243 return m_itm->first; | |
244 } | |
245 | |
246 /** | |
247 * Get the iterator position (for arrays). | |
248 * | |
249 * @pre iterator must be dereferenceable | |
250 * @pre iterator must come from arrays | |
251 * @return the index | |
252 */ | |
253 inline unsigned index() const noexcept | |
254 { | |
255 assert(m_value.isArray()); | |
256 assert(m_ita != m_value.m_array.end()); | |
257 | |
258 return std::distance(m_value.m_array.begin(), m_ita); | |
259 } | |
260 | |
261 /** | |
262 * Dereference the iterator. | |
263 * | |
264 * @pre iterator be dereferenceable | |
265 * @return the value | |
266 */ | |
267 inline ValueType &operator*() noexcept | |
268 { | |
269 assert((m_value.isArray() && m_ita != m_value.m_array.end()) || | |
270 (m_value.isObject() && m_itm != m_value.m_object.end())); | |
271 | |
272 return (m_value.m_type == Type::Object) ? m_itm->second : *m_ita; | |
273 } | |
274 | |
275 /** | |
276 * Dereference the iterator as a pointer. | |
277 * | |
278 * @pre iterator must be dereferenceable | |
279 * @return the value | |
280 */ | |
281 inline ValueType *operator->() noexcept | |
282 { | |
283 assert((m_value.isArray() && m_ita != m_value.m_array.end()) || | |
284 (m_value.isObject() && m_itm != m_value.m_object.end())); | |
285 | |
286 return (m_value.m_type == Type::Object) ? &m_itm->second : &(*m_ita); | |
287 } | |
288 | |
289 /** | |
290 * Increment the iterator. (Prefix version). | |
291 * | |
292 * @pre iterator must be dereferenceable | |
293 * @return *this; | |
294 */ | |
295 inline BaseIterator &operator++() noexcept | |
296 { | |
297 assert((m_value.isArray() && m_ita != m_value.m_array.end()) || | |
298 (m_value.isObject() && m_itm != m_value.m_object.end())); | |
299 | |
300 increment(); | |
301 | |
302 return *this; | |
303 } | |
304 | |
305 /** | |
306 * Increment the iterator. (Postfix version). | |
307 * | |
308 * @pre iterator must be dereferenceable | |
309 * @return *this; | |
310 */ | |
311 inline BaseIterator &operator++(int) noexcept | |
312 { | |
313 assert((m_value.isArray() && m_ita != m_value.m_array.end()) || | |
314 (m_value.isObject() && m_itm != m_value.m_object.end())); | |
315 | |
316 increment(); | |
317 | |
318 return *this; | |
319 } | |
320 | |
321 /** | |
322 * Compare two iterators. | |
323 * | |
324 * @param it1 the first iterator | |
325 * @param it2 the second iterator | |
326 * @return true if they are same | |
327 */ | |
328 bool operator==(const BaseIterator &it) const noexcept | |
329 { | |
330 if (m_value.isObject() && it.m_value.isObject()) | |
331 return m_itm == it.m_itm; | |
332 if (m_value.isArray() && it.m_value.isArray()) | |
333 return m_ita == it.m_ita; | |
334 | |
335 return false; | |
336 } | |
337 | |
338 /** | |
339 * Test if the iterator is different. | |
340 * | |
341 * @param it the iterator | |
342 * @return true if they are different | |
343 */ | |
344 inline bool operator!=(const BaseIterator &it) const noexcept | |
345 { | |
346 return !(*this == it); | |
347 } | |
348 }; | |
349 | |
350 public: | |
351 /** | |
352 * Forward iterator. | |
353 */ | |
354 using iterator = BaseIterator<Value, typename std::vector<Value>::iterator, typename std::map<std::string, Value>::iterator>; | |
355 | |
356 /** | |
357 * Const forward iterator. | |
358 */ | |
359 using const_iterator = BaseIterator<const Value, typename std::vector<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>; | |
360 | |
361 /** | |
362 * Construct a null value. | |
363 */ | |
364 inline Value() | |
365 { | |
366 } | |
367 | |
368 /** | |
369 * Create a value with a specified type, this is usually only needed when you want to create an object or | |
370 * an array. | |
371 * | |
372 * For any other types, initialize with sane default value. | |
373 * | |
374 * @param type the type | |
375 */ | |
376 Value(Type type); | |
377 | |
378 /** | |
379 * Construct a null value. | |
380 */ | |
381 inline Value(std::nullptr_t) noexcept | |
382 : m_type{Type::Null} | |
383 { | |
384 } | |
385 | |
386 /** | |
387 * Construct a boolean value. | |
388 * | |
389 * @param value the boolean value | |
390 */ | |
391 inline Value(bool value) noexcept | |
392 : m_type{Type::Boolean} | |
393 , m_boolean{value} | |
394 { | |
395 } | |
396 | |
397 /** | |
398 * Create value from integer. | |
399 * | |
400 * @param value the value | |
401 */ | |
402 inline Value(int value) noexcept | |
403 : m_type{Type::Int} | |
404 , m_integer{value} | |
405 { | |
406 } | |
407 | |
408 /** | |
409 * Construct a value from a C-string. | |
410 * | |
411 * @param value the C-string | |
412 */ | |
413 inline Value(const char *value) | |
414 : m_type{Type::String} | |
415 { | |
416 new (&m_string) std::string{value ? value : ""}; | |
417 } | |
418 | |
419 /** | |
420 * Construct a number value. | |
421 * | |
422 * @param value the real value | |
423 */ | |
424 inline Value(double value) noexcept | |
425 : m_type{Type::Real} | |
426 , m_number{value} | |
427 { | |
428 } | |
429 | |
430 /** | |
431 * Construct a string value. | |
432 * | |
433 * @param value the string | |
434 */ | |
435 inline Value(std::string value) noexcept | |
436 : m_type{Type::String} | |
437 { | |
438 new (&m_string) std::string{std::move(value)}; | |
439 } | |
440 | |
441 /** | |
442 * Create an object from a map. | |
443 * | |
444 * @param values the values | |
445 * @see fromObject | |
446 */ | |
447 inline Value(std::map<std::string, Value> values) | |
448 : Value{Type::Object} | |
449 { | |
450 for (const auto &pair : values) { | |
451 insert(pair.first, pair.second); | |
452 } | |
453 } | |
454 | |
455 /** | |
456 * Create an array from a vector. | |
457 * | |
458 * @param values the values | |
459 * @see fromArray | |
460 */ | |
461 inline Value(std::vector<Value> values) | |
462 : Value{Type::Array} | |
463 { | |
464 for (Value value : values) { | |
465 append(std::move(value)); | |
466 } | |
467 } | |
468 | |
469 /** | |
470 * Construct a value from a buffer. | |
471 * | |
472 * @param buffer the text | |
473 * @throw Error on errors | |
474 */ | |
475 Value(const Buffer &buffer); | |
476 | |
477 /** | |
478 * Construct a value from a file. | |
479 * | |
480 * @param file the file | |
481 * @throw Error on errors | |
482 */ | |
483 Value(const File &file); | |
484 | |
485 /** | |
486 * Move constructor. | |
487 * | |
488 * @param other the value to move from | |
489 */ | |
490 inline Value(Value &&other) | |
491 { | |
492 move(std::move(other)); | |
493 } | |
494 | |
495 /** | |
496 * Copy constructor. | |
497 * | |
498 * @param other the value to copy from | |
499 */ | |
500 inline Value(const Value &other) | |
501 { | |
502 copy(other); | |
503 } | |
504 | |
505 /** | |
506 * Copy operator. | |
507 * | |
508 * @param other the value to copy from | |
509 * @return *this | |
510 */ | |
511 inline Value &operator=(const Value &other) | |
512 { | |
513 copy(other); | |
514 | |
515 return *this; | |
516 } | |
517 | |
518 /** | |
519 * Move operator. | |
520 * | |
521 * @param other the value to move from | |
522 */ | |
523 inline Value &operator=(Value &&other) | |
524 { | |
525 move(std::move(other)); | |
526 | |
527 return *this; | |
528 } | |
529 | |
530 /** | |
531 * Destructor. | |
532 */ | |
533 ~Value(); | |
534 | |
535 /** | |
536 * Get an iterator to the beginning. | |
537 * | |
538 * @pre must be an array or object | |
539 * @return the iterator | |
540 */ | |
541 inline iterator begin() noexcept | |
542 { | |
543 assert(isArray() || isObject()); | |
544 | |
545 return m_type == Type::Object ? iterator(*this, m_object.begin()) : iterator(*this, m_array.begin()); | |
546 } | |
547 | |
548 /** | |
549 * Overloaded function. | |
550 * | |
551 * @pre must be an array or object | |
552 * @return the iterator | |
553 */ | |
554 inline const_iterator begin() const noexcept | |
555 { | |
556 assert(isArray() || isObject()); | |
557 | |
558 return m_type == Type::Object ? const_iterator(*this, m_object.begin()) : const_iterator(*this, m_array.begin()); | |
559 } | |
560 | |
561 /** | |
562 * Overloaded function. | |
563 * | |
564 * @pre must be an array or object | |
565 * @return the iterator | |
566 */ | |
567 inline const_iterator cbegin() const noexcept | |
568 { | |
569 assert(isArray() || isObject()); | |
570 | |
571 return m_type == Type::Object ? const_iterator(*this, m_object.cbegin()) : const_iterator(*this, m_array.cbegin()); | |
572 } | |
573 | |
574 /** | |
575 * Get an iterator to the end. | |
576 * | |
577 * @pre must be an array or object | |
578 * @return the iterator | |
579 */ | |
580 inline iterator end() noexcept | |
581 { | |
582 assert(isArray() || isObject()); | |
583 | |
584 return m_type == Type::Object ? iterator(*this, m_object.end()) : iterator(*this, m_array.end()); | |
585 } | |
586 | |
587 /** | |
588 * Get an iterator to the end. | |
589 * | |
590 * @pre must be an array or object | |
591 * @return the iterator | |
592 */ | |
593 inline const_iterator end() const noexcept | |
594 { | |
595 assert(isArray() || isObject()); | |
596 | |
597 return m_type == Type::Object ? const_iterator(*this, m_object.end()) : const_iterator(*this, m_array.end()); | |
598 } | |
599 | |
600 /** | |
601 * Get an iterator to the end. | |
602 * | |
603 * @pre must be an array or object | |
604 * @return the iterator | |
605 */ | |
606 inline const_iterator cend() const noexcept | |
607 { | |
608 assert(isArray() || isObject()); | |
609 | |
610 return m_type == Type::Object ? const_iterator(*this, m_object.cend()) : const_iterator(*this, m_array.cend()); | |
611 } | |
612 | |
613 /** | |
614 * Get the value type. | |
615 * | |
616 * @return the type | |
617 */ | |
618 inline Type typeOf() const noexcept | |
619 { | |
620 return m_type; | |
621 } | |
622 | |
623 /** | |
624 * Get the value as boolean. | |
625 * | |
626 * @return the value or false if not a boolean | |
627 */ | |
628 bool toBool() const noexcept; | |
629 | |
630 /** | |
631 * Get the value as integer. | |
632 * | |
633 * @return the value or 0 if not a integer | |
634 */ | |
635 int toInt() const noexcept; | |
636 | |
637 /** | |
638 * Get the value as real. | |
639 * | |
640 * @return the value or 0 if not a real | |
641 */ | |
642 double toReal() const noexcept; | |
643 | |
644 /** | |
645 * Get the value as string. | |
646 * | |
647 * @param coerce set to true to coerce the value if not a string | |
648 * @return the value or empty string if not a string | |
649 */ | |
650 std::string toString(bool coerce = false) const noexcept; | |
651 | |
652 /** | |
653 * Check if the value is boolean type. | |
654 * | |
655 * @return true if boolean | |
656 */ | |
657 inline bool isBool() const noexcept | |
658 { | |
659 return m_type == Type::Boolean; | |
660 } | |
661 | |
662 /** | |
663 * Check if the value is integer type. | |
664 * | |
665 * @return true if integer | |
666 */ | |
667 inline bool isInt() const noexcept | |
668 { | |
669 return m_type == Type::Int; | |
670 } | |
671 | |
672 /** | |
673 * Check if the value is object type. | |
674 * | |
675 * @return true if object | |
676 */ | |
677 inline bool isObject() const noexcept | |
678 { | |
679 return m_type == Type::Object; | |
680 } | |
681 | |
682 /** | |
683 * Check if the value is array type. | |
684 * | |
685 * @return true if array | |
686 */ | |
687 inline bool isArray() const noexcept | |
688 { | |
689 return m_type == Type::Array; | |
690 } | |
691 | |
692 /** | |
693 * Check if the value is integer or real type. | |
694 * | |
695 * @return true if integer or real | |
696 * @see toInt | |
697 * @see toReal | |
698 */ | |
699 inline bool isNumber() const noexcept | |
700 { | |
701 return m_type == Type::Real || m_type == Type::Int; | |
702 } | |
703 | |
704 /** | |
705 * Check if the value is real type. | |
706 * | |
707 * @return true if real | |
708 */ | |
709 inline bool isReal() const noexcept | |
710 { | |
711 return m_type == Type::Real; | |
712 } | |
713 | |
714 /** | |
715 * Check if the value is null type. | |
716 * | |
717 * @return true if null | |
718 */ | |
719 inline bool isNull() const noexcept | |
720 { | |
721 return m_type == Type::Null; | |
722 } | |
723 | |
724 /** | |
725 * Check if the value is string type. | |
726 * | |
727 * @return true if string | |
728 */ | |
729 inline bool isString() const noexcept | |
730 { | |
731 return m_type == Type::String; | |
732 } | |
733 | |
734 /** | |
735 * Get the array or object size. | |
736 * | |
737 * @pre must be an array or object | |
738 * @return the size | |
739 */ | |
740 inline unsigned size() const noexcept | |
741 { | |
742 assert(isArray() || isObject()); | |
743 | |
744 if (m_type == Type::Object) { | |
745 return m_object.size(); | |
746 } | |
747 | |
748 return m_array.size(); | |
749 } | |
750 | |
751 /** | |
752 * Remove all the values. | |
753 * | |
754 * @pre must be an array or an object | |
755 */ | |
756 inline void clear() noexcept | |
757 { | |
758 assert(isArray() || isObject()); | |
759 | |
760 if (m_type == Type::Array) { | |
761 m_array.clear(); | |
762 } else { | |
763 m_object.clear(); | |
764 } | |
765 } | |
766 | |
767 /* | |
768 * Array functions | |
769 * ---------------------------------------------------------- | |
770 */ | |
771 | |
772 /** | |
773 * Get the value at the specified position or the defaultValue if position is out of bounds. | |
774 * | |
775 * @param position the position | |
776 * @param defaultValue the value replacement | |
777 * @return the value or defaultValue | |
778 */ | |
779 template <typename DefaultValue> | |
780 inline Value valueOr(unsigned position, DefaultValue &&defaultValue) const | |
781 { | |
782 if (m_type != Type::Array || position >= m_array.size()) { | |
783 return defaultValue; | |
784 } | |
785 | |
786 return m_array[position]; | |
787 } | |
788 | |
789 /** | |
790 * Overloaded function with type check. | |
791 * | |
792 * @param position the position | |
793 * @param type the requested type | |
794 * @param defaultValue the value replacement | |
795 * @return the value or defaultValue | |
796 */ | |
797 template <typename DefaultValue> | |
798 inline Value valueOr(unsigned position, Type type, DefaultValue &&defaultValue) const | |
799 { | |
800 if (m_type != Type::Array || position >= m_array.size() || m_array[position].typeOf() != type) { | |
801 return defaultValue; | |
802 } | |
803 | |
804 return m_array[position]; | |
805 } | |
806 | |
807 /** | |
808 * Get a value at the specified index. | |
809 * | |
810 * @pre must be an array | |
811 * @param position the position | |
812 * @return the value | |
813 * @throw std::out_of_range if out of bounds | |
814 */ | |
815 inline const Value &at(unsigned position) const | |
816 { | |
817 assert(isArray()); | |
818 | |
819 return m_array.at(position); | |
820 } | |
821 | |
822 /** | |
823 * Overloaded function. | |
824 * | |
825 * @pre must be an array | |
826 * @param position the position | |
827 * @return the value | |
828 * @throw std::out_of_range if out of bounds | |
829 */ | |
830 inline Value &at(unsigned position) | |
831 { | |
832 assert(isArray()); | |
833 | |
834 return m_array.at(position); | |
835 } | |
836 | |
837 /** | |
838 * Get a value at the specified index. | |
839 * | |
840 * @pre must be an array | |
841 * @pre position must be valid | |
842 * @param position the position | |
843 * @return the value | |
844 */ | |
845 inline const Value &operator[](unsigned position) const | |
846 { | |
847 assert(isArray()); | |
848 assert(position < m_array.size()); | |
849 | |
850 return m_array[position]; | |
851 } | |
852 | |
853 /** | |
854 * Overloaded function. | |
855 * | |
856 * @pre must be an array | |
857 * @pre position must be valid | |
858 * @param position the position | |
859 * @return the value | |
860 */ | |
861 inline Value &operator[](unsigned position) | |
862 { | |
863 assert(isArray()); | |
864 assert(position < m_array.size()); | |
865 | |
866 return m_array[position]; | |
867 } | |
868 | |
869 /** | |
870 * Push a value to the beginning of the array. | |
871 * | |
872 * @pre must be an array | |
873 * @param value the value to push | |
874 */ | |
875 inline void push(const Value &value) | |
876 { | |
877 assert(isArray()); | |
878 | |
879 m_array.insert(m_array.begin(), value); | |
880 } | |
881 | |
882 /** | |
883 * Overloaded function. | |
884 * | |
885 * @pre must be an array | |
886 * @param value the value to push | |
887 */ | |
888 inline void push(Value &&value) | |
889 { | |
890 assert(isArray()); | |
891 | |
892 m_array.insert(m_array.begin(), std::move(value)); | |
893 } | |
894 | |
895 /** | |
896 * Insert a value at the specified position. | |
897 * | |
898 * @pre must be an array | |
899 * @pre position must be valid | |
900 * @param position the position | |
901 * @param value the value to push | |
902 */ | |
903 inline void insert(unsigned position, const Value &value) | |
904 { | |
905 assert(isArray()); | |
906 assert(position <= m_array.size()); | |
907 | |
908 m_array.insert(m_array.begin() + position, value); | |
909 } | |
910 | |
911 /** | |
912 * Overloaded function. | |
913 * | |
914 * @pre must be an array | |
915 * @pre position must be valid | |
916 * @param position the position | |
917 * @param value the value to push | |
918 */ | |
919 inline void insert(unsigned position, Value &&value) | |
920 { | |
921 assert(isArray()); | |
922 assert(position <= m_array.size()); | |
923 | |
924 m_array.insert(m_array.begin() + position, std::move(value)); | |
925 } | |
926 | |
927 /** | |
928 * Add a new value to the end. | |
929 * | |
930 * @pre must be an array | |
931 * @param value the value to append | |
932 */ | |
933 inline void append(const Value &value) | |
934 { | |
935 assert(isArray()); | |
936 | |
937 m_array.push_back(value); | |
938 } | |
939 | |
940 /** | |
941 * Overloaded function. | |
942 * | |
943 * @pre must be an array | |
944 * @param value the value to append | |
945 */ | |
946 inline void append(Value &&value) | |
947 { | |
948 assert(isArray()); | |
949 | |
950 m_array.push_back(std::move(value)); | |
951 } | |
952 | |
953 /** | |
954 * Remove a value at the specified position. | |
955 * | |
956 * @pre must be an array | |
957 * @pre position must be valid | |
958 * @param position the position | |
959 */ | |
960 inline void erase(unsigned position) | |
961 { | |
962 assert(isArray()); | |
963 assert(position < m_array.size()); | |
964 | |
965 m_array.erase(m_array.begin() + position); | |
966 } | |
967 | |
968 /* | |
969 * Object functions | |
970 * ---------------------------------------------------------- | |
971 */ | |
972 | |
973 /** | |
974 * Get the value at the specified key or the defaultValue if key is absent. | |
975 * | |
976 * @param name the name | |
977 * @param defaultValue the value replacement | |
978 * @return the value or defaultValue | |
979 */ | |
980 template <typename DefaultValue> | |
981 Value valueOr(const std::string &name, DefaultValue &&defaultValue) const | |
982 { | |
983 if (m_type != Type::Object) { | |
984 return defaultValue; | |
985 } | |
986 | |
987 auto it = m_object.find(name); | |
988 | |
989 if (it == m_object.end()) { | |
990 return defaultValue; | |
991 } | |
992 | |
993 return it->second; | |
994 } | |
995 | |
996 /** | |
997 * Overloaded function with type check. | |
998 * | |
999 * @param name the name | |
1000 * @param type the requested type | |
1001 * @param defaultValue the value replacement | |
1002 * @return the value or defaultValue | |
1003 */ | |
1004 template <typename DefaultValue> | |
1005 Value valueOr(const std::string &name, Type type, DefaultValue &&defaultValue) const | |
1006 { | |
1007 if (m_type != Type::Object) { | |
1008 return defaultValue; | |
1009 } | |
1010 | |
1011 auto it = m_object.find(name); | |
1012 | |
1013 if (it == m_object.end() || it->second.typeOf() != type) { | |
1014 return defaultValue; | |
1015 } | |
1016 | |
1017 return it->second; | |
1018 } | |
1019 | |
1020 /** | |
1021 * Get a value from the object. | |
1022 * | |
1023 * @pre must be an object | |
1024 * @param name the value key | |
1025 * @return the value | |
1026 * @throw std::out_of_range if not found | |
1027 */ | |
1028 inline const Value &at(const std::string &name) const | |
1029 { | |
1030 assert(isObject()); | |
1031 | |
1032 return m_object.at(name); | |
1033 } | |
1034 | |
1035 /** | |
1036 * Overloaded function. | |
1037 * | |
1038 * @pre must be an object | |
1039 * @param name the value key | |
1040 * @return the value | |
1041 * @throw std::out_of_range if not found | |
1042 */ | |
1043 inline Value &at(const std::string &name) | |
1044 { | |
1045 assert(isObject()); | |
1046 | |
1047 return m_object.at(name); | |
1048 } | |
1049 | |
1050 /** | |
1051 * Get a value from the object. | |
1052 * | |
1053 * @pre must be an object | |
1054 * @param name the value key | |
1055 * @return the value | |
1056 */ | |
1057 inline Value &operator[](const std::string &name) | |
1058 { | |
1059 assert(isObject()); | |
1060 | |
1061 return m_object[name]; | |
1062 } | |
1063 | |
1064 /** | |
1065 * Find a value by key. | |
1066 * | |
1067 * @pre must be an object | |
1068 * @param key the property key | |
1069 * @return the iterator or past the end if not found | |
1070 */ | |
1071 inline iterator find(const std::string &key) | |
1072 { | |
1073 assert(isObject()); | |
1074 | |
1075 return iterator(*this, m_object.find(key)); | |
1076 } | |
1077 | |
1078 /** | |
1079 * Overloaded function. | |
1080 * | |
1081 * @pre must be an object | |
1082 * @param key the property key | |
1083 * @return the iterator or past the end if not found | |
1084 */ | |
1085 inline const_iterator find(const std::string &key) const | |
1086 { | |
1087 assert(isObject()); | |
1088 | |
1089 return const_iterator(*this, m_object.find(key)); | |
1090 } | |
1091 | |
1092 /** | |
1093 * Insert a new value. | |
1094 * | |
1095 * @pre must be an object | |
1096 * @param name the key | |
1097 * @param value the value | |
1098 */ | |
1099 inline void insert(std::string name, const Value &value) | |
1100 { | |
1101 assert(isObject()); | |
1102 | |
1103 m_object.insert({std::move(name), value}); | |
1104 } | |
1105 | |
1106 /** | |
1107 * Overloaded function. | |
1108 * | |
1109 * @pre must be an object | |
1110 * @param name the key | |
1111 * @param value the value | |
1112 */ | |
1113 inline void insert(std::string name, Value &&value) | |
1114 { | |
1115 assert(isObject()); | |
1116 | |
1117 m_object.insert({std::move(name), std::move(value)}); | |
1118 } | |
1119 | |
1120 /** | |
1121 * Check if a value exists. | |
1122 * | |
1123 * @pre must be an object | |
1124 * @param key the key value | |
1125 * @return true if exists | |
1126 */ | |
1127 inline bool contains(const std::string &key) const noexcept | |
1128 { | |
1129 assert(isObject()); | |
1130 | |
1131 return m_object.find(key) != m_object.end(); | |
1132 } | |
1133 | |
1134 /** | |
1135 * Remove a value of the specified key. | |
1136 * | |
1137 * @pre must be an object | |
1138 * @param key the value key | |
1139 */ | |
1140 inline void erase(const std::string &key) | |
1141 { | |
1142 assert(isObject()); | |
1143 | |
1144 m_object.erase(key); | |
1145 } | |
1146 | |
1147 /** | |
1148 * Return this value as JSon representation. | |
1149 * | |
1150 * @param indent, the indentation to use (0 == compact, < 0 == tabs, > 0 == number of spaces) | |
1151 * @param tabs, use tabs or not | |
1152 * @return the string | |
1153 */ | |
1154 inline std::string toJson(int indent = 2) const | |
1155 { | |
1156 return toJson(indent, 0); | |
1157 } | |
1158 }; | |
1159 | |
1160 /** | |
1161 * Escape the input. | |
1162 * | |
1163 * @param input the input | |
1164 * @return the escaped string | |
1165 */ | |
1166 std::string escape(const std::string &input); | |
1167 | |
1168 /** | |
1169 * Convenient function for creating array from initializer list. | |
1170 * | |
1171 * @param values the values | |
1172 * @return the array | |
1173 */ | |
1174 inline Value array(std::initializer_list<Value> values) | |
1175 { | |
1176 return Value(std::vector<Value>(values.begin(), values.end())); | |
1177 } | |
1178 | |
1179 /** | |
1180 * Convenient function for creating object from initializer list. | |
1181 * | |
1182 * @param values the values | |
1183 * @return the object | |
1184 */ | |
1185 inline Value object(std::initializer_list<std::pair<std::string, Value>> values) | |
1186 { | |
1187 return Value(std::map<std::string, Value>(values.begin(), values.end())); | |
1188 } | |
1189 | |
1190 } // !json | |
1191 | |
1192 } // !irccd | |
1193 | |
1194 #endif // !_JSON_H_ |