6 #ifndef JBSON_JSON_READER_HPP
7 #define JBSON_JSON_READER_HPP
15 #include "detail/config.hpp"
17 JBSON_PUSH_DISABLE_DOCUMENTATION_WARNING
18 #include <boost/range/as_literal.hpp>
19 #include <boost/range/algorithm.hpp>
20 #include <boost/range/algorithm_ext.hpp>
21 #include <boost/lexical_cast.hpp>
22 #include <boost/exception/exception.hpp>
23 #include <boost/spirit/home/support/iterators/line_pos_iterator.hpp>
24 #include <boost/io/ios_state.hpp>
25 JBSON_CLANG_POP_WARNINGS
27 #include "document.hpp"
28 #include "detail/traits.hpp"
30 JBSON_PUSH_DISABLE_DEPRECATED_WARNING
34 using boost::spirit::line_pos_iterator;
36 struct json_parse_error;
37 enum class json_error_num;
40 using container_type = std::vector<char>;
41 using range_type = boost::iterator_range<container_type::const_iterator>;
43 json_reader() noexcept(std::is_nothrow_constructible<container_type>::value) =
default;
45 template <
typename ForwardIterator>
void parse(ForwardIterator, ForwardIterator);
46 template <
typename ForwardIterator>
47 void parse(line_pos_iterator<ForwardIterator>, line_pos_iterator<ForwardIterator>);
49 template <
typename ForwardRange_>
void parse(ForwardRange_&& range_) {
50 auto range = boost::as_literal(std::forward<ForwardRange_>(range_));
51 using ForwardRange = decltype(range);
52 BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<ForwardRange>));
53 using line_it = line_pos_iterator<typename boost::range_const_iterator<std::decay_t<ForwardRange>>::type>;
54 parse(line_it{std::cbegin(range)}, line_it{std::cend(range)});
64 template <
typename C1,
typename C2>
71 template <
typename C1,
typename C2>
78 template <
typename Vec>
85 template <
typename Vec>
93 template <
typename ForwardIterator,
typename OutputIterator>
94 OutputIterator parse_document(line_pos_iterator<ForwardIterator>&,
const line_pos_iterator<ForwardIterator>&,
96 template <
typename ForwardIterator,
typename OutputIterator>
97 OutputIterator parse_array(line_pos_iterator<ForwardIterator>&,
const line_pos_iterator<ForwardIterator>&,
100 template <
typename ForwardIterator,
typename OutputIterator>
101 std::tuple<OutputIterator, element_type> parse_value(line_pos_iterator<ForwardIterator>&,
102 const line_pos_iterator<ForwardIterator>&, OutputIterator);
104 template <
typename OutputIterator>
108 template <
typename ForwardIterator,
typename OutputIterator>
109 OutputIterator parse_string(line_pos_iterator<ForwardIterator>&,
const line_pos_iterator<ForwardIterator>&,
112 template <
typename ForwardIterator,
typename OutputIterator>
113 OutputIterator parse_name(line_pos_iterator<ForwardIterator>&,
const line_pos_iterator<ForwardIterator>&,
114 OutputIterator,
bool allow_null =
false);
116 template <
typename ForwardIterator,
typename OutputIterator>
117 OutputIterator parse_escape(line_pos_iterator<ForwardIterator>&,
const line_pos_iterator<ForwardIterator>&,
120 template <
typename ForwardIterator,
typename OutputIterator>
121 std::tuple<OutputIterator, element_type> parse_number(line_pos_iterator<ForwardIterator>&,
122 const line_pos_iterator<ForwardIterator>&, OutputIterator);
124 template <
typename ForwardIterator>
125 void skip_space(line_pos_iterator<ForwardIterator>&,
const line_pos_iterator<ForwardIterator>&);
127 template <
typename ForwardIterator>
128 json_parse_error make_parse_exception(json_error_num,
const line_pos_iterator<ForwardIterator>& current,
129 const line_pos_iterator<ForwardIterator>& last,
130 const std::string& expected = {})
const;
131 json_parse_error make_parse_exception(json_error_num,
const std::string& expected = {})
const;
134 std::shared_ptr<void> m_start;
135 container_type m_data;
138 enum class json_error_num { invalid_root_element, unexpected_end_of_range, unexpected_token, };
140 template <
typename CharT,
typename TraitsT>
141 std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, json_error_num err) {
143 case json_error_num::invalid_root_element:
144 os <<
"invalid root element; must be document (object) or array";
146 case json_error_num::unexpected_end_of_range:
147 os <<
"unexpected end of range";
149 case json_error_num::unexpected_token:
150 os <<
"unexpected token";
153 os <<
"unknown error";
158 using parse_error = boost::error_info<struct err_val_, json_error_num>;
159 using expected_token = boost::error_info<struct token_, std::string>;
160 using current_line_string = boost::error_info<struct line_, std::string>;
161 using line_position = boost::error_info<struct line_pos_, size_t>;
162 using line_number = boost::error_info<struct line_num_, size_t>;
165 const char* what()
const noexcept
override {
return "json_parse_error"; }
170 template <
typename ForwardIterator>
172 json_reader::make_parse_exception(json_error_num err,
const line_pos_iterator<ForwardIterator>& current,
173 const line_pos_iterator<ForwardIterator>& last,
const std::string& expected)
const {
174 using char_type =
typename std::iterator_traits<ForwardIterator>::value_type;
175 BOOST_CONCEPT_ASSERT((boost::ForwardIteratorConcept<ForwardIterator>));
176 auto e = make_parse_exception(err, expected);
178 auto start = *
static_cast<line_pos_iterator<ForwardIterator>*
>(m_start.get());
179 auto begin = boost::spirit::get_line_start(start, current);
180 if(begin != current && begin != last && (*begin ==
'\n' || *begin ==
'\r'))
181 std::advance(begin, 1);
182 auto range = boost::range::find_first_of<boost::return_begin_found>(boost::make_iterator_range(begin, last),
183 boost::as_literal(
"\n\r"));
184 using cvt_char_type =
185 std::conditional_t<std::is_same<char_type, container_type::value_type>::value, char32_t, char_type>;
186 thread_local std::wstring_convert<std::codecvt_utf8<cvt_char_type>, cvt_char_type> cvt;
188 std::basic_string<cvt_char_type> str{range.begin(), range.end()};
189 if(std::is_same<char_type, container_type::value_type>::value)
190 e << current_line_string(boost::lexical_cast<std::string>(range));
193 e << current_line_string(cvt.to_bytes(str));
196 auto c = str[boost::spirit::get_line(current)];
197 e << current_line_string(std::to_string((
int)c));
200 e << line_number(boost::spirit::get_line(current));
201 e << line_position(boost::spirit::get_column(begin, current));
207 inline json_parse_error json_reader::make_parse_exception(json_error_num err,
const std::string& expected)
const {
208 auto e = json_parse_error{};
209 e << parse_error(err);
210 if(!expected.empty())
211 e << expected_token(expected);
215 inline std::string error_message(json_parse_error& err) {
216 std::stringstream is;
218 const auto line_num = boost::get_error_info<line_number>(err);
220 is <<
"line " << *line_num <<
": ";
222 is << err.what() <<
": ";
223 const auto num = boost::get_error_info<parse_error>(err);
225 is <<
"unknown error";
230 const auto line = boost::get_error_info<current_line_string>(err);
233 const auto pos = boost::get_error_info<line_position>(err);
239 boost::io::ios_width_saver ios(is);
240 is << std::setw(*pos) <<
"^";
243 const auto expected = boost::get_error_info<expected_token>(err);
244 if(!expected || expected->empty())
247 is <<
"\nExpected: " << *expected;
252 template <
typename ForwardIterator>
void json_reader::parse(ForwardIterator first, ForwardIterator last) {
253 parse(line_pos_iterator<ForwardIterator>{first}, line_pos_iterator<ForwardIterator>{last});
256 template <
typename ForwardIterator>
257 void json_reader::parse(line_pos_iterator<ForwardIterator> first, line_pos_iterator<ForwardIterator> last) {
258 BOOST_CONCEPT_ASSERT((boost::ForwardIteratorConcept<ForwardIterator>));
260 m_data = container_type{};
261 if(detail::is_iterator_pointer<std::decay_t<ForwardIterator>>::value)
262 m_data.reserve(+std::distance(&*first, &*last));
264 m_data.reserve(+std::distance(first, last));
266 m_start = std::make_shared<line_pos_iterator<ForwardIterator>>(first);
267 skip_space(first, last);
268 if(first == last || *first ==
'\0')
269 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
272 parse_document(first, last, m_data.end());
275 parse_array(first, last, m_data.end());
278 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::invalid_root_element, first, last));
280 m_data.shrink_to_fit();
282 skip_space(first, last);
283 if(first != last && *first !=
'\0')
284 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"end of input"));
287 template <
typename ForwardIterator,
typename OutputIterator>
288 OutputIterator json_reader::parse_document(line_pos_iterator<ForwardIterator>& first,
289 const line_pos_iterator<ForwardIterator>& last, OutputIterator out) {
291 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
292 assert(last != first);
294 const auto start_idx = std::distance(m_data.begin(), out);
296 assert(out >= m_data.begin() && out <= m_data.end());
297 out = std::next(m_data.insert(out, 4,
'\0'), 4);
300 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"{"));
301 skip_space(++first, last);
303 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
307 assert(out >= m_data.begin() && out <= m_data.end());
308 out = std::next(m_data.insert(out,
'\0'));
310 int32_t size = std::distance(std::next(m_data.begin(), start_idx), out);
312 BOOST_THROW_EXCEPTION(invalid_document_size{} << detail::expected_size(5) << detail::actual_size(size));
313 boost::range::copy(detail::native_to_little_endian(size), std::next(m_data.begin(), start_idx));
319 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
321 assert(out >= m_data.begin() && out <= m_data.end());
324 const auto type_idx = std::distance(m_data.begin(), out);
326 skip_space(first, last);
327 out = parse_name(first, last, out);
328 skip_space(first, last);
331 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
":"));
333 skip_space(first, last);
335 std::tie(out, type) = parse_value(first, last, out);
336 m_data[type_idx] =
static_cast<char>(type);
338 skip_space(first, last);
344 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"}"));
348 assert(out >= m_data.begin() && out <= m_data.end());
349 out = std::next(m_data.insert(out,
'\0'));
351 int32_t size = std::distance(std::next(m_data.begin(), start_idx), out);
353 BOOST_THROW_EXCEPTION(invalid_document_size{} << detail::expected_size(5) << detail::actual_size(size));
354 boost::range::copy(detail::native_to_little_endian(size), std::next(m_data.begin(), start_idx));
360 template <
typename ForwardIterator,
typename OutputIterator>
361 OutputIterator json_reader::parse_array(line_pos_iterator<ForwardIterator>& first,
362 const line_pos_iterator<ForwardIterator>& last, OutputIterator out) {
364 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
365 assert(last != first);
367 const auto start_idx = std::distance(m_data.begin(), out);
369 assert(out >= m_data.begin() && out <= m_data.end());
370 out = std::next(m_data.insert(out, 4,
'\0'), 4);
373 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"["));
374 skip_space(++first, last);
376 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
380 assert(out >= m_data.begin() && out <= m_data.end());
381 out = std::next(m_data.insert(out,
'\0'));
383 const int32_t size = std::distance(std::next(m_data.begin(), start_idx), out);
385 BOOST_THROW_EXCEPTION(invalid_document_size{} << detail::expected_size(5) << detail::actual_size(size));
386 boost::range::copy(detail::native_to_little_endian(size), std::next(m_data.begin(), start_idx));
393 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
395 assert(out >= m_data.begin() && out <= m_data.end());
397 auto type_idx = std::distance(m_data.begin(), out);
398 auto sidx = std::to_string(idx++);
401 assert(out >= m_data.begin() && out <= m_data.end());
402 out = m_data.insert(out, sidx.size() + 1,
'\0');
403 out = std::next(boost::range::copy(sidx, out));
404 assert(out >= m_data.begin() && out <= m_data.end());
406 skip_space(first, last);
409 std::tie(out, type) = parse_value(first, last, out);
410 m_data[type_idx] =
static_cast<char>(type);
412 skip_space(first, last);
419 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
", or ]"));
423 assert(out >= m_data.begin() && out <= m_data.end());
424 out = std::next(m_data.insert(out,
'\0'));
426 int32_t size = std::distance(std::next(m_data.begin(), start_idx), out);
428 BOOST_THROW_EXCEPTION(invalid_document_size{} << detail::expected_size(5) << detail::actual_size(size));
429 boost::range::copy(detail::native_to_little_endian(size), std::next(m_data.begin(), start_idx));
435 template <
typename ForwardIterator,
typename OutputIterator>
436 std::tuple<OutputIterator, element_type> json_reader::parse_value(line_pos_iterator<ForwardIterator>& first,
437 const line_pos_iterator<ForwardIterator>& last,
438 OutputIterator out) {
440 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
441 assert(last != first);
446 out = parse_string(first, last, out);
450 out = parse_array(first, last, out);
454 if(boost::equal(boost::as_literal(
"false"), boost::make_iterator_range(first, std::next(first, 5)),
455 [](
char a,
auto&& b) {
return b == (decltype(b))a; })) {
456 assert(out >= m_data.begin() && out <= m_data.end());
457 out = std::next(m_data.insert(out,
false));
458 std::advance(first, 5);
461 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"false"));
464 if(!boost::equal(boost::as_literal(
"null"), boost::make_iterator_range(first, std::next(first, 4)),
465 [](
char a,
auto&& b) {
return b == (decltype(b))a; }))
466 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"null"));
467 std::advance(first, 4);
471 if(boost::equal(boost::as_literal(
"true"), boost::make_iterator_range(first, std::next(first, 4)),
472 [](
char a,
auto&& b) {
return b == (decltype(b))a; })) {
473 assert(out >= m_data.begin() && out <= m_data.end());
474 out = std::next(m_data.insert(out,
true));
475 std::advance(first, 4);
478 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"true"));
480 auto idx = std::distance(m_data.begin(), out);
481 auto r = parse_document(first, last, out);
483 basic_document<range_type> doc{std::next(m_data.begin(), idx), r};
484 assert(std::distance(std::next(m_data.begin(), idx), r) >= 5);
485 assert(doc.size() >= 5);
487 boost::string_ref name;
488 const auto it = doc.begin();
491 if(!name.empty() && name[0] ==
'$') {
492 boost::optional<OutputIterator> o_out;
493 std::tie(o_out, type) = parse_extended_value(doc, std::next(m_data.begin(), idx));
496 m_data.resize(std::distance(m_data.begin(), out));
505 std::tie(out, type) = parse_number(first, last, out);
508 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
509 return std::make_tuple(out, type);
512 template <
typename OutputIterator>
513 std::tuple<boost::optional<OutputIterator>,
element_type>
514 json_reader::parse_extended_value(
const basic_document<range_type>& doc, OutputIterator out) {
516 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"extended json value")
517 << detail::expected_size(5) << detail::actual_size(doc.size()));
519 const auto name = doc.begin()->name();
520 if(name ==
"$binary" || name ==
"$type") {
522 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"binary element"));
525 }
else if(name ==
"$date") {
526 if(doc.size() != 1 ||
528 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"date element"));
529 using DateT = detail::ElementTypeMap<element_type::date_element, element::container_type>;
531 detail::serialise(m_data, out, static_cast<DateT>(get<element_type::int32_element>(*doc.begin())));
533 detail::serialise(m_data, out, static_cast<DateT>(get<element_type::int64_element>(*doc.begin())));
535 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"date element"));
537 }
else if(name ==
"$timestamp") {
539 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"timestamp element"));
542 }
else if(name ==
"$regex" || name ==
"$options") {
544 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"regex element"));
545 auto it = doc.find(
"$regex");
547 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"regex element"));
548 auto re = get<element_type::string_element>(*it);
549 it = doc.find(
"$options");
551 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"regex element"));
552 auto options = get<element_type::string_element>(*it);
555 detail::serialise(m_data, out, std::make_tuple(re, options));
556 }
else if(name ==
"$oid") {
558 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"oid element"));
559 auto str = get<element_type::string_element>(*doc.begin());
561 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"oid element"));
562 std::array<char, 12> oid;
563 for(
auto i = 0; i < 24; i += 2)
564 oid[i / 2] = static_cast<char>(std::stoi(boost::lexical_cast<std::string>(str.substr(i, 2)),
nullptr, 16));
567 detail::serialise(m_data, out, oid);
568 }
else if(name ==
"$ref" || name ==
"$id") {
570 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"ref element"));
571 auto it = doc.find(
"$id");
573 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"ref element"));
574 auto str = get<element_type::string_element>(*it);
576 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"oid element"));
577 std::array<char, 12> oid;
578 for(
auto i = 0; i < 24; i += 2)
579 oid[i / 2] = static_cast<char>(std::stoi(boost::lexical_cast<std::string>(str.substr(i, 2)),
nullptr, 16));
581 it = doc.find(
"$ref");
583 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"ref element"));
584 auto coll = get<element_type::string_element>(*it);
587 detail::serialise(m_data, out, std::make_tuple(coll, oid));
588 }
else if(name ==
"$undefined") {
590 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"undefined element"));
592 }
else if(name ==
"$minkey") {
594 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"minkey element"));
596 }
else if(name ==
"$maxkey") {
598 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
"maxkey element"));
602 return std::make_tuple(out, type);
605 template <
typename ForwardIterator,
typename OutputIterator>
606 OutputIterator json_reader::parse_string(line_pos_iterator<ForwardIterator>& first,
607 const line_pos_iterator<ForwardIterator>& last, OutputIterator out) {
608 assert(last != first);
610 assert(out >= m_data.begin() && out <= m_data.end());
611 out = m_data.insert(out, 4,
'\0');
613 const auto size = std::distance(m_data.begin(), std::next(out, 4));
614 out = parse_name(first, last, std::next(out, 4),
true);
615 boost::range::copy(detail::native_to_little_endian<int32_t>(m_data.size() - size),
616 std::next(m_data.begin(), size - 4));
622 template <
typename CharT> constexpr
bool iscntrl(CharT c) {
624 return (std::make_unsigned_t<CharT>)c < 0x1f;
627 template <
typename CharT> constexpr
bool isdigit(CharT c) {
return (std::make_unsigned_t<CharT>)(c -
'0') < 10; }
629 template <
typename CharT> constexpr
bool isxdigit(CharT c) {
630 return detail::isdigit(c) || (std::make_unsigned_t<CharT>)(c -
'A') < 6 ||
631 (std::make_unsigned_t<CharT>)(c -
'a') < 6;
634 template <
typename CharT> constexpr
bool isspace(CharT c) {
635 return c == 0x20 || (std::make_unsigned_t<CharT>)(c -
'\t') < 5;
639 using type = std::codecvt_utf8<CharT>;
642 template <>
struct codecvt<char> : std::codecvt<char, char, std::mbstate_t> {
647 using type = std::codecvt_utf8_utf16<char16_t>;
650 template <
typename CharT>
using codecvt_t =
typename codecvt<CharT>::type;
654 template <
typename ForwardIterator,
typename OutputIterator>
655 OutputIterator json_reader::parse_name(line_pos_iterator<ForwardIterator>& first,
656 const line_pos_iterator<ForwardIterator>& last, OutputIterator out,
658 using char_type =
typename std::iterator_traits<ForwardIterator>::value_type;
659 assert(last != first);
661 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
663 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
"\""));
664 std::advance(first, 1);
666 detail::codecvt_t<char_type> cvt;
667 std::mbstate_t state{};
668 std::array<char_type, 2> buf;
672 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
677 std::advance(first, 1);
680 if(buf[0] ==
'\0' && !allow_null) {
681 std::advance(first, 1);
686 if(std::is_same<char_type, char16_t>::value && buf[0] >= 0xD800 && buf[0] <= 0xDBFF)
692 out = parse_escape(first, last, out);
694 }
else if(detail::iscntrl(buf[0]))
695 BOOST_THROW_EXCEPTION(
696 make_parse_exception(json_error_num::unexpected_token, first, last,
"non-control char"));
698 if(std::is_same<char_type, container_type::value_type>::value) {
699 assert(out >= m_data.begin() && out <= m_data.end());
700 out = std::next(m_data.insert(out, buf[0]));
702 std::array<char, std::max(sizeof(buf), 2 * sizeof(char16_t)) + 1> to;
704 const char_type* frm_next;
706 auto res = cvt.out(state, buf.data(), buf.data() + (buf[1] ? 2 : 1), frm_next, to.data(),
707 to.data() + to.size(), to_next);
708 if(!std::mbsinit(&state) || res != std::codecvt_base::ok)
709 BOOST_THROW_EXCEPTION(
710 make_parse_exception(json_error_num::unexpected_token, first, last,
"valid unicode code point(s)"));
711 auto len = std::strlen(to.data());
712 out = m_data.insert(out, len,
'\0');
713 out = std::copy(to.data(), to.data() + len, out);
716 std::advance(first, 1);
718 assert(out >= m_data.begin() && out <= m_data.end());
719 return std::next(m_data.insert(out,
'\0'));
722 template <
typename ForwardIterator,
typename OutputIterator>
723 OutputIterator json_reader::parse_escape(line_pos_iterator<ForwardIterator>& first,
724 const line_pos_iterator<ForwardIterator>& last, OutputIterator out) {
725 assert(last != first);
726 assert(*first ==
'\\');
727 std::advance(first, 1);
729 if(first == last || *first ==
'\0')
730 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_end_of_range, first, last));
733 out = std::next(m_data.insert(out,
'"'));
735 out = std::next(m_data.insert(out,
'/'));
737 out = std::next(m_data.insert(out,
'\\'));
739 out = std::next(m_data.insert(out,
'\b'));
741 out = std::next(m_data.insert(out,
'\f'));
743 out = std::next(m_data.insert(out,
'\n'));
745 out = std::next(m_data.insert(out,
'\r'));
747 out = std::next(m_data.insert(out,
'\t'));
749 if(std::next(first, 4) !=
750 std::find_if_not(first, std::next(first, 4), [](
auto&& c) {
return detail::isxdigit(c); }))
751 BOOST_THROW_EXCEPTION(
752 make_parse_exception(json_error_num::unexpected_token, first, last,
"4x hex (0-9;a-f/A-F)"));
754 std::array<char, 5> buf;
756 std::copy(first, std::next(first, 4), buf.begin());
757 assert(buf.back() == 0);
760 std::array<char16_t, 2> codepoints;
761 codepoints[0] = std::strtol(buf.data(), &pos, 16);
763 if(pos != buf.data() + 4)
764 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
765 std::next(first, pos - buf.data()), last,
766 "valid hex characters (0-9;a-f/A-F)"));
768 if(codepoints[0] == 0x0000) {
769 auto null_str = R
"(\u0000)";
770 std::advance(first, 4);
771 out = m_data.insert(out, 6, '\0');
772 out = std::copy(null_str, null_str + 6, out);
776 if(codepoints[0] >= 0xD800 && codepoints[0] <= 0xDBFF) {
778 std::advance(first, 4);
779 if(*first++ !=
'\\' || *first++ !=
'u')
780 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
781 "trail surrogate after lead surrogate (utf-16)"));
782 if(std::next(first, 4) !=
783 std::find_if_not(first, std::next(first, 4), [](
auto&& c) {
return detail::isxdigit(c); }))
784 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first, last,
785 "4x valid hex characters (0-9;a-f/A-F)"));
787 std::copy(first, std::next(first, 4), buf.begin());
788 assert(buf.back() == 0);
790 codepoints[1] = std::strtol(buf.data(), &pos, 16);
791 if(pos != buf.data() + 4)
792 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token,
793 std::next(first, pos - buf.data()), last,
794 "valid hex characters (0-9;a-f/A-F)"));
797 std::codecvt_utf8_utf16<char16_t> cvt16;
798 std::mbstate_t state{};
800 const char16_t* frm_next;
802 auto res = cvt16.out(state, codepoints.data(), codepoints.data() + codepoints.size(), frm_next, buf.data(),
803 buf.data() + buf.size(), to_next);
804 if(!std::mbsinit(&state) || res != std::codecvt_base::ok)
805 BOOST_THROW_EXCEPTION(
806 make_parse_exception(json_error_num::unexpected_token, first, last,
"valid unicode code point(s)"));
807 std::advance(first, 4);
808 const auto len = std::strlen(buf.data());
809 out = m_data.insert(out, len,
'\0');
810 out = std::copy(buf.data(), buf.data() + len, out);
812 BOOST_THROW_EXCEPTION(
813 make_parse_exception(json_error_num::unexpected_token, first, last,
"valid control char"));
817 template <
typename ForwardIterator,
typename OutputIterator>
818 std::tuple<OutputIterator, element_type> json_reader::parse_number(line_pos_iterator<ForwardIterator>& first_,
819 const line_pos_iterator<ForwardIterator>& last_,
820 OutputIterator out) {
821 assert(last_ != first_);
823 if(!detail::isdigit(*first_) && *first_ !=
'-')
824 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first_, last_,
"number"));
825 const auto last = std::find_if_not(first_, last_, [](
char c) {
826 return detail::isdigit(c) || c ==
'.' || c ==
'+' || c ==
'-' || c ==
'e' || c ==
'E';
829 const auto buf_len = detail::is_iterator_pointer<std::decay_t<ForwardIterator>>::value
830 ? std::distance(&*first_, &*last)
831 : std::distance(first_, last);
832 char* buf = (
char*)alloca(buf_len + 1);
833 char*
const buf_end = buf + buf_len;
835 assert(buf !=
nullptr);
836 std::copy(first_, last, buf);
838 if(*buf ==
'0' && buf_len > 1 && *std::next(buf) !=
'.')
839 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first_, last_,
"number"));
843 const int64_t val = std::strtoll(buf, &pos, 10);
845 if(pos == buf || pos != buf_end || errno == ERANGE) {
848 const double val = std::strtod(buf, &pos);
850 if(val == HUGE_VALL || pos == buf || pos != buf_end)
851 BOOST_THROW_EXCEPTION(make_parse_exception(json_error_num::unexpected_token, first_, last_,
"number"));
853 std::advance(first_, buf_len);
855 assert(out >= m_data.begin() && out <= m_data.end());
856 detail::serialise(m_data, out, val);
858 return std::make_tuple(out, type);
861 std::advance(first_, buf_len);
863 if(val > std::numeric_limits<int32_t>::min() && val < std::numeric_limits<int32_t>::max()) {
864 assert(out >= m_data.begin() && out <= m_data.end());
865 detail::serialise(m_data, out, static_cast<int32_t>(val));
868 assert(out >= m_data.begin() && out <= m_data.end());
869 detail::serialise(m_data, out, val);
873 return std::make_tuple(out, type);
876 template <
typename ForwardIterator>
877 void json_reader::skip_space(line_pos_iterator<ForwardIterator>& first,
878 const line_pos_iterator<ForwardIterator>& last) {
879 first = std::find_if_not(first, last, [](
auto&& c) {
return detail::isspace(c); });
882 inline namespace literal {
884 inline document_set operator"" _json_set(
const char* str,
size_t len) {
885 auto reader = json_reader{};
886 reader.parse(str, str + len);
887 return document_set(basic_document<std::vector<char>, std::vector<char>>(std::move(reader)));
890 inline document operator"" _json_doc(
const char* str,
size_t len) {
891 auto reader = json_reader{};
892 reader.parse(str, str + len);
893 return std::move(reader);
896 inline array operator"" _json_arr(
const char* str,
size_t len) {
897 auto reader = json_reader{};
898 reader.parse(str, str + len);
899 return std::move(reader);
902 inline document_set operator"" _json_set(
const wchar_t* str,
size_t len) {
903 auto reader = json_reader{};
904 reader.parse(str, str + len);
905 return document_set(basic_document<std::vector<char>, std::vector<char>>(std::move(reader)));
908 inline document operator"" _json_doc(
const wchar_t* str,
size_t len) {
909 auto reader = json_reader{};
910 reader.parse(str, str + len);
911 return std::move(reader);
914 inline array operator"" _json_arr(
const wchar_t* str,
size_t len) {
915 auto reader = json_reader{};
916 reader.parse(str, str + len);
917 return std::move(reader);
920 inline document_set operator"" _json_set(
const char16_t* str,
size_t len) {
921 auto reader = json_reader{};
922 reader.parse(str, str + len);
923 return document_set(basic_document<std::vector<char>, std::vector<char>>(std::move(reader)));
926 inline document operator"" _json_doc(
const char16_t* str,
size_t len) {
927 auto reader = json_reader{};
928 reader.parse(str, str + len);
929 return std::move(reader);
932 inline array operator"" _json_arr(
const char16_t* str,
size_t len) {
933 auto reader = json_reader{};
934 reader.parse(str, str + len);
935 return std::move(reader);
938 inline document_set operator"" _json_set(
const char32_t* str,
size_t len) {
939 auto reader = json_reader{};
940 reader.parse(str, str + len);
941 return document_set(basic_document<std::vector<char>, std::vector<char>>(std::move(reader)));
944 inline document operator"" _json_doc(
const char32_t* str,
size_t len) {
945 auto reader = json_reader{};
946 reader.parse(str, str + len);
947 return std::move(reader);
950 inline array operator"" _json_arr(
const char32_t* str,
size_t len) {
951 auto reader = json_reader{};
952 reader.parse(str, str + len);
953 return std::move(reader);
962 #endif // JBSON_JSON_READER_HPP
element_type
The element_type enum represents a BSON data type.
std::string or boost::string_ref (string_type)
std::multiset< basic_element< Container >, detail::elem_compare > basic_document_set
BSON document in the form of a std::set for ease of manipulation.
void swap(basic_document< Container, EContainer > &a, basic_document< Container, EContainer > &b) noexcept(noexcept(a.swap(b)))
Non-member swap for basic_document. Calls basic_document::swap.
basic_array< std::vector< char >> array
Default basic_array type alias for owned BSON data.
basic_document_set< std::vector< char >> document_set
Default basic_document_set type alias.
Exception type. Base class of all exceptions thrown directly by jbson.
basic_document> (document_type)
basic_document< std::vector< char >> document
Default basic_document type alias for owned BSON data.