Simulant  21.12-574
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
json.h
1 #pragma once
2 
3 #include <memory>
4 #include <iosfwd>
5 #include <string>
6 #include <vector>
7 
8 #include "../generic/optional.h"
9 #include "../path.h"
10 
11 namespace smlt {
12 
13 enum JSONNodeType {
14  JSON_OBJECT,
15  JSON_ARRAY,
16  JSON_STRING,
17  JSON_NUMBER,
18  JSON_TRUE,
19  JSON_FALSE,
20  JSON_NULL
21 };
22 
23 namespace _json_impl {
24  typedef std::shared_ptr<std::istream> IStreamPtr;
25 }
26 
27 class JSONIterator;
28 
29 class JSONNode {
30 private:
31  std::string read_value_from_stream() const;
32 public:
33  JSONNode() = default;
34  JSONNode(_json_impl::IStreamPtr stream, std::streampos start, std::streampos end, std::size_t size=0):
35  stream_(stream), start_(start), end_(end), size_(size) {}
36 
37  std::streampos start() const {
38  return start_;
39  }
40 
41  std::streampos end() const {
42  return end_;
43  }
44 
45  JSONNodeType type() const;
46 
47  /* For non-value-types, returns the number
48  * of child items. Value types return 0 */
49  std::size_t size() const;
50 
51  /* Returns true if this is an object, that contains the
52  * provided key */
53  bool has_key(const std::string& key) const;
54 
55  /* Returns the keys found in the object, if this
56  * node is an object */
57  std::vector<std::string> keys() const;
58 
59  /* Returns true if the type is a NUMBER, STRING, TRUE, FALSE, or NULL */
60  bool is_value_type() const;
61 
62  bool is_bool() const {
63  return type_ == JSON_FALSE || type_ == JSON_TRUE;
64  }
65 
66  bool is_str() const {
67  return type_ == JSON_STRING;
68  }
69 
70  bool is_number() const {
71  return type_ == JSON_NUMBER;
72  }
73 
74  bool is_array() const {
75  return type_ == JSON_ARRAY;
76  }
77 
78  bool is_object() const {
79  return type_ == JSON_OBJECT;
80  }
81 
82  bool is_null() const;
83 
84  /* Convert the value to a string, this is well-defined for all value types
85  * and will return the following:
86  *
87  * - STRING - returns the verbatim value
88  * - NUMBER - returns the stringified floating point value
89  * - TRUE - returns "true"
90  * - FALSE - returns "false"
91  * - NULL - returns "null"
92  */
93  optional<std::string> to_str() const {
94  switch(type_) {
95  case JSON_OBJECT: return optional<std::string>();
96  case JSON_ARRAY: return optional<std::string>();
97  case JSON_STRING: return optional<std::string>(read_value_from_stream());
98  case JSON_NUMBER: return optional<std::string>(read_value_from_stream());
99  case JSON_TRUE: return optional<std::string>("true");
100  case JSON_FALSE: return optional<std::string>("false");
101  case JSON_NULL: return optional<std::string>("null");
102  default:
103  return optional<std::string>();
104  }
105  }
106 
107  /* Returns the value as an integer if the type is NUMBER */
108  optional<int64_t> to_int() const;
109 
110  /* Returns the value as a float if the type is NUMBER */
111  optional<float> to_float() const;
112 
113  /* Returns the value as a bool if the type is TRUE, FALSE, or NULL.
114  * NULL always returns false. */
115  optional<bool> to_bool() const;
116 
117  /* Returns an iterator pointing to this node */
118  JSONIterator to_iterator() const;
119 
120 private:
121  friend class JSONIterator;
122  mutable _json_impl::IStreamPtr stream_;
123  std::streampos start_ = 0;
124  std::streampos end_ = 0;
125  std::size_t size_ = 0;
126  JSONNodeType type_ = JSON_OBJECT;
127 
128  /* Internal function. If this is an object type,
129  * will read from start to end and call cb() with
130  * each key found */
131  template<typename Func>
132  void read_keys(Func&& cb) const;
133 };
134 
136  friend JSONIterator json_parse(const std::string&);
137  friend JSONIterator json_load(const Path&);
138  friend JSONIterator json_read(std::shared_ptr<std::istream>);
139 
140  friend class JSONNode;
141 private:
142  JSONIterator() = default; /* Invalid or end */
143 
144  JSONIterator(_json_impl::IStreamPtr stream, std::streampos pos, bool is_array_item=false):
145  stream_(stream),
146  is_array_iterator_(is_array_item) {
147 
148  current_node_ = std::make_shared<JSONNode>();
149  parse_node(*current_node_, stream, pos);
150  }
151 
152 
153  /* mutable as we need to manipulate inside const contexts */
154  mutable _json_impl::IStreamPtr stream_;
155  bool is_array_iterator_ = false;
156 
157  std::shared_ptr<JSONNode> current_node_;
158 
159  void parse_node(JSONNode& node, _json_impl::IStreamPtr stream, std::streampos pos);
160  void set_invalid(const std::string& message);
161 
162 public:
163  typedef JSONNode value_type;
164  typedef JSONNode* pointer;
165  typedef JSONNode reference;
166  typedef std::input_iterator_tag iterator_category;
167 
168  bool is_valid() const {
169  return bool(current_node_);
170  }
171 
172  JSONNode* operator->() const {
173  return current_node_.get();
174  }
175 
176  JSONNode& operator*() const {
177  return *current_node_.get();
178  }
179 
180  JSONIterator operator[](const std::string& key) const;
181  JSONIterator operator[](const std::size_t i) const;
182 
183  /* Range-loop iteration, only for array items */
184  explicit operator bool() const {
185  return is_valid();
186  }
187 
188  JSONIterator begin() const;
189 
190  JSONIterator end() const {
191  return JSONIterator();
192  }
193 
194  JSONIterator& operator++();
195  bool operator==(const JSONIterator& rhs) const {
196  if(!current_node_ && !rhs.current_node_) {
197  return true;
198  }
199 
200  return ((stream_.get() == rhs.stream_.get()) &&
201  (current_node_->start() == rhs.current_node_->start()));
202  }
203 
204  bool operator!=(const JSONIterator& rhs) const {
205  return !((*this) == rhs);
206  }
207 
208  bool is_array_iterator() const {
209  return is_array_iterator_;
210  }
211 };
212 
213 template<typename T>
214 optional<T> json_auto_cast(JSONIterator it);
215 
216 template<>
217 inline optional<int> json_auto_cast<int>(JSONIterator it) {
218  return optional<int>(it->to_int().value());
219 }
220 
221 template<>
222 inline optional<long> json_auto_cast<long>(JSONIterator it) {
223  return optional<long>(it->to_int().value());
224 }
225 
226 template<>
227 inline optional<float> json_auto_cast<float>(JSONIterator it) {
228  return it->to_float();
229 }
230 
231 template<>
232 inline optional<bool> json_auto_cast<bool>(JSONIterator it) {
233  return it->to_bool();
234 }
235 
236 template<>
237 inline optional<std::string> json_auto_cast<std::string>(JSONIterator it) {
238  return optional<std::string>(it->to_str());
239 }
240 
241 JSONIterator json_load(const Path& path);
242 JSONIterator json_parse(const std::string& data);
243 JSONIterator json_read(std::shared_ptr<std::istream> stream);
244 
245 }
smlt::JSONIterator
Definition: json.h:135
smlt
Definition: animation.cpp:25
smlt::JSONNode
Definition: json.h:29
smlt::optional
Definition: optional.h:13
smlt::Path
Definition: path.h:7