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_