Medial Code Documentation
Loading...
Searching...
No Matches
json.h
1
4#ifndef XGBOOST_JSON_H_
5#define XGBOOST_JSON_H_
6
8#include <xgboost/logging.h>
9#include <xgboost/parameter.h>
10#include <xgboost/string_view.h>
11
12#include <functional>
13#include <map>
14#include <memory>
15#include <string>
16#include <type_traits> // std::enable_if,std::enable_if_t
17#include <utility>
18#include <vector>
19
20namespace xgboost {
21
22class Json;
23class JsonReader;
24class JsonWriter;
25
26class Value {
27 private:
28 mutable class IntrusivePtrCell ref_;
29 friend IntrusivePtrCell &
30 IntrusivePtrRefCount(xgboost::Value const *t) noexcept {
31 return t->ref_;
32 }
33
34 public:
36 enum class ValueKind {
37 kString,
38 kNumber,
39 kInteger,
40 kObject, // std::map
41 kArray, // std::vector
42 kBoolean,
43 kNull,
44 // typed array for ubjson
45 kNumberArray,
46 kU8Array,
47 kI32Array,
48 kI64Array
49 };
50
51 explicit Value(ValueKind _kind) : kind_{_kind} {}
52
53 ValueKind Type() const { return kind_; }
54 virtual ~Value() = default;
55
56 virtual void Save(JsonWriter* writer) const = 0;
57
58 virtual Json& operator[](std::string const& key);
59 virtual Json& operator[](int ind);
60
61 virtual bool operator==(Value const& rhs) const = 0;
62#if !defined(__APPLE__)
63 virtual Value& operator=(Value const& rhs) = delete;
64#endif // !defined(__APPLE__)
65
66 std::string TypeStr() const;
67
68 private:
69 ValueKind kind_;
70};
71
72template <typename T>
73bool IsA(Value const* value) {
74 return T::IsClassOf(value);
75}
76
77template <typename T, typename U>
78T* Cast(U* value) {
79 if (IsA<T>(value)) {
80 return dynamic_cast<T*>(value);
81 } else {
82 LOG(FATAL) << "Invalid cast, from " + value->TypeStr() + " to " + T().TypeStr();
83 }
84 return dynamic_cast<T*>(value); // suppress compiler warning.
85}
86
87class JsonString : public Value {
88 std::string str_;
89
90 public:
91 JsonString() : Value(ValueKind::kString) {}
92 JsonString(std::string const& str) : // NOLINT
93 Value(ValueKind::kString), str_{str} {}
94 JsonString(std::string&& str) noexcept : // NOLINT
95 Value(ValueKind::kString), str_{std::forward<std::string>(str)} {}
96 JsonString(JsonString&& str) noexcept : Value(ValueKind::kString) { // NOLINT
97 std::swap(str.str_, this->str_);
98 }
99
100 void Save(JsonWriter* writer) const override;
101
102 std::string const& GetString() && { return str_; }
103 std::string const& GetString() const & { return str_; }
104 std::string& GetString() & { return str_; }
105
106 bool operator==(Value const& rhs) const override;
107
108 static bool IsClassOf(Value const* value) {
109 return value->Type() == ValueKind::kString;
110 }
111};
112
113class JsonArray : public Value {
114 std::vector<Json> vec_;
115
116 public:
117 JsonArray() : Value(ValueKind::kArray) {}
118 JsonArray(std::vector<Json>&& arr) noexcept // NOLINT
119 : Value(ValueKind::kArray), vec_{std::forward<std::vector<Json>>(arr)} {}
120 JsonArray(std::vector<Json> const& arr) : // NOLINT
121 Value(ValueKind::kArray), vec_{arr} {}
122 JsonArray(JsonArray const& that) = delete;
123 JsonArray(JsonArray && that) noexcept;
124
125 void Save(JsonWriter* writer) const override;
126
127 Json& operator[](int ind) override { return vec_.at(ind); }
128 // silent the partial oveeridden warning
129 Json& operator[](std::string const& key) override { return Value::operator[](key); }
130
131 std::vector<Json> const& GetArray() && { return vec_; }
132 std::vector<Json> const& GetArray() const & { return vec_; }
133 std::vector<Json>& GetArray() & { return vec_; }
134
135 bool operator==(Value const& rhs) const override;
136
137 static bool IsClassOf(Value const* value) {
138 return value->Type() == ValueKind::kArray;
139 }
140};
141
148template <typename T, Value::ValueKind kind>
149class JsonTypedArray : public Value {
150 std::vector<T> vec_;
151
152 public:
153 using Type = T;
154
155 JsonTypedArray() : Value(kind) {}
156 explicit JsonTypedArray(size_t n) : Value(kind) { vec_.resize(n); }
157 JsonTypedArray(JsonTypedArray&& that) noexcept : Value{kind}, vec_{std::move(that.vec_)} {}
158
159 bool operator==(Value const& rhs) const override;
160
161 void Set(size_t i, T v) { vec_[i] = v; }
162 size_t Size() const { return vec_.size(); }
163
164 void Save(JsonWriter* writer) const override;
165
166 std::vector<T> const& GetArray() && { return vec_; }
167 std::vector<T> const& GetArray() const& { return vec_; }
168 std::vector<T>& GetArray() & { return vec_; }
169
170 static bool IsClassOf(Value const* value) { return value->Type() == kind; }
171};
172
189
190class JsonObject : public Value {
191 public:
192 using Map = std::map<std::string, Json, std::less<>>;
193
194 private:
195 Map object_;
196
197 public:
198 JsonObject() : Value(ValueKind::kObject) {}
199 JsonObject(Map&& object) noexcept; // NOLINT
200 JsonObject(JsonObject const& that) = delete;
201 JsonObject(JsonObject&& that) noexcept;
202
203 void Save(JsonWriter* writer) const override;
204
205 // silent the partial oveeridden warning
206 Json& operator[](int ind) override { return Value::operator[](ind); }
207 Json& operator[](std::string const& key) override { return object_[key]; }
208
209 Map const& GetObject() && { return object_; }
210 Map const& GetObject() const& { return object_; }
211 Map& GetObject() & { return object_; }
212
213 bool operator==(Value const& rhs) const override;
214
215 static bool IsClassOf(Value const* value) { return value->Type() == ValueKind::kObject; }
216 ~JsonObject() override = default;
217};
218
219class JsonNumber : public Value {
220 public:
221 using Float = float;
222
223 private:
224 Float number_ { 0 };
225
226 public:
227 JsonNumber() : Value(ValueKind::kNumber) {}
228 template <typename FloatT,
229 typename std::enable_if<std::is_same<FloatT, Float>::value>::type* = nullptr>
230 JsonNumber(FloatT value) : Value(ValueKind::kNumber) { // NOLINT
231 number_ = value;
232 }
233 template <typename FloatT,
234 typename std::enable_if<std::is_same<FloatT, double>::value>::type* = nullptr>
235 JsonNumber(FloatT value) : Value{ValueKind::kNumber}, // NOLINT
236 number_{static_cast<Float>(value)} {}
237 JsonNumber(JsonNumber const& that) = delete;
238 JsonNumber(JsonNumber&& that) noexcept : Value{ValueKind::kNumber}, number_{that.number_} {}
239
240 void Save(JsonWriter* writer) const override;
241
242 Float const& GetNumber() && { return number_; }
243 Float const& GetNumber() const & { return number_; }
244 Float& GetNumber() & { return number_; }
245
246 bool operator==(Value const& rhs) const override;
247
248 static bool IsClassOf(Value const* value) {
249 return value->Type() == ValueKind::kNumber;
250 }
251};
252
253class JsonInteger : public Value {
254 public:
255 using Int = int64_t;
256
257 private:
258 Int integer_ {0};
259
260 public:
261 JsonInteger() : Value(ValueKind::kInteger) {} // NOLINT
262 template <typename IntT,
263 typename std::enable_if<std::is_same<IntT, Int>::value>::type* = nullptr>
264 JsonInteger(IntT value) : Value(ValueKind::kInteger), integer_{value} {} // NOLINT
265 template <typename IntT,
266 typename std::enable_if<std::is_same<IntT, size_t>::value>::type* = nullptr>
267 JsonInteger(IntT value) : Value(ValueKind::kInteger), // NOLINT
268 integer_{static_cast<Int>(value)} {}
269 template <typename IntT,
270 typename std::enable_if<std::is_same<IntT, int32_t>::value>::type* = nullptr>
271 JsonInteger(IntT value) : Value(ValueKind::kInteger), // NOLINT
272 integer_{static_cast<Int>(value)} {}
273 template <typename IntT,
274 typename std::enable_if<
275 std::is_same<IntT, uint32_t>::value &&
276 !std::is_same<std::size_t, uint32_t>::value>::type * = nullptr>
277 JsonInteger(IntT value) // NOLINT
278 : Value(ValueKind::kInteger),
279 integer_{static_cast<Int>(value)} {}
280
281 JsonInteger(JsonInteger &&that) noexcept
282 : Value{ValueKind::kInteger}, integer_{that.integer_} {}
283
284 bool operator==(Value const& rhs) const override;
285
286 Int const& GetInteger() && { return integer_; }
287 Int const& GetInteger() const & { return integer_; }
288 Int& GetInteger() & { return integer_; }
289 void Save(JsonWriter* writer) const override;
290
291 static bool IsClassOf(Value const* value) {
292 return value->Type() == ValueKind::kInteger;
293 }
294};
295
296class JsonNull : public Value {
297 public:
298 JsonNull() : Value(ValueKind::kNull) {}
299 JsonNull(std::nullptr_t) : Value(ValueKind::kNull) {} // NOLINT
300 JsonNull(JsonNull&&) noexcept : Value(ValueKind::kNull) {}
301
302 void Save(JsonWriter* writer) const override;
303
304 bool operator==(Value const& rhs) const override;
305
306 static bool IsClassOf(Value const* value) {
307 return value->Type() == ValueKind::kNull;
308 }
309};
310
312class JsonBoolean : public Value {
313 bool boolean_ = false;
314
315 public:
316 JsonBoolean() : Value(ValueKind::kBoolean) {} // NOLINT
317 // Ambigious with JsonNumber.
318 template <typename Bool,
319 typename std::enable_if<
320 std::is_same<Bool, bool>::value ||
321 std::is_same<Bool, bool const>::value>::type* = nullptr>
322 JsonBoolean(Bool value) : // NOLINT
323 Value(ValueKind::kBoolean), boolean_{value} {}
324 JsonBoolean(JsonBoolean&& value) noexcept: // NOLINT
325 Value(ValueKind::kBoolean), boolean_{value.boolean_} {}
326
327 void Save(JsonWriter* writer) const override;
328
329 bool const& GetBoolean() && { return boolean_; }
330 bool const& GetBoolean() const & { return boolean_; }
331 bool& GetBoolean() & { return boolean_; }
332
333 bool operator==(Value const& rhs) const override;
334
335 static bool IsClassOf(Value const* value) {
336 return value->Type() == ValueKind::kBoolean;
337 }
338};
339
357class Json {
358 public:
363 static Json Load(StringView str, std::ios::openmode mode = std::ios::in);
365 static Json Load(JsonReader* reader);
370 static void Dump(Json json, std::string* out, std::ios::openmode mode = std::ios::out);
371 static void Dump(Json json, std::vector<char>* out, std::ios::openmode mode = std::ios::out);
373 static void Dump(Json json, JsonWriter* writer);
374
375 Json() = default;
376
377 // number
378 explicit Json(JsonNumber number) : ptr_{new JsonNumber(std::move(number))} {}
379 Json& operator=(JsonNumber number) {
380 ptr_.reset(new JsonNumber(std::move(number)));
381 return *this;
382 }
383 // integer
384 explicit Json(JsonInteger integer) : ptr_{new JsonInteger(std::move(integer))} {}
385 Json& operator=(JsonInteger integer) {
386 ptr_.reset(new JsonInteger(std::move(integer)));
387 return *this;
388 }
389 // array
390 explicit Json(JsonArray&& list) : ptr_{new JsonArray(std::forward<JsonArray>(list))} {}
391 Json& operator=(JsonArray&& array) {
392 ptr_.reset(new JsonArray(std::forward<JsonArray>(array)));
393 return *this;
394 }
395 // typed array
396 template <typename T, Value::ValueKind kind>
397 explicit Json(JsonTypedArray<T, kind>&& list)
398 : ptr_{new JsonTypedArray<T, kind>(std::forward<JsonTypedArray<T, kind>>(list))} {}
399 template <typename T, Value::ValueKind kind>
400 Json& operator=(JsonTypedArray<T, kind>&& array) {
401 ptr_.reset(new JsonTypedArray<T, kind>(std::forward<JsonTypedArray<T, kind>>(array)));
402 return *this;
403 }
404 // object
405 explicit Json(JsonObject&& object) : ptr_{new JsonObject(std::forward<JsonObject>(object))} {}
406 Json& operator=(JsonObject&& object) {
407 ptr_.reset(new JsonObject(std::forward<JsonObject>(object)));
408 return *this;
409 }
410 // string
411 explicit Json(JsonString&& str) : ptr_{new JsonString(std::forward<JsonString>(str))} {}
412 Json& operator=(JsonString&& str) {
413 ptr_.reset(new JsonString(std::forward<JsonString>(str)));
414 return *this;
415 }
416 // bool
417 explicit Json(JsonBoolean boolean) :
418 ptr_{new JsonBoolean(std::move(boolean))} {}
419 Json& operator=(JsonBoolean boolean) {
420 ptr_.reset(new JsonBoolean(std::move(boolean)));
421 return *this;
422 }
423 // null
424 explicit Json(JsonNull null) :
425 ptr_{new JsonNull(std::move(null))} {}
426 Json& operator=(JsonNull null) {
427 ptr_.reset(new JsonNull(std::move(null)));
428 return *this;
429 }
430
431 // copy
432 Json(Json const& other) = default;
433 Json& operator=(Json const& other) = default;
434 // move
435 Json(Json &&other) noexcept { std::swap(this->ptr_, other.ptr_); }
436 Json &operator=(Json &&other) noexcept {
437 std::swap(this->ptr_, other.ptr_);
438 return *this;
439 }
440
442 Json& operator[](std::string const & key) const { return (*ptr_)[key]; }
444 Json& operator[](int ind) const { return (*ptr_)[ind]; }
445
447 Value const& GetValue() const & { return *ptr_; }
448 Value const& GetValue() && { return *ptr_; }
449 Value& GetValue() & { return *ptr_; }
450
451 bool operator==(Json const& rhs) const {
452 return *ptr_ == *(rhs.ptr_);
453 }
454
455 friend std::ostream& operator<<(std::ostream& os, Json const& j) {
456 std::string str;
457 Json::Dump(j, &str);
458 os << str;
459 return os;
460 }
461
462 IntrusivePtr<Value> const& Ptr() const { return ptr_; }
463
464 private:
465 IntrusivePtr<Value> ptr_{new JsonNull};
466};
467
477template <typename T>
478bool IsA(Json const& j) {
479 auto const& v = j.GetValue();
480 return IsA<T>(&v);
481}
482
483namespace detail {
484// Number
485template <typename T,
486 typename std::enable_if<
487 std::is_same<T, JsonNumber>::value>::type* = nullptr>
488JsonNumber::Float& GetImpl(T& val) { // NOLINT
489 return val.GetNumber();
490}
491template <typename T,
492 typename std::enable_if<
493 std::is_same<T, JsonNumber const>::value>::type* = nullptr>
494JsonNumber::Float const& GetImpl(T& val) { // NOLINT
495 return val.GetNumber();
496}
497
498// Integer
499template <typename T,
500 typename std::enable_if<
501 std::is_same<T, JsonInteger>::value>::type* = nullptr>
502JsonInteger::Int& GetImpl(T& val) { // NOLINT
503 return val.GetInteger();
504}
505template <typename T,
506 typename std::enable_if<
507 std::is_same<T, JsonInteger const>::value>::type* = nullptr>
508JsonInteger::Int const& GetImpl(T& val) { // NOLINT
509 return val.GetInteger();
510}
511
512// String
513template <typename T,
514 typename std::enable_if<
515 std::is_same<T, JsonString>::value>::type* = nullptr>
516std::string& GetImpl(T& val) { // NOLINT
517 return val.GetString();
518}
519template <typename T,
520 typename std::enable_if<
521 std::is_same<T, JsonString const>::value>::type* = nullptr>
522std::string const& GetImpl(T& val) { // NOLINT
523 return val.GetString();
524}
525
526// Boolean
527template <typename T,
528 typename std::enable_if<
529 std::is_same<T, JsonBoolean>::value>::type* = nullptr>
530bool& GetImpl(T& val) { // NOLINT
531 return val.GetBoolean();
532}
533template <typename T,
534 typename std::enable_if<
535 std::is_same<T, JsonBoolean const>::value>::type* = nullptr>
536bool const& GetImpl(T& val) { // NOLINT
537 return val.GetBoolean();
538}
539
540// Array
541template <typename T,
542 typename std::enable_if<
543 std::is_same<T, JsonArray>::value>::type* = nullptr>
544std::vector<Json>& GetImpl(T& val) { // NOLINT
545 return val.GetArray();
546}
547template <typename T,
548 typename std::enable_if<
549 std::is_same<T, JsonArray const>::value>::type* = nullptr>
550std::vector<Json> const& GetImpl(T& val) { // NOLINT
551 return val.GetArray();
552}
553
554// Typed Array
555template <typename T, Value::ValueKind kind>
556std::vector<T>& GetImpl(JsonTypedArray<T, kind>& val) { // NOLINT
557 return val.GetArray();
558}
559template <typename T, Value::ValueKind kind>
560std::vector<T> const& GetImpl(JsonTypedArray<T, kind> const& val) {
561 return val.GetArray();
562}
563
564// Object
565template <typename T, typename std::enable_if<std::is_same<T, JsonObject>::value>::type* = nullptr>
566JsonObject::Map& GetImpl(T& val) { // NOLINT
567 return val.GetObject();
568}
569template <typename T,
570 typename std::enable_if<std::is_same<T, JsonObject const>::value>::type* = nullptr>
571JsonObject::Map const& GetImpl(T& val) { // NOLINT
572 return val.GetObject();
573}
574} // namespace detail
575
584template <typename T, typename U>
585auto get(U& json) -> decltype(detail::GetImpl(*Cast<T>(&json.GetValue())))& { // NOLINT
586 auto& value = *Cast<T>(&json.GetValue());
587 return detail::GetImpl(value);
588}
589
590using Object = JsonObject;
591using Array = JsonArray;
592using Number = JsonNumber;
593using Integer = JsonInteger;
594using Boolean = JsonBoolean;
595using String = JsonString;
596using Null = JsonNull;
597
598// Utils tailored for XGBoost.
599namespace detail {
600template <typename Head>
601bool TypeCheckImpl(Json const& value) {
602 return IsA<Head>(value);
603}
604
605template <typename Head, typename... JT>
606std::enable_if_t<sizeof...(JT) != 0, bool> TypeCheckImpl(Json const& value) {
607 return IsA<Head>(value) || TypeCheckImpl<JT...>(value);
608}
609
610template <typename Head>
611std::string TypeCheckError() {
612 return "`" + Head{}.TypeStr() + "`";
613}
614
615template <typename Head, typename... JT>
616std::enable_if_t<sizeof...(JT) != 0, std::string> TypeCheckError() {
617 return "`" + Head{}.TypeStr() + "`, " + TypeCheckError<JT...>();
618}
619} // namespace detail
620
627template <typename... JT>
628void TypeCheck(Json const& value, StringView name) {
629 if (!detail::TypeCheckImpl<JT...>(value)) {
630 LOG(FATAL) << "Invalid type for: `" << name << "`, expecting one of the: {`"
631 << detail::TypeCheckError<JT...>() << "}, got: `" << value.GetValue().TypeStr()
632 << "`";
633 }
634}
635
645template <typename Parameter>
646Object ToJson(Parameter const& param) {
647 Object obj;
648 for (auto const& kv : param.__DICT__()) {
649 obj[kv.first] = kv.second;
650 }
651 return obj;
652}
653
664template <typename Parameter>
665Args FromJson(Json const& obj, Parameter* param) {
666 auto const& j_param = get<Object const>(obj);
667 Args args;
668 for (auto const& kv : j_param) {
669 args.emplace_back(kv.first, get<String const>(kv.second));
670 }
671 return param->UpdateAllowUnknown(args);
672}
673} // namespace xgboost
674#endif // XGBOOST_JSON_H_
Helper class for embedding reference counting into client objects. See https://www....
Definition intrusive_ptr.h:20
Definition json.h:113
Describes both true and false.
Definition json.h:312
Definition json.h:253
Definition json.h:296
Definition json.h:219
Definition json.h:190
A json reader, currently error checking and utf-8 is not fully supported.
Definition json_io.h:23
Definition json.h:87
Typed array for Universal Binary JSON.
Definition json.h:149
Definition json_io.h:113
Data structure representing JSON format.
Definition json.h:357
Json & operator[](int ind) const
Index Json object with int, used for Json Array.
Definition json.h:444
static Json Load(StringView str, std::ios::openmode mode=std::ios::in)
Decode the JSON object.
Definition json.cc:652
Json & operator[](std::string const &key) const
Index Json object with a std::string, used for Json Object.
Definition json.h:442
static void Dump(Json json, std::string *out, std::ios::openmode mode=std::ios::out)
Encode the JSON object.
Definition json.cc:669
Value const & GetValue() const &
Return the reference to stored Json value.
Definition json.h:447
Definition json.h:26
ValueKind
Simplified implementation of LLVM RTTI.
Definition json.h:36
defines console logging options for xgboost. Use to enforce unified print behavior.
macro for using C++11 enum class as DMLC parameter
Implementation of Intrusive Ptr.
detail namespace with internal helper functions
Definition json.hpp:249
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:24418
namespace of xgboost
Definition base.h:90
void TypeCheck(Json const &value, StringView name)
Type check for JSON-based parameters.
Definition json.h:628
auto get(U &json) -> decltype(detail::GetImpl(*Cast< T >(&json.GetValue())))&
Get Json value.
Definition json.h:585
Object ToJson(Parameter const &param)
Convert XGBoost parameter to JSON object.
Definition json.h:646
Args FromJson(Json const &obj, Parameter *param)
Load a XGBoost parameter from a JSON object.
Definition json.h:665
Definition string_view.h:15