jubilant-funicular
Json.h
1 #ifndef UTILS_JSON_H_INCLUDED
2 #define UTILS_JSON_H_INCLUDED
3 
4 #include <map>
5 #include <queue>
6 #include <iterator>
7 #include <cstring>
8 
9 #include <common.h>
10 
11 namespace utils {
12  class Json;
13  typedef std::map<std::string, Json> JsonObject;
14  typedef std::vector<Json> JsonArray;
15 
17  enum JsonNumType {
18  POS_INT,
19  NEG_INT,
20  FLOAT
21  };
25  class JsonNum {
26  private:
28  JsonNumType m_type;
29  union {
31  uint64_t m_pos;
33  int64_t m_neg;
35  double m_flt;
36  };
37  public:
39  JsonNum() : m_type(POS_INT), m_pos(0) {}
40  JsonNum(uint64_t n) : m_type(POS_INT), m_pos(n) {}
41  JsonNum(int64_t n) : m_type(NEG_INT), m_neg(n) {}
42  JsonNum(double n) : m_type(FLOAT), m_flt(n) {}
43  JsonNum(int n) : m_type(n >= 0 ? POS_INT : NEG_INT) {
44  if (m_type == POS_INT) {
45  m_pos = n;
46  } else {
47  m_neg = n;
48  }
49  }
50  JsonNumType get_type() { return m_type; }
51  uint64_t as_uint() const { return m_type == FLOAT ? m_flt : m_pos; }
52  int64_t as_int() const { return m_type == FLOAT ? m_flt : m_neg; }
53  double as_float() const { return m_type == FLOAT ? m_flt : m_neg; }
54  double as_double() const { return m_type == FLOAT ? m_flt : m_neg; }
55 
56  operator uint64_t() const { return as_uint(); }
57  operator int64_t() const { return as_int(); }
58  operator double() const { return as_double(); }
59 
60  bool operator==(const JsonNum& rhs) const {
61  if (m_type != rhs.m_type) return false;
62  switch(m_type) {
63  case POS_INT: return m_pos == rhs.m_pos;
64  case NEG_INT: return m_neg == rhs.m_neg;
65  case FLOAT: return m_flt == rhs.m_flt;
66  }
67  }
68 
70  std::string to_string() const { return dump(); }
72  std::string dump() const {
73  switch(m_type) {
74  case POS_INT: return utils::to_string(m_pos);
75  case NEG_INT: return utils::to_string(m_neg);
76  case FLOAT: return utils::to_string(m_flt);
77  }
78  }
79  };
80 
82  enum JsonValueType {
83  STRING = 0,
84  NUMBER = 1,
85  OBJECT = 2,
86  ARRAY = 3,
87  BOOLEAN = 4,
88  NONE = 5 // Should be called null
89  };
93  class Json {
94  public:
95  // I really like Keys
98  friend class Json;
99  SetBeginEndKey() {}
101  SetBeginEndKey& operator=(const SetBeginEndKey&);
102  };
114  template<bool c=0>
115  class iterator {
116  public:
117  using value_type = typename std::conditional<c, const Json, Json>::type;
118  using difference_type = std::ptrdiff_t;
119  using pointer = typename std::conditional<c, const Json*, Json*>::type;
120  using reference = typename std::conditional<c, const Json&, Json&>::type;
121  using iterator_category = std::bidirectional_iterator_tag;
122  private:
123  pointer m_json;
124  union {
125  JsonObject::iterator m_obj_iter;
126  JsonArray::iterator m_arr_iter;
127  };
128  public:
129  iterator() : m_json(nullptr) {}
130  iterator(pointer json) : m_json(json) {
131  assert(json != nullptr);
132  switch(m_json->get_type()) {
133  case OBJECT: m_obj_iter = JsonObject::iterator(); break;
134  case ARRAY: m_arr_iter = JsonArray::iterator(); break;
135  }
136  }
137  reference operator*() const {
138  switch(m_json->get_type()) {
139  case OBJECT: return m_obj_iter->second;
140  case ARRAY: return *m_arr_iter;
141  default: return *m_json;
142  }
143  }
144  pointer operator->() const {
145  switch(m_json->get_type()) {
146  case OBJECT: return &m_obj_iter->second;
147  case ARRAY: return &*m_arr_iter;
148  default: return m_json;
149  }
150  }
151  iterator& operator++() {
152  switch(m_json->get_type()) {
153  case OBJECT: ++m_obj_iter; break;
154  case ARRAY: ++m_arr_iter; break;
155  default: ++m_json; break;
156  }
157  return *this;
158  }
159  iterator operator++(int) {
160  auto ret = *this;
161  operator++();
162  return ret;
163  }
164  iterator& operator--() {
165  switch(m_json->get_type()) {
166  case OBJECT: --m_obj_iter; break;
167  case ARRAY: --m_arr_iter; break;
168  default: --m_json; break;
169  }
170  return *this;
171  }
172  iterator operator--(int) {
173  auto ret = *this;
174  operator--();
175  return ret;
176  }
177  bool operator==(const iterator& rhs) const {
178  if (m_json->get_type() != rhs.m_json->get_type()) return false;
179  switch(m_json->get_type()) {
180  case OBJECT: return m_obj_iter == rhs.m_obj_iter;
181  case ARRAY: return m_arr_iter == rhs.m_arr_iter;
182  default: return m_json == rhs.m_json;
183  }
184  }
185  bool operator!=(const iterator& rhs) const {
186  return !operator==(rhs);
187  }
188 
189  std::string key() {
190  switch(m_json->get_type()) {
191  case OBJECT: return m_obj_iter->first;
192  default: return "";
193  }
194  }
195  reference value() {
196  switch(m_json->get_type()) {
197  case OBJECT: return m_obj_iter->second;
198  case ARRAY: return *m_arr_iter;
199  default: return *m_json;
200  }
201  }
202 
203  void set_begin(SetBeginEndKey _) {
204  switch(m_json->get_type()) {
205  case OBJECT: m_obj_iter = m_json->m_obj->begin(); break;
206  case ARRAY: m_arr_iter = m_json->m_arr->begin(); break;
207  case NONE: ++m_json; break;
208  }
209  }
210  void set_end(SetBeginEndKey _) {
211  switch(m_json->get_type()) {
212  case OBJECT: m_obj_iter = m_json->m_obj->end(); break;
213  case ARRAY: m_arr_iter = m_json->m_arr->end(); break;
214  default: ++m_json; break;
215  }
216  }
217  };
218  private:
219  enum JsonTokenType {
220  SYMBOL, NUMTKN
221  };
223  struct JsonToken {
224  JsonToken() : type(SYMBOL), str(nullptr) {}
225  JsonToken(char c) : type(SYMBOL) {
226  str = (char*)malloc(2);
227  str[0] = c;
228  str[1] = '\0';
229  }
230  JsonToken(const std::string& str) : type(SYMBOL) {
231  this->str = strdup(str.c_str());
232  }
233  JsonToken(const JsonToken& other) {
234  operator=(other);
235  }
236  ~JsonToken() {
237  if (type == SYMBOL && str) free(str);
238  }
239 
240  JsonToken& operator=(const JsonToken& other) {
241  type = other.type;
242  if (type == SYMBOL) {
243  str = other.str ? strdup(other.str) : nullptr;
244  } else {
245  num = other.num;
246  }
247  return *this;
248  }
249  bool operator==(const JsonToken& rhs) const {
250  return type == rhs.type && ( type == SYMBOL ?
251  strcmp(str, rhs.str) == 0 : num == rhs.num);
252  }
253  bool operator!=(const JsonToken& rhs) const {
254  return !(*this == rhs);
255  }
256 
257  JsonTokenType type;
258  union {
259  char* str;
260  JsonNum num;
261  };
262  };
263 
264  Json(JsonValueType type) : m_type(type) {}
265 
267  static bool lex_string(std::string& str, JsonToken& ret);
269  static bool lex_number(std::string& str, JsonToken& ret);
271  static bool lex_bool(std::string& str, JsonToken& ret);
273  static bool lex_null(std::string& str, JsonToken& ret);
274 
276  static std::queue<JsonToken> tokenize(std::string curr);
278  static Json parse_tokens(std::queue<JsonToken>& tokens);
279 
280  JsonValueType m_type;
281  union {
282  char* m_str;
283  JsonNum m_num;
284  JsonObject* m_obj;
285  JsonArray* m_arr;
286  bool m_bool;
287  };
288  public:
289  Json() : m_type(NONE) {}
290  Json(const std::string& str) : m_type(STRING), m_str(strdup(str.c_str())) {}
291  Json(const char* str) : m_type(STRING), m_str(strdup(str)) {}
292  Json(JsonNum num) : m_type(NUMBER), m_num(num) {}
293  Json(double num) : m_type(NUMBER), m_num(num) {}
294  Json(std::size_t num) : m_type(NUMBER), m_num(num) {}
295  Json(int num) : m_type(NUMBER), m_num(num) {}
296  Json(JsonObject obj) : m_type(OBJECT), m_obj(new JsonObject(obj)) {}
297  Json(JsonArray arr) : m_type(ARRAY), m_arr(new JsonArray(arr)) {}
298  Json(bool b) : m_type(BOOLEAN), m_bool(b) {}
299  Json(const std::initializer_list<Json>& data);
300  Json(const Json& other);
301  Json(Json&& other);
302  ~Json();
303 
304  static Json string(const std::string& str) {
305  Json s(STRING);
306  s.m_str = strdup(str.c_str());
307  return s;
308  }
309  static Json string(const char* str) {
310  Json s(STRING);
311  s.m_str = strdup(str);
312  return s;
313  }
314  static Json number(JsonNum num) {
315  Json n(NUMBER);
316  n.m_num = num;
317  return n;
318  }
319  static Json object(JsonObject obj) {
320  Json o(OBJECT);
321  o.m_obj = new JsonObject(obj);
322  return o;
323  }
324  static Json array(JsonArray arr) {
325  Json a(ARRAY);
326  a.m_arr = new JsonArray(arr);
327  return a;
328  }
329  static Json boolean(bool boolean) {
330  Json b(BOOLEAN);
331  b.m_bool = boolean;
332  return b;
333  }
334  static Json null() { return Json(NONE); }
335 
337  static Json parse(const std::string& json);
338  static Json from_file(const std::string& path);
339 
340  JsonValueType get_type() const { return m_type; }
341  bool is_string() const { return m_type == STRING; }
342  bool is_number() const { return m_type == NUMBER; }
343  bool is_object() const { return m_type == OBJECT; }
344  bool is_array() const { return m_type == ARRAY; }
345  bool is_bool() const { return m_type == BOOLEAN; }
346  bool is_null() const { return m_type == NONE; }
347 
348  std::string as_string() const;
349  JsonNum as_number() const;
350  uint64_t as_uint() const { return as_number().as_uint(); }
351  int64_t as_int() const { return as_number().as_int(); }
352  double as_float() const { return as_number().as_float(); }
353  double as_double() const { return as_number().as_double(); }
354  JsonObject as_object() const { return *m_obj; }
355  JsonArray as_array() const { return *m_arr; }
356  bool as_bool() const;
357 
358  std::size_t size() const;
359  bool is_empty() const { return size() == 0; }
360  bool has_key(const std::string& key) const;
364  bool resize(std::size_t size);
368  bool push_back(const Json& val);
370  Json& front();
372  Json& back();
376  Json& merge(const Json& other);
377 
381  std::string dump(std::size_t indent = 0, std::size_t offset = 0) const;
382 
383  operator std::string() const { return as_string(); }
384  operator JsonNum() const { return as_number(); }
385  operator uint64_t() const { return as_uint(); }
386  operator int64_t() const { return as_int(); }
387  operator int() const { return as_int(); }
388  operator float() const { return as_double(); }
389  operator double() const { return as_double(); }
390  operator JsonObject() const { return as_object(); }
391  operator JsonArray() const { return as_array(); }
392  operator bool() const { return as_bool(); }
393 
394  Json& operator=(const Json& other);
395  Json& operator=(Json&& other);
396  bool operator==(const Json& other) const;
397  bool operator!=(const Json& other) const { return !(*this == other); }
398  bool operator==(const std::string& other) const { return *this == Json::string(other); }
399  bool operator!=(const std::string& other) const { return !(*this == other); }
400  bool operator==(const char* other) const { return *this == Json::string(other); }
401  bool operator!=(const char* other) const { return !(*this == other); }
402  bool operator==(const JsonNum& other) const { return *this == Json::number(other); }
403  bool operator!=(const JsonNum& other) const { return !(*this == other); }
404  bool operator==(const int& other) const { return *this == Json::number(other); }
405  bool operator!=(const int& other) const { return !(*this == other); }
406  bool operator==(const JsonObject& other) const { return *this == Json::object(other); }
407  bool operator!=(const JsonObject& other) const { return !(*this == other); }
408  bool operator==(const JsonArray& other) const { return *this == Json::array(other); }
409  bool operator!=(const JsonArray& other) const { return !(*this == other); }
410  bool operator==(const bool& other) const { return *this == Json::boolean(other); }
411  bool operator!=(const bool& other) const { return !(*this == other); }
412 
414  Json& operator[](const std::string& key);
415  Json& operator[](const std::string& key) const;
416  Json& operator[](const char* key) { return operator[](std::string(key)); }
417  Json& operator[](const char* key) const { return operator[](std::string(key)); }
419  Json& operator[](std::size_t idx);
420  Json& operator[](std::size_t idx) const;
421  Json& operator[](int idx) { return operator[]((std::size_t)idx); }
422  Json& operator[](int idx) const { return operator[]((std::size_t)idx); }
423 
424  iterator<0> begin() {
425  iterator<0> ret(this);
426  ret.set_begin(SetBeginEndKey());
427  return ret;
428  }
429  iterator<1> cbegin() const {
430  iterator<1> ret(this);
431  ret.set_begin(SetBeginEndKey());
432  return ret;
433  }
434  iterator<0> end() {
435  iterator<0> ret(this);
436  ret.set_end(SetBeginEndKey());
437  return ret;
438  }
439  iterator<1> cend() const {
440  iterator<1> ret(this);
441  ret.set_end(SetBeginEndKey());
442  return ret;
443  }
444  };
445 }
446 
447 #endif // UTILS_JSON_H_INCLUDED
utils::Json::from_file
static Json from_file(const std::string &path)
Definition: Json.cpp:357
utils::Json::lex_null
static bool lex_null(std::string &str, JsonToken &ret)
Attempts to retreive a null token from the beginning of str.
Definition: Json.cpp:272
utils::Json::lex_string
static bool lex_string(std::string &str, JsonToken &ret)
Attempts to retreive a string token from the beginning of str.
Definition: Json.cpp:221
utils::Json::merge
Json & merge(const Json &other)
Definition: Json.cpp:153
utils::Json::dump
std::string dump(std::size_t indent=0, std::size_t offset=0) const
Definition: Json.cpp:189
utils::JsonNum::dump
std::string dump() const
Same as to_string()
Definition: Json.h:72
utils::Json::parse
static Json parse(const std::string &json)
Parses Json value from a string.
Definition: Json.cpp:350
utils::Json::lex_bool
static bool lex_bool(std::string &str, JsonToken &ret)
Attempts to retreive a boolean token from the beginning of str.
Definition: Json.cpp:258
utils::Json::resize
bool resize(std::size_t size)
Definition: Json.cpp:121
utils::JsonNum::JsonNum
JsonNum()
By default, this is 0.
Definition: Json.h:39
utils::Json::push_back
bool push_back(const Json &val)
Definition: Json.cpp:131
utils::JsonNum::m_type
JsonNumType m_type
The type of number.
Definition: Json.h:28
utils::Json::lex_number
static bool lex_number(std::string &str, JsonToken &ret)
Attempts to retreive a number token from the beginning of str.
Definition: Json.cpp:234
utils::Json::front
Json & front()
Returns first element if this is an array.
Definition: Json.cpp:139
utils::JsonNum
Definition: Json.h:25
utils::Json::JsonToken
Used for tokenizing strings before parsing them into Json objects.
Definition: Json.h:223
utils::Json::SetBeginEndKey
Key unlocking the set_{begin,end}() "private" functions of class Json::iterator.
Definition: Json.h:97
utils::Json
Definition: Json.h:93
utils::JsonNum::to_string
std::string to_string() const
Return string equivalent of stored value.
Definition: Json.h:70
utils::Json::iterator
Definition: Json.h:115
utils::Json::parse_tokens
static Json parse_tokens(std::queue< JsonToken > &tokens)
Converts stream of tokens into a Json value.
Definition: Json.cpp:309
utils::Json::operator[]
Json & operator[](const std::string &key)
When m_type == NONE, first converts this into an Object.
Definition: Json.cpp:85
utils::Json::back
Json & back()
Returns last element if this is an array.
Definition: Json.cpp:146
utils::Json::tokenize
static std::queue< JsonToken > tokenize(std::string curr)
Converts curr into a stream of tokens.
Definition: Json.cpp:281