annotate C++/modules/Json/Json.cpp @ 405:f81478065901

Json: - Complete rewrite, - Convert jansson tree to own C++ tree, - Conversion from Value to Object/Array makes copies
author David Demelier <markand@malikania.fr>
date Mon, 05 Oct 2015 17:04:40 +0200
parents 9ab878fb9fa2
children d485d36a8de1
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
1 /*
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
2 * Json.cpp -- C++14 JSON manipulation using jansson parser
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
3 *
403
d5ec1174b707 Massive cleanup
David Demelier <markand@malikania.fr>
parents: 334
diff changeset
4 * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr>
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
5 *
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
6 * Permission to use, copy, modify, and/or distribute this software for any
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
7 * purpose with or without fee is hereby granted, provided that the above
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
8 * copyright notice and this permission notice appear in all copies.
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
9 *
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
17 */
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
18
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
19 #include "Json.h"
314
4c3019385769 Json: add iterators
David Demelier <markand@malikania.fr>
parents: 312
diff changeset
20
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
21 #include <jansson.h>
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
22
404
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
23 namespace json {
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
24
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
25 namespace {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
26
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
27 void readObject(Value &parent, json_t *object);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
28 void readArray(Value &parent, json_t *array);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
29
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
30 Value readValue(json_t *v)
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
31 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
32 if (json_is_null(v)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
33 return Value{nullptr};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
34 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
35 if (json_is_string(v)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
36 return Value{json_string_value(v)};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
37 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
38 if (json_is_number(v)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
39 return Value{json_number_value(v)};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
40 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
41 if (json_is_boolean(v)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
42 return Value{json_boolean_value(v)};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
43 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
44 if (json_is_object(v)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
45 Object object;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
46
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
47 readObject(object, v);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
48
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
49 return object;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
50 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
51 if (json_is_array(v)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
52 Array array;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
53
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
54 readArray(array, v);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
55
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
56 return array;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
57 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
58
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
59 return Value{};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
60 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
61
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
62 void readObject(Value &parent, json_t *object)
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
63 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
64 const char *key;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
65 json_t *value;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
66
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
67 json_object_foreach(object, key, value) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
68 static_cast<Object &>(parent).insert(key, readValue(value));
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
69 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
70 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
71
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
72 void readArray(Value &parent, json_t *array)
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
73 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
74 size_t index;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
75 json_t *value;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
76
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
77 json_array_foreach(array, index, value) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
78 static_cast<Array &>(parent).append(readValue(value));
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
79 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
80 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
81
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
82 template <typename Func, typename... Args>
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
83 Value convert(Func fn, Args&&... args)
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
84 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
85 json_error_t error;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
86 json_t *json = fn(std::forward<Args>(args)..., &error);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
87
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
88 if (json == nullptr) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
89 throw Error{error.text, error.source, error.line, error.column, error.position};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
90 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
91
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
92 Value value;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
93
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
94 if (json_is_object(json)) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
95 value = Object{};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
96 readObject(value, json);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
97 } else {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
98 value = Array{};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
99 readArray(value, json);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
100 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
101
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
102 json_decref(json);
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
103
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
104 return value;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
105 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
106
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
107 } // !namespace
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
108
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
109 bool Value::toBool() const noexcept
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
110 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
111 if (m_type != Type::Boolean)
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
112 return false;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
113
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
114 return m_boolean;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
115 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
116
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
117 double Value::toNumber() const noexcept
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
118 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
119 if (m_type != Type::Number)
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
120 return 0;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
121
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
122 return m_number;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
123 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
124
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
125 std::string Value::toString() const noexcept
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
126 {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
127 if (m_type != Type::String) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
128 return "";
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
129 }
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
130
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
131 return m_string;
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
132 }
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
133
404
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
134 Object Value::toObject() const noexcept
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
135 {
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
136 if (m_type != Type::Object) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
137 return Object{};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
138 }
311
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
139
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
140 return Object(*this);
311
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
141 }
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
142
404
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
143 Array Value::toArray() const noexcept
311
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
144 {
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
145 if (m_type != Type::Array) {
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
146 return Array{};
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
147 }
314
4c3019385769 Json: add iterators
David Demelier <markand@malikania.fr>
parents: 312
diff changeset
148
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
149 return Array(*this);
311
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
150 }
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
151
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
152 Document::Document(Buffer buffer)
311
David Demelier <markand@malikania.fr>
parents: 244
diff changeset
153 {
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
154 m_value = convert(json_loads, buffer.text.c_str(), 0);
244
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
155 }
777bc3cb665a Add Json, a jansson wrapper
David Demelier <markand@malikania.fr>
parents:
diff changeset
156
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
157 Document::Document(File file)
314
4c3019385769 Json: add iterators
David Demelier <markand@malikania.fr>
parents: 312
diff changeset
158 {
405
David Demelier <markand@malikania.fr>
parents: 404
diff changeset
159 m_value = convert(json_load_file, file.path.c_str(), 0);
404
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
160 }
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
161
9ab878fb9fa2 Json: bring classes into json namespace
David Demelier <markand@malikania.fr>
parents: 403
diff changeset
162 } // !json