OmniSciDB  fe05a0c208
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
json.h
Go to the documentation of this file.
1 // Copyright (c) 2021 OmniSci, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // OmniSci JSON
16 
17 // EXAMPLE #1
18 //
19 // #include "Shared/json.h"
20 // JSON json;
21 // json["item1"] = "abc";
22 // json["item2"] = 123;
23 // std::cout << json.str() << std::endl;
24 // std::cout << static_cast<int>(json["item2"]) << std::endl;
25 //
26 // OUTPUT: {"item1":"abc","item2":123}
27 // OUTPUT: 123
28 
29 // EXAMPLE #2
30 //
31 // #include "Shared/json.h"
32 // std::string text = R"json(
33 // {
34 // "item1": "abc",
35 // "item2": 123
36 // }
37 // )json";
38 // JSON json(text);
39 // json["item3"] = false;
40 // json["item4"].parse("[0, 1, 2, 3, 4]");
41 // std::cout << json.str() << std::endl;
42 // std::cout << static_cast<size_t>(json["item4"][2]) << std::endl;
43 //
44 // OUTPUT: {"item1":"abc","item2":123,"item3":false,"item4":[0,1,2,3,4]}
45 // OUTPUT: 2
46 
47 #pragma once
48 
49 #include <rapidjson/document.h>
50 #include <rapidjson/stringbuffer.h>
51 #include <rapidjson/writer.h>
52 #include <limits>
53 #include <memory>
54 #include <stdexcept>
55 #include <string>
56 #include <type_traits>
57 
58 class JSON final {
59  std::shared_ptr<rapidjson::Document> doc_;
60  rapidjson::Value* vptr_;
61  rapidjson::Document::AllocatorType& allo_;
62  const std::string name_; // only used in error messages
63 
64  public:
65  JSON()
66  : doc_(std::make_shared<rapidjson::Document>())
67  , vptr_(&*doc_)
68  , allo_(doc_->GetAllocator())
69  , name_("JSON") {}
70 
71  JSON(const JSON& peer) : JSON() { vptr_->CopyFrom(*peer.vptr_, allo_); }
72 
73  JSON(JSON&&) = default;
74 
75  JSON(const std::string& json) : JSON() { parse(json); }
76 
77  JSON(const char* json) : JSON() { parse(json); }
78 
79  JSON(const char* json, size_t len) : JSON() { parse(json, len); }
80 
81  void parse(const std::string& json) {
82  if (doc_->Parse(json).HasParseError()) {
83  throw std::runtime_error("failed to parse json");
84  }
85  }
86 
87  void parse(const char* json) {
88  if (doc_->Parse(json).HasParseError()) {
89  throw std::runtime_error("failed to parse json");
90  }
91  }
92 
93  void parse(const char* json, size_t len) {
94  if (doc_->Parse(json, len).HasParseError()) {
95  throw std::runtime_error("failed to parse json");
96  }
97  }
98 
99  std::string str() const {
100  rapidjson::StringBuffer buf;
101  rapidjson::Writer<rapidjson::StringBuffer> wr(buf);
102  vptr_->Accept(wr);
103  return buf.GetString();
104  }
105 
106  std::string getType() const { return kTypeNames[vptr_->GetType()]; }
107 
108  operator std::string() const {
109  if (!vptr_->IsString()) {
110  throw std::runtime_error("expected JSON field '" + name_ +
111  "' to be String but got [" + kTypeNames[vptr_->GetType()] +
112  "]");
113  }
114  return std::string{vptr_->GetString(), vptr_->GetStringLength()};
115  }
116 
117  operator bool() const {
118  if (!vptr_->IsBool()) {
119  throw std::runtime_error("expected JSON field '" + name_ +
120  "' to be Boolean but got [" +
121  kTypeNames[vptr_->GetType()] + "]");
122  }
123  return vptr_->GetBool();
124  }
125 
126  template <typename T>
127  operator T() const {
128  static_assert(std::numeric_limits<T>::is_integer &&
129  !std::is_same_v<bool, std::remove_cv_t<T>>);
130  if constexpr (std::numeric_limits<T>::is_signed) {
131  if constexpr (sizeof(T) < 8) {
132  if (!vptr_->IsInt()) {
133  throw std::runtime_error("expected JSON field '" + name_ +
134  "' to be signed integer but got [" +
135  kTypeNames[vptr_->GetType()] + "]");
136  }
137  return vptr_->GetInt();
138  } else {
139  if (!vptr_->IsInt64()) {
140  throw std::runtime_error("expected JSON field '" + name_ +
141  "' to be signed 64-bit integer but got [" +
142  kTypeNames[vptr_->GetType()] + "]");
143  }
144  return vptr_->GetInt64();
145  }
146  } else {
147  if constexpr (sizeof(T) < 8) {
148  if (!vptr_->IsUint()) {
149  throw std::runtime_error("expected JSON field '" + name_ +
150  "' to be unsigned integer but got [" +
151  kTypeNames[vptr_->GetType()] + "]");
152  }
153  return vptr_->GetUint();
154  } else {
155  if (!vptr_->IsUint64()) {
156  throw std::runtime_error("expected JSON field '" + name_ +
157  "' to be unsigned 64-bit integer but got [" +
158  kTypeNames[vptr_->GetType()] + "]");
159  }
160  return vptr_->GetUint64();
161  }
162  }
163  }
164 
165  JSON& operator=(const JSON& peer) {
166  vptr_->CopyFrom(*peer.vptr_, allo_);
167  return *this;
168  }
169 
170  JSON& operator=(const std::string& item) {
171  *vptr_ = rapidjson::Value().SetString(item, allo_);
172  return *this;
173  }
174 
175  JSON& operator=(const char* item) {
176  *vptr_ = rapidjson::Value().SetString(item, allo_);
177  return *this;
178  }
179 
180  JSON& operator=(bool item) {
181  vptr_->SetBool(item);
182  return *this;
183  }
184 
185  JSON& operator=(int32_t item) {
186  vptr_->SetInt(item);
187  return *this;
188  }
189 
190  JSON& operator=(int64_t item) {
191  vptr_->SetInt64(item);
192  return *this;
193  }
194 
195  JSON& operator=(uint32_t item) {
196  vptr_->SetUint(item);
197  return *this;
198  }
199 
200  JSON& operator=(uint64_t item) {
201  vptr_->SetUint64(item);
202  return *this;
203  }
204 
205  JSON operator[](const std::string& name) { return (*this)[name.c_str()]; }
206  JSON operator[](const char* name) {
207  if (!vptr_->IsObject()) {
208  vptr_->SetObject();
209  }
210  if (!vptr_->HasMember(name)) {
211  vptr_->AddMember(
212  rapidjson::Value(name, allo_).Move(), rapidjson::Value().Move(), allo_);
213  auto f = vptr_->FindMember(name);
214  // f necessary because AddMember inexplicably doesn't return the new member
215  // https://stackoverflow.com/questions/52113291/which-object-reference-does-genericvalueaddmember-return
216  return JSON(doc_, &f->value, allo_, name);
217  }
218  return JSON(doc_, &(*vptr_)[name], allo_, name);
219  }
220 
221  JSON operator[](const std::string& name) const { return (*this)[name.c_str()]; }
222  JSON operator[](const char* name) const {
223  if (!vptr_->IsObject()) {
224  throw std::runtime_error("JSON " + getType() + " field '" + name_ +
225  "' can't use operator []");
226  }
227  if (!vptr_->HasMember(name)) {
228  throw std::runtime_error("JSON field '" + std::string(name) + "' not found");
229  }
230  return JSON(doc_, &(*vptr_)[name], allo_, name);
231  }
232 
233  template <typename T>
234  JSON operator[](T index) {
235  return operator[](static_cast<size_t>(index));
236  }
237  JSON operator[](size_t index) {
238  if (!vptr_->IsArray()) {
239  vptr_->SetArray();
240  }
241  if (index >= vptr_->Size()) {
242  throw std::runtime_error("JSON array index " + std::to_string(index) +
243  " out of range " + std::to_string(vptr_->Size()));
244  }
245  return JSON(doc_, &(*vptr_)[index], allo_, std::to_string(index));
246  }
247 
248  template <typename T>
249  JSON operator[](T index) const {
250  return operator[](static_cast<size_t>(index));
251  }
252  JSON operator[](size_t index) const {
253  if (!vptr_->IsArray()) {
254  throw std::runtime_error("JSON " + getType() + " field '" + name_ +
255  "' can't use operator []");
256  }
257  if (index >= vptr_->Size()) {
258  throw std::runtime_error("JSON array index " + std::to_string(index) +
259  " out of range " + std::to_string(vptr_->Size()));
260  }
261  return JSON(doc_, &(*vptr_)[index], allo_, std::to_string(index));
262  }
263 
264  private:
265  inline static std::string kTypeNames[] =
266  {"Null", "False", "True", "Object", "Array", "String", "Number"};
267 
268  JSON(std::shared_ptr<rapidjson::Document> doc,
269  rapidjson::Value* vptr,
270  rapidjson::Document::AllocatorType& allo,
271  const std::string& name)
272  : doc_(doc), vptr_(vptr), allo_(allo), name_(name) {}
273 }; // struct JSON
std::shared_ptr< rapidjson::Document > doc_
Definition: json.h:59
JSON operator[](size_t index)
Definition: json.h:237
JSON operator[](T index) const
Definition: json.h:249
JSON(const JSON &peer)
Definition: json.h:71
JSON operator[](T index)
Definition: json.h:234
JSON operator[](const char *name) const
Definition: json.h:222
JSON & operator=(const char *item)
Definition: json.h:175
JSON operator[](size_t index) const
Definition: json.h:252
const std::string name_
Definition: json.h:62
JSON(std::shared_ptr< rapidjson::Document > doc, rapidjson::Value *vptr, rapidjson::Document::AllocatorType &allo, const std::string &name)
Definition: json.h:268
JSON & operator=(bool item)
Definition: json.h:180
string name
Definition: setup.in.py:72
rapidjson::Document::AllocatorType & allo_
Definition: json.h:61
JSON(const char *json)
Definition: json.h:77
std::string str() const
Definition: json.h:99
JSON & operator=(int32_t item)
Definition: json.h:185
std::string to_string(char const *&&v)
void parse(const std::string &json)
Definition: json.h:81
JSON & operator=(int64_t item)
Definition: json.h:190
void parse(const char *json)
Definition: json.h:87
JSON()
Definition: json.h:65
JSON & operator=(uint64_t item)
Definition: json.h:200
JSON operator[](const std::string &name)
Definition: json.h:205
JSON(const std::string &json)
Definition: json.h:75
static std::string kTypeNames[]
Definition: json.h:265
JSON & operator=(uint32_t item)
Definition: json.h:195
JSON operator[](const char *name)
Definition: json.h:206
Definition: json.h:58
JSON operator[](const std::string &name) const
Definition: json.h:221
JSON(const char *json, size_t len)
Definition: json.h:79
JSON & operator=(const std::string &item)
Definition: json.h:170
char * f
rapidjson::Value * vptr_
Definition: json.h:60
std::string getType() const
Definition: json.h:106
void parse(const char *json, size_t len)
Definition: json.h:93
JSON & operator=(const JSON &peer)
Definition: json.h:165