1 | /*! |
2 | * Copyright (c) 2015 by Contributors |
3 | * \file json.h |
4 | * \brief Lightweight JSON Reader/Writer that read save into C++ data structs. |
5 | * This includes STL composites and structures. |
6 | */ |
7 | #ifndef DMLC_JSON_H_ |
8 | #define DMLC_JSON_H_ |
9 | |
10 | // This code requires C++11 to compile |
11 | #include <vector> |
12 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
13 | #include <iostream> |
14 | #include <sstream> |
15 | #endif |
16 | #include <cctype> |
17 | #include <string> |
18 | #include <algorithm> |
19 | #include <map> |
20 | #include <list> |
21 | #include <utility> |
22 | |
23 | #include "./base.h" |
24 | #include "./logging.h" |
25 | #include "./type_traits.h" |
26 | |
27 | #if DMLC_USE_CXX11 |
28 | #include <typeindex> |
29 | #include <typeinfo> |
30 | #include <unordered_map> |
31 | #if DMLC_STRICT_CXX11 |
32 | #if DMLC_ENABLE_RTTI |
33 | #include "./any.h" |
34 | #endif // DMLC_ENABLE_RTTI |
35 | #endif // DMLC_STRICT_CXX11 |
36 | #endif // DMLC_USE_CXX11 |
37 | |
38 | namespace dmlc { |
39 | /*! |
40 | * \brief Lightweight JSON Reader to read any STL compositions and structs. |
41 | * The user need to know the schema of the |
42 | * |
43 | */ |
44 | class JSONReader { |
45 | public: |
46 | /*! |
47 | * \brief Constructor. |
48 | * \param is the input source. |
49 | */ |
50 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
51 | explicit JSONReader(std::istream *is) |
52 | #else |
53 | explicit JSONReader(std::string *is) |
54 | #endif |
55 | : is_(is), |
56 | line_count_r_(0), |
57 | line_count_n_(0) {} |
58 | /*! |
59 | * \brief Parse next JSON string. |
60 | * \param out_str the output string. |
61 | * \throw dmlc::Error when next token is not string |
62 | */ |
63 | inline void ReadString(std::string *out_str); |
64 | /*! |
65 | * \brief Read Number. |
66 | * \param out_value output value; |
67 | * \throw dmlc::Error when next token is not number of ValueType. |
68 | * \tparam ValueType type of the number |
69 | */ |
70 | template<typename ValueType> |
71 | inline void ReadNumber(ValueType *out_value); |
72 | /*! |
73 | * \brief Begin parsing an object. |
74 | * \code |
75 | * std::string key; |
76 | * // value can be any type that is json serializable. |
77 | * std::string value; |
78 | * reader->BeginObject(); |
79 | * while (reader->NextObjectItem(&key)) { |
80 | * // do somthing to key value |
81 | * reader->Read(&value); |
82 | * } |
83 | * \endcode |
84 | */ |
85 | inline void BeginObject(); |
86 | /*! |
87 | * \brief Begin parsing an array. |
88 | * \code |
89 | * // value can be any type that is json serializable. |
90 | * std::string value; |
91 | * reader->BeginArray(); |
92 | * while (reader->NextArrayItem()) { |
93 | * reader->Read(&value); |
94 | * // do somthing to value |
95 | * } |
96 | * \endcode |
97 | */ |
98 | inline void BeginArray(); |
99 | /*! |
100 | * \brief Try to move to next object item. |
101 | * If this call is successful, user can proceed to call |
102 | * reader->Read to read in the value. |
103 | * \param out_key the key to the next object. |
104 | * \return true if the read is successful, false if we are at end of the object. |
105 | */ |
106 | inline bool NextObjectItem(std::string *out_key); |
107 | /*! |
108 | * \brief Try to read the next element in the array. |
109 | * If this call is successful, user can proceed to call |
110 | * reader->Read to read in the value. |
111 | * \return true if the read is successful, false if we are at end of the array. |
112 | */ |
113 | inline bool NextArrayItem(); |
114 | /*! |
115 | * \brief Read next ValueType. |
116 | * \param out_value any STL or json readable type to be read |
117 | * \throw dmlc::Error when the read of ValueType is not successful. |
118 | * \tparam ValueType the data type to be read. |
119 | */ |
120 | template<typename ValueType> |
121 | inline void Read(ValueType *out_value); |
122 | |
123 | /*! \return current line count */ |
124 | inline std::string line_info() const { |
125 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
126 | char temp[64]; |
127 | std::ostringstream os; |
128 | os << " Line " << std::max(line_count_r_, line_count_n_); |
129 | is_->getline(temp, 64); |
130 | os << ", around ^`" << temp << "`" ; |
131 | return os.str(); |
132 | #else |
133 | std::string info = " Line " ; |
134 | info += std::to_string(std::max(line_count_r_, line_count_n_)); |
135 | |
136 | // string getline |
137 | size_t end_pos = is_->find('\n'); |
138 | end_pos = std::min(static_cast<size_t>(64), |
139 | end_pos == std::string::npos ? is_->size() : end_pos); |
140 | std::string line = is_->substr(0, end_pos); |
141 | is_->erase(0, line.size() + 1); // +1 for \n |
142 | |
143 | info += ", around ^`" + line + "`" ; |
144 | return info; |
145 | #endif |
146 | } |
147 | |
148 | private: |
149 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
150 | /*! \brief internal reader stream */ |
151 | std::istream *is_; |
152 | #else |
153 | /*! \brief internal reader string */ |
154 | std::string *is_; |
155 | #endif |
156 | /*! \brief "\\r" counter */ |
157 | size_t line_count_r_; |
158 | /*! \brief "\\n" counter */ |
159 | size_t line_count_n_; |
160 | /*! |
161 | * \brief record how many element processed in |
162 | * current array/object scope. |
163 | */ |
164 | std::vector<size_t> scope_counter_; |
165 | /*! |
166 | * \brief Read next nonspace character. |
167 | * \return the next nonspace character. |
168 | */ |
169 | inline int NextNonSpace(); |
170 | /*! |
171 | * \brief Read just before next nonspace but not read that. |
172 | * \return the next nonspace character. |
173 | */ |
174 | inline int PeekNextNonSpace(); |
175 | /*! |
176 | * \brief Takes the next char from the input source. |
177 | * \return the next character. |
178 | */ |
179 | inline int NextChar(); |
180 | /*! |
181 | * \brief Returns the next char from the input source. |
182 | * \return the next character. |
183 | */ |
184 | inline int PeekNextChar(); |
185 | }; |
186 | |
187 | /*! |
188 | * \brief Lightweight json to write any STL compositions. |
189 | */ |
190 | class JSONWriter { |
191 | public: |
192 | /*! |
193 | * \brief Constructor. |
194 | * \param os the output reciever. |
195 | */ |
196 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
197 | explicit JSONWriter(std::ostream *os) |
198 | #else |
199 | explicit JSONWriter(std::string *os) |
200 | #endif |
201 | : os_(os) {} |
202 | /*! |
203 | * \brief Write a string that do not contain escape characters. |
204 | * \param s the string to be written. |
205 | */ |
206 | inline void WriteNoEscape(const std::string &s); |
207 | /*! |
208 | * \brief Write a string that can contain escape characters. |
209 | * \param s the string to be written. |
210 | */ |
211 | inline void WriteString(const std::string &s); |
212 | /*! |
213 | * \brief Write a string that can contain escape characters. |
214 | * \param v the value to be written. |
215 | * \tparam ValueType The value type to be written. |
216 | */ |
217 | template<typename ValueType> |
218 | inline void WriteNumber(const ValueType &v); |
219 | /*! |
220 | * \brief Start beginning of array. |
221 | * \param multi_line whether to start an multi_line array. |
222 | * \code |
223 | * writer->BeginArray(); |
224 | * for (auto& v : vdata) { |
225 | * writer->WriteArrayItem(v); |
226 | * } |
227 | * writer->EndArray(); |
228 | * \endcode |
229 | */ |
230 | inline void BeginArray(bool multi_line = true); |
231 | /*! \brief Finish writing an array. */ |
232 | inline void EndArray(); |
233 | /*! |
234 | * \brief Start beginning of array. |
235 | * \param multi_line whether to start an multi_line array. |
236 | * \code |
237 | * writer->BeginObject(); |
238 | * for (auto& kv : vmap) { |
239 | * writer->WriteObjectKeyValue(kv.first, kv.second); |
240 | * } |
241 | * writer->EndObject(); |
242 | * \endcode |
243 | */ |
244 | inline void BeginObject(bool multi_line = true); |
245 | /*! \brief Finish writing object. */ |
246 | inline void EndObject(); |
247 | /*! |
248 | * \brief Write key value pair in the object. |
249 | * \param key the key of the object. |
250 | * \param value the value of to be written. |
251 | * \tparam ValueType The value type to be written. |
252 | */ |
253 | template<typename ValueType> |
254 | inline void WriteObjectKeyValue(const std::string &key, |
255 | const ValueType &value); |
256 | /*! |
257 | * \brief Write seperator of array, before writing next element. |
258 | * User can proceed to call writer->Write to write next item |
259 | */ |
260 | inline void WriteArraySeperator(); |
261 | /*! |
262 | * \brief Write value into array. |
263 | * \param value The value of to be written. |
264 | * \tparam ValueType The value type to be written. |
265 | */ |
266 | template<typename ValueType> |
267 | inline void WriteArrayItem(const ValueType &value); |
268 | /*! |
269 | * \brief Write value to json. |
270 | * \param value any STL or json readable that can be written. |
271 | * \tparam ValueType the data type to be write. |
272 | */ |
273 | template<typename ValueType> |
274 | inline void Write(const ValueType &value); |
275 | |
276 | private: |
277 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
278 | /*! \brief Output stream */ |
279 | std::ostream *os_; |
280 | #else |
281 | std::string *os_; |
282 | #endif |
283 | /*! |
284 | * \brief record how many element processed in |
285 | * current array/object scope. |
286 | */ |
287 | std::vector<size_t> scope_counter_; |
288 | /*! \brief Record whether current is a multiline scope */ |
289 | std::vector<bool> scope_multi_line_; |
290 | /*! |
291 | * \brief Write seperating space and newlines |
292 | */ |
293 | inline void WriteSeperator(); |
294 | }; |
295 | |
296 | /*! |
297 | * \brief Helper class to read JSON into a class or struct object. |
298 | * \code |
299 | * struct Param { |
300 | * std::string name; |
301 | * int value; |
302 | * // define load function from JSON |
303 | * inline void Load(dmlc::JSONReader *reader) { |
304 | * dmlc::JSONStructReadHelper helper; |
305 | * helper.DeclareField("name", &name); |
306 | * helper.DeclareField("value", &value); |
307 | * helper.ReadAllFields(reader); |
308 | * } |
309 | * }; |
310 | * \endcode |
311 | */ |
312 | class JSONObjectReadHelper { |
313 | public: |
314 | /*! |
315 | * \brief Declare field of type T |
316 | * \param key the key of the of field. |
317 | * \param addr address of the data type. |
318 | * \tparam T the data type to be read, must be STL composition of JSON serializable. |
319 | */ |
320 | template<typename T> |
321 | inline void DeclareField(const std::string &key, T *addr) { |
322 | DeclareFieldInternal(key, addr, false); |
323 | } |
324 | /*! |
325 | * \brief Declare optional field of type T |
326 | * \param key the key of the of field. |
327 | * \param addr address of the data type. |
328 | * \tparam T the data type to be read, must be STL composition of JSON serializable. |
329 | */ |
330 | template<typename T> |
331 | inline void DeclareOptionalField(const std::string &key, T *addr) { |
332 | DeclareFieldInternal(key, addr, true); |
333 | } |
334 | /*! |
335 | * \brief Read in all the declared fields. |
336 | * \param reader the JSONReader to read the json. |
337 | */ |
338 | inline void ReadAllFields(JSONReader *reader); |
339 | |
340 | private: |
341 | /*! |
342 | * \brief Internal function to declare field. |
343 | * \param key the key of the of field. |
344 | * \param addr address of the data type. |
345 | * \param optional if set to true, no error will be reported if the key is not presented. |
346 | * \tparam T the data type to be read, must be STL composition of JSON serializable. |
347 | */ |
348 | template<typename T> |
349 | inline void DeclareFieldInternal(const std::string &key, T *addr, bool optional); |
350 | /*! |
351 | * \brief The internal reader function. |
352 | * \param reader The reader to read. |
353 | * \param addr The memory address to read. |
354 | */ |
355 | template<typename T> |
356 | inline static void ReaderFunction(JSONReader *reader, void *addr); |
357 | /*! \brief callback type to reader function */ |
358 | typedef void (*ReadFunction)(JSONReader *reader, void *addr); |
359 | /*! \brief internal data entry */ |
360 | struct Entry { |
361 | /*! \brief the reader function */ |
362 | ReadFunction func; |
363 | /*! \brief the address to read */ |
364 | void *addr; |
365 | /*! \brief whether it is optional */ |
366 | bool optional; |
367 | }; |
368 | /*! \brief the internal map of reader callbacks */ |
369 | std::map<std::string, Entry> map_; |
370 | }; |
371 | |
372 | #define DMLC_JSON_ENABLE_ANY_VAR_DEF(KeyName) \ |
373 | static DMLC_ATTRIBUTE_UNUSED ::dmlc::json::AnyJSONManager& \ |
374 | __make_AnyJSONType ## _ ## KeyName ## __ |
375 | |
376 | /*! |
377 | * \def DMLC_JSON_ENABLE_ANY |
378 | * \brief Macro to enable save/load JSON of dmlc:: whose actual type is Type. |
379 | * Any type will be saved as json array [KeyName, content] |
380 | * |
381 | * \param Type The type to be registered. |
382 | * \param KeyName The Type key assigned to the type, must be same during load. |
383 | */ |
384 | #define DMLC_JSON_ENABLE_ANY(Type, KeyName) \ |
385 | DMLC_STR_CONCAT(DMLC_JSON_ENABLE_ANY_VAR_DEF(KeyName), __COUNTER__) = \ |
386 | ::dmlc::json::AnyJSONManager::Global()->EnableType<Type>(#KeyName) \ |
387 | |
388 | //! \cond Doxygen_Suppress |
389 | namespace json { |
390 | |
391 | /*! |
392 | * \brief generic serialization handler |
393 | * \tparam T the type to be serialized |
394 | */ |
395 | template<typename T> |
396 | struct Handler; |
397 | |
398 | template<typename ValueType> |
399 | struct NumericHandler { |
400 | inline static void Write(JSONWriter *writer, const ValueType &value) { |
401 | writer->WriteNumber<ValueType>(value); |
402 | } |
403 | inline static void Read(JSONReader *reader, ValueType *value) { |
404 | reader->ReadNumber<ValueType>(value); |
405 | } |
406 | }; |
407 | |
408 | template<typename ContainerType> |
409 | struct ArrayHandler { |
410 | inline static void Write(JSONWriter *writer, const ContainerType &array) { |
411 | typedef typename ContainerType::value_type ElemType; |
412 | writer->BeginArray(array.size() > 10 || !dmlc::is_pod<ElemType>::value); |
413 | for (typename ContainerType::const_iterator it = array.begin(); |
414 | it != array.end(); ++it) { |
415 | writer->WriteArrayItem(*it); |
416 | } |
417 | writer->EndArray(); |
418 | } |
419 | inline static void Read(JSONReader *reader, ContainerType *array) { |
420 | typedef typename ContainerType::value_type ElemType; |
421 | array->clear(); |
422 | reader->BeginArray(); |
423 | while (reader->NextArrayItem()) { |
424 | ElemType value; |
425 | Handler<ElemType>::Read(reader, &value); |
426 | array->insert(array->end(), value); |
427 | } |
428 | } |
429 | }; |
430 | |
431 | template<typename ContainerType> |
432 | struct MapHandler{ |
433 | inline static void Write(JSONWriter *writer, const ContainerType &map) { |
434 | writer->BeginObject(map.size() > 1); |
435 | for (typename ContainerType::const_iterator it = map.begin(); it != map.end(); ++it) { |
436 | writer->WriteObjectKeyValue(it->first, it->second); |
437 | } |
438 | writer->EndObject(); |
439 | } |
440 | inline static void Read(JSONReader *reader, ContainerType *map) { |
441 | typedef typename ContainerType::mapped_type ElemType; |
442 | map->clear(); |
443 | reader->BeginObject(); |
444 | std::string key; |
445 | while (reader->NextObjectItem(&key)) { |
446 | ElemType value; |
447 | reader->Read(&value); |
448 | (*map)[key] = value; |
449 | } |
450 | } |
451 | }; |
452 | |
453 | template<typename T> |
454 | struct CommonJSONSerializer { |
455 | inline static void Write(JSONWriter *writer, const T &value) { |
456 | value.Save(writer); |
457 | } |
458 | inline static void Read(JSONReader *reader, T *value) { |
459 | value->Load(reader); |
460 | } |
461 | }; |
462 | |
463 | template<> |
464 | struct Handler<std::string> { |
465 | inline static void Write(JSONWriter *writer, const std::string &value) { |
466 | writer->WriteString(value); |
467 | } |
468 | inline static void Read(JSONReader *reader, std::string *str) { |
469 | reader->ReadString(str); |
470 | } |
471 | }; |
472 | |
473 | template<typename T> |
474 | struct Handler<std::vector<T> > : public ArrayHandler<std::vector<T> > { |
475 | }; |
476 | |
477 | template<typename K, typename V> |
478 | struct Handler<std::pair<K, V> > { |
479 | inline static void Write(JSONWriter *writer, const std::pair<K, V> &kv) { |
480 | writer->BeginArray(); |
481 | writer->WriteArrayItem(kv.first); |
482 | writer->WriteArrayItem(kv.second); |
483 | writer->EndArray(); |
484 | } |
485 | inline static void Read(JSONReader *reader, std::pair<K, V> *kv) { |
486 | reader->BeginArray(); |
487 | CHECK(reader->NextArrayItem()) |
488 | << "Expect array of length 2" ; |
489 | Handler<K>::Read(reader, &(kv->first)); |
490 | CHECK(reader->NextArrayItem()) |
491 | << "Expect array of length 2" ; |
492 | Handler<V>::Read(reader, &(kv->second)); |
493 | CHECK(!reader->NextArrayItem()) |
494 | << "Expect array of length 2" ; |
495 | } |
496 | }; |
497 | |
498 | template<typename T> |
499 | struct Handler<std::list<T> > : public ArrayHandler<std::list<T> > { |
500 | }; |
501 | |
502 | template<typename V> |
503 | struct Handler<std::map<std::string, V> > : public MapHandler<std::map<std::string, V> > { |
504 | }; |
505 | |
506 | #if DMLC_USE_CXX11 |
507 | template<typename V> |
508 | struct Handler<std::unordered_map<std::string, V> > |
509 | : public MapHandler<std::unordered_map<std::string, V> > { |
510 | }; |
511 | #endif // DMLC_USE_CXX11 |
512 | |
513 | template<typename T> |
514 | struct Handler { |
515 | inline static void Write(JSONWriter *writer, const T &data) { |
516 | typedef typename dmlc::IfThenElseType<dmlc::is_arithmetic<T>::value, |
517 | NumericHandler<T>, |
518 | CommonJSONSerializer<T> >::Type THandler; |
519 | THandler::Write(writer, data); |
520 | } |
521 | inline static void Read(JSONReader *reader, T *data) { |
522 | typedef typename dmlc::IfThenElseType<dmlc::is_arithmetic<T>::value, |
523 | NumericHandler<T>, |
524 | CommonJSONSerializer<T> >::Type THandler; |
525 | THandler::Read(reader, data); |
526 | } |
527 | }; |
528 | |
529 | #if DMLC_STRICT_CXX11 |
530 | #if DMLC_ENABLE_RTTI |
531 | // Manager to store json serialization strategy. |
532 | class AnyJSONManager { |
533 | public: |
534 | template<typename T> |
535 | inline AnyJSONManager& EnableType(const std::string& type_name) { // NOLINT(*) |
536 | std::type_index tp = std::type_index(typeid(T)); |
537 | if (type_name_.count(tp) != 0) { |
538 | CHECK(type_name_.at(tp) == type_name) |
539 | << "Type has already been registered as another typename " << type_name_.at(tp); |
540 | return *this; |
541 | } |
542 | CHECK(type_map_.count(type_name) == 0) |
543 | << "Type name " << type_name << " already registered in registry" ; |
544 | Entry e; |
545 | e.read = ReadAny<T>; |
546 | e.write = WriteAny<T>; |
547 | type_name_[tp] = type_name; |
548 | type_map_[type_name] = e; |
549 | return *this; |
550 | } |
551 | // return global singleton |
552 | inline static AnyJSONManager* Global() { |
553 | static AnyJSONManager inst; |
554 | return &inst; |
555 | } |
556 | |
557 | private: |
558 | AnyJSONManager() {} |
559 | |
560 | template<typename T> |
561 | inline static void WriteAny(JSONWriter *writer, const any &data) { |
562 | writer->Write(dmlc::unsafe_get<T>(data)); |
563 | } |
564 | template<typename T> |
565 | inline static void ReadAny(JSONReader *reader, any* data) { |
566 | T temp; |
567 | reader->Read(&temp); |
568 | *data = std::move(temp); |
569 | } |
570 | // data entry to store vtable for any type |
571 | struct Entry { |
572 | void (*read)(JSONReader* reader, any *data); |
573 | void (*write)(JSONWriter* reader, const any& data); |
574 | }; |
575 | |
576 | template<typename T> |
577 | friend struct Handler; |
578 | |
579 | std::unordered_map<std::type_index, std::string> type_name_; |
580 | std::unordered_map<std::string, Entry> type_map_; |
581 | }; |
582 | |
583 | template<> |
584 | struct Handler<any> { |
585 | inline static void Write(JSONWriter *writer, const any &data) { |
586 | std::unordered_map<std::type_index, std::string>& |
587 | nmap = AnyJSONManager::Global()->type_name_; |
588 | std::type_index id = std::type_index(data.type()); |
589 | auto it = nmap.find(id); |
590 | CHECK(it != nmap.end() && it->first == id) |
591 | << "Type " << id.name() << " has not been registered via DMLC_JSON_ENABLE_ANY" ; |
592 | std::string type_name = it->second; |
593 | AnyJSONManager::Entry e = AnyJSONManager::Global()->type_map_.at(type_name); |
594 | writer->BeginArray(false); |
595 | writer->WriteArrayItem(type_name); |
596 | writer->WriteArraySeperator(); |
597 | e.write(writer, data); |
598 | writer->EndArray(); |
599 | } |
600 | inline static void Read(JSONReader *reader, any *data) { |
601 | std::string type_name; |
602 | reader->BeginArray(); |
603 | CHECK(reader->NextArrayItem()) << "invalid any json format" ; |
604 | Handler<std::string>::Read(reader, &type_name); |
605 | std::unordered_map<std::string, AnyJSONManager::Entry>& |
606 | tmap = AnyJSONManager::Global()->type_map_; |
607 | auto it = tmap.find(type_name); |
608 | CHECK(it != tmap.end() && it->first == type_name) |
609 | << "Typename " << type_name << " has not been registered via DMLC_JSON_ENABLE_ANY" ; |
610 | AnyJSONManager::Entry e = it->second; |
611 | CHECK(reader->NextArrayItem()) << "invalid any json format" ; |
612 | e.read(reader, data); |
613 | CHECK(!reader->NextArrayItem()) << "invalid any json format" ; |
614 | } |
615 | }; |
616 | #endif // DMLC_ENABLE_RTTI |
617 | #endif // DMLC_STRICT_CXX11 |
618 | |
619 | } // namespace json |
620 | |
621 | // implementations of JSONReader/Writer |
622 | inline int JSONReader::NextChar() { |
623 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
624 | return is_->get(); |
625 | #else |
626 | int ch = is_->at(0); |
627 | is_->erase(0, 1); |
628 | return ch; |
629 | #endif |
630 | } |
631 | |
632 | inline int JSONReader::PeekNextChar() { |
633 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
634 | return is_->peek(); |
635 | #else |
636 | return is_->at(0); |
637 | #endif |
638 | } |
639 | |
640 | inline int JSONReader::NextNonSpace() { |
641 | int ch; |
642 | do { |
643 | ch = NextChar(); |
644 | if (ch == '\n') ++line_count_n_; |
645 | if (ch == '\r') ++line_count_r_; |
646 | } while (isspace(ch)); |
647 | return ch; |
648 | } |
649 | |
650 | inline int JSONReader::PeekNextNonSpace() { |
651 | int ch; |
652 | while (true) { |
653 | ch = PeekNextChar(); |
654 | if (ch == '\n') ++line_count_n_; |
655 | if (ch == '\r') ++line_count_r_; |
656 | if (!isspace(ch)) break; |
657 | NextChar(); |
658 | } |
659 | return ch; |
660 | } |
661 | |
662 | namespace { |
663 | template<typename T> |
664 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
665 | void Extend(std::ostream *os, T item) { |
666 | *os << item; |
667 | } |
668 | #else |
669 | void Extend(std::string *ostr, T item) { |
670 | *ostr += item; |
671 | } |
672 | #endif |
673 | } // namespace |
674 | |
675 | inline void JSONReader::ReadString(std::string *out_str) { |
676 | int ch = NextNonSpace(); |
677 | CHECK_EQ(ch, '\"') |
678 | << "Error at" << line_info() |
679 | << ", Expect \'\"\' but get \'" << static_cast<char>(ch) << '\''; |
680 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
681 | std::ostringstream output; |
682 | #else |
683 | std::string output = "" ; |
684 | #endif |
685 | while (true) { |
686 | ch = NextChar(); |
687 | if (ch == '\\') { |
688 | char sch = static_cast<char>(NextChar()); |
689 | switch (sch) { |
690 | case 'r': Extend(&output, "\r" ); break; |
691 | case 'n': Extend(&output, "\n" ); break; |
692 | case '\\': Extend(&output, "\\" ); break; |
693 | case 't': Extend(&output, "\t" ); break; |
694 | case '\"': Extend(&output, "\"" ); break; |
695 | default: LOG(FATAL) << "unknown string escape \\" << sch; |
696 | } |
697 | } else { |
698 | if (ch == '\"') break; |
699 | Extend(&output, static_cast<char>(ch)); |
700 | } |
701 | if (ch == EOF || ch == '\r' || ch == '\n') { |
702 | LOG(FATAL) |
703 | << "Error at" << line_info() |
704 | << ", Expect \'\"\' but reach end of line " ; |
705 | } |
706 | } |
707 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
708 | *out_str = output.str(); |
709 | #else |
710 | *out_str = output; |
711 | #endif |
712 | } |
713 | |
714 | template<typename ValueType> |
715 | inline void JSONReader::ReadNumber(ValueType *out_value) { |
716 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
717 | *is_ >> *out_value; |
718 | CHECK(!is_->fail()) |
719 | << "Error at" << line_info() |
720 | << ", Expect number" ; |
721 | #else |
722 | char* endptr; |
723 | const char* icstr = is_->c_str(); |
724 | unsigned number = strtol(icstr, &endptr, 10); |
725 | is_->erase(0, endptr - icstr); |
726 | *out_value = static_cast<ValueType>(number); |
727 | #endif |
728 | } |
729 | |
730 | inline void JSONReader::BeginObject() { |
731 | int ch = NextNonSpace(); |
732 | CHECK_EQ(ch, '{') |
733 | << "Error at" << line_info() |
734 | << ", Expect \'{\' but get \'" << static_cast<char>(ch) << '\''; |
735 | scope_counter_.push_back(0); |
736 | } |
737 | |
738 | inline void JSONReader::BeginArray() { |
739 | int ch = NextNonSpace(); |
740 | CHECK_EQ(ch, '[') |
741 | << "Error at" << line_info() |
742 | << ", Expect \'[\' but get \'" << static_cast<char>(ch) << '\''; |
743 | scope_counter_.push_back(0); |
744 | } |
745 | |
746 | inline bool JSONReader::NextObjectItem(std::string *out_key) { |
747 | bool next = true; |
748 | if (scope_counter_.back() != 0) { |
749 | int ch = NextNonSpace(); |
750 | if (ch == EOF) { |
751 | next = false; |
752 | } else if (ch == '}') { |
753 | next = false; |
754 | } else { |
755 | CHECK_EQ(ch, ',') |
756 | << "Error at" << line_info() |
757 | << ", JSON object expect \'}\' or \',\' \'" << static_cast<char>(ch) << '\''; |
758 | } |
759 | } else { |
760 | int ch = PeekNextNonSpace(); |
761 | if (ch == '}') { |
762 | NextChar(); |
763 | next = false; |
764 | } |
765 | } |
766 | if (!next) { |
767 | scope_counter_.pop_back(); |
768 | return false; |
769 | } else { |
770 | scope_counter_.back() += 1; |
771 | ReadString(out_key); |
772 | int ch = NextNonSpace(); |
773 | CHECK_EQ(ch, ':') |
774 | << "Error at" << line_info() |
775 | << ", Expect \':\' but get \'" << static_cast<char>(ch) << '\''; |
776 | return true; |
777 | } |
778 | } |
779 | |
780 | inline bool JSONReader::NextArrayItem() { |
781 | bool next = true; |
782 | if (scope_counter_.back() != 0) { |
783 | int ch = NextNonSpace(); |
784 | if (ch == EOF) { |
785 | next = false; |
786 | } else if (ch == ']') { |
787 | next = false; |
788 | } else { |
789 | CHECK_EQ(ch, ',') |
790 | << "Error at" << line_info() |
791 | << ", JSON array expect \']\' or \',\'. Get \'" << static_cast<char>(ch) << "\' instead" ; |
792 | } |
793 | } else { |
794 | int ch = PeekNextNonSpace(); |
795 | if (ch == ']') { |
796 | NextChar(); |
797 | next = false; |
798 | } |
799 | } |
800 | if (!next) { |
801 | scope_counter_.pop_back(); |
802 | return false; |
803 | } else { |
804 | scope_counter_.back() += 1; |
805 | return true; |
806 | } |
807 | } |
808 | |
809 | template<typename ValueType> |
810 | inline void JSONReader::Read(ValueType *out_value) { |
811 | json::Handler<ValueType>::Read(this, out_value); |
812 | } |
813 | |
814 | inline void JSONWriter::WriteNoEscape(const std::string &s) { |
815 | Extend(os_, '\"'); |
816 | Extend(os_, s); |
817 | Extend(os_, '\"'); |
818 | } |
819 | |
820 | inline void JSONWriter::WriteString(const std::string &s) { |
821 | Extend(os_, '\"'); |
822 | for (size_t i = 0; i < s.length(); ++i) { |
823 | char ch = s[i]; |
824 | switch (ch) { |
825 | case '\r': Extend(os_, "\\r" ); break; |
826 | case '\n': Extend(os_, "\\n" ); break; |
827 | case '\\': Extend(os_, "\\\\" ); break; |
828 | case '\t': Extend(os_, "\\t" ); break; |
829 | case '\"': Extend(os_, "\\\"" ); break; |
830 | default: Extend(os_, ch); |
831 | } |
832 | } |
833 | Extend(os_, '\"'); |
834 | } |
835 | |
836 | template<typename ValueType> |
837 | inline void JSONWriter::WriteNumber(const ValueType &v) { |
838 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
839 | Extend(os_, v); |
840 | #else |
841 | Extend(os_, std::to_string(v)); |
842 | #endif |
843 | } |
844 | |
845 | inline void JSONWriter::BeginArray(bool multi_line) { |
846 | Extend(os_, '['); |
847 | scope_multi_line_.push_back(multi_line); |
848 | scope_counter_.push_back(0); |
849 | } |
850 | |
851 | inline void JSONWriter::EndArray() { |
852 | CHECK_NE(scope_multi_line_.size(), 0U); |
853 | CHECK_NE(scope_counter_.size(), 0U); |
854 | bool newline = scope_multi_line_.back(); |
855 | size_t nelem = scope_counter_.back(); |
856 | scope_multi_line_.pop_back(); |
857 | scope_counter_.pop_back(); |
858 | if (newline && nelem != 0) WriteSeperator(); |
859 | Extend(os_, ']'); |
860 | } |
861 | |
862 | inline void JSONWriter::BeginObject(bool multi_line) { |
863 | Extend(os_, '{'); |
864 | scope_multi_line_.push_back(multi_line); |
865 | scope_counter_.push_back(0); |
866 | } |
867 | |
868 | inline void JSONWriter::EndObject() { |
869 | CHECK_NE(scope_multi_line_.size(), 0U); |
870 | CHECK_NE(scope_counter_.size(), 0U); |
871 | bool newline = scope_multi_line_.back(); |
872 | size_t nelem = scope_counter_.back(); |
873 | scope_multi_line_.pop_back(); |
874 | scope_counter_.pop_back(); |
875 | if (newline && nelem != 0) WriteSeperator(); |
876 | Extend(os_, '}'); |
877 | } |
878 | |
879 | template<typename ValueType> |
880 | inline void JSONWriter::WriteObjectKeyValue(const std::string &key, |
881 | const ValueType &value) { |
882 | if (scope_counter_.back() > 0) { |
883 | Extend(os_, ", " ); |
884 | } |
885 | WriteSeperator(); |
886 | Extend(os_, '\"'); |
887 | Extend(os_, key); |
888 | Extend(os_, "\": " ); |
889 | scope_counter_.back() += 1; |
890 | json::Handler<ValueType>::Write(this, value); |
891 | } |
892 | |
893 | inline void JSONWriter::WriteArraySeperator() { |
894 | if (scope_counter_.back() != 0) { |
895 | Extend(os_, ", " ); |
896 | } |
897 | scope_counter_.back() += 1; |
898 | WriteSeperator(); |
899 | } |
900 | |
901 | template<typename ValueType> |
902 | inline void JSONWriter::WriteArrayItem(const ValueType &value) { |
903 | this->WriteArraySeperator(); |
904 | json::Handler<ValueType>::Write(this, value); |
905 | } |
906 | |
907 | template<typename ValueType> |
908 | inline void JSONWriter::Write(const ValueType &value) { |
909 | size_t nscope = scope_multi_line_.size(); |
910 | json::Handler<ValueType>::Write(this, value); |
911 | CHECK_EQ(nscope, scope_multi_line_.size()) |
912 | << "Uneven scope, did you call EndArray/EndObject after each BeginObject/Array?" ; |
913 | } |
914 | |
915 | inline void JSONWriter::WriteSeperator() { |
916 | if (scope_multi_line_.size() == 0 || scope_multi_line_.back()) { |
917 | Extend(os_, '\n'); |
918 | Extend(os_, std::string(scope_multi_line_.size() * 2, ' ')); |
919 | } |
920 | } |
921 | |
922 | inline void JSONObjectReadHelper::ReadAllFields(JSONReader *reader) { |
923 | reader->BeginObject(); |
924 | std::map<std::string, int> visited; |
925 | std::string key; |
926 | while (reader->NextObjectItem(&key)) { |
927 | if (map_.count(key) != 0) { |
928 | Entry e = map_[key]; |
929 | (*e.func)(reader, e.addr); |
930 | visited[key] = 0; |
931 | } else { |
932 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
933 | std::ostringstream err; |
934 | #else |
935 | std::string err("" ); |
936 | #endif |
937 | Extend(&err, "JSONReader: Unknown field " ); |
938 | Extend(&err, key); |
939 | Extend(&err, ", candidates are: \n" ); |
940 | for (std::map<std::string, Entry>::iterator |
941 | it = map_.begin(); it != map_.end(); ++it) { |
942 | Extend(&err, '\"'); |
943 | Extend(&err, it->first); |
944 | Extend(&err, "\"\n" ); |
945 | } |
946 | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
947 | LOG(FATAL) << err.str(); |
948 | #else |
949 | LOG(FATAL) << err; |
950 | #endif |
951 | } |
952 | } |
953 | if (visited.size() != map_.size()) { |
954 | for (std::map<std::string, Entry>::iterator |
955 | it = map_.begin(); it != map_.end(); ++it) { |
956 | if (it->second.optional) continue; |
957 | CHECK_NE(visited.count(it->first), 0U) |
958 | << "JSONReader: Missing field \"" << it->first << "\"\n At " |
959 | << reader->line_info(); |
960 | } |
961 | } |
962 | } |
963 | |
964 | template<typename T> |
965 | inline void JSONObjectReadHelper::ReaderFunction(JSONReader *reader, void *addr) { |
966 | json::Handler<T>::Read(reader, static_cast<T*>(addr)); |
967 | } |
968 | |
969 | template<typename T> |
970 | inline void JSONObjectReadHelper:: |
971 | DeclareFieldInternal(const std::string &key, T *addr, bool optional) { |
972 | CHECK_EQ(map_.count(key), 0U) |
973 | << "Adding duplicate field " << key; |
974 | Entry e; |
975 | e.func = ReaderFunction<T>; |
976 | e.addr = static_cast<void*>(addr); |
977 | e.optional = optional; |
978 | map_[key] = e; |
979 | } |
980 | |
981 | //! \endcond |
982 | } // namespace dmlc |
983 | #endif // DMLC_JSON_H_ |
984 | |