diff options
Diffstat (limited to 'vendor/jsoncons-0.104.0')
41 files changed, 29278 insertions, 0 deletions
diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/heap_only_string.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/heap_only_string.hpp new file mode 100644 index 00000000..5348b436 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/heap_only_string.hpp @@ -0,0 +1,155 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_HEAPONLYSTRING_HPP +#define JSONCONS_DETAIL_HEAPONLYSTRING_HPP + +#include <stdexcept> +#include <string> +#include <cstdlib> +#include <exception> +#include <ostream> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { namespace detail { + +template <class Allocator> +class heap_only_string_base +{ + Allocator allocator_; +public: + Allocator& get_allocator() + { + return allocator_; + } + + const Allocator& get_allocator() const + { + return allocator_; + } +protected: + heap_only_string_base(const Allocator& allocator) + : allocator_(allocator) + { + } + + ~heap_only_string_base() {} +}; + +template <class CharT,class Allocator> +class heap_only_string_factory; + +template <class CharT, class Allocator> +class heap_only_string : public heap_only_string_base<Allocator> +{ + typedef typename std::allocator_traits<Allocator>::template rebind_alloc<CharT> allocator_type; + typedef std::allocator_traits<allocator_type> allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + + friend class heap_only_string_factory<CharT, Allocator>; +public: + typedef CharT char_type; + typedef heap_only_string<CharT,Allocator> value_type; + + ~heap_only_string() {} + + const char_type* c_str() const { return to_plain_pointer(p_); } + const char_type* data() const { return to_plain_pointer(p_); } + size_t length() const { return length_; } + + using heap_only_string_base<Allocator>::get_allocator; + + + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const heap_only_string& s) + { + os.write(s.data(),s.length()); + return os; + } +private: + heap_only_string() + : heap_only_string_base<Allocator>(Allocator()) + { + + } + heap_only_string(const Allocator& allocator) + : heap_only_string_base<Allocator>(allocator) + { + + } + + pointer p_; + size_t length_; + + heap_only_string(const heap_only_string&) = delete; + heap_only_string& operator=(const heap_only_string&) = delete; + +}; + +template <class CharT, class Allocator> +class heap_only_string_factory +{ + typedef CharT char_type; + typedef typename std::allocator_traits<Allocator>::template rebind_alloc<char> byte_allocator_type; + typedef std::allocator_traits<byte_allocator_type> byte_allocator_traits_type; + typedef typename byte_allocator_traits_type::pointer byte_pointer; + typedef typename heap_only_string<CharT,Allocator>::pointer pointer; +public: + + typedef typename std::allocator_traits<Allocator>::template rebind_alloc<heap_only_string<CharT,Allocator>> string_allocator_type; + typedef std::allocator_traits<string_allocator_type> string_allocator_traits_type; + typedef typename string_allocator_traits_type::pointer string_pointer; + + typedef heap_only_string<char_type,Allocator>* raw_string_pointer_type; + + struct string_storage + { + heap_only_string<CharT,Allocator> data; + char_type c[1]; + }; + typedef typename std::aligned_storage<sizeof(string_storage), JSONCONS_ALIGNOF(string_storage)>::type storage_type; + + static size_t aligned_size(size_t n) + { + return sizeof(storage_type) + n; + } +public: + static string_pointer create(const char_type* s, size_t length) + { + return create(s, length, Allocator()); + } + static string_pointer create(const char_type* s, size_t length, const Allocator& allocator) + { + size_t mem_size = aligned_size(length*sizeof(char_type)); + + byte_allocator_type alloc(allocator); + byte_pointer ptr = alloc.allocate(mem_size); + + char* storage = to_plain_pointer(ptr); + raw_string_pointer_type ps = new(storage)heap_only_string<char_type,Allocator>(alloc); + auto psa = reinterpret_cast<string_storage*>(storage); + + CharT* p = new(&psa->c)char_type[length + 1]; + memcpy(p, s, length*sizeof(char_type)); + p[length] = 0; + ps->p_ = std::pointer_traits<pointer>::pointer_to(*p); + ps->length_ = length; + return std::pointer_traits<string_pointer>::pointer_to(*ps); + } + + static void destroy(string_pointer ptr) + { + raw_string_pointer_type rawp = to_plain_pointer(ptr); + char* p = reinterpret_cast<char*>(rawp); + size_t mem_size = aligned_size(ptr->length_*sizeof(char_type)); + byte_allocator_type alloc(ptr->get_allocator()); + alloc.deallocate(p,mem_size); + } +}; + + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/number_parsers.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/number_parsers.hpp new file mode 100644 index 00000000..1a8fc0a9 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/number_parsers.hpp @@ -0,0 +1,266 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_NUMBERPARSERS_HPP +#define JSONCONS_DETAIL_NUMBERPARSERS_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <exception> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { namespace detail { + +struct to_integer_result +{ + int64_t value; + bool overflow; +}; + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template <class CharT> +to_integer_result to_integer(const CharT* s, size_t length) +{ + JSONCONS_ASSERT(length > 0); + + int64_t n = 0; + bool overflow = false; + const CharT* end = s + length; + if (*s == '-') + { + static const int64_t min_value = (std::numeric_limits<int64_t>::min)(); + static const int64_t min_value_div_10 = min_value / 10; + ++s; + for (; s < end; ++s) + { + int64_t x = *s - '0'; + if (n < min_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n < min_value + x) + { + overflow = true; + break; + } + + n -= x; + } + } + else + { + static const int64_t max_value = (std::numeric_limits<int64_t>::max)(); + static const int64_t max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + int64_t x = *s - '0'; + if (n > max_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n > max_value - x) + { + overflow = true; + break; + } + + n += x; + } + } + + return to_integer_result({ n,overflow }); +} + +struct to_uinteger_result +{ + uint64_t value; + bool overflow; +}; + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template <class CharT> +to_uinteger_result to_uinteger(const CharT* s, size_t length) +{ + JSONCONS_ASSERT(length > 0); + + static const uint64_t max_value = (std::numeric_limits<uint64_t>::max)(); + static const uint64_t max_value_div_10 = max_value / 10; + uint64_t n = 0; + bool overflow = false; + + const CharT* end = s + length; + for (; s < end; ++s) + { + uint64_t x = *s - '0'; + if (n > max_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n > max_value - x) + { + overflow = true; + break; + } + + n += x; + } + return to_uinteger_result{ n,overflow }; +} + +#if defined(JSONCONS_HAS_MSC__STRTOD_L) + +class string_to_double +{ +private: + _locale_t locale_; +public: + string_to_double() + { + locale_ = _create_locale(LC_NUMERIC, "C"); + } + ~string_to_double() + { + _free_locale(locale_); + } + + char get_decimal_point() const + { + return '.'; + } + + double operator()(const char* s, size_t) const + { + const char *begin = s; + char *end = nullptr; + double val = _strtod_l(begin, &end, locale_); + if (begin == end) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Invalid float value")); + } + return val; + } +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double&) = delete; + string_to_double& operator=(const string_to_double&) = delete; +}; + +#elif defined(JSONCONS_HAS_STRTOLD_L) + +class string_to_double +{ +private: + locale_t locale_; +public: + string_to_double() + { + locale_ = newlocale(LC_ALL_MASK, "C", (locale_t) 0); + } + ~string_to_double() + { + freelocale(locale_); + } + + char get_decimal_point() const + { + return '.'; + } + + double operator()(const char* s, size_t length) const + { + const char *begin = s; + char *end = nullptr; + double val = strtold_l(begin, &end, locale_); + if (begin == end) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Invalid float value")); + } + return val; + } + +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double& fr) = delete; + string_to_double& operator=(const string_to_double& fr) = delete; +}; + +#else +class string_to_double +{ +private: + std::vector<char> buffer_; + char decimal_point_; +public: + string_to_double() + : buffer_() + { + struct lconv * lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + else + { + decimal_point_ = '.'; + } + buffer_.reserve(100); + } + + char get_decimal_point() const + { + return decimal_point_; + } + + double operator()(const char* s, size_t /*length*/) const + { + char *end = nullptr; + double val = strtod(s, &end); + if (s == end) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("string_to_double failed")); + } + return val; + } + +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double& fr) = delete; + string_to_double& operator=(const string_to_double& fr) = delete; +}; +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/number_printers.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/number_printers.hpp new file mode 100644 index 00000000..58779280 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/number_printers.hpp @@ -0,0 +1,374 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_NUMBERPRINTERS_HPP +#define JSONCONS_DETAIL_NUMBERPRINTERS_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <algorithm> +#include <exception> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/detail/obufferedstream.hpp> + +namespace jsoncons { namespace detail { + +// print_integer + +template<class Writer> +void print_integer(int64_t value, Writer& os) +{ + typedef typename Writer::char_type char_type; + + char_type buf[255]; + uint64_t u = (value < 0) ? static_cast<uint64_t>(-value) : static_cast<uint64_t>(value); + char_type* p = buf; + do + { + *p++ = static_cast<char_type>(48 + u%10); + } + while (u /= 10); + if (value < 0) + { + os.put('-'); + } + while (--p >= buf) + { + os.put(*p); + } +} + +// print_uinteger + +template<class Writer> +void print_uinteger(uint64_t value, Writer& os) +{ + typedef typename Writer::char_type char_type; + + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = static_cast<char_type>(48 + value % 10); + } while (value /= 10); + while (--p >= buf) + { + os.put(*p); + } +} + +// print_double + +#if defined(JSONCONS_HAS__ECVT_S) + +class print_double +{ +private: + uint8_t precision_override_; +public: + print_double(uint8_t precision) + : precision_override_(precision) + { + } + + template <class Writer> + void operator()(double val, uint8_t precision, Writer& writer) + { + typedef typename Writer::char_type char_type; + + char buf[_CVTBUFSIZE]; + int decimal_point = 0; + int sign = 0; + + int prec; + if (precision_override_ != 0) + { + prec = precision_override_; + } + else if (precision != 0) + { + prec = precision; + } + else + { + prec = std::numeric_limits<double>::digits10; + } + + int err = _ecvt_s(buf, _CVTBUFSIZE, val, prec, &decimal_point, &sign); + if (err != 0) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed attempting double to string conversion")); + } + //std::cout << "prec:" << prec << ", buf:" << buf << std::endl; + char* s = buf; + char* se = s + prec; + + int i, k; + int j; + + if (sign) + { + writer.put('-'); + } + if (decimal_point <= -4 || decimal_point > se - s + 5) + { + writer.put(*s++); + if (s < se) + { + writer.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + + while(s < se) + { + writer.put(*s++); + } + } + writer.put('e'); + /* sprintf(b, "%+.2d", decimal_point - 1); */ + if (--decimal_point < 0) { + writer.put('-'); + decimal_point = -decimal_point; + } + else + writer.put('+'); + for(j = 2, k = 10; 10*k <= decimal_point; j++, k *= 10); + for(;;) + { + i = decimal_point / k; + writer.put(static_cast<char_type>(i) + '0'); + if (--j <= 0) + break; + decimal_point -= i*k; + decimal_point *= 10; + } + } + else if (decimal_point <= 0) + { + writer.put('0'); + writer.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + for(; decimal_point < 0; decimal_point++) + { + writer.put('0'); + } + while(s < se) + { + writer.put(*s++); + } + } + else { + while(s < se) + { + writer.put(*s++); + if ((--decimal_point == 0) && s < se) + { + writer.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + } + } + for(; decimal_point > 0; decimal_point--) + { + writer.put('0'); + } + } + } +}; + +#elif defined(JSONCONS_NO_LOCALECONV) + +class print_double +{ +private: + uint8_t precision_override_; + basic_obufferedstream<char> os_; +public: + print_double(uint8_t precision) + : precision_override_(precision) + { + os_.imbue(std::locale::classic()); + os_.precision(precision); + } + + template <class Writer> + void operator()(double val, uint8_t precision, Writer& writer) + { + typedef typename Writer::char_type char_type; + + int prec; + if (precision_override_ != 0) + { + prec = precision_override_; + } + else if (precision != 0) + { + prec = precision; + } + else + { + prec = std::numeric_limits<double>::digits10; + } + + os_.clear_sequence(); + os_.precision(prec); + os_ << val; + + //std::cout << "precision_override_:" << (int)precision_override_ << ", precision:" << (int)precision << ", buf:" << os_.data() << std::endl; + + const char_type* sbeg = os_.data(); + const char_type* send = sbeg + os_.length(); + const char_type* pexp = send; + + if (sbeg != send) + { + bool dot = false; + for (pexp = sbeg; *pexp != 'e' && *pexp != 'E' && pexp < send; ++pexp) + { + } + + const char_type* qend = pexp; + while (qend >= sbeg+2 && *(qend-1) == '0' && *(qend-2) != '.') + { + --qend; + } + if (pexp == send) + { + qend = ((qend >= sbeg+2) && *(qend-2) == '.') ? qend : send; + } + + for (const char_type* q = sbeg; q < qend; ++q) + { + if (*q == '.') + { + dot = true; + } + writer.put(*q); + } + if (!dot) + { + writer.put('.'); + writer.put('0'); + dot = true; + } + for (const char_type* q = pexp; q < send; ++q) + { + writer.put(*q); + } + } + } +}; +#else + +class print_double +{ +private: + uint8_t precision_override_; + char decimal_point_; +public: + print_double(uint8_t precision) + : precision_override_(precision) + { + struct lconv * lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + else + { + decimal_point_ = '.'; + } + } + + template <class Writer> + void operator()(double val, uint8_t precision, Writer& writer) + { + typedef typename Writer::char_type char_type; + + int prec; + if (precision_override_ != 0) + { + prec = precision_override_; + } + else if (precision != 0) + { + prec = precision; + } + else + { + prec = std::numeric_limits<double>::digits10; + } + + char number_buffer[100]; + int length = snprintf(number_buffer, 100, "%1.*g", prec, val); + if (length < 0) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("print_double failed.")); + } + + const char* sbeg = number_buffer; + const char* send = sbeg + length; + const char* pexp = send; + + if (sbeg != send) + { + bool dot = false; + for (pexp = sbeg; *pexp != 'e' && *pexp != 'E' && pexp < send; ++pexp) + { + } + + for (const char* q = sbeg; q < pexp; ++q) + { + switch (*q) + { + case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + writer.put(*q); + break; + default: + if (*q == decimal_point_) + { + dot = true; + writer.put('.'); + } + break; + } + } + if (!dot) + { + writer.put('.'); + writer.put('0'); + dot = true; + } + for (const char* q = pexp; q < send; ++q) + { + writer.put(*q); + } + } + } +}; + +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/obufferedstream.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/obufferedstream.hpp new file mode 100644 index 00000000..7b499f4b --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/obufferedstream.hpp @@ -0,0 +1,264 @@ +// Copyright 2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_OBUFFEREDSTREAM_HPP +#define JSONCONS_DETAIL_OBUFFEREDSTREAM_HPP + +#include <ios> +#include <ostream> +#include <string> +#include <cstddef> +#include <vector> +#include <locale> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { + +template< + class CharT, + class Traits = std::char_traits<CharT> +> class basic_obufferedstream; + +template<class CharT, class Traits> +class basic_ovectorbuf + : public std::basic_streambuf<CharT, Traits> +{ +private: + std::ios_base::openmode mode_; + std::vector<CharT> buf_; + +public: + typedef CharT char_type; + typedef typename Traits::int_type int_type; + typedef typename Traits::pos_type pos_type; + typedef typename Traits::off_type off_type; + typedef Traits traits_type; + +public: + + explicit basic_ovectorbuf() JSONCONS_NOEXCEPT + : mode_(std::ios_base::out | std::ios_base::binary), + buf_(100u) + { + // Set write position to beginning of buffer. + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->setg(buf_.data(), 0, buf_.data()); + } + + explicit basic_ovectorbuf(std::size_t length) JSONCONS_NOEXCEPT + : mode_(std::ios_base::out | std::ios_base::binary), + buf_(length) + { + // Set write position to beginning of buffer. + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->setg(buf_.data(), 0, buf_.data()); + } + + virtual ~basic_ovectorbuf() JSONCONS_NOEXCEPT {} + + basic_ovectorbuf(const basic_ovectorbuf<CharT,Traits>&) = delete; + + //basic_ovectorbuf(basic_ovectorbuf<CharT,Traits>&&) = default; + + basic_ovectorbuf<CharT,Traits>& operator=(const basic_ovectorbuf<CharT,Traits>&) = delete; + + //basic_ovectorbuf<CharT,Traits>& operator=(basic_ovectorbuf<CharT,Traits>&&) = default; + + const CharT* data() const + { + return buf_.data(); + } + + size_t length() const + { + return this->pptr() - this->pbase(); + } + + virtual int sync() override + { + return EOF; + } + +protected: + int_type underflow() override + { + return this->gptr() != this->egptr() ? + Traits::to_int_type(*this->gptr()) : Traits::eof(); + } + + int_type pbackfail(int_type c = Traits::eof()) override + { + if (this->gptr() != this->eback()) + { + if (!Traits::eq_int_type(c, Traits::eof())) + { + if (Traits::eq(Traits::to_char_type(c), this->gptr()[-1])) + { + this->gbump(-1); + return c; + } + this->gbump(-1); + *this->gptr() = static_cast<CharT>(c); + return c; + } + else + { + this->gbump(-1); + return Traits::not_eof(c); + } + } + else + { + return Traits::eof(); + } + } + + int_type overflow(int_type c = Traits::eof()) override + { + if (!Traits::eq_int_type(c, Traits::eof())) + { + size_t pos = buf_.size()+1; + buf_.resize(pos*2); + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->pubseekpos(pos, std::ios_base::out); + *this->pptr() = Traits::to_char_type(c); + this->pbump(1); + this->pubsync(); + return c; + } + else + { + return Traits::not_eof(c); + } + } + + pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode mode = std::ios_base::out) override + { + (void)mode; // Always out + + std::streamoff newoff; + switch (dir) + { + case std::ios_base::beg: + newoff = 0; + break; + case std::ios_base::end: + newoff = static_cast<std::streamoff>(buf_.size()); + break; + case std::ios_base::cur: + newoff = static_cast<std::streamoff>(this->pptr() - this->pbase()); + break; + default: + return pos_type(off_type(-1)); + } + + off += newoff; + + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if (off < 0 || off > n) return pos_type(off_type(-1)); + else + { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(static_cast<int>(off)); + } + + return pos_type(off); + } + + pos_type seekoff_beg(off_type off) + { + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if (off < 0 || off > n) + { + return pos_type(off_type(-1)); + } + else + { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(static_cast<int>(off)); + } + + return pos_type(off); + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode mode + = std::ios_base::out) override + { + + (void)mode; // Always out + + return seekoff_beg(pos - pos_type(off_type(0))); + } +}; + +template<class CharT, class Traits> +class basic_obufferedstream : + public std::basic_ostream<CharT, Traits> +{ +public: + typedef typename std::basic_ios<CharT, Traits>::char_type char_type; + typedef typename std::basic_ios<char_type, Traits>::int_type int_type; + typedef typename std::basic_ios<char_type, Traits>::pos_type pos_type; + typedef typename std::basic_ios<char_type, Traits>::off_type off_type; + typedef typename std::basic_ios<char_type, Traits>::traits_type traits_type; + +private: + typedef basic_ovectorbuf<CharT, Traits> base_ouputbuf; + typedef std::basic_ios<char_type, Traits> base_ios; + + basic_ovectorbuf<CharT, Traits> buf_; + +public: + basic_obufferedstream() JSONCONS_NOEXCEPT + : std::basic_ostream<CharT, Traits>( (std::basic_streambuf<CharT, Traits>*)(&buf_)), + buf_() + {} + basic_obufferedstream(std::size_t length) JSONCONS_NOEXCEPT + : std::basic_ostream<CharT, Traits>( (std::basic_streambuf<CharT, Traits>*)(&buf_)), + buf_(length) + {} + + basic_obufferedstream(const basic_obufferedstream<CharT,Traits>&) = delete; + + //basic_obufferedstream(basic_obufferedstream<CharT,Traits>&&) = default; + + virtual ~basic_obufferedstream() JSONCONS_NOEXCEPT + { + } + + basic_obufferedstream<CharT,Traits>& operator=(const basic_obufferedstream<CharT,Traits>&) = delete; + + //basic_obufferedstream<CharT,Traits>& operator=(basic_obufferedstream<CharT,Traits>&&) = default; + + const CharT* data() const + { + return buf_.data(); + } + + size_t length() const + { + return buf_.length(); + } + + void set_locale(const std::locale& loc) + { + std::locale result = std::basic_ostream<CharT, Traits>::imbue(loc); + //this->pubimbue(loc); + } + + void clear_sequence() + { + this->clear(); + this->seekp(0, std::ios::beg); + } +}; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/type_traits_helper.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/type_traits_helper.hpp new file mode 100644 index 00000000..4dce8e63 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/type_traits_helper.hpp @@ -0,0 +1,226 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_TYPETRAITSHELPER_HPP +#define JSONCONS_DETAIL_TYPETRAITSHELPER_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <memory> +#include <iterator> +#include <exception> +#include <array> +#include <initializer_list> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/detail/obufferedstream.hpp> + +namespace jsoncons +{ +// static_max + +template <size_t arg1, size_t ... argn> +struct static_max; + +template <size_t arg> +struct static_max<arg> +{ + static const size_t value = arg; +}; + +template <size_t arg1, size_t arg2, size_t ... argn> +struct static_max<arg1,arg2,argn ...> +{ + static const size_t value = arg1 >= arg2 ? + static_max<arg1,argn...>::value : + static_max<arg2,argn...>::value; +}; + +// type_wrapper + +template <class T> +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <class T> +struct type_wrapper<const T> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <class T> +struct type_wrapper<T&> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <class T> +struct type_wrapper<const T&> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +// json_literals + +namespace detail { +JSONCONS_DEFINE_LITERAL(null_literal,"null") +JSONCONS_DEFINE_LITERAL(true_literal,"true") +JSONCONS_DEFINE_LITERAL(false_literal,"false") +} + +inline +unsigned char to_hex_character(unsigned char c) +{ + JSONCONS_ASSERT(c <= 0xF); + + return (c < 10) ? ('0' + c) : ('A' - 10 + c); +} + +inline +bool is_control_character(uint32_t c) +{ + return c <= 0x1F || c == 0x7f; +} + +inline +bool is_non_ascii_codepoint(uint32_t cp) +{ + return cp >= 0x80; +} + +template <typename T> +struct is_stateless + : public std::integral_constant<bool, + (std::is_default_constructible<T>::value && + std::is_empty<T>::value)> +{}; + +// type traits extensions + + +namespace detail { + +// to_plain_pointer + +template<class Pointer> inline +typename std::pointer_traits<Pointer>::element_type* to_plain_pointer(Pointer ptr) +{ + return (std::addressof(*ptr)); +} + +template<class T> inline +T * to_plain_pointer(T * ptr) +{ + return (ptr); +} + +// is_string_like + +template <class T, class Enable=void> +struct is_string_like : std::false_type {}; + +template <class T> +struct is_string_like<T, + typename std::enable_if<!std::is_void<typename T::traits_type>::value +>::type> : std::true_type {}; + +// is_integer_like + +template <class T, class Enable=void> +struct is_integer_like : std::false_type {}; + +template <class T> +struct is_integer_like<T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value && + !std::is_same<T,bool>::value>::type> : std::true_type {}; + +// is_uinteger_like + +template <class T, class Enable=void> +struct is_uinteger_like : std::false_type {}; + +template <class T> +struct is_uinteger_like<T, + typename std::enable_if<std::is_integral<T>::value && + !std::is_signed<T>::value && + !std::is_same<T,bool>::value>::type> : std::true_type {}; + +// is_floating_point_like + +template <class T, class Enable=void> +struct is_floating_point_like : std::false_type {}; + +template <class T> +struct is_floating_point_like<T, + typename std::enable_if<std::is_floating_point<T>::value>::type> : std::true_type {}; + +// is_map_like + +template <class T, class Enable=void> +struct is_map_like : std::false_type {}; + +template <class T> +struct is_map_like<T, + typename std::enable_if<!std::is_void<typename T::mapped_type>::value>::type> + : std::true_type {}; + +// is_array_like +template<class T> +struct is_array_like : std::false_type {}; + +template<class E, size_t N> +struct is_array_like<std::array<E, N>> : std::true_type {}; + +// is_vector_like + +template <class T, class Enable=void> +struct is_vector_like : std::false_type {}; + +template <class T> +struct is_vector_like<T, + typename std::enable_if<!std::is_void<typename T::value_type>::value && + !is_array_like<T>::value && + !is_string_like<T>::value && + !is_map_like<T>::value +>::type> + : std::true_type {}; + +} + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/unicode_traits.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/unicode_traits.hpp new file mode 100644 index 00000000..affbb9b7 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/unicode_traits.hpp @@ -0,0 +1,1463 @@ +// Copyright 2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/unicode_traits for latest version + +/* + * Includes code derived from Unicode, Inc decomposition code in ConvertUTF.h and ConvertUTF.c + * http://www.unicode.org/ + * + * "Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard." +*/ + +#ifndef UNICONS_UNICODE_TRAITS_HPP +#define UNICONS_UNICODE_TRAITS_HPP + +#if defined (__clang__) +#if defined(_GLIBCXX_USE_NOEXCEPT) +#define UNICONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#else +#define UNICONS_NOEXCEPT noexcept +#endif +#elif defined(__GNUC__) +#define UNICONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define UNICONS_NOEXCEPT noexcept +#else +#define UNICONS_NOEXCEPT +#endif +#else +#define UNICONS_NOEXCEPT +#endif + +#include <string> +#include <iterator> +#include <type_traits> +#include <system_error> + +namespace unicons { + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. Source: ConvertUTF.c + */ +const uint32_t offsets_from_utf8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. Source: ConvertUTF.c + */ +const uint8_t first_byte_mark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. Source: ConvertUTF.c + */ +const uint8_t trailing_bytes_for_utf8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +// Some fundamental constants. Source: ConvertUTF.h +const uint32_t replacement_char = 0x0000FFFD; +const uint32_t max_bmp = 0x0000FFFF; +const uint32_t max_utf16 = 0x0010FFFF; +const uint32_t max_utf32 = 0x7FFFFFFF; +const uint32_t max_legal_utf32 = 0x0010FFFF; + +const int half_shift = 10; // used for shifting by 10 bits +const uint32_t half_base = 0x0010000UL; +const uint32_t half_mask = 0x3FFUL; + +const uint16_t sur_high_start = 0xD800; +const uint16_t sur_high_end = 0xDBFF; +const uint16_t sur_low_start = 0xDC00; +const uint16_t sur_low_end = 0xDFFF; + +inline +static bool is_continuation_byte(unsigned char ch) +{ + return (ch & 0xC0) == 0x80; +} + +inline +bool is_high_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_high_start && ch <= sur_high_end); +} + +inline +bool is_low_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_low_start && ch <= sur_low_end); +} + +inline +bool is_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_high_start && ch <= sur_low_end); +} + +enum class conv_flags +{ + strict = 0, + lenient +}; + +// conv_errc + +enum class conv_errc +{ + ok = 0, + over_long_utf8_sequence = 1, // over long utf8 sequence + expected_continuation_byte, // expected continuation byte + unpaired_high_surrogate, // unpaired high surrogate UTF-16 + illegal_surrogate_value, // UTF-16 surrogate values are illegal in UTF-32 + source_exhausted, // partial character in source, but hit end + source_illegal // source sequence is illegal/malformed +}; + +class Unicode_traits_error_category_impl_ + : public std::error_category +{ +public: + virtual const char* name() const UNICONS_NOEXCEPT + { + return "unicons conversion error"; + } + virtual std::string message(int ev) const + { + switch (static_cast<conv_errc>(ev)) + { + case conv_errc::over_long_utf8_sequence: + return "Over long utf8 sequence"; + case conv_errc::expected_continuation_byte: + return "Expected continuation byte"; + case conv_errc::unpaired_high_surrogate: + return "Unpaired high surrogate UTF-16"; + case conv_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case conv_errc::source_exhausted: + return "Partial character in source, but hit end"; + case conv_errc::source_illegal: + return "Source sequence is illegal/malformed"; + default: + return ""; + break; + } + } +}; + +inline +const std::error_category& unicode_traits_error_category() +{ + static Unicode_traits_error_category_impl_ instance; + return instance; +} + +inline +std::error_code make_error_code(conv_errc result) +{ + return std::error_code(static_cast<int>(result),unicode_traits_error_category()); +} + +// encoding_errc + +enum class encoding_errc +{ + ok = 0, + expected_u8_found_u16 = 1, + expected_u8_found_u32, + expected_u16_found_fffe, + expected_u32_found_fffe +}; + +class Encoding_errc_impl_ + : public std::error_category +{ +public: + virtual const char* name() const UNICONS_NOEXCEPT + { + return "unicons encoding error"; + } + virtual std::string message(int ev) const + { + switch (static_cast<encoding_errc>(ev)) + { + case encoding_errc::expected_u8_found_u16: + return "Expected UTF-8, found UTF-16"; + case encoding_errc::expected_u8_found_u32: + return "Expected UTF-8, found UTF-32"; + case encoding_errc::expected_u16_found_fffe: + return "Expected UTF-16, found non character"; + case encoding_errc::expected_u32_found_fffe: + return "Expected UTF-32, found non character"; + default: + return ""; + break; + } + } +}; + +inline +const std::error_category& encoding_error_category() +{ + static Encoding_errc_impl_ instance; + return instance; +} + +inline +std::error_code make_error_code(encoding_errc result) +{ + return std::error_code(static_cast<int>(result),encoding_error_category()); +} +} + +namespace std { + template<> + struct is_error_code_enum<unicons::conv_errc> : public true_type + { + }; + template<> + struct is_error_code_enum<unicons::encoding_errc> : public true_type + { + }; +} + +namespace unicons { + +// utf8 + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value + && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint8_t), + conv_errc >::type +is_legal_utf8(Iterator first, size_t length) +{ + uint8_t a; + Iterator srcptr = first+length; + switch (length) { + default: + return conv_errc::over_long_utf8_sequence; + case 4: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + // FALLTHRU + case 3: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + // FALLTHRU + case 2: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + + switch (static_cast<uint8_t>(*first)) + { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return conv_errc::source_illegal; break; + case 0xED: if (a > 0x9F) return conv_errc::source_illegal; break; + case 0xF0: if (a < 0x90) return conv_errc::source_illegal; break; + case 0xF4: if (a > 0x8F) return conv_errc::source_illegal; break; + default: if (a < 0x80) return conv_errc::source_illegal; + } + + // FALLTHRU + case 1: + if (static_cast<uint8_t>(*first) >= 0x80 && static_cast<uint8_t>(*first) < 0xC2) + return conv_errc::source_illegal; + // FALLTHRU + } + if (static_cast<uint8_t>(*first) > 0xF4) + return conv_errc::source_illegal; + + return conv_errc(); +} + +template <class...> using void_t = void; + +template <class, class, class = void> +struct is_output_iterator : std::false_type {}; + +template <class I, class E> +struct is_output_iterator<I, E, void_t< + typename std::iterator_traits<I>::iterator_category, + decltype(*std::declval<I>() = std::declval<E>())>> : std::true_type {}; + +// is_same_size fixes issue with vs2013 + +// primary template +template<class T1, class T2, class Enable = void> +struct is_same_size : std::false_type +{ +}; + +// specialization for non void types +template<class T1, class T2> +struct is_same_size<T1, T2, typename std::enable_if<!std::is_void<T1>::value && !std::is_void<T2>::value>::type> +{ + static const bool value = (sizeof(T1) == sizeof(T2)); +}; + +template<class OutputIt, class CharT, class Enable = void> +struct is_compatible_output_iterator : std::false_type {}; + +template<class OutputIt, class CharT> +struct is_compatible_output_iterator<OutputIt,CharT, + typename std::enable_if<is_output_iterator<OutputIt,CharT>::value + && std::is_void<typename std::iterator_traits<OutputIt>::value_type>::value + && std::is_integral<typename OutputIt::container_type::value_type>::value + && !std::is_void<typename OutputIt::container_type::value_type>::value + && is_same_size<typename OutputIt::container_type::value_type,CharT>::value>::type +> : std::true_type {}; + +template<class OutputIt, class CharT> +struct is_compatible_output_iterator<OutputIt,CharT, + typename std::enable_if<is_output_iterator<OutputIt,CharT>::value + && std::is_integral<typename std::iterator_traits<OutputIt>::value_type>::value + && is_same_size<typename std::iterator_traits<OutputIt>::value_type,CharT>::value>::type +> : std::true_type {}; + +template<class OutputIt, class CharT> +struct is_compatible_output_iterator<OutputIt,CharT, + typename std::enable_if<is_output_iterator<OutputIt,CharT>::value + && std::is_void<typename std::iterator_traits<OutputIt>::value_type>::value + && is_same_size<typename OutputIt::char_type,CharT>::value>::type +> : std::true_type {}; + +// convert + +template <class Iterator> +struct convert_result +{ + Iterator it; + conv_errc ec; +}; + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator<OutputIt,uint8_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, OutputIt target, conv_flags flags=conv_flags::strict) +{ + (void)flags; + + conv_errc result = conv_errc(); + while (first != last) + { + size_t length = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)] + 1; + if (length > (size_t)(last - first)) + { + return convert_result<InputIt>{first, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(first, length)) != conv_errc()) + { + return convert_result<InputIt>{first,result}; + } + + switch (length) { + case 4: *target++ = (static_cast<uint8_t>(*first++)); + case 3: *target++ = (static_cast<uint8_t>(*first++)); + case 2: *target++ = (static_cast<uint8_t>(*first++)); + case 1: *target++ = (static_cast<uint8_t>(*first++)); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator<OutputIt,uint16_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) + { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extra_bytes_to_read) { + case 5: ch += static_cast<uint8_t>(*first++); ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += static_cast<uint8_t>(*first++); ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 2: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 1: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 0: ch += static_cast<uint8_t>(*first++); + } + ch -= offsets_from_utf8[extra_bytes_to_read]; + + if (ch <= max_bmp) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + first -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = ((uint16_t)ch); /* normal case */ + } + } else if (ch > max_utf16) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + first -= (extra_bytes_to_read+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = (replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + *target++ = ((uint16_t)((ch >> half_shift) + sur_high_start)); + *target++ = ((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator<OutputIt,uint32_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first < last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extra_bytes_to_read) { + case 5: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 4: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 3: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 2: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 1: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 0: ch += static_cast<uint8_t>(*first++); + } + ch -= offsets_from_utf8[extra_bytes_to_read]; + + if (ch <= max_legal_utf32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + first -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = (ch); + } + } else { /* i.e., ch > max_legal_utf32 */ + result = conv_errc::source_illegal; + *target++ = (replacement_char); + } + } + return convert_result<InputIt>{first,result} ; +} + +// utf16 + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator<OutputIt,uint8_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) { + conv_errc result = conv_errc(); + while (first < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to uint32_t first. */ + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, convert to uint32_t. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (uint32_t)0x80) { + bytes_to_write = 1; + } else if (ch < (uint32_t)0x800) { + bytes_to_write = 2; + } else if (ch < (uint32_t)0x10000) { + bytes_to_write = 3; + } else if (ch < (uint32_t)0x110000) { + bytes_to_write = 4; + } else { + bytes_to_write = 3; + ch = replacement_char; + } + + uint8_t byte1 = 0; + uint8_t byte2 = 0; + uint8_t byte3 = 0; + uint8_t byte4 = 0; + + switch (bytes_to_write) { // note: everything falls through + case 4: byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 3: byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 2: byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 1: byte1 = (uint8_t)(ch | first_byte_mark[bytes_to_write]); + } + switch (bytes_to_write) + { + case 4: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + *target++ = (byte4); + break; + case 3: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + break; + case 2: + *target++ = (byte1); + *target++ = (byte2); + break; + case 1: + *target++ = (byte1); + break; + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator<OutputIt,uint16_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to uint32_t first. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + *target++ = ((uint16_t)ch); + *target++ = ((uint16_t)ch2); + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (is_low_surrogate(ch)) + { + // illegal leading low surrogate + if (flags == conv_flags::strict) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + else + { + *target++ = ((uint16_t)ch); + } + } + else + { + *target++ = ((uint16_t)ch); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator<OutputIt,uint32_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end ) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch) ) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + *target++ = (ch); + } + return convert_result<InputIt>{first,result} ; +} + +// utf32 + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator<OutputIt,uint8_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + while (first < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *first++; + if (flags == conv_flags::strict ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (uint32_t)0x80) { bytes_to_write = 1; + } else if (ch < (uint32_t)0x800) { bytes_to_write = 2; + } else if (ch < (uint32_t)0x10000) { bytes_to_write = 3; + } else if (ch <= max_legal_utf32) { bytes_to_write = 4; + } else { + bytes_to_write = 3; + ch = replacement_char; + result = conv_errc::source_illegal; + } + + uint8_t byte1 = 0; + uint8_t byte2 = 0; + uint8_t byte3 = 0; + uint8_t byte4 = 0; + + switch (bytes_to_write) { + case 4: + byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + // FALLTHRU + case 3: + byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + // FALLTHRU + case 2: + byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + // FALLTHRU + case 1: + byte1 = (uint8_t) (ch | first_byte_mark[bytes_to_write]); + } + + switch (bytes_to_write) + { + case 4: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + *target++ = (byte4); + break; + case 3: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + break; + case 2: + *target++ = (byte1); + *target++ = (byte2); + break; + case 1: + *target++ = (byte1); + break; + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator<OutputIt,uint16_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + if (ch <= max_bmp) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = ((uint16_t)ch); /* normal case */ + } + } else if (ch > max_legal_utf32) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + } else { + *target++ = (replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + *target++ = ((uint16_t)((ch >> half_shift) + sur_high_start)); + *target++ = ((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator<OutputIt,uint32_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + if (flags == conv_flags::strict ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + if (ch <= max_legal_utf32) + { + *target++ = (ch); + } + else + { + *target++ = (replacement_char); + result = conv_errc::source_illegal; + } + } + return convert_result<InputIt>{first,result} ; +} + +// validate + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + ,convert_result<InputIt>>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + while (first != last) + { + size_t length = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)] + 1; + if (length > (size_t)(last - first)) + { + return convert_result<InputIt>{first, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(first, length)) != conv_errc()) + { + return convert_result<InputIt>{first,result} ; + } + first += length; + } + return convert_result<InputIt>{first,result} ; +} + +// utf16 + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + ,convert_result<InputIt>>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, validate to uint32_t first. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ++first; + } else { + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (is_low_surrogate(ch)) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + return convert_result<InputIt>{first,result} ; +} + + +// utf32 + + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + ,convert_result<InputIt>>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + if (!(ch <= max_legal_utf32)) + { + result = conv_errc::source_illegal; + } + } + return convert_result<InputIt>{first,result} ; +} + +// sequence + +template <class Iterator> +class sequence +{ + Iterator first_; + size_t length_; +public: + sequence(Iterator first, size_t length) + : first_(first), length_(length) + { + } + + Iterator begin() const + { + return first_; + } + + size_t length() const + { + return length_; + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint8_t),uint32_t>::type + codepoint() const UNICONS_NOEXCEPT + { + uint32_t ch = 0; + Iterator it = first_; + switch (length_) + { + default: + return replacement_char; + break; + case 4: + ch += static_cast<uint8_t>(*it++); ch <<= 6; + // FALLTHRU + case 3: + ch += static_cast<uint8_t>(*it++); ch <<= 6; + // FALLTHRU + case 2: + ch += static_cast<uint8_t>(*it++); ch <<= 6; + // FALLTHRU + case 1: + ch += static_cast<uint8_t>(*it++); + ch -= offsets_from_utf8[length_ - 1]; + break; + } + if (ch <= max_legal_utf32) + { + if (is_surrogate(ch)) + { + ch = replacement_char; + } + } + else // ch > max_legal_utf32 + { + ch = replacement_char; + } + return ch; + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint16_t),uint32_t>::type + codepoint() const UNICONS_NOEXCEPT + { + if (length_ == 0) + { + return replacement_char; + } + if (length_ == 2) + { + uint32_t ch = *first_; + uint32_t ch2 = *(first_+ 1); + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + return ch; + } + else + { + return *first_; + } + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint32_t),uint32_t>::type + codepoint() const UNICONS_NOEXCEPT + { + if (length_ == 0) + { + return replacement_char; + } + return *(first_); + } +}; + +// sequence_generator + +template <class Iterator> +class sequence_generator +{ + Iterator begin_; + Iterator last_; + conv_flags flags_; + size_t length_; + conv_errc err_cd_; +public: + typedef sequence<Iterator> sequence_type; + + sequence_generator(Iterator first, Iterator last, + conv_flags flags = conv_flags::strict) UNICONS_NOEXCEPT + : begin_(first), last_(last), flags_(flags), + length_(0), err_cd_(conv_errc()) + { + next(); + } + + bool done() const UNICONS_NOEXCEPT + { + return err_cd_ != conv_errc() || begin_ == last_; + } + + conv_errc status() const UNICONS_NOEXCEPT + { + return err_cd_; + } + + sequence_type get() const UNICONS_NOEXCEPT + { + return sequence<Iterator>(begin_,length_); + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint8_t)>::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + if (begin_ != last_) + { + size_t length = trailing_bytes_for_utf8[static_cast<uint8_t>(*begin_)] + 1; + if (length > (size_t)(last_ - begin_)) + { + err_cd_ = conv_errc::source_exhausted; + } + else if ((err_cd_ = is_legal_utf8(begin_, length)) != conv_errc()) + { + } + else + { + length_ = length; + } + } + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint16_t)>::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + if (begin_ != last_) + { + if (begin_ != last_) + { + + Iterator it = begin_; + + uint32_t ch = *it++; + /* If we have a surrogate pair, validate to uint32_t it. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the it buffer... */ + if (it < last_) { + uint32_t ch2 = *it; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) + { + ++it; + length_ = 2; + } + else + { + err_cd_ = conv_errc::unpaired_high_surrogate; + } + } + else + { + // We don't have the 16 bits following the high surrogate. + err_cd_ = conv_errc::source_exhausted; + } + } + else if (is_low_surrogate(ch)) + { + /* leading low surrogate */ + err_cd_ = conv_errc::source_illegal; + } + else + { + length_ = 1; + } + } + } + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint32_t)>::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + length_ = 1; + } +}; + +template <class Iterator> +sequence_generator<Iterator> make_sequence_generator(Iterator first, Iterator last, + conv_flags flags = conv_flags::strict) +{ + return sequence_generator<Iterator>(first, last, flags); +} + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value + && (sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) || sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t)), + sequence<InputIt>>::type +sequence_at(InputIt first, InputIt last, size_t index) +{ + sequence_generator<InputIt> g(first, last, unicons::conv_flags::strict); + + size_t count = 0; + while (!g.done() && count < index) + { + g.next(); + ++count; + } + return (!g.done() && count == index) ? g.get() : sequence<InputIt>(last,0); +} + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t), + sequence<InputIt>>::type +sequence_at(InputIt first, InputIt last, size_t index) +{ + size_t size = std::distance(first,last); + return index < size ? sequence<InputIt>(first+index,1) : sequence<InputIt>(last,0); +} + +// u8_length + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + return std::distance(first,last); +} + +// utf16 + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_flags flags = conv_flags::strict; + size_t count = 0; + for (InputIt p = first; p != last; ++p) + { + uint32_t ch = *p; + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the p buffer... */ + if (p < last) { + uint32_t ch2 = *(++p); + /* If it's a low surrogate, convert to uint32_t. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch)) { + break; + } + } + if (ch < (uint32_t)0x80) { + ++count; + } else if (ch < (uint32_t)0x800) { + count += 2; + } else if (ch < (uint32_t)0x10000) { + count += 3; + } else if (ch < (uint32_t)0x110000) { + count += 4; + } else { + count += 3; + } + } + return count; +} + + +// utf32 + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + size_t count = 0; + for (InputIt p = first; p < last; ++p) + { + uint32_t ch = *p; + if (ch < (uint32_t)0x80) { + ++count; + } else if (ch < (uint32_t)0x800) { + count += 2; + } else if (ch < (uint32_t)0x10000) { + count += 3; + } else if (ch <= max_legal_utf32) { + count += 4; + } else { + count += 3; + } + } + return count; +} + +// u32_length + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value + && (sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) || sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t)), + size_t>::type +u32_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + sequence_generator<InputIt> g(first, last, unicons::conv_flags::strict); + + size_t count = 0; + while (!g.done()) + { + g.next(); + ++count; + } + return count; +} + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t), + size_t>::type +u32_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + return std::distance(first,last); +} + +enum class encoding {u8,u16le,u16be,u32le,u32be,undetected}; + +template <class Iterator> +struct detect_encoding_result +{ + Iterator it; + encoding ec; +}; + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint8_t), + detect_encoding_result<Iterator>>::type +detect_encoding(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + Iterator it1 = first; + if (std::distance(first,last) < 4) + { + if (std::distance(first,last) == 3) + { + Iterator it2 = ++first; + Iterator it3 = ++first; + if (static_cast<uint8_t>(*it1) == 0xEF && static_cast<uint8_t>(*it2) == 0xBB && static_cast<uint8_t>(*it3) == 0xBF) + { + return detect_encoding_result<Iterator>{last,encoding::u8}; + } + } + return detect_encoding_result<Iterator>{it1,encoding::undetected}; + } + else + { + Iterator it2 = ++first; + Iterator it3 = ++first; + Iterator it4 = ++first; + + uint32_t bom = static_cast<uint8_t>(*it1) | (static_cast<uint8_t>(*it2) << 8) | (static_cast<uint8_t>(*it3) << 16) | (static_cast<uint8_t>(*it4) << 24); + if (bom == 0xFFFE0000) + { + return detect_encoding_result<Iterator>{it4++,encoding::u32be}; + } + else if (bom == 0x0000FEFF) + { + return detect_encoding_result<Iterator>{first,encoding::u32le}; + } + else if ((bom & 0xFFFF) == 0xFFFE) + { + return detect_encoding_result<Iterator>{it3,encoding::u16be}; + } + else if ((bom & 0xFFFF) == 0xFEFF) + { + return detect_encoding_result<Iterator>{it3,encoding::u16le}; + } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) + { + return detect_encoding_result<Iterator>{it4,encoding::u8}; + } + else + { + uint32_t pattern = (static_cast<uint8_t>(*it1) ? 1 : 0) | (static_cast<uint8_t>(*it2) ? 2 : 0) | (static_cast<uint8_t>(*it3) ? 4 : 0) | (static_cast<uint8_t>(*it4) ? 8 : 0); + switch (pattern) { + case 0x08: + return detect_encoding_result<Iterator>{it1,encoding::u32be}; + case 0x0A: + return detect_encoding_result<Iterator>{it1,encoding::u16be}; + case 0x01: + return detect_encoding_result<Iterator>{it1,encoding::u32le}; + case 0x05: + return detect_encoding_result<Iterator>{it1,encoding::u16le}; + case 0x0F: + return detect_encoding_result<Iterator>{it1,encoding::u8}; + default: + return detect_encoding_result<Iterator>{it1,encoding::undetected}; + } + } + } +} + +template <class Iterator> +struct skip_bom_result +{ + Iterator it; + encoding_errc ec; +}; + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint8_t), + skip_bom_result<Iterator>>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + auto result = unicons::detect_encoding(first,last); + switch (result.ec) + { + case unicons::encoding::u8: + return skip_bom_result<Iterator>{result.it,encoding_errc()}; + break; + case unicons::encoding::u16le: + case unicons::encoding::u16be: + return skip_bom_result<Iterator>{result.it,encoding_errc::expected_u8_found_u16}; + break; + case unicons::encoding::u32le: + case unicons::encoding::u32be: + return skip_bom_result<Iterator>{result.it,encoding_errc::expected_u8_found_u32}; + break; + default: + return skip_bom_result<Iterator>{result.it,encoding_errc()}; + break; + } +} + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint16_t), + skip_bom_result<Iterator>>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + if (first == last) + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } + uint16_t bom = static_cast<uint16_t>(*first); + if (bom == 0xFEFF) + { + return skip_bom_result<Iterator>{++first,encoding_errc()}; + } + else if (bom == 0xFFFE) + { + return skip_bom_result<Iterator>{last,encoding_errc::expected_u16_found_fffe}; + } + else + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } +} + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint32_t), + skip_bom_result<Iterator>>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + if (first == last) + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } + uint32_t bom = static_cast<uint32_t>(*first); + if (bom == 0xFEFF0000) + { + return skip_bom_result<Iterator>{++first,encoding_errc()}; + } + else if (bom == 0xFFFE0000) + { + return skip_bom_result<Iterator>{last,encoding_errc::expected_u32_found_fffe}; + } + else + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } +} + +} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/writer.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/writer.hpp new file mode 100644 index 00000000..c832f06f --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/writer.hpp @@ -0,0 +1,155 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_WRITERS_HPP +#define JSONCONS_DETAIL_WRITERS_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <exception> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/detail/type_traits_helper.hpp> + +namespace jsoncons { namespace detail { + +template <class CharT> +class ostream_buffered_writer +{ +public: + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef std::basic_ostream<CharT> output_type; +private: + static const size_t default_buffer_length = 16384; + + std::basic_ostream<CharT>& os_; + std::vector<CharT> buffer_; + CharT * begin_buffer_; + const CharT* end_buffer_; + CharT* p_; + + // Noncopyable and nonmoveable + ostream_buffered_writer(const ostream_buffered_writer&) = delete; + ostream_buffered_writer& operator=(const ostream_buffered_writer&) = delete; + +public: + ostream_buffered_writer(std::basic_ostream<CharT>& os) + : os_(os), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + ostream_buffered_writer(std::basic_ostream<CharT>& os, size_t buflen) + : os_(os), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + ~ostream_buffered_writer() + { + os_.write(begin_buffer_, buffer_length()); + os_.flush(); + } + + void flush() + { + os_.write(begin_buffer_, buffer_length()); + p_ = buffer_.data(); + } + + void write(const CharT* s, size_t length) + { + size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(CharT)); + p_ += length; + } + else + { + os_.write(begin_buffer_, buffer_length()); + os_.write(s,length); + p_ = begin_buffer_; + } + } + + void write(const string_view_type& s) + { + write(s.data(),s.length()); + } + + void put(CharT ch) + { + if (p_ < end_buffer_) + { + *p_++ = ch; + } + else + { + os_.write(begin_buffer_, buffer_length()); + p_ = begin_buffer_; + put(ch); + } + } +private: + + size_t buffer_length() const + { + return p_ - begin_buffer_; + } +}; + +template <class CharT> +class string_writer +{ +public: + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef std::basic_string<CharT> output_type; +private: + std::basic_string<CharT>& s_; + + // Noncopyable and nonmoveable + string_writer(const string_writer&) = delete; + string_writer& operator=(const string_writer&) = delete; +public: + + string_writer(std::basic_string<CharT>& s) + : s_(s) + { + } + + void flush() + { + } + + void write(const CharT* s, size_t length) + { + s_.append(s,length); + } + + void write(const string_view_type& s) + { + s_.append(s.data(),s.length()); + } + + void put(CharT ch) + { + s_.push_back(ch); + } +}; + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json.hpp b/vendor/jsoncons-0.104.0/jsoncons/json.hpp new file mode 100644 index 00000000..fe9aec4e --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json.hpp @@ -0,0 +1,4959 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_HPP +#define JSONCONS_JSON_HPP + +#include <limits> +#include <string> +#include <vector> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <ostream> +#include <memory> +#include <typeinfo> +#include <cstring> +#include <jsoncons/version.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/json_structures.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_serializer.hpp> +#include <jsoncons/json_decoder.hpp> +#include <jsoncons/json_reader.hpp> +#include <jsoncons/json_type_traits.hpp> +#include <jsoncons/json_error_category.hpp> +#include <jsoncons/detail/heap_only_string.hpp> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons { + +struct sorted_policy +{ + static const bool preserve_order = false; + + template <class T,class Allocator> + using object_storage = std::vector<T,Allocator>; + + template <class T,class Allocator> + using array_storage = std::vector<T,Allocator>; + + template <class CharT, class CharTraits, class Allocator> + using key_storage = std::basic_string<CharT, CharTraits,Allocator>; + + template <class CharT, class CharTraits, class Allocator> + using string_storage = std::basic_string<CharT, CharTraits,Allocator>; + + typedef default_parse_error_handler parse_error_handler_type; +}; + +struct preserve_order_policy : public sorted_policy +{ + static const bool preserve_order = true; +}; + +template <typename IteratorT> +class range +{ + IteratorT first_; + IteratorT last_; +public: + range(const IteratorT& first, const IteratorT& last) + : first_(first), last_(last) + { + } + +public: + IteratorT begin() + { + return first_; + } + IteratorT end() + { + return last_; + } +}; + +enum class json_type_tag : uint8_t +{ + null_t = 0, + empty_object_t, + bool_t, + integer_t, + uinteger_t, + double_t, + small_string_t, + string_t, + byte_string_t, + array_t, + object_t +}; + +template <class CharT, + class ImplementationPolicy = sorted_policy, + class Allocator = std::allocator<CharT>> +class basic_json +{ +public: + + typedef Allocator allocator_type; + + typedef ImplementationPolicy implementation_policy; + + typedef typename ImplementationPolicy::parse_error_handler_type parse_error_handler_type; + + typedef CharT char_type; + typedef typename std::char_traits<char_type> char_traits_type; + + typedef basic_string_view_ext<char_type,char_traits_type> string_view_type; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<char_type> char_allocator_type; + using string_storage_type = typename implementation_policy::template string_storage<CharT,char_traits_type,char_allocator_type>; + using key_storage_type = typename implementation_policy::template key_storage<CharT,char_traits_type,char_allocator_type>; + + // string_type is for interface only, not storage + typedef std::basic_string<CharT,char_traits_type,char_allocator_type> string_type; + + typedef basic_json<CharT,ImplementationPolicy,Allocator> value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef key_value_pair<key_storage_type,value_type> key_value_pair_type; + +#if !defined(JSONCONS_NO_DEPRECATED) + typedef value_type json_type; + typedef key_value_pair_type kvp_type; + typedef key_value_pair_type member_type; + typedef jsoncons::null_type null_type; +#endif + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<basic_json> val_allocator_type; + using array_storage_type = typename implementation_policy::template array_storage<basic_json, val_allocator_type>; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t> byte_allocator_type; + using byte_string_storage_type = typename implementation_policy::template array_storage<uint8_t, byte_allocator_type>; + + typedef json_array<basic_json> array; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<key_value_pair_type> kvp_allocator_type; + + using object_storage_type = typename implementation_policy::template object_storage<key_value_pair_type , kvp_allocator_type>; + typedef json_object<key_storage_type,basic_json,implementation_policy::preserve_order> object; + + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<array> array_allocator; + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<object> object_allocator; + + typedef typename object::iterator object_iterator; + typedef typename object::const_iterator const_object_iterator; + typedef typename array::iterator array_iterator; + typedef typename array::const_iterator const_array_iterator; + + struct variant + { + struct data_base + { + json_type_tag type_id_; + + data_base(json_type_tag id) + : type_id_(id) + {} + }; + + class null_data final : public data_base + { + public: + null_data() + : data_base(json_type_tag::null_t) + { + } + }; + + class empty_object_data final : public data_base + { + public: + empty_object_data() + : data_base(json_type_tag::empty_object_t) + { + } + }; + + class bool_data final : public data_base + { + bool val_; + public: + bool_data(bool val) + : data_base(json_type_tag::bool_t),val_(val) + { + } + + bool_data(const bool_data& val) + : data_base(json_type_tag::bool_t),val_(val.val_) + { + } + + bool value() const + { + return val_; + } + + }; + + class integer_data final : public data_base + { + int64_t val_; + public: + integer_data(int64_t val) + : data_base(json_type_tag::integer_t),val_(val) + { + } + + integer_data(const integer_data& val) + : data_base(json_type_tag::integer_t),val_(val.val_) + { + } + + int64_t value() const + { + return val_; + } + }; + + class uinteger_data final : public data_base + { + uint64_t val_; + public: + uinteger_data(uint64_t val) + : data_base(json_type_tag::uinteger_t),val_(val) + { + } + + uinteger_data(const uinteger_data& val) + : data_base(json_type_tag::uinteger_t),val_(val.val_) + { + } + + uint64_t value() const + { + return val_; + } + }; + + class double_data final : public data_base + { + chars_format format_; + uint8_t precision_; + uint8_t decimal_places_; + double val_; + public: + double_data(double val) + : data_base(json_type_tag::double_t), + precision_(0), + decimal_places_(0), + val_(val) + { + } + double_data(double val, const number_format& fmt) + : data_base(json_type_tag::double_t), + format_(fmt.floating_point_format()), + precision_(fmt.precision()), + decimal_places_(fmt.decimal_places()), + val_(val) + { + } + + double_data(const double_data& val) + : data_base(json_type_tag::double_t), + precision_(val.precision_), + decimal_places_(val.decimal_places_), + val_(val.val_) + { + } + + double value() const + { + return val_; + } + + uint8_t precision() const + { + return precision_; + } + + uint8_t decimal_places() const + { + return precision_; + } + }; + + class small_string_data final : public data_base + { + static const size_t capacity = 14/sizeof(char_type); + uint8_t length_; + char_type data_[capacity]; + public: + static const size_t max_length = (14 / sizeof(char_type)) - 1; + + small_string_data(const char_type* p, uint8_t length) + : data_base(json_type_tag::small_string_t), length_(length) + { + JSONCONS_ASSERT(length <= max_length); + std::memcpy(data_,p,length*sizeof(char_type)); + data_[length] = 0; + } + + small_string_data(const small_string_data& val) + : data_base(json_type_tag::small_string_t), length_(val.length_) + { + std::memcpy(data_,val.data_,val.length_*sizeof(char_type)); + data_[length_] = 0; + } + + uint8_t length() const + { + return length_; + } + + const char_type* data() const + { + return data_; + } + + const char_type* c_str() const + { + return data_; + } + }; + + // string_data + class string_data final : public data_base + { + typedef typename detail::heap_only_string_factory<char_type, Allocator>::string_pointer pointer; + + pointer ptr_; + public: + string_data(const string_data& val) + : data_base(json_type_tag::string_t) + { + ptr_ = detail::heap_only_string_factory<char_type,Allocator>::create(val.data(),val.length(),val.get_allocator()); + } + + string_data(string_data&& val) + : data_base(json_type_tag::string_t), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + string_data(const string_data& val, const Allocator& a) + : data_base(json_type_tag::string_t) + { + ptr_ = detail::heap_only_string_factory<char_type,Allocator>::create(val.data(),val.length(),a); + } + + string_data(const char_type* data, size_t length, const Allocator& a) + : data_base(json_type_tag::string_t) + { + ptr_ = detail::heap_only_string_factory<char_type,Allocator>::create(data,length,a); + } + + ~string_data() + { + if (ptr_ != nullptr) + { + detail::heap_only_string_factory<char_type,Allocator>::destroy(ptr_); + } + } + + void swap(string_data& val) + { + std::swap(val.ptr_,ptr_); + } + + const char_type* data() const + { + return ptr_->data(); + } + + const char_type* c_str() const + { + return ptr_->c_str(); + } + + size_t length() const + { + return ptr_->length(); + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + // byte_string_data + class byte_string_data final : public data_base + { + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<byte_string_storage_type> string_holder_allocator_type; + typedef typename std::allocator_traits<string_holder_allocator_type>::pointer pointer; + + pointer ptr_; + + template <typename... Args> + void create(string_holder_allocator_type allocator, Args&& ... args) + { + typename std::allocator_traits<Allocator>:: template rebind_alloc<byte_string_storage_type> alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits<string_holder_allocator_type>:: template rebind_traits<byte_string_storage_type>::construct(alloc, detail::to_plain_pointer(ptr_), std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + byte_string_data(const byte_string_data& val) + : data_base(json_type_tag::byte_string_t) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + byte_string_data(byte_string_data&& val) + : data_base(json_type_tag::byte_string_t), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + byte_string_data(const byte_string_data& val, const Allocator& a) + : data_base(json_type_tag::byte_string_t) + { + create(string_holder_allocator_type(a), *(val.ptr_), a); + } + + byte_string_data(const uint8_t* data, size_t length, const Allocator& a) + : data_base(json_type_tag::byte_string_t) + { + create(string_holder_allocator_type(a), data, data+length, a); + } + + ~byte_string_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits<string_holder_allocator_type>:: template rebind_alloc<byte_string_storage_type> alloc(ptr_->get_allocator()); + std::allocator_traits<string_holder_allocator_type>:: template rebind_traits<byte_string_storage_type>::destroy(alloc, detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + void swap(byte_string_data& val) + { + std::swap(val.ptr_,ptr_); + } + + const uint8_t* data() const + { + return ptr_->data(); + } + + size_t length() const + { + return ptr_->size(); + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + // array_data + class array_data final : public data_base + { + typedef typename std::allocator_traits<array_allocator>::pointer pointer; + pointer ptr_; + + template <typename... Args> + void create(array_allocator allocator, Args&& ... args) + { + typename std::allocator_traits<Allocator>:: template rebind_alloc<array> alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits<array_allocator>:: template rebind_traits<array>::construct(alloc, detail::to_plain_pointer(ptr_), std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + array_data(const array& val) + : data_base(json_type_tag::array_t) + { + create(val.get_allocator(), val); + } + + array_data(const array& val, const Allocator& a) + : data_base(json_type_tag::array_t) + { + create(array_allocator(a), val, a); + } + + array_data(const array_data& val) + : data_base(json_type_tag::array_t) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + array_data(array_data&& val) + : data_base(json_type_tag::array_t), ptr_(nullptr) + { + std::swap(val.ptr_, ptr_); + } + + array_data(const array_data& val, const Allocator& a) + : data_base(json_type_tag::array_t) + { + create(array_allocator(a), *(val.ptr_), a); + } + ~array_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits<array_allocator>:: template rebind_alloc<array> alloc(ptr_->get_allocator()); + std::allocator_traits<array_allocator>:: template rebind_traits<array>::destroy(alloc, detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + + void swap(array_data& val) + { + std::swap(val.ptr_,ptr_); + } + + array& value() + { + return *ptr_; + } + + const array& value() const + { + return *ptr_; + } + }; + + // object_data + class object_data final : public data_base + { + typedef typename std::allocator_traits<object_allocator>::pointer pointer; + pointer ptr_; + + template <typename... Args> + void create(Allocator allocator, Args&& ... args) + { + typename std::allocator_traits<object_allocator>:: template rebind_alloc<object> alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits<object_allocator>:: template rebind_traits<object>::construct(alloc, detail::to_plain_pointer(ptr_), std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + explicit object_data(const Allocator& a) + : data_base(json_type_tag::object_t) + { + create(a,a); + } + + explicit object_data(const object& val) + : data_base(json_type_tag::object_t) + { + create(val.get_allocator(), val); + } + + explicit object_data(const object& val, const Allocator& a) + : data_base(json_type_tag::object_t) + { + create(object_allocator(a), val, a); + } + + explicit object_data(const object_data& val) + : data_base(json_type_tag::object_t) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + explicit object_data(object_data&& val) + : data_base(json_type_tag::object_t), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + explicit object_data(const object_data& val, const Allocator& a) + : data_base(json_type_tag::object_t) + { + create(object_allocator(a), *(val.ptr_), a); + } + + ~object_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits<Allocator>:: template rebind_alloc<object> alloc(ptr_->get_allocator()); + std::allocator_traits<Allocator>:: template rebind_traits<object>::destroy(alloc, detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + void swap(object_data& val) + { + std::swap(val.ptr_,ptr_); + } + + object& value() + { + return *ptr_; + } + + const object& value() const + { + return *ptr_; + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + private: + static const size_t data_size = static_max<sizeof(uinteger_data),sizeof(double_data),sizeof(small_string_data), sizeof(string_data), sizeof(array_data), sizeof(object_data)>::value; + static const size_t data_align = static_max<JSONCONS_ALIGNOF(uinteger_data),JSONCONS_ALIGNOF(double_data),JSONCONS_ALIGNOF(small_string_data),JSONCONS_ALIGNOF(string_data),JSONCONS_ALIGNOF(array_data),JSONCONS_ALIGNOF(object_data)>::value; + + typedef typename std::aligned_storage<data_size,data_align>::type data_t; + + data_t data_; + public: + variant() + { + new(reinterpret_cast<void*>(&data_))empty_object_data(); + } + + variant(const Allocator& a) + { + new(reinterpret_cast<void*>(&data_))object_data(a); + } + + variant(const variant& val) + { + Init_(val); + } + + variant(const variant& val, const Allocator& allocator) + { + Init_(val,allocator); + } + + variant(variant&& val) JSONCONS_NOEXCEPT + { + Init_rv_(std::forward<variant>(val)); + } + + variant(variant&& val, const Allocator& allocator) JSONCONS_NOEXCEPT + { + Init_rv_(std::forward<variant>(val), allocator, + typename std::allocator_traits<Allocator>::propagate_on_container_move_assignment()); + } + + explicit variant(null_type) + { + new(reinterpret_cast<void*>(&data_))null_data(); + } + explicit variant(bool val) + { + new(reinterpret_cast<void*>(&data_))bool_data(val); + } + explicit variant(int64_t val) + { + new(reinterpret_cast<void*>(&data_))integer_data(val); + } + explicit variant(uint64_t val, const Allocator&) + { + new(reinterpret_cast<void*>(&data_))uinteger_data(val); + } + explicit variant(uint64_t val) + { + new(reinterpret_cast<void*>(&data_))uinteger_data(val); + } + variant(double val) + { + new(reinterpret_cast<void*>(&data_))double_data(val); + } + variant(double val, const number_format& fmt) + { + new(reinterpret_cast<void*>(&data_))double_data(val, fmt); + } + variant(const char_type* s, size_t length) + { + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, char_allocator_type()); + } + } + variant(const uint8_t* s, size_t length) + { + new(reinterpret_cast<void*>(&data_))byte_string_data(s, length, byte_allocator_type()); + } + + variant(const uint8_t* s, size_t length, const Allocator& alloc) + { + new(reinterpret_cast<void*>(&data_))byte_string_data(s, length, alloc); + } + + variant(const char_type* s) + { + size_t length = char_traits_type::length(s); + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, char_allocator_type()); + } + } + + variant(const char_type* s, const Allocator& alloc) + { + size_t length = char_traits_type::length(s); + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, alloc); + } + } + + variant(const char_type* s, size_t length, const Allocator& alloc) + { + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, alloc); + } + } + variant(const object& val) + { + new(reinterpret_cast<void*>(&data_))object_data(val); + } + variant(const object& val, const Allocator& alloc) + { + new(reinterpret_cast<void*>(&data_))object_data(val, alloc); + } + variant(const array& val) + { + new(reinterpret_cast<void*>(&data_))array_data(val); + } + variant(const array& val, const Allocator& alloc) + { + new(reinterpret_cast<void*>(&data_))array_data(val,alloc); + } + + ~variant() + { + Destroy_(); + } + + void Destroy_() + { + switch (type_id()) + { + case json_type_tag::string_t: + reinterpret_cast<string_data*>(&data_)->~string_data(); + break; + case json_type_tag::byte_string_t: + reinterpret_cast<byte_string_data*>(&data_)->~byte_string_data(); + break; + case json_type_tag::object_t: + reinterpret_cast<object_data*>(&data_)->~object_data(); + break; + case json_type_tag::array_t: + reinterpret_cast<array_data*>(&data_)->~array_data(); + break; + default: + break; + } + } + + variant& operator=(const variant& val) + { + if (this !=&val) + { + Destroy_(); + switch (val.type_id()) + { + case json_type_tag::null_t: + new(reinterpret_cast<void*>(&data_))null_data(); + break; + case json_type_tag::empty_object_t: + new(reinterpret_cast<void*>(&data_))empty_object_data(); + break; + case json_type_tag::bool_t: + new(reinterpret_cast<void*>(&data_))bool_data(*(val.bool_data_cast())); + break; + case json_type_tag::integer_t: + new(reinterpret_cast<void*>(&data_))integer_data(*(val.integer_data_cast())); + break; + case json_type_tag::uinteger_t: + new(reinterpret_cast<void*>(&data_))uinteger_data(*(val.uinteger_data_cast())); + break; + case json_type_tag::double_t: + new(reinterpret_cast<void*>(&data_))double_data(*(val.double_data_cast())); + break; + case json_type_tag::small_string_t: + new(reinterpret_cast<void*>(&data_))small_string_data(*(val.small_string_data_cast())); + break; + case json_type_tag::string_t: + new(reinterpret_cast<void*>(&data_))string_data(*(val.string_data_cast())); + break; + case json_type_tag::byte_string_t: + new(reinterpret_cast<void*>(&data_))byte_string_data(*(val.byte_string_data_cast())); + break; + case json_type_tag::array_t: + new(reinterpret_cast<void*>(&data_))array_data(*(val.array_data_cast())); + break; + case json_type_tag::object_t: + new(reinterpret_cast<void*>(&data_))object_data(*(val.object_data_cast())); + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + return *this; + } + + variant& operator=(variant&& val) JSONCONS_NOEXCEPT + { + if (this !=&val) + { + swap(val); + } + return *this; + } + + json_type_tag type_id() const + { + return reinterpret_cast<const data_base*>(&data_)->type_id_; + } + + const null_data* null_data_cast() const + { + return reinterpret_cast<const null_data*>(&data_); + } + + const empty_object_data* empty_object_data_cast() const + { + return reinterpret_cast<const empty_object_data*>(&data_); + } + + const bool_data* bool_data_cast() const + { + return reinterpret_cast<const bool_data*>(&data_); + } + + const integer_data* integer_data_cast() const + { + return reinterpret_cast<const integer_data*>(&data_); + } + + const uinteger_data* uinteger_data_cast() const + { + return reinterpret_cast<const uinteger_data*>(&data_); + } + + const double_data* double_data_cast() const + { + return reinterpret_cast<const double_data*>(&data_); + } + + const small_string_data* small_string_data_cast() const + { + return reinterpret_cast<const small_string_data*>(&data_); + } + + string_data* string_data_cast() + { + return reinterpret_cast<string_data*>(&data_); + } + + const string_data* string_data_cast() const + { + return reinterpret_cast<const string_data*>(&data_); + } + + byte_string_data* byte_string_data_cast() + { + return reinterpret_cast<byte_string_data*>(&data_); + } + + const byte_string_data* byte_string_data_cast() const + { + return reinterpret_cast<const byte_string_data*>(&data_); + } + + object_data* object_data_cast() + { + return reinterpret_cast<object_data*>(&data_); + } + + const object_data* object_data_cast() const + { + return reinterpret_cast<const object_data*>(&data_); + } + + array_data* array_data_cast() + { + return reinterpret_cast<array_data*>(&data_); + } + + const array_data* array_data_cast() const + { + return reinterpret_cast<const array_data*>(&data_); + } + + string_view_type as_string_view() const + { + switch (type_id()) + { + case json_type_tag::small_string_t: + return string_view_type(small_string_data_cast()->data(),small_string_data_cast()->length()); + case json_type_tag::string_t: + return string_view_type(string_data_cast()->data(),string_data_cast()->length()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a string")); + } + } + + byte_string_view as_byte_string_view() const + { + switch (type_id()) + { + case json_type_tag::byte_string_t: + return byte_string_view(byte_string_data_cast()->data(),byte_string_data_cast()->length()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a byte string")); + } + } + + bool operator==(const variant& rhs) const + { + if (this ==&rhs) + { + return true; + } + switch (type_id()) + { + case json_type_tag::null_t: + switch (rhs.type_id()) + { + case json_type_tag::null_t: + return true; + default: + return false; + } + break; + case json_type_tag::empty_object_t: + switch (rhs.type_id()) + { + case json_type_tag::empty_object_t: + return true; + case json_type_tag::object_t: + return rhs.object_data_cast()->value().size() == 0; + default: + return false; + } + break; + case json_type_tag::bool_t: + switch (rhs.type_id()) + { + case json_type_tag::bool_t: + return bool_data_cast()->value() == rhs.bool_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::integer_t: + switch (rhs.type_id()) + { + case json_type_tag::integer_t: + return integer_data_cast()->value() == rhs.integer_data_cast()->value(); + case json_type_tag::uinteger_t: + return integer_data_cast()->value() >= 0 ? static_cast<uint64_t>(integer_data_cast()->value()) == rhs.uinteger_data_cast()->value() : false; + case json_type_tag::double_t: + return static_cast<double>(integer_data_cast()->value()) == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::uinteger_t: + switch (rhs.type_id()) + { + case json_type_tag::integer_t: + return rhs.integer_data_cast()->value() >= 0 ? uinteger_data_cast()->value() == static_cast<uint64_t>(rhs.integer_data_cast()->value()) : false; + case json_type_tag::uinteger_t: + return uinteger_data_cast()->value() == rhs.uinteger_data_cast()->value(); + case json_type_tag::double_t: + return static_cast<double>(uinteger_data_cast()->value()) == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::double_t: + switch (rhs.type_id()) + { + case json_type_tag::integer_t: + return double_data_cast()->value() == static_cast<double>(rhs.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return double_data_cast()->value() == static_cast<double>(rhs.uinteger_data_cast()->value()); + case json_type_tag::double_t: + return double_data_cast()->value() == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::small_string_t: + switch (rhs.type_id()) + { + case json_type_tag::small_string_t: + return as_string_view() == rhs.as_string_view(); + case json_type_tag::string_t: + return as_string_view() == rhs.as_string_view(); + default: + return false; + } + break; + case json_type_tag::byte_string_t: + switch (rhs.type_id()) + { + case json_type_tag::byte_string_t: + { + return as_byte_string_view() == rhs.as_byte_string_view(); + } + default: + return false; + } + break; + case json_type_tag::string_t: + switch (rhs.type_id()) + { + case json_type_tag::small_string_t: + return as_string_view() == rhs.as_string_view(); + case json_type_tag::string_t: + return as_string_view() == rhs.as_string_view(); + default: + return false; + } + break; + case json_type_tag::array_t: + switch (rhs.type_id()) + { + case json_type_tag::array_t: + return array_data_cast()->value() == rhs.array_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::object_t: + switch (rhs.type_id()) + { + case json_type_tag::empty_object_t: + return object_data_cast()->value().size() == 0; + case json_type_tag::object_t: + return object_data_cast()->value() == rhs.object_data_cast()->value(); + default: + return false; + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + bool operator!=(const variant& rhs) const + { + return !(*this == rhs); + } + + template <class Alloc = allocator_type> + typename std::enable_if<std::is_pod<typename std::allocator_traits<Alloc>::pointer>::value,void>::type + swap(variant& other) JSONCONS_NOEXCEPT + { + if (this ==&other) + { + return; + } + + std::swap(data_,other.data_); + } + + template <class Alloc = allocator_type> + typename std::enable_if<!std::is_pod<typename std::allocator_traits<Alloc>::pointer>::value, void>::type + swap(variant& other) JSONCONS_NOEXCEPT + { + if (this ==&other) + { + return; + } + switch (type_id()) + { + case json_type_tag::null_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::empty_object_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::bool_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::integer_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::uinteger_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::double_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::small_string_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::string_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + string_data_cast()->swap(*other.string_data_cast()); + } + break; + case json_type_tag::byte_string_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))array_data(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))object_data(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + case json_type_tag::byte_string_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))string_data(*(other.string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data_cast()->swap(*other.byte_string_data_cast()); + } + break; + case json_type_tag::array_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))array_data(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))object_data(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + case json_type_tag::array_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))string_data(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data_cast()->swap(*other.array_data_cast()); + } + break; + case json_type_tag::object_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))object_data(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + case json_type_tag::object_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))string_data(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))array_data(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data_cast()->swap(*other.object_data_cast()); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + private: + + void Init_(const variant& val) + { + switch (val.type_id()) + { + case json_type_tag::null_t: + new(reinterpret_cast<void*>(&data_))null_data(); + break; + case json_type_tag::empty_object_t: + new(reinterpret_cast<void*>(&data_))empty_object_data(); + break; + case json_type_tag::bool_t: + new(reinterpret_cast<void*>(&data_))bool_data(*(val.bool_data_cast())); + break; + case json_type_tag::integer_t: + new(reinterpret_cast<void*>(&data_))integer_data(*(val.integer_data_cast())); + break; + case json_type_tag::uinteger_t: + new(reinterpret_cast<void*>(&data_))uinteger_data(*(val.uinteger_data_cast())); + break; + case json_type_tag::double_t: + new(reinterpret_cast<void*>(&data_))double_data(*(val.double_data_cast())); + break; + case json_type_tag::small_string_t: + new(reinterpret_cast<void*>(&data_))small_string_data(*(val.small_string_data_cast())); + break; + case json_type_tag::string_t: + new(reinterpret_cast<void*>(&data_))string_data(*(val.string_data_cast())); + break; + case json_type_tag::byte_string_t: + new(reinterpret_cast<void*>(&data_))byte_string_data(*(val.byte_string_data_cast())); + break; + case json_type_tag::object_t: + new(reinterpret_cast<void*>(&data_))object_data(*(val.object_data_cast())); + break; + case json_type_tag::array_t: + new(reinterpret_cast<void*>(&data_))array_data(*(val.array_data_cast())); + break; + default: + break; + } + } + + void Init_(const variant& val, const Allocator& a) + { + switch (val.type_id()) + { + case json_type_tag::null_t: + case json_type_tag::empty_object_t: + case json_type_tag::bool_t: + case json_type_tag::integer_t: + case json_type_tag::uinteger_t: + case json_type_tag::double_t: + case json_type_tag::small_string_t: + Init_(val); + break; + case json_type_tag::string_t: + new(reinterpret_cast<void*>(&data_))string_data(*(val.string_data_cast()),a); + break; + case json_type_tag::byte_string_t: + new(reinterpret_cast<void*>(&data_))byte_string_data(*(val.byte_string_data_cast()),a); + break; + case json_type_tag::array_t: + new(reinterpret_cast<void*>(&data_))array_data(*(val.array_data_cast()),a); + break; + case json_type_tag::object_t: + new(reinterpret_cast<void*>(&data_))object_data(*(val.object_data_cast()),a); + break; + default: + break; + } + } + + void Init_rv_(variant&& val) JSONCONS_NOEXCEPT + { + switch (val.type_id()) + { + case json_type_tag::null_t: + case json_type_tag::empty_object_t: + case json_type_tag::double_t: + case json_type_tag::integer_t: + case json_type_tag::uinteger_t: + case json_type_tag::bool_t: + case json_type_tag::small_string_t: + Init_(val); + break; + case json_type_tag::string_t: + { + new(reinterpret_cast<void*>(&data_))string_data(std::move(*val.string_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + case json_type_tag::byte_string_t: + { + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*val.byte_string_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + case json_type_tag::array_t: + { + new(reinterpret_cast<void*>(&data_))array_data(std::move(*val.array_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + case json_type_tag::object_t: + { + new(reinterpret_cast<void*>(&data_))object_data(std::move(*val.object_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + void Init_rv_(variant&& val, const Allocator& a, std::true_type) JSONCONS_NOEXCEPT + { + Init_rv_(std::forward<variant>(val)); + } + + void Init_rv_(variant&& val, const Allocator& a, std::false_type) JSONCONS_NOEXCEPT + { + switch (val.type_id()) + { + case json_type_tag::null_t: + case json_type_tag::empty_object_t: + case json_type_tag::double_t: + case json_type_tag::integer_t: + case json_type_tag::uinteger_t: + case json_type_tag::bool_t: + case json_type_tag::small_string_t: + Init_(std::forward<variant>(val)); + break; + case json_type_tag::string_t: + { + if (a == val.string_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case json_type_tag::byte_string_t: + { + if (a == val.byte_string_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case json_type_tag::object_t: + { + if (a == val.object_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case json_type_tag::array_t: + { + if (a == val.array_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + default: + break; + } + } + }; + + template <class ParentT> + class json_proxy + { + private: + typedef json_proxy<ParentT> proxy_type; + + ParentT& parent_; + key_storage_type key_; + + json_proxy() = delete; + json_proxy& operator = (const json_proxy& other) = delete; + + json_proxy(ParentT& parent, key_storage_type&& name) + : parent_(parent), key_(std::forward<key_storage_type>(name)) + { + } + + basic_json& evaluate() + { + return parent_.evaluate(string_view_type(key_.data(),key_.size())); + } + + const basic_json& evaluate() const + { + return parent_.evaluate(string_view_type(key_.data(),key_.size())); + } + + basic_json& evaluate_with_default() + { + basic_json& val = parent_.evaluate_with_default(); + auto it = val.find(string_view_type(key_.data(),key_.size())); + if (it == val.object_range().end()) + { + it = val.set_(val.object_range().begin(),std::move(key_),object(val.object_value().get_allocator())); + } + return it->value(); + } + + basic_json& evaluate(size_t index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(size_t index) const + { + return evaluate().at(index); + } + + basic_json& evaluate(const string_view_type& index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(const string_view_type& index) const + { + return evaluate().at(index); + } + public: + + friend class basic_json<CharT,ImplementationPolicy,Allocator>; + + range<object_iterator> object_range() + { + return evaluate().object_range(); + } + + range<const_object_iterator> object_range() const + { + return evaluate().object_range(); + } + + range<array_iterator> array_range() + { + return evaluate().array_range(); + } + + range<const_array_iterator> array_range() const + { + return evaluate().array_range(); + } + + size_t size() const JSONCONS_NOEXCEPT + { + return evaluate().size(); + } + + json_type_tag type_id() const + { + return evaluate().type_id(); + } + + size_t count(const string_view_type& name) const + { + return evaluate().count(name); + } + + bool has_key(const string_view_type& name) const + { + return evaluate().has_key(name); + } + + bool is_null() const JSONCONS_NOEXCEPT + { + return evaluate().is_null(); + } + + bool empty() const + { + return evaluate().empty(); + } + + size_t capacity() const + { + return evaluate().capacity(); + } + + void reserve(size_t n) + { + evaluate().reserve(n); + } + + void resize(size_t n) + { + evaluate().resize(n); + } + + template <class T> + void resize(size_t n, T val) + { + evaluate().resize(n,val); + } + + template<class T, class... Args> + bool is(Args&&... args) const + { + return evaluate().template is<T>(std::forward<Args>(args)...); + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return evaluate().is_string(); + } + + bool is_byte_string() const JSONCONS_NOEXCEPT + { + return evaluate().is_byte_string(); + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return evaluate().is_number(); + } + bool is_bool() const JSONCONS_NOEXCEPT + { + return evaluate().is_bool(); + } + + bool is_object() const JSONCONS_NOEXCEPT + { + return evaluate().is_object(); + } + + bool is_array() const JSONCONS_NOEXCEPT + { + return evaluate().is_array(); + } + bool is_integer() const JSONCONS_NOEXCEPT + { + return evaluate().is_integer(); + } + + bool is_uinteger() const JSONCONS_NOEXCEPT + { + return evaluate().is_uinteger(); + } + + bool is_double() const JSONCONS_NOEXCEPT + { + return evaluate().is_double(); + } + + string_view_type as_string_view() const + { + return evaluate().as_string_view(); + } + + byte_string_view as_byte_string_view() const + { + return evaluate().as_byte_string_view(); + } + + string_type as_string() const + { + return evaluate().as_string(); + } + + template <class SAllocator> + string_type as_string(const SAllocator& allocator) const + { + return evaluate().as_string(allocator); + } + + string_type as_string(const basic_serialization_options<char_type>& options) const + { + return evaluate().as_string(options); + } + + template <class SAllocator> + string_type as_string(const basic_serialization_options<char_type>& options, + const SAllocator& allocator) const + { + return evaluate().as_string(options,allocator); + } + + template<class T, class... Args> + T as(Args&&... args) const + { + return evaluate().template as<T>(std::forward<Args>(args)...); + } + + template<class T> + typename std::enable_if<std::is_same<string_type,T>::value,T>::type + as(const char_allocator_type& allocator) const + { + return evaluate().template as<T>(allocator); + } + bool as_bool() const + { + return evaluate().as_bool(); + } + + double as_double() const + { + return evaluate().as_double(); + } + + int64_t as_integer() const + { + return evaluate().as_integer(); + } + + unsigned long long as_ulonglong() const + { + return evaluate().as_ulonglong(); + } + + uint64_t as_uinteger() const + { + return evaluate().as_uinteger(); + } + + template <class T> + json_proxy& operator=(T&& val) + { + parent_.evaluate_with_default().set_(std::move(key_), std::forward<T>(val)); + return *this; + } + + bool operator==(const basic_json& val) const + { + return evaluate() == val; + } + + bool operator!=(const basic_json& val) const + { + return evaluate() != val; + } + + basic_json& operator[](size_t i) + { + return evaluate_with_default().at(i); + } + + const basic_json& operator[](size_t i) const + { + return evaluate().at(i); + } + + json_proxy<proxy_type> operator[](const string_view_type& name) + { + return json_proxy<proxy_type>(*this,key_storage_type(name.begin(),name.end(),key_.get_allocator())); + } + + const basic_json& operator[](const string_view_type& name) const + { + return at(name); + } + + basic_json& at(const string_view_type& name) + { + return evaluate().at(name); + } + + const basic_json& at(const string_view_type& name) const + { + return evaluate().at(name); + } + + const basic_json& at(size_t index) + { + return evaluate().at(index); + } + + const basic_json& at(size_t index) const + { + return evaluate().at(index); + } + + object_iterator find(const string_view_type& name) + { + return evaluate().find(name); + } + + const_object_iterator find(const string_view_type& name) const + { + return evaluate().find(name); + } + + template <class T> + basic_json get(const string_view_type& name, T&& default_val) const + { + return evaluate().get(name,std::forward<T>(default_val)); + } + + template <class T> + T get_with_default(const string_view_type& name, const T& default_val) const + { + return evaluate().get_with_default(name,default_val); + } + + const CharT* get_with_default(const string_view_type& name, const CharT* default_val) const + { + return evaluate().get_with_default(name,default_val); + } + + void shrink_to_fit() + { + evaluate_with_default().shrink_to_fit(); + } + + void clear() + { + evaluate().clear(); + } + // Remove all elements from an array or object + + void erase(const_object_iterator pos) + { + evaluate().erase(pos); + } + // Remove a range of elements from an object + + void erase(const_object_iterator first, const_object_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an object + + void erase(const string_view_type& name) + { + evaluate().erase(name); + } + + void erase(const_array_iterator pos) + { + evaluate().erase(pos); + } + // Removes the element at pos + + void erase(const_array_iterator first, const_array_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an array + + // merge + + void merge(const basic_json& source) + { + return evaluate().merge(source); + } + + void merge(basic_json&& source) + { + return evaluate().merge(std::forward<basic_json>(source)); + } + + void merge(object_iterator hint, const basic_json& source) + { + return evaluate().merge(hint, source); + } + + void merge(object_iterator hint, basic_json&& source) + { + return evaluate().merge(hint, std::forward<basic_json>(source)); + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + return evaluate().merge_or_update(source); + } + + void merge_or_update(basic_json&& source) + { + return evaluate().merge_or_update(std::forward<basic_json>(source)); + } + + void merge_or_update(object_iterator hint, const basic_json& source) + { + return evaluate().merge_or_update(hint, source); + } + + void merge_or_update(object_iterator hint, basic_json&& source) + { + return evaluate().merge_or_update(hint, std::forward<basic_json>(source)); + } + + // set + + template <class T> + std::pair<object_iterator,bool> set(const string_view_type& name, T&& val) + { + return evaluate().set(name,std::forward<T>(val)); + } + + template <class T> + std::pair<object_iterator,bool> insert_or_assign(const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(name,std::forward<T>(val)); + } + + template <class T> + void set_(key_storage_type&& name, T&& val) + { + evaluate().set_(std::forward<key_storage_type>(name),std::forward<T>(val)); + } + + // emplace + + template <class ... Args> + std::pair<object_iterator,bool> try_emplace(const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(name,std::forward<Args>(args)...); + } + + template <class T> + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().set(hint, name, std::forward<T>(val)); + } + + template <class T> + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(hint, name, std::forward<T>(val)); + } + + template <class ... Args> + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(hint, name, std::forward<Args>(args)...); + } + + template <class T> + object_iterator set_(object_iterator hint, key_storage_type&& name, T&& val) + { + return evaluate().set_(hint, std::forward<key_storage_type>(name), std::forward<T>(val)); + } + + template <class... Args> + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + evaluate_with_default().emplace(pos, std::forward<Args>(args)...); + } + + template <class... Args> + basic_json& emplace_back(Args&&... args) + { + return evaluate_with_default().emplace_back(std::forward<Args>(args)...); + } + + template <class T> + void add(T&& val) + { + evaluate_with_default().add(std::forward<T>(val)); + } + + template <class T> + void push_back(T&& val) + { + evaluate_with_default().push_back(std::forward<T>(val)); + } + + template <class T> + array_iterator add(const_array_iterator pos, T&& val) + { + return evaluate_with_default().add(pos, std::forward<T>(val)); + } + + template <class T> + array_iterator insert(const_array_iterator pos, T&& val) + { + return evaluate_with_default().insert(pos, std::forward<T>(val)); + } + + template <class InputIt> + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + return evaluate_with_default().insert(pos, first, last); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s) const + { + evaluate().dump(s); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s, + const basic_serialization_options<char_type>& options) const + { + evaluate().dump(s,options); + } + void dump(basic_json_output_handler<char_type>& handler) const + { + evaluate().dump(handler); + } + + void dump(std::basic_ostream<char_type>& os) const + { + evaluate().dump(os); + } + + void dump(std::basic_ostream<char_type>& os, bool pprint) const + { + evaluate().dump(os, pprint); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + evaluate().dump(os,options); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + evaluate().dump(os,options,pprint); + } +#if !defined(JSONCONS_NO_DEPRECATED) + + string_type to_string(const char_allocator_type& allocator = char_allocator_type()) const JSONCONS_NOEXCEPT + { + return evaluate().to_string(allocator); + } + void write(basic_json_output_handler<char_type>& handler) const + { + evaluate().write(handler); + } + + void write(std::basic_ostream<char_type>& os) const + { + evaluate().write(os); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + evaluate().write(os,options); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + evaluate().write(os,options,pprint); + } + + string_type to_string(const basic_serialization_options<char_type>& options, char_allocator_type& allocator = char_allocator_type()) const + { + return evaluate().to_string(options,allocator); + } + + range<object_iterator> members() + { + return evaluate().members(); + } + + range<const_object_iterator> members() const + { + return evaluate().members(); + } + + range<array_iterator> elements() + { + return evaluate().elements(); + } + + range<const_array_iterator> elements() const + { + return evaluate().elements(); + } + void to_stream(basic_json_output_handler<char_type>& handler) const + { + evaluate().to_stream(handler); + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + evaluate().to_stream(os); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + evaluate().to_stream(os,options); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + evaluate().to_stream(os,options,pprint); + } +#endif + void swap(basic_json& val) + { + evaluate_with_default().swap(val); + } + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_proxy& o) + { + o.dump(os); + return os; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void resize_array(size_t n) + { + evaluate().resize_array(n); + } + + template <class T> + void resize_array(size_t n, T val) + { + evaluate().resize_array(n,val); + } + + object_iterator begin_members() + { + return evaluate().begin_members(); + } + + const_object_iterator begin_members() const + { + return evaluate().begin_members(); + } + + object_iterator end_members() + { + return evaluate().end_members(); + } + + const_object_iterator end_members() const + { + return evaluate().end_members(); + } + + array_iterator begin_elements() + { + return evaluate().begin_elements(); + } + + const_array_iterator begin_elements() const + { + return evaluate().begin_elements(); + } + + array_iterator end_elements() + { + return evaluate().end_elements(); + } + + const_array_iterator end_elements() const + { + return evaluate().end_elements(); + } + + const basic_json& get(const string_view_type& name) const + { + return evaluate().get(name); + } + + bool is_ulonglong() const JSONCONS_NOEXCEPT + { + return evaluate().is_ulonglong(); + } + + bool is_longlong() const JSONCONS_NOEXCEPT + { + return evaluate().is_longlong(); + } + + int as_int() const + { + return evaluate().as_int(); + } + + unsigned int as_uint() const + { + return evaluate().as_uint(); + } + + long as_long() const + { + return evaluate().as_long(); + } + + unsigned long as_ulong() const + { + return evaluate().as_ulong(); + } + + long long as_longlong() const + { + return evaluate().as_longlong(); + } + + void add(size_t index, const basic_json& value) + { + evaluate_with_default().add(index, value); + } + + void add(size_t index, basic_json&& value) + { + evaluate_with_default().add(index, std::forward<basic_json>(value)); + } + + bool has_member(const key_storage_type& name) const + { + return evaluate().has_member(name); + } + + // Remove a range of elements from an array + void remove_range(size_t from_index, size_t to_index) + { + evaluate().remove_range(from_index, to_index); + } + // Remove a range of elements from an array + void remove(const string_view_type& name) + { + evaluate().remove(name); + } + void remove_member(const string_view_type& name) + { + evaluate().remove(name); + } + bool is_empty() const JSONCONS_NOEXCEPT + { + return empty(); + } + bool is_numeric() const JSONCONS_NOEXCEPT + { + return is_number(); + } +#endif + }; + + static basic_json parse(std::basic_istream<char_type>& is); + static basic_json parse(std::basic_istream<char_type>& is, parse_error_handler& err_handler); + + static basic_json parse(const string_view_type& s) + { + parse_error_handler_type err_handler; + return parse(s,err_handler); + } + + static basic_json parse(const char_type* s, size_t length) + { + parse_error_handler_type err_handler; + return parse(s,length,err_handler); + } + + static basic_json parse(const char_type* s, size_t length, parse_error_handler& err_handler) + { + return parse(string_view_type(s,length),err_handler); + } + + static basic_json parse(const string_view_type& s, parse_error_handler& err_handler) + { + json_decoder<basic_json> decoder; + basic_json_parser<char_type> parser(decoder,err_handler); + + auto result = unicons::skip_bom(s.begin(), s.end()); + if (result.ec != unicons::encoding_errc()) + { + throw parse_error(result.ec,1,1); + } + size_t offset = result.it - s.begin(); + parser.set_source(s.data()+offset,s.size()-offset); + parser.parse_some(); + parser.end_parse(); + parser.check_done(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json string")); + } + return decoder.get_result(); + } + + static basic_json make_array() + { + return basic_json(variant(array())); + } + + static basic_json make_array(const array& a) + { + return basic_json(variant(a)); + } + + static basic_json make_array(const array& a, allocator_type allocator) + { + return basic_json(variant(a,allocator)); + } + + static basic_json make_array(std::initializer_list<basic_json> init, const Allocator& allocator = Allocator()) + { + return array(std::move(init),allocator); + } + + static basic_json make_array(size_t n, const Allocator& allocator = Allocator()) + { + return array(n,allocator); + } + + template <class T> + static basic_json make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) + { + return basic_json::array(n, val,allocator); + } + + template <size_t dim> + static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n) + { + return array(n); + } + + template <size_t dim, class T> + static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) + { + return array(n,val,allocator); + } + + template <size_t dim, typename... Args> + static typename std::enable_if<(dim>1),basic_json>::type make_array(size_t n, Args... args) + { + const size_t dim1 = dim - 1; + + basic_json val = make_array<dim1>(args...); + val.resize(n); + for (size_t i = 0; i < n; ++i) + { + val[i] = make_array<dim1>(args...); + } + return val; + } + + static const basic_json& null() + { + static basic_json a_null = basic_json(variant(null_type())); + return a_null; + } + + variant var_; + + basic_json() + : var_() + { + } + + explicit basic_json(const Allocator& allocator) + : var_(allocator) + { + } + + basic_json(const basic_json& val) + : var_(val.var_) + { + } + + basic_json(const basic_json& val, const Allocator& allocator) + : var_(val.var_,allocator) + { + } + + basic_json(basic_json&& other) JSONCONS_NOEXCEPT + : var_(std::move(other.var_)) + { + } + + basic_json(basic_json&& other, const Allocator& allocator) JSONCONS_NOEXCEPT + : var_(std::move(other.var_) /*,allocator*/ ) + { + } + + basic_json(const variant& val) + : var_(val) + { + } + + basic_json(variant&& other) + : var_(std::forward<variant>(other)) + { + } + + basic_json(const array& val) + : var_(val) + { + } + + basic_json(array&& other) + : var_(std::forward<array>(other)) + { + } + + basic_json(const object& other) + : var_(other) + { + } + + basic_json(object&& other) + : var_(std::forward<object>(other)) + { + } + + template <class ParentT> + basic_json(const json_proxy<ParentT>& proxy) + : var_(proxy.evaluate().var_) + { + } + + template <class ParentT> + basic_json(const json_proxy<ParentT>& proxy, const Allocator& allocator) + : var_(proxy.evaluate().var_,allocator) + { + } + + template <class T> + basic_json(const T& val) + : var_(json_type_traits<basic_json,T>::to_json(val).var_) + { + } + + template <class T> + basic_json(const T& val, const Allocator& allocator) + : var_(json_type_traits<basic_json,T>::to_json(val,allocator).var_) + { + } + + basic_json(const char_type* s) + : var_(s) + { + } + + basic_json(const char_type* s, const Allocator& allocator) + : var_(s,allocator) + { + } + + basic_json(double val, uint8_t precision) + : var_(val, number_format(precision, 0)) + { + } + + basic_json(double val, const number_format& fmt) + : var_(val, fmt) + { + } + + basic_json(const char_type *s, size_t length) + : var_(s, length) + { + } + + basic_json(const char_type *s, size_t length, const Allocator& allocator) + : var_(s, length, allocator) + { + } + + basic_json(const uint8_t* s, size_t length) + : var_(s, length) + { + } + + explicit basic_json(const byte_string_view& s) + : var_(s.data(), s.length()) + { + } + + basic_json(const uint8_t* s, size_t length, const Allocator& allocator) + : var_(s, length, allocator) + { + } +#if !defined(JSONCONS_NO_DEPRECATED) + template<class InputIterator> + basic_json(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) + : var_(first,last,allocator) + { + } +#endif + + ~basic_json() + { + } + + basic_json& operator=(const basic_json& rhs) + { + if (this != &rhs) + { + var_ = rhs.var_; + } + return *this; + } + + basic_json& operator=(basic_json&& rhs) JSONCONS_NOEXCEPT + { + if (this !=&rhs) + { + var_ = std::move(rhs.var_); + } + return *this; + } + + template <class T> + basic_json& operator=(const T& val) + { + var_ = json_type_traits<basic_json,T>::to_json(val).var_; + return *this; + } + + basic_json& operator=(const char_type* s) + { + var_ = variant(s); + return *this; + } + + bool operator!=(const basic_json& rhs) const + { + return !(*this == rhs); + } + + bool operator==(const basic_json& rhs) const + { + return var_ == rhs.var_; + } + + size_t size() const JSONCONS_NOEXCEPT + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return 0; + case json_type_tag::object_t: + return object_value().size(); + case json_type_tag::array_t: + return array_value().size(); + default: + return 0; + } + } + + basic_json& operator[](size_t i) + { + return at(i); + } + + const basic_json& operator[](size_t i) const + { + return at(i); + } + + json_proxy<basic_json> operator[](const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return json_proxy<basic_json>(*this, key_storage_type(name.begin(),name.end(),char_allocator_type(object_value().get_allocator()))); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + const basic_json& operator[](const string_view_type& name) const + { + return at(name); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s) const + { + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s); + dump(serializer); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s, + const basic_serialization_options<char_type>& options) const + { + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s, options); + dump(serializer); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + void dump_body(basic_json_output_handler<char_type>& handler) const + { + dump_fragment(handler); + } +#endif + void dump_fragment(basic_json_output_handler<char_type>& handler) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + handler.string_value(as_string_view()); + break; + case json_type_tag::byte_string_t: + handler.byte_string_value(var_.byte_string_data_cast()->data(), var_.byte_string_data_cast()->length()); + break; + case json_type_tag::double_t: + handler.double_value(var_.double_data_cast()->value(), number_format(var_.double_data_cast()->precision(), var_.double_data_cast()->decimal_places())); + break; + case json_type_tag::integer_t: + handler.integer_value(var_.integer_data_cast()->value()); + break; + case json_type_tag::uinteger_t: + handler.uinteger_value(var_.uinteger_data_cast()->value()); + break; + case json_type_tag::bool_t: + handler.bool_value(var_.bool_data_cast()->value()); + break; + case json_type_tag::null_t: + handler.null_value(); + break; + case json_type_tag::empty_object_t: + handler.begin_object(0); + handler.end_object(); + break; + case json_type_tag::object_t: + { + handler.begin_object(size()); + const object& o = object_value(); + for (const_object_iterator it = o.begin(); it != o.end(); ++it) + { + handler.name(string_view_type((it->key()).data(),it->key().length())); + it->value().dump_fragment(handler); + } + handler.end_object(); + } + break; + case json_type_tag::array_t: + { + handler.begin_array(size()); + const array& o = array_value(); + for (const_array_iterator it = o.begin(); it != o.end(); ++it) + { + it->dump_fragment(handler); + } + handler.end_array(); + } + break; + default: + break; + } + } + void dump(basic_json_output_handler<char_type>& handler) const + { + handler.begin_json(); + dump_fragment(handler); + handler.end_json(); + } + + void dump(std::basic_ostream<char_type>& os) const + { + basic_json_serializer<char_type> serializer(os); + dump(serializer); + } + + void dump(std::basic_ostream<char_type>& os, bool pprint) const + { + basic_json_serializer<char_type> serializer(os, pprint); + dump(serializer); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + basic_json_serializer<char_type> serializer(os, options); + dump(serializer); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + basic_json_serializer<char_type> serializer(os, options, pprint); + dump(serializer); + } + + string_type to_string(const char_allocator_type& allocator=char_allocator_type()) const JSONCONS_NOEXCEPT + { + string_type s(allocator); + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s); + dump_fragment(serializer); + return s; + } + + string_type to_string(const basic_serialization_options<char_type>& options, + const char_allocator_type& allocator=char_allocator_type()) const + { + string_type s(allocator); + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s,options); + dump_fragment(serializer); + return s; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void write_body(basic_json_output_handler<char_type>& handler) const + { + dump(handler); + } + void write(basic_json_output_handler<char_type>& handler) const + { + dump(handler); + } + + void write(std::basic_ostream<char_type>& os) const + { + dump(os); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + dump(os,options); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + dump(os,options,pprint); + } + + void to_stream(basic_json_output_handler<char_type>& handler) const + { + handler.begin_json(); + dump_fragment(handler); + handler.end_json(); + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + basic_json_serializer<char_type> serializer(os); + to_stream(serializer); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + basic_json_serializer<char_type> serializer(os, options); + to_stream(serializer); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + basic_json_serializer<char_type> serializer(os, options, pprint); + to_stream(serializer); + } +#endif + bool is_null() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::null_t; + } + + bool has_key(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end(); + } + break; + default: + return false; + } + } + + size_t count(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::object_t: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + return 0; + } + size_t count = 0; + while (it != object_range().end()&& it->key() == name) + { + ++count; + ++it; + } + return count; + } + break; + default: + return 0; + } + } + + template<class T, class... Args> + bool is(Args&&... args) const + { + return json_type_traits<basic_json,T>::is(*this,std::forward<Args>(args)...); + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return (var_.type_id() == json_type_tag::string_t) || (var_.type_id() == json_type_tag::small_string_t); + } + + bool is_byte_string() const JSONCONS_NOEXCEPT + { + return (var_.type_id() == json_type_tag::byte_string_t); + } + + bool is_bool() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::bool_t; + } + + bool is_object() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::object_t || var_.type_id() == json_type_tag::empty_object_t; + } + + bool is_array() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::array_t; + } + + bool is_integer() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::integer_t || (var_.type_id() == json_type_tag::uinteger_t&& (as_uinteger() <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))); + } + + bool is_uinteger() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::uinteger_t || (var_.type_id() == json_type_tag::integer_t&& as_integer() >= 0); + } + + bool is_double() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::double_t; + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::integer_t || var_.type_id() == json_type_tag::uinteger_t || var_.type_id() == json_type_tag::double_t; + } + + bool empty() const JSONCONS_NOEXCEPT + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + return var_.small_string_data_cast()->length() == 0; + case json_type_tag::string_t: + return var_.string_data_cast()->length() == 0; + case json_type_tag::array_t: + return array_value().size() == 0; + case json_type_tag::empty_object_t: + return true; + case json_type_tag::object_t: + return object_value().size() == 0; + default: + return false; + } + } + + size_t capacity() const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().capacity(); + case json_type_tag::object_t: + return object_value().capacity(); + default: + return 0; + } + } + + template<class U=Allocator> + typename std::enable_if<is_stateless<U>::value,void>::type + create_object_implicitly() + { + var_ = variant(Allocator()); + } + + template<class U=Allocator> + typename std::enable_if<!is_stateless<U>::value,void>::type + create_object_implicitly() const + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Cannot create object implicitly - allocator is not default constructible.")); + } + + void reserve(size_t n) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().reserve(n); + break; + case json_type_tag::empty_object_t: + { + create_object_implicitly(); + object_value().reserve(n); + } + break; + case json_type_tag::object_t: + { + object_value().reserve(n); + } + break; + default: + break; + } + } + + void resize(size_t n) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().resize(n); + break; + default: + break; + } + } + + template <class T> + void resize(size_t n, T val) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().resize(n, val); + break; + default: + break; + } + } + + template<class T, class... Args> + T as(Args&&... args) const + { + return json_type_traits<basic_json,T>::as(*this,std::forward<Args>(args)...); + } + + template<class T> + typename std::enable_if<std::is_same<string_type,T>::value,T>::type + as(const char_allocator_type& allocator) const + { + return json_type_traits<basic_json,T>::as(*this,allocator); + } + + bool as_bool() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as_bool(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a bool")); + } + break; + case json_type_tag::bool_t: + return var_.bool_data_cast()->value(); + case json_type_tag::double_t: + return var_.double_data_cast()->value() != 0.0; + case json_type_tag::integer_t: + return var_.integer_data_cast()->value() != 0; + case json_type_tag::uinteger_t: + return var_.uinteger_data_cast()->value() != 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a bool")); + } + } + + int64_t as_integer() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as<int64_t>(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an integer")); + } + break; + case json_type_tag::double_t: + return static_cast<int64_t>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<int64_t>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<int64_t>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an integer")); + } + } + + uint64_t as_uinteger() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as<uint64_t>(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned integer")); + } + break; + case json_type_tag::double_t: + return static_cast<uint64_t>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<uint64_t>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<uint64_t>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned integer")); + } + } + + size_t precision() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return var_.double_data_cast()->precision(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } + + size_t decimal_places() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return var_.double_data_cast()->decimal_places(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } + + double as_double() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as<double>(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + break; + case json_type_tag::double_t: + return var_.double_data_cast()->value(); + case json_type_tag::integer_t: + return static_cast<double>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<double>(var_.uinteger_data_cast()->value()); + //case json_type_tag::null_t: + // return std::numeric_limits<double>::quiet_NaN(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } + + string_view_type as_string_view() const + { + return var_.as_string_view(); + } + + byte_string_view as_byte_string_view() const + { + return var_.as_byte_string_view(); + } + + string_type as_string() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length()); + default: + return to_string(); + } + } + + template <class SAllocator> + string_type as_string(const SAllocator& allocator) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length(),allocator); + default: + return to_string(allocator); + } + } + + string_type as_string(const basic_serialization_options<char_type>& options) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length()); + default: + return to_string(options); + } + } + + template <class SAllocator> + string_type as_string(const basic_serialization_options<char_type>& options, + const SAllocator& allocator) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length(),allocator); + default: + return to_string(options,allocator); + } + } + + const char_type* as_cstring() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + return var_.small_string_data_cast()->c_str(); + case json_type_tag::string_t: + return var_.string_data_cast()->c_str(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a cstring")); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t double_precision() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return var_.double_data_cast()->precision(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } +#endif + + basic_json& at(const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case json_type_tag::object_t: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + basic_json& evaluate() + { + return *this; + } + + basic_json& evaluate_with_default() + { + return *this; + } + + const basic_json& evaluate() const + { + return *this; + } + basic_json& evaluate(const string_view_type& name) + { + return at(name); + } + + const basic_json& evaluate(const string_view_type& name) const + { + return at(name); + } + + const basic_json& at(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case json_type_tag::object_t: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + basic_json& at(size_t i) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return array_value().operator[](i); + case json_type_tag::object_t: + return object_value().at(i); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Index on non-array value not supported")); + } + } + + const basic_json& at(size_t i) const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return array_value().operator[](i); + case json_type_tag::object_t: + return object_value().at(i); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Index on non-array value not supported")); + } + } + + object_iterator find(const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return object_range().end(); + case json_type_tag::object_t: + return object_value().find(name); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const_object_iterator find(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return object_range().end(); + case json_type_tag::object_t: + return object_value().find(name); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template<class T> + basic_json get(const string_view_type& name, T&& default_val) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + { + return basic_json(std::forward<T>(default_val)); + } + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value(); + } + else + { + return basic_json(std::forward<T>(default_val)); + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template<class T> + T get_with_default(const string_view_type& name, const T& default_val) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + { + return default_val; + } + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value().template as<T>(); + } + else + { + return default_val; + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const CharT* get_with_default(const string_view_type& name, const CharT* default_val) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + { + return default_val; + } + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value().as_cstring(); + } + else + { + return default_val; + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // Modifiers + + void shrink_to_fit() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().shrink_to_fit(); + break; + case json_type_tag::object_t: + object_value().shrink_to_fit(); + break; + default: + break; + } + } + + void clear() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().clear(); + break; + case json_type_tag::object_t: + object_value().clear(); + break; + default: + break; + } + } + + void erase(const_object_iterator pos) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + break; + case json_type_tag::object_t: + object_value().erase(pos); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + break; + } + } + + void erase(const_object_iterator first, const_object_iterator last) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + break; + case json_type_tag::object_t: + object_value().erase(first, last); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + break; + } + } + + void erase(const_array_iterator pos) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().erase(pos); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + break; + } + } + + void erase(const_array_iterator first, const_array_iterator last) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().erase(first, last); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + break; + } + } + + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void erase(const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + break; + case json_type_tag::object_t: + object_value().erase(name); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + template <class T> + std::pair<object_iterator,bool> set(const string_view_type& name, T&& val) + { + return insert_or_assign(name, std::forward<T>(val)); + } + + template <class T> + std::pair<object_iterator,bool> insert_or_assign(const string_view_type& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().insert_or_assign(name, std::forward<T>(val)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class ... Args> + std::pair<object_iterator,bool> try_emplace(const string_view_type& name, Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().try_emplace(name, std::forward<Args>(args)...); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class T> + void set_(key_storage_type&& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + object_value().set_(std::forward<key_storage_type>(name), std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // merge + + void merge(const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + void merge(basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(hint, source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(hint, std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(object_iterator hint, const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(hint, source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(object_iterator hint, basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(hint, std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + // set + + template <class T> + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return insert_or_assign(hint, name, std::forward<T>(val)); + } + + template <class T> + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().insert_or_assign(hint, name, std::forward<T>(val)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class ... Args> + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().try_emplace(hint, name, std::forward<Args>(args)...); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class T> + object_iterator set_(object_iterator hint, key_storage_type&& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().set_(hint, std::forward<key_storage_type>(name), std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class T> + void add(T&& val) + { + push_back(std::forward<T>(val)); + } + + template <class T> + void push_back(T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().push_back(std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class T> + array_iterator add(const_array_iterator pos, T&& val) + { + return insert(pos, std::forward<T>(val)); + } + + template <class T> + array_iterator insert(const_array_iterator pos, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().insert(pos, std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class InputIt> + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().insert(pos, first, last); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class... Args> + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().emplace(pos, std::forward<Args>(args)...); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class... Args> + basic_json& emplace_back(Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().emplace_back(std::forward<Args>(args)...); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + json_type_tag type_id() const + { + return var_.type_id(); + } + + void swap(basic_json& b) + { + var_.swap(b.var_); + } + + friend void swap(basic_json& a, basic_json& b) + { + a.swap(b); + } + + static basic_json make_string(const string_view_type& s) + { + return basic_json(variant(s.data(),s.length())); + } + + static basic_json make_string(const char_type* rhs, size_t length) + { + return basic_json(variant(rhs,length)); + } + + static basic_json make_string(const string_view_type& s, allocator_type allocator) + { + return basic_json(variant(s.data(),s.length(),allocator)); + } + + static basic_json from_integer(int64_t val) + { + return basic_json(variant(val)); + } + + static basic_json from_integer(int64_t val, allocator_type) + { + return basic_json(variant(val)); + } + + static basic_json from_uinteger(uint64_t val) + { + return basic_json(variant(val)); + } + + static basic_json from_uinteger(uint64_t val, allocator_type) + { + return basic_json(variant(val)); + } + + static basic_json from_floating_point(double val) + { + return basic_json(variant(val)); + } + + static basic_json from_floating_point(double val, allocator_type) + { + return basic_json(variant(val)); + } + + static basic_json from_bool(bool val) + { + return basic_json(variant(val)); + } + + static basic_json make_object(const object& o) + { + return basic_json(variant(o)); + } + + static basic_json make_object(const object& o, allocator_type allocator) + { + return basic_json(variant(o,allocator)); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + static basic_json parse_file(const std::basic_string<char_type,char_traits_type>& filename) + { + parse_error_handler_type err_handler; + return parse_file(filename,err_handler); + } + + static basic_json parse_file(const std::basic_string<char_type,char_traits_type>& filename, + parse_error_handler& err_handler) + { + std::basic_ifstream<CharT> is(filename); + return parse(is,err_handler); + } + + static basic_json parse_stream(std::basic_istream<char_type>& is) + { + return parse(is); + } + static basic_json parse_stream(std::basic_istream<char_type>& is, parse_error_handler& err_handler) + { + return parse(is,err_handler); + } + + static basic_json parse_string(const string_type& s) + { + return parse(s); + } + + static basic_json parse_string(const string_type& s, parse_error_handler& err_handler) + { + return parse(s,err_handler); + } + + void resize_array(size_t n) + { + resize(n); + } + + template <class T> + void resize_array(size_t n, T val) + { + resize(n,val); + } + + object_iterator begin_members() + { + return object_range().begin(); + } + + const_object_iterator begin_members() const + { + return object_range().begin(); + } + + object_iterator end_members() + { + return object_range().end(); + } + + const_object_iterator end_members() const + { + return object_range().end(); + } + + array_iterator begin_elements() + { + return array_range().begin(); + } + + const_array_iterator begin_elements() const + { + return array_range().begin(); + } + + array_iterator end_elements() + { + return array_range().end(); + } + + const_array_iterator end_elements() const + { + return array_range().end(); + } + + const basic_json& get(const string_view_type& name) const + { + static const basic_json a_null = null_type(); + + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return a_null; + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end() ? it->value() : a_null; + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + bool is_longlong() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::integer_t; + } + + bool is_ulonglong() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::uinteger_t; + } + + long long as_longlong() const + { + return as_integer(); + } + + unsigned long long as_ulonglong() const + { + return as_uinteger(); + } + + int as_int() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<int>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<int>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<int>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an int")); + } + } + + unsigned int as_uint() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<unsigned int>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<unsigned int>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<unsigned int>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned int")); + } + } + + long as_long() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<long>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<long>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<long>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a long")); + } + } + + unsigned long as_ulong() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<unsigned long>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<unsigned long>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<unsigned long>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned long")); + } + } + + bool has_member(const key_storage_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end(); + } + break; + default: + return false; + } + } + + void remove_range(size_t from_index, size_t to_index) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().remove_range(from_index, to_index); + break; + default: + break; + } + } + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void remove(const string_view_type& name) + { + erase(name); + } + void remove_member(const string_view_type& name) + { + erase(name); + } + // Removes a member from an object value + + bool is_empty() const JSONCONS_NOEXCEPT + { + return empty(); + } + bool is_numeric() const JSONCONS_NOEXCEPT + { + return is_number(); + } + + template<int size> + static typename std::enable_if<size==1,basic_json>::type make_multi_array() + { + return make_array(); + } + template<size_t size> + static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n) + { + return make_array(n); + } + template<size_t size,typename T> + static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n, T val) + { + return make_array(n,val); + } + template<size_t size> + static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n) + { + return make_array<2>(m, n); + } + template<size_t size,typename T> + static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n, T val) + { + return make_array<2>(m, n, val); + } + template<size_t size> + static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k) + { + return make_array<3>(m, n, k); + } + template<size_t size,typename T> + static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k, T val) + { + return make_array<3>(m, n, k, val); + } + range<object_iterator> members() + { + return object_range(); + } + + range<const_object_iterator> members() const + { + return object_range(); + } + + range<array_iterator> elements() + { + return array_range(); + } + + range<const_array_iterator> elements() const + { + return array_range(); + } +#endif + + range<object_iterator> object_range() + { + static basic_json empty_object = object(); + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return range<object_iterator>(empty_object.object_range().begin(), empty_object.object_range().end()); + case json_type_tag::object_t: + return range<object_iterator>(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + } + } + + range<const_object_iterator> object_range() const + { + static const basic_json empty_object = object(); + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return range<const_object_iterator>(empty_object.object_range().begin(), empty_object.object_range().end()); + case json_type_tag::object_t: + return range<const_object_iterator>(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + } + } + + range<array_iterator> array_range() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return range<array_iterator>(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + } + } + + range<const_array_iterator> array_range() const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return range<const_array_iterator>(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + } + } + + array& array_value() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return var_.array_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad array cast")); + break; + } + } + + const array& array_value() const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return var_.array_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad array cast")); + break; + } + } + + object& object_value() + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return var_.object_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad object cast")); + break; + } + } + + const object& object_value() const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + const_cast<basic_json*>(this)->create_object_implicitly(); // HERE + // FALLTHRU + case json_type_tag::object_t: + return var_.object_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad object cast")); + break; + } + } + +private: + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const basic_json& o) + { + o.dump(os); + return os; + } + + friend std::basic_istream<char_type>& operator<<(std::basic_istream<char_type>& is, basic_json& o) + { + json_decoder<basic_json> handler; + basic_json_reader<char_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json stream")); + } + o = handler.get_result(); + return is; + } +}; + +template <class Json> +void swap(typename Json::key_value_pair_type& a, typename Json::key_value_pair_type& b) +{ + a.swap(b); +} + +template<class CharT,class ImplementationPolicy,class Allocator> +basic_json<CharT,ImplementationPolicy,Allocator> basic_json<CharT,ImplementationPolicy,Allocator>::parse(std::basic_istream<char_type>& is) +{ + parse_error_handler_type err_handler; + return parse(is,err_handler); +} + +template<class CharT,class ImplementationPolicy,class Allocator> +basic_json<CharT,ImplementationPolicy,Allocator> basic_json<CharT,ImplementationPolicy,Allocator>::parse(std::basic_istream<char_type>& is, + parse_error_handler& err_handler) +{ + json_decoder<basic_json<CharT,ImplementationPolicy,Allocator>> handler; + basic_json_reader<char_type> reader(is, handler, err_handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json stream")); + } + return handler.get_result(); +} + +template <class Json> +std::basic_istream<typename Json::char_type>& operator>>(std::basic_istream<typename Json::char_type>& is, Json& o) +{ + json_decoder<Json> handler; + basic_json_reader<typename Json::char_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json stream")); + } + o = handler.get_result(); + return is; +} + +template<class Json> +class json_printable +{ +public: + typedef typename Json::char_type char_type; + + json_printable(const Json& o, + bool is_pretty_print) + : o_(&o), is_pretty_print_(is_pretty_print) + { + } + + json_printable(const Json& o, + bool is_pretty_print, + const basic_serialization_options<char_type>& options) + : o_(&o), is_pretty_print_(is_pretty_print), options_(options) + { + ; + } + + void dump(std::basic_ostream<char_type>& os) const + { + o_->dump(os, options_, is_pretty_print_); + } + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_printable<Json>& o) + { + o.dump(os); + return os; + } + + const Json *o_; + bool is_pretty_print_; + basic_serialization_options<char_type> options_; +private: + json_printable(); +}; + +template<class Json> +json_printable<Json> print(const Json& val) +{ + return json_printable<Json>(val,false); +} + +template<class Json> +json_printable<Json> print(const Json& val, + const basic_serialization_options<typename Json::char_type>& options) +{ + return json_printable<Json>(val, false, options); +} + +template<class Json> +json_printable<Json> pretty_print(const Json& val) +{ + return json_printable<Json>(val,true); +} + +template<class Json> +json_printable<Json> pretty_print(const Json& val, + const basic_serialization_options<typename Json::char_type>& options) +{ + return json_printable<Json>(val, true, options); +} + +typedef basic_json<char,sorted_policy,std::allocator<char>> json; +typedef basic_json<wchar_t,sorted_policy,std::allocator<wchar_t>> wjson; +typedef basic_json<char, preserve_order_policy, std::allocator<char>> ojson; +typedef basic_json<wchar_t, preserve_order_policy, std::allocator<wchar_t>> wojson; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_json<wchar_t, preserve_order_policy, std::allocator<wchar_t>> owjson; +typedef json_decoder<json> json_deserializer; +typedef json_decoder<wjson> wjson_deserializer; +typedef json_decoder<ojson> ojson_deserializer; +typedef json_decoder<wojson> wojson_deserializer; +#endif + +#if defined(JSONCONS_HAS_USER_DEFINED_LITERALS) +namespace literals { + +inline +jsoncons::json operator "" _json(const char* s, std::size_t n) +{ + return jsoncons::json::parse(s, n); +} + +inline +jsoncons::wjson operator "" _json(const wchar_t* s, std::size_t n) +{ + return jsoncons::wjson::parse(s, n); +} + +inline +jsoncons::ojson operator "" _ojson(const char* s, std::size_t n) +{ + return jsoncons::ojson::parse(s, n); +} + +inline +jsoncons::wojson operator "" _ojson(const wchar_t* s, std::size_t n) +{ + return jsoncons::wojson::parse(s, n); +} + +} +#endif + +} + + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_decoder.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_decoder.hpp new file mode 100644 index 00000000..9ca5bd4c --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_decoder.hpp @@ -0,0 +1,310 @@ +// Copyright 2013-2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_DECODER_HPP +#define JSONCONS_JSON_DECODER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> + +namespace jsoncons { + +template <class Json,class Allocator=std::allocator<typename Json::char_type>> +class json_decoder final : public basic_json_input_handler<typename Json::char_type> +{ +public: + typedef typename Json::char_type char_type; + using typename basic_json_input_handler<char_type>::string_view_type; + + typedef typename Json::key_value_pair_type key_value_pair_type; + typedef typename Json::key_storage_type key_storage_type; + typedef typename Json::string_type string_type; + typedef typename Json::array array; + typedef typename Json::object object; + typedef typename Json::allocator_type json_allocator_type; + typedef typename string_type::allocator_type json_string_allocator; + typedef typename array::allocator_type json_array_allocator; + typedef typename object::allocator_type json_object_allocator; + + json_string_allocator string_allocator_; + json_object_allocator object_allocator_; + json_array_allocator array_allocator_; + + Json result_; + + struct stack_item + { + stack_item(key_storage_type&& name) + : name_(std::forward<key_storage_type>(name)) + { + } + stack_item(Json&& value) + : value_(std::forward<Json>(value)) + { + } + + stack_item() = default; + stack_item(const stack_item&) = default; + stack_item(stack_item&&) = default; + stack_item& operator=(const stack_item&) = default; + stack_item& operator=(stack_item&&) = default; + + key_storage_type name_; + Json value_; + }; + + struct structure_offset + { + size_t offset_; + bool is_object_; + }; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<stack_item> stack_item_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<structure_offset> size_t_allocator_type; + + + std::vector<stack_item,stack_item_allocator_type> stack_; + std::vector<structure_offset,size_t_allocator_type> stack_offsets_; + bool is_valid_; + +public: + json_decoder(const json_allocator_type& jallocator = json_allocator_type()) + : string_allocator_(jallocator), + object_allocator_(jallocator), + array_allocator_(jallocator), + is_valid_(false) + + { + stack_offsets_.reserve(100); + stack_.reserve(1000); + } + + bool is_valid() const + { + return is_valid_; + } + + Json get_result() + { + is_valid_ = false; + return std::move(result_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + Json& root() + { + return result_; + } +#endif + +private: + + void push_object() + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(object(object_allocator_)); + } + else + { + stack_.push_back(Json(object(object_allocator_))); + } + stack_offsets_.push_back({stack_.size()-1,true}); + } + + void pop_object() + { + stack_.erase(stack_.begin()+stack_offsets_.back().offset_+1, stack_.end()); + stack_offsets_.pop_back(); + } + + void push_array() + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(array(array_allocator_)); + } + else + { + stack_.push_back(Json(array(array_allocator_))); + } + stack_offsets_.push_back({stack_.size()-1,false}); + } + + void pop_array() + { + stack_.erase(stack_.begin()+stack_offsets_.back().offset_+1, stack_.end()); + stack_offsets_.pop_back(); + } + + void do_begin_json() override + { + stack_offsets_.clear(); + stack_.clear(); + stack_offsets_.push_back({0,false}); + is_valid_ = false; + } + + void do_end_json() override + { + if (stack_.size() == 1) + { + result_.swap(stack_.front().value_); + stack_.pop_back(); + is_valid_ = true; + } + } + + void do_begin_object(const parsing_context&) override + { + push_object(); + } + + void do_end_object(const parsing_context&) override + { + end_structure(); + pop_object(); + } + + void do_begin_array(const parsing_context&) override + { + push_array(); + } + + void do_end_array(const parsing_context&) override + { + end_structure(); + pop_array(); + } + + void end_structure() + { + JSONCONS_ASSERT(stack_offsets_.size() > 0); + const size_t structure_index = stack_offsets_.back().offset_; + JSONCONS_ASSERT(stack_.size() > structure_index); + const size_t count = stack_.size() - (structure_index + 1); + + auto first = stack_.begin() + (structure_index+1); + auto last = first + count; + if (stack_offsets_.back().is_object_) + { + stack_[structure_index].value_.object_value().insert( + std::make_move_iterator(first), + std::make_move_iterator(last), + [](stack_item&& val){return key_value_pair_type(std::move(val.name_),std::move(val.value_));}); + } + else + { + auto& j = stack_[structure_index].value_; + j.reserve(count); + while (first != last) + { + j.push_back(std::move(first->value_)); + ++first; + } + } + } + + void do_name(const string_view_type& name, const parsing_context&) override + { + stack_.push_back(key_storage_type(name.begin(),name.end(),string_allocator_)); + } + + void do_string_value(const string_view_type& val, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(val.data(),val.length(),string_allocator_); + } + else + { + stack_.push_back(Json(val.data(),val.length(),string_allocator_)); + } + } + + void do_byte_string_value(const uint8_t* data, size_t length, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(data,length,string_allocator_); + } + else + { + stack_.push_back(Json(data,length,string_allocator_)); + } + } + + void do_integer_value(int64_t value, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = value; + } + else + { + stack_.push_back(Json(value)); + } + } + + void do_uinteger_value(uint64_t value, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = value; + } + else + { + stack_.push_back(Json(value)); + } + } + + void do_double_value(double value, const number_format& fmt, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(value,fmt); + } + else + { + stack_.push_back(Json(value,fmt)); + } + } + + void do_bool_value(bool value, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = value; + } + else + { + stack_.push_back(Json(value)); + } + } + + void do_null_value(const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json::null(); + } + else + { + stack_.push_back(Json(Json::null())); + } + } +}; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_deserializer.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_deserializer.hpp new file mode 100644 index 00000000..05b44a40 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_deserializer.hpp @@ -0,0 +1,12 @@ +// Copyright 2013-2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_DESERIALIZER_HPP +#define JSONCONS_JSON_DESERIALIZER_HPP + +#include <jsoncons/json_decoder.hpp> + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_error_category.hpp new file mode 100644 index 00000000..c09b847a --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_error_category.hpp @@ -0,0 +1,148 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_ERROR_CATEGORY_HPP +#define JSONCONS_JSON_ERROR_CATEGORY_HPP + +#include <system_error> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { + + enum class json_parser_errc + { + ok = 0, + unexpected_eof = 1, + source_error, + invalid_json_text, + extra_character, + max_depth_exceeded, + single_quote, + illegal_character_in_string, + extra_comma, + expected_name, + expected_value, + invalid_value, + expected_colon, + illegal_control_character, + illegal_escaped_character, + expected_codepoint_surrogate_pair, + invalid_hex_escape_sequence, + invalid_unicode_escape_sequence, + leading_zero, + invalid_number, + expected_comma_or_right_brace, + expected_comma_or_right_bracket, + unexpected_right_bracket, + unexpected_right_brace, + illegal_comment, + expected_continuation_byte, + over_long_utf8_sequence, + illegal_codepoint, + illegal_surrogate_value, + unpaired_high_surrogate + }; + +class json_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsoncons"; + } + virtual std::string message(int ev) const + { + switch (static_cast<json_parser_errc>(ev)) + { + case json_parser_errc::unexpected_eof: + return "Unexpected end of file"; + case json_parser_errc::source_error: + return "Source error"; + case json_parser_errc::invalid_json_text: + return "Invalid JSON text"; + case json_parser_errc::extra_character: + return "Unexpected non-whitespace character after JSON text"; + case json_parser_errc::max_depth_exceeded: + return "Maximum JSON depth exceeded"; + case json_parser_errc::single_quote: + return "JSON strings cannot be quoted with single quotes"; + case json_parser_errc::illegal_character_in_string: + return "Illegal character in string"; + case json_parser_errc::extra_comma: + return "Extra comma"; + case json_parser_errc::expected_name: + return "Expected object member name"; + case json_parser_errc::expected_value: + return "Expected value"; + case json_parser_errc::invalid_value: + return "Invalid value"; + case json_parser_errc::expected_colon: + return "Expected name separator ':'"; + case json_parser_errc::illegal_control_character: + return "Illegal control character in string"; + case json_parser_errc::illegal_escaped_character: + return "Illegal escaped character in string"; + case json_parser_errc::expected_codepoint_surrogate_pair: + return "Invalid codepoint, expected another \\u token to begin the second half of a codepoint surrogate pair."; + case json_parser_errc::invalid_hex_escape_sequence: + return "Invalid codepoint, expected hexadecimal digit."; + case json_parser_errc::invalid_unicode_escape_sequence: + return "Invalid codepoint, expected four hexadecimal digits."; + case json_parser_errc::leading_zero: + return "A number cannot have a leading zero"; + case json_parser_errc::invalid_number: + return "Invalid number"; + case json_parser_errc::expected_comma_or_right_brace: + return "Expected comma or right brace ']'"; + case json_parser_errc::expected_comma_or_right_bracket: + return "Expected comma or right bracket ']'"; + case json_parser_errc::unexpected_right_brace: + return "Unexpected right brace '}'"; + case json_parser_errc::unexpected_right_bracket: + return "Unexpected right bracket ']'"; + case json_parser_errc::illegal_comment: + return "Illegal comment"; + case json_parser_errc::expected_continuation_byte: + return "Expected continuation byte"; + case json_parser_errc::over_long_utf8_sequence: + return "Over long UTF-8 sequence"; + case json_parser_errc::illegal_codepoint: + return "Illegal codepoint (>= 0xd800 && <= 0xdfff)"; + case json_parser_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case json_parser_errc::unpaired_high_surrogate: + return "Expected low surrogate following the high surrogate"; + default: + return "Unknown JSON parser error"; + } + } +}; + +inline +const std::error_category& json_error_category() +{ + static json_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(json_parser_errc result) +{ + return std::error_code(static_cast<int>(result),json_error_category()); +} + + +} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::json_parser_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_exception.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_exception.hpp new file mode 100644 index 00000000..668fa3c5 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_exception.hpp @@ -0,0 +1,107 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSON_EXCEPTION_HPP +#define JSON_EXCEPTION_HPP + +#include <locale> +#include <string> +#include <vector> +#include <cstdlib> +#include <cwchar> +#include <cstdint> +#include <iostream> +#include <vector> +#include <iterator> +#include <jsoncons/detail/unicode_traits.hpp> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { + +// json_exception + +class json_exception +{ +public: + virtual const char* what() const JSONCONS_NOEXCEPT = 0; +}; + +template <class Base> +class json_exception_impl : public Base, public virtual json_exception +{ +public: + json_exception_impl(const std::string& s) JSONCONS_NOEXCEPT + : Base(""), message_(s) + { + } + ~json_exception_impl() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return message_.c_str(); + } +private: + std::string message_; +}; + +class key_not_found : public std::out_of_range, public virtual json_exception +{ +public: + template <class CharT> + explicit key_not_found(const CharT* key, size_t length) JSONCONS_NOEXCEPT + : std::out_of_range("") + { + buffer_.append("Key '"); + unicons::convert(key, key+length, std::back_inserter(buffer_), + unicons::conv_flags::strict); + buffer_.append("' not found"); + } + ~key_not_found() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +class not_an_object : public std::runtime_error, public virtual json_exception +{ +public: + template <class CharT> + explicit not_an_object(const CharT* key, size_t length) JSONCONS_NOEXCEPT + : std::runtime_error("") + { + buffer_.append("Attempting to access or modify '"); + unicons::convert(key, key+length, std::back_inserter(buffer_), + unicons::conv_flags::strict); + buffer_.append("' on a value that is not an object"); + } + ~not_an_object() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +#define JSONCONS_STR2(x) #x +#define JSONCONS_STR(x) JSONCONS_STR2(x) + +#define JSONCONS_ASSERT(x) if (!(x)) { \ + throw jsoncons::json_exception_impl<std::runtime_error>("assertion '" #x "' failed at " __FILE__ ":" \ + JSONCONS_STR(__LINE__)); } + +#define JSONCONS_THROW(x) throw (x) + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_filter.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_filter.hpp new file mode 100644 index 00000000..30b69e18 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_filter.hpp @@ -0,0 +1,465 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_FILTER_HPP +#define JSONCONS_JSON_FILTER_HPP + +#include <string> + +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> + +namespace jsoncons { + +template <class CharT> +class basic_json_output_input_adapter : public basic_json_input_handler<CharT> +{ +public: + using typename basic_json_input_handler<CharT>::string_view_type; +private: + + basic_null_json_output_handler<CharT> null_output_handler_; + basic_json_output_handler<CharT>& output_handler_; + + // noncopyable and nonmoveable + basic_json_output_input_adapter<CharT>(const basic_json_output_input_adapter<CharT>&) = delete; + basic_json_output_input_adapter<CharT>& operator=(const basic_json_output_input_adapter<CharT>&) = delete; + +public: + basic_json_output_input_adapter() + : output_handler_(null_output_handler_) + { + } + + basic_json_output_input_adapter(basic_json_output_handler<CharT>& handler) + : output_handler_(handler) + { + } + +private: + + void do_begin_json() override + { + output_handler_.begin_json(); + } + + void do_end_json() override + { + output_handler_.end_json(); + } + + void do_begin_object(const parsing_context&) override + { + output_handler_.begin_object(); + } + + void do_begin_object(size_t length, const parsing_context&) override + { + output_handler_.begin_object(length); + } + + void do_end_object(const parsing_context&) override + { + output_handler_.end_object(); + } + + void do_begin_array(const parsing_context&) override + { + output_handler_.begin_array(); + } + + void do_begin_array(size_t length, const parsing_context&) override + { + output_handler_.begin_array(length); + } + + void do_end_array(const parsing_context&) override + { + output_handler_.end_array(); + } + + void do_name(const string_view_type& name, + const parsing_context&) override + { + output_handler_.name(name); + } + + void do_string_value(const string_view_type& value, + const parsing_context&) override + { + output_handler_.string_value(value); + } + + void do_byte_string_value(const uint8_t* data, size_t length, + const parsing_context&) override + { + output_handler_.byte_string_value(data, length); + } + + void do_integer_value(int64_t value, const parsing_context&) override + { + output_handler_.integer_value(value); + } + + void do_uinteger_value(uint64_t value, + const parsing_context&) override + { + output_handler_.uinteger_value(value); + } + + void do_double_value(double value, const number_format& fmt, const parsing_context&) override + { + output_handler_.double_value(value, fmt); + } + + void do_bool_value(bool value, const parsing_context&) override + { + output_handler_.bool_value(value); + } + + void do_null_value(const parsing_context&) override + { + output_handler_.null_value(); + } +}; + +template <class CharT> +class basic_json_input_output_adapter : public basic_json_output_handler<CharT> +{ +public: + using typename basic_json_output_handler<CharT>::string_view_type ; +private: + class null_parsing_context : public parsing_context + { + size_t do_line_number() const override { return 0; } + + size_t do_column_number() const override { return 0; } + }; + const null_parsing_context default_context_ = null_parsing_context(); + + basic_null_json_input_handler<CharT> null_input_handler_; + basic_json_output_input_adapter<CharT> default_input_output_adapter_; + basic_json_input_handler<CharT>& input_handler_; + const basic_json_output_input_adapter<CharT>& input_output_adapter_; + + // noncopyable and nonmoveable + basic_json_input_output_adapter<CharT>(const basic_json_input_output_adapter<CharT>&) = delete; + basic_json_input_output_adapter<CharT>& operator=(const basic_json_input_output_adapter<CharT>&) = delete; + +public: + basic_json_input_output_adapter() + : input_handler_(null_input_handler_), + input_output_adapter_(default_input_output_adapter_) + { + } + basic_json_input_output_adapter(basic_json_input_handler<CharT>& input_handler) + : input_handler_(input_handler), + input_output_adapter_(default_input_output_adapter_) + { + } + basic_json_input_output_adapter(basic_json_input_handler<CharT>& input_handler, + const basic_json_output_input_adapter<CharT>& input_output_adapter) + : input_handler_(input_handler), + input_output_adapter_(input_output_adapter) + { + } + +private: + + void do_begin_json() override + { + input_handler_.begin_json(); + } + + void do_end_json() override + { + input_handler_.end_json(); + } + + void do_begin_object() override + { + input_handler_.begin_object(default_context_); + } + + void do_begin_object(size_t length) override + { + input_handler_.begin_object(length, default_context_); + } + + void do_end_object() override + { + input_handler_.end_object(default_context_); + } + + void do_begin_array() override + { + input_handler_.begin_array(default_context_); + } + + void do_begin_array(size_t length) override + { + input_handler_.begin_array(length, default_context_); + } + + void do_end_array() override + { + input_handler_.end_array(default_context_); + } + + void do_name(const string_view_type& name) override + { + input_handler_.name(name, default_context_); + } + + void do_string_value(const string_view_type& value) override + { + input_handler_.string_value(value, default_context_); + } + + void do_byte_string_value(const uint8_t* data, size_t length) override + { + input_handler_.byte_string_value(data, length, default_context_); + } + + void do_integer_value(int64_t value) override + { + input_handler_.integer_value(value, default_context_); + } + + void do_uinteger_value(uint64_t value) override + { + input_handler_.uinteger_value(value, default_context_); + } + + void do_double_value(double value, const number_format& fmt) override + { + input_handler_.double_value(value, fmt, default_context_); + } + + void do_bool_value(bool value) override + { + input_handler_.bool_value(value, default_context_); + } + + void do_null_value() override + { + input_handler_.null_value(default_context_); + } +}; + +template <class CharT> +class basic_json_filter : public basic_json_input_handler<CharT> +{ +public: + using typename basic_json_input_handler<CharT>::string_view_type ; +private: + basic_json_output_input_adapter<CharT> input_output_adapter_; + basic_json_input_output_adapter<CharT> output_input_adapter_; + basic_json_output_handler<CharT>& output_handler_; + basic_json_input_handler<CharT>& downstream_handler_; + + // noncopyable and nonmoveable + basic_json_filter<CharT>(const basic_json_filter<CharT>&) = delete; + basic_json_filter<CharT>& operator=(const basic_json_filter<CharT>&) = delete; +public: + basic_json_filter(basic_json_output_handler<CharT>& handler) + : input_output_adapter_(handler), + output_input_adapter_(*this), + output_handler_(output_input_adapter_), + downstream_handler_(input_output_adapter_) + { + } + + basic_json_filter(basic_json_input_handler<CharT>& handler) + : output_input_adapter_(*this), + output_handler_(output_input_adapter_), + downstream_handler_(handler) + { + } + + operator basic_json_output_handler<CharT>&() + { + return output_handler_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_json_input_handler<CharT>& input_handler() + { + return downstream_handler_; + } +#endif + + basic_json_input_handler<CharT>& downstream_handler() + { + return downstream_handler_; + } + +private: + void do_begin_json() override + { + downstream_handler_.begin_json(); + } + + void do_end_json() override + { + downstream_handler_.end_json(); + } + + void do_begin_object(const parsing_context& context) override + { + downstream_handler_.begin_object(context); + } + + void do_begin_object(size_t length, const parsing_context& context) override + { + downstream_handler_.begin_object(length, context); + } + + void do_end_object(const parsing_context& context) override + { + downstream_handler_.end_object(context); + } + + void do_begin_array(const parsing_context& context) override + { + downstream_handler_.begin_array(context); + } + + void do_begin_array(size_t length, const parsing_context& context) override + { + downstream_handler_.begin_array(length, context); + } + + void do_end_array(const parsing_context& context) override + { + downstream_handler_.end_array(context); + } + + void do_name(const string_view_type& name, + const parsing_context& context) override + { + downstream_handler_.name(name,context); + } + + void do_string_value(const string_view_type& value, + const parsing_context& context) override + { + downstream_handler_.string_value(value,context); + } + + void do_byte_string_value(const uint8_t* data, size_t length, + const parsing_context& context) override + { + downstream_handler_.byte_string_value(data, length, context); + } + + void do_double_value(double value, const number_format& fmt, + const parsing_context& context) override + { + downstream_handler_.double_value(value, fmt, context); + } + + void do_integer_value(int64_t value, + const parsing_context& context) override + { + downstream_handler_.integer_value(value,context); + } + + void do_uinteger_value(uint64_t value, + const parsing_context& context) override + { + downstream_handler_.uinteger_value(value,context); + } + + void do_bool_value(bool value, + const parsing_context& context) override + { + downstream_handler_.bool_value(value,context); + } + + void do_null_value(const parsing_context& context) override + { + downstream_handler_.null_value(context); + } + +}; + +// Filters out begin_json and end_json events +template <class CharT> +class basic_json_fragment_filter : public basic_json_filter<CharT> +{ +public: + using typename basic_json_filter<CharT>::string_view_type; + + basic_json_fragment_filter(basic_json_input_handler<CharT>& handler) + : basic_json_filter<CharT>(handler) + { + } +private: + void do_begin_json() override + { + } + + void do_end_json() override + { + } +}; + +template <class CharT> +class basic_rename_object_member_filter : public basic_json_filter<CharT> +{ +public: + using typename basic_json_filter<CharT>::string_view_type; + +private: + std::basic_string<CharT> name_; + std::basic_string<CharT> new_name_; +public: + basic_rename_object_member_filter(const std::basic_string<CharT>& name, + const std::basic_string<CharT>& new_name, + basic_json_output_handler<CharT>& handler) + : basic_json_filter<CharT>(handler), + name_(name), new_name_(new_name) + { + } + + basic_rename_object_member_filter(const std::basic_string<CharT>& name, + const std::basic_string<CharT>& new_name, + basic_json_input_handler<CharT>& handler) + : basic_json_filter<CharT>(handler), + name_(name), new_name_(new_name) + { + } + +private: + void do_name(const string_view_type& name, + const parsing_context& context) override + { + if (name == name_) + { + this->downstream_handler().name(new_name_,context); + } + else + { + this->downstream_handler().name(name,context); + } + } +}; + +typedef basic_json_filter<char> json_filter; +typedef basic_json_filter<wchar_t> wjson_filter; +typedef basic_rename_object_member_filter<char> rename_object_member_filter; +typedef basic_rename_object_member_filter<wchar_t> wrename_object_member_filter; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_rename_object_member_filter<char> rename_name_filter; +typedef basic_rename_object_member_filter<wchar_t> wrename_name_filter; +#endif + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_input_handler.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_input_handler.hpp new file mode 100644 index 00000000..ed014287 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_input_handler.hpp @@ -0,0 +1,308 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_INPUT_HANDLER_HPP +#define JSONCONS_JSON_INPUT_HANDLER_HPP + +#include <string> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#if !defined(JSONCONS_NO_DEPRECATED) +#include <jsoncons/json_type_traits.hpp> // for null_type +#endif + +namespace jsoncons { + +class parsing_context; + +template <class CharT> +class basic_json_input_handler +{ +public: + typedef CharT char_type; + typedef std::char_traits<char_type> char_traits_type; + + typedef basic_string_view_ext<char_type,char_traits_type> string_view_type; + + virtual ~basic_json_input_handler() {} + + void begin_json() + { + do_begin_json(); + } + + void end_json() + { + do_end_json(); + } + + void begin_object(const parsing_context& context) + { + do_begin_object(context); + } + + void begin_object(size_t length, const parsing_context& context) + { + do_begin_object(length, context); + } + + void end_object(const parsing_context& context) + { + do_end_object(context); + } + + void begin_array(const parsing_context& context) + { + do_begin_array(context); + } + + void begin_array(size_t length, const parsing_context& context) + { + do_begin_array(length, context); + } + + void end_array(const parsing_context& context) + { + do_end_array(context); + } + + void name(const string_view_type& name, const parsing_context& context) + { + do_name(name, context); + } + +// new + + void string_value(const string_view_type& value, const parsing_context& context) + { + do_string_value(value, context); + } + + void byte_string_value(const uint8_t* data, size_t length, const parsing_context& context) + { + do_byte_string_value(data, length, context); + } + + void integer_value(int64_t value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void uinteger_value(uint64_t value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void double_value(double value, const parsing_context& context) + { + do_double_value(value, number_format(), context); + } + + void double_value(double value, uint8_t precision, const parsing_context& context) + { + do_double_value(value, number_format(precision, 0), context); + } + + void double_value(double value, const number_format& fmt, const parsing_context& context) + { + do_double_value(value, fmt, context); + } + + void bool_value(bool value, const parsing_context& context) + { + do_bool_value(value,context); + } + + void null_value(const parsing_context& context) + { + do_null_value(context); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void name(const CharT* p, size_t length, const parsing_context& context) + { + do_name(string_view_type(p, length), context); + } + + void value(const std::basic_string<CharT>& value, const parsing_context& context) + { + do_string_value(value, context); + } + + void value(const CharT* p, size_t length, const parsing_context& context) + { + do_string_value(string_view_type(p, length), context); + } + + void value(const CharT* p, const parsing_context& context) + { + do_string_value(string_view_type(p), context); + } + + void value(int value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void value(long value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void value(long long value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void value(unsigned int value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void value(unsigned long value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void value(unsigned long long value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void value(float value, uint8_t precision, const parsing_context& context) + { + do_double_value(value, number_format(precision, 0), context); + } + + void value(double value, uint8_t precision, const parsing_context& context) + { + do_double_value(value, number_format(precision, 0), context); + } + + void value(bool value, const parsing_context& context) + { + do_bool_value(value,context); + } + + void value(null_type, const parsing_context& context) + { + do_null_value(context); + } +#endif + +private: + virtual void do_begin_json() = 0; + + virtual void do_end_json() = 0; + + virtual void do_begin_object(const parsing_context& context) = 0; + + virtual void do_begin_object(size_t length, const parsing_context& context) + { + do_begin_object(context); + } + + virtual void do_end_object(const parsing_context& context) = 0; + + virtual void do_begin_array(const parsing_context& context) = 0; + + virtual void do_begin_array(size_t length, const parsing_context& context) + { + do_begin_array(context); + } + + virtual void do_end_array(const parsing_context& context) = 0; + + virtual void do_name(const string_view_type& name, const parsing_context& context) = 0; + + virtual void do_null_value(const parsing_context& context) = 0; + + virtual void do_string_value(const string_view_type& value, const parsing_context& context) = 0; + + virtual void do_byte_string_value(const uint8_t* data, size_t length, const parsing_context& context) = 0; + + virtual void do_double_value(double value, const number_format& fmt, const parsing_context& context) = 0; + + virtual void do_integer_value(int64_t value, const parsing_context& context) = 0; + + virtual void do_uinteger_value(uint64_t value, const parsing_context& context) = 0; + + virtual void do_bool_value(bool value, const parsing_context& context) = 0; +}; + +template <class CharT> +class basic_null_json_input_handler final : public basic_json_input_handler<CharT> +{ +public: + using typename basic_json_input_handler<CharT>::string_view_type ; +private: + void do_begin_json() override + { + } + + void do_end_json() override + { + } + + void do_begin_object(const parsing_context&) override + { + } + + void do_end_object(const parsing_context&) override + { + } + + void do_begin_array(const parsing_context&) override + { + } + + void do_end_array(const parsing_context&) override + { + } + + void do_name(const string_view_type&, const parsing_context&) override + { + } + + void do_null_value(const parsing_context&) override + { + } + + void do_string_value(const string_view_type&, const parsing_context&) override + { + } + + void do_byte_string_value(const uint8_t* data, size_t length, const parsing_context&) override + { + } + + void do_double_value(double, const number_format& fmt, const parsing_context&) override + { + } + + void do_integer_value(int64_t, const parsing_context&) override + { + } + + void do_uinteger_value(uint64_t, const parsing_context&) override + { + } + + void do_bool_value(bool, const parsing_context&) override + { + } +}; + +typedef basic_json_input_handler<char> json_input_handler; +typedef basic_json_input_handler<wchar_t> wjson_input_handler; + +typedef basic_null_json_input_handler<char> null_json_input_handler; +typedef basic_null_json_input_handler<wchar_t> wnull_json_input_handler; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_output_handler.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_output_handler.hpp new file mode 100644 index 00000000..b16f098e --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_output_handler.hpp @@ -0,0 +1,300 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_OUTPUT_HANDLER_HPP +#define JSONCONS_JSON_OUTPUT_HANDLER_HPP + +#include <string> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#if !defined(JSONCONS_NO_DEPRECATED) +#include <jsoncons/json_type_traits.hpp> // for null_type +#endif + +namespace jsoncons { + +template <class CharT> +class basic_json_output_handler +{ +public: + typedef CharT char_type; + typedef std::char_traits<char_type> char_traits_type; + + typedef basic_string_view_ext<char_type,char_traits_type> string_view_type; + + virtual ~basic_json_output_handler() {} + + // Overloaded methods + + void begin_json() + { + do_begin_json(); + } + + void end_json() + { + do_end_json(); + } + + void begin_object() + { + do_begin_object(); + } + + void begin_object(size_t length) + { + do_begin_object(length); + } + + void end_object() + { + do_end_object(); + } + + void begin_array() + { + do_begin_array(); + } + + void begin_array(size_t length) + { + do_begin_array(length); + } + + void end_array() + { + do_end_array(); + } + + void name(const string_view_type& name) + { + do_name(name); + } + + void string_value(const string_view_type& value) + { + do_string_value(value); + } + + void byte_string_value(const uint8_t* data, size_t length) + { + do_byte_string_value(data, length); + } + + void integer_value(int64_t value) + { + do_integer_value(value); + } + + void uinteger_value(uint64_t value) + { + do_uinteger_value(value); + } + + void double_value(double value) + { + do_double_value(value, number_format()); + } + + void double_value(double value, uint8_t precision) + { + do_double_value(value, number_format(precision, 0)); + } + + void double_value(double value, const number_format& fmt) + { + do_double_value(value, fmt); + } + + void bool_value(bool value) + { + do_bool_value(value); + } + + void null_value() + { + do_null_value(); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void name(const CharT* p, size_t length) + { + do_name(string_view_type(p, length)); + } + + void value(const string_view_type& value) + { + do_string_value(value); + } + + void value(const CharT* p, size_t length) + { + do_string_value(string_view_type(p, length)); + } + + void value(const CharT* p) + { + do_string_value(string_view_type(p)); + } + + void value(int value) + { + do_integer_value(value); + } + + void value(long value) + { + do_integer_value(value); + } + + void value(long long value) + { + do_integer_value(value); + } + + void value(unsigned int value) + { + do_uinteger_value(value); + } + + void value(unsigned long value) + { + do_uinteger_value(value); + } + + void value(unsigned long long value) + { + do_uinteger_value(value); + } + + void value(double value, uint8_t precision = 0, uint8_t decimal_places = 0) + { + do_double_value(value, precision, decimal_places); + } + + void value(bool value) + { + do_bool_value(value); + } + + void value(null_type) + { + do_null_value(); + } +#endif + +private: + + virtual void do_begin_json() = 0; + + virtual void do_end_json() = 0; + + virtual void do_name(const string_view_type& name) = 0; + + virtual void do_begin_object() = 0; + + virtual void do_begin_object(size_t length) + { + do_begin_object(); + } + + virtual void do_end_object() = 0; + + virtual void do_begin_array() = 0; + + virtual void do_begin_array(size_t length) + { + do_begin_array(); + } + + virtual void do_end_array() = 0; + + virtual void do_null_value() = 0; + + virtual void do_string_value(const string_view_type& value) = 0; + + virtual void do_byte_string_value(const uint8_t* data, size_t length) = 0; + + virtual void do_double_value(double value, const number_format& fmt) = 0; + + virtual void do_integer_value(int64_t value) = 0; + + virtual void do_uinteger_value(uint64_t value) = 0; + + virtual void do_bool_value(bool value) = 0; +}; + +template <class CharT> +class basic_null_json_output_handler : public basic_json_output_handler<CharT> +{ +public: + using typename basic_json_output_handler<CharT>::string_view_type ; +private: + + void do_begin_json() override + { + } + + void do_end_json() override + { + } + + void do_name(const string_view_type&) override + { + } + + void do_begin_object() override + { + } + + void do_end_object() override + { + } + + void do_begin_array() override + { + } + + void do_end_array() override + { + } + + void do_null_value() override + { + } + + void do_string_value(const string_view_type&) override + { + } + + void do_byte_string_value(const uint8_t* data, size_t length) override + { + } + + void do_double_value(double, const number_format&) override + { + } + + void do_integer_value(int64_t) override + { + } + + void do_uinteger_value(uint64_t) override + { + } + + void do_bool_value(bool) override + { + } + +}; + +typedef basic_json_output_handler<char> json_output_handler; +typedef basic_json_output_handler<wchar_t> wjson_output_handler; + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_parser.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_parser.hpp new file mode 100644 index 00000000..13bd9500 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_parser.hpp @@ -0,0 +1,2830 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_PARSER_HPP +#define JSONCONS_JSON_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons/json_error_category.hpp> +#include <jsoncons/detail/number_parsers.hpp> + +#define JSONCONS_ILLEGAL_CONTROL_CHARACTER \ + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: \ + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: \ + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f + +namespace jsoncons { + +enum class parse_state : uint8_t +{ + root, + start, + slash, + slash_slash, + slash_star, + slash_star_star, + expect_comma_or_end, + object, + expect_member_name_or_end, + expect_member_name, + expect_colon, + expect_value_or_end, + expect_value, + array, + string_u1, + member_name, + escape, + escape_u1, + escape_u2, + escape_u3, + escape_u4, + escape_expect_surrogate_pair1, + escape_expect_surrogate_pair2, + escape_u6, + escape_u7, + escape_u8, + escape_u9, + minus, + zero, + integer, + fraction1, + fraction2, + exp1, + exp2, + exp3, + n, + nu, + nul, + t, + tr, + tru, + f, + fa, + fal, + fals, + cr, + lf, + done +}; + +template <class CharT, class Allocator = std::allocator<char>> +class basic_json_parser : private parsing_context +{ + static const size_t initial_string_buffer_capacity_ = 1024; + static const size_t initial_number_buffer_capacity_ = 64; + static const int default_initial_stack_capacity_ = 100; + typedef typename basic_json_input_handler<CharT>::string_view_type string_view_type; + + basic_null_json_input_handler<CharT> default_input_handler_; + default_parse_error_handler default_err_handler_; + + basic_json_input_handler<CharT>& handler_; + parse_error_handler& err_handler_; + uint32_t cp_; + uint32_t cp2_; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<char> numeral_allocator_type; + + std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_buffer_; + std::basic_string<char,std::char_traits<char>,numeral_allocator_type> number_buffer_; + + bool is_negative_; + uint8_t precision_; + uint8_t decimal_places_; + + size_t line_; + size_t column_; + int nesting_depth_; + int initial_stack_capacity_; + + int max_depth_; + detail::string_to_double to_double_; + const CharT* begin_input_; + const CharT* input_end_; + const CharT* input_ptr_; + + parse_state state_; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<parse_state> parse_state_allocator_type; + std::vector<parse_state,parse_state_allocator_type> state_stack_; + + // Noncopyable and nonmoveable + basic_json_parser(const basic_json_parser&) = delete; + basic_json_parser& operator=(const basic_json_parser&) = delete; + +public: + + basic_json_parser() + : handler_(default_input_handler_), + err_handler_(default_err_handler_), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + basic_json_parser(parse_error_handler& err_handler) + : handler_(default_input_handler_), + err_handler_(err_handler), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + basic_json_parser(basic_json_input_handler<CharT>& handler) + : handler_(handler), + err_handler_(default_err_handler_), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + basic_json_parser(basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : handler_(handler), + err_handler_(err_handler), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + size_t line_number() const + { + return line_; + } + + size_t column_number() const + { + return column_; + } + + void set_column_number(size_t column) + { + column_ = column; + } + + bool source_exhausted() const + { + return input_ptr_ == input_end_; + } + + const parsing_context& parsing_context() const + { + return *this; + } + + ~basic_json_parser() + { + } + + size_t max_nesting_depth() const + { + return static_cast<size_t>(max_depth_); + } + + void max_nesting_depth(size_t max_nesting_depth) + { + max_depth_ = static_cast<int>((std::min)(max_nesting_depth,static_cast<size_t>((std::numeric_limits<int>::max)()))); + } + + parse_state parent() const + { + JSONCONS_ASSERT(state_stack_.size() >= 1); + return state_stack_.back(); + } + + bool done() const + { + return state_ == parse_state::done; + } + + void skip_whitespace() + { + const CharT* local_input_end = input_end_; + for (;;) + { + if (JSONCONS_UNLIKELY(input_ptr_ == local_input_end)) + { + return; + } + else if (*input_ptr_ == ' ' || *input_ptr_ == '\t') + { + ++input_ptr_; + ++column_; + } + else + { + return; + } + } + } + + void do_begin_object(std::error_code& ec) + { + if (++nesting_depth_ >= max_depth_) + { + if (err_handler_.error(json_parser_errc::max_depth_exceeded, *this)) + { + ec = json_parser_errc::max_depth_exceeded; + return; + } + } + push_state(parse_state::object); + state_ = parse_state::expect_member_name_or_end; + handler_.begin_object(*this); + } + + void do_end_object(std::error_code& ec) + { + --nesting_depth_; + state_ = pop_state(); + if (state_ == parse_state::object) + { + handler_.end_object(*this); + } + else if (state_ == parse_state::array) + { + err_handler_.fatal_error(json_parser_errc::expected_comma_or_right_bracket, *this); + ec = json_parser_errc::expected_comma_or_right_bracket; + return; + } + else + { + err_handler_.fatal_error(json_parser_errc::unexpected_right_brace, *this); + ec = json_parser_errc::unexpected_right_brace; + return; + } + + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + + void do_begin_array(std::error_code& ec) + { + if (++nesting_depth_ >= max_depth_) + { + if (err_handler_.error(json_parser_errc::max_depth_exceeded, *this)) + { + ec = json_parser_errc::max_depth_exceeded; + return; + } + + } + push_state(parse_state::array); + state_ = parse_state::expect_value_or_end; + handler_.begin_array(*this); + } + + void do_end_array(std::error_code& ec) + { + --nesting_depth_; + state_ = pop_state(); + if (state_ == parse_state::array) + { + handler_.end_array(*this); + } + else if (state_ == parse_state::object) + { + err_handler_.fatal_error(json_parser_errc::expected_comma_or_right_brace, *this); + ec = json_parser_errc::expected_comma_or_right_brace; + return; + } + else + { + err_handler_.fatal_error(json_parser_errc::unexpected_right_bracket, *this); + ec = json_parser_errc::unexpected_right_bracket; + return; + } + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + + void reset() + { + state_stack_.clear(); + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + state_ = parse_state::start; + line_ = 1; + column_ = 1; + nesting_depth_ = 0; + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void check_done(std::error_code& ec) + { + if (state_ != parse_state::done) + { + if (err_handler_.error(json_parser_errc::unexpected_eof, *this)) + { + ec = json_parser_errc::unexpected_eof; + return; + } + } + for (; input_ptr_ != input_end_; ++input_ptr_) + { + CharT curr_char_ = *input_ptr_; + switch (curr_char_) + { + case '\n': + case '\r': + case '\t': + case ' ': + break; + default: + if (err_handler_.error(json_parser_errc::extra_character, *this)) + { + ec = json_parser_errc::extra_character; + return; + } + break; + } + } + } + + void parse_some(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + + while ((input_ptr_ < local_input_end) && (state_ != parse_state::done)) + { + switch (state_) + { + case parse_state::cr: + ++line_; + column_ = 1; + switch (*input_ptr_) + { + case '\n': + state_ = pop_state(); + ++input_ptr_; + break; + default: + state_ = pop_state(); + break; + } + break; + case parse_state::lf: + ++line_; + column_ = 1; + state_ = pop_state(); + break; + case parse_state::start: + { + handler_.begin_json(); + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '{': + do_begin_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + do_begin_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + state_ = parse_state::string_u1; + ++input_ptr_; + ++column_; + break; + case '-': + number_buffer_.clear(); + is_negative_ = true; + precision_ = 0; + ++input_ptr_; + ++column_; + state_ = parse_state::minus; + parse_number(ec); + if (ec) {return;} + break; + case '0': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + state_ = parse_state::zero; + ++input_ptr_; + ++column_; + parse_number(ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::integer; + parse_number(ec); + if (ec) {return;} + break; + case 'n': + parse_null(ec); + if (ec) {return;} + break; + case 't': + parse_true(ec); + if (ec) {return;} + break; + case 'f': + parse_false(ec); + if (ec) {return;} + break; + case '}': + err_handler_.fatal_error(json_parser_errc::unexpected_right_brace, *this); + ec = json_parser_errc::unexpected_right_brace; + return; + case ']': + err_handler_.fatal_error(json_parser_errc::unexpected_right_bracket, *this); + ec = json_parser_errc::unexpected_right_bracket; + return; + default: + err_handler_.fatal_error(json_parser_errc::invalid_json_text, *this); + ec = json_parser_errc::invalid_json_text; + return; + } + } + break; + + case parse_state::expect_comma_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '}': + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ']': + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ',': + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + default: + if (parent() == parse_state::array) + { + if (err_handler_.error(json_parser_errc::expected_comma_or_right_bracket, *this)) + { + ec = json_parser_errc::expected_comma_or_right_bracket; + return; + } + } + else if (parent() == parse_state::object) + { + if (err_handler_.error(json_parser_errc::expected_comma_or_right_brace, *this)) + { + ec = json_parser_errc::expected_comma_or_right_brace; + return; + } + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_member_name_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '}': + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + push_state(parse_state::member_name); + state_ = parse_state::string_u1; + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_name, *this)) + { + ec = json_parser_errc::expected_name; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_member_name: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '\"': + ++input_ptr_; + ++column_; + push_state(parse_state::member_name); + state_ = parse_state::string_u1; + break; + case '}': + if (err_handler_.error(json_parser_errc::extra_comma, *this)) + { + ec = json_parser_errc::extra_comma; + return; + } + do_end_object(ec); // Recover + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_name, *this)) + { + ec = json_parser_errc::expected_name; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_colon: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + state_ = parse_state::cr; + ++input_ptr_; + ++column_; + break; + case '\n': + push_state(state_); + state_ = parse_state::lf; + ++input_ptr_; + ++column_; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + push_state(state_); + state_ = parse_state::slash; + ++input_ptr_; + ++column_; + break; + case ':': + state_ = parse_state::expect_value; + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_colon, *this)) + { + ec = json_parser_errc::expected_colon; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + + case parse_state::expect_value: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + break; + case '\n': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + break; + case '{': + do_begin_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + do_begin_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + state_ = parse_state::string_u1; + break; + case '-': + number_buffer_.clear(); + is_negative_ = true; + precision_ = 0; + ++input_ptr_; + ++column_; + state_ = parse_state::minus; + parse_number(ec); + if (ec) {return;} + break; + case '0': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::zero; + parse_number(ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::integer; + parse_number(ec); + if (ec) {return;} + break; + case 'n': + parse_null(ec); + if (ec) {return;} + break; + case 't': + parse_true(ec); + if (ec) {return;} + break; + case 'f': + parse_false(ec); + if (ec) {return;} + break; + case ']': + if (parent() == parse_state::array) + { + if (err_handler_.error(json_parser_errc::extra_comma, *this)) + { + ec = json_parser_errc::extra_comma; + return; + } + do_end_array(ec); // Recover + if (ec) return; + } + else + { + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + } + ++input_ptr_; + ++column_; + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_value_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '{': + do_begin_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + do_begin_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ']': + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + state_ = parse_state::string_u1; + break; + case '-': + number_buffer_.clear(); + is_negative_ = true; + precision_ = 0; + ++input_ptr_; + ++column_; + state_ = parse_state::minus; + parse_number(ec); + if (ec) {return;} + break; + case '0': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::zero; + parse_number(ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::integer; + parse_number(ec); + if (ec) {return;} + break; + case 'n': + parse_null(ec); + if (ec) {return;} + break; + case 't': + parse_true(ec); + if (ec) {return;} + break; + case 'f': + parse_false(ec); + if (ec) {return;} + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::string_u1: + case parse_state::escape: + case parse_state::escape_u1: + case parse_state::escape_u2: + case parse_state::escape_u3: + case parse_state::escape_u4: + case parse_state::escape_expect_surrogate_pair1: + case parse_state::escape_expect_surrogate_pair2: + case parse_state::escape_u6: + case parse_state::escape_u7: + case parse_state::escape_u8: + case parse_state::escape_u9: + parse_string(ec); + if (ec) return; + break; + case parse_state::minus: + case parse_state::zero: + case parse_state::integer: + case parse_state::fraction1: + case parse_state::fraction2: + case parse_state::exp1: + case parse_state::exp2: + case parse_state::exp3: + parse_number(ec); + if (ec) return; + break; + case parse_state::t: + switch (*input_ptr_) + { + case 'r': + ++input_ptr_; + ++column_; + state_ = parse_state::tr; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + break; + case parse_state::tr: + switch (*input_ptr_) + { + case 'u': + state_ = parse_state::tru; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::tru: + switch (*input_ptr_) + { + case 'e': + handler_.bool_value(true,*this); + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::f: + switch (*input_ptr_) + { + case 'a': + ++input_ptr_; + ++column_; + state_ = parse_state::fa; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + break; + case parse_state::fa: + switch (*input_ptr_) + { + case 'l': + state_ = parse_state::fal; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::fal: + switch (*input_ptr_) + { + case 's': + state_ = parse_state::fals; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::fals: + switch (*input_ptr_) + { + case 'e': + handler_.bool_value(false,*this); + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::n: + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++column_; + state_ = parse_state::nu; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + break; + case parse_state::nu: + switch (*input_ptr_) + { + case 'l': + state_ = parse_state::nul; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::nul: + switch (*input_ptr_) + { + case 'l': + handler_.null_value(*this); + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::slash: + { + switch (*input_ptr_) + { + case '*': + state_ = parse_state::slash_star; + if (err_handler_.error(json_parser_errc::illegal_comment, *this)) + { + ec = json_parser_errc::illegal_comment; + return; + } + break; + case '/': + state_ = parse_state::slash_slash; + if (err_handler_.error(json_parser_errc::illegal_comment, *this)) + { + ec = json_parser_errc::illegal_comment; + return; + } + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + ++input_ptr_; + ++column_; + break; + case parse_state::slash_star: + { + switch (*input_ptr_) + { + case '\r': + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + push_state(state_); + state_ = parse_state::lf; + break; + case '*': + state_ = parse_state::slash_star_star; + break; + } + } + ++input_ptr_; + ++column_; + break; + case parse_state::slash_slash: + { + switch (*input_ptr_) + { + case '\r': + state_ = pop_state(); + break; + case '\n': + state_ = pop_state(); + break; + default: + ++input_ptr_; + ++column_; + } + } + break; + case parse_state::slash_star_star: + { + switch (*input_ptr_) + { + case '/': + state_ = pop_state(); + break; + default: + state_ = parse_state::slash_star; + break; + } + } + ++input_ptr_; + ++column_; + break; + default: + JSONCONS_ASSERT(false); + break; + } + } + } + + void parse_true(std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'r' && *(input_ptr_+2) == 'u' && *(input_ptr_+3) == 'e') + { + handler_.bool_value(true,*this); + input_ptr_ += 4; + column_ += 4; + if (parent() == parse_state::root) + { + handler_.end_json(); + state_ = parse_state::done; + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = parse_state::t; + } + } + + void parse_null(std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'u' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 'l') + { + handler_.null_value(*this); + input_ptr_ += 4; + column_ += 4; + if (parent() == parse_state::root) + { + handler_.end_json(); + state_ = parse_state::done; + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = parse_state::n; + } + } + + void parse_false(std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 5)) + { + if (*(input_ptr_+1) == 'a' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 's' && *(input_ptr_+4) == 'e') + { + handler_.bool_value(false,*this); + input_ptr_ += 5; + column_ += 5; + if (parent() == parse_state::root) + { + handler_.end_json(); + state_ = parse_state::done; + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = parse_state::f; + } + } + + void parse_number(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + + switch (state_) + { + case parse_state::minus: + goto minus_sign; + case parse_state::zero: + goto zero; + case parse_state::integer: + goto integer; + case parse_state::fraction1: + goto fraction1; + case parse_state::fraction2: + goto fraction2; + case parse_state::exp1: + goto exp1; + case parse_state::exp2: + goto exp2; + case parse_state::exp3: + goto exp3; + default: + JSONCONS_UNREACHABLE(); + } +minus_sign: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::minus; + return; + } + switch (*input_ptr_) + { + case '0': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++precision_; + ++input_ptr_; + ++column_; + goto zero; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++precision_; + ++input_ptr_; + ++column_; + goto integer; + default: + err_handler_.error(json_parser_errc::expected_value, *this); + ec = json_parser_errc::expected_value; + return; + } +zero: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::zero; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + return; + case '\n': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_integer_value(ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_integer_value(ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + return; + case '}': + end_integer_value(ec); + if (ec) return; + do_end_object(ec); + ++input_ptr_; + ++column_; + if (ec) return; + return; + case ']': + end_integer_value(ec); + if (ec) return; + do_end_array(ec); + ++input_ptr_; + ++column_; + if (ec) return; + return; + case '.': + decimal_places_ = 0; + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++column_; + goto fraction1; + case 'e':case 'E': + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + case ',': + end_integer_value(ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + err_handler_.error(json_parser_errc::leading_zero, *this); + ec = json_parser_errc::leading_zero; + state_ = parse_state::zero; + return; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::zero; + return; + } +integer: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::integer; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + return; + case '\n': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_integer_value(ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + return; + case '}': + end_integer_value(ec); + if (ec) return; + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ']': + end_integer_value(ec); + if (ec) return; + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++precision_; + ++input_ptr_; + ++column_; + goto integer; + case '.': + decimal_places_ = 0; + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++column_; + goto fraction1; + case 'e':case 'E': + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + case ',': + end_integer_value(ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::integer; + return; + } +fraction1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::fraction1; + return; + } + switch (*input_ptr_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + ++precision_; + ++decimal_places_; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto fraction2; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::fraction1; + return; + } +fraction2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::fraction2; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + return; + case '\n': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + return; + case '}': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ']': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ',': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + ++precision_; + ++decimal_places_; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto fraction2; + case 'e':case 'E': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::fraction2; + return; + } +exp1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::exp1; + return; + } + switch (*input_ptr_) + { + case '+': + ++input_ptr_; + ++column_; + goto exp2; + case '-': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp2; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.error(json_parser_errc::expected_value, *this); + ec = json_parser_errc::expected_value; + state_ = parse_state::exp1; + return; + } +exp2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::exp2; + return; + } + switch (*input_ptr_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.error(json_parser_errc::expected_value, *this); + ec = json_parser_errc::expected_value; + state_ = parse_state::exp2; + return; + } + +exp3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::exp3; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + return; + case '\n': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + return; + case '}': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ']': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ',': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::exp3; + return; + } + + JSONCONS_UNREACHABLE(); + } + + void parse_string(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + const CharT* sb = input_ptr_; + + switch (state_) + { + case parse_state::string_u1: + goto string_u1; + case parse_state::escape: + goto escape; + case parse_state::escape_u1: + goto escape_u1; + case parse_state::escape_u2: + goto escape_u2; + case parse_state::escape_u3: + goto escape_u3; + case parse_state::escape_u4: + goto escape_u4; + case parse_state::escape_expect_surrogate_pair1: + goto escape_expect_surrogate_pair1; + case parse_state::escape_expect_surrogate_pair2: + goto escape_expect_surrogate_pair2; + case parse_state::escape_u6: + goto escape_u6; + case parse_state::escape_u7: + goto escape_u7; + case parse_state::escape_u8: + goto escape_u8; + case parse_state::escape_u9: + goto escape_u9; + default: + JSONCONS_UNREACHABLE(); + } + +string_u1: + while (input_ptr_ < local_input_end) + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + state_ = parse_state::string_u1; + return; + } + // recovery - skip + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb,input_ptr_-sb); + ++input_ptr_; + state_ = parse_state::string_u1; + return; + } + case '\r': + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_character_in_string, *this)) + { + ec = json_parser_errc::illegal_character_in_string; + state_ = parse_state::string_u1; + return; + } + // recovery - keep + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + push_state(state_); + state_ = parse_state::cr; + return; + } + case '\n': + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_character_in_string, *this)) + { + ec = json_parser_errc::illegal_character_in_string; + state_ = parse_state::string_u1; + return; + } + // recovery - keep + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + push_state(state_); + state_ = parse_state::lf; + return; + } + case '\t': + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_character_in_string, *this)) + { + ec = json_parser_errc::illegal_character_in_string; + state_ = parse_state::string_u1; + return; + } + // recovery - keep + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + state_ = parse_state::string_u1; + return; + } + case '\\': + { + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb,input_ptr_-sb); + column_ += (input_ptr_ - sb + 1); + ++input_ptr_; + goto escape; + } + case '\"': + { + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + if (string_buffer_.length() == 0) + { + end_string_value(sb,input_ptr_-sb, ec); + if (ec) {return;} + } + else + { + string_buffer_.append(sb,input_ptr_-sb); + end_string_value(string_buffer_.data(),string_buffer_.length(), ec); + string_buffer_.clear(); + if (ec) {return;} + } + column_ += (input_ptr_ - sb + 1); + ++input_ptr_; + return; + } + default: + break; + } + ++input_ptr_; + } + + // Buffer exhausted + { + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb,input_ptr_-sb); + column_ += (input_ptr_ - sb + 1); + state_ = parse_state::string_u1; + return; + } + +escape: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape; + return; + } + switch (*input_ptr_) + { + case '\"': + string_buffer_.push_back('\"'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case '\\': + string_buffer_.push_back('\\'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case '/': + string_buffer_.push_back('/'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'b': + string_buffer_.push_back('\b'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'f': + string_buffer_.push_back('\f'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'n': + string_buffer_.push_back('\n'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'r': + string_buffer_.push_back('\r'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 't': + string_buffer_.push_back('\t'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'u': + cp_ = 0; + ++input_ptr_; + ++column_; + goto escape_u1; + default: + err_handler_.error(json_parser_errc::illegal_escaped_character, *this); + ec = json_parser_errc::illegal_escaped_character; + state_ = parse_state::escape; + return; + } + +escape_u1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u1; + return; + } + { + append_codepoint(*input_ptr_,ec); + if (ec) + { + state_ = parse_state::escape_u1; + return; + } + ++input_ptr_; + ++column_; + goto escape_u2; + } + +escape_u2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u2; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u2; + return; + } + ++input_ptr_; + ++column_; + goto escape_u3; + } + +escape_u3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u3; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u3; + return; + } + ++input_ptr_; + ++column_; + goto escape_u4; + } + +escape_u4: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u4; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u4; + return; + } + if (unicons::is_high_surrogate(cp_)) + { + ++input_ptr_; + ++column_; + goto escape_expect_surrogate_pair1; + } + else + { + unicons::convert(&cp_, &cp_ + 1, std::back_inserter(string_buffer_)); + sb = ++input_ptr_; + ++column_; + state_ = parse_state::string_u1; + return; + } + } + +escape_expect_surrogate_pair1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_expect_surrogate_pair1; + return; + } + { + switch (*input_ptr_) + { + case '\\': + cp2_ = 0; + ++input_ptr_; + ++column_; + goto escape_expect_surrogate_pair2; + default: + err_handler_.error(json_parser_errc::expected_codepoint_surrogate_pair, *this); + ec = json_parser_errc::expected_codepoint_surrogate_pair; + state_ = parse_state::escape_expect_surrogate_pair1; + return; + } + } + +escape_expect_surrogate_pair2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_expect_surrogate_pair2; + return; + } + { + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++column_; + goto escape_u6; + default: + err_handler_.error(json_parser_errc::expected_codepoint_surrogate_pair, *this); + ec = json_parser_errc::expected_codepoint_surrogate_pair; + state_ = parse_state::escape_expect_surrogate_pair2; + return; + } + } + +escape_u6: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u6; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u6; + return; + } + } + ++input_ptr_; + ++column_; + goto escape_u7; + +escape_u7: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u7; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u7; + return; + } + ++input_ptr_; + ++column_; + goto escape_u8; + } + +escape_u8: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u8; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u8; + return; + } + ++input_ptr_; + ++column_; + goto escape_u9; + } + +escape_u9: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u9; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u9; + return; + } + uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); + unicons::convert(&cp, &cp + 1, std::back_inserter(string_buffer_)); + sb = ++input_ptr_; + ++column_; + goto string_u1; + } + + JSONCONS_UNREACHABLE(); + } + + void translate_conv_errc(unicons::conv_errc result, std::error_code& ec) + { + switch (result) + { + case unicons::conv_errc(): + break; + case unicons::conv_errc::over_long_utf8_sequence: + if (err_handler_.error(json_parser_errc::over_long_utf8_sequence, *this)) + { + ec = json_parser_errc::over_long_utf8_sequence; + return; + } + break; + case unicons::conv_errc::unpaired_high_surrogate: + if (err_handler_.error(json_parser_errc::unpaired_high_surrogate, *this)) + { + ec = json_parser_errc::unpaired_high_surrogate; + return; + } + break; + case unicons::conv_errc::expected_continuation_byte: + if (err_handler_.error(json_parser_errc::expected_continuation_byte, *this)) + { + ec = json_parser_errc::expected_continuation_byte; + return; + } + break; + case unicons::conv_errc::illegal_surrogate_value: + if (err_handler_.error(json_parser_errc::illegal_surrogate_value, *this)) + { + ec = json_parser_errc::illegal_surrogate_value; + return; + } + break; + default: + if (err_handler_.error(json_parser_errc::illegal_codepoint, *this)) + { + ec = json_parser_errc::illegal_codepoint; + return; + } + break; + } + } + + void parse_some() + { + std::error_code ec; + parse_some(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void end_parse() + { + std::error_code ec; + end_parse(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void end_parse(std::error_code& ec) + { + if (parent() == parse_state::root) + { + switch (state_) + { + case parse_state::zero: + case parse_state::integer: + end_integer_value(ec); + if (ec) return; + break; + case parse_state::fraction2: + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + break; + case parse_state::exp3: + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + break; + default: + break; + } + } + if (state_ == parse_state::lf || state_ == parse_state::cr) + { + state_ = pop_state(); + } + if (!(state_ == parse_state::done || state_ == parse_state::start)) + { + if (err_handler_.error(json_parser_errc::unexpected_eof, *this)) + { + ec = json_parser_errc::unexpected_eof; + return; + } + } + } + + parse_state state() const + { + return state_; + } + + void set_source(const CharT* input, size_t length) + { + begin_input_ = input; + input_end_ = input + length; + input_ptr_ = begin_input_; + } +private: + + void end_integer_value(std::error_code& ec) + { + if (is_negative_) + { + end_negative_value(ec); + } + else + { + end_positive_value(ec); + } + } + + void end_negative_value(std::error_code& ec) + { + static const int64_t min_value = (std::numeric_limits<int64_t>::min)(); + static const int64_t min_value_div_10 = min_value / 10; + + const char* s = number_buffer_.data(); + size_t length = number_buffer_.length(); + int64_t n = 0; + bool overflow = false; + const char* end = s + length; + for (; s < end; ++s) + { + int64_t x = *s - '0'; + if (n < min_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n < min_value + x) + { + overflow = true; + break; + } + + n -= x; + } + + if (!overflow) + { + handler_.integer_value(n, *this); + + switch (parent()) + { + case parse_state::array: + case parse_state::object: + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + else + { + end_fraction_value(chars_format::general,ec); + } + } + + void end_positive_value(std::error_code& ec) + { + static const uint64_t max_value = (std::numeric_limits<uint64_t>::max)(); + static const uint64_t max_value_div_10 = max_value / 10; + uint64_t n = 0; + bool overflow = false; + const char* s = number_buffer_.data(); + size_t length = number_buffer_.length(); + + const char* end = s + length; + for (; s < end; ++s) + { + uint64_t x = *s - '0'; + if (n > max_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n > max_value - x) + { + overflow = true; + break; + } + + n += x; + } + + if (!overflow) + { + handler_.uinteger_value(n, *this); + + switch (parent()) + { + case parse_state::array: + case parse_state::object: + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + else + { + end_fraction_value(chars_format::general,ec); + } + } + + void end_fraction_value(chars_format format, std::error_code& ec) + { + try + { + double d = to_double_(number_buffer_.c_str(), number_buffer_.length()); + if (is_negative_) + d = -d; + + if (precision_ > std::numeric_limits<double>::max_digits10) + { + handler_.double_value(d, number_format(format,std::numeric_limits<double>::max_digits10, decimal_places_), *this); + } + else + { + handler_.double_value(d, number_format(format,static_cast<uint8_t>(precision_), decimal_places_), *this); + } + } + catch (...) + { + if (err_handler_.error(json_parser_errc::invalid_number, *this)) + { + ec = json_parser_errc::invalid_number; + return; + } + handler_.null_value(*this); // recovery + } + + switch (parent()) + { + case parse_state::array: + case parse_state::object: + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + + void append_codepoint(int c, std::error_code& ec) + { + switch (c) + { + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp_ = append_to_codepoint(cp_, c, ec); + if (ec) return; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + break; + } + } + + void append_second_codepoint(int c, std::error_code& ec) + { + switch (c) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp2_ = append_to_codepoint(cp2_, c, ec); + if (ec) return; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + break; + } + } + + void end_string_value(const CharT* s, size_t length, std::error_code& ec) + { + switch (parent()) + { + case parse_state::member_name: + handler_.name(string_view_type(s, length), *this); + state_ = pop_state(); + state_ = parse_state::expect_colon; + break; + case parse_state::object: + case parse_state::array: + handler_.string_value(string_view_type(s, length), *this); + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + handler_.string_value(string_view_type(s, length), *this); + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + + void begin_member_or_element(std::error_code& ec) + { + switch (parent()) + { + case parse_state::object: + state_ = parse_state::expect_member_name; + break; + case parse_state::array: + state_ = parse_state::expect_value; + break; + case parse_state::root: + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + + void push_state(parse_state state) + { + state_stack_.push_back(state); + } + + parse_state pop_state() + { + JSONCONS_ASSERT(!state_stack_.empty()) + parse_state state = state_stack_.back(); + state_stack_.pop_back(); + return state; + } + + uint32_t append_to_codepoint(uint32_t cp, int c, std::error_code& ec) + { + cp *= 16; + if (c >= '0' && c <= '9') + { + cp += c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + cp += c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + cp += c - 'A' + 10; + } + else + { + if (err_handler_.error(json_parser_errc::invalid_hex_escape_sequence, *this)) + { + ec = json_parser_errc::invalid_hex_escape_sequence; + return cp; + } + } + return cp; + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } +}; + +typedef basic_json_parser<char> json_parser; +typedef basic_json_parser<wchar_t> wjson_parser; + +} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_reader.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_reader.hpp new file mode 100644 index 00000000..d419e2d8 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_reader.hpp @@ -0,0 +1,408 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_READER_HPP +#define JSONCONS_JSON_READER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <ios> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons/json_parser.hpp> + +namespace jsoncons { + +// utf8_other_json_input_adapter + +template <class CharT> +class json_utf8_other_input_handler_adapter : public json_input_handler +{ +public: + using json_input_handler::string_view_type; +private: + basic_null_json_input_handler<CharT> default_input_handler_; + basic_json_input_handler<CharT>& other_handler_; + //parse_error_handler& err_handler_; + + // noncopyable and nonmoveable + json_utf8_other_input_handler_adapter<CharT>(const json_utf8_other_input_handler_adapter<CharT>&) = delete; + json_utf8_other_input_handler_adapter<CharT>& operator=(const json_utf8_other_input_handler_adapter<CharT>&) = delete; + +public: + json_utf8_other_input_handler_adapter() + : other_handler_(default_input_handler_) + { + } + + json_utf8_other_input_handler_adapter(basic_json_input_handler<CharT>& other_handler/*, + parse_error_handler& err_handler*/) + : other_handler_(other_handler)/*, + err_handler_(err_handler)*/ + { + } + +private: + + void do_begin_json() override + { + other_handler_.begin_json(); + } + + void do_end_json() override + { + other_handler_.end_json(); + } + + void do_begin_object(const parsing_context& context) override + { + other_handler_.begin_object(context); + } + + void do_end_object(const parsing_context& context) override + { + other_handler_.end_object(context); + } + + void do_begin_array(const parsing_context& context) override + { + other_handler_.begin_array(context); + } + + void do_end_array(const parsing_context& context) override + { + other_handler_.end_array(context); + } + + void do_name(const string_view_type& name, const parsing_context& context) override + { + std::basic_string<CharT> target; + auto result = unicons::convert( + name.begin(), name.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw parse_error(result.ec,context.line_number(),context.column_number()); + } + other_handler_.name(target, context); + } + + void do_string_value(const string_view_type& value, const parsing_context& context) override + { + std::basic_string<CharT> target; + auto result = unicons::convert( + value.begin(), value.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw parse_error(result.ec,context.line_number(),context.column_number()); + } + other_handler_.string_value(target, context); + } + + void do_integer_value(int64_t value, const parsing_context& context) override + { + other_handler_.integer_value(value, context); + } + + void do_uinteger_value(uint64_t value, const parsing_context& context) override + { + other_handler_.uinteger_value(value, context); + } + + void do_double_value(double value, const number_format& fmt, const parsing_context& context) override + { + other_handler_.double_value(value, fmt, context); + } + + void do_bool_value(bool value, const parsing_context& context) override + { + other_handler_.bool_value(value, context); + } + + void do_null_value(const parsing_context& context) override + { + other_handler_.null_value(context); + } +}; + +template<class CharT,class Allocator=std::allocator<char>> +class basic_json_reader +{ + static const size_t default_max_buffer_length = 16384; + + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + + basic_json_parser<CharT,Allocator> parser_; + std::basic_istream<CharT>& is_; + bool eof_; + std::vector<CharT,char_allocator_type> buffer_; + size_t buffer_length_; + bool begin_; + + // Noncopyable and nonmoveable + basic_json_reader(const basic_json_reader&) = delete; + basic_json_reader& operator=(const basic_json_reader&) = delete; + +public: + + basic_json_reader(std::basic_istream<CharT>& is) + : parser_(), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + parse_error_handler& err_handler) + : parser_(err_handler), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler) + : parser_(handler), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : parser_(handler,err_handler), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + + size_t max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_nesting_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } + + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + throw parse_error(ec,parser_.line_number(),parser_.column_number()); + } + } + + void read_buffer(std::error_code& ec) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + is_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast<size_t>(is_.gcount())); + if (buffer_.size() == 0) + { + eof_ = true; + } + else if (begin_) + { + auto result = unicons::skip_bom(buffer_.begin(), buffer_.end()); + if (result.ec != unicons::encoding_errc()) + { + ec = result.ec; + return; + } + size_t offset = result.it - buffer_.begin(); + parser_.set_source(buffer_.data()+offset,buffer_.size()-offset); + begin_ = false; + } + else + { + parser_.set_source(buffer_.data(),buffer_.size()); + } + } + + void read_next(std::error_code& ec) + { + parser_.reset(); + while (!eof_ && !parser_.done()) + { + if (parser_.source_exhausted()) + { + if (!is_.eof()) + { + if (is_.fail()) + { + ec = json_parser_errc::source_error; + return; + } + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.parse_some(ec); + if (ec) return; + } + } + if (eof_) + { + parser_.end_parse(ec); + if (ec) return; + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw parse_error(ec,parser_.line_number(),parser_.column_number()); + } + } + + size_t line_number() const + { + return parser_.line_number(); + } + + size_t column_number() const + { + return parser_.column_number(); + } + + void check_done(std::error_code& ec) + { + if (eof_) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + while (!eof_) + { + if (parser_.source_exhausted()) + { + if (!is_.eof()) + { + if (is_.fail()) + { + ec = json_parser_errc::source_error; + return; + } + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.check_done(ec); + if (ec) return; + } + } + } + } + + bool eof() const + { + return eof_; + } + + void read() + { + read_next(); + check_done(); + } + + void read(std::error_code& ec) + { + read_next(ec); + if (!ec) + { + check_done(ec); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t buffer_capacity() const + { + return buffer_length_; + } + + void buffer_capacity(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + size_t max_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } +#endif + +private: +}; + +typedef basic_json_reader<char> json_reader; +typedef basic_json_reader<wchar_t> wjson_reader; + +} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_serializer.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_serializer.hpp new file mode 100644 index 00000000..42538671 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_serializer.hpp @@ -0,0 +1,585 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_SERIALIZER_HPP +#define JSONCONS_JSON_SERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> // std::numeric_limits +#include <fstream> +#include <memory> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/detail/writer.hpp> +#include <jsoncons/detail/number_printers.hpp> + +namespace jsoncons { + +template<class CharT,class Writer=detail::ostream_buffered_writer<CharT>> +class basic_json_serializer final : public basic_json_output_handler<CharT> +{ +public: + using typename basic_json_output_handler<CharT>::string_view_type; + typedef Writer writer_type; + typedef typename Writer::output_type output_type; + +private: + static const size_t default_buffer_length = 16384; + + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0), split_lines_(line_split_kind::same_line), indent_once_(false), unindent_at_end_(false) + { + } + stack_item(bool is_object, line_split_kind split_lines, bool indent_once = false) + : is_object_(is_object), count_(0), split_lines_(split_lines), indent_once_(indent_once), unindent_at_end_(false) + { + } + + size_t count() const + { + return count_; + } + + bool unindent_at_end() const + { + return unindent_at_end_; + } + + bool is_object() const + { + return is_object_; + } + + bool is_new_line() const + { + return split_lines_ != line_split_kind::same_line; + } + + bool is_multi_line() const + { + return split_lines_ == line_split_kind::multi_line; + } + + bool is_indent_once() const + { + return count_ == 0 ? indent_once_ : false; + } + + bool is_object_; + size_t count_; + line_split_kind split_lines_; + bool indent_once_; + bool unindent_at_end_; + }; + basic_serialization_options<CharT> options_; + std::vector<stack_item> stack_; + int indent_; + bool indenting_; + detail::print_double fp_; + Writer writer_; + + // Noncopyable and nonmoveable + basic_json_serializer(const basic_json_serializer&) = delete; + basic_json_serializer& operator=(const basic_json_serializer&) = delete; +public: + basic_json_serializer(output_type& os) + : indent_(0), + indenting_(false), + fp_(options_.precision()), + writer_(os) + { + } + + basic_json_serializer(output_type& os, bool pprint) + : indent_(0), + indenting_(pprint), + fp_(options_.precision()), + writer_(os) + { + } + + basic_json_serializer(output_type& os, const basic_serialization_options<CharT>& options) + : options_(options), + indent_(0), + indenting_(false), + fp_(options_.precision()), + writer_(os) + { + } + basic_json_serializer(output_type& os, const basic_serialization_options<CharT>& options, bool pprint) + : options_(options), + indent_(0), + indenting_(pprint), + fp_(options_.precision()), + writer_(os) + { + } + + ~basic_json_serializer() + { + } + +private: + void escape_string(const CharT* s, + size_t length, + const basic_serialization_options<CharT>& options, + writer_type& writer) + { + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + switch (c) + { + case '\\': + writer.put('\\'); + writer.put('\\'); + break; + case '"': + writer.put('\\'); + writer.put('\"'); + break; + case '\b': + writer.put('\\'); + writer.put('b'); + break; + case '\f': + writer.put('\\'); + writer.put('f'); + break; + case '\n': + writer.put('\\'); + writer.put('n'); + break; + case '\r': + writer.put('\\'); + writer.put('r'); + break; + case '\t': + writer.put('\\'); + writer.put('t'); + break; + default: + if (options.escape_solidus() && c == '/') + { + writer.put('\\'); + writer.put('/'); + } + else if (is_control_character(c) || options.escape_all_non_ascii()) + { + // convert utf8 to codepoint + unicons::sequence_generator<const CharT*> g(it,end,unicons::conv_flags::strict); + if (g.done() || g.status() != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid codepoint")); + } + uint32_t cp = g.get().codepoint(); + it += (g.get().length() - 1); + if (is_non_ascii_codepoint(cp) || is_control_character(c)) + { + if (cp > 0xFFFF) + { + cp -= 0x10000; + uint32_t first = (cp >> 10) + 0xD800; + uint32_t second = ((cp & 0x03FF) + 0xDC00); + + writer.put('\\'); + writer.put('u'); + writer.put(to_hex_character(first >> 12 & 0x000F)); + writer.put(to_hex_character(first >> 8 & 0x000F)); + writer.put(to_hex_character(first >> 4 & 0x000F)); + writer.put(to_hex_character(first & 0x000F)); + writer.put('\\'); + writer.put('u'); + writer.put(to_hex_character(second >> 12 & 0x000F)); + writer.put(to_hex_character(second >> 8 & 0x000F)); + writer.put(to_hex_character(second >> 4 & 0x000F)); + writer.put(to_hex_character(second & 0x000F)); + } + else + { + writer.put('\\'); + writer.put('u'); + writer.put(to_hex_character(cp >> 12 & 0x000F)); + writer.put(to_hex_character(cp >> 8 & 0x000F)); + writer.put(to_hex_character(cp >> 4 & 0x000F)); + writer.put(to_hex_character(cp & 0x000F)); + } + } + else + { + writer.put(c); + } + } + else + { + writer.put(c); + } + break; + } + } + } + // Implementing methods + void do_begin_json() override + { + } + + void do_end_json() override + { + writer_.flush(); + } + + void do_begin_object() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + } + } + + if (indenting_) + { + if (!stack_.empty() && stack_.back().is_object()) + { + stack_.push_back(stack_item(true,options_.object_object_split_lines(), false)); + } + else if (!stack_.empty()) + { + if (options_.array_object_split_lines() != line_split_kind::same_line) + { + stack_.back().unindent_at_end_ = true; + stack_.push_back(stack_item(true,options_.array_object_split_lines(), false)); + write_indent1(); + } + else + { + stack_.push_back(stack_item(true,options_.array_object_split_lines(), false)); + } + } + else + { + stack_.push_back(stack_item(true, line_split_kind::multi_line, false)); + } + indent(); + } + else + { + stack_.push_back(stack_item(true)); + } + writer_.put('{'); + } + + void do_end_object() override + { + JSONCONS_ASSERT(!stack_.empty()); + if (indenting_) + { + unindent(); + if (stack_.back().unindent_at_end()) + { + write_indent(); + } + } + stack_.pop_back(); + writer_.put('}'); + + end_value(); + } + + + void do_begin_array() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + } + } + if (indenting_) + { + if (!stack_.empty() && stack_.back().is_object()) + { + writer_.put('['); + indent(); + if (options_.object_array_split_lines() != line_split_kind::same_line) + { + stack_.push_back(stack_item(false,options_.object_array_split_lines(),true)); + } + else + { + stack_.push_back(stack_item(false,options_.object_array_split_lines(),false)); + } + } + else if (!stack_.empty()) + { + if (options_.array_array_split_lines() != line_split_kind::same_line) + { + write_indent(); + } + stack_.push_back(stack_item(false,options_.array_array_split_lines(), false)); + indent(); + writer_.put('['); + } + else + { + stack_.push_back(stack_item(false, line_split_kind::multi_line, false)); + indent(); + writer_.put('['); + } + } + else + { + stack_.push_back(stack_item(false)); + writer_.put('['); + } + } + + void do_end_array() override + { + JSONCONS_ASSERT(!stack_.empty()); + if (indenting_) + { + unindent(); + if (stack_.back().unindent_at_end()) + { + write_indent(); + } + } + stack_.pop_back(); + writer_.put(']'); + end_value(); + } + + void do_name(const string_view_type& name) override + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + if (indenting_) + { + if (stack_.back().is_multi_line()) + { + write_indent(); + } + } + } + + writer_.put('\"'); + escape_string(name.data(), name.length(), options_, writer_); + writer_.put('\"'); + writer_.put(':'); + if (indenting_) + { + writer_.put(' '); + } + } + + void do_null_value() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + auto buf = detail::null_literal<CharT>(); + writer_.write(buf, 4); + + end_value(); + } + + void do_string_value(const string_view_type& value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + writer_. put('\"'); + escape_string(value.data(), value.length(), options_, writer_); + writer_. put('\"'); + + end_value(); + } + + void do_byte_string_value(const uint8_t* data, size_t length) override + { + std::basic_string<CharT> s; + encode_base64url(data,data+length,s); + do_string_value(s); + } + + void do_double_value(double value, const number_format& fmt) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + if ((std::isnan)(value)) + { + writer_.write(options_.nan_replacement()); + } + else if (value == std::numeric_limits<double>::infinity()) + { + writer_.write(options_.pos_inf_replacement()); + } + else if (!(std::isfinite)(value)) + { + writer_.write(options_.neg_inf_replacement()); + } + else + { + fp_(value, fmt.precision(), writer_); + } + + end_value(); + } + + void do_integer_value(int64_t value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + detail::print_integer(value, writer_); + end_value(); + } + + void do_uinteger_value(uint64_t value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + detail::print_uinteger(value, writer_); + end_value(); + } + + void do_bool_value(bool value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + if (value) + { + auto buf = detail::true_literal<CharT>(); + writer_.write(buf,4); + } + else + { + auto buf = detail::false_literal<CharT>(); + writer_.write(buf,5); + } + + end_value(); + } + + void begin_scalar_value() + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + if (indenting_) + { + if (stack_.back().is_multi_line() || stack_.back().is_indent_once()) + { + write_indent(); + } + } + } + } + + void begin_value() + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + if (indenting_) + { + if (stack_.back().is_new_line()) + { + write_indent(); + } + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } + + void indent() + { + indent_ += static_cast<int>(options_.indent()); + } + + void unindent() + { + indent_ -= static_cast<int>(options_.indent()); + } + + void write_indent() + { + if (!stack_.empty()) + { + stack_.back().unindent_at_end_ = true; + } + writer_. put('\n'); + for (int i = 0; i < indent_; ++i) + { + writer_. put(' '); + } + } + + void write_indent1() + { + writer_. put('\n'); + for (int i = 0; i < indent_; ++i) + { + writer_. put(' '); + } + } +}; + +typedef basic_json_serializer<char,detail::ostream_buffered_writer<char>> json_serializer; +typedef basic_json_serializer<wchar_t, detail::ostream_buffered_writer<wchar_t>> wjson_serializer; + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_structures.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_structures.hpp new file mode 100644 index 00000000..74aa1507 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_structures.hpp @@ -0,0 +1,1864 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_STRUCTURES_HPP +#define JSONCONS_JSON_STRUCTURES_HPP + +#include <string> +#include <vector> +#include <deque> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <algorithm> +#include <sstream> +#include <iomanip> +#include <utility> +#include <initializer_list> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/json_type_traits.hpp> + +namespace jsoncons { + +// json_array + +template <class Json> +class Json_array_base_ +{ +public: + typedef typename Json::allocator_type allocator_type; + +public: + Json_array_base_() + : self_allocator_() + { + } + Json_array_base_(const allocator_type& allocator) + : self_allocator_(allocator) + { + } + + allocator_type get_allocator() const + { + return self_allocator_; + } + + allocator_type self_allocator_; +}; + +// json_array + +template <class Json> +class json_array: public Json_array_base_<Json> +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef Json value_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type> val_allocator_type; + + typedef typename Json::array_storage_type array_storage_type; + + typedef typename array_storage_type::iterator iterator; + typedef typename array_storage_type::const_iterator const_iterator; + + typedef typename std::iterator_traits<iterator>::reference reference; + typedef typename std::iterator_traits<const_iterator>::reference const_reference; + + using Json_array_base_<Json>::get_allocator; + + json_array() + : Json_array_base_<Json>(), + elements_() + { + } + + explicit json_array(const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(val_allocator_type(allocator)) + { + } + + explicit json_array(size_t n, + const allocator_type& allocator = allocator_type()) + : Json_array_base_<Json>(allocator), + elements_(n,Json(),val_allocator_type(allocator)) + { + } + + explicit json_array(size_t n, + const Json& value, + const allocator_type& allocator = allocator_type()) + : Json_array_base_<Json>(allocator), + elements_(n,value,val_allocator_type(allocator)) + { + } + + template <class InputIterator> + json_array(InputIterator begin, InputIterator end, const allocator_type& allocator = allocator_type()) + : Json_array_base_<Json>(allocator), + elements_(begin,end,val_allocator_type(allocator)) + { + } + json_array(const json_array& val) + : Json_array_base_<Json>(val.get_allocator()), + elements_(val.elements_) + { + } + json_array(const json_array& val, const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(val.elements_,val_allocator_type(allocator)) + { + } + + json_array(json_array&& val) JSONCONS_NOEXCEPT + : Json_array_base_<Json>(val.get_allocator()), + elements_(std::move(val.elements_)) + { + } + json_array(json_array&& val, const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(std::move(val.elements_),val_allocator_type(allocator)) + { + } + + json_array(std::initializer_list<Json> init) + : Json_array_base_<Json>(), + elements_(std::move(init)) + { + } + + json_array(std::initializer_list<Json> init, + const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(std::move(init),val_allocator_type(allocator)) + { + } + ~json_array() + { + } + + void swap(json_array<Json>& val) + { + elements_.swap(val.elements_); + } + + size_t size() const {return elements_.size();} + + size_t capacity() const {return elements_.capacity();} + + void clear() {elements_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < elements_.size(); ++i) + { + elements_[i].shrink_to_fit(); + } + elements_.shrink_to_fit(); + } + + void reserve(size_t n) {elements_.reserve(n);} + + void resize(size_t n) {elements_.resize(n);} + + void resize(size_t n, const Json& val) {elements_.resize(n,val);} + + void remove_range(size_t from_index, size_t to_index) + { + JSONCONS_ASSERT(from_index <= to_index); + JSONCONS_ASSERT(to_index <= elements_.size()); + elements_.erase(elements_.begin()+from_index,elements_.begin()+to_index); + } + + void erase(const_iterator pos) + { + elements_.erase(pos); + } + + void erase(const_iterator first, const_iterator last) + { + elements_.erase(first,last); + } + + Json& operator[](size_t i) {return elements_[i];} + + const Json& operator[](size_t i) const {return elements_[i];} + + // push_back + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward<T>(value)); + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward<T>(value),get_allocator()); + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + insert(const_iterator pos, T&& value) + { +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward<T>(value)); +#else + return elements_.emplace(pos, std::forward<T>(value)); +#endif + } + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + insert(const_iterator pos, T&& value) + { +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward<T>(value), get_allocator()); +#else + return elements_.emplace(pos, std::forward<T>(value), get_allocator()); +#endif + } + + template <class InputIt> + iterator insert(const_iterator pos, InputIt first, InputIt last) + { +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.insert(it, first, last); +#else + return elements_.insert(pos, first, last); +#endif + } + +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + emplace(const_iterator pos, Args&&... args) + { + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward<Args>(args)...); + } +#else + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + emplace(const_iterator pos, Args&&... args) + { + return elements_.emplace(pos, std::forward<Args>(args)...); + } +#endif + template <class... Args> + Json& emplace_back(Args&&... args) + { + elements_.emplace_back(std::forward<Args>(args)...); + return elements_.back(); + } + + iterator begin() {return elements_.begin();} + + iterator end() {return elements_.end();} + + const_iterator begin() const {return elements_.begin();} + + const_iterator end() const {return elements_.end();} + + bool operator==(const json_array<Json>& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (size_t i = 0; i < size(); ++i) + { + if (elements_[i] != rhs.elements_[i]) + { + return false; + } + } + return true; + } +private: + array_storage_type elements_; + + json_array& operator=(const json_array<Json>&) = delete; +}; + +// json_object + +template <class BidirectionalIt,class BinaryPredicate> +BidirectionalIt last_wins_unique_sequence(BidirectionalIt first, BidirectionalIt last, BinaryPredicate compare) +{ + + if (first == last) + { + return last; + } + + typedef typename BidirectionalIt::value_type value_type; + typedef typename BidirectionalIt::pointer pointer; + std::vector<value_type> dups; + { + std::vector<pointer> v(std::distance(first,last)); + auto p = v.begin(); + for (auto it = first; it != last; ++it) + { + *p++ = &(*it); + } + std::sort(v.begin(), v.end(), [&](pointer a, pointer b){return compare(*a,*b)<0;}); + auto it = v.begin(); + auto end = v.end(); + for (auto begin = it+1; begin != end; ++it, ++begin) + { + if (compare(*(*it),*(*begin)) == 0) + { + dups.push_back(*(*it)); + } + } + } + if (dups.size() == 0) + { + return last; + } + + auto it = last; + for (auto p = first; p != last && p != it; ) + { + bool no_dup = true; + if (dups.size() > 0) + { + for (auto q = dups.begin(); no_dup && q != dups.end();) + { + if (compare(*p,*q) == 0) + { + dups.erase(q); + no_dup = false; + } + else + { + ++q; + } + } + } + if (!no_dup) + { + --it; + for (auto r = p; r != it; ++r) + { + *r = std::move(*(r+1)); + } + } + else + { + ++p; + } + } + + return it; +} + +template <class KeyT, class ValueT> +class key_value_pair +{ +public: + typedef KeyT key_storage_type; + typedef typename KeyT::value_type char_type; + typedef typename KeyT::allocator_type allocator_type; + typedef typename ValueT::string_view_type string_view_type; + + key_value_pair() + { + } + + key_value_pair(const key_storage_type& name, const ValueT& val) + : key_(name), value_(val) + { + } + + template <class T> + key_value_pair(key_storage_type&& name, T&& val) + : key_(std::forward<key_storage_type>(name)), + value_(std::forward<T>(val)) + { + } + + template <class T> + key_value_pair(key_storage_type&& name, + T&& val, + const allocator_type& allocator) + : key_(std::forward<key_storage_type>(name)), value_(std::forward<T>(val), allocator) + { + } + + key_value_pair(const key_value_pair& member) + : key_(member.key_), value_(member.value_) + { + } + + key_value_pair(key_value_pair&& member) + : key_(std::move(member.key_)), value_(std::move(member.value_)) + { + } + + string_view_type key() const + { + return string_view_type(key_.data(),key_.size()); + } + + ValueT& value() + { + return value_; + } + + const ValueT& value() const + { + return value_; + } + + template <class T> + void value(T&& value) + { + value_ = std::forward<T>(value); + } + + void swap(key_value_pair& member) + { + key_.swap(member.key_); + value_.swap(member.value_); + } + + key_value_pair& operator=(const key_value_pair& member) + { + if (this != & member) + { + key_ = member.key_; + value_ = member.value_; + } + return *this; + } + + key_value_pair& operator=(key_value_pair&& member) + { + if (this != &member) + { + key_.swap(member.key_); + value_.swap(member.value_); + } + return *this; + } + + void shrink_to_fit() + { + key_.shrink_to_fit(); + value_.shrink_to_fit(); + } +#if !defined(JSONCONS_NO_DEPRECATED) + const key_storage_type& name() const + { + return key_; + } +#endif +private: + key_storage_type key_; + ValueT value_; +}; + +template <class KeyT,class Json> +class Json_object_ +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef typename Json::char_type char_type; + typedef typename Json::char_allocator_type char_allocator_type; + typedef KeyT key_storage_type; + typedef typename Json::string_view_type string_view_type; + typedef key_value_pair<KeyT,Json> value_type; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type> kvp_allocator_type; + typedef typename Json::object_storage_type object_storage_type; + + typedef typename object_storage_type::iterator iterator; + typedef typename object_storage_type::const_iterator const_iterator; + +protected: + allocator_type self_allocator_; + object_storage_type members_; +public: + Json_object_() + : self_allocator_(), members_() + { + } + Json_object_(const allocator_type& allocator) + : self_allocator_(allocator), + members_(kvp_allocator_type(allocator)) + { + } + + Json_object_(const Json_object_& val) + : self_allocator_(val.get_allocator()), members_(val.members_) + { + } + + Json_object_(Json_object_&& val) + : self_allocator_(val.get_allocator()), + members_(std::move(val.members_)) + { + } + + Json_object_(const Json_object_& val, const allocator_type& allocator) : + self_allocator_(allocator), + members_(val.members_,kvp_allocator_type(allocator)) + { + } + + Json_object_(Json_object_&& val,const allocator_type& allocator) : + self_allocator_(allocator), members_(std::move(val.members_),kvp_allocator_type(allocator)) + { + } + + void swap(Json_object_& val) + { + members_.swap(val.members_); + } + + allocator_type get_allocator() const + { + return this->self_allocator_; + } +}; + +// json_object + +template <class KeyT,class Json,bool PreserveOrder> +class json_object +{ +}; + +// Do not preserve order +template <class KeyT,class Json> +class json_object<KeyT,Json,false> final : public Json_object_<KeyT,Json> +{ +public: + using typename Json_object_<KeyT,Json>::allocator_type; + using typename Json_object_<KeyT,Json>::char_type; + using typename Json_object_<KeyT,Json>::char_allocator_type; + using typename Json_object_<KeyT,Json>::key_storage_type; + using typename Json_object_<KeyT,Json>::string_view_type; + using typename Json_object_<KeyT,Json>::value_type; + using typename Json_object_<KeyT,Json>::kvp_allocator_type; + using typename Json_object_<KeyT,Json>::object_storage_type; + using typename Json_object_<KeyT,Json>::iterator; + using typename Json_object_<KeyT,Json>::const_iterator; + using Json_object_<KeyT,Json>::get_allocator; + + json_object() + : Json_object_<KeyT,Json>() + { + } + json_object(const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + } + + json_object(const json_object& val) + : Json_object_<KeyT,Json>(val) + { + } + + json_object(json_object&& val) + : Json_object_<KeyT,Json>(std::forward<json_object>(val)) + { + } + + json_object(const json_object& val, const allocator_type& allocator) + : Json_object_<KeyT,Json>(val,allocator) + { + } + + json_object(json_object&& val,const allocator_type& allocator) + : Json_object_<KeyT,Json>(std::forward<json_object>(val),allocator) + { + } + + json_object(std::initializer_list<std::pair<string_view_type,Json>> init) + : Json_object_<KeyT,Json>() + { + this->members_.reserve(init.size()); + for (auto& item : init) + { + insert_or_assign(item.first, std::move(item.second)); + } + } + + json_object(std::initializer_list<std::pair<string_view_type,Json>> init, + const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + this->members_.reserve(init.size()); + for (auto& item : init) + { + insert_or_assign(item.first, std::move(item.second), allocator); + } + } + + void swap(json_object& val) + { + Json_object_<KeyT,Json>::swap(val); + } + + iterator begin() + { + return this->members_.begin(); + } + + iterator end() + { + return this->members_.end(); + } + + const_iterator begin() const + { + return this->members_.begin(); + } + + const_iterator end() const + { + return this->members_.end(); + } + + size_t size() const {return this->members_.size();} + + size_t capacity() const {return this->members_.capacity();} + + void clear() {this->members_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < this->members_.size(); ++i) + { + this->members_[i].shrink_to_fit(); + } + this->members_.shrink_to_fit(); + } + + void reserve(size_t n) {this->members_.reserve(n);} + + Json& at(size_t i) + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + const Json& at(size_t i) const + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + iterator find(const string_view_type& name) + { + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + auto result = (it != this->members_.end() && it->key() == name) ? it : this->members_.end(); + return result; + } + + const_iterator find(const string_view_type& name) const + { + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), + name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + auto result = (it != this->members_.end() && it->key() == name) ? it : this->members_.end(); + return result; + } + + void erase(const_iterator pos) + { + this->members_.erase(pos); + } + + void erase(const_iterator first, const_iterator last) + { + this->members_.erase(first,last); + } + + void erase(const string_view_type& name) + { + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it != this->members_.end() && it->key() == name) + { + this->members_.erase(it); + } + } + + template<class InputIt, class UnaryPredicate> + void insert(InputIt first, InputIt last, UnaryPredicate pred) + { + size_t count = std::distance(first,last); + this->members_.reserve(this->members_.size() + count); + for (auto s = first; s != last; ++s) + { + this->members_.emplace_back(pred(*s)); + } + std::stable_sort(this->members_.begin(),this->members_.end(), + [](const value_type& a, const value_type& b){return a.key().compare(b.key()) < 0;}); + auto it = std::unique(this->members_.rbegin(), this->members_.rend(), + [](const value_type& a, const value_type& b){ return !(a.key().compare(b.key()));}); + this->members_.erase(this->members_.begin(),it.base()); + } + + // merge + + void merge(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + else if (it->key() != pos->key()) + { + this->members_.emplace(pos,*it); + } + } + } + + void merge(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, it->key(),it->value()); + } + } + + void merge(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + iterator pos; + if (hint != this->members_.end() && hint->key() <= it->key()) + { + pos = std::lower_bound(hint,this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + hint = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() != pos->key()) + { + hint = this->members_.emplace(pos,*it); + } + } + } + + // merge_or_update + + void merge_or_update(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign(it->key(),it->value()); + } + } + + void merge_or_update(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + else + { + pos->value(it->value()); + } + } + } + + void merge_or_update(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, it->key(),it->value()); + } + } + + void merge_or_update(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + iterator pos; + if (hint != this->members_.end() && hint->key() <= it->key()) + { + pos = std::lower_bound(hint,this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + hint = this->members_.begin() + (this->members_.size() - 1); + } + else + { + pos->value(it->value()); + hint = pos; + } + } + } + + // insert_or_assign + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + inserted = true; + it = this->members_.begin() + this->members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value))); + inserted = false; // assigned + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + inserted = true; + it = this->members_.begin() + this->members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value), get_allocator())); + inserted = false; // assigned + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + inserted = true; + } + return std::make_pair(it,inserted); + } + + // try_emplace + + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class... Args> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + } + return it; + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + } + return it; + } + + // set_ + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,void>::type + set_(key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value)); + } + else if (string_view_type(it->key().data(),it->key().length()) == s) + { + it->value(Json(std::forward<T>(value))); + } + else + { + this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value)); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,void>::type + set_(key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + } + else if (string_view_type(it->key().data(), it->key().length()) == s) + { + it->value(Json(std::forward<T>(value),get_allocator() )); + } + else + { + this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value))); + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value),get_allocator())); + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + iterator it; + if (hint != this->members_.end() && hint->key() <= s) + { + it = std::lower_bound(hint,this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value)); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (string_view_type(it->key().data(), it->key().length()) == s) + { + it->value(Json(std::forward<T>(value))); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value)); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + iterator it; + if (hint != this->members_.end() && hint->key() <= s) + { + it = std::lower_bound(hint,this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (string_view_type(it->key().data(), it->key().length()) == s) + { + it->value(Json(std::forward<T>(value),get_allocator() )); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + } + return it; + } + + bool operator==(const json_object& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (auto it = this->members_.begin(); it != this->members_.end(); ++it) + { + + auto rhs_it = std::lower_bound(rhs.begin(), rhs.end(), *it, + [](const value_type& a, const value_type& b){return a.key().compare(b.key()) < 0;}); + if (rhs_it == rhs.end() || rhs_it->key() != it->key() || rhs_it->value() != it->value()) + { + return false; + } + } + return true; + } +private: + json_object& operator=(const json_object&) = delete; +}; + +// Preserve order +template <class KeyT,class Json> +class json_object<KeyT,Json,true> final : public Json_object_<KeyT,Json> +{ +public: + using typename Json_object_<KeyT,Json>::allocator_type; + using typename Json_object_<KeyT,Json>::char_type; + using typename Json_object_<KeyT,Json>::char_allocator_type; + using typename Json_object_<KeyT,Json>::key_storage_type; + using typename Json_object_<KeyT,Json>::string_view_type; + using typename Json_object_<KeyT,Json>::value_type; + using typename Json_object_<KeyT,Json>::kvp_allocator_type; + using typename Json_object_<KeyT,Json>::object_storage_type; + using typename Json_object_<KeyT,Json>::iterator; + using typename Json_object_<KeyT,Json>::const_iterator; + using Json_object_<KeyT,Json>::get_allocator; + + json_object() + : Json_object_<KeyT,Json>() + { + } + json_object(const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + } + + json_object(const json_object& val) + : Json_object_<KeyT,Json>(val) + { + } + + json_object(json_object&& val) + : Json_object_<KeyT,Json>(std::forward<json_object>(val)) + { + } + + json_object(const json_object& val, const allocator_type& allocator) + : Json_object_<KeyT,Json>(val,allocator) + { + } + + json_object(json_object&& val,const allocator_type& allocator) + : Json_object_<KeyT,Json>(std::forward<json_object>(val),allocator) + { + } + + json_object(std::initializer_list<typename Json::array> init) + : Json_object_<KeyT,Json>() + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + json_object(std::initializer_list<typename Json::array> init, + const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + void swap(json_object& val) + { + Json_object_<KeyT,Json>::swap(val); + } + + iterator begin() + { + return this->members_.begin(); + } + + iterator end() + { + return this->members_.end(); + } + + const_iterator begin() const + { + return this->members_.begin(); + } + + const_iterator end() const + { + return this->members_.end(); + } + + size_t size() const {return this->members_.size();} + + size_t capacity() const {return this->members_.capacity();} + + void clear() {this->members_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < this->members_.size(); ++i) + { + this->members_[i].shrink_to_fit(); + } + this->members_.shrink_to_fit(); + } + + void reserve(size_t n) {this->members_.reserve(n);} + + Json& at(size_t i) + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + const Json& at(size_t i) const + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + iterator find(const string_view_type& name) + { + return std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& kv){return kv.key() == name;}); + } + + const_iterator find(const string_view_type& name) const + { + return std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& kv){return kv.key() == name;}); + } + + void erase(const_iterator first, const_iterator last) + { + this->members_.erase(first,last); + } + + void erase(const string_view_type& name) + { + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& kv){return kv.key() == name;}); + if (it != this->members_.end()) + { + this->members_.erase(it); + } + } + + template<class InputIt, class UnaryPredicate> + void insert(InputIt first, InputIt last, UnaryPredicate pred) + { + size_t count = std::distance(first,last); + this->members_.reserve(this->members_.size() + count); + for (auto s = first; s != last; ++s) + { + this->members_.emplace_back(pred(*s)); + } + auto it = last_wins_unique_sequence(this->members_.begin(), this->members_.end(), + [](const value_type& a, const value_type& b){ return a.key().compare(b.key());}); + this->members_.erase(it,this->members_.end()); + } + + // insert_or_assign + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& a){return a.key() == name;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else + { + it->value(Json(std::forward<T>(value))); + inserted = false; // assigned + } + return std::make_pair(it,inserted); + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& a){return a.key() == name;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(),get_allocator()), + std::forward<T>(value),get_allocator()); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else + { + it->value(Json(std::forward<T>(value),get_allocator())); + inserted = false; // assigned + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class T> + typename std::enable_if<is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + iterator it; + if (hint == this->members_.end()) + { + auto result = insert_or_assign(key, std::forward<T>(value)); + it = result.first; + } + else + { + it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end()), + std::forward<T>(value)); + it = this->members_.begin() + this->members_.size() - 1; + } + else + { + it->value(Json(std::forward<T>(value))); + } + } + return it; + } + + template <class A=allocator_type, class T> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + iterator it; + if (hint == this->members_.end()) + { + auto result = insert_or_assign(key, std::forward<T>(value)); + it = result.first; + } + else + { + it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end(),get_allocator()), + std::forward<T>(value),get_allocator()); + it = this->members_.begin() + this->members_.size() - 1; + } + else + { + it->value(Json(std::forward<T>(value),get_allocator())); + } + } + return it; + } + + // merge + + void merge(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + } + } + + void merge(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, it->key(),it->value()); + } + } + + void merge(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + hint = this->members_.emplace(hint,*it); + } + } + } + + // merge_or_update + + void merge_or_update(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign(it->key(),it->value()); + } + } + + void merge_or_update(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + else + { + pos->value(it->value()); + } + } + } + + void merge_or_update(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, it->key(),it->value()); + } + } + + void merge_or_update(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + hint = this->members_.emplace(hint,*it); + } + else + { + pos->value(it->value()); + hint = pos; + } + } + } + + // try_emplace + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& key, Args&&... args) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + + } + else + { + inserted = false; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class... Args> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& key, Args&&... args) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + + } + else + { + inserted = false; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + if (hint == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else + { + it = this->members_.emplace(hint, + key_storage_type(key.begin(),key.end()), + std::forward<Args>(args)...); + } + } + return it; + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + if (hint == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else + { + it = this->members_.emplace(hint, + key_storage_type(key.begin(),key.end(), get_allocator()), + std::forward<Args>(args)...); + } + } + return it; + } + + // set_ + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,void>::type + set_(key_storage_type&& key, T&& value) + { + string_view_type s(key.data(),key.size()); + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [s](const value_type& a){return a.key().compare(s) == 0;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value)); + } + else + { + it->value(Json(std::forward<T>(value))); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,void>::type + set_(key_storage_type&& key, T&& value) + { + string_view_type s(key.data(),key.size()); + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [s](const value_type& a){return a.key().compare(s) == 0;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value),get_allocator()); + } + else + { + it->value(Json(std::forward<T>(value),get_allocator())); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& key, T&& value) + { + iterator it = hint; + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value)); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == key) + { + it->value(Json(std::forward<T>(value))); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(key), + std::forward<T>(value)); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& key, T&& value) + { + iterator it = hint; + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value), get_allocator()); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == key) + { + it->value(Json(std::forward<T>(value), get_allocator())); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(key), + std::forward<T>(value), get_allocator()); + } + return it; + } + + bool operator==(const json_object& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (auto it = this->members_.begin(); it != this->members_.end(); ++it) + { + auto rhs_it = std::find_if(rhs.begin(),rhs.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (rhs_it == rhs.end() || rhs_it->key() != it->key() || rhs_it->value() != it->value()) + { + return false; + } + } + return true; + } +private: + json_object& operator=(const json_object&) = delete; +}; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_type_traits.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_type_traits.hpp new file mode 100644 index 00000000..1c76c4c0 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_type_traits.hpp @@ -0,0 +1,966 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_TYPE_TRAITS_HPP +#define JSONCONS_JSON_TYPE_TRAITS_HPP + +#include <array> +#include <string> +#include <vector> +#include <valarray> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <utility> +#include <algorithm> +#include <fstream> +#include <limits> +#include <type_traits> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/detail/type_traits_helper.hpp> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons { + +// null_type + +struct null_type +{ +}; + +// json_type_traits + +template <class Json, class T, class Enable=void> +struct json_type_traits +{ + static const bool is_compatible = false; + + static bool is(const Json&) + { + return false; + } +}; + +namespace detail { + +// is_incompatible +template<class Json, class T, class Enable = void> +struct is_incompatible : std::false_type {}; + + +// is_incompatible +template<class Json, class T> +struct is_incompatible<Json,T, + typename std::enable_if<!std::integral_constant<bool, json_type_traits<Json, T>::is_compatible>::value>::type +> : std::true_type {}; + +// is_compatible_string_type +template<class Json, class T, class Enable=void> +struct is_compatible_string_type : std::false_type {}; + +template<class Json, class T> +struct is_compatible_string_type<Json,T, + typename std::enable_if<!std::is_same<T,typename Json::array>::value && + detail::is_string_like<T>::value && + !is_incompatible<Json,typename std::iterator_traits<typename T::iterator>::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_array_type +template<class Json, class T, class Enable=void> +struct is_compatible_array_type : std::false_type {}; + +template<class Json, class T> +struct is_compatible_array_type<Json,T, + typename std::enable_if<!std::is_same<T,typename Json::array>::value && + detail::is_vector_like<T>::value && + !is_incompatible<Json,typename std::iterator_traits<typename T::iterator>::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_object_type +template<class Json, class T, class Enable=void> +struct is_compatible_object_type : std::false_type {}; + +template<class Json, class T> +struct is_compatible_object_type<Json,T, + typename std::enable_if< + !is_incompatible<Json,typename T::mapped_type>::value +>::type> : std::true_type {}; + +// is_std_array +template<class T> +struct is_std_array : std::false_type {}; + +template<class E, size_t N> +struct is_std_array<std::array<E, N>> : std::true_type {}; + +template <class Json, class T> +class json_array_input_iterator +{ +public: + typedef typename Json::const_array_iterator iterator_base; + typedef typename std::iterator_traits<iterator_base>::value_type value_type; + typedef typename std::iterator_traits<iterator_base>::difference_type difference_type; + typedef typename std::iterator_traits<iterator_base>::pointer pointer; + typedef T reference; + typedef std::input_iterator_tag iterator_category; + + json_array_input_iterator() + { + } + + json_array_input_iterator(iterator_base it) + : it_(it) + { + } + + json_array_input_iterator& operator=(json_array_input_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_array_input_iterator& operator++() + { + ++it_; + return *this; + } + + json_array_input_iterator operator++(int) // postfix increment + { + json_array_input_iterator temp(*this); + ++it_; + return temp; + } + + json_array_input_iterator& operator--() + { + --it_; + return *this; + } + + json_array_input_iterator operator--(int) + { + json_array_input_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return json_type_traits<Json,T>::as(*it_); + } + + friend bool operator==(const json_array_input_iterator& it1, const json_array_input_iterator& it2) + { + return it1.it_ == it2.it_; + } + friend bool operator!=(const json_array_input_iterator& it1, const json_array_input_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_array_input_iterator& lhs, json_array_input_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + +private: + iterator_base it_; +}; + +template <class Json, class T> +class json_object_input_iterator +{ +public: + typedef typename Json::const_object_iterator iterator_base; + typedef typename std::iterator_traits<iterator_base>::value_type value_type; + typedef typename std::iterator_traits<iterator_base>::difference_type difference_type; + typedef typename std::iterator_traits<iterator_base>::pointer pointer; + typedef T reference; + typedef std::input_iterator_tag iterator_category; + typedef typename T::first_type key_type; + typedef typename T::second_type mapped_type; + + json_object_input_iterator() + { + } + + json_object_input_iterator(iterator_base it) + : it_(it) + { + } + + json_object_input_iterator& operator=(json_object_input_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_object_input_iterator& operator++() + { + ++it_; + return *this; + } + + json_object_input_iterator operator++(int) // postfix increment + { + json_object_input_iterator temp(*this); + ++it_; + return temp; + } + + json_object_input_iterator& operator--() + { + --it_; + return *this; + } + + json_object_input_iterator operator--(int) + { + json_object_input_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return T(key_type(it_->key()),json_type_traits<Json,mapped_type>::as(it_->value())); + } + + friend bool operator==(const json_object_input_iterator& it1, const json_object_input_iterator& it2) + { + return it1.it_ == it2.it_; + } + friend bool operator!=(const json_object_input_iterator& it1, const json_object_input_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_object_input_iterator& lhs, json_object_input_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + +private: + iterator_base it_; +}; + +} + +template<class Json> +struct json_type_traits<Json, typename type_wrapper<typename Json::char_type>::const_pointer_type> +{ + typedef typename Json::char_type char_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_string(); + } + static const char_type* as(const Json& j) + { + return j.as_cstring(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, typename type_wrapper<typename Json::char_type>::pointer_type> +{ + typedef typename Json::char_type char_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_string(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +// integral + +template<class Json, class T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_integer_like<T>::value +>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + if (j.is_integer()) + { + return j.as_integer() >= (std::numeric_limits<T>::min)() && j.as_integer() <= (std::numeric_limits<T>::max)(); + } + else if (j.is_uinteger()) + { + return j.as_uinteger() <= static_cast<uint64_t>((std::numeric_limits<T>::max)()); + } + else + { + return false; + } + } + static T as(const Json& j) + { + return static_cast<T>(j.as_integer()); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json::from_integer(std::forward<Args>(args)...); + } +}; + +template<class Json, class T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_uinteger_like<T>::value +>::type > +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + if (j.is_integer()) + { + return j.as_integer() >= 0 && static_cast<uint64_t>(j.as_integer()) <= (std::numeric_limits<T>::max)(); + } + else if (j.is_uinteger()) + { + return j.as_uinteger() <= (std::numeric_limits<T>::max)(); + } + else + { + return false; + } + } + static T as(const Json& j) + { + return static_cast<T>(j.as_uinteger()); + } + + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json::from_uinteger(std::forward<Args>(args)...); + } +}; + +template<class Json,class T> +struct json_type_traits<Json, T, + typename std::enable_if<std::is_floating_point<T>::value +>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_double(); + } + static T as(const Json& j) + { + return static_cast<T>(j.as_double()); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json::from_floating_point(std::forward<Args>(args)...); + } +}; + +template<class Json> +struct json_type_traits<Json, typename Json::object> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_object(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, typename Json::array> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_array(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, Json> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json&) JSONCONS_NOEXCEPT + { + return true; + } + static Json as(Json j) + { + return j; + } + static Json to_json(const Json& val) + { + return val; + } + static Json to_json(const Json& val, allocator_type) + { + return val; + } +}; + +template<class Json> +struct json_type_traits<Json, jsoncons::null_type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_null(); + } + static typename jsoncons::null_type as(const Json& j) + { + JSONCONS_ASSERT(j.is_null()); + return jsoncons::null_type(); + } + static Json to_json(jsoncons::null_type) + { + return Json::null(); + } + static Json to_json(jsoncons::null_type, allocator_type) + { + return Json::null(); + } +}; + +template<class Json> +struct json_type_traits<Json, bool> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json,class T> +struct json_type_traits<Json, T, typename std::enable_if<std::is_same<T, + std::conditional<!std::is_same<bool,std::vector<bool>::const_reference>::value, + std::vector<bool>::const_reference, + void>::type>::value>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, std::vector<bool>::reference> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json, typename T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_compatible_array_type<Json,T>::value && + !detail::is_std_array<T>::value>::type> +{ + typedef typename std::iterator_traits<typename T::iterator>::value_type element_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is<element_type>()) + { + result = false; + break; + } + } + } + return result; + } + + template <class Ty = element_type> + static typename std::enable_if<!(std::is_integral<Ty>::value && !std::is_same<Ty,bool>::value),T>::type + as(const Json& j) + { + if (j.is_array()) + { + T v(detail::json_array_input_iterator<Json, element_type>(j.array_range().begin()), + detail::json_array_input_iterator<Json, element_type>(j.array_range().end())); + return v; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempt to cast json non-array to array")); + } + } + + template <class Ty = element_type> + static typename std::enable_if<std::is_integral<Ty>::value && !std::is_same<Ty,bool>::value,T>::type + as(const Json& j) + { + if (j.is_array()) + { + T v(detail::json_array_input_iterator<Json, element_type>(j.array_range().begin()), + detail::json_array_input_iterator<Json, element_type>(j.array_range().end())); + return v; + } + else if (j.is_byte_string()) + { + T v(j.as_byte_string_view().begin(),j.as_byte_string_view().end()); + return v; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempt to cast json non-array to array")); + } + } + + static Json to_json(const T& val) + { + Json j = typename Json::array(); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first, last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } +}; + +template<class Json, typename T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_compatible_string_type<Json,T>::value>::type> +{ + typedef typename std::iterator_traits<typename T::iterator>::value_type element_type; + typedef typename Json::allocator_type allocator_type; + typedef typename T::allocator_type string_allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_string(); + } + + static T as(const Json& j) + { + if (j.is_string()) + { + return j.as_string(string_allocator_type()); + } + else + { + T s; + j.dump(s); + return s; + } + } + + static Json to_json(const T& val) + { + return Json(typename Json::variant(val.data(), val.size())); + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + return Json(typename Json::variant(val.data(),val.size(),allocator)); + } +}; + +template<class Json, typename T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_compatible_object_type<Json,T>::value>::type +> +{ + typedef typename T::mapped_type mapped_type; + typedef typename T::value_type value_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_object(); + for (auto member : j.object_range()) + { + if (!member.value().template is<mapped_type>()) + { + result = false; + } + } + return result; + } + + static T as(const Json& j) + { + T v(detail::json_object_input_iterator<Json,value_type>(j.object_range().begin()), + detail::json_object_input_iterator<Json,value_type>(j.object_range().end())); + return v; + } + + static Json to_json(const T& val) + { + Json j; + j.reserve(val.size()); + for (auto p: val) + { + j.set(p.first, p.second); + } + return j; + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + Json j(allocator); + j.reserve(val.size()); + for (auto p: val) + { + j.set(p.first, p.second); + } + return j; + } +}; + +template<class Json, class E, size_t N> +struct json_type_traits<Json, std::array<E, N>> +{ + typedef typename Json::allocator_type allocator_type; + + typedef E element_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_array() && j.size() == N; + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is<element_type>()) + { + result = false; + break; + } + } + } + return result; + } + + static std::array<E, N> as(const Json& j) + { + std::array<E, N> buff; + JSONCONS_ASSERT(j.size() == N); + for (size_t i = 0; i < N; i++) + { + buff[i] = j[i].template as<E>(); + } + return buff; + } + + static Json to_json(const std::array<E, N>& val) + { + Json j = typename Json::array(); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const std::array<E, N>& val, + const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } +}; + +namespace detail +{ + +template<size_t Pos, class Json, class Tuple> +struct json_tuple_helper +{ + using element_type = typename std::tuple_element<Pos - 1, Tuple>::type; + using next = json_tuple_helper<Pos - 1, Json, Tuple>; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + if(j[Pos - 1].template is<element_type>()) + { + return next::is(j); + } + else + { + return false; + } + } + + static void as(Tuple& tuple, const Json& j) + { + std::get<Pos - 1>(tuple) = j[Pos - 1].template as<element_type>(); + next::as(tuple, j); + } + + static void to_json(const Tuple& tuple, std::array<Json, std::tuple_size<Tuple>::value>& jsons) + { + jsons[Pos - 1] = json_type_traits<Json, element_type>::to_json(std::get<Pos-1>(tuple)); + next::to_json(tuple, jsons); + } +}; + +template<class Json, class Tuple> +struct json_tuple_helper<0, Json, Tuple> +{ + static bool is(const Json&) JSONCONS_NOEXCEPT + { + return true; + } + + static void as(Tuple&, const Json&) + { + } + + static void to_json(const Tuple&, std::array<Json, std::tuple_size<Tuple>::value>&) + { + } +}; + +} + +template<class Json, typename... E> +struct json_type_traits<Json, std::tuple<E...>> +{ +private: + using helper = detail::json_tuple_helper<sizeof...(E), Json, std::tuple<E...>>; + +public: + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return helper::is(j); + } + + static std::tuple<E...> as(const Json& j) + { + std::tuple<E...> buff; + helper::as(buff, j); + return buff; + } + + static Json to_json(const std::tuple<E...>& val) + { + std::array<Json, sizeof...(E)> buf; + helper::to_json(val, buf); + return Json(typename Json::array(buf.begin(), buf.end())); + } +}; + +template<class Json, class T1, class T2> +struct json_type_traits<Json, std::pair<T1,T2>> +{ +public: + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_array() && j.size() == 2; + } + + static std::pair<T1,T2> as(const Json& j) + { + return std::make_pair<T1,T2>(j[0]. template as<T1>(),j[1]. template as<T2>()); + } + + static Json to_json(const std::pair<T1,T2>& val) + { + return typename Json::array{val.first,val.second}; + } +}; + +template<class Json, class Allocator> +struct json_type_traits<Json, basic_byte_string<Allocator>> +{ +public: + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_byte_string(); + } + + static basic_byte_string<Allocator> as(const Json& j) + { + return basic_byte_string<Allocator>(j.as_byte_string_view()); + } + + static Json to_json(const basic_byte_string<Allocator>& val) + { + return Json(val.data(),val.length()); + } +}; + +// std::valarray + +template<class Json, class T> +struct json_type_traits<Json, std::valarray<T>> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is<T>()) + { + result = false; + break; + } + } + } + return result; + } + + static std::valarray<T> as(const Json& j) + { + if (j.is_array()) + { + std::valarray<T> v(j.size()); + for (size_t i = 0; i < j.size(); ++i) + { + v[i] = j[i].template as<T>(); + } + return v; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempt to cast json non-array to array")); + } + } + + static Json to_json(const std::valarray<T>& val) + { + Json j = typename Json::array(); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const std::valarray<T>& val, const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } +}; + +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/jsoncons_config.hpp b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_config.hpp new file mode 100644 index 00000000..59c6b650 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_config.hpp @@ -0,0 +1,106 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONS_CONFIG_HPP +#define JSONCONS_JSONCONS_CONFIG_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <exception> +#include <limits> // std::numeric_limits + +// Uncomment the following line to suppress deprecated names (recommended for new code) +//#define JSONCONS_NO_DEPRECATED + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +#if defined(__GNUC__) || defined(__clang__) +#define JSONCONS_LIKELY(x) __builtin_expect(!!(x), 1) +#define JSONCONS_UNLIKELY(x) __builtin_expect(!!(x), 0) +#define JSONCONS_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +#define JSONCONS_LIKELY(x) x +#define JSONCONS_UNLIKELY(x) x +#define JSONCONS_UNREACHABLE() __assume(0) +#else +#define JSONCONS_LIKELY(x) x +#define JSONCONS_UNLIKELY(x) x +#define JSONCONS_UNREACHABLE() do {} while (0) +#endif + +namespace jsoncons +{ + +#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 +#else +#define JSONCONS_NO_CONSTEXPR +#endif + +#define JSONCONS_NO_TO_CHARS + +#if defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define JSONCONS_HAS_USER_DEFINED_LITERALS +#endif +#else +#define JSONCONS_HAS_USER_DEFINED_LITERALS +#endif + +//#define JSONCONS_HAS_STRING_VIEW + +#if defined(ANDROID) || defined(__ANDROID__) +#define JSONCONS_HAS_STRTOLD_L +#define JSONCONS_NO_LOCALECONV +#endif + +#if defined (__clang__) +#if defined(_GLIBCXX_USE_NOEXCEPT) +#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#else +#define JSONCONS_NOEXCEPT noexcept +#endif +#elif defined(__GNUC__) +#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define JSONCONS_NOEXCEPT noexcept +#else +#define JSONCONS_NOEXCEPT +#endif +#else +#define JSONCONS_NOEXCEPT +#endif + +#if defined(_MSC_VER) +#define JSONCONS_HAS_MSC__STRTOD_L +#define JSONCONS_HAS__ECVT_S +#define JSONCONS_HAS_FOPEN_S +#if _MSC_VER >= 1900 +#define JSONCONS_ALIGNOF alignof +#else +#define JSONCONS_ALIGNOF __alignof +#endif +#else +#define JSONCONS_ALIGNOF alignof +#endif + +#define JSONCONS_DEFINE_LITERAL( name, lit ) \ +template< class Ch > Ch const* name(); \ +template<> inline char const * name<char>() { return lit; } \ +template<> inline wchar_t const* name<wchar_t>() { return L ## lit; } + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/jsoncons_utilities.hpp b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_utilities.hpp new file mode 100644 index 00000000..28a9eb71 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_utilities.hpp @@ -0,0 +1,954 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONSUTILITIES_HPP +#define JSONCONS_JSONCONSUTILITIES_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <memory> +#include <iterator> +#include <exception> +#include <array> +#include <initializer_list> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/json_exception.hpp> +#if !defined(JSONCONS_NO_TO_CHARS) +#include <charconv> +#endif +#include <jsoncons/detail/obufferedstream.hpp> + +namespace jsoncons +{ + +#if !defined(JSONCONS_HAS_STRING_VIEW) +template <class CharT, class Traits = std::char_traits<CharT>> +class Basic_string_view_ +{ +private: + const CharT* data_; + size_t length_; +public: + typedef CharT value_type; + typedef const CharT& const_reference; + typedef Traits traits_type; + typedef std::size_t size_type; + static const size_type npos = size_type(-1); + typedef const CharT* const_iterator; + typedef const CharT* iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + Basic_string_view_() + : data_(nullptr), length_(0) + { + } + Basic_string_view_(const CharT* data, size_t length) + : data_(data), length_(length) + { + } + Basic_string_view_(const CharT* data) + : data_(data), length_(Traits::length(data)) + { + } + Basic_string_view_(const Basic_string_view_& other) = default; + + template <class Allocator> + Basic_string_view_(const std::basic_string<CharT,Traits,Allocator>& s) + : data_(s.data()), length_(s.length()) + { + } + + template <class Allocator> + explicit operator std::basic_string<CharT,Traits,Allocator>() const + { + return std::basic_string<CharT,Traits>(data_,length_); + } + + // iterator support + const_iterator begin() const JSONCONS_NOEXCEPT + { + return data_; + } + const_iterator end() const JSONCONS_NOEXCEPT + { + return data_ + length_; + } + const_iterator cbegin() const JSONCONS_NOEXCEPT + { + return data_; + } + const_iterator cend() const JSONCONS_NOEXCEPT + { + return data_ + length_; + } + const_reverse_iterator rbegin() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crbegin() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crend() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + + // capacity + + size_t size() const + { + return length_; + } + + size_t length() const + { + return length_; + } + size_type max_size() const JSONCONS_NOEXCEPT + { + return length_; + } + bool empty() const JSONCONS_NOEXCEPT + { + return length_ == 0; + } + + // element access + + const_reference operator[](size_type pos) const + { + return data_[pos]; + } + + const_reference at(size_t pos) const + { + if (pos >= length_) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("pos exceeds length")); + } + return data_[pos]; + } + + const_reference front() const + { + return data_[0]; + } + const_reference back() const + { + return data_[length_-1]; + } + + const CharT* data() const + { + return data_; + } + + // string operations + + Basic_string_view_ substr(size_type pos, size_type n=npos) const + { + if (pos > length_) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("pos exceeds size")); + } + if (n == npos || pos + n > length_) + { + n = length_ - pos; + } + return Basic_string_view_(data_ + pos, n); + } + + int compare(Basic_string_view_ s) const + { + const int rc = Traits::compare(data_, s.data_, (std::min)(length_, s.length_)); + return rc != 0 ? rc : (length_ == s.length_ ? 0 : length_ < s.length_ ? -1 : 1); + } + + int compare(const CharT* data) const + { + const size_t length = Traits::length(data); + const int rc = Traits::compare(data_, data, (std::min)(length_, length)); + return rc != 0 ? rc : (length_ == length? 0 : length_ < length? -1 : 1); + } + + template <class Allocator> + int compare(const std::basic_string<CharT,Traits,Allocator>& s) const + { + const int rc = Traits::compare(data_, s.data(), (std::min)(length_, s.length())); + return rc != 0 ? rc : (length_ == s.length() ? 0 : length_ < s.length() ? -1 : 1); + } + + size_type find(Basic_string_view_ s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + if (pos > length_) + { + return npos; + } + if (s.length_ == 0) + { + return pos; + } + const_iterator it = std::search(cbegin() + pos, cend(), + s.cbegin(), s.cend(), Traits::eq); + return it == cend() ? npos : std::distance(cbegin(), it); + } + size_type find(CharT ch, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find(Basic_string_view_(&ch, 1), pos); + } + size_type find(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find(Basic_string_view_(s, n), pos); + } + size_type find(const CharT* s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find(Basic_string_view_(s), pos); + } + + size_type rfind(Basic_string_view_ s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + if (length_ < s.length_) + { + return npos; + } + if (pos > length_ - s.length_) + { + pos = length_ - s.length_; + } + if (s.length_ == 0) + { + return pos; + } + for (const CharT* p = data_ + pos; true; --p) + { + if (Traits::compare(p, s.data_, s.length_) == 0) + { + return p - data_; + } + if (p == data_) + { + return npos; + } + }; + } + size_type rfind(CharT ch, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return rfind(Basic_string_view_(&ch, 1), pos); + } + size_type rfind(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return rfind(Basic_string_view_(s, n), pos); + } + size_type rfind(const CharT* s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return rfind(Basic_string_view_(s), pos); + } + + size_type find_first_of(Basic_string_view_ s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + if (pos >= length_ || s.length_ == 0) + { + return npos; + } + const_iterator it = std::find_first_of + (cbegin() + pos, cend(), s.cbegin(), s.cend(), Traits::eq); + return it == cend() ? npos : std::distance (cbegin(), it); + } + size_type find_first_of(CharT ch, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_first_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_first_of(Basic_string_view_(s, n), pos); + } + size_type find_first_of(const CharT* s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_of(Basic_string_view_(s), pos); + } + + size_type find_last_of(Basic_string_view_ s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + if (s.length_ == 0) + { + return npos; + } + if (pos >= length_) + { + pos = 0; + } + else + { + pos = length_ - (pos+1); + } + const_reverse_iterator it = std::find_first_of + (crbegin() + pos, crend(), s.cbegin(), s.cend(), Traits::eq); + return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it)); + } + size_type find_last_of(CharT ch, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_last_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_last_of(Basic_string_view_(s, n), pos); + } + size_type find_last_of(const CharT* s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_of(Basic_string_view_(s), pos); + } + + size_type find_first_not_of(Basic_string_view_ s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + if (pos >= length_) + return npos; + if (s.length_ == 0) + return pos; + + const_iterator it = cend(); + for (auto p = cbegin()+pos; p != cend(); ++p) + { + if (Traits::find(s.data_, s.length_, *p) == 0) + { + it = p; + break; + } + } + return it == cend() ? npos : std::distance (cbegin(), it); + } + size_type find_first_not_of(CharT ch, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_not_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_first_not_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_first_not_of(Basic_string_view_(s, n), pos); + } + size_type find_first_not_of(const CharT* s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_not_of(Basic_string_view_(s), pos); + } + + size_type find_last_not_of(Basic_string_view_ s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + if (pos >= length_) + { + pos = length_ - 1; + } + if (s.length_ == 0) + { + return pos; + } + pos = length_ - (pos+1); + + const_iterator it = crend(); + for (auto p = crbegin()+pos; p != crend(); ++p) + { + if (Traits::find(s.data_, s.length_, *p) == 0) + { + it = p; + break; + } + } + return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it)); + } + size_type find_last_not_of(CharT ch, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_not_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_last_not_of(Basic_string_view_(s, n), pos); + } + size_type find_last_not_of(const CharT* s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_not_of(Basic_string_view_(s), pos); + } + + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const Basic_string_view_& sv) + { + os.write(sv.data_,sv.length_); + return os; + } +}; + +// == +template<class CharT,class Traits> +bool operator==(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) == 0; +} +template<class CharT,class Traits,class Allocator> +bool operator==(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) == 0; +} +template<class CharT,class Traits,class Allocator> +bool operator==(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) == 0; +} +template<class CharT,class Traits> +bool operator==(const Basic_string_view_<CharT,Traits>& lhs, + const CharT* rhs) +{ + return lhs.compare(rhs) == 0; +} +template<class CharT,class Traits> +bool operator==(const CharT* lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) == 0; +} + +// != +template<class CharT,class Traits> +bool operator!=(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) != 0; +} +template<class CharT,class Traits,class Allocator> +bool operator!=(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) != 0; +} +template<class CharT,class Traits,class Allocator> +bool operator!=(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) != 0; +} +template<class CharT,class Traits> +bool operator!=(const Basic_string_view_<CharT,Traits>& lhs, + const CharT* rhs) +{ + return lhs.compare(rhs) != 0; +} +template<class CharT,class Traits> +bool operator!=(const CharT* lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) != 0; +} + +// <= +template<class CharT,class Traits> +bool operator<=(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<=(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<=(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) >= 0; +} + +// < +template<class CharT,class Traits> +bool operator<(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) < 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) < 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) > 0; +} + +// >= +template<class CharT,class Traits> +bool operator>=(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>=(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>=(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) <= 0; +} + +// > +template<class CharT,class Traits> +bool operator>(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) > 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) > 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) < 0; +} +#endif + +#if !defined(JSONCONS_HAS_STRING_VIEW) +template <class CharT, class Traits = std::char_traits<CharT>> +using basic_string_view_ext = Basic_string_view_<CharT, Traits>; +#else +#include <string_view> +template <class CharT, class Traits = std::char_traits<CharT>> +using basic_string_view_ext = std::basic_string_view<CharT, Traits>; +#endif + +#if !defined(JSONCONS_NO_TO_CHARS) +using chars_format = std::chars_format; +#else +enum class chars_format : uint8_t {fixed=1,scientific=2,hex=4,general=fixed|scientific}; +#endif + +// number_format + +class number_format +{ + chars_format format_; + uint8_t precision_; + uint8_t decimal_places_; +public: + number_format() + : format_(chars_format::general), precision_(0), decimal_places_(0) + { + } + + number_format(uint8_t precision, uint8_t decimal_places) + : format_(chars_format::general), precision_(precision), decimal_places_(decimal_places) + { + } + + number_format(chars_format format, uint8_t precision, uint8_t decimal_places) + : format_(format), precision_(precision), decimal_places_(decimal_places) + { + } + + number_format(chars_format format) + : format_(format), precision_(0), decimal_places_(0) + { + } + + number_format(const number_format&) = default; + number_format(number_format&&) = default; + number_format& operator=(const number_format& e) = default; + number_format& operator=(number_format&& e) = default; + + uint8_t precision() const + { + return precision_; + } + + uint8_t decimal_places() const + { + return decimal_places_; + } + + chars_format floating_point_format() const + { + return format_; + } +}; + +// byte_string_view +class byte_string_view +{ + const uint8_t* data_; + size_t length_; +public: + typedef const uint8_t* const_iterator; + typedef const uint8_t* iterator; + typedef std::size_t size_type; + + byte_string_view(const uint8_t* data, size_t length) + : data_(data), length_(length) + { + } + + const uint8_t* data() const + { + return data_; + } + + size_t length() const + { + return length_; + } + + size_t size() const + { + return length_; + } + + // iterator support + const_iterator begin() const JSONCONS_NOEXCEPT + { + return data_; + } + const_iterator end() const JSONCONS_NOEXCEPT + { + return data_ + length_; + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + friend bool operator==(const byte_string_view& lhs, const byte_string_view& rhs) + { + if (lhs.length() != rhs.length()) + { + return false; + } + for (size_t i = 0; i < lhs.length(); ++i) + { + if (lhs[i] != rhs[i]) + { + return false; + } + } + return true; + } + + friend bool operator!=(const byte_string_view& lhs, const byte_string_view& rhs) + { + return !(lhs == rhs); + } + + template <class CharT> + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const byte_string_view& o) + { + std::basic_ostringstream<CharT> ss; + ss.flags(std::ios::hex | std::ios::showbase); + for (auto b : o) + { + ss << (int)b; + } + os << ss.str(); + return os; + } +}; + +// basic_byte_string +template <class Allocator = std::allocator<uint8_t>> +class basic_byte_string +{ + std::vector<uint8_t,Allocator> data_; +public: + typedef typename std::vector<uint8_t,Allocator>::const_iterator const_iterator; + typedef typename std::vector<uint8_t,Allocator>::const_iterator iterator; + typedef std::size_t size_type; + + basic_byte_string() = default; + + explicit basic_byte_string(const Allocator& alloc) + : data_(alloc) + { + } + + basic_byte_string(std::initializer_list<uint8_t> init) + : data_(std::move(init)) + { + } + + basic_byte_string(std::initializer_list<uint8_t> init, const Allocator& alloc) + : data_(std::move(init), alloc) + { + } + + explicit basic_byte_string(const byte_string_view& v) + : data_(v.begin(),v.end()) + { + } + + basic_byte_string(const byte_string_view& v, const Allocator& alloc) + : data_(v.begin(),v.end(),alloc) + { + } + + basic_byte_string(const char* s) + { + while (*s) + { + data_.push_back(*s++); + } + } + + basic_byte_string(const uint8_t* data, size_t length) + { + data_.insert(data,data+length); + } + + basic_byte_string(const basic_byte_string& s) = default; + + basic_byte_string(basic_byte_string&& s) = default; + + basic_byte_string& operator=(const basic_byte_string& s) = default; + + basic_byte_string& operator=(basic_byte_string&& s) = default; + + operator byte_string_view() const JSONCONS_NOEXCEPT + { + return byte_string_view(data(),length()); + } + + void push_back(uint8_t b) + { + data_.push_back(b); + } + + void assign(const uint8_t* s, size_t count) + { + data_.clear(); + data_.insert(s, s+count); + } + + void append(const uint8_t* s, size_t count) + { + data_.insert(s, s+count); + } + + void clear() + { + data_.clear(); + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + // iterator support + const_iterator begin() const JSONCONS_NOEXCEPT + { + return data_.begin(); + } + const_iterator end() const JSONCONS_NOEXCEPT + { + return data_.end(); + } + + const uint8_t* data() const + { + return data_.data(); + } + + size_t size() const + { + return data_.size(); + } + + size_t length() const + { + return data_.size(); + } + + friend bool operator==(const basic_byte_string& lhs, const basic_byte_string& rhs) + { + return byte_string_view(lhs) == byte_string_view(rhs); + } + + friend bool operator!=(const basic_byte_string& lhs, const basic_byte_string& rhs) + { + return byte_string_view(lhs) != byte_string_view(rhs); + } + + template <class CharT> + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const basic_byte_string& o) + { + os << byte_string_view(o); + return os; + } +}; + +typedef basic_byte_string<std::allocator<uint8_t>> byte_string; + +static const std::string base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" + "="; +static const std::string base64url_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_" + "\0"; + +inline +static bool is_base64(uint8_t c) +{ + return isalnum(c) || c == '+' || c == '/'; +} + +template <class InputIt,class CharT> +void encode_base64(InputIt first, InputIt last, const std::string& alphabet, std::basic_string<CharT>& result) +{ + unsigned char a3[3]; + unsigned char a4[4]; + unsigned char fill = alphabet.back(); + int i = 0; + int j = 0; + + while (first != last) + { + a3[i++] = *first++; + if (i == 3) + { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = a3[2] & 0x3f; + + for (i = 0; i < 4; i++) + { + result.push_back(alphabet[a4[i]]); + } + i = 0; + } + } + + if (i > 0) + { + for (j = i; j < 3; ++j) + { + a3[j] = 0; + } + + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + + for (j = 0; j < i + 1; ++j) + { + result.push_back(alphabet[a4[j]]); + } + + if (fill != 0) + { + while (i++ < 3) + { + result.push_back(fill); + } + } + } +} + +template <class InputIt,class CharT> +void encode_base64url(InputIt first, InputIt last, std::basic_string<CharT>& result) +{ + return encode_base64(first,last,base64url_alphabet,result); +} + +template <class InputIt,class CharT> +void encode_base64(InputIt first, InputIt last, std::basic_string<CharT>& result) +{ + encode_base64(first,last,base64_alphabet,result); +} + +inline +std::string decode_base64(const std::string& base64_string) +{ + std::string result; + uint8_t a4[4], a3[3]; + uint8_t i = 0; + uint8_t j = 0; + + auto first = base64_string.begin(); + auto last = base64_string.end(); + + while (first != last && *first != '=') + { + JSONCONS_ASSERT(is_base64(*first)); + + a4[i++] = *first++; + if (i == 4) + { + for (i = 0; i < 4; ++i) + { + a4[i] = static_cast<uint8_t>(base64_alphabet.find(a4[i])); + } + + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + + for (i = 0; i < 3; i++) + { + result.push_back(a3[i]); + } + i = 0; + } + } + + if (i > 0) + { + for (j = 0; j < i; ++j) + { + a4[j] = static_cast<uint8_t>(base64_alphabet.find(a4[j])); + } + + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + + for (j = 0; j < i - 1; ++j) + { + result.push_back(a3[j]); + } + } + + return result; +} + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/parse_error_handler.hpp b/vendor/jsoncons-0.104.0/jsoncons/parse_error_handler.hpp new file mode 100644 index 00000000..e38785ae --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/parse_error_handler.hpp @@ -0,0 +1,165 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_PARSE_ERROR_HANDLER_HPP +#define JSONCONS_PARSE_ERROR_HANDLER_HPP + +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_error_category.hpp> +#include <system_error> + +namespace jsoncons { + +class parse_error : public std::exception, public virtual json_exception +{ +public: + parse_error() + : line_number_(0), + column_number_(0) + { + } + parse_error(std::error_code ec, + size_t line, + size_t column) + : error_code_(ec), + line_number_(line), + column_number_(column) + { + } + parse_error(const parse_error& other) + : error_code_(other.error_code_), + line_number_(other.line_number_), + column_number_(other.column_number_) + { + } + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + std::ostringstream os; + os << error_code_.message() << " at line " << line_number_ << " and column " << column_number_; + const_cast<std::string&>(buffer_) = os.str(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + size_t line_number() const + { + return line_number_; + } + + size_t column_number() const + { + return column_number_; + } + + parse_error& operator=(const parse_error& e) + { + error_code_ = e.error_code_; + line_number_ = e.line_number_; + column_number_ = e.column_number_; + return *this; + } +private: + std::error_code error_code_; + std::string buffer_; + size_t line_number_; + size_t column_number_; +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef parse_error json_parse_exception; +typedef parse_error parse_exception; +#endif + +class parsing_context +{ +public: + virtual ~parsing_context() = default; + + size_t line_number() const + { + return do_line_number(); + } + size_t column_number() const + { + return do_column_number(); + } + +private: + virtual size_t do_line_number() const = 0; + virtual size_t do_column_number() const = 0; +}; + +class parse_error_handler +{ +public: + virtual ~parse_error_handler() + { + } + + bool error(std::error_code ec, + const parsing_context& context) JSONCONS_NOEXCEPT + { + return do_error(ec,context); + } + + void fatal_error(std::error_code ec, + const parsing_context& context) JSONCONS_NOEXCEPT + { + do_fatal_error(ec,context); + } + +private: + virtual bool do_error(std::error_code, + const parsing_context& context) JSONCONS_NOEXCEPT = 0; + + virtual void do_fatal_error(std::error_code, + const parsing_context&) JSONCONS_NOEXCEPT + { + } +}; + +class default_parse_error_handler : public parse_error_handler +{ +private: + bool do_error(std::error_code code, + const parsing_context&) JSONCONS_NOEXCEPT override + { + static const std::error_code illegal_comment = make_error_code(json_parser_errc::illegal_comment); + + if (code == illegal_comment) + { + return false; + } + else + { + return true; + } + } +}; + +class strict_parse_error_handler : public parse_error_handler +{ +private: + bool do_error(std::error_code, const parsing_context&) JSONCONS_NOEXCEPT override + { + return true; + } +}; + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/serialization_options.hpp b/vendor/jsoncons-0.104.0/jsoncons/serialization_options.hpp new file mode 100644 index 00000000..18be2ce3 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/serialization_options.hpp @@ -0,0 +1,279 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_SERIALIZATION_OPTIONS_HPP +#define JSONCONS_SERIALIZATION_OPTIONS_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> +#include <cwchar> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/detail/type_traits_helper.hpp> + +namespace jsoncons { + +#if !defined(JSONCONS_NO_DEPRECATED) +enum class block_options {next_line,same_line}; +#endif + +enum class line_split_kind{same_line,new_line,multi_line}; + +template <class CharT,class Allocator=std::allocator<CharT>> +class basic_serialization_options +{ +public: + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_type; +private: + int indent_; + uint8_t precision_; + uint8_t decimal_places_; + bool replace_nan_; + bool replace_pos_inf_; + bool replace_neg_inf_; + string_type nan_replacement_; + string_type pos_inf_replacement_; + string_type neg_inf_replacement_; + bool escape_all_non_ascii_; + bool escape_solidus_; + + line_split_kind object_object_split_lines_; + line_split_kind object_array_split_lines_; + line_split_kind array_array_split_lines_; + line_split_kind array_object_split_lines_; + + chars_format floating_point_format_; +public: + static const size_t default_indent = 4; + +// Constructors + + basic_serialization_options() + : + indent_(default_indent), + precision_(0), + replace_nan_(true), + replace_pos_inf_(true), + replace_neg_inf_(true), + nan_replacement_(detail::null_literal<CharT>()), + pos_inf_replacement_(detail::null_literal<CharT>()), + neg_inf_replacement_(detail::null_literal<CharT>()), + escape_all_non_ascii_(false), + escape_solidus_(false), + object_object_split_lines_(line_split_kind::multi_line), + object_array_split_lines_(line_split_kind::same_line), + array_array_split_lines_(line_split_kind::new_line), + array_object_split_lines_(line_split_kind::multi_line) + { + } + +// Accessors + line_split_kind object_object_split_lines() const {return object_object_split_lines_;} + line_split_kind array_object_split_lines() const {return array_object_split_lines_;} + line_split_kind object_array_split_lines() const {return object_array_split_lines_;} + line_split_kind array_array_split_lines() const {return array_array_split_lines_;} + + basic_serialization_options<CharT>& object_object_split_lines(line_split_kind value) {object_object_split_lines_ = value; return *this;} + basic_serialization_options<CharT>& array_object_split_lines(line_split_kind value) {array_object_split_lines_ = value; return *this;} + basic_serialization_options<CharT>& object_array_split_lines(line_split_kind value) {object_array_split_lines_ = value; return *this;} + basic_serialization_options<CharT>& array_array_split_lines(line_split_kind value) {array_array_split_lines_ = value; return *this;} + +#if !defined(JSONCONS_NO_DEPRECATED) + block_options array_array_block_option() + { + return (array_array_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& array_array_block_option(block_options value) + { + array_array_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } + + block_options array_object_block_option() + { + return (array_object_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& array_object_block_option(block_options value) + { + array_object_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } + + block_options object_array_block_option() + { + return (object_array_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& object_array_block_option(block_options value) + { + object_array_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } + + block_options object_object_block_option() + { + return (object_object_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& object_object_block_option(block_options value) + { + object_object_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } +#endif + + int indent() const + { + return indent_; + } + + basic_serialization_options<CharT>& indent(int value) + { + indent_ = value; + return *this; + } + + chars_format floating_point_format() const + { + return floating_point_format_; + } + + basic_serialization_options<CharT>& floating_point_format(chars_format value) + { + floating_point_format_ = value; + return *this; + } + + uint8_t precision() const + { + return precision_; + } + + basic_serialization_options<CharT>& precision(uint8_t value) + { + precision_ = value; + return *this; + } + + uint8_t decimal_places() const + { + return decimal_places_; + } + + basic_serialization_options<CharT>& decimal_places(uint8_t value) + { + decimal_places_ = value; + return *this; + } + + bool escape_all_non_ascii() const + { + return escape_all_non_ascii_; + } + + basic_serialization_options<CharT>& escape_all_non_ascii(bool value) + { + escape_all_non_ascii_ = value; + return *this; + } + + bool escape_solidus() const + { + return escape_solidus_; + } + + basic_serialization_options<CharT>& escape_solidus(bool value) + { + escape_solidus_ = value; + return *this; + } + + bool replace_nan() const {return replace_nan_;} + + basic_serialization_options<CharT>& replace_nan(bool replace) + { + replace_nan_ = replace; + return *this; + } + + bool replace_pos_inf() const {return replace_pos_inf_;} + + bool replace_neg_inf() const {return replace_neg_inf_;} + + basic_serialization_options<CharT>& replace_inf(bool replace) + { + replace_pos_inf_ = replace; + replace_neg_inf_ = replace; + return *this; + } + + basic_serialization_options<CharT>& replace_pos_inf(bool replace) + { + replace_pos_inf_ = replace; + return *this; + } + + basic_serialization_options<CharT>& replace_neg_inf(bool replace) + { + replace_neg_inf_ = replace; + return *this; + } + + const string_type& nan_replacement() const + { + return nan_replacement_; + } + + basic_serialization_options<CharT>& nan_replacement(const string_type& replacement) + { + nan_replacement_ = replacement; + return *this; + } + + basic_serialization_options<CharT>& neg_inf_replacement(const string_type& replacement) + { + neg_inf_replacement_ = replacement; + return *this; + } + + const string_type& pos_inf_replacement() const + { + return pos_inf_replacement_; + } + + basic_serialization_options<CharT>& pos_inf_replacement(const string_type& replacement) + { + pos_inf_replacement_ = replacement; + return *this; + } + + const string_type& neg_inf_replacement() const + { + return neg_inf_replacement_; + } +}; + +typedef basic_serialization_options<char> serialization_options; +typedef basic_serialization_options<wchar_t> wserialization_options; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_serialization_options<char> output_format; +typedef basic_serialization_options<wchar_t> woutput_format; +#endif + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/serialization_traits.hpp b/vendor/jsoncons-0.104.0/jsoncons/serialization_traits.hpp new file mode 100644 index 00000000..aa22769f --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/serialization_traits.hpp @@ -0,0 +1,315 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_SERIALIZATION_TRAITS_HPP +#define JSONCONS_SERIALIZATION_TRAITS_HPP + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +#include <iostream> +#include <string> +#include <tuple> +#include <array> +#include <type_traits> +#include <memory> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_serializer.hpp> +#include <jsoncons/jsoncons_utilities.hpp> + +namespace jsoncons { + +// serialization_traits + +template <class T, class Enable = void> +struct serialization_traits +{ + template <class CharT> + static void encode(const T&, basic_json_output_handler<CharT>&) + { + } +}; + +// dump + +template <class CharT, class T> +void dump(const T& val, basic_json_output_handler<CharT>& handler) +{ + handler.begin_json(); + serialization_traits<T>::encode(val,handler); + handler.end_json(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template <class CharT, class T> +void dump_body(const T& val, basic_json_output_handler<CharT>& handler) +{ + dump_fragment(val,handler); +} +#endif + +template <class CharT, class T> +void dump_fragment(const T& val, basic_json_output_handler<CharT>& handler) +{ + serialization_traits<T>::encode(val,handler); +} + +template <class CharT, class T> +void dump(const T& val, std::basic_ostream<CharT>& os) +{ + basic_json_serializer<CharT> serializer(os); + dump(val, serializer); +} + +template <class CharT, class T> +void dump(const T& val, const basic_serialization_options<CharT>& options, + std::basic_ostream<CharT>& os) +{ + basic_json_serializer<CharT> serializer(os, options); + dump(val, serializer); +} + +template <class CharT, class T> +void dump(const T& val, std::basic_ostream<CharT>& os, bool pprint) +{ + basic_json_serializer<CharT> serializer(os, pprint); + dump(val, serializer); +} + +template <class CharT, class T> +void dump(const T& val, const basic_serialization_options<CharT>& options, + std::basic_ostream<CharT>& os, bool pprint) +{ + basic_json_serializer<CharT> serializer(os, options, pprint); + dump(val, serializer); +} + +// integer + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_integer_like<T>::value +>::type> +{ + template <class CharT> + static void encode(T val, basic_json_output_handler<CharT>& handler) + { + handler.integer_value(val); + } +}; + +// uinteger + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_uinteger_like<T>::value +>::type> +{ + template <class CharT> + static void encode(T val, basic_json_output_handler<CharT>& handler) + { + handler.uinteger_value(val); + } +}; + +// double + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_floating_point_like<T>::value +>::type> +{ + template <class CharT> + static void encode(T val, basic_json_output_handler<CharT>& handler) + { + handler.double_value(val); + } +}; + +// bool + +template<> +struct serialization_traits<bool> +{ + template <class CharT> + static void encode(bool val, basic_json_output_handler<CharT>& handler) + { + handler.bool_value(val); + } +}; + +// string + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_string_like<T>::value +>::type> +{ + template <class CharT> + static void encode(const T& val, basic_json_output_handler<CharT>& handler) + { + handler.string_value(val); + } +}; + +/*template<> +struct serialization_traits<typename type_wrapper<CharT>::const_pointer_type> +{ + template <class CharT> + static void encode(typename type_wrapper<CharT>::const_pointer_type val, basic_json_output_handler<CharT>& handler) + { + handler.string_value(val); + } +};*/ + +// sequence container (except string and array) + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_vector_like<T>::value +>::type> +{ + typedef typename std::iterator_traits<typename T::iterator>::value_type value_type; + + template <class CharT> + static void encode(const T& val, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + serialization_traits<value_type>::encode(*it,handler); + } + handler.end_array(); + } +}; + +// std::array + +template<class T, size_t N> +struct serialization_traits<std::array<T,N>> +{ + typedef typename std::array<T,N>::value_type value_type; +public: + + template <class CharT> + static void encode(const std::array<T, N>& val, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + serialization_traits<value_type>::encode(*it,handler); + } + handler.end_array(); + } +}; + +// associative container + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_map_like<T>::value +>::type> +{ + typedef typename T::mapped_type mapped_type; + typedef typename T::value_type value_type; + + template <class CharT> + static void encode(const T& val, basic_json_output_handler<CharT>& handler) + { + handler.begin_object(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + handler.name(it->first); + serialization_traits<mapped_type>::encode(it->second,handler); + } + handler.end_object(); + } +}; + +namespace detail { namespace streaming { + +template<size_t Pos, class Tuple> +struct tuple_helper +{ + using element_type = typename std::tuple_element<std::tuple_size<Tuple>::value - Pos, Tuple>::type; + using next = tuple_helper<Pos - 1, Tuple>; + + template <class CharT> + static void encode(const Tuple& tuple, basic_json_output_handler<CharT>& handler) + { + serialization_traits<element_type>::encode(std::get<std::tuple_size<Tuple>::value - Pos>(tuple),handler); + next::encode(tuple, handler); + } +}; + +template<class Tuple> +struct tuple_helper<0, Tuple> +{ + template <class CharT> + static void encode(const Tuple&, basic_json_output_handler<CharT>&) + { + } +}; + +}} + +template<typename... E> +struct serialization_traits<std::tuple<E...>> +{ +private: + using helper = detail::streaming::tuple_helper<sizeof...(E), std::tuple<E...>>; + +public: + template <class CharT> + static void encode(const std::tuple<E...>& value, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + helper::encode(value, handler); + handler.end_array(); + } +}; + +template<class T1, class T2> +struct serialization_traits<std::pair<T1,T2>> +{ +public: + + template <class CharT> + static void encode(const std::pair<T1,T2>& value, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + serialization_traits<T1>::encode(value.first, handler); + serialization_traits<T2>::encode(value.second, handler); + handler.end_array(); + } +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class T> +struct serialization_traits<std::shared_ptr<T>> +{ +public: + + template <class CharT> + static void encode(std::shared_ptr<T> p, basic_json_output_handler<CharT>& handler) + { + serialization_traits<T>::encode(*p, handler); + } +}; +#endif + +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif + + diff --git a/vendor/jsoncons-0.104.0/jsoncons/version.hpp b/vendor/jsoncons-0.104.0/jsoncons/version.hpp new file mode 100644 index 00000000..c7971685 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/version.hpp @@ -0,0 +1,50 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_VERSION_HPP +#define JSONCONS_VERSION_HPP + +#include <iostream> + +namespace jsoncons { + +struct versioning_info +{ + versioning_info(unsigned int major, + unsigned int minor, + unsigned int patch) + : major_(major), + minor_(minor), + patch_(patch) + {} + + unsigned int const major_; + unsigned int const minor_; + unsigned int const patch_; + + friend std::ostream& operator<<(std::ostream& os, const versioning_info& ver) + { + os << ver.major_ << '.' + << ver.minor_ << '.' + << ver.patch_; + return os; + } + + versioning_info(const versioning_info&) = default; + versioning_info() = delete; + versioning_info& operator=(const versioning_info&) = delete; +}; + +inline +versioning_info version() +{ + static versioning_info ver(0, 104, 0); + return ver; +} + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/binary/binary_utilities.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/binary/binary_utilities.hpp new file mode 100644 index 00000000..4d350e06 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/binary/binary_utilities.hpp @@ -0,0 +1,354 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BINARY_BINARY_UTILITIES_HPP +#define JSONCONS_BINARY_BINARY_UTILITIES_HPP + +#include <assert.h> +#include <cfloat> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <istream> +#include <limits> +#include <memory> +#include <sstream> +#include <vector> + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +#ifdef __F16C__ +# include <immintrin.h> +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \ + (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32)) +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define JSONCONS_BINARY_TO_BE64 __builtin_bswap64 +# define JSONCONS_BINARY_FROM_BE64 __builtin_bswap64 +# define JSONCONS_BINARY_TO_BE32 __builtin_bswap32 +# define JSONCONS_BINARY_FROM_BE32 __builtin_bswap32 +# ifdef __INTEL_COMPILER +# define JSONCONS_BINARY_TO_BE16 _bswap16 +# define JSONCONS_BINARY_FROM_BE16 _bswap16 +# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16) +# define JSONCONS_BINARY_TO_BE16 __builtin_bswap16 +# define JSONCONS_BINARY_FROM_BE16 __builtin_bswap16 +# else +# define JSONCONS_BINARY_TO_BE16(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8)) +# define JSONCONS_BINARY_FROM_BE16 JSONCONS_BINARY_TO_BE16 +# endif +# else +# define JSONCONS_BINARY_TO_BE64 +# define JSONCONS_BINARY_FROM_BE64 +# define JSONCONS_BINARY_TO_BE32 +# define JSONCONS_BINARY_FROM_BE32 +# define JSONCONS_BINARY_TO_BE16 +# define JSONCONS_BINARY_FROM_BE16 +# endif +#elif defined(__sun) +# include <sys/byteorder.h> +#elif defined(_MSC_VER) +/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */ +# define JSONCONS_BINARY_TO_BE64 _byteswap_uint64 +# define JSONCONS_BINARY_FROM_BE64 _byteswap_uint64 +# define JSONCONS_BINARY_TO_BE32 _byteswap_ulong +# define JSONCONS_BINARY_FROM_BE32 _byteswap_ulong +# define JSONCONS_BINARY_TO_BE16 _byteswap_ushort +# define JSONCONS_BINARY_FROM_BE16 _byteswap_ushort +#endif +#ifndef JSONCONS_BINARY_TO_BE16 +# include <arpa/inet.h> +# define JSONCONS_BINARY_TO_BE16 ntohs +# define JSONCONS_BINARY_FROM_BE16 htons +#endif +#ifndef JSONCONS_BINARY_TO_BE32 +# include <arpa/inet.h> +# define JSONCONS_BINARY_TO_BE32 ntohl +# define JSONCONS_BINARY_FROM_BE32 htonl +#endif +#ifndef JSONCONS_BINARY_TO_BE64 +# define JSONCONS_BINARY_TO_BE64 ntohll +# define JSONCONS_BINARY_FROM_BE64 htonll +/* ntohll isn't usually defined */ +# ifndef ntohll +# if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define ntohll +# define htonll +# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ntohll(x) ((ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (ntohl((x) >> 32))) +# define htonll ntohll +# else +# error "Unable to determine byte order!" +# endif +# endif +#endif + +namespace jsoncons { namespace binary { + +class read_nbytes_failed : public std::invalid_argument, public virtual json_exception +{ +public: + explicit read_nbytes_failed(size_t count) JSONCONS_NOEXCEPT + : std::invalid_argument("") + { + buffer_.append("Failed attempting to read "); + buffer_.append(std::to_string(count)); + buffer_.append(" bytes from vector"); + } + ~read_nbytes_failed() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace detail { + +static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r) +{ +#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow(v1, v2, r); +#else + /* unsigned additions are well-defined */ + *r = v1 + v2; + return v1 > v1 + v2; +#endif +} + +} + +inline +uint16_t encode_half(double val) +{ +#ifdef __F16C__ + return _cvtss_sh(val, 3); +#else + uint64_t v; + memcpy(&v, &val, sizeof(v)); + int sign = v >> 63 << 15; + int exp = (v >> 52) & 0x7ff; + int mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */ + exp -= 1023; + if (exp == 1024) { + /* infinity or NaN */ + exp = 16; + mant >>= 1; + } else if (exp >= 16) { + /* overflow, as largest number */ + exp = 15; + mant = 1023; + } else if (exp >= -14) { + /* regular normal */ + } else if (exp >= -24) { + /* subnormal */ + mant |= 1024; + mant >>= -(exp + 14); + exp = -15; + } else { + /* underflow, make zero */ + return 0; + } + + /* safe cast here as bit operations above guarantee not to overflow */ + return (uint16_t)(sign | ((exp + 15) << 10) | mant); +#endif +} + +/* this function was copied & adapted from RFC 7049 Appendix D */ +inline +double decode_half(uint16_t half) +{ +#ifdef __F16C__ + return _cvtsh_ss(half); +#else + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val; + if (exp == 0) + { + val = ldexp(mant, -24); + } + else if (exp != 31) + { + val = ldexp(mant + 1024, exp - 25); + } + else + { + val = mant == 0 ? INFINITY : NAN; + } + return half & 0x8000 ? -val : val; +#endif +} + +// to_big_endian + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint8_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + v.push_back(static_cast<uint8_t>((val) & 0xff)); +} + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint16_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + T x = JSONCONS_BINARY_FROM_BE16(val); + + uint8_t where[sizeof(T)]; + memcpy(where, &x, sizeof(T)); + + for (auto e : where) + { + v.push_back(e); + } +} + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint32_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + T x = JSONCONS_BINARY_FROM_BE32(val); + + uint8_t where[sizeof(T)]; + memcpy(where, &x, sizeof(T)); + + for (auto e : where) + { + v.push_back(e); + } +} + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint64_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + T x = JSONCONS_BINARY_FROM_BE64(val); + + uint8_t where[sizeof(T)]; + memcpy(where, &x, sizeof(T)); + + for (auto e : where) + { + v.push_back(e); + } +} + +inline +void to_big_endian(float val, std::vector<uint8_t>& v) +{ + to_big_endian(*reinterpret_cast<uint32_t*>(&val), v); +} + +inline +void to_big_endian(double val, std::vector<uint8_t>& v) +{ + to_big_endian(*reinterpret_cast<uint64_t*>(&val), v); +} + +// from_big_endian + +template<class T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint8_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return static_cast<T>(*(first)); + } +} + +template<class T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint16_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return JSONCONS_BINARY_TO_BE16(*reinterpret_cast<const uint16_t*>(first)); + } +} + +template<class T> +typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint32_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return JSONCONS_BINARY_TO_BE32(*reinterpret_cast<const uint32_t*>(first)); + } +} + +template<class T> +typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint64_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return JSONCONS_BINARY_TO_BE64(*reinterpret_cast<const uint64_t*>(first)); + } +} + +template<class T> +typename std::enable_if<std::is_floating_point<T>::value && +sizeof(T) == sizeof(uint32_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint32_t data = from_big_endian<uint32_t>(first,last,endp); + return *reinterpret_cast<T*>(&data); +} + +template<class T> +typename std::enable_if<std::is_floating_point<T>::value && +sizeof(T) == sizeof(uint64_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint64_t data = from_big_endian<uint64_t>(first,last,endp); + return *reinterpret_cast<T*>(&data); +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/cbor/cbor.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/cbor/cbor.hpp new file mode 100644 index 00000000..73f0cbcd --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/cbor/cbor.hpp @@ -0,0 +1,2792 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_HPP +#define JSONCONS_CBOR_CBOR_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <limits> +#include <cassert> +#include <iterator> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/binary/binary_utilities.hpp> + +// Positive integer 0x00..0x17 (0..23) +#define JSONCONS_CBOR_0x00_0x17 \ + 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x09:case 0x0a:case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16:case 0x17 + +// Negative integer -1-0x00..-1-0x17 (-1..-24) +#define JSONCONS_CBOR_0x20_0x37 \ + 0x20:case 0x21:case 0x22:case 0x23:case 0x24:case 0x25:case 0x26:case 0x27:case 0x28:case 0x29:case 0x2a:case 0x2b:case 0x2c:case 0x2d:case 0x2e:case 0x2f:case 0x30:case 0x31:case 0x32:case 0x33:case 0x34:case 0x35:case 0x36:case 0x37 + +// byte string (0x00..0x17 bytes follow) +#define JSONCONS_CBOR_0x40_0x57 \ + 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57 + +// UTF-8 string (0x00..0x17 bytes follow) +#define JSONCONS_CBOR_0x60_0x77 \ + 0x60:case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:case 0x67:case 0x68:case 0x69:case 0x6a:case 0x6b:case 0x6c:case 0x6d:case 0x6e:case 0x6f:case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77 + +// array (0x00..0x17 data items follow) +#define JSONCONS_CBOR_0x80_0x97 \ + 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87:case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f:case 0x90:case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97 + +// map (0x00..0x17 pairs of data items follow) +#define JSONCONS_CBOR_0xa0_0xb7 \ + 0xa0:case 0xa1:case 0xa2:case 0xa3:case 0xa4:case 0xa5:case 0xa6:case 0xa7:case 0xa8:case 0xa9:case 0xaa:case 0xab:case 0xac:case 0xad:case 0xae:case 0xaf:case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7 + +namespace jsoncons { namespace cbor { + +class cbor_decode_error : public std::invalid_argument, public virtual json_exception +{ +public: + explicit cbor_decode_error(size_t pos) JSONCONS_NOEXCEPT + : std::invalid_argument("") + { + buffer_.append("Error decoding a cbor at position "); + buffer_.append(std::to_string(pos)); + } + ~cbor_decode_error() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace detail { + +void walk(const uint8_t* first, const uint8_t* last, const uint8_t** endp); + +inline +size_t get_byte_string_length(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + size_t length = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + { + length = *first & 0x1f; + *endp = p; + break; + } + case 0x58: // byte string (one-byte uint8_t for n follows) + { + length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x59: // byte string (two-byte uint16_t for n follow) + { + length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x5a: // byte string (four-byte uint32_t for n follow) + { + length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x5b: // byte string (eight-byte uint64_t for n follow) + { + length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x5f: // byte string, byte strings follow, terminated by "break" + { + length = 0; + while (*p != 0xff) + { + size_t len = detail::get_byte_string_length(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + length += len; + } + break; + } + default: + { + *endp = first; + } + } + } + return length; +} + +inline +std::vector<uint8_t> get_byte_string(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + std::vector<uint8_t> v; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + { + size_t length = *first & 0x1f; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + break; + } + case 0x58: // byte string (one-byte uint8_t for n follows) + { + const auto length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x59: // byte string (two-byte uint16_t for n follow) + { + const auto length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x5a: // byte string (four-byte uint32_t for n follow) + { + const auto length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x5b: // byte string (eight-byte uint64_t for n follow) + { + const auto length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x5f: // byte string, byte strings follow, terminated by "break" + { + while (*p != 0xff) + { + std::vector<uint8_t> ss = detail::get_byte_string(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + else + { + p = *endp; + v.insert(v.end(),ss.begin(),ss.end()); + } + } + break; + } + default: + { + *endp = first; + } + } + } + return v; +} + +inline +size_t get_text_string_length(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + size_t length = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x60_0x77: // UTF-8 string (0x00..0x17 bytes follow) + { + length = *first & 0x1f; + *endp = p; + break; + } + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + { + length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + { + length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x7f: // UTF-8 string, text strings follow, terminated by "break" + { + length = 0; + while (*p != 0xff) + { + size_t len = detail::get_text_string_length(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + length += len; + } + break; + } + default: + *endp = first; + break; + } + } + return length; +} + +inline +std::string get_text_string(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + std::string s; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x60_0x77: // UTF-8 string (0x00..0x17 bytes follow) + { + size_t length = *first & 0x1f; + *endp = p + length; + s = std::string(p, *endp); + break; + } + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + const auto length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + const auto length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + { + const auto length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + { + const auto length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x7f: // UTF-8 string, text strings follow, terminated by "break" + { + while (*p != 0xff) + { + std::string ss = detail::get_text_string(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + else + { + p = *endp; + s.append(std::move(ss)); + } + } + break; + } + default: + *endp = first; + break; + } + } + return s; +} + +inline +void walk_object(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + size_t size = 0; + + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0xa0_0xb7: // map (0x00..0x17 pairs of data items follow) + { + size = *first & 0x1f; + *endp = p; + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + break; + } + + case 0xb8: // map (one-byte uint8_t for n follows) + { + size = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + + case 0xb9: // map (two-byte uint16_t for n follow) + { + size = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + + case 0xba: // map (four-byte uint32_t for n follow) + { + size = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + + case 0xbb: // map (eight-byte uint64_t for n follow) + { + size = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + case 0xbf: + { + *endp = p; + while (*p != 0xff) + { + walk_object(p, last, endp); + if (*endp == p) + { + *endp = first; + break; + } + } + break; + } + default: + { + *endp = first; + } + } + } +} + +inline +void walk_array(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + size_t size = 0; + + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x80_0x97: // array (0x00..0x17 data items follow) + { + size = *first & 0x1f; + *endp = p; + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + break; + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + size = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + size = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + + case 0x9a: // array (four-byte uint32_t for n follow) + { + size = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + + case 0x9b: // array (eight-byte uint64_t for n follow) + { + size = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + case 0x9f: // array (indefinite length) + { + *endp = p; + while (*p != 0xff) + { + walk_array(p, last, endp); + if (*endp == p) + { + *endp = first; + break; + } + } + break; + } + default: + { + *endp = first; + } + } + } +} + +inline +uint64_t get_uinteger(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint64_t val = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const size_t length = last - first; + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + val = *first; + *endp = p; + break; + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + val = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + val = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + val = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + val = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + default: + { + *endp = first; + } + } + } + return val; +} + +inline +int64_t get_integer(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + int64_t val = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const size_t length = last - first; + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + val = static_cast<int8_t>(0x20 - 1 - *first); + *endp = p; + break; + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + auto x = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- x; + } + break; + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + auto x = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- x; + } + break; + } + + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + { + auto x = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- x; + } + break; + } + + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + auto x = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- static_cast<int64_t>(x); + } + break; + } + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + // FALLTHRU + case 0x18: // Unsigned integer (one-byte uint8_t follows) + // FALLTHRU + case 0x19: // Unsigned integer (two-byte uint16_t follows) + // FALLTHRU + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + // FALLTHRU + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + uint64_t x = detail::get_uinteger(first,last,endp); + if (*endp != first) + { + if (x <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) + { + val = x; + } + else + { + *endp = first; + } + } + break; + } + default: + { + *endp = first; + } + } + } + return val; +} + +inline +double get_double(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + double val = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const size_t length = last - first; + const uint8_t* p = first+1; + switch (*first) + { + case 0xf9: // Half-Precision Float (two-byte IEEE 754) + { + if (JSONCONS_UNLIKELY(1+sizeof(uint16_t) > length)) + { + *endp = first; + } + else + { + uint16_t x = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = binary::decode_half(x); + } + } + } + break; + + + case 0xfa: // Single-Precision Float (four-byte IEEE 754) + { + if (JSONCONS_UNLIKELY(1+sizeof(float) > length)) + { + *endp = first; + } + else + { + val = binary::from_big_endian<float>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + } + } + break; + + case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + { + if (JSONCONS_UNLIKELY(1+sizeof(double) > length)) + { + *endp = first; + } + else + { + val = binary::from_big_endian<double>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + } + } + break; + default: + { + *endp = first; + } + } + } + return val; +} + +inline +bool is_array(uint8_t b) +{ + return (b >= 0x80 && b <= 0x9b) || b == 0x9f; +} + +inline +bool is_object(uint8_t b) +{ + return (b >= 0xa0 && b <= 0xbb) || b == 0xb8; +} + +inline +bool is_string(uint8_t b) +{ + return (b >= 0x60 && b <= 0x7b) || b == 0x7f; +} + +inline +bool is_bool(uint8_t b) +{ + return b == 0xf5 || b == 0xf4; +} + +inline +bool is_double(uint8_t b) +{ + return b == 0xf9 || b == 0xfa || b == 0xfb; +} + +inline +bool is_integer(const uint8_t* first, const uint8_t* last) +{ + bool result; + + switch (*first) + { + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x38: // Negative integer (one-byte uint8_t follows) + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + case 0x18: // Unsigned integer (one-byte uint8_t follows) + case 0x19: // Unsigned integer (two-byte uint16_t follows) + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + result = true; + break; + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + const uint8_t* endp; + uint64_t x = detail::get_uinteger(first,last,&endp); + if (endp != first) + { + if (x <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) + { + result = true; + } + else + { + result = false; + } + } + else + { + result = false; + } + break; + } + default: + result = false; + break; + } + return result; +} + +inline +bool is_uinteger(uint8_t b) +{ + bool result; + + switch (b) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + // FALLTHRU + case 0x18: // Unsigned integer (one-byte uint8_t follows) + // FALLTHRU + case 0x19: // Unsigned integer (two-byte uint16_t follows) + // FALLTHRU + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + // FALLTHRU + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + result = true; + break; + default: + result = false; + break; + } + return result; +} + +inline +void walk(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first >= last) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + { + *endp = p; + break; + } + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + p += sizeof(uint8_t); + *endp = p; + break; + } + + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + p += sizeof(uint16_t); + *endp = p; + break; + } + + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + p += sizeof(uint32_t); + *endp = p; + break; + } + + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + p += sizeof(uint64_t); + *endp = p; + break; + } + + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + { + *endp = p; + break; + } + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + p += sizeof(uint8_t); + *endp = p; + break; + } + + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + p += sizeof(uint16_t); + *endp = p; + break; + } + + + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + { + p += sizeof(uint32_t); + *endp = p; + break; + } + + + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + p += sizeof(uint64_t); + *endp = p; + break; + } + + + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + { + size_t len = *first & 0x1f; + *endp = p + len; + break; + } + + case 0x58: // byte string (one-byte uint8_t for n follows) + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x59: // byte string (two-byte uint16_t for n follow) + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x5a: // byte string (four-byte uint32_t for n follow) + { + const auto len = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x5b: // byte string (eight-byte uint64_t for n follow) + { + const auto len = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x5f: // byte string (indefinite length) + { + while (*p != 0xff) + { + if (p == last) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("eof")); + } + walk(p, last, &p); + } + *endp = p; + break; + } + + // UTF-8 string (0x00..0x17 bytes follow) + case JSONCONS_CBOR_0x60_0x77: + { + size_t len = *first & 0x1f; + *endp = p + len; + break; + } + // UTF-8 string (one-byte uint8_t for n follows) + case 0x78: + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (two-byte uint16_t for n follow) + case 0x79: + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (four-byte uint32_t for n follow) + case 0x7a: + { + const auto len = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7b: + { + const auto len = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (indefinite length) + case 0x7f: + { + while (*p != 0xff) + { + if (p == last) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("eof")); + } + walk(p, last, &p); + } + *endp = p; + break; + } + + + case JSONCONS_CBOR_0x80_0x97: // array (0x00..0x17 data items follow) + // FALLTHRU + case 0x98: // array (one-byte uint8_t for n follows) + // FALLTHRU + case 0x99: // array (two-byte uint16_t for n follow) + // FALLTHRU + case 0x9a: // array (four-byte uint32_t for n follow) + // FALLTHRU + case 0x9b: // array (eight-byte uint64_t for n follow) + // FALLTHRU + case 0x9f: // array (indefinite length) + { + walk_array(first,last,endp); + break; + } + + case JSONCONS_CBOR_0xa0_0xb7: // map (0x00..0x17 pairs of data items follow) + // FALLTHRU + case 0xb8: // map (one-byte uint8_t for n follows) + // FALLTHRU + case 0xb9: // map (two-byte uint16_t for n follow) + // FALLTHRU + case 0xba: // map (four-byte uint32_t for n follow) + // FALLTHRU + case 0xbb: // map (eight-byte uint64_t for n follow) + // FALLTHRU + case 0xbf: + { + walk_object(first,last,endp); + break; + } + + // False + case 0xf4: + { + *endp = p; + break; + } + + // True + case 0xf5: + { + *endp = p; + break; + } + + // Null + case 0xf6: + { + *endp = p; + break; + } + + // Half-Precision Float (two-byte IEEE 754) + case 0xf9: + { + p += sizeof(uint16_t); + *endp = p; + break; + } + + // Single-Precision Float (four-byte IEEE 754) + case 0xfa: + { + p += sizeof(float); + *endp = p; + break; + } + + // Double-Precision Float (eight-byte IEEE 754) + case 0xfb: + { + p += sizeof(double); + *endp = p; + break; + } + + default: + { + *endp = first; + break; + } + } + } +} + +inline +size_t get_size(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + const uint8_t* p = first + 1; + switch (*first) + { + // array (0x00..0x17 data items follow) + case JSONCONS_CBOR_0x80_0x97: + { + *endp = p; + return *first & 0x1f; + } + + // array (one-byte uint8_t for n follows) + case 0x98: + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (two-byte uint16_t for n follow) + case 0x99: + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (four-byte uint32_t for n follow) + case 0x9a: + { + const auto len = binary::from_big_endian<int32_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (eight-byte uint64_t for n follow) + case 0x9b: + { + const auto len = binary::from_big_endian<int64_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (indefinite length) + case 0x9f: + { + size_t len = 0; + while (*p != 0xff) + { + size_t sz = get_size(p,last,&p); + len += sz; + walk(p, last, &p); + } + *endp = first + 1; + return len; + } + + // map (0x00..0x17 pairs of data items follow) + case JSONCONS_CBOR_0xa0_0xb7: + { + *endp = p; + return *first & 0x1f; + } + + // map (one-byte uint8_t for n follows) + case 0xb8: + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (two-byte uint16_t for n follow) + case 0xb9: + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (four-byte uint32_t for n follow) + case 0xba: + { + const auto len = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (eight-byte uint64_t for n follow) + case 0xbb: + { + const auto len = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (indefinite length) + case 0xbf: + { + size_t len = 0; + while (*p != 0xff) + { + walk(p, last, &p); + walk(p, last, &p); + } + *endp = first + 1; + return len; + } + default: + *endp = last; + return 0; + } +} + +template <class T> +class const_array_iterator +{ + const uint8_t* p_; + const uint8_t* last_; + T current_; +public: + typedef typename T::difference_type difference_type; + typedef typename T::value_type value_type; + typedef typename T::const_reference reference; + typedef typename T::const_pointer pointer; + typedef std::forward_iterator_tag iterator_catagory; + + const_array_iterator() + : p_(nullptr), last_(nullptr) + { + } + + const_array_iterator(const uint8_t* p, const uint8_t* last) + : p_(p), last_(last) + { + } + + const_array_iterator(const const_array_iterator& other) = default; + + friend bool operator==(const const_array_iterator& lhs, const const_array_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + friend bool operator!=(const const_array_iterator& lhs, const const_array_iterator& rhs) + { + return lhs.p_ != rhs.p_; + } + + friend bool operator<(const const_array_iterator& lhs, const const_array_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + const_array_iterator& operator++() + { + detail::walk(p_, last_, &p_); + return *this; + } + + reference operator*() const + { + const uint8_t* endp; + detail::walk(p_, last_, &endp); + const_cast<T*>(¤t_)->first_ = p_; + const_cast<T*>(¤t_)->last_ = endp; + return current_; + } + + pointer operator->() const + { + const uint8_t* endp; + detail::walk(p_, last_, &endp); + const_cast<T*>(¤t_)->first_ = p_; + const_cast<T*>(¤t_)->last_ = endp; + return ¤t_; + } +}; + +template <class T> +class const_object_iterator; + +template <class T> +class key_value_pair_view +{ + const uint8_t* key_begin_; + const uint8_t* key_end_; + const uint8_t* val_begin_; + const uint8_t* val_end_; + +public: + friend class const_object_iterator<T>; + + key_value_pair_view() + : key_begin_(nullptr), key_end_(nullptr), val_begin_(nullptr), val_end_(nullptr) + { + } + key_value_pair_view(const uint8_t* key_begin, const uint8_t* key_end, const uint8_t* val_begin, const uint8_t* val_end) + : key_begin_(key_begin), key_end_(key_end), val_begin_(val_begin), val_end_(val_end) + { + } + key_value_pair_view(const key_value_pair_view& other) = default; + + std::string key() const + { + const uint8_t* endp; + return get_text_string(key_begin_, key_end_, &endp); + } + + T value() const + { + return T(val_begin_, val_end_ - val_begin_); + } +}; + +template <class T> +class const_object_iterator +{ + const uint8_t* p_; + const uint8_t* last_; + key_value_pair_view<T> kvpair_; +public: + typedef typename T::difference_type difference_type; + typedef key_value_pair_view<T> value_type; + typedef const key_value_pair_view<T>& reference; + typedef const key_value_pair_view<T>* pointer; + typedef std::forward_iterator_tag iterator_catagory; + + const_object_iterator() + : p_(nullptr), last_(nullptr) + { + } + + const_object_iterator(const uint8_t* p, const uint8_t* last) + : p_(p), last_(last) + { + } + + const_object_iterator(const const_object_iterator& other) = default; + + friend bool operator==(const const_object_iterator& lhs, const const_object_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + friend bool operator!=(const const_object_iterator& lhs, const const_object_iterator& rhs) + { + return lhs.p_ != rhs.p_; + } + + friend bool operator<(const const_object_iterator& lhs, const const_object_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + const_object_iterator& operator++() + { + detail::walk(p_, last_, &p_); + detail::walk(p_, last_, &p_); + return *this; + } + + reference operator*() const + { + const uint8_t* endp; + + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_begin_ = p_; + detail::walk(kvpair_.key_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_end_ = endp; + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_begin_ = kvpair_.key_end_; + detail::walk(kvpair_.val_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_end_ = endp; + + return kvpair_; + } + + pointer operator->() const + { + const uint8_t* endp; + + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_begin_ = p_; + detail::walk(kvpair_.key_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_end_ = endp; + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_begin_ = kvpair_.key_end_; + detail::walk(kvpair_.val_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_end_ = endp; + + return &kvpair_; + } +}; + +} // namespace detail + +class cbor_view +{ + const uint8_t* first_; + const uint8_t* last_; +public: + typedef std::ptrdiff_t difference_type; + typedef cbor_view value_type; + typedef cbor_view& reference; + typedef const cbor_view& const_reference; + typedef cbor_view* pointer; + typedef const cbor_view* const_pointer; + typedef std::string string_type; + typedef char char_type; + typedef std::char_traits<char_type> char_traits_type; + typedef basic_string_view_ext<char_type> string_view_type; + typedef detail::const_object_iterator<cbor_view> object_iterator; + typedef detail::const_object_iterator<cbor_view> const_object_iterator; + typedef detail::const_array_iterator<cbor_view> array_iterator; + typedef detail::const_array_iterator<cbor_view> const_array_iterator; + typedef detail::key_value_pair_view<cbor_view> key_value_pair_type; + + friend class detail::const_array_iterator<cbor_view>; + + range<const_object_iterator> object_range() const + { + const uint8_t* endp; + const uint8_t* begin; + + switch (*first_) + { + case JSONCONS_CBOR_0xa0_0xb7: // map (0x00..0x17 pairs of data items follow) + // FALLTHRU + case 0xb8: // map (one-byte uint8_t for n follows) + // FALLTHRU + case 0xb9: // map (two-byte uint16_t for n follow) + // FALLTHRU + case 0xba: // map (four-byte uint32_t for n follow) + // FALLTHRU + case 0xbb: // map (eight-byte uint64_t for n follow) + // FALLTHRU + case 0xbf: + detail::get_size(first_,last_,&begin); + break; + default: + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Not an object")); + break; + } + detail::walk_object(first_,last_,&endp); + + return range<const_object_iterator>(const_object_iterator(begin,endp), const_object_iterator(endp, endp)); + } + + range<const_array_iterator> array_range() const + { + const uint8_t* endp; + const uint8_t* begin; + + switch (*first_) + { + case JSONCONS_CBOR_0x80_0x97: // array (0x00..0x17 data items follow) + // FALLTHRU + case 0x98: // array (one-byte uint8_t for n follows) + // FALLTHRU + case 0x99: // array (two-byte uint16_t for n follow) + // FALLTHRU + case 0x9a: // array (four-byte uint32_t for n follow) + // FALLTHRU + case 0x9b: // array (eight-byte uint64_t for n follow) + // FALLTHRU + case 0x9f: // array (indefinite length) + detail::get_size(first_,last_,&begin); + break; + default: + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Not an array")); + break; + } + detail::walk_array(first_,last_,&endp); + return range<const_array_iterator>(const_array_iterator(begin,endp), const_array_iterator(endp, endp)); + } + + cbor_view() + : first_(nullptr), last_(nullptr) + { + } + + cbor_view(const uint8_t* buffer, size_t buflen) + : first_(buffer), last_(buffer+buflen) + { + } + + cbor_view(const std::vector<uint8_t>& v) + : first_(v.data()), last_(v.data()+v.size()) + { + } + + cbor_view(const cbor_view& other) + : first_(other.first_), last_(other.last_) + { + } + + cbor_view& operator=(const cbor_view&) = default; + + friend bool operator==(const cbor_view& lhs, const cbor_view& rhs) + { + return lhs.first_ == rhs.first_ && lhs.last_ == rhs.last_; + } + + friend bool operator!=(const cbor_view& lhs, const cbor_view& rhs) + { + return !(lhs == rhs); + } + + const uint8_t* buffer() const + { + return first_; + } + + const size_t buflen() const + { + return last_ - first_; + } + + bool is_null() const + { + JSONCONS_ASSERT(buflen() > 0); + return first_[0] == 0xf6; + } + + bool empty() const + { + bool is_empty; + if (is_array() || is_object()) + { + is_empty = (size() == 0); + } + else if (is_string()) + { + const uint8_t* endp; + size_t length = detail::get_text_string_length(first_,last_,&endp); + is_empty = (length == 0); + } + else if (is_byte_string()) + { + const uint8_t* endp; + size_t length = detail::get_byte_string_length(first_, last_, &endp); + is_empty = (length == 0); + } + else + { + is_empty = false; + } + + return is_empty; + } + + bool is_array() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_array(first_[0]); + } + + bool is_object() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_object(first_[0]); + } + + bool is_string() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_string(first_[0]); + } + + bool is_byte_string() const + { + JSONCONS_ASSERT(buflen() > 0); + + bool result; + switch (first_[0]) + { + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + // FALLTHRU + case 0x58: // byte string (one-byte uint8_t for n follows) + // FALLTHRU + case 0x59: // byte string (two-byte uint16_t for n follow) + // FALLTHRU + case 0x5a: // byte string (four-byte uint32_t for n follow) + // FALLTHRU + case 0x5b: // byte string (eight-byte uint64_t for n follow) + // FALLTHRU + case 0x5f: // byte string, byte strings follow, terminated by "break" + result = true; + break; + default: + result = false; + break; + } + return result; + } + + bool is_bool() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_bool(first_[0]); + } + + bool is_double() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_double(first_[0]); + } + + bool is_integer() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_integer(first_,last_); + } + + bool is_uinteger() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_uinteger(first_[0]); + } + + size_t size() const + { + const uint8_t* it; + size_t len = detail::get_size(first_,last_,&it); + return len; + } + + cbor_view at(size_t index) const + { + JSONCONS_ASSERT(is_array()); + const uint8_t* it = first_; + + size_t len = detail::get_size(it, last_, &it); + + for (size_t i = 0; i < index; ++i) + { + detail::walk(it, last_, &it); + } + + const uint8_t* endp; + detail::walk(it, last_, &endp); + + return cbor_view(it,endp-it); + } + + cbor_view at(const string_view_type& key) const + { + JSONCONS_ASSERT(is_object()); + const uint8_t* it = first_; + + size_t len = detail::get_size(first_, last_, &it); + + for (size_t i = 0; i < len; ++i) + { + const uint8_t* endp; + string_type a_key = detail::get_text_string(it, last_, &endp); + if (endp == it) + { + JSONCONS_THROW(cbor_decode_error(last_-it)); + } + else + { + it = endp; + } + if (a_key == key) + { + const uint8_t* last; + detail::walk(it, last_, &last); + JSONCONS_ASSERT(last >= it); + return cbor_view(it,last-it); + } + const uint8_t* last; + detail::walk(it, last_, &last); + it = last; + } + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Key not found")); + } + + bool has_key(const string_view_type& key) const + { + if (!is_object()) + { + return false; + } + const uint8_t* it = first_; + + size_t len = detail::get_size(it, last_, &it); + + for (size_t i = 0; i < len; ++i) + { + const uint8_t* endp; + string_type a_key = detail::get_text_string(it, last_,&endp); + if (endp == it) + { + JSONCONS_THROW(cbor_decode_error(last_-it)); + } + else + { + it = endp; + } + if (a_key == key) + { + return true; + } + detail::walk(it, last_, &it); + } + return false; + } + + int64_t as_integer() const + { + const uint8_t* endp; + int64_t val = detail::get_integer(first_,last_,&endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an integer")); + } + return val; + } + + bool as_bool() const + { + if (*first_ == 0xf5) + { + return true; + } + else if (*first_ == 0xf4) + { + return false; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a bool")); + } + } + + uint64_t as_uinteger() const + { + const uint8_t* endp; + uint64_t val = detail::get_uinteger(first_, last_, &endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned integer")); + } + return val; + } + + double as_double() const + { + double val; + + if (is_double()) + { + const uint8_t* endp; + val = detail::get_double(first_,last_,&endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid CBOR")); + } + } + else if (is_uinteger()) + { + val = static_cast<double>(as_uinteger()); + } + else if (is_integer()) + { + val = static_cast<double>(as_integer()); + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + return val; + } + + std::string as_string() const + { + const uint8_t* endp; + std::string val = detail::get_text_string(first_,last_,&endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a string")); + } + return val; + } +}; + +struct Encode_cbor_ +{ + template <typename T> + void operator()(T val, std::vector<uint8_t>& v) + { + binary::to_big_endian(val,v); + } +}; + +struct Calculate_size_ +{ + template <typename T> + void operator()(T, size_t& size) + { + size += sizeof(T); + } +}; + +template<class Json> +struct cbor_Encoder_ +{ + typedef typename Json::string_view_type string_view_type; + + static size_t calculate_size(const Json& j) + { + size_t n = 0; + cbor_Encoder_<Json>::encode(j,Calculate_size_(),n); + return n; + } + + template <class Action, class Result> + static void encode(const Json& jval, Action action, Result& v) + { + switch (jval.type_id()) + { + case json_type_tag::null_t: + { + action(static_cast<uint8_t>(0xf6), v); + break; + } + + case json_type_tag::bool_t: + { + action(static_cast<uint8_t>(jval.as_bool() ? 0xf5 : 0xf4), v); + break; + } + + case json_type_tag::integer_t: + { + int64_t val = jval.as_integer(); + if (val >= 0) + { + if (val <= 0x17) + { + action(static_cast<uint8_t>(val), v); + } else if (val <= (std::numeric_limits<uint8_t>::max)()) + { + action(static_cast<uint8_t>(0x18), v); + action(static_cast<uint8_t>(val), v); + } else if (val <= (std::numeric_limits<uint16_t>::max)()) + { + action(static_cast<uint8_t>(0x19), v); + action(static_cast<uint16_t>(val), v); + } else if (val <= (std::numeric_limits<uint32_t>::max)()) + { + action(static_cast<uint8_t>(0x1a), v); + action(static_cast<uint32_t>(val), v); + } else if (val <= (std::numeric_limits<int64_t>::max)()) + { + action(static_cast<uint8_t>(0x1b), v); + action(static_cast<int64_t>(val), v); + } + } else + { + const auto posnum = -1 - val; + if (val >= -24) + { + action(static_cast<uint8_t>(0x20 + posnum), v); + } else if (posnum <= (std::numeric_limits<uint8_t>::max)()) + { + action(static_cast<uint8_t>(0x38), v); + action(static_cast<uint8_t>(posnum), v); + } else if (posnum <= (std::numeric_limits<uint16_t>::max)()) + { + action(static_cast<uint8_t>(0x39), v); + action(static_cast<uint16_t>(posnum), v); + } else if (posnum <= (std::numeric_limits<uint32_t>::max)()) + { + action(static_cast<uint8_t>(0x3a), v); + action(static_cast<uint32_t>(posnum), v); + } else if (posnum <= (std::numeric_limits<int64_t>::max)()) + { + action(static_cast<uint8_t>(0x3b), v); + action(static_cast<int64_t>(posnum), v); + } + } + break; + } + + case json_type_tag::uinteger_t: + { + uint64_t val = jval.as_uinteger(); + if (val <= 0x17) + { + action(static_cast<uint8_t>(val),v); + } else if (val <=(std::numeric_limits<uint8_t>::max)()) + { + action(static_cast<uint8_t>(0x18), v); + action(static_cast<uint8_t>(val),v); + } else if (val <=(std::numeric_limits<uint16_t>::max)()) + { + action(static_cast<uint8_t>(0x19), v); + action(static_cast<uint16_t>(val),v); + } else if (val <=(std::numeric_limits<uint32_t>::max)()) + { + action(static_cast<uint8_t>(0x1a), v); + action(static_cast<uint32_t>(val),v); + } else if (val <=(std::numeric_limits<uint64_t>::max)()) + { + action(static_cast<uint8_t>(0x1b), v); + action(static_cast<uint64_t>(val),v); + } + break; + } + + case json_type_tag::double_t: + { + action(static_cast<uint8_t>(0xfb), v); + action(jval.as_double(),v); + break; + } + + case json_type_tag::byte_string_t: + { + encode_byte_string(jval. template as<std::vector<uint8_t>>(), action, v); + break; + } + + case json_type_tag::small_string_t: + case json_type_tag::string_t: + { + encode_string(jval.as_string_view(), action, v); + break; + } + + case json_type_tag::array_t: + { + const auto length = jval.array_value().size(); + if (length <= 0x17) + { + action(static_cast<uint8_t>(static_cast<uint8_t>(0x80 + length)), v); + } else if (length <= 0xff) + { + action(static_cast<uint8_t>(0x98), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0x99), v); + action(static_cast<uint16_t>(length),v); + } else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0x9a), v); + action(static_cast<uint32_t>(length),v); + } else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0x9b), v); + action(static_cast<uint64_t>(length),v); + } + + // append each element + for (const auto& el : jval.array_range()) + { + encode(el,action,v); + } + break; + } + + case json_type_tag::object_t: + { + const auto length = jval.object_value().size(); + if (length <= 0x17) + { + action(static_cast<uint8_t>(static_cast<uint8_t>(0xa0 + length)), v); + } else if (length <= 0xff) + { + action(static_cast<uint8_t>(0xb8), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0xb9), v); + action(static_cast<uint16_t>(length),v); + } else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0xba), v); + action(static_cast<uint32_t>(length),v); + } else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0xbb), v); + action(static_cast<uint64_t>(length),v); + } + + // append each element + for (const auto& kv: jval.object_range()) + { + encode_string(kv.key(), action, v); + encode(kv.value(), action, v); + } + break; + } + + default: + { + break; + } + } + } + + template <class Action,class Result> + static void encode_string(const string_view_type& sv, Action action, Result& v) + { + std::basic_string<uint8_t> target; + auto result = unicons::convert( + sv.begin(), sv.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + + const size_t length = target.length(); + if (length <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + action(static_cast<uint8_t>(static_cast<uint8_t>(0x60 + length)), v); + } + else if (length <= 0xff) + { + action(static_cast<uint8_t>(0x78), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } + else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0x79), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0x7a), v); + action(static_cast<uint32_t>(length), v); + } + else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0x7b), v); + action(static_cast<uint64_t>(length),v); + } + + for (size_t i = 0; i < length; ++i) + { + action(static_cast<uint8_t>(target.data()[i]), v); + } + } + + template <class Action,class Result> + static void encode_byte_string(const std::vector<uint8_t>& target, Action action, Result& v) + { + const size_t length = target.size(); + if (length <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + action(static_cast<uint8_t>(static_cast<uint8_t>(0x40 + length)), v); + } + else if (length <= 0xff) + { + action(static_cast<uint8_t>(0x58), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } + else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0x59), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0x5a), v); + action(static_cast<uint32_t>(length), v); + } + else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0x5b), v); + action(static_cast<uint64_t>(length),v); + } + + for (size_t i = 0; i < length; ++i) + { + action(static_cast<uint8_t>(target.data()[i]), v); + } + } +}; + +// decode_cbor + +template<class Json> +class Decode_cbor_ +{ + const uint8_t* begin_; + const uint8_t* end_; + const uint8_t* it_; +public: + typedef typename Json::char_type char_type; + + Decode_cbor_(const uint8_t* begin, const uint8_t* end) + : begin_(begin), end_(end), it_(begin) + { + } + + Json decode() + { + const uint8_t* pos = it_++; + switch (*pos) + { + + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + // FALLTHRU + case 0x18: // Unsigned integer (one-byte uint8_t follows) + // FALLTHRU + case 0x19: // Unsigned integer (two-byte uint16_t follows) + // FALLTHRU + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + // FALLTHRU + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + const uint8_t* endp; + uint64_t val = detail::get_uinteger(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(endp-begin_)); + } + it_ = endp; + return Json(val); + } + break; + + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + // FALLTHRU + case 0x38: // Negative integer (one-byte uint8_t follows) + // FALLTHRU + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + // FALLTHRU + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + // FALLTHRU + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + const uint8_t* endp; + int64_t val = detail::get_integer(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(endp-begin_)); + } + it_ = endp; + return Json(val); + } + break; + // byte string (0x00..0x17 bytes follow) + case JSONCONS_CBOR_0x40_0x57: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5f: + { + const uint8_t* endp; + std::vector<uint8_t> v = detail::get_byte_string(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(end_-pos)); + } + else + { + it_ = endp; + } + + return Json(v.data(),v.size()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case JSONCONS_CBOR_0x60_0x77: + case 0x78: + case 0x79: + case 0x7a: + case 0x7b: + case 0x7f: + { + const uint8_t* endp; + std::string s = detail::get_text_string(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(end_-pos)); + } + else + { + it_ = endp; + } + std::basic_string<char_type> target; + auto result = unicons::convert(s.begin(),s.end(),std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return Json(target); + } + + // array (0x00..0x17 data items follow) + case JSONCONS_CBOR_0x80_0x97: + { + return get_fixed_length_array(*pos & 0x1f); + } + + // array (one-byte uint8_t for n follows) + case 0x98: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (two-byte uint16_t for n follow) + case 0x99: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (four-byte uint32_t for n follow) + case 0x9a: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (eight-byte uint64_t for n follow) + case 0x9b: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (indefinite length) + case 0x9f: + { + Json result = typename Json::array(); + while (*pos != 0xff) + { + result.push_back(decode()); + pos = it_; + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case JSONCONS_CBOR_0xa0_0xb7: + { + return get_fixed_length_map(*pos & 0x1f); + } + + // map (one-byte uint8_t for n follows) + case 0xb8: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (two-byte uint16_t for n follow) + case 0xb9: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (four-byte uint32_t for n follow) + case 0xba: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (eight-byte uint64_t for n follow) + case 0xbb: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (indefinite length) + case 0xbf: + { + Json result = typename Json::object(); + while (*pos != 0xff) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + pos = it_; + } + return result; + } + + // False + case 0xf4: + { + return Json(false); + } + + // True + case 0xf5: + { + return Json(true); + } + + // Null + case 0xf6: + { + return Json::null(); + } + + + case 0xf9: // Half-Precision Float (two-byte IEEE 754) + // FALLTHRU + case 0xfa: // Single-Precision Float (four-byte IEEE 754) + // FALLTHRU + case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + { + const uint8_t* endp; + double val = detail::get_double(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(endp-begin_)); + } + it_ = endp; + return Json(val); + } + + default: + { + JSONCONS_THROW(cbor_decode_error(end_-pos)); + } + } + } + + template<typename T> + Json get_fixed_length_array(const T len) + { + Json result = typename Json::array(); + result.reserve(len); + for (T i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + + template<typename T> + Json get_fixed_length_map(const T len) + { + Json result = typename Json::object(); + result.reserve(len); + for (T i = 0; i < len; ++i) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + } + return result; + } +}; + +template<class Json> +void encode_cbor(const Json& j, std::vector<uint8_t>& v) +{ + size_t n = 0; + cbor_Encoder_<Json>::encode(j,Calculate_size_(),n); + + v.reserve(n); + cbor_Encoder_<Json>::encode(j,Encode_cbor_(),v); +} + +template<class Json> +Json decode_cbor(const cbor_view& v) +{ + Decode_cbor_<Json> decoder(v.buffer(),v.buffer()+v.buflen()); + return decoder.decode(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class Json> +std::vector<uint8_t> encode_cbor(const Json& j) +{ + std::vector<uint8_t> v; + encode_cbor(j, v); + return v; +} +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_error_category.hpp new file mode 100644 index 00000000..0e986cda --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_error_category.hpp @@ -0,0 +1,70 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_ERROR_CATEGORY_HPP +#define JSONCONS_CSV_CSV_ERROR_CATEGORY_HPP + +#include <system_error> +#include <jsoncons/json_exception.hpp> + +namespace jsoncons { namespace csv { + + enum class csv_parser_errc : int + { + ok = 0, + unexpected_eof = 1, + expected_quote = 2, + invalid_csv_text = 3, + invalid_state = 4 + }; + +class csv_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "csv"; + } + virtual std::string message(int ev) const + { + switch (static_cast<csv_parser_errc>(ev)) + { + case csv_parser_errc::unexpected_eof: + return "Unexpected end of file"; + case csv_parser_errc::expected_quote: + return "Expected quote character"; + case csv_parser_errc::invalid_csv_text: + return "Invalid CSV text"; + default: + return "Unknown JSON parser error"; + } + } +}; + +inline +const std::error_category& csv_error_category() +{ + static csv_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(csv_parser_errc result) +{ + return std::error_code(static_cast<int>(result),csv_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::csv::csv_parser_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parameters.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parameters.hpp new file mode 100644 index 00000000..61b635f3 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parameters.hpp @@ -0,0 +1,635 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARAMETERS_HPP +#define JSONCONS_CSV_CSV_PARAMETERS_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <unordered_map> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> +#include <cwchar> + +namespace jsoncons { namespace csv { + +namespace detail { + JSONCONS_DEFINE_LITERAL(string_literal,"string") + JSONCONS_DEFINE_LITERAL(integer_literal,"integer") + JSONCONS_DEFINE_LITERAL(float_literal,"float") + JSONCONS_DEFINE_LITERAL(boolean_literal,"boolean") +} + +enum class csv_column_type +{ + string_t,integer_t,float_t,boolean_t,repeat_t +}; + +enum class quote_style_type +{ + all,minimal,none,nonnumeric +}; + +typedef quote_style_type quote_styles; + +enum class mapping_type +{ + n_rows, + n_objects, + m_columns +}; + +enum class column_state {sequence,label}; + +struct csv_type_info +{ + csv_type_info() = default; + csv_type_info(const csv_type_info&) = default; + csv_type_info(csv_type_info&&) = default; + + csv_type_info(csv_column_type ctype, size_t lev, size_t repcount = 0) + { + col_type = ctype; + level = lev; + rep_count = repcount; + } + + csv_column_type col_type; + size_t level; + size_t rep_count; +}; + +template <class CharT,class Allocator=std::allocator<CharT>> +class basic_csv_parameters +{ + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type> string_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<csv_type_info> csv_type_info_allocator_type; + + bool assume_header_; + bool ignore_empty_values_; + bool ignore_empty_lines_; + bool trim_leading_; + bool trim_trailing_; + bool trim_leading_inside_quotes_; + bool trim_trailing_inside_quotes_; + bool unquoted_empty_value_is_null_; + CharT field_delimiter_; + CharT quote_char_; + CharT quote_escape_char_; + CharT comment_starter_; + quote_style_type quote_style_; + std::pair<mapping_type,bool> mapping_; + unsigned long max_lines_; + size_t header_lines_; + string_type line_delimiter_; + bool infer_types_; + + std::vector<string_type,string_allocator_type> column_names_; + std::vector<csv_type_info,csv_type_info_allocator_type> column_types_; + std::vector<string_type,string_allocator_type> column_defaults_; +public: + static const size_t default_indent = 4; + +// Constructors + + basic_csv_parameters() + : + assume_header_(false), + ignore_empty_values_(false), + ignore_empty_lines_(true), + trim_leading_(false), + trim_trailing_(false), + trim_leading_inside_quotes_(false), + trim_trailing_inside_quotes_(false), + unquoted_empty_value_is_null_(false), + field_delimiter_(','), + quote_char_('\"'), + quote_escape_char_('\"'), + comment_starter_('\0'), + quote_style_(quote_style_type::minimal), + mapping_({mapping_type::n_rows,false}), + max_lines_((std::numeric_limits<unsigned long>::max)()), + header_lines_(0), + infer_types_(true) + { + line_delimiter_.push_back('\n'); + } + +// Properties + + size_t header_lines() const + { + return (assume_header_ && header_lines_ <= 1) ? 1 : header_lines_; + } + + basic_csv_parameters& header_lines(size_t value) + { + header_lines_ = value; + return *this; + } + + bool assume_header() const + { + return assume_header_; + } + + basic_csv_parameters& assume_header(bool value) + { + assume_header_ = value; + return *this; + } + + bool ignore_empty_values() const + { + return ignore_empty_values_; + } + + basic_csv_parameters& ignore_empty_values(bool value) + { + ignore_empty_values_ = value; + return *this; + } + + bool ignore_empty_lines() const + { + return ignore_empty_lines_; + } + + basic_csv_parameters& ignore_empty_lines(bool value) + { + ignore_empty_lines_ = value; + return *this; + } + + bool trim_leading() const + { + return trim_leading_; + } + + basic_csv_parameters& trim_leading(bool value) + { + trim_leading_ = value; + return *this; + } + + bool trim_trailing() const + { + return trim_trailing_; + } + + basic_csv_parameters& trim_trailing(bool value) + { + trim_trailing_ = value; + return *this; + } + + bool trim_leading_inside_quotes() const + { + return trim_leading_inside_quotes_; + } + + basic_csv_parameters& trim_leading_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + return *this; + } + + bool trim_trailing_inside_quotes() const + { + return trim_trailing_inside_quotes_; + } + + basic_csv_parameters& trim_trailing_inside_quotes(bool value) + { + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool trim() const + { + return trim_leading_ && trim_trailing_; + } + + basic_csv_parameters& trim(bool value) + { + trim_leading_ = value; + trim_trailing_ = value; + return *this; + } + + bool trim_inside_quotes() const + { + return trim_leading_inside_quotes_ && trim_trailing_inside_quotes_; + } + + basic_csv_parameters& trim_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool unquoted_empty_value_is_null() const + { + return unquoted_empty_value_is_null_; + } + + basic_csv_parameters& unquoted_empty_value_is_null(bool value) + { + unquoted_empty_value_is_null_ = value; + return *this; + } + + std::vector<string_type,string_allocator_type> column_names() const + { + return column_names_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_csv_parameters& column_names(const std::vector<string_type,string_allocator_type>& value) + { + column_names_ = value; + return *this; + } + + basic_csv_parameters& column_defaults(const std::vector<string_type,string_allocator_type>& value) + { + column_defaults_ = value; + return *this; + } + + basic_csv_parameters& column_types(const std::vector<string_type,string_allocator_type>& value) + { + if (value.size() > 0) + { + column_types_.reserve(value.size()); + for (size_t i = 0; i < value.size(); ++i) + { + if (value[i] == detail::string_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::string_t,0); + } + else if (value[i] == detail::integer_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::integer_t,0); + } + else if (value[i] == detail::float_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::float_t,0); + } + else if (value[i] == detail::boolean_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::boolean_t,0); + } + } + } + return *this; + } +#endif + basic_csv_parameters& column_names(const string_type& names) + { + column_names_ = parse_column_names(names); + return *this; + } + + std::vector<csv_type_info,csv_type_info_allocator_type> column_types() const + { + return column_types_; + } + + basic_csv_parameters& column_types(const string_type& types) + { + column_types_ = parse_column_types(types); + return *this; + } + + std::vector<string_type,string_allocator_type> column_defaults() const + { + return column_defaults_; + } + + basic_csv_parameters& column_defaults(const string_type& defaults) + { + column_defaults_ = parse_column_names(defaults); + return *this; + } + + CharT field_delimiter() const + { + return field_delimiter_; + } + + basic_csv_parameters& field_delimiter(CharT value) + { + field_delimiter_ = value; + return *this; + } + + string_type line_delimiter() const + { + return line_delimiter_; + } + + basic_csv_parameters& line_delimiter(string_type value) + { + line_delimiter_ = value; + return *this; + } + + CharT quote_char() const + { + return quote_char_; + } + + basic_csv_parameters& quote_char(CharT value) + { + quote_char_ = value; + return *this; + } + + bool infer_types() const + { + return infer_types_; + } + + basic_csv_parameters& infer_types(bool value) + { + infer_types_ = value; + return *this; + } + + CharT quote_escape_char() const + { + return quote_escape_char_; + } + + basic_csv_parameters& quote_escape_char(CharT value) + { + quote_escape_char_ = value; + return *this; + } + + CharT comment_starter() const + { + return comment_starter_; + } + + basic_csv_parameters& comment_starter(CharT value) + { + comment_starter_ = value; + return *this; + } + + quote_style_type quote_style() const + { + return quote_style_; + } + + mapping_type mapping() const + { + return mapping_.second ? (mapping_.first) : (assume_header() || column_names_.size() > 0 ? mapping_type::n_objects : mapping_type::n_rows); + } + + basic_csv_parameters& quote_style(quote_style_type value) + { + quote_style_ = value; + return *this; + } + + basic_csv_parameters& mapping(mapping_type value) + { + mapping_ = {value,true}; + return *this; + } + + unsigned long max_lines() const + { + return max_lines_; + } + + basic_csv_parameters& max_lines(unsigned long value) + { + max_lines_ = value; + return *this; + } + + static std::vector<string_type,string_allocator_type> parse_column_names(const string_type& names) + { + std::vector<string_type,string_allocator_type> column_names; + + column_state state = column_state::sequence; + string_type buffer; + + auto p = names.begin(); + while (p != names.end()) + { + switch (state) + { + case column_state::sequence: + { + switch (*p) + { + case ' ': case '\t':case '\r': case '\n': + ++p; + break; + default: + buffer.clear(); + state = column_state::label; + break; + } + break; + } + case column_state::label: + { + switch (*p) + { + case ',': + column_names.push_back(buffer); + buffer.clear(); + ++p; + state = column_state::sequence; + break; + default: + buffer.push_back(*p); + ++p; + break; + } + break; + } + } + } + if (state == column_state::label) + { + column_names.push_back(buffer); + buffer.clear(); + } + return column_names; + } + + static std::vector<csv_type_info,csv_type_info_allocator_type> parse_column_types(const string_type& types) + { + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,csv_column_type>> pair_allocator_type; + + const std::unordered_map<string_type,csv_column_type, std::hash<string_type>,std::equal_to<string_type>,pair_allocator_type> type_dictionary = + { + + {detail::string_literal<char_type>(),csv_column_type::string_t}, + {detail::integer_literal<char_type>(),csv_column_type::integer_t}, + {detail::float_literal<char_type>(),csv_column_type::float_t}, + {detail::boolean_literal<char_type>(),csv_column_type::boolean_t} + }; + + std::vector<csv_type_info,csv_type_info_allocator_type> column_types; + + column_state state = column_state::sequence; + int depth = 0; + string_type buffer; + + auto p = types.begin(); + while (p != types.end()) + { + switch (state) + { + case column_state::sequence: + { + switch (*p) + { + case ' ': case '\t':case '\r': case '\n': + ++p; + break; + case '[': + ++depth; + ++p; + break; + case ']': + JSONCONS_ASSERT(depth > 0); + --depth; + ++p; + break; + case '*': + { + JSONCONS_ASSERT(column_types.size() != 0); + size_t offset = 0; + size_t level = column_types.size() > 0 ? column_types.back().level: 0; + if (level > 0) + { + for (auto it = column_types.rbegin(); + it != column_types.rend() && level == it->level; + ++it) + { + ++offset; + } + } + else + { + offset = 1; + } + column_types.emplace_back(csv_column_type::repeat_t,depth,offset); + ++p; + break; + } + default: + buffer.clear(); + state = column_state::label; + break; + } + break; + } + case column_state::label: + { + switch (*p) + { + case '*': + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + state = column_state::sequence; + } + break; + case ',': + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + ++p; + state = column_state::sequence; + } + break; + case ']': + { + JSONCONS_ASSERT(depth > 0); + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + --depth; + ++p; + state = column_state::sequence; + } + break; + default: + { + buffer.push_back(*p); + ++p; + } + break; + } + break; + } + } + } + if (state == column_state::label) + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + } + return column_types; + } + +}; + +typedef basic_csv_parameters<char> csv_parameters; +typedef basic_csv_parameters<wchar_t> wcsv_parameters; + + +}} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parser.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parser.hpp new file mode 100644 index 00000000..c870c28b --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parser.hpp @@ -0,0 +1,1260 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARSER_HPP +#define JSONCONS_CSV_CSV_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <cctype> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons/json_reader.hpp> +#include <jsoncons/json_filter.hpp> +#include <jsoncons/json.hpp> +#include <jsoncons/detail/number_parsers.hpp> +#include <jsoncons_ext/csv/csv_error_category.hpp> +#include <jsoncons_ext/csv/csv_parameters.hpp> + +namespace jsoncons { namespace csv { + +enum class csv_mode_type +{ + initial, + header, + data +}; + +enum class csv_state_type +{ + start, + comment, + expect_value, + between_fields, + quoted_string, + unquoted_string, + escaped_value, + minus, + zero, + integer, + fraction, + exp1, + exp2, + exp3, + done +}; + +template<class CharT,class Allocator=std::allocator<CharT>> +class basic_csv_parser : private parsing_context +{ + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type> string_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<csv_mode_type> csv_mode_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<csv_type_info> csv_type_info_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::vector<string_type,string_allocator_type>> string_vector_allocator_type; + typedef basic_json<CharT,preserve_order_policy,Allocator> json_type; + + static const int default_depth = 3; + + default_parse_error_handler default_err_handler_; + csv_state_type state_; + int top_; + std::vector<csv_mode_type,csv_mode_allocator_type> stack_; + basic_json_input_handler<CharT>& handler_; + parse_error_handler& err_handler_; + size_t index_; + unsigned long column_; + unsigned long line_; + CharT curr_char_; + CharT prev_char_; + string_type value_buffer_; + int depth_; + basic_csv_parameters<CharT,Allocator> parameters_; + std::vector<string_type,string_allocator_type> column_names_; + std::vector<std::vector<string_type,string_allocator_type>,string_vector_allocator_type> column_values_; + std::vector<csv_type_info,csv_type_info_allocator_type> column_types_; + std::vector<string_type,string_allocator_type> column_defaults_; + size_t column_index_; + basic_json_fragment_filter<CharT> filter_; + size_t level_; + size_t offset_; + jsoncons::detail::string_to_double to_double_; + std::vector<json_decoder<json_type>> decoders_; + +public: + basic_csv_parser(basic_json_input_handler<CharT>& handler) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(default_err_handler_), + index_(0), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + basic_csv_parameters<CharT,Allocator> params) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(default_err_handler_), + index_(0), + parameters_(params), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(err_handler), + index_(0), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler, + basic_csv_parameters<CharT,Allocator> params) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(err_handler), + index_(0), + parameters_(params), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + ~basic_csv_parser() + { + } + + const parsing_context& parsing_context() const + { + return *this; + } + + bool done() const + { + return state_ == csv_state_type::done; + } + + const std::vector<std::basic_string<CharT>>& column_labels() const + { + return column_names_; + } + + void after_field() + { + ++column_index_; + } + + void before_record() + { + offset_ = 0; + if (stack_[top_] == csv_mode_type::data) + { + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + handler_.begin_array(*this); + break; + case mapping_type::n_objects: + handler_.begin_object(*this); + break; + case mapping_type::m_columns: + break; + default: + break; + } + } + } + + void after_record() + { + if (column_types_.size() > 0) + { + if (level_ > 0) + { + handler_.end_array(*this); + level_ = 0; + } + } + if (stack_[top_] == csv_mode_type::header) + { + if (line_ >= parameters_.header_lines()) + { + flip(csv_mode_type::header, csv_mode_type::data); + } + column_values_.resize(column_names_.size()); + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + if (column_names_.size() > 0) + { + handler_.begin_array(*this); + for (const auto& name : column_names_) + { + handler_.string_value(name, *this); + } + handler_.end_array(*this); + } + break; + case mapping_type::m_columns: + for (const auto& name : column_names_) + { + decoders_.push_back(json_decoder<json_type>()); + decoders_.back().begin_json(); + decoders_.back().begin_array(*this); + } + break; + default: + break; + } + } + else if (stack_[top_] == csv_mode_type::data) + { + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + handler_.end_array(*this); + break; + case mapping_type::n_objects: + handler_.end_object(*this); + break; + default: + break; + } + } + column_index_ = 0; + } + + void reset() + { + push_mode(csv_mode_type::initial); + handler_.begin_json(); + + for (auto name : parameters_.column_names()) + { + column_names_.emplace_back(name.data(),name.size()); + } + for (auto name : parameters_.column_types()) + { + column_types_.push_back(name); + } + for (auto name : parameters_.column_defaults()) + { + column_defaults_.emplace_back(name.data(), name.size()); + } + if (parameters_.header_lines() > 0) + { + push_mode(csv_mode_type::header); + } + else + { + push_mode(csv_mode_type::data); + } + if (parameters_.mapping() != mapping_type::m_columns) + { + handler_.begin_array(*this); + } + state_ = csv_state_type::expect_value; + column_index_ = 0; + prev_char_ = 0; + curr_char_ = 0; + column_ = 1; + level_ = 0; + } + + void parse(const CharT* p, size_t start, size_t length) + { + std::error_code ec; + parse(p, start, length, ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void parse(const CharT* p, size_t start, size_t length, std::error_code& ec) + { + index_ = start; + for (; index_ < length && state_ != csv_state_type::done; ++index_) + { + curr_char_ = p[index_]; +all_csv_states: + switch (state_) + { + case csv_state_type::comment: + if (curr_char_ == '\n') + { + state_ = csv_state_type::expect_value; + } + else if (prev_char_ == '\r') + { + state_ = csv_state_type::expect_value; + goto all_csv_states; + } + break; + case csv_state_type::expect_value: + if (column_ == 1 && curr_char_ == parameters_.comment_starter()) + { + state_ = csv_state_type::comment; + } + else + { + state_ = csv_state_type::unquoted_string; + goto all_csv_states; + } + break; + case csv_state_type::between_fields: + if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) + { + after_record(); + state_ = csv_state_type::expect_value; + } + else if (curr_char_ == parameters_.field_delimiter()) + { + state_ = csv_state_type::expect_value; + } + break; + case csv_state_type::escaped_value: + { + if (curr_char_ == parameters_.quote_char()) + { + value_buffer_.push_back(static_cast<CharT>(curr_char_)); + state_ = csv_state_type::quoted_string; + } + else if (parameters_.quote_escape_char() == parameters_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + state_ = csv_state_type::between_fields; + goto all_csv_states; + } + } + break; + case csv_state_type::quoted_string: + { + if (curr_char_ == parameters_.quote_escape_char()) + { + state_ = csv_state_type::escaped_value; + } + else if (curr_char_ == parameters_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + state_ = csv_state_type::between_fields; + } + else + { + value_buffer_.push_back(static_cast<CharT>(curr_char_)); + } + } + break; + case csv_state_type::unquoted_string: + { + if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) + { + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (!parameters_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + after_record(); + } + state_ = csv_state_type::expect_value; + } + else if (curr_char_ == '\n') + { + if (prev_char_ != '\r') + { + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (!parameters_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + after_record(); + } + state_ = csv_state_type::expect_value; + } + } + else if (curr_char_ == parameters_.field_delimiter()) + { + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + state_ = csv_state_type::expect_value; + } + else if (curr_char_ == parameters_.quote_char()) + { + value_buffer_.clear(); + state_ = csv_state_type::quoted_string; + } + else + { + value_buffer_.push_back(static_cast<CharT>(curr_char_)); + } + } + break; + default: + err_handler_.fatal_error(csv_parser_errc::invalid_state, *this); + ec = csv_parser_errc::invalid_state; + return; + } + if (line_ > parameters_.max_lines()) + { + state_ = csv_state_type::done; + } + switch (curr_char_) + { + case '\r': + ++line_; + column_ = 1; + break; + case '\n': + if (prev_char_ != '\r') + { + ++line_; + } + column_ = 1; + break; + default: + ++column_; + break; + } + prev_char_ = curr_char_; + } + } + + void end_parse() + { + std::error_code ec; + end_parse(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void end_parse(std::error_code& ec) + { + switch (state_) + { + case csv_state_type::unquoted_string: + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (!parameters_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + } + break; + case csv_state_type::escaped_value: + if (parameters_.quote_escape_char() == parameters_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + } + break; + default: + break; + } + if (column_index_ > 0) + { + after_record(); + } + switch (stack_[top_]) + { + case csv_mode_type::header: + pop_mode(csv_mode_type::header); + break; + case csv_mode_type::data: + pop_mode(csv_mode_type::data); + break; + default: + break; + } + if (parameters_.mapping() == mapping_type::m_columns) + { + basic_json_fragment_filter<CharT> fragment_filter(handler_); + handler_.begin_object(*this); + for (size_t i = 0; i < column_names_.size(); ++i) + { + handler_.name(column_names_[i],*this); + decoders_[i].end_array(*this); + decoders_[i].end_json(); + decoders_[i].get_result().dump_fragment(fragment_filter); + } + handler_.end_object(*this); + } + else + { + handler_.end_array(*this); + } + if (!pop_mode(csv_mode_type::initial)) + { + err_handler_.fatal_error(csv_parser_errc::unexpected_eof, *this); + ec = csv_parser_errc::unexpected_eof; + return; + } + handler_.end_json(); + } + + csv_state_type state() const + { + return state_; + } + + size_t index() const + { + return index_; + } +private: + + void trim_string_buffer(bool trim_leading, bool trim_trailing) + { + size_t start = 0; + size_t length = value_buffer_.length(); + if (trim_leading) + { + bool done = false; + while (!done && start < value_buffer_.length()) + { + if ((value_buffer_[start] < 256) && std::isspace(value_buffer_[start])) + { + ++start; + } + else + { + done = true; + } + } + } + if (trim_trailing) + { + bool done = false; + while (!done && length > 0) + { + if ((value_buffer_[length-1] < 256) && std::isspace(value_buffer_[length-1])) + { + --length; + } + else + { + done = true; + } + } + } + if (start != 0 || length != value_buffer_.size()) + { + value_buffer_ = value_buffer_.substr(start,length-start); + } + } + + void end_unquoted_string_value() + { + switch (stack_[top_]) + { + case csv_mode_type::header: + if (parameters_.assume_header() && line_ == 1) + { + column_names_.push_back(value_buffer_); + } + break; + case csv_mode_type::data: + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),handler_); + } + break; + case mapping_type::n_objects: + if (!(parameters_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + handler_.name(column_names_[column_index_ - offset_], *this); + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),handler_); + } + } + else if (level_ > 0) + { + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),handler_); + } + } + } + break; + case mapping_type::m_columns: + if (column_index_ < decoders_.size()) + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),decoders_[column_index_]); + } + break; + } + break; + default: + break; + } + state_ = csv_state_type::expect_value; + value_buffer_.clear(); + } + + void end_quoted_string_value(std::error_code& ec) + { + if (parameters_.trim_leading_inside_quotes() | parameters_.trim_trailing_inside_quotes()) + { + trim_string_buffer(parameters_.trim_leading_inside_quotes(),parameters_.trim_trailing_inside_quotes()); + } + switch (stack_[top_]) + { + case csv_mode_type::header: + if (parameters_.assume_header() && line_ == 1) + { + column_names_.push_back(value_buffer_); + } + break; + case csv_mode_type::data: + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + end_value(value_buffer_,column_index_,false,handler_); + break; + case mapping_type::n_objects: + if (!(parameters_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + handler_.name(column_names_[column_index_ - offset_], *this); + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,false,handler_); + } + } + else if (level_ > 0) + { + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,false,handler_); + } + } + } + break; + case mapping_type::m_columns: + if (column_index_ < decoders_.size()) + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),decoders_[column_index_]); + } + break; + } + break; + default: + err_handler_.fatal_error(csv_parser_errc::invalid_csv_text, *this); + ec = csv_parser_errc::invalid_csv_text; + return; + } + state_ = csv_state_type::expect_value; + value_buffer_.clear(); + } + + void end_value(const string_view_type& value, size_t column_index, bool infer_types, basic_json_input_handler<CharT>& handler) + { + if (column_index < column_types_.size() + offset_) + { + if (column_types_[column_index - offset_].col_type == csv_column_type::repeat_t) + { + offset_ = offset_ + column_types_[column_index - offset_].rep_count; + if (column_index - offset_ + 1 < column_types_.size()) + { + if (column_index == offset_ || level_ > column_types_[column_index-offset_].level) + { + handler.end_array(*this); + } + level_ = column_index == offset_ ? 0 : column_types_[column_index - offset_].level; + } + } + if (level_ < column_types_[column_index - offset_].level) + { + handler.begin_array(*this); + level_ = column_types_[column_index - offset_].level; + } + else if (level_ > column_types_[column_index - offset_].level) + { + handler.end_array(*this); + level_ = column_types_[column_index - offset_].level; + } + switch (column_types_[column_index - offset_].col_type) + { + case csv_column_type::integer_t: + { + std::istringstream iss{ std::string(value) }; + int64_t val; + iss >> val; + if (!iss.fail()) + { + handler.integer_value(val, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.null_value(*this); + } + } + } + break; + case csv_column_type::float_t: + { + std::istringstream iss{ std::string(value) }; + double val; + iss >> val; + if (!iss.fail()) + { + handler.double_value(val, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.null_value(*this); + } + } + } + break; + case csv_column_type::boolean_t: + { + if (value.length() == 1 && value[0] == '0') + { + handler.bool_value(false, *this); + } + else if (value.length() == 1 && value[0] == '1') + { + handler.bool_value(true, *this); + } + else if (value.length() == 5 && ((value[0] == 'f' || value[0] == 'F') && (value[1] == 'a' || value[1] == 'A') && (value[2] == 'l' || value[2] == 'L') && (value[3] == 's' || value[3] == 'S') && (value[4] == 'e' || value[4] == 'E'))) + { + handler.bool_value(false, *this); + } + else if (value.length() == 4 && ((value[0] == 't' || value[0] == 'T') && (value[1] == 'r' || value[1] == 'R') && (value[2] == 'u' || value[2] == 'U') && (value[3] == 'e' || value[3] == 'E'))) + { + handler.bool_value(true, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.null_value(*this); + } + } + } + break; + default: + if (value.length() > 0) + { + handler.string_value(value, *this); + } + else + { + if (column_index < column_defaults_.size() + offset_ && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.string_value(string_view_type(), *this); + } + } + break; + } + } + else + { + if (infer_types) + { + end_value_with_numeric_check(value, handler); + } + else + { + handler.string_value(value, *this); + } + } + } + + enum class numeric_check_state + { + initial, + null, + boolean_true, + boolean_false, + minus, + zero, + integer, + fraction1, + fraction, + exp1, + exp, + done + }; + + void end_value_with_numeric_check(const string_view_type& value, basic_json_input_handler<CharT>& handler) + { + numeric_check_state state = numeric_check_state::initial; + bool is_negative = false; + uint8_t precision = 0; + uint8_t decimal_places = 0; + chars_format format = chars_format::general; + + auto last = value.end(); + + std::string buffer; + for (auto p = value.begin(); state != numeric_check_state::done && p != last; ++p) + { + switch (state) + { + case numeric_check_state::initial: + { + switch (*p) + { + case 'n':case 'N': + if ((last-p) == 4 && (p[1] == 'u' || p[1] == 'U') && (p[2] == 'l' || p[2] == 'L') && (p[3] == 'l' || p[3] == 'L')) + { + state = numeric_check_state::null; + } + else + { + state = numeric_check_state::done; + } + break; + case 't':case 'T': + if ((last-p) == 4 && (p[1] == 'r' || p[1] == 'R') && (p[2] == 'u' || p[2] == 'U') && (p[3] == 'e' || p[3] == 'U')) + { + state = numeric_check_state::boolean_true; + } + else + { + state = numeric_check_state::done; + } + break; + case 'f':case 'F': + if ((last-p) == 5 && (p[1] == 'a' || p[1] == 'A') && (p[2] == 'l' || p[2] == 'L') && (p[3] == 's' || p[3] == 'S') && (p[4] == 'e' || p[4] == 'E')) + { + state = numeric_check_state::boolean_false; + } + else + { + state = numeric_check_state::done; + } + break; + case '-': + is_negative = true; + buffer.push_back(*p); + state = numeric_check_state::minus; + break; + case '0': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::zero: + { + switch (*p) + { + case '.': + buffer.push_back(to_double_.get_decimal_point()); + state = numeric_check_state::fraction1; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::integer: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + break; + case '.': + buffer.push_back(to_double_.get_decimal_point()); + state = numeric_check_state::fraction1; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::minus: + { + switch (*p) + { + case '0': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::fraction1: + { + format = chars_format::fixed; + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + ++decimal_places; + buffer.push_back(*p); + state = numeric_check_state::fraction; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::fraction: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + ++decimal_places; + buffer.push_back(*p); + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::exp1: + { + format = chars_format::scientific; + switch (*p) + { + case '-': + buffer.push_back(*p); + state = numeric_check_state::exp; + break; + case '+': + state = numeric_check_state::exp; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::exp: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + buffer.push_back(*p); + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + } + } + + switch (state) + { + case numeric_check_state::null: + handler.null_value(*this); + break; + case numeric_check_state::boolean_true: + handler.bool_value(true,*this); + break; + case numeric_check_state::boolean_false: + handler.bool_value(false,*this); + break; + case numeric_check_state::zero: + case numeric_check_state::integer: + { + if (is_negative) + { + jsoncons::detail::to_integer_result result = jsoncons::detail::to_integer(value.data(), value.length()); + if (!result.overflow) + { + handler.integer_value(result.value,*this); + } + else + { + double d = to_double_(buffer.data(), buffer.length()); + handler.double_value(d, number_format(format), *this); + } + } + else + { + jsoncons::detail::to_uinteger_result result = jsoncons::detail::to_uinteger(value.data(), value.length()); + if (!result.overflow) + { + handler.uinteger_value(result.value,*this); + } + else + { + double d = to_double_(buffer.data(), buffer.length()); + handler.double_value(d, number_format(format), *this); + } + } + break; + } + case numeric_check_state::fraction: + case numeric_check_state::exp: + { + double d = to_double_(buffer.data(), buffer.length()); + handler.double_value(d, number_format(format, precision, decimal_places), *this); + break; + } + default: + handler.string_value(value, *this); + } + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + void push_mode(csv_mode_type mode) + { + ++top_; + if (top_ >= depth_) + { + depth_ *= 2; + stack_.resize(depth_); + } + stack_[top_] = mode; + } + + int peek() + { + return stack_[top_]; + } + + bool peek(csv_mode_type mode) + { + return stack_[top_] == mode; + } + + bool flip(csv_mode_type mode1, csv_mode_type mode2) + { + if (top_ < 0 || stack_[top_] != mode1) + { + return false; + } + stack_[top_] = mode2; + return true; + } + + bool pop_mode(csv_mode_type mode) + { + if (top_ < 0 || stack_[top_] != mode) + { + return false; + } + --top_; + return true; + } +}; + +typedef basic_csv_parser<char> csv_parser; +typedef basic_csv_parser<wchar_t> wcsv_parser; + +}} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_reader.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_reader.hpp new file mode 100644 index 00000000..5834b1a0 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_reader.hpp @@ -0,0 +1,235 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_READER_HPP +#define JSONCONS_CSV_CSV_READER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons_ext/csv/csv_error_category.hpp> +#include <jsoncons_ext/csv/csv_parser.hpp> +#include <jsoncons/json.hpp> +#include <jsoncons/json_reader.hpp> +#include <jsoncons/json_decoder.hpp> +#include <jsoncons_ext/csv/csv_parameters.hpp> + +namespace jsoncons { namespace csv { + +template<class CharT,class Allocator=std::allocator<char>> +class basic_csv_reader +{ + struct stack_item + { + stack_item() + : array_begun_(false) + { + } + + bool array_begun_; + }; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + + basic_csv_reader(const basic_csv_reader&) = delete; + basic_csv_reader& operator = (const basic_csv_reader&) = delete; + + basic_csv_parser<CharT,Allocator> parser_; + std::basic_istream<CharT>& is_; + std::vector<CharT,char_allocator_type> buffer_; + size_t buffer_length_; + size_t buffer_position_; + bool eof_; + size_t index_; +public: + // Structural characters + static const size_t default_max_buffer_length = 16384; + //! Parse an input stream of CSV text into a json object + /*! + \param is The input stream to read from + */ + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler) + + : parser_(handler), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + basic_csv_parameters<CharT,Allocator> params) + + : parser_(handler,params), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : + parser_(handler,err_handler), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler, + basic_csv_parameters<CharT,Allocator> params) + : + parser_(handler,err_handler,params), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + ~basic_csv_reader() + { + } + + void read() + { + parser_.reset(); + while (!eof_ && !parser_.done()) + { + if (!(index_ < buffer_.size())) + { + if (!is_.eof()) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + is_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast<size_t>(is_.gcount())); + if (buffer_.size() == 0) + { + eof_ = true; + } + index_ = 0; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.parse(buffer_.data(),index_,buffer_.size()); + index_ = parser_.index(); + } + } + parser_.end_parse(); + } + + bool eof() const + { + return eof_; + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t buffer_capacity() const + { + return buffer_length_; + } + + void buffer_capacity(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } +#endif +}; + +template <class Json> +Json decode_csv(typename Json::string_view_type s) +{ + json_decoder<Json> decoder; + + basic_csv_parser<typename Json::char_type> parser(decoder); + parser.reset(); + parser.parse(s.data(), 0, s.size()); + parser.end_parse(); + return decoder.get_result(); +} + +template <class Json,class Allocator> +Json decode_csv(typename Json::string_view_type s, const basic_csv_parameters<typename Json::char_type,Allocator>& params) +{ + json_decoder<Json,Allocator> decoder; + + basic_csv_parser<typename Json::char_type,Allocator> parser(decoder, params); + parser.reset(); + parser.parse(s.data(), 0, s.size()); + parser.end_parse(); + return decoder.get_result(); +} + +template <class Json> +Json decode_csv(std::basic_istream<typename Json::char_type>& is) +{ + json_decoder<Json> decoder; + + basic_csv_reader<typename Json::char_type> reader(is,decoder); + reader.read(); + return decoder.get_result(); +} + +template <class Json,class Allocator> +Json decode_csv(std::basic_istream<typename Json::char_type>& is, const basic_csv_parameters<typename Json::char_type,Allocator>& params) +{ + json_decoder<Json,Allocator> decoder; + + basic_csv_reader<typename Json::char_type,Allocator> reader(is,decoder,params); + reader.read(); + return decoder.get_result(); +} + +typedef basic_csv_reader<char> csv_reader; +typedef basic_csv_reader<wchar_t> wcsv_reader; + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_serializer.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_serializer.hpp new file mode 100644 index 00000000..54c8035d --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_serializer.hpp @@ -0,0 +1,504 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_SERIALIZER_HPP +#define JSONCONS_CSV_CSV_SERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <ostream> +#include <cstdlib> +#include <unordered_map> +#include <memory> +#include <limits> // std::numeric_limits +#include <jsoncons/json_exception.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/detail/number_printers.hpp> +#include <jsoncons/detail/obufferedstream.hpp> +#include <jsoncons_ext/csv/csv_parameters.hpp> +#include <jsoncons/detail/writer.hpp> + +namespace jsoncons { namespace csv { + +template<class CharT,class Writer=jsoncons::detail::ostream_buffered_writer<CharT>,class Allocator=std::allocator<CharT>> +class basic_csv_serializer final : public basic_json_output_handler<CharT> +{ +public: + typedef typename Writer::output_type output_type; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT, std::char_traits<CharT>, char_allocator_type> string_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type> string_allocator_type; + + using typename basic_json_output_handler<CharT>::string_view_type ; +private: + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0) + { + } + bool is_object() const + { + return is_object_; + } + + bool is_object_; + size_t count_; + string_type name_; + }; + Writer writer_; + basic_csv_parameters<CharT,Allocator> parameters_; + basic_serialization_options<CharT> options_; + std::vector<stack_item> stack_; + jsoncons::detail::print_double fp_; + std::vector<string_type,string_allocator_type> column_names_; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,string_type>> string_string_allocator_type; + std::unordered_map<string_type,string_type, std::hash<string_type>,std::equal_to<string_type>,string_string_allocator_type> buffered_line_; + + // Noncopyable and nonmoveable + basic_csv_serializer(const basic_csv_serializer&) = delete; + basic_csv_serializer& operator=(const basic_csv_serializer&) = delete; +public: + basic_csv_serializer(output_type& os) + : + writer_(os), + options_(), + stack_(), + fp_(options_.precision()), + column_names_(parameters_.column_names()) + { + } + + basic_csv_serializer(output_type& os, + const basic_csv_parameters<CharT,Allocator>& params) + : + writer_(os), + parameters_(params), + options_(), + stack_(), + fp_(options_.precision()), + column_names_(parameters_.column_names()) + { + } + +private: + + template<class AnyWriter> + void escape_string(const CharT* s, + size_t length, + CharT quote_char, CharT quote_escape_char, + AnyWriter& writer) + { + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + if (c == quote_char) + { + writer.put(quote_escape_char); + writer.put(quote_char); + } + else + { + writer.put(c); + } + } + } + + void do_begin_json() override + { + } + + void do_end_json() override + { + writer_.flush(); + } + + void do_begin_object() override + { + stack_.push_back(stack_item(true)); + } + + void do_end_object() override + { + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + writer_.put(parameters_.field_delimiter()); + } + writer_.write(column_names_[i]); + } + writer_.write(parameters_.line_delimiter()); + } + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + writer_.put(parameters_.field_delimiter()); + } + auto it = buffered_line_.find(column_names_[i]); + if (it != buffered_line_.end()) + { + writer_.write(it->second); + it->second.clear(); + } + } + writer_.write(parameters_.line_delimiter()); + } + stack_.pop_back(); + + end_value(); + } + + void do_begin_array() override + { + stack_.push_back(stack_item(false)); + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + writer_.put(parameters_.field_delimiter()); + } + writer_.write(column_names_[i]); + } + if (column_names_.size() > 0) + { + writer_.write(parameters_.line_delimiter()); + } + } + } + } + + void do_end_array() override + { + if (stack_.size() == 2) + { + writer_.write(parameters_.line_delimiter()); + } + stack_.pop_back(); + + end_value(); + } + + void do_name(const string_view_type& name) override + { + if (stack_.size() == 2) + { + stack_.back().name_ = string_type(name); + buffered_line_[string_type(name)] = std::basic_string<CharT>(); + if (stack_[0].count_ == 0 && parameters_.column_names().size() == 0) + { + column_names_.push_back(string_type(name)); + } + } + } + + template <class AnyWriter> + void write_string(const CharT* s, size_t length, AnyWriter& writer) + { + bool quote = false; + if (parameters_.quote_style() == quote_style_type::all || parameters_.quote_style() == quote_style_type::nonnumeric || + (parameters_.quote_style() == quote_style_type::minimal && + (std::char_traits<CharT>::find(s, length, parameters_.field_delimiter()) != nullptr || std::char_traits<CharT>::find(s, length, parameters_.quote_char()) != nullptr))) + { + quote = true; + writer.put(parameters_.quote_char()); + } + escape_string(s, length, parameters_.quote_char(), parameters_.quote_escape_char(), writer); + if (quote) + { + writer.put(parameters_.quote_char()); + } + + } + + void do_null_value() override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + do_null_value(bo); + bo.flush(); + it->second = s; + } + } + else + { + do_null_value(writer_); + } + } + } + + void do_string_value(const string_view_type& val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_byte_string_value(const uint8_t*, size_t) override + { + + } + + void do_double_value(double val, const number_format&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_integer_value(int64_t val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_uinteger_value(uint64_t val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_bool_value(bool val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + template <class AnyWriter> + void value(const string_view_type& value, AnyWriter& writer) + { + begin_value(writer); + write_string(value.data(),value.length(),writer); + end_value(); + } + + template <class AnyWriter> + void value(double val, AnyWriter& writer) + { + begin_value(writer); + + if ((std::isnan)(val)) + { + writer.write(options_.nan_replacement()); + } + else if (val == std::numeric_limits<double>::infinity()) + { + writer.write(options_.pos_inf_replacement()); + } + else if (!(std::isfinite)(val)) + { + writer.write(options_.neg_inf_replacement()); + } + else + { + fp_(val,options_.precision(),writer); + } + + end_value(); + + } + + template <class AnyWriter> + void value(int64_t val, AnyWriter& writer) + { + begin_value(writer); + + std::basic_ostringstream<CharT> ss; + ss << val; + writer.write(ss.str()); + + end_value(); + } + + template <class AnyWriter> + void value(uint64_t val, AnyWriter& writer) + { + begin_value(writer); + + std::basic_ostringstream<CharT> ss; + ss << val; + writer.write(ss.str()); + + end_value(); + } + + template <class AnyWriter> + void value(bool val, AnyWriter& writer) + { + begin_value(writer); + + if (val) + { + auto buf = jsoncons::detail::true_literal<CharT>(); + writer.write(buf,4); + } + else + { + auto buf = jsoncons::detail::false_literal<CharT>(); + writer.write(buf,5); + } + + end_value(); + } + + template <class AnyWriter> + void do_null_value(AnyWriter& writer) + { + begin_value(writer); + auto buf = jsoncons::detail::null_literal<CharT>(); + writer.write(buf,4); + end_value(); + + } + + template <class AnyWriter> + void begin_value(AnyWriter& writer) + { + if (!stack_.empty()) + { + if (!stack_.back().is_object_ && stack_.back().count_ > 0) + { + writer.put(parameters_.field_delimiter()); + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +template <class Json> +void encode_csv(const Json& j, std::basic_ostream<typename Json::char_type>& os) +{ + typedef typename Json::char_type char_type; + basic_csv_serializer<char_type> serializer(os); + j.dump(serializer); +} + +template <class Json,class Allocator> +void encode_csv(const Json& j, std::basic_ostream<typename Json::char_type>& os, const basic_csv_parameters<typename Json::char_type,Allocator>& params) +{ + typedef typename Json::char_type char_type; + basic_csv_serializer<char_type,jsoncons::detail::ostream_buffered_writer<char_type>,Allocator> serializer(os,params); + j.dump(serializer); +} + +typedef basic_csv_serializer<char> csv_serializer; + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch.hpp new file mode 100644 index 00000000..f6997001 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch.hpp @@ -0,0 +1,530 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPATCH_HPP +#define JSONCONS_JSONPOINTER_JSONPATCH_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/jsonpointer/jsonpointer.hpp> +#include <jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp> + +namespace jsoncons { namespace jsonpatch { + +class jsonpatch_error : public std::exception, public virtual json_exception +{ +public: + jsonpatch_error(const std::error_code& ec) + : error_code_(ec) + { + } + jsonpatch_error(const jsonpatch_error& other) = default; + + jsonpatch_error(jsonpatch_error&& other) = default; + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + const_cast<std::string&>(buffer_) = error_code_.message(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + jsonpatch_error& operator=(const jsonpatch_error& e) = default; + jsonpatch_error& operator=(jsonpatch_error&& e) = default; +private: + std::string buffer_; + std::error_code error_code_; +}; + +namespace detail { + + JSONCONS_DEFINE_LITERAL(test_literal,"test") + JSONCONS_DEFINE_LITERAL(add_literal,"add") + JSONCONS_DEFINE_LITERAL(remove_literal,"remove") + JSONCONS_DEFINE_LITERAL(replace_literal,"replace") + JSONCONS_DEFINE_LITERAL(move_literal,"move") + JSONCONS_DEFINE_LITERAL(copy_literal,"copy") + JSONCONS_DEFINE_LITERAL(op_literal,"op") + JSONCONS_DEFINE_LITERAL(path_literal,"path") + JSONCONS_DEFINE_LITERAL(from_literal,"from") + JSONCONS_DEFINE_LITERAL(value_literal,"value") + + enum class op_type {add,remove,replace}; + enum class state_type {begin,abort,commit}; + + template <class Json> + struct operation_unwinder + { + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + struct entry + { + op_type op; + string_type path; + Json value; + }; + + Json& target; + state_type state; + std::vector<entry> stack; + + operation_unwinder(Json& j) + : target(j), state(state_type::begin) + { + } + + ~operation_unwinder() + { + std::error_code ec; + //std::cout << "state: " << std::boolalpha << (state == state_type::commit) << ", stack size: " << stack.size() << std::endl; + if (state != state_type::commit) + { + for (auto it = stack.rbegin(); it != stack.rend(); ++it) + { + if (it->op == op_type::add) + { + jsonpointer::insert_or_assign(target,it->path,it->value,ec); + if (ec) + { + //std::cout << "add: " << it->path << std::endl; + break; + } + } + else if (it->op == op_type::remove) + { + jsonpointer::remove(target,it->path,ec); + if (ec) + { + //std::cout << "remove: " << it->path << std::endl; + break; + } + } + else if (it->op == op_type::replace) + { + jsonpointer::replace(target,it->path,it->value,ec); + if (ec) + { + //std::cout << "replace: " << it->path << std::endl; + break; + } + } + } + } + } + }; + + template <class Json> + Json from_diff(const Json& source, const Json& target, const typename Json::string_type& path) + { + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + Json result = typename Json::array(); + + if (source == target) + { + return result; + } + + if (source.is_array() && target.is_array()) + { + size_t common = (std::min)(source.size(),target.size()); + for (size_t i = 0; i < common; ++i) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/' << i; + auto temp_diff = from_diff(source[i],target[i],ss.str()); + result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); + } + // Element in source, not in target - remove + for (size_t i = target.size(); i < source.size(); ++i) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/' << i; + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), remove_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + result.push_back(std::move(val)); + } + // Element in target, not in source - add, + // Fix contributed by Alexander rog13 + for (size_t i = source.size(); i < target.size(); ++i) + { + const auto& a = target[i]; + std::basic_ostringstream<char_type> ss; + ss << path << '/' << i; + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), add_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + val.insert_or_assign(value_literal<char_type>(), a); + result.push_back(std::move(val)); + } + } + else if (source.is_object() && target.is_object()) + { + for (const auto& a : source.object_range()) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/'; + jsonpointer::escape(a.key(),ss); + auto it = target.find(a.key()); + if (it != target.object_range().end()) + { + auto temp_diff = from_diff(a.value(),it->value(),ss.str()); + result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); + } + else + { + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), remove_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + result.push_back(std::move(val)); + } + } + for (const auto& a : target.object_range()) + { + auto it = source.find(a.key()); + if (it == source.object_range().end()) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/'; + jsonpointer::escape(a.key(),ss); + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), add_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + val.insert_or_assign(value_literal<char_type>(), a.value()); + result.push_back(std::move(val)); + } + } + } + else + { + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), replace_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), path); + val.insert_or_assign(value_literal<char_type>(), target); + result.push_back(std::move(val)); + } + + return result; + } +} + +template <class Json> +void apply_patch(Json& target, const Json& patch, std::error_code& patch_ec) +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + detail::operation_unwinder<Json> unwinder(target); + + // Validate + + string_type bad_path; + for (const auto& operation : patch.array_range()) + { + unwinder.state = detail::state_type::begin; + + if (operation.count(detail::op_literal<char_type>()) != 1 || operation.count(detail::path_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + const string_view_type op = operation.at(detail::op_literal<char_type>()).as_string_view(); + const string_view_type path = operation.at(detail::path_literal<char_type>()).as_string_view(); + + if (op == detail::test_literal<char_type>()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::test_failed; + unwinder.state = detail::state_type::abort; + } + else if (operation.count(detail::value_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else if (val != operation.at(detail::value_literal<char_type>())) + { + patch_ec = jsonpatch_errc::test_failed; + unwinder.state = detail::state_type::abort; + } + } + else if (op == detail::add_literal<char_type>()) + { + if (operation.count(detail::value_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code insert_ec; + Json val = operation.at(detail::value_literal<char_type>()); + auto npath = jsonpointer::normalized_path(target,path); + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath,select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::add_failed; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target,npath,val,replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::add_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::replace,npath,orig_val}); + } + } + } + else // insert without replace succeeded + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + else if (op == detail::remove_literal<char_type>()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::remove_failed; + unwinder.state = detail::state_type::abort; + } + else + { + jsonpointer::remove(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::remove_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::add,string_type(path),val}); + } + } + } + else if (op == detail::replace_literal<char_type>()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::replace_failed; + unwinder.state = detail::state_type::abort; + } + else if (operation.count(detail::value_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + jsonpointer::replace(target,path,operation.at(detail::value_literal<char_type>()),ec); + if (ec) + { + patch_ec = jsonpatch_errc::replace_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::replace,string_type(path),val}); + } + } + } + else if (op == detail::move_literal<char_type>()) + { + if (operation.count(detail::from_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + string_view_type from = operation.at(detail::from_literal<char_type>()).as_string_view(); + std::error_code ec; + Json val = jsonpointer::get(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::move_failed; + unwinder.state = detail::state_type::abort; + } + else + { + jsonpointer::remove(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::move_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::add,string_type(from),val}); + // add + std::error_code insert_ec; + auto npath = jsonpointer::normalized_path(target,path); + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath,select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target, npath, val, replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + + } + else + { + unwinder.stack.push_back({ detail::op_type::replace,npath,orig_val }); + } + + } + } + else + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + } + } + else if (op == detail::copy_literal<char_type>()) + { + if (operation.count(detail::from_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code ec; + string_view_type from = operation.at(detail::from_literal<char_type>()).as_string_view(); + Json val = jsonpointer::get(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + // add + auto npath = jsonpointer::normalized_path(target,path); + std::error_code insert_ec; + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // Failed, try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath, select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target, npath, val,replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({ detail::op_type::replace,npath,orig_val }); + } + } + } + else + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + } + if (unwinder.state != detail::state_type::begin) + { + bad_path = string_type(path); + } + } + if (unwinder.state != detail::state_type::begin) + { + break; + } + } + if (unwinder.state == detail::state_type::begin) + { + unwinder.state = detail::state_type::commit; + } +} + +template <class Json> +Json from_diff(const Json& source, const Json& target) +{ + typename Json::string_type path; + return detail::from_diff(source, target, path); +} + +template <class Json> +void apply_patch(Json& target, const Json& patch) +{ + std::error_code ec; + apply_patch(target, patch, ec); + if (ec) + { + JSONCONS_THROW(jsonpatch_error(ec)); + } +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp new file mode 100644 index 00000000..6e566fc1 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp @@ -0,0 +1,82 @@ +/// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATCH_JSONPATCH_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPATCH_JSONPATCH_ERROR_CATEGORY_HPP + +#include <jsoncons/json_exception.hpp> +#include <system_error> + +namespace jsoncons { namespace jsonpatch { + +enum class jsonpatch_errc +{ + ok = 0, + invalid_patch = 1, + test_failed, + add_failed, + remove_failed, + replace_failed, + move_failed, + copy_failed + +}; + +class jsonpatch_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsonpatch"; + } + virtual std::string message(int ev) const + { + switch (static_cast<jsonpatch_errc>(ev)) + { + case jsonpatch_errc::invalid_patch: + return "Invalid JSON Patch document"; + case jsonpatch_errc::test_failed: + return "JSON Patch test operation failed"; + case jsonpatch_errc::add_failed: + return "JSON Patch add operation failed"; + case jsonpatch_errc::remove_failed: + return "JSON Patch remove operation failed"; + case jsonpatch_errc::replace_failed: + return "JSON Patch replace operation failed"; + case jsonpatch_errc::move_failed: + return "JSON Patch move operation failed"; + case jsonpatch_errc::copy_failed: + return "JSON Patch copy operation failed"; + default: + return "Unknown JSON Patch error"; + } + } +}; + +inline +const std::error_category& jsonpatch_error_category() +{ + static jsonpatch_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpatch_errc result) +{ + return std::error_code(static_cast<int>(result),jsonpatch_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::jsonpatch::jsonpatch_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp new file mode 100644 index 00000000..b042bbbb --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp @@ -0,0 +1,1119 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONQUERY_HPP +#define JSONCONS_JSONPATH_JSONQUERY_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include "jsonpath_filter.hpp" +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { + +enum class result_type {value,path}; + +template<class Json> +Json json_query(const Json& root, const typename Json::string_view_type& path, result_type result_t = result_type::value) +{ + if (result_t == result_type::value) + { + detail::jsonpath_evaluator<Json,const Json&,detail::VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(root,path.data(),path.length()); + return evaluator.get_values(); + } + else + { + detail::jsonpath_evaluator<Json,const Json&,detail::PathConstructor<Json>> evaluator; + evaluator.evaluate(root,path.data(),path.length()); + return evaluator.get_normalized_paths(); + } +} + +template<class Json, class T> +void json_replace(Json& root, const typename Json::string_view_type& path, T&& new_value) +{ + detail::jsonpath_evaluator<Json,Json&,detail::VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(root,path.data(),path.length()); + evaluator.replace(std::forward<T>(new_value)); +} + +namespace detail { + +template<class CharT> +bool try_string_to_index(const CharT *s, size_t length, size_t* value, bool* positive) +{ + static const size_t max_value = (std::numeric_limits<size_t>::max)(); + static const size_t max_value_div_10 = max_value / 10; + + size_t start = 0; + size_t n = 0; + if (length > 0) + { + if (s[start] == '-') + { + *positive = false; + ++start; + } + else + { + *positive = true; + } + } + if (length > start) + { + for (size_t i = start; i < length; ++i) + { + CharT c = s[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + { + size_t x = c - '0'; + if (n > max_value_div_10) + { + return false; + } + n = n * 10; + if (n > max_value - x) + { + return false; + } + + n += x; + } + break; + default: + return false; + break; + } + } + *value = n; + return true; + } + else + { + return false; + } +} + +enum class path_state +{ + start, + cr, + lf, + expect_dot_or_left_bracket, + expect_unquoted_name_or_left_bracket, + unquoted_name, + left_bracket_single_quoted_string, + left_bracket_double_quoted_string, + left_bracket, + left_bracket_start, + left_bracket_end, + left_bracket_end2, + left_bracket_step, + left_bracket_step2, + expect_comma_or_right_bracket, + dot +}; + +template<class Json, + class JsonReference=const Json&, + class PathCons=PathConstructor<Json>> +class jsonpath_evaluator : private parsing_context +{ +private: + typedef typename Json::char_type char_type; + typedef typename Json::char_traits_type char_traits_type; + typedef std::basic_string<char_type,char_traits_type> string_type; + typedef typename Json::string_view_type string_view_type; + typedef JsonReference reference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + struct node_type + { + node_type() = default; + node_type(const string_type& p, const pointer& valp) + : skip_contained_object(false),path(p),val_ptr(valp) + { + } + node_type(string_type&& p, pointer&& valp) + : skip_contained_object(false),path(std::move(p)),val_ptr(valp) + { + } + node_type(const node_type&) = default; + node_type(node_type&&) = default; + + bool skip_contained_object; + string_type path; + pointer val_ptr; + }; + typedef std::vector<node_type> node_set; + + static string_view_type length_literal() + { + static const char_type data[] = {'l','e','n','g','t','h'}; + return string_view_type{data,sizeof(data)/sizeof(char_type)}; + } + + class selector + { + public: + virtual ~selector() + { + } + virtual void select(node_type& node, const string_type& path, reference val, + node_set& nodes, std::vector<std::shared_ptr<Json>>& temp_json_values) = 0; + }; + + class expr_selector final : public selector + { + private: + jsonpath_filter_expr<Json> result_; + public: + expr_selector(const jsonpath_filter_expr<Json>& result) + : result_(result) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, std::vector<std::shared_ptr<Json>>& temp_json_values) override + { + auto index = result_.eval(val); + if (index.template is<size_t>()) + { + size_t start = index. template as<size_t>(); + if (val.is_array() && start < val.size()) + { + nodes.emplace_back(PathCons()(path,start),std::addressof(val[start])); + } + } + else if (index.is_string()) + { + name_selector selector(index.as_string_view(),true); + selector.select(node, path, val, nodes, temp_json_values); + } + } + }; + + class filter_selector final : public selector + { + private: + jsonpath_filter_expr<Json> result_; + public: + filter_selector(const jsonpath_filter_expr<Json>& result) + : result_(result) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, std::vector<std::shared_ptr<Json>>&) override + { + if (val.is_array()) + { + node.skip_contained_object =true; + for (size_t i = 0; i < val.size(); ++i) + { + if (result_.exists(val[i])) + { + nodes.emplace_back(PathCons()(path,i),std::addressof(val[i])); + } + } + } + else if (val.is_object()) + { + if (!node.skip_contained_object) + { + if (result_.exists(val)) + { + nodes.emplace_back(path, std::addressof(val)); + } + } + else + { + node.skip_contained_object = false; + } + } + } + }; + + class name_selector final : public selector + { + private: + string_type name_; + bool positive_start_; + public: + name_selector(const string_view_type& name, bool positive_start) + : name_(name), positive_start_(positive_start) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, + std::vector<std::shared_ptr<Json>>& temp_json_values) override + { + if (val.is_object() && val.count(name_) > 0) + { + nodes.emplace_back(PathCons()(path,name_),std::addressof(val.at(name_))); + } + else if (val.is_array()) + { + size_t pos = 0; + if (try_string_to_index(name_.data(), name_.size(), &pos, &positive_start_)) + { + size_t index = positive_start_ ? pos : val.size() - pos; + if (index < val.size()) + { + nodes.emplace_back(PathCons()(path,index),std::addressof(val[index])); + } + } + else if (name_ == length_literal() && val.size() > 0) + { + auto temp = std::make_shared<Json>(val.size()); + temp_json_values.push_back(temp); + nodes.emplace_back(PathCons()(path,name_),temp.get()); + } + } + else if (val.is_string()) + { + size_t pos = 0; + string_view_type sv = val.as_string_view(); + if (try_string_to_index(name_.data(), name_.size(), &pos, &positive_start_)) + { + size_t index = positive_start_ ? pos : sv.size() - pos; + auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), index); + if (sequence.length() > 0) + { + auto temp = std::make_shared<Json>(sequence.begin(),sequence.length()); + temp_json_values.push_back(temp); + nodes.emplace_back(PathCons()(path,index),temp.get()); + } + } + else if (name_ == length_literal() && sv.size() > 0) + { + size_t count = unicons::u32_length(sv.begin(),sv.end()); + auto temp = std::make_shared<Json>(count); + temp_json_values.push_back(temp); + nodes.emplace_back(PathCons()(path,name_),temp.get()); + } + } + } + }; + + class array_slice_selector final : public selector + { + private: + size_t start_; + bool positive_start_; + size_t end_; + bool positive_end_; + bool undefined_end_; + size_t step_; + bool positive_step_; + public: + array_slice_selector(size_t start, bool positive_start, + size_t end, bool positive_end, + size_t step, bool positive_step, + bool undefined_end) + : start_(start), positive_start_(positive_start), + end_(end), positive_end_(positive_end),undefined_end_(undefined_end), + step_(step), positive_step_(positive_step) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, + std::vector<std::shared_ptr<Json>>&) override + { + if (positive_step_) + { + end_array_slice1(path, val, nodes); + } + else + { + end_array_slice2(path, val, nodes); + } + } + + void end_array_slice1(const string_type& path, reference val, node_set& nodes) + { + if (val.is_array()) + { + size_t start = positive_start_ ? start_ : val.size() - start_; + size_t end; + if (!undefined_end_) + { + end = positive_end_ ? end_ : val.size() - end_; + } + else + { + end = val.size(); + } + for (size_t j = start; j < end; j += step_) + { + if (j < val.size()) + { + nodes.emplace_back(PathCons()(path,j),std::addressof(val[j])); + } + } + } + } + + void end_array_slice2(const string_type& path, reference val, node_set& nodes) + { + if (val.is_array()) + { + size_t start = positive_start_ ? start_ : val.size() - start_; + size_t end; + if (!undefined_end_) + { + end = positive_end_ ? end_ : val.size() - end_; + } + else + { + end = val.size(); + } + + size_t j = end + step_ - 1; + while (j > (start+step_-1)) + { + j -= step_; + if (j < val.size()) + { + nodes.emplace_back(PathCons()(path,j),std::addressof(val[j])); + } + } + } + } + }; + + default_parse_error_handler default_err_handler_; + parse_error_handler *err_handler_; + path_state state_; + string_type buffer_; + size_t start_; + bool positive_start_; + size_t end_; + bool positive_end_; + bool undefined_end_; + size_t step_; + bool positive_step_; + bool recursive_descent_; + node_set nodes_; + std::vector<node_set> stack_; + std::vector<std::shared_ptr<Json>> temp_json_values_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + std::vector<std::shared_ptr<selector>> selectors_; + +public: + jsonpath_evaluator() + : err_handler_(&default_err_handler_), + state_(path_state::start), + start_(0), positive_start_(true), + end_(0), positive_end_(true), undefined_end_(false), + step_(0), positive_step_(true), + recursive_descent_(false), + line_(0), column_(0), + begin_input_(nullptr), end_input_(nullptr), + p_(nullptr) + { + } + + Json get_values() const + { + Json result = typename Json::array(); + + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(*(p.val_ptr)); + } + } + return result; + } + + Json get_normalized_paths() const + { + Json result = typename Json::array(); + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(p.path); + } + } + return result; + } + + template <class T> + void replace(T&& new_value) + { + if (stack_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + *(stack_.back()[i].val_ptr) = new_value; + } + } + } + + void evaluate(reference root, const string_view_type& path) + { + evaluate(root,path.data(),path.length()); + } + void evaluate(reference root, const char_type* path) + { + evaluate(root,path,char_traits_type::length(path)); + } + + void evaluate(reference root, + const char_type* path, + size_t length) + { + std::error_code ec; + evaluate(root, path, length, ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void evaluate(reference root, + const char_type* path, + size_t length, + std::error_code& ec) + { + path_state pre_line_break_state = path_state::start; + + begin_input_ = path; + end_input_ = path + length; + p_ = begin_input_; + + line_ = 1; + column_ = 1; + state_ = path_state::start; + + recursive_descent_ = false; + + clear_index(); + + while (p_ < end_input_) + { + switch (state_) + { + case path_state::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_ = pre_line_break_state; + ++p_; + ++column_; + break; + default: + state_ = pre_line_break_state; + break; + } + break; + case path_state::lf: + ++line_; + column_ = 1; + state_ = pre_line_break_state; + break; + case path_state::start: + switch (*p_) + { + case ' ':case '\t': + break; + case '$': + case '@': + { + string_type s; + s.push_back('$'); + node_set v; + v.emplace_back(std::move(s),std::addressof(root)); + stack_.push_back(v); + + state_ = path_state::expect_dot_or_left_bracket; + } + break; + default: + err_handler_->fatal_error(jsonpath_parser_errc::expected_root, *this); + ec = jsonpath_parser_errc::expected_root; + return; + }; + ++p_; + ++column_; + break; + case path_state::dot: + switch (*p_) + { + case '.': + recursive_descent_ = true; + ++p_; + ++column_; + state_ = path_state::expect_unquoted_name_or_left_bracket; + break; + default: + state_ = path_state::expect_unquoted_name_or_left_bracket; + break; + } + break; + case path_state::expect_unquoted_name_or_left_bracket: + switch (*p_) + { + case '.': + err_handler_->fatal_error(jsonpath_parser_errc::expected_name, *this); + ec = jsonpath_parser_errc::expected_name; + return; + case '*': + end_all(); + transfer_nodes(); + state_ = path_state::expect_dot_or_left_bracket; + ++p_; + ++column_; + break; + case '[': + state_ = path_state::left_bracket; + ++p_; + ++column_; + break; + default: + buffer_.clear(); + state_ = path_state::unquoted_name; + break; + } + break; + case path_state::expect_dot_or_left_bracket: + switch (*p_) + { + case ' ':case '\t': + break; + case '.': + state_ = path_state::dot; + break; + case '[': + state_ = path_state::left_bracket; + break; + default: + err_handler_->fatal_error(jsonpath_parser_errc::expected_separator, *this); + ec = jsonpath_parser_errc::expected_separator; + return; + }; + ++p_; + ++column_; + break; + case path_state::expect_comma_or_right_bracket: + switch (*p_) + { + case ',': + state_ = path_state::left_bracket; + break; + case ']': + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + case ' ':case '\t': + break; + default: + err_handler_->fatal_error(jsonpath_parser_errc::expected_right_bracket, *this); + ec = jsonpath_parser_errc::expected_right_bracket; + return; + } + ++p_; + ++column_; + break; + case path_state::left_bracket: + switch (*p_) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + case '(': + { + jsonpath_filter_parser<Json> parser(line_,column_); + auto result = parser.parse(root, p_,end_input_,&p_); + line_ = parser.line(); + column_ = parser.column(); + selectors_.push_back(std::make_shared<expr_selector>(result)); + state_ = path_state::expect_comma_or_right_bracket; + } + break; + case '?': + { + jsonpath_filter_parser<Json> parser(line_,column_); + auto result = parser.parse(root,p_,end_input_,&p_); + line_ = parser.line(); + column_ = parser.column(); + selectors_.push_back(std::make_shared<filter_selector>(result)); + state_ = path_state::expect_comma_or_right_bracket; + } + break; + case ':': + clear_index(); + state_ = path_state::left_bracket_end; + ++p_; + ++column_; + break; + case '*': + end_all(); + state_ = path_state::expect_comma_or_right_bracket; + ++p_; + ++column_; + break; + case '\'': + state_ = path_state::left_bracket_single_quoted_string; + ++p_; + ++column_; + break; + case '\"': + state_ = path_state::left_bracket_double_quoted_string; + ++p_; + ++column_; + break; + default: + clear_index(); + buffer_.push_back(*p_); + state_ = path_state::left_bracket_start; + ++p_; + ++column_; + break; + } + break; + case path_state::left_bracket_start: + switch (*p_) + { + case ':': + if (!try_string_to_index(buffer_.data(), buffer_.size(), &start_, &positive_start_)) + { + err_handler_->fatal_error(jsonpath_parser_errc::expected_index, *this); + ec = jsonpath_parser_errc::expected_index; + return; + } + state_ = path_state::left_bracket_end; + break; + case ',': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + default: + buffer_.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_end: + switch (*p_) + { + case '-': + positive_end_ = false; + state_ = path_state::left_bracket_end2; + break; + case ':': + step_ = 0; + state_ = path_state::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + undefined_end_ = false; + end_ = static_cast<size_t>(*p_-'0'); + state_ = path_state::left_bracket_end2; + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_end2: + switch (*p_) + { + case ':': + step_ = 0; + state_ = path_state::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + undefined_end_ = false; + end_ = end_*10 + static_cast<size_t>(*p_-'0'); + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_step: + switch (*p_) + { + case '-': + positive_step_ = false; + state_ = path_state::left_bracket_step2; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = static_cast<size_t>(*p_-'0'); + state_ = path_state::left_bracket_step2; + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_step2: + switch (*p_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = step_*10 + static_cast<size_t>(*p_-'0'); + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::unquoted_name: + switch (*p_) + { + case '[': + apply_unquoted_string(buffer_); + transfer_nodes(); + start_ = 0; + state_ = path_state::left_bracket; + break; + case '.': + apply_unquoted_string(buffer_); + transfer_nodes(); + state_ = path_state::dot; + break; + case ' ':case '\t': + apply_unquoted_string(buffer_); + transfer_nodes(); + state_ = path_state::expect_dot_or_left_bracket; + break; + case '\r': + apply_unquoted_string(buffer_); + transfer_nodes(); + pre_line_break_state = path_state::expect_dot_or_left_bracket; + state_= path_state::cr; + break; + case '\n': + apply_unquoted_string(buffer_); + transfer_nodes(); + pre_line_break_state = path_state::expect_dot_or_left_bracket; + state_= path_state::lf; + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::left_bracket_single_quoted_string: + switch (*p_) + { + case '\'': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + state_ = path_state::expect_comma_or_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::left_bracket_double_quoted_string: + switch (*p_) + { + case '\"': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + state_ = path_state::expect_comma_or_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + switch (state_) + { + case path_state::unquoted_name: + { + apply_unquoted_string(buffer_); + transfer_nodes(); + } + break; + default: + break; + } + } + + void clear_index() + { + buffer_.clear(); + start_ = 0; + positive_start_ = true; + end_ = 0; + positive_end_ = true; + undefined_end_ = true; + step_ = 1; + positive_step_ = true; + } + + void end_all() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + const auto& path = stack_.back()[i].path; + pointer p = stack_.back()[i].val_ptr; + + if (p->is_array()) + { + for (auto it = p->array_range().begin(); it != p->array_range().end(); ++it) + { + nodes_.emplace_back(PathCons()(path,it - p->array_range().begin()),std::addressof(*it)); + } + } + else if (p->is_object()) + { + for (auto it = p->object_range().begin(); it != p->object_range().end(); ++it) + { + nodes_.emplace_back(PathCons()(path,it->key()),std::addressof(it->value())); + } + } + + } + start_ = 0; + } + + void apply_unquoted_string(const string_view_type& name) + { + if (name.length() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + apply_unquoted_string(stack_.back()[i].path, *(stack_.back()[i].val_ptr), name); + } + } + buffer_.clear(); + } + + void apply_unquoted_string(const string_type& path, reference val, const string_view_type& name) + { + if (val.is_object()) + { + if (val.count(name) > 0) + { + nodes_.emplace_back(PathCons()(path,name),std::addressof(val.at(name))); + } + if (recursive_descent_) + { + for (auto it = val.object_range().begin(); it != val.object_range().end(); ++it) + { + if (it->value().is_object() || it->value().is_array()) + { + apply_unquoted_string(path, it->value(), name); + } + } + } + } + else if (val.is_array()) + { + size_t pos = 0; + if (try_string_to_index(name.data(),name.size(),&pos, &positive_start_)) + { + size_t index = positive_start_ ? pos : val.size() - pos; + if (index < val.size()) + { + nodes_.emplace_back(PathCons()(path,index),std::addressof(val[index])); + } + } + else if (name == length_literal() && val.size() > 0) + { + auto temp = std::make_shared<Json>(val.size()); + temp_json_values_.push_back(temp); + nodes_.emplace_back(PathCons()(path,name),temp.get()); + } + if (recursive_descent_) + { + for (auto it = val.array_range().begin(); it != val.array_range().end(); ++it) + { + if (it->is_object() || it->is_array()) + { + apply_unquoted_string(path, *it, name); + } + } + } + } + else if (val.is_string()) + { + string_view_type sv = val.as_string_view(); + size_t pos = 0; + if (try_string_to_index(name.data(),name.size(),&pos, &positive_start_)) + { + auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), pos); + if (sequence.length() > 0) + { + auto temp = std::make_shared<Json>(sequence.begin(),sequence.length()); + temp_json_values_.push_back(temp); + nodes_.emplace_back(PathCons()(path,pos),temp.get()); + } + } + else if (name == length_literal() && sv.size() > 0) + { + size_t count = unicons::u32_length(sv.begin(),sv.end()); + auto temp = std::make_shared<Json>(count); + temp_json_values_.push_back(temp); + nodes_.emplace_back(PathCons()(path,name),temp.get()); + } + } + } + + void apply_selectors() + { + if (selectors_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + node_type& node = stack_.back()[i]; + apply_selectors(node, node.path, *(node.val_ptr)); + } + selectors_.clear(); + } + transfer_nodes(); + } + + void apply_selectors(node_type& node, const string_type& path, reference val) + { + for (const auto& selector : selectors_) + { + selector->select(node, path, val, nodes_, temp_json_values_); + } + if (recursive_descent_) + { + if (val.is_object()) + { + for (auto& nvp : val.object_range()) + { + if (nvp.value().is_object() || nvp.value().is_array()) + { + apply_selectors(node,PathCons()(path,nvp.key()),nvp.value()); + } + } + } + else if (val.is_array()) + { + for (auto& elem : val.array_range()) + { + if (elem.is_object() || elem.is_array()) + { + apply_selectors(node,path, elem); + } + } + } + } + } + + void transfer_nodes() + { + stack_.push_back(nodes_); + nodes_.clear(); + recursive_descent_ = false; + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + +}; + +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_error_category.hpp new file mode 100644 index 00000000..62aa5889 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_error_category.hpp @@ -0,0 +1,97 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP + +#include <jsoncons/json_exception.hpp> +#include <system_error> + +namespace jsoncons { namespace jsonpath { + +enum class jsonpath_parser_errc +{ + ok = 0, + expected_root = 1, + expected_right_bracket = 2, + expected_name = 3, + expected_separator = 4, + invalid_filter = 5, + invalid_filter_expected_slash = 6, + invalid_filter_unbalanced_paren = 7, + invalid_filter_unsupported_operator = 8, + invalid_filter_expected_right_brace = 9, + invalid_filter_expected_primary = 10, + expected_index = 11, + expected_left_bracket_token = 12, + unexpected_operator = 13 +}; + +class jsonpath_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsonpath"; + } + virtual std::string message(int ev) const + { + switch (static_cast<jsonpath_parser_errc>(ev)) + { + case jsonpath_parser_errc::expected_root: + return "Expected $"; + case jsonpath_parser_errc::expected_right_bracket: + return "Expected ]"; + case jsonpath_parser_errc::expected_name: + return "Expected a name following a dot"; + case jsonpath_parser_errc::expected_index: + return "Expected index"; + case jsonpath_parser_errc::expected_separator: + return "Expected dot or left bracket separator"; + case jsonpath_parser_errc::invalid_filter: + return "Invalid path filter"; + case jsonpath_parser_errc::invalid_filter_expected_slash: + return "Invalid path filter, expected '/'"; + case jsonpath_parser_errc::invalid_filter_unbalanced_paren: + return "Invalid path filter, unbalanced parenthesis"; + case jsonpath_parser_errc::invalid_filter_unsupported_operator: + return "Unsupported operator"; + case jsonpath_parser_errc::invalid_filter_expected_right_brace: + return "Invalid path filter, expected right brace }"; + case jsonpath_parser_errc::invalid_filter_expected_primary: + return "Invalid path filter, expected primary expression."; + case jsonpath_parser_errc::expected_left_bracket_token: + return "Expected ?,',\",0-9,*"; + default: + return "Unknown jsonpath parser error"; + } + } +}; + +inline +const std::error_category& jsonpath_error_category() +{ + static jsonpath_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpath_parser_errc result) +{ + return std::error_code(static_cast<int>(result),jsonpath_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::jsonpath::jsonpath_parser_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_filter.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_filter.hpp new file mode 100644 index 00000000..c3af2edd --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_filter.hpp @@ -0,0 +1,1874 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_FILTER_HPP +#define JSONCONS_JSONPATH_FILTER_HPP + +#include <string> +#include <map> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <regex> +#include <functional> +#include <cmath> +#include <jsoncons/json.hpp> +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { namespace detail { + +JSONCONS_DEFINE_LITERAL(eqtilde_literal,"=~") +JSONCONS_DEFINE_LITERAL(star_literal,"*") +JSONCONS_DEFINE_LITERAL(forwardslash_literal,"/") +JSONCONS_DEFINE_LITERAL(plus_literal,"+") +JSONCONS_DEFINE_LITERAL(minus_literal,"-") +JSONCONS_DEFINE_LITERAL(lt_literal,"<") +JSONCONS_DEFINE_LITERAL(lte_literal,"<=") +JSONCONS_DEFINE_LITERAL(gt_literal,">") +JSONCONS_DEFINE_LITERAL(gte_literal,">=") +JSONCONS_DEFINE_LITERAL(eq_literal,"==") +JSONCONS_DEFINE_LITERAL(ne_literal,"!=") +JSONCONS_DEFINE_LITERAL(ampamp_literal,"&&") +JSONCONS_DEFINE_LITERAL(pipepipe_literal,"||") +JSONCONS_DEFINE_LITERAL(max_literal,"max") +JSONCONS_DEFINE_LITERAL(min_literal,"min") + +template<class Json> +struct PathConstructor +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::string_type string_type; + + string_type operator()(const string_type& path, size_t index) const + { + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = static_cast<char_type>(48 + index % 10); + } while (index /= 10); + + string_type s; + s.append(path); + s.push_back('['); + while (--p >= buf) + { + s.push_back(*p); + } + s.push_back(']'); + return s; + } + + string_type operator()(const string_type& path, const string_view_type& sv) const + { + string_type s; + s.append(path); + s.push_back('['); + s.push_back('\''); + s.append(sv.data(),sv.length()); + s.push_back('\''); + s.push_back(']'); + return s; + } +}; + +template<class Json> +struct VoidPathConstructor +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::string_type string_type; + + string_type operator()(const string_type&, size_t) const + { + return string_type{}; + } + + string_type operator()(const string_type&, string_view_type) const + { + return string_type{}; + } +}; + +template <class Json, + class JsonReference, + class PathCons> +class jsonpath_evaluator; + +enum class filter_state +{ + start, + cr, + lf, + expect_right_round_bracket, + expect_oper_or_right_round_bracket, + expect_path_or_value_or_unary_op, + expect_regex, + regex, + single_quoted_text, + double_quoted_text, + unquoted_text, + path, + value, + oper, + function_argument, + done +}; + +enum class token_type +{ + operand, + unary_operator, + binary_operator, + lparen, + rparen +}; + +template <class Json> +class term +{ +public: + typedef typename Json::string_type string_type; + typedef typename Json::char_type char_type; + + virtual ~term() {} + + virtual void initialize(const Json&) + { + } + virtual bool accept_single_node() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json evaluate_single_node() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool exclaim() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool eq_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool eq(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ne_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ne(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool regex_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool regex2(const string_type&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ampamp_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ampamp(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool pipepipe_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool pipepipe(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool lt_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool lt(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool gt_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool gt(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json minus_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json minus(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json left_minus(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json unary_minus() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json plus_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json plus(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json mult_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json mult(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json div_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json div(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json left_div(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } +}; + +template <class Json> +struct operator_properties +{ + typedef std::function<Json(const term<Json>&, const term<Json>&)> operator_type; + + size_t precedence_level; + bool is_right_associative; + operator_type op; +}; + +template <class Json> +struct function_properties +{ + typedef std::function<Json(const term<Json>&)> function_type; + + size_t precedence_level; + bool is_right_associative; + bool is_aggregate; + function_type op; +}; + +template <class Json> +class token +{ + token_type type_; + size_t precedence_level_; + bool is_right_associative_; + bool is_aggregate_; + std::shared_ptr<term<Json>> operand_ptr_; + std::function<Json(const term<Json>&)> unary_operator_; + std::function<Json(const term<Json>&, const term<Json>&)> operator_; +public: + typedef std::function<Json(const term<Json>&)> unary_operator_type; + typedef std::function<Json(const term<Json>&, const term<Json>&)> operator_type; + + Json operator()(const term<Json>& a) + { + return unary_operator_(a); + } + + Json operator()(const term<Json>& a, const term<Json>& b) + { + return operator_(a,b); + } + + token(token_type type) + : type_(type),precedence_level_(0),is_right_associative_(false),is_aggregate_(false) + { + } + token(token_type type, std::shared_ptr<term<Json>> term_ptr) + : type_(type),precedence_level_(0),is_right_associative_(false),is_aggregate_(false),operand_ptr_(term_ptr) + { + } + token(size_t precedence_level, + bool is_right_associative, + std::function<Json(const term<Json>&)> unary_operator) + : type_(token_type::unary_operator), + precedence_level_(precedence_level), + is_right_associative_(is_right_associative), + is_aggregate_(false), + unary_operator_(unary_operator) + { + } + token(const operator_properties<Json>& properties) + : type_(token_type::binary_operator), + precedence_level_(properties.precedence_level), + is_right_associative_(properties.is_right_associative), + is_aggregate_(false), + operator_(properties.op) + { + } + token(const function_properties<Json>& properties) + : type_(token_type::unary_operator), + precedence_level_(properties.precedence_level), + is_right_associative_(properties.is_right_associative), + is_aggregate_(properties.is_aggregate), + unary_operator_(properties.op) + { + } + token(const token& t) = default; + //token(token&& t) = default; + + token<Json>& operator=(const token<Json>& val) = default; + //token<Json>& operator=(token<Json>&& val) = default; + + bool is_operator() const + { + return is_unary_operator() || is_binary_operator(); + } + + bool is_unary_operator() const + { + return type_ == token_type::unary_operator; + } + + bool is_binary_operator() const + { + return type_ == token_type::binary_operator; + } + + bool is_operand() const + { + return type_ == token_type::operand; + } + + bool is_lparen() const + { + return type_ == token_type::lparen; + } + + bool is_rparen() const + { + return type_ == token_type::rparen; + } + + size_t precedence_level() const + { + return precedence_level_; + } + + bool is_right_associative() const + { + return is_right_associative_; + } + + bool is_aggregate() const + { + return is_aggregate_; + } + + const term<Json>& operand() + { + JSONCONS_ASSERT(type_ == token_type::operand && operand_ptr_ != nullptr); + return *operand_ptr_; + } + + void initialize(const Json& context_node) + { + if (operand_ptr_.get() != nullptr) + { + operand_ptr_->initialize(context_node); + } + } +}; + +template <class Json> +bool ampamp(const Json& lhs, const Json& rhs) +{ + return lhs.as_bool() && rhs.as_bool(); +} + +template <class Json> +bool pipepipe(const Json& lhs, const Json& rhs) +{ + return lhs.as_bool() || rhs.as_bool(); +} + +template <class Json> +bool lt(const Json& lhs, const Json& rhs) +{ + bool result = false; + if (lhs. template is<unsigned long long>() && rhs. template is<unsigned long long>()) + { + result = lhs. template as<unsigned long long>() < rhs. template as<unsigned long long>(); + } + else if (lhs. template is<long long>() && rhs. template is<long long>()) + { + result = lhs. template as<long long>() < rhs. template as<long long>(); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = lhs.as_double() < rhs.as_double(); + } + else if (lhs.is_string() && rhs.is_string()) + { + result = lhs.as_string_view() < rhs.as_string_view(); + } + return result; +} + +template <class Json> +bool gt(const Json& lhs, const Json& rhs) +{ + return lt(rhs,lhs); +} + +template <class Json> +Json plus(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_integer() && rhs.is_integer()) + { + result = Json(((lhs.as_integer() + rhs.as_integer()))); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = Json((lhs.as_double() + rhs.as_double())); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = Json((lhs.as_uinteger() + rhs.as_uinteger())); + } + return result; +} + +template <class Json> +Json mult(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_integer() && rhs.is_integer()) + { + result = Json(((lhs.as_integer() * rhs.as_integer()))); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = Json((lhs.as_double() * rhs.as_double())); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = Json((lhs.as_uinteger() * rhs.as_uinteger())); + } + return result; +} + +template <class Json> +Json div(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_integer() && rhs.is_integer()) + { + result = Json((double)(lhs.as_integer() / (double)rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = Json((lhs.as_double() / rhs.as_double())); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = Json((double)(lhs.as_uinteger() / (double)rhs.as_uinteger())); + } + return result; +} + +template <class Json> +Json unary_minus(const Json& lhs) +{ + Json result = Json::null(); + if (lhs.is_integer()) + { + result = -lhs.as_integer(); + } + else if (lhs.is_double()) + { + result = -lhs.as_double(); + } + return result; +} + +template <class Json> +Json minus(const Json& lhs, const Json& rhs) +{ + Json result = Json::null(); + if (lhs.is_integer() && rhs.is_integer()) + { + result = ((lhs.as_integer() - rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = (lhs.as_double() - rhs.as_double()); + } + else if (lhs.is_uinteger() && rhs.is_uinteger() && lt(rhs,lhs)) + { + result = (lhs.as_uinteger() - rhs.as_uinteger()); + } + return result; +} + +template <class Json> +class value_term final : public term<Json> +{ + Json value_; +public: + template <class T> + value_term(const T& val) + : value_(val) + { + } + + bool accept_single_node() const override + { + return value_.as_bool(); + } + + Json evaluate_single_node() const override + { + return value_; + } + + bool exclaim() const override + { + return !value_.as_bool(); + } + + bool eq_term(const term<Json>& rhs) const override + { + return rhs.eq(value_); + } + + bool eq(const Json& rhs) const override + { + return value_ == rhs; + } + + bool ne_term(const term<Json>& rhs) const override + { + return rhs.ne(value_); + } + bool ne(const Json& rhs) const override + { + return value_ != rhs; + } + bool regex_term(const term<Json>& rhs) const override + { + return rhs.regex2(value_.as_string()); + } + bool ampamp_term(const term<Json>& rhs) const override + { + return rhs.ampamp(value_); + } + bool ampamp(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::ampamp(value_,rhs); + } + bool pipepipe_term(const term<Json>& rhs) const override + { + return rhs.pipepipe(value_); + } + bool pipepipe(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::pipepipe(value_,rhs); + } + + bool lt_term(const term<Json>& rhs) const override + { + return rhs.gt(value_); + } + bool lt(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::lt(value_,rhs); + } + + bool gt_term(const term<Json>& rhs) const override + { + return rhs.lt(value_); + } + bool gt(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::gt(value_,rhs); + } + + Json minus_term(const term<Json>& rhs) const override + { + return rhs.left_minus(value_); + } + Json minus(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::minus(value_,rhs); + } + + Json left_minus(const Json& lhs) const override + { + return jsoncons::jsonpath::detail::minus(lhs,value_); + } + + Json unary_minus() const override + { + return jsoncons::jsonpath::detail::unary_minus(value_); + } + + Json plus_term(const term<Json>& rhs) const override + { + return rhs.plus(value_); + } + + Json plus(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::plus(value_,rhs); + } + Json mult_term(const term<Json>& rhs) const override + { + return rhs.mult(value_); + } + + Json mult(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::mult(value_,rhs); + } + + Json div_term(const term<Json>& rhs) const override + { + return rhs.left_div(value_); + } + Json div(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::div(value_,rhs); + } + + Json left_div(const Json& lhs) const override + { + return jsoncons::jsonpath::detail::div(lhs,value_); + } +}; + +template <class Json> +class regex_term final : public term<Json> +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + const std::basic_regex<char_type> pattern_; +public: + regex_term(const string_type& pattern, std::regex::flag_type flags) + : pattern_(pattern,flags) + { + } + + bool regex2(const string_type& subject) const override + { + return std::regex_match(subject, pattern_); + } +}; + +template <class Json> +class path_term final : public term<Json> +{ + typedef typename Json::string_type string_type; + + string_type path_; + Json nodes_; +public: + path_term(const string_type& path) + : path_(path) + { + } + + void initialize(const Json& context_node) override + { + jsonpath_evaluator<Json,const Json&,VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(context_node,path_); + nodes_ = evaluator.get_values(); + } + + bool accept_single_node() const override + { + return nodes_.size() != 0; + } + + Json evaluate_single_node() const override + { + return nodes_.size() == 1 ? nodes_[0] : nodes_; + } + + bool exclaim() const override + { + return nodes_.size() == 0; + } + + bool eq_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.eq(nodes_[i]); + } + } + return result; + } + + bool eq(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] == rhs; + } + } + return result; + } + + bool ne_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ne(nodes_[i]); + } + } + return result; + + } + bool ne(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] != rhs; + } + } + return result; + } + bool regex_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.regex2(nodes_[i].as_string()); + } + } + return result; + } + bool ampamp_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ampamp(nodes_[i]); + } + } + return result; + } + bool ampamp(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::ampamp(nodes_[i],rhs); + } + } + return result; + } + bool pipepipe_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.pipepipe(nodes_[i]); + } + } + return result; + } + bool pipepipe(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::pipepipe(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::lt(nodes_[i],rhs); + } + } + return result; + } + + bool lt_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.gt(nodes_[i]); + } + } + return result; + } + + bool gt(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::gt(nodes_[i],rhs); + } + } + return result; + } + + bool gt_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.lt(nodes_[i]); + } + } + return result; + } + + Json minus_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.left_minus(nodes_[0]) : a_null; + } + Json minus(const Json& rhs) const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::minus(nodes_[0],rhs) : Json(jsoncons::null_type()); + } + + Json left_minus(const Json& lhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::minus(lhs,nodes_[0]) : a_null; + } + + Json unary_minus() const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::unary_minus(nodes_[0]) : Json::null(); + } + + Json plus_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.plus(nodes_[0]) : a_null; + } + Json plus(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::plus(nodes_[0],rhs) : a_null; + } + + Json mult_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.mult(nodes_[0]) : a_null; + } + Json mult(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::mult(nodes_[0],rhs) : a_null; + } + + Json div_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.left_div(nodes_[0]) : a_null; + } + Json div(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::div(nodes_[0],rhs) : a_null; + } + + Json left_div(const Json& lhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::div(lhs, nodes_[0]) : a_null; + } +}; + +template <class Json> +token<Json> evaluate(const Json& context, std::vector<token<Json>>& tokens) +{ + for (auto it= tokens.begin(); it != tokens.end(); ++it) + { + it->initialize(context); + } + std::vector<token<Json>> stack; + for (auto t : tokens) + { + if (t.is_operand()) + { + stack.push_back(t); + } + else if (t.is_unary_operator()) + { + auto rhs = stack.back(); + stack.pop_back(); + Json val = t(rhs.operand()); + stack.push_back(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + else if (t.is_binary_operator()) + { + auto rhs = stack.back(); + stack.pop_back(); + auto lhs = stack.back(); + stack.pop_back(); + Json val = t(lhs.operand(), rhs.operand()); + stack.push_back(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + } + if (stack.size() != 1) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid state")); + } + + return stack.back(); +} + +template <class Json> +class jsonpath_filter_expr +{ +public: + std::vector<token<Json>> tokens_; + size_t line_; + size_t column_; +public: + + jsonpath_filter_expr(const std::vector<token<Json>>& tokens, size_t line, size_t column) + : tokens_(tokens), line_(line), column_(column) + { + } + + Json eval(const Json& context_node) + { + try + { + auto t = evaluate(context_node,tokens_); + + return t.operand().evaluate_single_node(); + + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + } + + bool exists(const Json& context_node) + { + try + { + auto t = evaluate(context_node,tokens_); + return t.operand().accept_single_node(); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + } +}; + +template <class Json> +class jsonpath_filter_parser +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::char_type char_type; + + std::vector<token<Json>> output_stack_; + std::vector<token<Json>> operator_stack_; + std::vector<filter_state> state_stack_; + + size_t line_; + size_t column_; + + static const operator_properties<Json> op_properties_[]; + + class function_table + { + typedef std::map<string_type,function_properties<Json>> function_dictionary; + + const function_dictionary functions_ = + { + { + max_literal<char_type>(),{1,true,true,[](const term<Json>& term) + { + Json a = term.evaluate_single_node(); + + double v = std::numeric_limits<double>::lowest(); + for (const auto& elem : a.array_range()) + { + double x = elem. template as<double>(); + if (x > v) + { + v = x; + } + } + return v; + } + } + }, + { + min_literal<char_type>(),{1,true,true,[](const term<Json>& term) + { + Json a = term.evaluate_single_node(); + + double v = (std::numeric_limits<double>::max)(); + for (const auto& elem : a.array_range()) + { + double x = elem. template as<double>(); + if (x < v) + { + v = x; + } + } + return v; + } + } + } + }; + + public: + + typename function_dictionary::const_iterator find(const string_type& key) const + { + return functions_.find(key); + } + typename function_dictionary::const_iterator end() const + { + return functions_.end(); + } + }; + + class binary_operator_table + { + typedef std::map<string_type,operator_properties<Json>> binary_operator_map; + + const binary_operator_map operators = + { + {eqtilde_literal<char_type>(),{2,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.regex_term(b)); }}}, + {star_literal<char_type>(),{3,false,[](const term<Json>& a, const term<Json>& b) {return a.mult_term(b); }}}, + {forwardslash_literal<char_type>(),{3,false,[](const term<Json>& a, const term<Json>& b) {return a.div_term(b); }}}, + {plus_literal<char_type>(),{4,false,[](const term<Json>& a, const term<Json>& b) {return a.plus_term(b); }}}, + {minus_literal<char_type>(),{4,false,[](const term<Json>& a, const term<Json>& b) {return a.minus_term(b); }}}, + {lt_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b)); }}}, + {lte_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b) || a.eq_term(b)); }}}, + {gt_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b)); }}}, + {gte_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b) || a.eq_term(b)); }}}, + {eq_literal<char_type>(),{6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.eq_term(b)); }}}, + {ne_literal<char_type>(),{6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ne_term(b)); }}}, + {ampamp_literal<char_type>(),{7,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ampamp_term(b)); }}}, + {pipepipe_literal<char_type>(),{8,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.pipepipe_term(b)); }}} + }; + + public: + typename binary_operator_map::const_iterator find(const string_type& key) const + { + return operators.find(key); + } + typename binary_operator_map::const_iterator end() const + { + return operators.end(); + } + }; + + function_table functions_; + binary_operator_table binary_operators_; + +public: + jsonpath_filter_parser() + : line_(1), column_(1) + { + } + jsonpath_filter_parser(size_t line, size_t column) + : line_(line), column_(column) + { + } + + size_t line() const + { + return line_; + } + + size_t column() const + { + return column_; + } + + jsonpath_filter_expr<Json> parse(const Json& root, const char_type* p, size_t length, const char_type** end_ptr) + { + return parse(root, p,p+length, end_ptr); + } + + void push_state(filter_state state) + { + state_stack_.push_back(state); + } + + filter_state pop_state() + { + if (state_stack_.empty()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid state")); + } + filter_state state = state_stack_.back(); + state_stack_.pop_back(); + return state; + } + + void add_token(token<Json> token) + { + if (token.is_operand()) + { + output_stack_.push_back(token); + } + else if (token.is_lparen()) + { + operator_stack_.push_back(token); + } + else if (token.is_rparen()) + { + auto it = operator_stack_.rbegin(); + while (it != operator_stack_.rend() && !it->is_lparen()) + { + output_stack_.push_back(*it); + ++it; + } + if (it == operator_stack_.rend()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Unbalanced parenthesis")); + } + operator_stack_.erase(it.base(),operator_stack_.end()); + operator_stack_.pop_back(); + } + else if (token.is_operator()) + { + if (operator_stack_.empty() || operator_stack_.back().is_lparen()) + { + operator_stack_.push_back(token); + } + else if (token.precedence_level() < operator_stack_.back().precedence_level() + || (token.precedence_level() == operator_stack_.back().precedence_level() && token.is_right_associative())) + { + operator_stack_.push_back(token); + } + else + { + auto it = operator_stack_.rbegin(); + while (it != operator_stack_.rend() && it->is_operator() + && (token.precedence_level() > it->precedence_level() + || (token.precedence_level() == it->precedence_level() && token.is_right_associative()))) + { + output_stack_.push_back(*it); + ++it; + } + + operator_stack_.erase(it.base(),operator_stack_.end()); + operator_stack_.push_back(token); + } + } + } + + jsonpath_filter_expr<Json> parse(const Json& root, const char_type* p, const char_type* end_expr, const char_type** end_ptr) + { + output_stack_.clear(); + operator_stack_.clear(); + state_stack_.clear(); + + string_type buffer; + + int depth = 0; + filter_state state = filter_state::start; + while (p < end_expr && state != filter_state::done) + { + switch (state) + { + case filter_state::cr: + ++line_; + column_ = 1; + switch (*p) + { + case '\n': + state = pop_state(); + ++p; + ++column_; + break; + default: + state = pop_state(); + break; + } + break; + case filter_state::lf: + ++line_; + column_ = 1; + state = pop_state(); + break; + case filter_state::start: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case '(': + state = filter_state::expect_path_or_value_or_unary_op; + ++depth; + add_token(token<Json>(token_type::lparen)); + break; + case ')': + state = filter_state::expect_path_or_value_or_unary_op; + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + break; + } + ++p; + ++column_; + break; + case filter_state::function_argument: + { + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case ' ':case '\t': + break; + case ')': + if (buffer.length() > 0) + { + if (operator_stack_.back().is_aggregate()) + { + try + { + // path, parse against root, get value + jsonpath_evaluator<Json,const Json&,detail::VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(root,buffer.data(),buffer.length()); + auto result = evaluator.get_values(); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(result))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + } + else + { + add_token(token<Json>(token_type::operand,std::make_shared<path_term<Json>>(buffer))); + } + buffer.clear(); + state = filter_state::expect_oper_or_right_round_bracket; + } + break; + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + } + break; + case filter_state::oper: + switch (*p) + { + case '~': + { + buffer.push_back(*p); + ++p; + ++column_; + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + add_token(token<Json>(it->second)); + state = filter_state::expect_regex; + } + break; + case '=': + case '&': + case '|': + { + buffer.push_back(*p); + ++p; + ++column_; + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + add_token(token<Json>(it->second)); + state = filter_state::expect_path_or_value_or_unary_op; + } + break; + default: + { + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + add_token(token<Json>(it->second)); + state = filter_state::expect_path_or_value_or_unary_op; + } + break; + } + break; + case filter_state::unquoted_text: + { + switch (*p) + { + case ' ':case '\t': + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + ++p; + ++column_; + break; + case '(': + { + auto it = functions_.find(buffer); + if (it == functions_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,line_,column_); + } + add_token(token<Json>(it->second)); + state = filter_state::function_argument; + buffer.clear(); + ++p; + ++column_; + break; + } + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + buffer.push_back(*p); + state = filter_state::oper; + ++p; + ++column_; + } + break; + case ')': + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_path_or_value_or_unary_op; + } + ++p; + ++column_; + break; + default: + buffer.push_back(*p); + ++p; + ++column_; + break; + } + } + break; + case filter_state::single_quoted_text: + { + switch (*p) + { + case '\\': + buffer.push_back(*p); + if (p+1 < end_expr) + { + ++p; + ++column_; + buffer.push_back(*p); + } + break; + case '\'': + buffer.push_back('\"'); + //if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + case filter_state::double_quoted_text: + { + switch (*p) + { + case '\\': + buffer.push_back(*p); + if (p+1 < end_expr) + { + ++p; + ++column_; + buffer.push_back(*p); + } + break; + case '\"': + buffer.push_back(*p); + //if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + case filter_state::expect_path_or_value_or_unary_op: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + ++p; + break; + case '\n': + push_state(state); + state = filter_state::lf; + ++p; + break; + case ' ':case '\t': + ++p; + ++column_; + break; + case '!': + { + std::function<Json(const term<Json>&)> f = [](const term<Json>& b) {return Json(b.exclaim());}; + add_token(token<Json>(1, true, f)); + ++p; + ++column_; + break; + } + case '-': + { + std::function<Json(const term<Json>&)> f = [](const term<Json>& b) {return b.unary_minus();}; + add_token(token<Json>(1, true, f)); + ++p; + ++column_; + break; + } + case '@': + buffer.push_back(*p); + state = filter_state::path; + ++p; + ++column_; + break; + case '\'': + buffer.push_back('\"'); + state = filter_state::single_quoted_text; + ++p; + ++column_; + break; + case '\"': + buffer.push_back(*p); + state = filter_state::double_quoted_text; + ++p; + ++column_; + break; + case '(': + ++depth; + add_token(token<Json>(token_type::lparen)); + ++p; + ++column_; + break; + case ')': + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + ++p; + ++column_; + break; + default: + // don't increment + state = filter_state::unquoted_text; + break; + }; + break; + case filter_state::expect_oper_or_right_round_bracket: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + ++p; + break; + case '\n': + push_state(state); + state = filter_state::lf; + ++p; + break; + case ' ':case '\t': + ++p; + ++column_; + break; + case ')': + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + ++p; // fix + } + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + buffer.push_back(*p); + state = filter_state::oper; + ++p; + ++column_; + } + break; + default: + throw parse_error(jsonpath_parser_errc::invalid_filter,line_,column_); + break; + }; + break; + case filter_state::expect_right_round_bracket: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case ' ':case '\t': + break; + case ')': + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_oper_or_right_round_bracket; + } + break; + default: + throw parse_error(jsonpath_parser_errc::invalid_filter,line_,column_); + break; + }; + ++p; + ++column_; + break; + case filter_state::path: + switch (*p) + { + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + if (buffer.length() > 0) + { + add_token(token<Json>(token_type::operand,std::make_shared<path_term<Json>>(buffer))); + buffer.clear(); + } + buffer.push_back(*p); + ++p; + ++column_; + state = filter_state::oper; + } + break; + case ')': + if (buffer.length() > 0) + { + add_token(token<Json>(token_type::operand,std::make_shared<path_term<Json>>(buffer))); + add_token(token<Json>(token_type::rparen)); + buffer.clear(); + } + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_path_or_value_or_unary_op; + } + ++p; + ++column_; + break; + default: + buffer.push_back(*p); + ++p; + ++column_; + break; + }; + break; + case filter_state::expect_regex: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case ' ':case '\t': + break; + case '/': + state = filter_state::regex; + break; + default: + throw parse_error(jsonpath_parser_errc::invalid_filter_expected_slash,line_,column_); + break; + }; + ++p; + ++column_; + break; + case filter_state::regex: + { + switch (*p) + { + case '/': + //if (buffer.length() > 0) + { + std::regex::flag_type flags = std::regex_constants::ECMAScript; + if (p+1 < end_expr && *(p+1) == 'i') + { + ++p; + ++column_; + flags |= std::regex_constants::icase; + } + add_token(token<Json>(token_type::operand,std::make_shared<regex_term<Json>>(buffer,flags))); + buffer.clear(); + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + default: + ++p; + ++column_; + break; + } + } + if (depth != 0) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unbalanced_paren,line_,column_); + } + *end_ptr = p; + + return jsonpath_filter_expr<Json>(output_stack_,line_,column_); + } +}; + +template <class Json> +const operator_properties<Json> jsonpath_filter_parser<Json>::op_properties_[] = +{ + {2,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.regex_term(b));}}, + {3,false,[](const term<Json>& a, const term<Json>& b) {return a.mult_term(b);}}, + {3,false,[](const term<Json>& a, const term<Json>& b) {return a.div_term(b);}}, + {4,false,[](const term<Json>& a, const term<Json>& b) {return a.plus_term(b);}}, + {4,false,[](const term<Json>& a, const term<Json>& b) {return a.minus_term(b);}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b));}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b) || a.eq_term(b));}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b));}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b) || a.eq_term(b));}}, + {6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.eq_term(b)); }}, + {6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ne_term(b)); }}, + {7,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ampamp_term(b));}}, + {8,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.pipepipe_term(b));}} +}; + +}}} + +#endif
\ No newline at end of file diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp new file mode 100644 index 00000000..56b4efa2 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp @@ -0,0 +1,810 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp> + +namespace jsoncons { namespace jsonpointer { + +class jsonpointer_error : public std::exception, public virtual json_exception +{ +public: + jsonpointer_error(const std::error_code& ec) + : error_code_(ec) + { + } + jsonpointer_error(const jsonpointer_error& other) = default; + + jsonpointer_error(jsonpointer_error&& other) = default; + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + const_cast<std::string&>(buffer_) = error_code_.message(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + jsonpointer_error& operator=(const jsonpointer_error& e) = default; + jsonpointer_error& operator=(jsonpointer_error&& e) = default; +private: + std::string buffer_; + std::error_code error_code_; +}; + +namespace detail { + +enum class pointer_state +{ + start, + array_reference_token, + zero_array_reference_token, + nonzero_array_reference_token, + after_last_array_reference_token, + object_reference_token, + escaped +}; +template <class Json,class JsonReference, class Enable = void> +class json_wrapper +{ +}; + +template <class Json,class JsonReference> +class json_wrapper<Json,JsonReference,typename std::enable_if<std::is_reference<decltype(std::declval<Json>().at(typename Json::string_view_type()))>::value>::type> +{ +public: + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + json_wrapper(reference ref) JSONCONS_NOEXCEPT + : ptr_(std::addressof(ref)) + { + } + + json_wrapper(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + json_wrapper& operator=(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + reference get() const JSONCONS_NOEXCEPT + { + return *ptr_; + } +private: + pointer ptr_; +}; + +template <class Json,class JsonReference> +class json_wrapper<Json,JsonReference,typename std::enable_if<!std::is_reference<decltype(std::declval<Json>().at(typename Json::string_view_type()))>::value>::type> +{ +public: + using value_type = typename Json::value_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + json_wrapper(reference ref) JSONCONS_NOEXCEPT + : val_(ref) + { + } + + json_wrapper(const json_wrapper& w) JSONCONS_NOEXCEPT + : val_(w.val_) + { + } + + json_wrapper& operator=(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + value_type get() const JSONCONS_NOEXCEPT + { + return val_; + } +private: + value_type val_; +}; + +template<class Json,class JsonReference> +struct path_resolver +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + size_t index) const + { + if (index >= current.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current.push_back(current.back().get().at(index)); + return jsonpointer_errc(); + } + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + const string_view_type& name) const + { + if (!current.back().get().has_key(name)) + { + return jsonpointer_errc::name_not_found; + } + current.push_back(current.back().get().at(name)); + return jsonpointer_errc(); + } +}; + +template<class Json, class JsonReference> +struct path_setter +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + size_t index) const + { + if (index >= current.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current.push_back(current.back().get().at(index)); + return jsonpointer_errc(); + } + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + const string_view_type& name) const + { + jsonpointer_errc ec = jsonpointer_errc(); + if (!current.back().get().has_key(name)) + { + return jsonpointer_errc::name_not_found; + } + current.push_back(current.back().get().at(name)); + return ec; + } +}; + +template<class Json,class JsonReference> +class jsonpointer_evaluator : private parsing_context +{ + typedef typename Json::string_type string_type; + typedef typename string_type::value_type char_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer::detail::pointer_state state_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + string_type buffer_; + size_t index_; + std::vector<json_wrapper<Json,JsonReference>> current_; +public: + Json get_result() + { + return std::move(current_.back().get()); + } + + size_t line_number() const + { + return line_; + } + + size_t column_number() const + { + return column_; + } + + jsonpointer_errc get(reference root, const string_view_type& path) + { + path_resolver<Json,reference> op; + jsonpointer_errc ec = evaluate(root,op,path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case pointer_state::start: + break; + case pointer_state::zero_array_reference_token: + case pointer_state::nonzero_array_reference_token: + ec = op(current_,index_); + break; + case pointer_state::object_reference_token: + ec = op(current_,buffer_); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + string_type normalized_path(reference root, const string_view_type& path) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return string_type(path); + } + if (state_ == jsonpointer::detail::pointer_state::after_last_array_reference_token) + { + string_type p = string_type(path.substr(0,path.length()-1)); + std::string s = std::to_string(current_.back().get().size()); + for (auto c : s) + { + p.push_back(c); + } + return p; + } + else + { + return string_type(path); + } + } + + jsonpointer_errc insert_or_assign(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ > current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + if (index_ == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index_,value); + } + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + current_.back().get().push_back(value); + break; + case jsonpointer::detail::pointer_state::object_reference_token: + current_.back().get().insert_or_assign(buffer_,value); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc insert(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ > current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + if (index_ == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index_,value); + } + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + current_.back().get().push_back(value); + break; + case jsonpointer::detail::pointer_state::object_reference_token: + if (current_.back().get().has_key(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc remove(reference root, const string_view_type& path) + { + jsonpointer_errc ec = evaluate(root,path_resolver<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ >= current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current_.back().get().erase(current_.back().get().array_range().begin()+index_); + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + return jsonpointer_errc::index_exceeds_array_size; + case jsonpointer::detail::pointer_state::object_reference_token: + if (!current_.back().get().has_key(buffer_)) + { + return jsonpointer_errc::name_not_found; + } + current_.back().get().erase(buffer_); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc replace(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_resolver<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ >= current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + (current_.back().get())[index_] = value; + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + return jsonpointer_errc::index_exceeds_array_size; + case jsonpointer::detail::pointer_state::object_reference_token: + if (!current_.back().get().has_key(buffer_)) + { + return jsonpointer_errc::name_not_found; + } + current_.back().get().insert_or_assign(buffer_,value); + break; + default: + return jsonpointer_errc::end_of_input; + } + return jsonpointer_errc(); + } + + template <class Op> + jsonpointer_errc evaluate(reference root, Op op, const string_view_type& path) + { + jsonpointer_errc ec = jsonpointer_errc(); + + line_ = 1; + column_ = 1; + state_ = jsonpointer::detail::pointer_state::start; + begin_input_ = path.data(); + end_input_ = path.data() + path.length(); + p_ = begin_input_; + + index_ = 0; + + current_.push_back(root); + + while (p_ < end_input_) + { + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + switch (*p_) + { + case '/': + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + default: + return jsonpointer_errc::expected_slash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::array_reference_token: + switch (*p_) + { + case '0': + index_ = 0; + state_ = jsonpointer::detail::pointer_state::zero_array_reference_token; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index_ = (*p_ - '0'); + state_ = jsonpointer::detail::pointer_state::nonzero_array_reference_token; + break; + case '-': + state_ = jsonpointer::detail::pointer_state::after_last_array_reference_token; + break; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,index_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return jsonpointer_errc::unexpected_leading_zero; + case '-': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + switch (*p_) + { + case '/': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_slash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,index_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index_ = index_ * 10 + (*p_ - '0'); + break; + case '-': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::object_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,buffer_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '~': + state_ = jsonpointer::detail::pointer_state::escaped; + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::escaped: + switch (*p_) + { + case '0': + buffer_.push_back('~'); + state_ = jsonpointer::detail::pointer_state::object_reference_token; + break; + case '1': + buffer_.push_back('/'); + state_ = jsonpointer::detail::pointer_state::object_reference_token; + break; + default: + return jsonpointer_errc::expected_0_or_1; + }; + ++p_; + ++column_; + break; + } + } + return ec; + } + +private: + + // parsing_context + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } +}; + +} + +template<class Json> +typename Json::string_type normalized_path(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + return evaluator.normalized_path(root,path); +} + +template<class Json> +Json get(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + jsonpointer_errc ec = evaluator.get(root,path); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template<class Json> +Json get(const Json& root, const typename Json::string_view_type& path, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + ec = evaluator.get(root,path); + return evaluator.get_result(); +} + +template<class Json> +bool contains(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + jsonpointer_errc ec = evaluator.get(root,path); + return ec == jsonpointer_errc() ? true : false; +} + +template<class Json> +void insert_or_assign(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.insert_or_assign(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void insert_or_assign(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.insert_or_assign(root,path,value); +} + +template<class Json> +void insert(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.insert(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void insert(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.insert(root,path,value); +} + +template<class Json> +void remove(Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.remove(root,path); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void remove(Json& root, const typename Json::string_view_type& path, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.remove(root,path); +} + +template<class Json> +void replace(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.replace(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void replace(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.replace(root,path,value); +} + +template <class String> +void escape(const String& s, std::basic_ostringstream<typename String::value_type>& os) +{ + for (auto c : s) + { + if (c == '~') + { + os.put('~'); + os.put('0'); + } + else if (c == '/') + { + os.put('~'); + os.put('1'); + } + else + { + os.put(c); + } + } +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp new file mode 100644 index 00000000..01ddc9dc --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp @@ -0,0 +1,87 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_ERROR_CATEGORY_HPP + +#include <jsoncons/json_exception.hpp> +#include <system_error> + +namespace jsoncons { namespace jsonpointer { + +enum class jsonpointer_errc +{ + ok = 0, + expected_slash = 1, + expected_digit_or_dash, + unexpected_leading_zero, + index_exceeds_array_size, + expected_0_or_1, + name_not_found, + key_already_exists, + expected_object_or_array, + end_of_input +}; + +class jsonpointer_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsoncons.jsonpointer"; + } + virtual std::string message(int ev) const + { + switch (static_cast<jsonpointer_errc>(ev)) + { + case jsonpointer_errc::expected_slash: + return "Expected /"; + case jsonpointer_errc::expected_digit_or_dash: + return "Expected digit or '-'"; + case jsonpointer_errc::unexpected_leading_zero: + return "Unexpected leading zero"; + case jsonpointer_errc::index_exceeds_array_size: + return "Index exceeds array size"; + case jsonpointer_errc::expected_0_or_1: + return "Expected '0' or '1' after escape character '~'"; + case jsonpointer_errc::name_not_found: + return "Name not found"; + case jsonpointer_errc::key_already_exists: + return "Key already exists"; + case jsonpointer_errc::expected_object_or_array: + return "Expected object or array"; + case jsonpointer_errc::end_of_input: + return "Unexpected end of input"; + default: + return "Unknown jsonpointer error"; + } + } +}; + +inline +const std::error_category& jsonpointer_error_category() +{ + static jsonpointer_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpointer_errc result) +{ + return std::error_code(static_cast<int>(result),jsonpointer_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::jsonpointer::jsonpointer_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/msgpack/msgpack.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/msgpack/msgpack.hpp new file mode 100644 index 00000000..fd35dfe6 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/msgpack/msgpack.hpp @@ -0,0 +1,795 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_HPP +#define JSONCONS_MSGPACK_MSGPACK_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <limits> +#include <cassert> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/binary/binary_utilities.hpp> + +namespace jsoncons { namespace msgpack { + +class msgpack_decode_error : public std::invalid_argument, public virtual json_exception +{ +public: + explicit msgpack_decode_error(size_t pos) JSONCONS_NOEXCEPT + : std::invalid_argument("") + { + buffer_.append("Error decoding a message pack at position "); + buffer_.append(std::to_string(pos)); + } + ~msgpack_decode_error() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace msgpack_format +{ + const uint8_t nil_cd = 0xc0; + const uint8_t false_cd = 0xc2; + const uint8_t true_cd = 0xc3; + const uint8_t float32_cd = 0xca; + const uint8_t float64_cd = 0xcb; + const uint8_t uint8_cd = 0xcc; + const uint8_t uint16_cd = 0xcd; + const uint8_t uint32_cd = 0xce; + const uint8_t uint64_cd = 0xcf; + const uint8_t int8_cd = 0xd0; + const uint8_t int16_cd = 0xd1; + const uint8_t int32_cd = 0xd2; + const uint8_t int64_cd = 0xd3; + const uint8_t str8_cd = 0xd9; + const uint8_t str16_cd = 0xda; + const uint8_t str32_cd = 0xdb; + const uint8_t array16_cd = 0xdc; + const uint8_t array32_cd = 0xdd; + const uint8_t map16_cd = 0xde; + const uint8_t map32_cd = 0xdf; +} + +struct Encode_msgpack_ +{ + template <typename T> + void operator()(T val, std::vector<uint8_t>& v) + { + binary::to_big_endian(val,v); + } +}; + +struct Calculate_size_ +{ + template <typename T> + void operator()(T, size_t& size) + { + size += sizeof(T); + } +}; + +template<class Json> +class msgpack_Encoder_ +{ +public: + typedef typename Json::string_view_type string_view_type; + + static size_t calculate_size(const Json& j) + { + size_t n = 0; + msgpack_Encoder_<Json>::encode(j,Calculate_size_(),n); + return n; + } + + template <class Action, class Result> + static void encode(const Json& jval, Action action, Result& v) + { + switch (jval.type_id()) + { + case json_type_tag::null_t: + { + // nil + action(static_cast<uint8_t>(msgpack_format::nil_cd), v); + break; + } + + case json_type_tag::bool_t: + { + // true and false + action(static_cast<uint8_t>(jval.as_bool() ? msgpack_format::true_cd : msgpack_format::false_cd),v); + break; + } + + case json_type_tag::integer_t: + { + int64_t val = jval.as_integer(); + if (val >= 0) + { + if (val <= (std::numeric_limits<int8_t>::max)()) + { + // positive fixnum stores 7-bit positive integer + action(static_cast<int8_t>(val),v); + } + else if (val <= (std::numeric_limits<uint8_t>::max)()) + { + // uint 8 stores a 8-bit unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint8_cd), v); + action(static_cast<uint8_t>(val),v); + } + else if (val <= (std::numeric_limits<uint16_t>::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint16_cd), v); + action(static_cast<uint16_t>(val),v); + } + else if (val <= (std::numeric_limits<uint32_t>::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint32_cd), v); + action(static_cast<uint32_t>(val),v); + } + else if (val <= (std::numeric_limits<int64_t>::max)()) + { + // int 64 stores a 64-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int64_cd), v); + action(static_cast<int64_t>(val),v); + } + } + else + { + if (val >= -32) + { + // negative fixnum stores 5-bit negative integer + action(static_cast<int8_t>(val), v); + } + else if (val >= (std::numeric_limits<int8_t>::min)()) + { + // int 8 stores a 8-bit signed integer + action(static_cast<uint8_t>(msgpack_format::int8_cd), v); + action(static_cast<int8_t>(val),v); + } + else if (val >= (std::numeric_limits<int16_t>::min)()) + { + // int 16 stores a 16-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int16_cd), v); + action(static_cast<int16_t>(val),v); + } + else if (val >= (std::numeric_limits<int32_t>::min)()) + { + // int 32 stores a 32-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int32_cd), v); + action(static_cast<int32_t>(val),v); + } + else if (val >= (std::numeric_limits<int64_t>::min)()) + { + // int 64 stores a 64-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int64_cd), v); + action(static_cast<int64_t>(val),v); + } + } + break; + } + + case json_type_tag::uinteger_t: + { + uint64_t val = jval.as_uinteger(); + if (val <= (std::numeric_limits<int8_t>::max)()) + { + // positive fixnum stores 7-bit positive integer + action(static_cast<uint8_t>(val), v); + } + else if (val <= (std::numeric_limits<uint8_t>::max)()) + { + // uint 8 stores a 8-bit unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint8_cd), v); + action(static_cast<uint8_t>(val), v); + } + else if (val <= (std::numeric_limits<uint16_t>::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint16_cd), v); + action(static_cast<uint16_t>(val),v); + } + else if (val <= (std::numeric_limits<uint32_t>::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint32_cd), v); + action(static_cast<uint32_t>(val),v); + } + else if (val <= (std::numeric_limits<uint64_t>::max)()) + { + // uint 64 stores a 64-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint64_cd), v); + action(static_cast<uint64_t>(val),v); + } + break; + } + + case json_type_tag::double_t: + { + // float 64 + action(static_cast<uint8_t>(msgpack_format::float64_cd), v); + action(jval.as_double(),v); + break; + } + + case json_type_tag::small_string_t: + case json_type_tag::string_t: + { + encode_string(jval.as_string_view(), action, v); + break; + } + + case json_type_tag::array_t: + { + const auto length = jval.array_value().size(); + if (length <= 15) + { + // fixarray + action(static_cast<uint8_t>(0x90 | length), v); + } + else if (length <= (std::numeric_limits<uint16_t>::max)()) + { + // array 16 + action(static_cast<uint8_t>(msgpack_format::array16_cd), v); + action(static_cast<uint16_t>(length),v); + } + else if (length <= (std::numeric_limits<uint32_t>::max)()) + { + // array 32 + action(static_cast<uint8_t>(msgpack_format::array32_cd), v); + action(static_cast<uint32_t>(length),v); + } + + // append each element + for (const auto& el : jval.array_range()) + { + encode(el, action, v); + } + break; + } + + case json_type_tag::object_t: + { + const auto length = jval.object_value().size(); + if (length <= 15) + { + // fixmap + action(static_cast<uint8_t>(0x80 | (length & 0xf)), v); + } + else if (length <= 65535) + { + // map 16 + action(static_cast<uint8_t>(msgpack_format::map16_cd), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= 4294967295) + { + // map 32 + action(static_cast<uint8_t>(msgpack_format::map32_cd), v); + action(static_cast<uint32_t>(length),v); + } + + // append each element + for (const auto& kv: jval.object_range()) + { + encode_string(kv.key(), action, v); + encode(kv.value(), action, v); + } + break; + } + + default: + { + break; + } + } + } + + template <class Action, class Result> + static void encode_string(const string_view_type& sv, Action action, Result& v) + { + std::basic_string<uint8_t> target; + auto result = unicons::convert( + sv.begin(), sv.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + + const size_t length = target.length(); + if (length <= 31) + { + // fixstr stores a byte array whose length is upto 31 bytes + action(static_cast<uint8_t>(0xa0 | length), v); + } + else if (length <= (std::numeric_limits<uint8_t>::max)()) + { + // str 8 stores a byte array whose length is upto (2^8)-1 bytes + action(static_cast<uint8_t>(msgpack_format::str8_cd), v); + action(static_cast<uint8_t>(length), v); + } + else if (length <= (std::numeric_limits<uint16_t>::max)()) + { + // str 16 stores a byte array whose length is upto (2^16)-1 bytes + action(static_cast<uint8_t>(msgpack_format::str16_cd), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= (std::numeric_limits<uint32_t>::max)()) + { + // str 32 stores a byte array whose length is upto (2^32)-1 bytes + action(static_cast<uint8_t>(msgpack_format::str32_cd), v); + action(static_cast<uint32_t>(length),v); + } + + for (size_t i = 0; i < length; ++i) + { + action(static_cast<uint8_t>(target.data()[i]), v); + } + } +}; + +// decode_msgpack + +template<class Json> +class Decode_msgpack_ +{ + const uint8_t* begin_; + const uint8_t* end_; + const uint8_t* it_; +public: + typedef typename Json::char_type char_type; + + Decode_msgpack_(const uint8_t* begin, const uint8_t* end) + : begin_(begin), end_(end), it_(begin) + { + } + + Json decode() + { + // store && increment index + const uint8_t* pos = it_++; + + if (*pos <= 0xbf) + { + if (*pos <= 0x7f) + { + // positive fixint + return Json(*pos); + } + else if (*pos <= 0x8f) + { + // fixmap + Json result; + const size_t len = *pos & 0x0f; + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + } + return result; + } + else if (*pos <= 0x9f) + { + // fixarray + Json result = typename Json::array(); + const size_t len = *pos & 0x0f; + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + else + { + // fixstr + const size_t len = *pos & 0x1f; + const uint8_t* first = &(*it_); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return Json(target); + } + } + else if (*pos >= 0xe0) + { + // negative fixint + return static_cast<int8_t>(*pos); + } + else + { + switch (*pos) + { + case msgpack_format::nil_cd: + { + return Json(null_type()); + } + case msgpack_format::true_cd: + { + return Json(true); + } + case msgpack_format::false_cd: + { + return Json(false); + } + case msgpack_format::float32_cd: + { + const uint8_t* endp; + float res = binary::from_big_endian<float>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return res; + } + + case msgpack_format::float64_cd: + { + const uint8_t* endp; + double res = binary::from_big_endian<double>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return res; + } + + case msgpack_format::uint8_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return Json(x); + } + + case msgpack_format::uint16_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::uint32_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::uint64_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::int8_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return Json(x); + } + + case msgpack_format::int16_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::int32_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::int64_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::str8_cd: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + + const uint8_t* first = &(*(pos + 2)); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return target; + } + + case msgpack_format::str16_cd: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + + const uint8_t* first = &(*(pos + 3)); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return target; + } + + case msgpack_format::str32_cd: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + + const uint8_t* first = &(*(pos + 5)); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return target; + } + + case msgpack_format::array16_cd: + { + Json result = typename Json::array(); + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + + case msgpack_format::array32_cd: + { + Json result = typename Json::array(); + const uint8_t* endp; + const auto len = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + + case msgpack_format::map16_cd : + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + Json result = typename Json::object(); + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + } + return result; + } + + case msgpack_format::map32_cd : + { + Json result = typename Json::object(); + const uint8_t* endp; + const auto len = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + auto key = decode().as_string_view(); + result.set(key,decode()); + } + return result; + } + + default: + { + JSONCONS_THROW(msgpack_decode_error(end_-pos)); + } + } + } + } +}; + +template<class Json> +void encode_msgpack(const Json& j, std::vector<uint8_t>& v) +{ + size_t n = 0; + msgpack_Encoder_<Json>::encode(j,Calculate_size_(),n); + v.reserve(n); + //v.reserve(msgpack_Encoder_<Json>::calculate_size(j)); + + msgpack_Encoder_<Json>::encode(j,Encode_msgpack_(),v); +} + +template<class Json> +Json decode_msgpack(const std::vector<uint8_t>& v) +{ + Decode_msgpack_<Json> decoder(v.data(),v.data()+v.size()); + return decoder.decode(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class Json> +std::vector<uint8_t> encode_msgpack(const Json& j) +{ + std::vector<uint8_t> v; + encode_msgpack(j, v); + return v; +} +#endif + +}} + +#endif |