json11.h 8.83 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Copyright (c) 2013 Dropbox, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

22
23
/* json11
 *
Guolin Ke's avatar
Guolin Ke committed
24
25
 * json11 is a tiny JSON library for C++11, providing JSON parsing and
 * serialization.
26
 *
Guolin Ke's avatar
Guolin Ke committed
27
28
29
 * The core object provided by the library is json11::Json. A Json object
 * represents any JSON value: null, bool, number (int or double), string
 * (std::string), array (std::vector), or object (std::map).
30
 *
Guolin Ke's avatar
Guolin Ke committed
31
32
33
34
 * Json objects act like values: they can be assigned, copied, moved, compared
 * for equality or order, etc. There are also helper methods Json::dump, to
 * serialize a Json to a string, and Json::parse (static) to parse a std::string
 * as a Json object.
35
 *
Guolin Ke's avatar
Guolin Ke committed
36
37
 * Internally, the various types of Json object are represented by the JsonValue
 * class hierarchy.
38
 *
Guolin Ke's avatar
Guolin Ke committed
39
40
41
42
43
44
45
 * A note on numbers - JSON specifies the syntax of number formatting but not
 * its semantics, so some JSON implementations distinguish between integers and
 * floating-point numbers, while some don't. In json11, we choose the latter.
 * Because some JSON implementations (namely Javascript itself) treat all
 * numbers as the same type, distinguishing the two leads to JSON that will be
 * *silently* changed by a round-trip through those implementations. Dangerous!
 * To avoid that risk, json11 stores all numbers as double internally, but also
46
47
 * provides integer helpers.
 *
Guolin Ke's avatar
Guolin Ke committed
48
49
50
51
52
 * Fortunately, double-precision IEEE754 ('double') can precisely store any
 * integer in the range +/-2^53, which includes every 'int' on most systems.
 * (Timestamps often use int64 or long long to avoid the Y2038K problem; a
 * double storing microseconds since some epoch will be exact for +/- 275
 * years.)
53
54
55
 */
#pragma once

56
#include <initializer_list>
57
58
#include <map>
#include <memory>
Guolin Ke's avatar
Guolin Ke committed
59
#include <string>
60
61
#include <utility>
#include <vector>
62

63
namespace json11_internal_lightgbm {
64

Guolin Ke's avatar
Guolin Ke committed
65
enum JsonParse { STANDARD, COMMENTS };
66
67
68
69

class JsonValue;

class Json final {
70
 public:
Guolin Ke's avatar
Guolin Ke committed
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
  // Types
  enum Type { NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT };

  // Array and object typedefs
  typedef std::vector<Json> array;
  typedef std::map<std::string, Json> object;

  // Constructors for the various types of JSON value.
  Json() noexcept;                          // NUL
  explicit Json(std::nullptr_t) noexcept;   // NUL
  explicit Json(double value);              // NUMBER
  explicit Json(int value);                 // NUMBER
  explicit Json(bool value);                // BOOL
  explicit Json(const std::string &value);  // STRING
  explicit Json(std::string &&value);       // STRING
  explicit Json(const char *value);         // STRING
  explicit Json(const array &values);       // ARRAY
  explicit Json(array &&values);            // ARRAY
  explicit Json(const object &values);      // OBJECT
  explicit Json(object &&values);           // OBJECT

  // Implicit constructor: anything with a to_json() function.
  template <class T, class = decltype(&T::to_json)>
  explicit Json(const T &t) : Json(t.to_json()) {}

  // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
  template <
      class M,
      typename std::enable_if<
          std::is_constructible<
              std::string, decltype(std::declval<M>().begin()->first)>::value &&
              std::is_constructible<
                  Json, decltype(std::declval<M>().begin()->second)>::value,
          int>::type = 0>
  explicit Json(const M &m) : Json(object(m.begin(), m.end())) {}

  // Implicit constructor: vector-like objects (std::list, std::vector,
  // std::set, etc)
  template <class V, typename std::enable_if<
                         std::is_constructible<
                             Json, decltype(*std::declval<V>().begin())>::value,
                         int>::type = 0>
  explicit Json(const V &v) : Json(array(v.begin(), v.end())) {}

  // This prevents Json(some_pointer) from accidentally producing a bool. Use
  // Json(bool(some_pointer)) if that behavior is desired.
  explicit Json(void *) = delete;

  // Accessors
  Type type() const;

  bool is_null() const { return type() == NUL; }
  bool is_number() const { return type() == NUMBER; }
  bool is_bool() const { return type() == BOOL; }
  bool is_string() const { return type() == STRING; }
  bool is_array() const { return type() == ARRAY; }
  bool is_object() const { return type() == OBJECT; }

  // Return the enclosed value if this is a number, 0 otherwise. Note that
  // json11 does not distinguish between integer and non-integer numbers -
  // number_value() and int_value() can both be applied to a NUMBER-typed
  // object.
  double number_value() const;
  int int_value() const;

  // Return the enclosed value if this is a boolean, false otherwise.
  bool bool_value() const;
  // Return the enclosed string if this is a string, "" otherwise.
  const std::string &string_value() const;
  // Return the enclosed std::vector if this is an array, or an empty vector
  // otherwise.
  const array &array_items() const;
  // Return the enclosed std::map if this is an object, or an empty map
  // otherwise.
  const object &object_items() const;

  // Return a reference to arr[i] if this is an array, Json() otherwise.
  const Json &operator[](size_t i) const;
  // Return a reference to obj[key] if this is an object, Json() otherwise.
  const Json &operator[](const std::string &key) const;

  // Serialize.
  void dump(std::string *out) const;
  std::string dump() const {
    std::string out;
    dump(&out);
    return out;
  }

  // Parse. If parse fails, return Json() and assign an error message to err.
  static Json parse(const std::string &in, std::string *err,
                    JsonParse strategy = JsonParse::STANDARD);
  static Json parse(const char *in, std::string *err,
                    JsonParse strategy = JsonParse::STANDARD) {
    if (in) {
      return parse(std::string(in), err, strategy);
    } else {
      *err = "null input";
      return Json(nullptr);
170
    }
Guolin Ke's avatar
Guolin Ke committed
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
  }
  // Parse multiple objects, concatenated or separated by whitespace
  static std::vector<Json> parse_multi(
      const std::string &in, std::string::size_type *parser_stop_pos,
      std::string *err, JsonParse strategy = JsonParse::STANDARD);

  static inline std::vector<Json> parse_multi(
      const std::string &in, std::string *err,
      JsonParse strategy = JsonParse::STANDARD) {
    std::string::size_type parser_stop_pos;
    return parse_multi(in, &parser_stop_pos, err, strategy);
  }

  bool operator==(const Json &rhs) const;
  bool operator<(const Json &rhs) const;
  bool operator!=(const Json &rhs) const { return !(*this == rhs); }
  bool operator<=(const Json &rhs) const { return !(rhs < *this); }
  bool operator>(const Json &rhs) const { return (rhs < *this); }
  bool operator>=(const Json &rhs) const { return !(*this < rhs); }

  /* has_shape(types, err)
   *
   * Return true if this is a JSON object and, for each item in types, has a
   * field of the given type. If not, return false and set err to a descriptive
   * message.
   */
  typedef std::initializer_list<std::pair<std::string, Type>> shape;
  bool has_shape(const shape &types, std::string *err) const;
199

Nikita Titov's avatar
Nikita Titov committed
200
 private:
Guolin Ke's avatar
Guolin Ke committed
201
  std::shared_ptr<JsonValue> m_ptr;
202
203
};

Guolin Ke's avatar
Guolin Ke committed
204
205
// Internal class hierarchy - JsonValue objects are not exposed to users of this
// API.
206
class JsonValue {
Nikita Titov's avatar
Nikita Titov committed
207
 protected:
Guolin Ke's avatar
Guolin Ke committed
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  friend class Json;
  friend class JsonInt;
  friend class JsonDouble;
  virtual Json::Type type() const = 0;
  virtual bool equals(const JsonValue *other) const = 0;
  virtual bool less(const JsonValue *other) const = 0;
  virtual void dump(std::string *out) const = 0;
  virtual double number_value() const;
  virtual int int_value() const;
  virtual bool bool_value() const;
  virtual const std::string &string_value() const;
  virtual const Json::array &array_items() const;
  virtual const Json &operator[](size_t i) const;
  virtual const Json::object &object_items() const;
  virtual const Json &operator[](const std::string &key) const;
  virtual ~JsonValue() {}
224
225
};

226
}  // namespace json11_internal_lightgbm