Horizon
json_sax.hpp
1 #pragma once
2 
3 #include <cassert> // assert
4 #include <cstddef>
5 #include <string> // string
6 #include <utility> // move
7 #include <vector> // vector
8 
9 #include <nlohmann/detail/exceptions.hpp>
10 #include <nlohmann/detail/macro_scope.hpp>
11 
12 namespace nlohmann
13 {
14 
23 template<typename BasicJsonType>
24 struct json_sax
25 {
27  using number_integer_t = typename BasicJsonType::number_integer_t;
29  using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
31  using number_float_t = typename BasicJsonType::number_float_t;
33  using string_t = typename BasicJsonType::string_t;
34 
39  virtual bool null() = 0;
40 
46  virtual bool boolean(bool val) = 0;
47 
53  virtual bool number_integer(number_integer_t val) = 0;
54 
60  virtual bool number_unsigned(number_unsigned_t val) = 0;
61 
68  virtual bool number_float(number_float_t val, const string_t& s) = 0;
69 
76  virtual bool string(string_t& val) = 0;
77 
84  virtual bool start_object(std::size_t elements) = 0;
85 
92  virtual bool key(string_t& val) = 0;
93 
98  virtual bool end_object() = 0;
99 
106  virtual bool start_array(std::size_t elements) = 0;
107 
112  virtual bool end_array() = 0;
113 
121  virtual bool parse_error(std::size_t position,
122  const std::string& last_token,
123  const detail::exception& ex) = 0;
124 
125  virtual ~json_sax() = default;
126 };
127 
128 
129 namespace detail
130 {
144 template<typename BasicJsonType>
145 class json_sax_dom_parser
146 {
147  public:
148  using number_integer_t = typename BasicJsonType::number_integer_t;
149  using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
150  using number_float_t = typename BasicJsonType::number_float_t;
151  using string_t = typename BasicJsonType::string_t;
152 
158  explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
159  : root(r), allow_exceptions(allow_exceptions_)
160  {}
161 
162  // make class move-only
163  json_sax_dom_parser(const json_sax_dom_parser&) = delete;
165  json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
166  json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;
167  ~json_sax_dom_parser() = default;
168 
169  bool null()
170  {
171  handle_value(nullptr);
172  return true;
173  }
174 
175  bool boolean(bool val)
176  {
177  handle_value(val);
178  return true;
179  }
180 
181  bool number_integer(number_integer_t val)
182  {
183  handle_value(val);
184  return true;
185  }
186 
187  bool number_unsigned(number_unsigned_t val)
188  {
189  handle_value(val);
190  return true;
191  }
192 
193  bool number_float(number_float_t val, const string_t& /*unused*/)
194  {
195  handle_value(val);
196  return true;
197  }
198 
199  bool string(string_t& val)
200  {
201  handle_value(val);
202  return true;
203  }
204 
205  bool start_object(std::size_t len)
206  {
207  ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
208 
209  if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
210  {
211  JSON_THROW(out_of_range::create(408,
212  "excessive object size: " + std::to_string(len)));
213  }
214 
215  return true;
216  }
217 
218  bool key(string_t& val)
219  {
220  // add null at given key and store the reference for later
221  object_element = &(ref_stack.back()->m_value.object->operator[](val));
222  return true;
223  }
224 
225  bool end_object()
226  {
227  ref_stack.pop_back();
228  return true;
229  }
230 
231  bool start_array(std::size_t len)
232  {
233  ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
234 
235  if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
236  {
237  JSON_THROW(out_of_range::create(408,
238  "excessive array size: " + std::to_string(len)));
239  }
240 
241  return true;
242  }
243 
244  bool end_array()
245  {
246  ref_stack.pop_back();
247  return true;
248  }
249 
250  bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
251  const detail::exception& ex)
252  {
253  errored = true;
254  if (allow_exceptions)
255  {
256  // determine the proper exception type from the id
257  switch ((ex.id / 100) % 100)
258  {
259  case 1:
260  JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
261  case 4:
262  JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
263  // LCOV_EXCL_START
264  case 2:
265  JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
266  case 3:
267  JSON_THROW(*static_cast<const detail::type_error*>(&ex));
268  case 5:
269  JSON_THROW(*static_cast<const detail::other_error*>(&ex));
270  default:
271  assert(false);
272  // LCOV_EXCL_STOP
273  }
274  }
275  return false;
276  }
277 
278  constexpr bool is_errored() const
279  {
280  return errored;
281  }
282 
283  private:
290  template<typename Value>
291  JSON_HEDLEY_RETURNS_NON_NULL
292  BasicJsonType* handle_value(Value&& v)
293  {
294  if (ref_stack.empty())
295  {
296  root = BasicJsonType(std::forward<Value>(v));
297  return &root;
298  }
299 
300  assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
301 
302  if (ref_stack.back()->is_array())
303  {
304  ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
305  return &(ref_stack.back()->m_value.array->back());
306  }
307 
308  assert(ref_stack.back()->is_object());
309  assert(object_element);
310  *object_element = BasicJsonType(std::forward<Value>(v));
311  return object_element;
312  }
313 
315  BasicJsonType& root;
317  std::vector<BasicJsonType*> ref_stack {};
319  BasicJsonType* object_element = nullptr;
321  bool errored = false;
323  const bool allow_exceptions = true;
324 };
325 
326 template<typename BasicJsonType>
327 class json_sax_dom_callback_parser
328 {
329  public:
330  using number_integer_t = typename BasicJsonType::number_integer_t;
331  using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
332  using number_float_t = typename BasicJsonType::number_float_t;
333  using string_t = typename BasicJsonType::string_t;
334  using parser_callback_t = typename BasicJsonType::parser_callback_t;
335  using parse_event_t = typename BasicJsonType::parse_event_t;
336 
337  json_sax_dom_callback_parser(BasicJsonType& r,
338  const parser_callback_t cb,
339  const bool allow_exceptions_ = true)
340  : root(r), callback(cb), allow_exceptions(allow_exceptions_)
341  {
342  keep_stack.push_back(true);
343  }
344 
345  // make class move-only
346  json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
347  json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;
348  json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
349  json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default;
350  ~json_sax_dom_callback_parser() = default;
351 
352  bool null()
353  {
354  handle_value(nullptr);
355  return true;
356  }
357 
358  bool boolean(bool val)
359  {
360  handle_value(val);
361  return true;
362  }
363 
364  bool number_integer(number_integer_t val)
365  {
366  handle_value(val);
367  return true;
368  }
369 
370  bool number_unsigned(number_unsigned_t val)
371  {
372  handle_value(val);
373  return true;
374  }
375 
376  bool number_float(number_float_t val, const string_t& /*unused*/)
377  {
378  handle_value(val);
379  return true;
380  }
381 
382  bool string(string_t& val)
383  {
384  handle_value(val);
385  return true;
386  }
387 
388  bool start_object(std::size_t len)
389  {
390  // check callback for object start
391  const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
392  keep_stack.push_back(keep);
393 
394  auto val = handle_value(BasicJsonType::value_t::object, true);
395  ref_stack.push_back(val.second);
396 
397  // check object limit
398  if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
399  {
400  JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len)));
401  }
402 
403  return true;
404  }
405 
406  bool key(string_t& val)
407  {
408  BasicJsonType k = BasicJsonType(val);
409 
410  // check callback for key
411  const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
412  key_keep_stack.push_back(keep);
413 
414  // add discarded value at given key and store the reference for later
415  if (keep and ref_stack.back())
416  {
417  object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
418  }
419 
420  return true;
421  }
422 
423  bool end_object()
424  {
425  if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
426  {
427  // discard object
428  *ref_stack.back() = discarded;
429  }
430 
431  assert(not ref_stack.empty());
432  assert(not keep_stack.empty());
433  ref_stack.pop_back();
434  keep_stack.pop_back();
435 
436  if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_object())
437  {
438  // remove discarded value
439  for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
440  {
441  if (it->is_discarded())
442  {
443  ref_stack.back()->erase(it);
444  break;
445  }
446  }
447  }
448 
449  return true;
450  }
451 
452  bool start_array(std::size_t len)
453  {
454  const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
455  keep_stack.push_back(keep);
456 
457  auto val = handle_value(BasicJsonType::value_t::array, true);
458  ref_stack.push_back(val.second);
459 
460  // check array limit
461  if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
462  {
463  JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len)));
464  }
465 
466  return true;
467  }
468 
469  bool end_array()
470  {
471  bool keep = true;
472 
473  if (ref_stack.back())
474  {
475  keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
476  if (not keep)
477  {
478  // discard array
479  *ref_stack.back() = discarded;
480  }
481  }
482 
483  assert(not ref_stack.empty());
484  assert(not keep_stack.empty());
485  ref_stack.pop_back();
486  keep_stack.pop_back();
487 
488  // remove discarded value
489  if (not keep and not ref_stack.empty() and ref_stack.back()->is_array())
490  {
491  ref_stack.back()->m_value.array->pop_back();
492  }
493 
494  return true;
495  }
496 
497  bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
498  const detail::exception& ex)
499  {
500  errored = true;
501  if (allow_exceptions)
502  {
503  // determine the proper exception type from the id
504  switch ((ex.id / 100) % 100)
505  {
506  case 1:
507  JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
508  case 4:
509  JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
510  // LCOV_EXCL_START
511  case 2:
512  JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
513  case 3:
514  JSON_THROW(*static_cast<const detail::type_error*>(&ex));
515  case 5:
516  JSON_THROW(*static_cast<const detail::other_error*>(&ex));
517  default:
518  assert(false);
519  // LCOV_EXCL_STOP
520  }
521  }
522  return false;
523  }
524 
525  constexpr bool is_errored() const
526  {
527  return errored;
528  }
529 
530  private:
546  template<typename Value>
547  std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
548  {
549  assert(not keep_stack.empty());
550 
551  // do not handle this value if we know it would be added to a discarded
552  // container
553  if (not keep_stack.back())
554  {
555  return {false, nullptr};
556  }
557 
558  // create value
559  auto value = BasicJsonType(std::forward<Value>(v));
560 
561  // check callback
562  const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
563 
564  // do not handle this value if we just learnt it shall be discarded
565  if (not keep)
566  {
567  return {false, nullptr};
568  }
569 
570  if (ref_stack.empty())
571  {
572  root = std::move(value);
573  return {true, &root};
574  }
575 
576  // skip this value if we already decided to skip the parent
577  // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
578  if (not ref_stack.back())
579  {
580  return {false, nullptr};
581  }
582 
583  // we now only expect arrays and objects
584  assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
585 
586  // array
587  if (ref_stack.back()->is_array())
588  {
589  ref_stack.back()->m_value.array->push_back(std::move(value));
590  return {true, &(ref_stack.back()->m_value.array->back())};
591  }
592 
593  // object
594  assert(ref_stack.back()->is_object());
595  // check if we should store an element for the current key
596  assert(not key_keep_stack.empty());
597  const bool store_element = key_keep_stack.back();
598  key_keep_stack.pop_back();
599 
600  if (not store_element)
601  {
602  return {false, nullptr};
603  }
604 
605  assert(object_element);
606  *object_element = std::move(value);
607  return {true, object_element};
608  }
609 
611  BasicJsonType& root;
613  std::vector<BasicJsonType*> ref_stack {};
615  std::vector<bool> keep_stack {};
617  std::vector<bool> key_keep_stack {};
619  BasicJsonType* object_element = nullptr;
621  bool errored = false;
623  const parser_callback_t callback = nullptr;
625  const bool allow_exceptions = true;
627  BasicJsonType discarded = BasicJsonType::value_t::discarded;
628 };
629 
630 template<typename BasicJsonType>
631 class json_sax_acceptor
632 {
633  public:
634  using number_integer_t = typename BasicJsonType::number_integer_t;
635  using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
636  using number_float_t = typename BasicJsonType::number_float_t;
637  using string_t = typename BasicJsonType::string_t;
638 
639  bool null()
640  {
641  return true;
642  }
643 
644  bool boolean(bool /*unused*/)
645  {
646  return true;
647  }
648 
649  bool number_integer(number_integer_t /*unused*/)
650  {
651  return true;
652  }
653 
654  bool number_unsigned(number_unsigned_t /*unused*/)
655  {
656  return true;
657  }
658 
659  bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
660  {
661  return true;
662  }
663 
664  bool string(string_t& /*unused*/)
665  {
666  return true;
667  }
668 
669  bool start_object(std::size_t /*unused*/ = std::size_t(-1))
670  {
671  return true;
672  }
673 
674  bool key(string_t& /*unused*/)
675  {
676  return true;
677  }
678 
679  bool end_object()
680  {
681  return true;
682  }
683 
684  bool start_array(std::size_t /*unused*/ = std::size_t(-1))
685  {
686  return true;
687  }
688 
689  bool end_array()
690  {
691  return true;
692  }
693 
694  bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
695  {
696  return false;
697  }
698 };
699 } // namespace detail
700 
701 } // namespace nlohmann
nlohmann::detail::exception
general exception of the basic_json class
Definition: exceptions.hpp:47
nlohmann::json_sax::number_unsigned_t
typename BasicJsonType::number_unsigned_t number_unsigned_t
type for unsigned integers
Definition: json_sax.hpp:29
nlohmann::json_sax::parse_error
virtual bool parse_error(std::size_t position, const std::string &last_token, const detail::exception &ex)=0
a parse error occurred
nlohmann::json_sax::number_unsigned
virtual bool number_unsigned(number_unsigned_t val)=0
an unsigned integer number was read
nlohmann::detail::json_sax_dom_parser::json_sax_dom_parser
json_sax_dom_parser(BasicJsonType &r, const bool allow_exceptions_=true)
Definition: json_sax.hpp:158
nlohmann
namespace for Niels Lohmann
Definition: adl_serializer.hpp:9
nlohmann::detail::json_sax_dom_parser
SAX implementation to create a JSON value from SAX events.
Definition: json_sax.hpp:146
nlohmann::json_sax::string
virtual bool string(string_t &val)=0
a string was read
nlohmann::json_sax::boolean
virtual bool boolean(bool val)=0
a boolean value was read
nlohmann::json_sax::number_integer_t
typename BasicJsonType::number_integer_t number_integer_t
type for (signed) integers
Definition: json_sax.hpp:27
nlohmann::json_sax::string_t
typename BasicJsonType::string_t string_t
type for strings
Definition: json_sax.hpp:33
nlohmann::json_sax::number_float
virtual bool number_float(number_float_t val, const string_t &s)=0
an floating-point number was read
nlohmann::json_sax::end_object
virtual bool end_object()=0
the end of an object was read
nlohmann::json_sax::start_object
virtual bool start_object(std::size_t elements)=0
the beginning of an object was read
nlohmann::json_sax::number_integer
virtual bool number_integer(number_integer_t val)=0
an integer number was read
nlohmann::json_sax::end_array
virtual bool end_array()=0
the end of an array was read
nlohmann::json_sax::number_float_t
typename BasicJsonType::number_float_t number_float_t
type for floating-point numbers
Definition: json_sax.hpp:31
nlohmann::json_sax::start_array
virtual bool start_array(std::size_t elements)=0
the beginning of an array was read
nlohmann::json_sax
SAX interface.
Definition: json_sax.hpp:25
nlohmann::json_sax::key
virtual bool key(string_t &val)=0
an object key was read