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 #include <string>
10 
11 #include <map>
12 #include <memory>
13 #include <vector>
14 #include <functional>
15 #include <utility>
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  String,
28  Number,
29  Integer,
30  Object, // std::map
31  Array, // std::vector
32  Boolean,
33  Null
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::String), str_{str} {}
76  JsonString(std::string&& str) : // NOLINT
77  Value(ValueKind::String), 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::String;
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::Array), vec_{std::move(arr)} {}
103  JsonArray(std::vector<Json> const& arr) : // NOLINT
104  Value(ValueKind::Array), 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::Array;
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::Object;
148  }
149  virtual ~JsonObject() = default;
150 };
151 
152 class JsonNumber : public Value {
153  public:
154  using Float = float;
155 
156  private:
157  Float number_;
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::Number) { // 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::Number}, // 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::Number;
186  }
187 };
188 
189 class JsonInteger : public Value {
190  public:
191  using Int = int64_t;
192 
193  private:
194  Int integer_;
195 
196  public:
197  JsonInteger() : Value(ValueKind::Integer), integer_{0} {} // NOLINT
198  template <typename IntT,
199  typename std::enable_if<std::is_same<IntT, Int>::value>::type* = nullptr>
200  JsonInteger(IntT value) : Value(ValueKind::Integer), 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::Integer), // 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::Integer), // 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
214  : Value(ValueKind::Integer),
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::Integer;
230  }
231 };
232 
233 class JsonNull : public Value {
234  public:
236  JsonNull(std::nullptr_t) : Value(ValueKind::Null) {} // 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::Null;
248  }
249 };
250 
252 class JsonBoolean : public Value {
253  bool boolean_;
254 
255  public:
256  JsonBoolean() : Value(ValueKind::Boolean) {} // 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::Boolean), 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::Boolean;
279  }
280 };
281 
282 struct StringView {
283  using CharT = char; // unsigned char
284  CharT const* str_;
285  size_t size_;
286 
287  public:
288  StringView() = default;
289  StringView(CharT const* str, size_t size) : str_{str}, size_{size} {}
290 
291  CharT const& operator[](size_t p) const { return str_[p]; }
292  CharT const& at(size_t p) const { // NOLINT
293  CHECK_LT(p, size_);
294  return str_[p];
295  }
296  size_t size() const { return size_; } // NOLINT
297  // Copies a portion of string. Since we don't have std::from_chars and friends here, so
298  // copying substring is necessary for appending `\0`. It's not too bad since string by
299  // default has small vector optimization, which is enabled by most if not all modern
300  // compilers for numeric values.
301  std::string substr(size_t beg, size_t n) const { // NOLINT
302  CHECK_LE(beg, size_);
303  return std::string {str_ + beg, n < (size_ - beg) ? n : (size_ - beg)};
304  }
305  char const* c_str() const { return str_; } // NOLINT
306 };
307 
325 class Json {
326  friend JsonWriter;
327 
328  public:
330  static Json Load(StringView str);
332  static Json Load(JsonReader* reader);
334  static void Dump(Json json, std::ostream* stream,
335  bool pretty = ConsoleLogger::ShouldLog(
336  ConsoleLogger::LogVerbosity::kDebug));
337  static void Dump(Json json, std::string* out,
338  bool pretty = ConsoleLogger::ShouldLog(
339  ConsoleLogger::LogVerbosity::kDebug));
340 
341  Json() : ptr_{new JsonNull} {}
342 
343  // number
344  explicit Json(JsonNumber number) : ptr_{new JsonNumber(number)} {}
346  ptr_.reset(new JsonNumber(std::move(number)));
347  return *this;
348  }
349 
350  // integer
351  explicit Json(JsonInteger integer) : ptr_{new JsonInteger(integer)} {}
353  ptr_.reset(new JsonInteger(std::move(integer)));
354  return *this;
355  }
356 
357  // array
358  explicit Json(JsonArray list) :
359  ptr_ {new JsonArray(std::move(list))} {}
361  ptr_.reset(new JsonArray(std::move(array)));
362  return *this;
363  }
364 
365  // object
366  explicit Json(JsonObject object) :
367  ptr_{new JsonObject(std::move(object))} {}
369  ptr_.reset(new JsonObject(std::move(object)));
370  return *this;
371  }
372  // string
373  explicit Json(JsonString str) :
374  ptr_{new JsonString(std::move(str))} {}
376  ptr_.reset(new JsonString(std::move(str)));
377  return *this;
378  }
379  // bool
380  explicit Json(JsonBoolean boolean) :
381  ptr_{new JsonBoolean(std::move(boolean))} {}
383  ptr_.reset(new JsonBoolean(std::move(boolean)));
384  return *this;
385  }
386  // null
387  explicit Json(JsonNull null) :
388  ptr_{new JsonNull(std::move(null))} {}
390  ptr_.reset(new JsonNull(std::move(null)));
391  return *this;
392  }
393 
394  // copy
395  Json(Json const& other) : ptr_{other.ptr_} {}
396  Json& operator=(Json const& other);
397  // move
398  Json(Json&& other) : ptr_{std::move(other.ptr_)} {}
399  Json& operator=(Json&& other) {
400  ptr_ = std::move(other.ptr_);
401  return *this;
402  }
403 
405  Json& operator[](std::string const & key) const { return (*ptr_)[key]; }
407  Json& operator[](int ind) const { return (*ptr_)[ind]; }
408 
410  Value const& GetValue() const & { return *ptr_; }
411  Value const& GetValue() && { return *ptr_; }
412  Value& GetValue() & { return *ptr_; }
413 
414  bool operator==(Json const& rhs) const {
415  return *ptr_ == *(rhs.ptr_);
416  }
417 
418  friend std::ostream& operator<<(std::ostream& os, Json const& j) {
419  std::string str;
420  Json::Dump(j, &str);
421  os << str;
422  return os;
423  }
424 
425  private:
426  std::shared_ptr<Value> ptr_;
427 };
428 
429 template <typename T>
430 bool IsA(Json const j) {
431  auto const& v = j.GetValue();
432  return IsA<T>(&v);
433 }
434 
435 namespace detail {
436 
437 // Number
438 template <typename T,
439  typename std::enable_if<
440  std::is_same<T, JsonNumber>::value>::type* = nullptr>
441 JsonNumber::Float& GetImpl(T& val) { // NOLINT
442  return val.getNumber();
443 }
444 template <typename T,
445  typename std::enable_if<
446  std::is_same<T, JsonNumber const>::value>::type* = nullptr>
447 JsonNumber::Float const& GetImpl(T& val) { // NOLINT
448  return val.getNumber();
449 }
450 
451 // Integer
452 template <typename T,
453  typename std::enable_if<
454  std::is_same<T, JsonInteger>::value>::type* = nullptr>
455 JsonInteger::Int& GetImpl(T& val) { // NOLINT
456  return val.getInteger();
457 }
458 template <typename T,
459  typename std::enable_if<
460  std::is_same<T, JsonInteger const>::value>::type* = nullptr>
461 JsonInteger::Int const& GetImpl(T& val) { // NOLINT
462  return val.getInteger();
463 }
464 
465 // String
466 template <typename T,
467  typename std::enable_if<
468  std::is_same<T, JsonString>::value>::type* = nullptr>
469 std::string& GetImpl(T& val) { // NOLINT
470  return val.getString();
471 }
472 template <typename T,
473  typename std::enable_if<
474  std::is_same<T, JsonString const>::value>::type* = nullptr>
475 std::string const& GetImpl(T& val) { // NOLINT
476  return val.getString();
477 }
478 
479 // Boolean
480 template <typename T,
481  typename std::enable_if<
482  std::is_same<T, JsonBoolean>::value>::type* = nullptr>
483 bool& GetImpl(T& val) { // NOLINT
484  return val.getBoolean();
485 }
486 template <typename T,
487  typename std::enable_if<
488  std::is_same<T, JsonBoolean const>::value>::type* = nullptr>
489 bool const& GetImpl(T& val) { // NOLINT
490  return val.getBoolean();
491 }
492 
493 // Array
494 template <typename T,
495  typename std::enable_if<
496  std::is_same<T, JsonArray>::value>::type* = nullptr>
497 std::vector<Json>& GetImpl(T& val) { // NOLINT
498  return val.getArray();
499 }
500 template <typename T,
501  typename std::enable_if<
502  std::is_same<T, JsonArray const>::value>::type* = nullptr>
503 std::vector<Json> const& GetImpl(T& val) { // NOLINT
504  return val.getArray();
505 }
506 
507 // Object
508 template <typename T,
509  typename std::enable_if<
510  std::is_same<T, JsonObject>::value>::type* = nullptr>
511 std::map<std::string, Json>& GetImpl(T& val) { // NOLINT
512  return val.getObject();
513 }
514 template <typename T,
515  typename std::enable_if<
516  std::is_same<T, JsonObject const>::value>::type* = nullptr>
517 std::map<std::string, Json> const& GetImpl(T& val) { // NOLINT
518  return val.getObject();
519 }
520 
521 } // namespace detail
522 
531 template <typename T, typename U>
532 auto get(U& json) -> decltype(detail::GetImpl(*Cast<T>(&json.GetValue())))& { // NOLINT
533  auto& value = *Cast<T>(&json.GetValue());
534  return detail::GetImpl(value);
535 }
536 
538 using Array = JsonArray;
543 using Null = JsonNull;
544 
545 // Utils tailored for XGBoost.
546 
547 template <typename Parameter>
548 Object toJson(Parameter const& param) {
549  Object obj;
550  for (auto const& kv : param.__DICT__()) {
551  obj[kv.first] = kv.second;
552  }
553  return obj;
554 }
555 
556 template <typename Parameter>
557 void fromJson(Json const& obj, Parameter* param) {
558  auto const& j_param = get<Object const>(obj);
559  std::map<std::string, std::string> m;
560  for (auto const& kv : j_param) {
561  m[kv.first] = get<String const>(kv.second);
562  }
563  param->UpdateAllowUnknown(m);
564 }
565 } // namespace xgboost
566 #endif // XGBOOST_JSON_H_
JsonInteger(IntT value)
Definition: json.h:200
virtual void Save(JsonWriter *writer)=0
int64_t Int
Definition: json.h:191
Definition: json.h:23
std::map< std::string, Json > & getObject() &
Definition: json.h:141
bool IsA(Value const *value)
Definition: json.h:56
std::map< std::string, Json > const & getObject() const &
Definition: json.h:140
Value const & GetValue() const &
Definition: json.h:410
JsonNumber::Float & GetImpl(T &val)
Definition: json.h:441
std::map< std::string, Json > const & getObject() &&
Definition: json.h:139
Value(ValueKind _kind)
Definition: json.h:36
bool const & getBoolean() &&
Definition: json.h:270
JsonString(std::string const &str)
Definition: json.h:74
static bool isClassOf(Value const *value)
Definition: json.h:228
std::vector< Json > const & getArray() const &
Definition: json.h:114
JsonBoolean()
Definition: json.h:256
Json & operator=(JsonInteger integer)
Definition: json.h:352
static bool isClassOf(Value const *value)
Definition: json.h:91
StringView(CharT const *str, size_t size)
Definition: json.h:289
std::vector< Json > const & getArray() &&
Definition: json.h:113
CharT const & at(size_t p) const
Definition: json.h:292
friend std::ostream & operator<<(std::ostream &os, Json const &j)
Definition: json.h:418
static bool isClassOf(Value const *value)
Definition: json.h:277
CharT const & operator[](size_t p) const
Definition: json.h:291
JsonNull(std::nullptr_t)
Definition: json.h:236
JsonArray(std::vector< Json > const &arr)
Definition: json.h:103
std::string const & getString() const &
Definition: json.h:85
Describes both true and false.
Definition: json.h:252
std::vector< Json > & getArray() &
Definition: json.h:115
size_t size_
Definition: json.h:285
std::string substr(size_t beg, size_t n) const
Definition: json.h:301
Definition: json.h:233
Int const & getInteger() const &
Definition: json.h:224
ValueKind Type() const
Definition: json.h:38
Json & operator=(JsonArray array)
Definition: json.h:360
Int & getInteger() &
Definition: json.h:225
JsonArray()
Definition: json.h:100
Json & operator[](int ind) const
Index Json object with int, used for Json Array.
Definition: json.h:407
JsonBoolean(Bool value)
Definition: json.h:262
JsonNull()
Definition: json.h:235
Definition: json_io.h:35
std::map< std::string, Json > const & GetImpl(T &val)
Definition: json.h:517
Float const & getNumber() &&
Definition: json.h:176
void fromJson(Json const &obj, Parameter *param)
Definition: json.h:557
T * Cast(U *value)
Definition: json.h:61
static bool isClassOf(Value const *value)
Definition: json.h:146
Json(JsonInteger integer)
Definition: json.h:351
char CharT
Definition: json.h:283
Definition: json.h:96
Object toJson(Parameter const &param)
Definition: json.h:548
JsonInteger()
Definition: json.h:197
Float & getNumber() &
Definition: json.h:178
bool const & getBoolean() const &
Definition: json.h:271
Json & operator=(JsonString str)
Definition: json.h:375
Value const & GetValue() &&
Definition: json.h:411
Json & operator=(JsonNumber number)
Definition: json.h:345
size_t size() const
Definition: json.h:296
float Float
Definition: json.h:154
Json & operator=(JsonNull null)
Definition: json.h:389
Json(Json &&other)
Definition: json.h:398
virtual bool operator==(Value const &rhs) const =0
std::string const & getString() &&
Definition: json.h:84
JsonString(std::string &&str)
Definition: json.h:76
ValueKind
Simplified implementation of LLVM RTTI.
Definition: json.h:26
Definition: json.h:189
CharT const * str_
Definition: json.h:284
Json(JsonString str)
Definition: json.h:373
Json()
Definition: json.h:341
namespace of xgboost
Definition: base.h:102
Json(JsonArray list)
Definition: json.h:358
Json(Json const &other)
Definition: json.h:395
Float const & getNumber() const &
Definition: json.h:177
JsonArray(std::vector< Json > &&arr)
Definition: json.h:101
Int const & getInteger() &&
Definition: json.h:223
virtual ~Value()=default
Definition: json.h:125
Json(JsonObject object)
Definition: json.h:366
Value & GetValue() &
Definition: json.h:412
std::string & getString() &
Definition: json.h:86
Definition: json.h:70
Json & operator=(Json &&other)
Definition: json.h:399
JsonObject()
Definition: json.h:129
bool operator==(Json const &rhs) const
Definition: json.h:414
Definition: json_io.h:119
std::string TypeStr() const
Definition: json.h:282
virtual Json & operator[](std::string const &key)=0
Data structure representing JSON format.
Definition: json.h:325
Json & operator[](std::string const &key) const
Index Json object with a std::string, used for Json Object.
Definition: json.h:405
static bool isClassOf(Value const *value)
Definition: json.h:120
char const * c_str() const
Definition: json.h:305
Json & operator=(JsonBoolean boolean)
Definition: json.h:382
JsonNumber(FloatT value)
Definition: json.h:163
static void Dump(Json json, std::ostream *stream, bool pretty=ConsoleLogger::ShouldLog(ConsoleLogger::LogVerbosity::kDebug))
Dump json into stream.
JsonNumber()
Definition: json.h:160
Json(JsonNull null)
Definition: json.h:387
Definition: json.h:152
Json & operator=(JsonObject object)
Definition: json.h:368
bool & getBoolean() &
Definition: json.h:272
Json(JsonNumber number)
Definition: json.h:344
static bool isClassOf(Value const *value)
Definition: json.h:246
JsonString()
Definition: json.h:73
Json(JsonBoolean boolean)
Definition: json.h:380
static bool isClassOf(Value const *value)
Definition: json.h:184
virtual Value & operator=(Value const &rhs)=0