xgboost
json.h
Go to the documentation of this file.
1 
4 #ifndef XGBOOST_JSON_H_
5 #define XGBOOST_JSON_H_
6 
7 #include <xgboost/logging.h>
8 #include <xgboost/parameter.h>
9 
10 #include <map>
11 #include <memory>
12 #include <vector>
13 #include <functional>
14 #include <utility>
15 #include <string>
16 
17 namespace xgboost {
18 
19 class Json;
20 class JsonReader;
21 class JsonWriter;
22 
23 class Value {
24  public:
26  enum class ValueKind {
27  kString,
28  kNumber,
29  kInteger,
30  kObject, // std::map
31  kArray, // std::vector
32  kBoolean,
33  kNull
34  };
35 
36  explicit Value(ValueKind _kind) : kind_{_kind} {}
37 
38  ValueKind Type() const { return kind_; }
39  virtual ~Value() = default;
40 
41  virtual void Save(JsonWriter* writer) = 0;
42 
43  virtual Json& operator[](std::string const & key) = 0;
44  virtual Json& operator[](int ind) = 0;
45 
46  virtual bool operator==(Value const& rhs) const = 0;
47  virtual Value& operator=(Value const& rhs) = 0;
48 
49  std::string TypeStr() const;
50 
51  private:
52  ValueKind kind_;
53 };
54 
55 template <typename T>
56 bool IsA(Value const* value) {
57  return T::IsClassOf(value);
58 }
59 
60 template <typename T, typename U>
61 T* Cast(U* value) {
62  if (IsA<T>(value)) {
63  return dynamic_cast<T*>(value);
64  } else {
65  LOG(FATAL) << "Invalid cast, from " + value->TypeStr() + " to " + T().TypeStr();
66  }
67  return dynamic_cast<T*>(value); // supress compiler warning.
68 }
69 
70 class JsonString : public Value {
71  std::string str_;
72  public:
74  JsonString(std::string const& str) : // NOLINT
75  Value(ValueKind::kString), str_{str} {}
76  JsonString(std::string&& str) : // NOLINT
77  Value(ValueKind::kString), str_{std::move(str)} {}
78 
79  void Save(JsonWriter* writer) override;
80 
81  Json& operator[](std::string const & key) override;
82  Json& operator[](int ind) override;
83 
84  std::string const& GetString() && { return str_; }
85  std::string const& GetString() const & { return str_; }
86  std::string& GetString() & { return str_; }
87 
88  bool operator==(Value const& rhs) const override;
89  Value& operator=(Value const& rhs) override;
90 
91  static bool IsClassOf(Value const* value) {
92  return value->Type() == ValueKind::kString;
93  }
94 };
95 
96 class JsonArray : public Value {
97  std::vector<Json> vec_;
98 
99  public:
101  JsonArray(std::vector<Json>&& arr) : // NOLINT
102  Value(ValueKind::kArray), vec_{std::move(arr)} {}
103  JsonArray(std::vector<Json> const& arr) : // NOLINT
104  Value(ValueKind::kArray), vec_{arr} {}
105  JsonArray(JsonArray const& that) = delete;
106  JsonArray(JsonArray && that);
107 
108  void Save(JsonWriter* writer) override;
109 
110  Json& operator[](std::string const & key) override;
111  Json& operator[](int ind) override;
112 
113  std::vector<Json> const& GetArray() && { return vec_; }
114  std::vector<Json> const& GetArray() const & { return vec_; }
115  std::vector<Json>& GetArray() & { return vec_; }
116 
117  bool operator==(Value const& rhs) const override;
118  Value& operator=(Value const& rhs) override;
119 
120  static bool IsClassOf(Value const* value) {
121  return value->Type() == ValueKind::kArray;
122  }
123 };
124 
125 class JsonObject : public Value {
126  std::map<std::string, Json> object_;
127 
128  public:
130  JsonObject(std::map<std::string, Json>&& object); // NOLINT
131  JsonObject(JsonObject const& that) = delete;
132  JsonObject(JsonObject && that);
133 
134  void Save(JsonWriter* writer) override;
135 
136  Json& operator[](std::string const & key) override;
137  Json& operator[](int ind) override;
138 
139  std::map<std::string, Json> const& GetObject() && { return object_; }
140  std::map<std::string, Json> const& GetObject() const & { return object_; }
141  std::map<std::string, Json> & GetObject() & { return object_; }
142 
143  bool operator==(Value const& rhs) const override;
144  Value& operator=(Value const& rhs) override;
145 
146  static bool IsClassOf(Value const* value) {
147  return value->Type() == ValueKind::kObject;
148  }
149  ~JsonObject() override = default;
150 };
151 
152 class JsonNumber : public Value {
153  public:
154  using Float = float;
155 
156  private:
157  Float number_ { 0 };
158 
159  public:
161  template <typename FloatT,
162  typename std::enable_if<std::is_same<FloatT, Float>::value>::type* = nullptr>
163  JsonNumber(FloatT value) : Value(ValueKind::kNumber) { // NOLINT
164  number_ = value;
165  }
166  template <typename FloatT,
167  typename std::enable_if<std::is_same<FloatT, double>::value>::type* = nullptr>
168  JsonNumber(FloatT value) : Value{ValueKind::kNumber}, // NOLINT
169  number_{static_cast<Float>(value)} {}
170 
171  void Save(JsonWriter* writer) override;
172 
173  Json& operator[](std::string const & key) override;
174  Json& operator[](int ind) override;
175 
176  Float const& GetNumber() && { return number_; }
177  Float const& GetNumber() const & { return number_; }
178  Float& GetNumber() & { return number_; }
179 
180 
181  bool operator==(Value const& rhs) const override;
182  Value& operator=(Value const& rhs) override;
183 
184  static bool IsClassOf(Value const* value) {
185  return value->Type() == ValueKind::kNumber;
186  }
187 };
188 
189 class JsonInteger : public Value {
190  public:
191  using Int = int64_t;
192 
193  private:
194  Int integer_ {0};
195 
196  public:
197  JsonInteger() : Value(ValueKind::kInteger) {} // NOLINT
198  template <typename IntT,
199  typename std::enable_if<std::is_same<IntT, Int>::value>::type* = nullptr>
200  JsonInteger(IntT value) : Value(ValueKind::kInteger), integer_{value} {} // NOLINT
201  template <typename IntT,
202  typename std::enable_if<std::is_same<IntT, size_t>::value>::type* = nullptr>
203  JsonInteger(IntT value) : Value(ValueKind::kInteger), // NOLINT
204  integer_{static_cast<Int>(value)} {}
205  template <typename IntT,
206  typename std::enable_if<std::is_same<IntT, int32_t>::value>::type* = nullptr>
207  JsonInteger(IntT value) : Value(ValueKind::kInteger), // NOLINT
208  integer_{static_cast<Int>(value)} {}
209  template <typename IntT,
210  typename std::enable_if<
211  std::is_same<IntT, uint32_t>::value &&
212  !std::is_same<std::size_t, uint32_t>::value>::type * = nullptr>
213  JsonInteger(IntT value) // NOLINT
215  integer_{static_cast<Int>(value)} {}
216 
217  Json& operator[](std::string const & key) override;
218  Json& operator[](int ind) override;
219 
220  bool operator==(Value const& rhs) const override;
221  Value& operator=(Value const& rhs) override;
222 
223  Int const& GetInteger() && { return integer_; }
224  Int const& GetInteger() const & { return integer_; }
225  Int& GetInteger() & { return integer_; }
226  void Save(JsonWriter* writer) override;
227 
228  static bool IsClassOf(Value const* value) {
229  return value->Type() == ValueKind::kInteger;
230  }
231 };
232 
233 class JsonNull : public Value {
234  public:
236  JsonNull(std::nullptr_t) : Value(ValueKind::kNull) {} // NOLINT
237 
238  void Save(JsonWriter* writer) override;
239 
240  Json& operator[](std::string const & key) override;
241  Json& operator[](int ind) override;
242 
243  bool operator==(Value const& rhs) const override;
244  Value& operator=(Value const& rhs) override;
245 
246  static bool IsClassOf(Value const* value) {
247  return value->Type() == ValueKind::kNull;
248  }
249 };
250 
252 class JsonBoolean : public Value {
253  bool boolean_;
254 
255  public:
256  JsonBoolean() : Value(ValueKind::kBoolean) {} // NOLINT
257  // Ambigious with JsonNumber.
258  template <typename Bool,
259  typename std::enable_if<
260  std::is_same<Bool, bool>::value ||
261  std::is_same<Bool, bool const>::value>::type* = nullptr>
262  JsonBoolean(Bool value) : // NOLINT
263  Value(ValueKind::kBoolean), boolean_{value} {}
264 
265  void Save(JsonWriter* writer) override;
266 
267  Json& operator[](std::string const & key) override;
268  Json& operator[](int ind) override;
269 
270  bool const& GetBoolean() && { return boolean_; }
271  bool const& GetBoolean() const & { return boolean_; }
272  bool& GetBoolean() & { return boolean_; }
273 
274  bool operator==(Value const& rhs) const override;
275  Value& operator=(Value const& rhs) override;
276 
277  static bool IsClassOf(Value const* value) {
278  return value->Type() == ValueKind::kBoolean;
279  }
280 };
281 
282 struct StringView {
283  private:
284  using CharT = char; // unsigned char
285  CharT const* str_;
286  size_t size_;
287 
288  public:
289  StringView() = default;
290  StringView(CharT const* str, size_t size) : str_{str}, size_{size} {}
291 
292  CharT const& operator[](size_t p) const { return str_[p]; }
293  CharT const& at(size_t p) const { // NOLINT
294  CHECK_LT(p, size_);
295  return str_[p];
296  }
297  size_t size() const { return size_; } // NOLINT
298  // Copies a portion of string. Since we don't have std::from_chars and friends here, so
299  // copying substring is necessary for appending `\0`. It's not too bad since string by
300  // default has small vector optimization, which is enabled by most if not all modern
301  // compilers for numeric values.
302  std::string substr(size_t beg, size_t n) const { // NOLINT
303  CHECK_LE(beg, size_);
304  return std::string {str_ + beg, n < (size_ - beg) ? n : (size_ - beg)};
305  }
306  char const* c_str() const { return str_; } // NOLINT
307 };
308 
326 class Json {
327  friend JsonWriter;
328 
329  public:
331  static Json Load(StringView str);
333  static Json Load(JsonReader* reader);
334  static void Dump(Json json, std::string* out);
335 
336  Json() : ptr_{new JsonNull} {}
337 
338  // number
339  explicit Json(JsonNumber number) : ptr_{new JsonNumber(number)} {}
341  ptr_.reset(new JsonNumber(std::move(number)));
342  return *this;
343  }
344 
345  // integer
346  explicit Json(JsonInteger integer) : ptr_{new JsonInteger(integer)} {}
348  ptr_.reset(new JsonInteger(std::move(integer)));
349  return *this;
350  }
351 
352  // array
353  explicit Json(JsonArray list) :
354  ptr_ {new JsonArray(std::move(list))} {}
356  ptr_.reset(new JsonArray(std::move(array)));
357  return *this;
358  }
359 
360  // object
361  explicit Json(JsonObject object) :
362  ptr_{new JsonObject(std::move(object))} {}
364  ptr_.reset(new JsonObject(std::move(object)));
365  return *this;
366  }
367  // string
368  explicit Json(JsonString str) :
369  ptr_{new JsonString(std::move(str))} {}
371  ptr_.reset(new JsonString(std::move(str)));
372  return *this;
373  }
374  // bool
375  explicit Json(JsonBoolean boolean) :
376  ptr_{new JsonBoolean(std::move(boolean))} {}
378  ptr_.reset(new JsonBoolean(std::move(boolean)));
379  return *this;
380  }
381  // null
382  explicit Json(JsonNull null) :
383  ptr_{new JsonNull(std::move(null))} {}
385  ptr_.reset(new JsonNull(std::move(null)));
386  return *this;
387  }
388 
389  // copy
390  Json(Json const& other) = default;
391  Json& operator=(Json const& other);
392  // move
393  Json(Json&& other) : ptr_{std::move(other.ptr_)} {}
394  Json& operator=(Json&& other) {
395  ptr_ = std::move(other.ptr_);
396  return *this;
397  }
398 
400  Json& operator[](std::string const & key) const { return (*ptr_)[key]; }
402  Json& operator[](int ind) const { return (*ptr_)[ind]; }
403 
405  Value const& GetValue() const & { return *ptr_; }
406  Value const& GetValue() && { return *ptr_; }
407  Value& GetValue() & { return *ptr_; }
408 
409  bool operator==(Json const& rhs) const {
410  return *ptr_ == *(rhs.ptr_);
411  }
412 
413  friend std::ostream& operator<<(std::ostream& os, Json const& j) {
414  std::string str;
415  Json::Dump(j, &str);
416  os << str;
417  return os;
418  }
419 
420  private:
421  std::shared_ptr<Value> ptr_;
422 };
423 
424 template <typename T>
425 bool IsA(Json const j) {
426  auto const& v = j.GetValue();
427  return IsA<T>(&v);
428 }
429 
430 namespace detail {
431 
432 // Number
433 template <typename T,
434  typename std::enable_if<
435  std::is_same<T, JsonNumber>::value>::type* = nullptr>
436 JsonNumber::Float& GetImpl(T& val) { // NOLINT
437  return val.GetNumber();
438 }
439 template <typename T,
440  typename std::enable_if<
441  std::is_same<T, JsonNumber const>::value>::type* = nullptr>
442 JsonNumber::Float const& GetImpl(T& val) { // NOLINT
443  return val.GetNumber();
444 }
445 
446 // Integer
447 template <typename T,
448  typename std::enable_if<
449  std::is_same<T, JsonInteger>::value>::type* = nullptr>
450 JsonInteger::Int& GetImpl(T& val) { // NOLINT
451  return val.GetInteger();
452 }
453 template <typename T,
454  typename std::enable_if<
455  std::is_same<T, JsonInteger const>::value>::type* = nullptr>
456 JsonInteger::Int const& GetImpl(T& val) { // NOLINT
457  return val.GetInteger();
458 }
459 
460 // String
461 template <typename T,
462  typename std::enable_if<
463  std::is_same<T, JsonString>::value>::type* = nullptr>
464 std::string& GetImpl(T& val) { // NOLINT
465  return val.GetString();
466 }
467 template <typename T,
468  typename std::enable_if<
469  std::is_same<T, JsonString const>::value>::type* = nullptr>
470 std::string const& GetImpl(T& val) { // NOLINT
471  return val.GetString();
472 }
473 
474 // Boolean
475 template <typename T,
476  typename std::enable_if<
477  std::is_same<T, JsonBoolean>::value>::type* = nullptr>
478 bool& GetImpl(T& val) { // NOLINT
479  return val.GetBoolean();
480 }
481 template <typename T,
482  typename std::enable_if<
483  std::is_same<T, JsonBoolean const>::value>::type* = nullptr>
484 bool const& GetImpl(T& val) { // NOLINT
485  return val.GetBoolean();
486 }
487 
488 // Array
489 template <typename T,
490  typename std::enable_if<
491  std::is_same<T, JsonArray>::value>::type* = nullptr>
492 std::vector<Json>& GetImpl(T& val) { // NOLINT
493  return val.GetArray();
494 }
495 template <typename T,
496  typename std::enable_if<
497  std::is_same<T, JsonArray const>::value>::type* = nullptr>
498 std::vector<Json> const& GetImpl(T& val) { // NOLINT
499  return val.GetArray();
500 }
501 
502 // Object
503 template <typename T,
504  typename std::enable_if<
505  std::is_same<T, JsonObject>::value>::type* = nullptr>
506 std::map<std::string, Json>& GetImpl(T& val) { // NOLINT
507  return val.GetObject();
508 }
509 template <typename T,
510  typename std::enable_if<
511  std::is_same<T, JsonObject const>::value>::type* = nullptr>
512 std::map<std::string, Json> const& GetImpl(T& val) { // NOLINT
513  return val.GetObject();
514 }
515 
516 } // namespace detail
517 
526 template <typename T, typename U>
527 auto get(U& json) -> decltype(detail::GetImpl(*Cast<T>(&json.GetValue())))& { // NOLINT
528  auto& value = *Cast<T>(&json.GetValue());
529  return detail::GetImpl(value);
530 }
531 
533 using Array = JsonArray;
538 using Null = JsonNull;
539 
540 // Utils tailored for XGBoost.
541 
542 template <typename Parameter>
543 Object ToJson(Parameter const& param) {
544  Object obj;
545  for (auto const& kv : param.__DICT__()) {
546  obj[kv.first] = kv.second;
547  }
548  return obj;
549 }
550 
551 template <typename Parameter>
552 void FromJson(Json const& obj, Parameter* param) {
553  auto const& j_param = get<Object const>(obj);
554  std::map<std::string, std::string> m;
555  for (auto const& kv : j_param) {
556  m[kv.first] = get<String const>(kv.second);
557  }
558  param->UpdateAllowUnknown(m);
559 }
560 } // namespace xgboost
561 #endif // XGBOOST_JSON_H_
JsonInteger(IntT value)
Definition: json.h:200
Int const & GetInteger() const &
Definition: json.h:224
void FromJson(Json const &obj, Parameter *param)
Definition: json.h:552
virtual void Save(JsonWriter *writer)=0
Int const & GetInteger() &&
Definition: json.h:223
bool const & GetBoolean() &&
Definition: json.h:270
int64_t Int
Definition: json.h:191
Definition: json.h:23
bool IsA(Value const *value)
Definition: json.h:56
Value const & GetValue() const &
Return the reference to stored Json value.
Definition: json.h:405
JsonNumber::Float & GetImpl(T &val)
Definition: json.h:436
Value(ValueKind _kind)
Definition: json.h:36
JsonString(std::string const &str)
Definition: json.h:74
JsonBoolean()
Definition: json.h:256
Json & operator=(JsonInteger integer)
Definition: json.h:347
StringView(CharT const *str, size_t size)
Definition: json.h:290
Float & GetNumber() &
Definition: json.h:178
CharT const & at(size_t p) const
Definition: json.h:293
friend std::ostream & operator<<(std::ostream &os, Json const &j)
Definition: json.h:413
CharT const & operator[](size_t p) const
Definition: json.h:292
JsonNull(std::nullptr_t)
Definition: json.h:236
JsonArray(std::vector< Json > const &arr)
Definition: json.h:103
Describes both true and false.
Definition: json.h:252
Int & GetInteger() &
Definition: json.h:225
std::map< std::string, Json > & GetObject() &
Definition: json.h:141
std::string substr(size_t beg, size_t n) const
Definition: json.h:302
Definition: json.h:233
ValueKind Type() const
Definition: json.h:38
Json & operator=(JsonArray array)
Definition: json.h:355
static bool IsClassOf(Value const *value)
Definition: json.h:246
JsonArray()
Definition: json.h:100
Json & operator[](int ind) const
Index Json object with int, used for Json Array.
Definition: json.h:402
static bool IsClassOf(Value const *value)
Definition: json.h:146
JsonBoolean(Bool value)
Definition: json.h:262
static bool IsClassOf(Value const *value)
Definition: json.h:277
JsonNull()
Definition: json.h:235
Definition: json_io.h:23
std::map< std::string, Json > const & GetImpl(T &val)
Definition: json.h:512
T * Cast(U *value)
Definition: json.h:61
std::string const & GetString() &&
Definition: json.h:84
Json(JsonInteger integer)
Definition: json.h:346
Definition: json.h:96
static void Dump(Json json, std::string *out)
JsonInteger()
Definition: json.h:197
Json & operator=(JsonString str)
Definition: json.h:370
Value const & GetValue() &&
Definition: json.h:406
Json & operator=(JsonNumber number)
Definition: json.h:340
size_t size() const
Definition: json.h:297
float Float
Definition: json.h:154
static bool IsClassOf(Value const *value)
Definition: json.h:91
Json & operator=(JsonNull null)
Definition: json.h:384
std::map< std::string, Json > const & GetObject() &&
Definition: json.h:139
Json(Json &&other)
Definition: json.h:393
virtual bool operator==(Value const &rhs) const =0
JsonString(std::string &&str)
Definition: json.h:76
static bool IsClassOf(Value const *value)
Definition: json.h:120
ValueKind
Simplified implementation of LLVM RTTI.
Definition: json.h:26
bool & GetBoolean() &
Definition: json.h:272
Definition: json.h:189
Json(JsonString str)
Definition: json.h:368
Json()
Definition: json.h:336
namespace of xgboost
Definition: base.h:102
Json(JsonArray list)
Definition: json.h:353
std::vector< Json > const & GetArray() &&
Definition: json.h:113
std::string & GetString() &
Definition: json.h:86
Float const & GetNumber() &&
Definition: json.h:176
JsonArray(std::vector< Json > &&arr)
Definition: json.h:101
virtual ~Value()=default
Definition: json.h:125
std::map< std::string, Json > const & GetObject() const &
Definition: json.h:140
Json(JsonObject object)
Definition: json.h:361
Value & GetValue() &
Definition: json.h:407
Definition: json.h:70
std::vector< Json > const & GetArray() const &
Definition: json.h:114
Json & operator=(Json &&other)
Definition: json.h:394
JsonObject()
Definition: json.h:129
static bool IsClassOf(Value const *value)
Definition: json.h:184
bool operator==(Json const &rhs) const
Definition: json.h:409
Definition: json_io.h:115
std::string TypeStr() const
Definition: json.h:282
virtual Json & operator[](std::string const &key)=0
Data structure representing JSON format.
Definition: json.h:326
Json & operator[](std::string const &key) const
Index Json object with a std::string, used for Json Object.
Definition: json.h:400
char const * c_str() const
Definition: json.h:306
Json & operator=(JsonBoolean boolean)
Definition: json.h:377
JsonNumber(FloatT value)
Definition: json.h:163
JsonNumber()
Definition: json.h:160
Json(JsonNull null)
Definition: json.h:382
Definition: json.h:152
Json & operator=(JsonObject object)
Definition: json.h:363
Float const & GetNumber() const &
Definition: json.h:177
bool const & GetBoolean() const &
Definition: json.h:271
Json(JsonNumber number)
Definition: json.h:339
Object ToJson(Parameter const &param)
Definition: json.h:543
static bool IsClassOf(Value const *value)
Definition: json.h:228
std::string const & GetString() const &
Definition: json.h:85
macro for using C++11 enum class as DMLC parameter
JsonString()
Definition: json.h:73
Json(JsonBoolean boolean)
Definition: json.h:375
std::vector< Json > & GetArray() &
Definition: json.h:115
virtual Value & operator=(Value const &rhs)=0