This repository has been archived by the owner on Apr 25, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmkjson.hpp
370 lines (294 loc) · 9.79 KB
/
mkjson.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
// Part of Measurement Kit <https://measurement-kit.github.io/>.
// Measurement Kit is free software under the BSD license. See AUTHORS
// and LICENSE for more information on the copying conditions.
#ifndef MEASUREMENT_KIT_MKJSON_HPP
#define MEASUREMENT_KIT_MKJSON_HPP
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
namespace mk {
namespace json {
/// Result contains the result of an operation.
template <typename Type>
class Result {
public:
/// good indicates whether the operation succeeded.
bool good = true;
/// failure indicates why the operation failed.
std::string failure;
/// value is the result of a successful operation.
Type value = {};
};
// Result<void> is a template specialization for the void special case.
template <>
class Result<void> {
public:
bool good = true;
std::string failure;
};
/// JSON is a JSON value.
class JSON {
public:
/// parse parses @p json_str and returns the result.
static Result<JSON> parse(const std::string &json_str) noexcept;
/// dump serializes the JSON and returns the result.
Result<std::string> dump() const noexcept;
/// JSON creates a new null JSON.
JSON() noexcept;
/// JSON is not copy constructible.
JSON(const JSON &) = delete;
/// operator= is not allowed for copy operations.
JSON &operator=(const JSON &) = delete;
/// JSON is move constructible.
JSON(JSON &&) noexcept;
/// operator= is allowed for move operations.
JSON &operator=(JSON &&) noexcept;
/// is_array tells you whether the JSON is an array.
bool is_array() const noexcept;
/// is_boolean tells you whether the JSON is a boolean.
bool is_boolean() const noexcept;
/// is_float64 tells you whether the JSON is a float64.
bool is_float64() const noexcept;
/// is_int64 tells you whether the JSON is a int64.
bool is_int64() const noexcept;
/// is_null tells you whether the JSON is null.
bool is_null() const noexcept;
/// is_object tells you whether the JSON is an object.
bool is_object() const noexcept;
/// is_string tells you whether the JSON is a string.
bool is_string() const noexcept;
/// get_value_at assumes that the JSON is an object and removes the value
/// currently at @p key, returning it. This method has move semantics; after
/// it has successfully returned, no value will be at @p key anymore.
Result<JSON> get_value_at(const std::string &key) noexcept;
/// get_value_array assumes that the JSON is an array and returns such
/// array. This method has move semantics; after it successfully returns,
/// the JSON will become empty.
Result<std::vector<JSON>> get_value_array() noexcept;
/// get_value_boolean is like get_value_array but for boolean.
Result<bool> get_value_boolean() noexcept;
/// get_value_float64 is like get_value_array but for float64.
Result<double> get_value_float64() noexcept;
/// get_value_int64 is like get_value_array but for int64.
Result<int64_t> get_value_int64() noexcept;
/// get_value_string is like get_value_array but for string.
Result<std::string> get_value_string() noexcept;
/// set_value_at is the dual operation of get_value_at.
Result<void> set_value_at(const std::string &key, JSON &&value) noexcept;
/// set_value_array unconditionally sets the JSON value to be @p value. The
/// previous content of the JSON will be wiped.
void set_value_array(std::vector<JSON> &&value) noexcept;
/// set_value_float64 is like set_value_array but for float64.
void set_value_float64(double value) noexcept;
/// set_value_int64 is like set_value_array but for int64.
void set_value_int64(int64_t value) noexcept;
/// set_value_string is like set_value_array but for strings.
void set_value_string(std::string &&value) noexcept;
/// ~JSON destroys the allocated resources.
~JSON() noexcept;
// Friend is a forward declaration to a friend class.
class Friend;
// Friend is a friend of us.
friend class Friend;
private:
// Impl is a forward declaration to the internal implementation.
class Impl;
// JSON constructs an instance from an implementation.
explicit JSON(Impl &&other_impl) noexcept;
// impl is a unique pointer to the internal implementation.
std::unique_ptr<Impl> impl;
};
} // namespace json
} // namespace mk
// MKJSON_INLINE_IMPL allows to inline the implementation.
#ifdef MKJSON_INLINE_IMPL
#include <exception>
#include <type_traits>
#include <utility>
#include "json.hpp"
#include "mkdata.hpp"
namespace mk {
namespace json {
// JSON::Impl is the concrete implementation of JSON.
class JSON::Impl {
public:
// nlohmann_json is the underlying nlohmann/json instance.
nlohmann::json nlohmann_json;
// Impl constructs the implementation from an existing JSON.
explicit Impl(nlohmann::json &&value) noexcept;
// Impl constructs an empty implementation.
Impl() noexcept;
};
/*explicit*/ JSON::Impl::Impl(nlohmann::json &&value) noexcept {
std::swap(value, nlohmann_json);
}
JSON::Impl::Impl() noexcept {}
// JSON::Friend is the definition of the class friend of JSON.
class JSON::Friend {
public:
// unwrap allows to unwrap a JSON to get the inner nlohmann::json.
static nlohmann::json &unwrap(JSON &json) noexcept;
};
/*static*/ nlohmann::json &JSON::Friend::unwrap(JSON &json) noexcept {
return json.impl->nlohmann_json;
}
/*explicit*/ JSON::JSON(Impl &&other_impl) noexcept : JSON{} {
std::swap(other_impl, *impl);
}
/*static*/ Result<JSON> JSON::parse(const std::string &json_str) noexcept {
Result<JSON> result;
try {
result.value.impl->nlohmann_json = nlohmann::json::parse(json_str);
} catch (const std::exception &exc) {
result.good = false;
result.failure = exc.what();
}
return result;
}
Result<std::string> JSON::dump() const noexcept {
Result<std::string> result;
try {
result.value = impl->nlohmann_json.dump();
} catch (const std::exception &exc) {
result.good = false;
result.failure = exc.what();
}
return result;
}
JSON::JSON() noexcept { impl.reset(new JSON::Impl); }
JSON::JSON(JSON &&other) noexcept : JSON{} {
std::swap(impl, other.impl);
}
JSON &JSON::operator=(JSON &&other) noexcept {
std::swap(impl, other.impl);
return *this;
}
bool JSON::is_array() const noexcept {
return impl->nlohmann_json.is_array();
}
bool JSON::is_boolean() const noexcept {
return impl->nlohmann_json.is_boolean();
}
bool JSON::is_float64() const noexcept {
return impl->nlohmann_json.is_number_float();
}
bool JSON::is_int64() const noexcept {
return impl->nlohmann_json.is_number_integer();
}
bool JSON::is_null() const noexcept {
return impl->nlohmann_json.is_null();
}
bool JSON::is_object() const noexcept {
return impl->nlohmann_json.is_object();
}
bool JSON::is_string() const noexcept {
return impl->nlohmann_json.is_string();
}
Result<JSON> JSON::get_value_at(const std::string &key) noexcept {
Result<JSON> result;
try {
result.value.impl->nlohmann_json = std::move(impl->nlohmann_json.at(key));
impl->nlohmann_json.erase(key);
} catch (const std::exception &exc) {
result.good = false;
result.failure = exc.what();
}
return result;
}
Result<std::vector<JSON>> JSON::get_value_array() noexcept {
Result<std::vector<JSON>> result;
auto valuep = impl->nlohmann_json.get_ptr<std::vector<nlohmann::json> *>();
if (valuep == nullptr) {
result.good = false;
result.failure = "Not an array";
return result;
}
for (nlohmann::json &entry : *valuep) {
result.value.push_back(JSON{JSON::Impl{std::move(entry)}});
}
impl->nlohmann_json = nullptr;
return result;
}
Result<bool> JSON::get_value_boolean() noexcept {
Result<bool> result;
auto valuep = impl->nlohmann_json.get_ptr<bool *>();
if (valuep == nullptr) {
result.good = false;
result.failure = "Not a boolean";
return result;
}
result.value = *valuep;
impl->nlohmann_json = nullptr;
return result;
}
Result<double> JSON::get_value_float64() noexcept {
Result<double> result;
auto valuep = impl->nlohmann_json.get_ptr<double *>();
if (valuep == nullptr) {
result.good = false;
result.failure = "Not a float64";
return result;
}
result.value = *valuep;
impl->nlohmann_json = nullptr;
return result;
}
Result<int64_t> JSON::get_value_int64() noexcept {
Result<int64_t> result;
auto valuep = impl->nlohmann_json.get_ptr<int64_t *>();
if (valuep == nullptr) {
result.good = false;
result.failure = "Not an int64";
return result;
}
result.value = *valuep;
impl->nlohmann_json = nullptr;
return result;
}
Result<std::string> JSON::get_value_string() noexcept {
Result<std::string> result;
auto valuep = impl->nlohmann_json.get_ptr<std::string *>();
if (valuep == nullptr) {
result.good = false;
result.failure = "Not a string";
return result;
}
std::swap(result.value, *valuep);
impl->nlohmann_json = nullptr;
return result;
}
Result<void> JSON::set_value_at(const std::string &key, JSON &&value) noexcept {
Result<void> result;
try {
std::swap(value.impl->nlohmann_json, impl->nlohmann_json[key]);
} catch (const std::exception &exc) {
result.good = false;
result.failure = exc.what();
}
return result;
}
void JSON::set_value_array(std::vector<JSON> &&value) noexcept {
std::vector<nlohmann::json> array;
for (JSON &entry : value) {
array.push_back(std::move(entry.impl->nlohmann_json));
}
impl->nlohmann_json = std::move(array);
}
void JSON::set_value_float64(double value) noexcept {
impl->nlohmann_json = value;
}
void JSON::set_value_int64(int64_t value) noexcept {
impl->nlohmann_json = value;
}
void JSON::set_value_string(std::string &&value) noexcept {
if (!mk::data::contains_valid_utf8(value)) {
value = mk::data::base64_encode(std::move(value));
}
impl->nlohmann_json = std::move(value);
}
JSON::~JSON() noexcept {}
} // namespace json
} // namespace mk
#endif // MKJSON_INLINE_IMPL
#endif // MEASUREMENT_KIT_MKJSON_HPP