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  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);
335  static void Dump(Json json, std::ostream* stream,
336  bool pretty = ConsoleLogger::ShouldLog(
337  ConsoleLogger::LogVerbosity::kDebug));
338  static void Dump(Json json, std::string* out,
339  bool pretty = ConsoleLogger::ShouldLog(
340  ConsoleLogger::LogVerbosity::kDebug));
341 
342  Json() : ptr_{new JsonNull} {}
343 
344  // number
345  explicit Json(JsonNumber number) : ptr_{new JsonNumber(number)} {}
347  ptr_.reset(new JsonNumber(std::move(number)));
348  return *this;
349  }
350 
351  // integer
352  explicit Json(JsonInteger integer) : ptr_{new JsonInteger(integer)} {}
354  ptr_.reset(new JsonInteger(std::move(integer)));
355  return *this;
356  }
357 
358  // array
359  explicit Json(JsonArray list) :
360  ptr_ {new JsonArray(std::move(list))} {}
362  ptr_.reset(new JsonArray(std::move(array)));
363  return *this;
364  }
365 
366  // object
367  explicit Json(JsonObject object) :
368  ptr_{new JsonObject(std::move(object))} {}
370  ptr_.reset(new JsonObject(std::move(object)));
371  return *this;
372  }
373  // string
374  explicit Json(JsonString str) :
375  ptr_{new JsonString(std::move(str))} {}
377  ptr_.reset(new JsonString(std::move(str)));
378  return *this;
379  }
380  // bool
381  explicit Json(JsonBoolean boolean) :
382  ptr_{new JsonBoolean(std::move(boolean))} {}
384  ptr_.reset(new JsonBoolean(std::move(boolean)));
385  return *this;
386  }
387  // null
388  explicit Json(JsonNull null) :
389  ptr_{new JsonNull(std::move(null))} {}
391  ptr_.reset(new JsonNull(std::move(null)));
392  return *this;
393  }
394 
395  // copy
396  Json(Json const& other) = default;
397  Json& operator=(Json const& other);
398  // move
399  Json(Json&& other) : ptr_{std::move(other.ptr_)} {}
400  Json& operator=(Json&& other) {
401  ptr_ = std::move(other.ptr_);
402  return *this;
403  }
404 
406  Json& operator[](std::string const & key) const { return (*ptr_)[key]; }
408  Json& operator[](int ind) const { return (*ptr_)[ind]; }
409 
411  Value const& GetValue() const & { return *ptr_; }
412  Value const& GetValue() && { return *ptr_; }
413  Value& GetValue() & { return *ptr_; }
414 
415  bool operator==(Json const& rhs) const {
416  return *ptr_ == *(rhs.ptr_);
417  }
418 
419  friend std::ostream& operator<<(std::ostream& os, Json const& j) {
420  std::string str;
421  Json::Dump(j, &str);
422  os << str;
423  return os;
424  }
425 
426  private:
427  std::shared_ptr<Value> ptr_;
428 };
429 
430 template <typename T>
431 bool IsA(Json const j) {
432  auto const& v = j.GetValue();
433  return IsA<T>(&v);
434 }
435 
436 namespace detail {
437 
438 // Number
439 template <typename T,
440  typename std::enable_if<
441  std::is_same<T, JsonNumber>::value>::type* = nullptr>
442 JsonNumber::Float& GetImpl(T& val) { // NOLINT
443  return val.GetNumber();
444 }
445 template <typename T,
446  typename std::enable_if<
447  std::is_same<T, JsonNumber const>::value>::type* = nullptr>
448 JsonNumber::Float const& GetImpl(T& val) { // NOLINT
449  return val.GetNumber();
450 }
451 
452 // Integer
453 template <typename T,
454  typename std::enable_if<
455  std::is_same<T, JsonInteger>::value>::type* = nullptr>
456 JsonInteger::Int& GetImpl(T& val) { // NOLINT
457  return val.GetInteger();
458 }
459 template <typename T,
460  typename std::enable_if<
461  std::is_same<T, JsonInteger const>::value>::type* = nullptr>
462 JsonInteger::Int const& GetImpl(T& val) { // NOLINT
463  return val.GetInteger();
464 }
465 
466 // String
467 template <typename T,
468  typename std::enable_if<
469  std::is_same<T, JsonString>::value>::type* = nullptr>
470 std::string& GetImpl(T& val) { // NOLINT
471  return val.GetString();
472 }
473 template <typename T,
474  typename std::enable_if<
475  std::is_same<T, JsonString const>::value>::type* = nullptr>
476 std::string const& GetImpl(T& val) { // NOLINT
477  return val.GetString();
478 }
479 
480 // Boolean
481 template <typename T,
482  typename std::enable_if<
483  std::is_same<T, JsonBoolean>::value>::type* = nullptr>
484 bool& GetImpl(T& val) { // NOLINT
485  return val.GetBoolean();
486 }
487 template <typename T,
488  typename std::enable_if<
489  std::is_same<T, JsonBoolean const>::value>::type* = nullptr>
490 bool const& GetImpl(T& val) { // NOLINT
491  return val.GetBoolean();
492 }
493 
494 // Array
495 template <typename T,
496  typename std::enable_if<
497  std::is_same<T, JsonArray>::value>::type* = nullptr>
498 std::vector<Json>& GetImpl(T& val) { // NOLINT
499  return val.GetArray();
500 }
501 template <typename T,
502  typename std::enable_if<
503  std::is_same<T, JsonArray const>::value>::type* = nullptr>
504 std::vector<Json> const& GetImpl(T& val) { // NOLINT
505  return val.GetArray();
506 }
507 
508 // Object
509 template <typename T,
510  typename std::enable_if<
511  std::is_same<T, JsonObject>::value>::type* = nullptr>
512 std::map<std::string, Json>& GetImpl(T& val) { // NOLINT
513  return val.GetObject();
514 }
515 template <typename T,
516  typename std::enable_if<
517  std::is_same<T, JsonObject const>::value>::type* = nullptr>
518 std::map<std::string, Json> const& GetImpl(T& val) { // NOLINT
519  return val.GetObject();
520 }
521 
522 } // namespace detail
523 
532 template <typename T, typename U>
533 auto get(U& json) -> decltype(detail::GetImpl(*Cast<T>(&json.GetValue())))& { // NOLINT
534  auto& value = *Cast<T>(&json.GetValue());
535  return detail::GetImpl(value);
536 }
537 
539 using Array = JsonArray;
544 using Null = JsonNull;
545 
546 // Utils tailored for XGBoost.
547 
548 template <typename Parameter>
549 Object ToJson(Parameter const& param) {
550  Object obj;
551  for (auto const& kv : param.__DICT__()) {
552  obj[kv.first] = kv.second;
553  }
554  return obj;
555 }
556 
557 template <typename Parameter>
558 void FromJson(Json const& obj, Parameter* param) {
559  auto const& j_param = get<Object const>(obj);
560  std::map<std::string, std::string> m;
561  for (auto const& kv : j_param) {
562  m[kv.first] = get<String const>(kv.second);
563  }
564  param->UpdateAllowUnknown(m);
565 }
566 } // namespace xgboost
567 #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:558
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:411
JsonNumber::Float & GetImpl(T &val)
Definition: json.h:442
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:353
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:419
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:361
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:408
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:35
std::map< std::string, Json > const & GetImpl(T &val)
Definition: json.h:518
T * Cast(U *value)
Definition: json.h:61
std::string const & GetString() &&
Definition: json.h:84
Json(JsonInteger integer)
Definition: json.h:352
Definition: json.h:96
JsonInteger()
Definition: json.h:197
Json & operator=(JsonString str)
Definition: json.h:376
Value const & GetValue() &&
Definition: json.h:412
Json & operator=(JsonNumber number)
Definition: json.h:346
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:390
std::map< std::string, Json > const & GetObject() &&
Definition: json.h:139
Json(Json &&other)
Definition: json.h:399
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:374
Json()
Definition: json.h:342
namespace of xgboost
Definition: base.h:102
Json(JsonArray list)
Definition: json.h:359
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:367
Value & GetValue() &
Definition: json.h:413
Definition: json.h:70
std::vector< Json > const & GetArray() const &
Definition: json.h:114
Json & operator=(Json &&other)
Definition: json.h:400
JsonObject()
Definition: json.h:129
static bool IsClassOf(Value const *value)
Definition: json.h:184
bool operator==(Json const &rhs) const
Definition: json.h:415
Definition: json_io.h:120
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:406
char const * c_str() const
Definition: json.h:306
Json & operator=(JsonBoolean boolean)
Definition: json.h:383
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:388
Definition: json.h:152
Json & operator=(JsonObject object)
Definition: json.h:369
Float const & GetNumber() const &
Definition: json.h:177
bool const & GetBoolean() const &
Definition: json.h:271
Json(JsonNumber number)
Definition: json.h:345
Object ToJson(Parameter const &param)
Definition: json.h:549
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:381
std::vector< Json > & GetArray() &
Definition: json.h:115
virtual Value & operator=(Value const &rhs)=0