From 1d055261b4144dbf86b2658437015b15d4dd9bff Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 4 Sep 2022 00:32:56 +0100 Subject: initial --- include/jsoncons/LICENSE | 28 + include/jsoncons/allocator_holder.hpp | 38 + include/jsoncons/basic_json.hpp | 5839 ++++++++++++++++++++ include/jsoncons/bigint.hpp | 1611 ++++++ include/jsoncons/byte_string.hpp | 820 +++ include/jsoncons/config/binary_config.hpp | 226 + include/jsoncons/config/compiler_support.hpp | 389 ++ include/jsoncons/config/jsoncons_config.hpp | 308 ++ include/jsoncons/config/version.hpp | 40 + include/jsoncons/conv_error.hpp | 218 + include/jsoncons/converter.hpp | 296 + include/jsoncons/decode_json.hpp | 209 + include/jsoncons/decode_traits.hpp | 651 +++ include/jsoncons/detail/endian.hpp | 44 + include/jsoncons/detail/grisu3.hpp | 312 ++ include/jsoncons/detail/optional.hpp | 483 ++ include/jsoncons/detail/parse_number.hpp | 1133 ++++ include/jsoncons/detail/span.hpp | 188 + include/jsoncons/detail/string_view.hpp | 537 ++ include/jsoncons/detail/string_wrapper.hpp | 370 ++ include/jsoncons/detail/write_number.hpp | 567 ++ include/jsoncons/encode_json.hpp | 315 ++ include/jsoncons/encode_traits.hpp | 378 ++ include/jsoncons/json.hpp | 18 + include/jsoncons/json_array.hpp | 324 ++ include/jsoncons/json_content_handler.hpp | 12 + include/jsoncons/json_cursor.hpp | 448 ++ include/jsoncons/json_decoder.hpp | 420 ++ include/jsoncons/json_encoder.hpp | 1587 ++++++ include/jsoncons/json_error.hpp | 156 + include/jsoncons/json_exception.hpp | 241 + include/jsoncons/json_filter.hpp | 653 +++ include/jsoncons/json_fwd.hpp | 23 + include/jsoncons/json_object.hpp | 1772 ++++++ include/jsoncons/json_options.hpp | 862 +++ include/jsoncons/json_parser.hpp | 2871 ++++++++++ include/jsoncons/json_reader.hpp | 731 +++ include/jsoncons/json_traits_macros.hpp | 1072 ++++ include/jsoncons/json_traits_macros_deprecated.hpp | 144 + include/jsoncons/json_type.hpp | 206 + include/jsoncons/json_type_traits.hpp | 1829 ++++++ include/jsoncons/json_visitor.hpp | 1560 ++++++ include/jsoncons/json_visitor2.hpp | 2079 +++++++ include/jsoncons/more_type_traits.hpp | 874 +++ include/jsoncons/pretty_print.hpp | 89 + include/jsoncons/ser_context.hpp | 57 + include/jsoncons/sink.hpp | 289 + include/jsoncons/source.hpp | 777 +++ include/jsoncons/source_adaptor.hpp | 148 + include/jsoncons/staj2_cursor.hpp | 1178 ++++ include/jsoncons/staj_cursor.hpp | 1233 +++++ include/jsoncons/staj_iterator.hpp | 449 ++ include/jsoncons/tag_type.hpp | 245 + include/jsoncons/text_source_adaptor.hpp | 144 + include/jsoncons/typed_array_view.hpp | 250 + include/jsoncons/unicode_traits.hpp | 1330 +++++ include/jsoncons/uri.hpp | 635 +++ 57 files changed, 39706 insertions(+) create mode 100644 include/jsoncons/LICENSE create mode 100644 include/jsoncons/allocator_holder.hpp create mode 100644 include/jsoncons/basic_json.hpp create mode 100644 include/jsoncons/bigint.hpp create mode 100644 include/jsoncons/byte_string.hpp create mode 100644 include/jsoncons/config/binary_config.hpp create mode 100644 include/jsoncons/config/compiler_support.hpp create mode 100644 include/jsoncons/config/jsoncons_config.hpp create mode 100644 include/jsoncons/config/version.hpp create mode 100644 include/jsoncons/conv_error.hpp create mode 100644 include/jsoncons/converter.hpp create mode 100644 include/jsoncons/decode_json.hpp create mode 100644 include/jsoncons/decode_traits.hpp create mode 100644 include/jsoncons/detail/endian.hpp create mode 100644 include/jsoncons/detail/grisu3.hpp create mode 100644 include/jsoncons/detail/optional.hpp create mode 100644 include/jsoncons/detail/parse_number.hpp create mode 100644 include/jsoncons/detail/span.hpp create mode 100644 include/jsoncons/detail/string_view.hpp create mode 100644 include/jsoncons/detail/string_wrapper.hpp create mode 100644 include/jsoncons/detail/write_number.hpp create mode 100644 include/jsoncons/encode_json.hpp create mode 100644 include/jsoncons/encode_traits.hpp create mode 100644 include/jsoncons/json.hpp create mode 100644 include/jsoncons/json_array.hpp create mode 100644 include/jsoncons/json_content_handler.hpp create mode 100644 include/jsoncons/json_cursor.hpp create mode 100644 include/jsoncons/json_decoder.hpp create mode 100644 include/jsoncons/json_encoder.hpp create mode 100644 include/jsoncons/json_error.hpp create mode 100644 include/jsoncons/json_exception.hpp create mode 100644 include/jsoncons/json_filter.hpp create mode 100644 include/jsoncons/json_fwd.hpp create mode 100644 include/jsoncons/json_object.hpp create mode 100644 include/jsoncons/json_options.hpp create mode 100644 include/jsoncons/json_parser.hpp create mode 100644 include/jsoncons/json_reader.hpp create mode 100644 include/jsoncons/json_traits_macros.hpp create mode 100644 include/jsoncons/json_traits_macros_deprecated.hpp create mode 100644 include/jsoncons/json_type.hpp create mode 100644 include/jsoncons/json_type_traits.hpp create mode 100644 include/jsoncons/json_visitor.hpp create mode 100644 include/jsoncons/json_visitor2.hpp create mode 100644 include/jsoncons/more_type_traits.hpp create mode 100644 include/jsoncons/pretty_print.hpp create mode 100644 include/jsoncons/ser_context.hpp create mode 100644 include/jsoncons/sink.hpp create mode 100644 include/jsoncons/source.hpp create mode 100644 include/jsoncons/source_adaptor.hpp create mode 100644 include/jsoncons/staj2_cursor.hpp create mode 100644 include/jsoncons/staj_cursor.hpp create mode 100644 include/jsoncons/staj_iterator.hpp create mode 100644 include/jsoncons/tag_type.hpp create mode 100644 include/jsoncons/text_source_adaptor.hpp create mode 100644 include/jsoncons/typed_array_view.hpp create mode 100644 include/jsoncons/unicode_traits.hpp create mode 100644 include/jsoncons/uri.hpp (limited to 'include/jsoncons') diff --git a/include/jsoncons/LICENSE b/include/jsoncons/LICENSE new file mode 100644 index 0000000..ecf46ab --- /dev/null +++ b/include/jsoncons/LICENSE @@ -0,0 +1,28 @@ +// Copyright Daniel Parker 2013 - 2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/include/jsoncons/allocator_holder.hpp b/include/jsoncons/allocator_holder.hpp new file mode 100644 index 0000000..b69fcfe --- /dev/null +++ b/include/jsoncons/allocator_holder.hpp @@ -0,0 +1,38 @@ +// 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_ALLOCATOR_HOLDER_HPP +#define JSONCONS_ALLOCATOR_HOLDER_HPP + +namespace jsoncons { + +template +class allocator_holder +{ +public: + using allocator_type = Allocator; +private: + allocator_type alloc_; +public: + allocator_holder() = default; + allocator_holder(const allocator_holder&) = default; + allocator_holder(allocator_holder&&) = default; + allocator_holder& operator=(const allocator_holder&) = default; + allocator_holder& operator=(allocator_holder&&) = default; + allocator_holder(const allocator_type& alloc) + : alloc_(alloc) + {} + ~allocator_holder() = default; + + allocator_type get_allocator() const + { + return alloc_; + } +}; + +} + +#endif diff --git a/include/jsoncons/basic_json.hpp b/include/jsoncons/basic_json.hpp new file mode 100644 index 0000000..31de47b --- /dev/null +++ b/include/jsoncons/basic_json.hpp @@ -0,0 +1,5839 @@ +// 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_BASIC_JSON_HPP +#define JSONCONS_BASIC_JSON_HPP + +#include // std::numeric_limits +#include +#include +#include +#include +#include +#include // std::allocator +#include +#include // std::memcpy +#include // std::swap +#include // std::initializer_list +#include // std::move +#include // std::enable_if +#include // std::basic_istream +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + namespace type_traits { + + namespace detail { + + template + using + basic_json_t = basic_json; + + } // namespace detail + + template + struct is_basic_json : std::false_type {}; + + template + struct is_basic_json::type>::value>::type + > : std::true_type {}; + + } // namespace type_traits + + namespace detail { + + template + class random_access_iterator_wrapper + { + }; + + template + class random_access_iterator_wrapper::iterator_category, + std::random_access_iterator_tag>::value>::type> + { + Iterator it_; + bool has_value_; + + template + friend class random_access_iterator_wrapper; + public: + using iterator_category = std::random_access_iterator_tag; + + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + + random_access_iterator_wrapper() : it_(), has_value_(false) + { + } + + explicit random_access_iterator_wrapper(Iterator ptr) : it_(ptr), has_value_(true) + { + } + + random_access_iterator_wrapper(const random_access_iterator_wrapper&) = default; + random_access_iterator_wrapper(random_access_iterator_wrapper&&) = default; + random_access_iterator_wrapper& operator=(const random_access_iterator_wrapper&) = default; + random_access_iterator_wrapper& operator=(random_access_iterator_wrapper&&) = default; + + template ::value && std::is_convertible::value>::type> + random_access_iterator_wrapper(const random_access_iterator_wrapper& other) + : it_(other.it_), has_value_(other.has_value_) + { + } + + operator Iterator() const + { + return it_; + } + + reference operator*() const + { + return *it_; + } + + pointer operator->() const + { + return &(*it_); + } + + random_access_iterator_wrapper& operator++() + { + ++it_; + return *this; + } + + random_access_iterator_wrapper operator++(int) + { + random_access_iterator_wrapper temp = *this; + ++*this; + return temp; + } + + random_access_iterator_wrapper& operator--() + { + --it_; + return *this; + } + + random_access_iterator_wrapper operator--(int) + { + random_access_iterator_wrapper temp = *this; + --*this; + return temp; + } + + random_access_iterator_wrapper& operator+=(const difference_type offset) + { + it_ += offset; + return *this; + } + + random_access_iterator_wrapper operator+(const difference_type offset) const + { + random_access_iterator_wrapper temp = *this; + return temp += offset; + } + + random_access_iterator_wrapper& operator-=(const difference_type offset) + { + return *this += -offset; + } + + random_access_iterator_wrapper operator-(const difference_type offset) const + { + random_access_iterator_wrapper temp = *this; + return temp -= offset; + } + + difference_type operator-(const random_access_iterator_wrapper& rhs) const noexcept + { + return it_ - rhs.it_; + } + + reference operator[](const difference_type offset) const noexcept + { + return *(*this + offset); + } + + bool operator==(const random_access_iterator_wrapper& rhs) const noexcept + { + if (!has_value_ || !rhs.has_value_) + { + return has_value_ == rhs.has_value_ ? true : false; + } + else + { + return it_ == rhs.it_; + } + } + + bool operator!=(const random_access_iterator_wrapper& rhs) const noexcept + { + return !(*this == rhs); + } + + bool operator<(const random_access_iterator_wrapper& rhs) const noexcept + { + if (!has_value_ || !rhs.has_value_) + { + return has_value_ == rhs.has_value_ ? false :(has_value_ ? false : true); + } + else + { + return it_ < rhs.it_; + } + } + + bool operator>(const random_access_iterator_wrapper& rhs) const noexcept + { + return rhs < *this; + } + + bool operator<=(const random_access_iterator_wrapper& rhs) const noexcept + { + return !(rhs < *this); + } + + bool operator>=(const random_access_iterator_wrapper& rhs) const noexcept + { + return !(*this < rhs); + } + + inline + friend random_access_iterator_wrapper operator+( + difference_type offset, random_access_iterator_wrapper next) + { + return next += offset; + } + + bool has_value() const + { + return has_value_; + } + }; + } // namespace detail + + struct sorted_policy + { + template + using object = sorted_json_object; + + template + using array = json_array; + + using parse_error_handler_type = default_json_parsing; + }; + + struct order_preserving_policy + { + template + using object = order_preserving_json_object; + + template + using array = json_array; + + using parse_error_handler_type = default_json_parsing; + }; + + #if !defined(JSONCONS_NO_DEPRECATED) + using preserve_order_policy = order_preserving_policy; + #endif + + template + class range + { + public: + using iterator = IteratorT; + using const_iterator = ConstIteratorT; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + private: + iterator first_; + iterator last_; + public: + range(const IteratorT& first, const IteratorT& last) + : first_(first), last_(last) + { + } + + iterator begin() + { + return first_; + } + iterator end() + { + return last_; + } + const_iterator cbegin() + { + return first_; + } + const_iterator cend() + { + return last_; + } + reverse_iterator rbegin() + { + return reverse_iterator(last_); + } + reverse_iterator rend() + { + return reverse_iterator(first_); + } + const_reverse_iterator crbegin() + { + return reverse_iterator(last_); + } + const_reverse_iterator crend() + { + return reverse_iterator(first_); + } + }; + + // is_proxy_of + + template + struct is_proxy_of : std::false_type {}; + + template + struct is_proxy_of::value>::type + > : std::true_type {}; + + + // is_proxy + + template + struct is_proxy : std::false_type {}; + + template + struct is_proxy::value>::type + > : std::true_type {}; + + template + class basic_json + { + public: + + using allocator_type = Allocator; + + using implementation_policy = ImplementationPolicy; + + using parse_error_handler_type = typename ImplementationPolicy::parse_error_handler_type; + + using char_type = CharT; + using char_traits_type = std::char_traits; + using string_view_type = jsoncons::basic_string_view; + + using char_allocator_type = typename std::allocator_traits:: template rebind_alloc; + + using key_type = std::basic_string; + + + using reference = basic_json&; + using const_reference = const basic_json&; + using pointer = basic_json*; + using const_pointer = const basic_json*; + + using key_value_type = key_value; + + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("no replacement") typedef basic_json value_type; + JSONCONS_DEPRECATED_MSG("no replacement") typedef std::basic_string string_type; + JSONCONS_DEPRECATED_MSG("Instead, use key_value_type") typedef key_value_type kvp_type; + JSONCONS_DEPRECATED_MSG("Instead, use key_value_type") typedef key_value_type member_type; + #endif + + using array = typename ImplementationPolicy::template array; + + using key_value_allocator_type = typename std::allocator_traits:: template rebind_alloc; + + using object = typename ImplementationPolicy::template object; + + using object_iterator = jsoncons::detail::random_access_iterator_wrapper; + using const_object_iterator = jsoncons::detail::random_access_iterator_wrapper; + using array_iterator = typename array::iterator; + using const_array_iterator = typename array::const_iterator; + + private: + + static constexpr uint8_t major_type_shift = 0x04; + static constexpr uint8_t additional_information_mask = (1U << 4) - 1; + + class common_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + }; + + class null_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + + null_storage(semantic_tag tag = semantic_tag::none) + : storage_kind_(static_cast(json_storage_kind::null_value)), length_(0), tag_(tag) + { + } + }; + + class empty_object_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + + empty_object_storage(semantic_tag tag) + : storage_kind_(static_cast(json_storage_kind::empty_object_value)), length_(0), tag_(tag) + { + } + }; + + class bool_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + bool val_; + public: + bool_storage(bool val, semantic_tag tag) + : storage_kind_(static_cast(json_storage_kind::bool_value)), length_(0), tag_(tag), + val_(val) + { + } + + bool value() const + { + return val_; + } + + }; + + class int64_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + int64_t val_; + public: + int64_storage(int64_t val, + semantic_tag tag = semantic_tag::none) + : storage_kind_(static_cast(json_storage_kind::int64_value)), length_(0), tag_(tag), + val_(val) + { + } + + int64_t value() const + { + return val_; + } + }; + + class uint64_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + uint64_t val_; + public: + uint64_storage(uint64_t val, + semantic_tag tag = semantic_tag::none) + : storage_kind_(static_cast(json_storage_kind::uint64_value)), length_(0), tag_(tag), + val_(val) + { + } + + uint64_t value() const + { + return val_; + } + }; + + class half_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + uint16_t val_; + public: + half_storage(uint16_t val, semantic_tag tag = semantic_tag::none) + : storage_kind_(static_cast(json_storage_kind::half_value)), length_(0), tag_(tag), + val_(val) + { + } + + uint16_t value() const + { + return val_; + } + }; + + class double_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + double val_; + public: + double_storage(double val, + semantic_tag tag = semantic_tag::none) + : storage_kind_(static_cast(json_storage_kind::double_value)), length_(0), tag_(tag), + val_(val) + { + } + + double value() const + { + return val_; + } + }; + + class short_string_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + static constexpr size_t capacity = (2*sizeof(uint64_t) - 2*sizeof(uint8_t))/sizeof(char_type); + char_type data_[capacity]; + public: + static constexpr size_t max_length = capacity - 1; + + short_string_storage(semantic_tag tag, const char_type* p, uint8_t length) + : storage_kind_(static_cast(json_storage_kind::short_string_value)), length_(length), tag_(tag) + { + JSONCONS_ASSERT(length <= max_length); + std::memcpy(data_,p,length*sizeof(char_type)); + data_[length] = 0; + } + + short_string_storage(const short_string_storage& val) + : storage_kind_(val.storage_kind_), length_(val.length_), tag_(val.tag_) + { + std::memcpy(data_,val.data_,val.length_*sizeof(char_type)); + data_[length_] = 0; + } + + short_string_storage& operator=(const short_string_storage& val) = delete; + + uint8_t length() const + { + return length_; + } + + const char_type* data() const + { + return data_; + } + + const char_type* c_str() const + { + return data_; + } + }; + + // long_string_storage + class long_string_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + jsoncons::detail::string_wrapper s_; + public: + + long_string_storage(semantic_tag tag, const char_type* data, std::size_t length, const Allocator& a) + : storage_kind_(static_cast(json_storage_kind::long_string_value)), length_(0), tag_(tag), + s_(data, length, a) + { + } + + long_string_storage(const long_string_storage& val) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + s_(val.s_) + { + } + + long_string_storage(long_string_storage&& val) noexcept + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + s_(nullptr) + { + swap(val); + } + + long_string_storage(const long_string_storage& val, const Allocator& a) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + s_(val.s_, a) + { + } + + ~long_string_storage() noexcept + { + } + + long_string_storage& operator=(const long_string_storage& val) = delete; + + long_string_storage& operator=(long_string_storage&& val) noexcept = delete; + + void swap(long_string_storage& val) noexcept + { + s_.swap(val.s_); + } + + const char_type* data() const + { + return s_.data(); + } + + const char_type* c_str() const + { + return s_.c_str(); + } + + std::size_t length() const + { + return s_.length(); + } + + allocator_type get_allocator() const + { + return s_.get_allocator(); + } + }; + + // byte_string_storage + class byte_string_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + jsoncons::detail::tagged_string_wrapper s_; + public: + + byte_string_storage(semantic_tag tag, const uint8_t* data, std::size_t length, uint64_t ext_tag, const Allocator& alloc) + : storage_kind_(static_cast(json_storage_kind::byte_string_value)), length_(0), tag_(tag), + s_(data, length, ext_tag, alloc) + { + } + + byte_string_storage(const byte_string_storage& val) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + s_(val.s_) + { + } + + byte_string_storage(byte_string_storage&& val) noexcept + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + s_(nullptr) + { + swap(val); + } + + byte_string_storage(const byte_string_storage& val, const Allocator& a) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + s_(val.s_, a) + { + } + + ~byte_string_storage() noexcept + { + } + + void swap(byte_string_storage& val) noexcept + { + s_.swap(val.s_); + } + + const uint8_t* data() const + { + return s_.data(); + } + + std::size_t length() const + { + return s_.length(); + } + + uint64_t ext_tag() const + { + return s_.tag(); + } + + allocator_type get_allocator() const + { + return s_.get_allocator(); + } + }; + + // array_storage + class array_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + using array_allocator = typename std::allocator_traits:: template rebind_alloc; + using pointer = typename std::allocator_traits::pointer; + + pointer ptr_; + + template + void create(array_allocator alloc, Args&& ... args) + { + ptr_ = std::allocator_traits::allocate(alloc, 1); + JSONCONS_TRY + { + std::allocator_traits::construct(alloc, type_traits::to_plain_pointer(ptr_), std::forward(args)...); + } + JSONCONS_CATCH(...) + { + std::allocator_traits::deallocate(alloc, ptr_,1); + JSONCONS_RETHROW; + } + } + + void destroy() noexcept + { + array_allocator alloc(ptr_->get_allocator()); + std::allocator_traits::destroy(alloc, type_traits::to_plain_pointer(ptr_)); + std::allocator_traits::deallocate(alloc, ptr_,1); + } + public: + array_storage(const array& val, semantic_tag tag) + : storage_kind_(static_cast(json_storage_kind::array_value)), length_(0), tag_(tag) + { + create(val.get_allocator(), val); + } + + array_storage(array&& val, semantic_tag tag) + : storage_kind_(static_cast(json_storage_kind::array_value)), length_(0), tag_(tag) + { + create(val.get_allocator(), std::forward(val)); + } + + array_storage(const array& val, semantic_tag tag, const Allocator& a) + : storage_kind_(val.storage_kind_), length_(0), tag_(tag) + { + create(array_allocator(a), val, a); + } + + array_storage(const array_storage& val) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + array_storage(array_storage&& val) noexcept + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + ptr_(nullptr) + { + std::swap(val.ptr_, ptr_); + } + + array_storage(const array_storage& val, const Allocator& a) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_) + { + create(array_allocator(a), *(val.ptr_), a); + } + ~array_storage() noexcept + { + if (ptr_ != nullptr) + { + destroy(); + } + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + + void swap(array_storage& val) noexcept + { + std::swap(val.ptr_,ptr_); + } + + array& value() + { + return *ptr_; + } + + const array& value() const + { + return *ptr_; + } + }; + + // object_storage + class object_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + using object_allocator = typename std::allocator_traits:: template rebind_alloc; + using pointer = typename std::allocator_traits::pointer; + + pointer ptr_; + + template + void create(object_allocator alloc, Args&& ... args) + { + ptr_ = std::allocator_traits::allocate(alloc, 1); + JSONCONS_TRY + { + std::allocator_traits::construct(alloc, type_traits::to_plain_pointer(ptr_), std::forward(args)...); + } + JSONCONS_CATCH(...) + { + std::allocator_traits::deallocate(alloc, ptr_,1); + JSONCONS_RETHROW; + } + } + public: + explicit object_storage(const object& val, semantic_tag tag) + : storage_kind_(static_cast(json_storage_kind::object_value)), length_(0), tag_(tag) + { + create(val.get_allocator(), val); + } + + explicit object_storage(object&& val, semantic_tag tag) + : storage_kind_(static_cast(json_storage_kind::object_value)), length_(0), tag_(tag) + { + create(val.get_allocator(), std::forward(val)); + } + + explicit object_storage(const object& val, semantic_tag tag, const Allocator& a) + : storage_kind_(val.storage_kind_), length_(0), tag_(tag) + { + create(object_allocator(a), val, a); + } + + explicit object_storage(const object_storage& val) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + explicit object_storage(object_storage&& val) noexcept + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_), + ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + explicit object_storage(const object_storage& val, const Allocator& a) + : storage_kind_(val.storage_kind_), length_(0), tag_(val.tag_) + { + create(object_allocator(a), *(val.ptr_), a); + } + + ~object_storage() noexcept + { + if (ptr_ != nullptr) + { + destroy(); + } + } + + void swap(object_storage& val) noexcept + { + 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: + + void destroy() noexcept + { + object_allocator alloc(ptr_->get_allocator()); + std::allocator_traits::destroy(alloc, type_traits::to_plain_pointer(ptr_)); + std::allocator_traits::deallocate(alloc, ptr_,1); + } + }; + + class json_const_pointer_storage final + { + public: + uint8_t storage_kind_:4; + uint8_t length_:4; + semantic_tag tag_; + private: + const basic_json* p_; + public: + json_const_pointer_storage(const basic_json* p) + : storage_kind_(static_cast(json_storage_kind::json_const_pointer)), length_(0), tag_(p->tag()), + p_(p) + { + } + + const basic_json* value() const + { + return p_; + } + }; + + template + class proxy + { + friend class basic_json; + + ParentType& parent_; + string_view_type key_; + + proxy() = delete; + + proxy(const proxy& other) = default; + proxy(proxy&& other) = default; + proxy& operator = (const proxy& other) = delete; + proxy& operator = (proxy&& other) = delete; + + proxy(ParentType& parent, const string_view_type& key) + : parent_(parent), key_(key) + { + } + + basic_json& evaluate_with_default() + { + basic_json& val = parent_.evaluate_with_default(); + auto it = val.find(key_); + if (it == val.object_range().end()) + { + auto r = val.try_emplace(key_, json_object_arg, semantic_tag::none, val.object_value().get_allocator()); + return r.first->value(); + } + else + { + return it->value(); + } + } + + basic_json& evaluate(std::size_t index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(std::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: + using proxied_type = basic_json; + using proxy_type = proxy; + + basic_json& evaluate() + { + return parent_.evaluate(key_); + } + + const basic_json& evaluate() const + { + return parent_.evaluate(key_); + } + + operator basic_json&() + { + return evaluate(); + } + + operator const basic_json&() const + { + return evaluate(); + } + + range object_range() + { + return evaluate().object_range(); + } + + range object_range() const + { + return evaluate().object_range(); + } + + range array_range() + { + return evaluate().array_range(); + } + + range array_range() const + { + return evaluate().array_range(); + } + + std::size_t size() const noexcept + { + if (!parent_.contains(key_)) + { + return 0; + } + return evaluate().size(); + } + + json_storage_kind storage_kind() const + { + return evaluate().storage_kind(); + } + + semantic_tag tag() const + { + return evaluate().tag(); + } + + json_type type() const + { + return evaluate().type(); + } + + std::size_t count(const string_view_type& name) const + { + return evaluate().count(name); + } + + allocator_type get_allocator() const + { + return evaluate().get_allocator(); + } + + uint64_t ext_tag() const + { + return evaluate().ext_tag(); + } + + bool contains(const string_view_type& key) const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + + return evaluate().contains(key); + } + + bool is_null() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_null(); + } + + bool empty() const noexcept + { + if (!parent_.contains(key_)) + { + return true; + } + return evaluate().empty(); + } + + std::size_t capacity() const + { + return evaluate().capacity(); + } + + void reserve(std::size_t n) + { + evaluate().reserve(n); + } + + void resize(std::size_t n) + { + evaluate().resize(n); + } + + template + void resize(std::size_t n, T val) + { + evaluate().resize(n,val); + } + + template + bool is(Args&&... args) const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().template is(std::forward(args)...); + } + + bool is_string() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_string(); + } + + bool is_string_view() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_string_view(); + } + + bool is_byte_string() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_byte_string(); + } + + bool is_byte_string_view() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_byte_string_view(); + } + + bool is_bignum() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_bignum(); + } + + bool is_number() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_number(); + } + bool is_bool() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_bool(); + } + + bool is_object() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_object(); + } + + bool is_array() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_array(); + } + + bool is_int64() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_int64(); + } + + bool is_uint64() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_uint64(); + } + + bool is_half() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().is_half(); + } + + bool is_double() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + 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(); + } + + template > + std::basic_string as_string() const + { + return evaluate().as_string(); + } + + template > + std::basic_string as_string(const SAllocator& alloc) const + { + return evaluate().as_string(alloc); + } + + template > + basic_byte_string as_byte_string() const + { + return evaluate().template as_byte_string(); + } + + template + typename std::enable_if::value,T>::type + as() const + { + return evaluate().template as(); + } + + template + typename std::enable_if::value,T>::type + as(byte_string_arg_t, semantic_tag hint) const + { + return evaluate().template as(byte_string_arg, hint); + } + + bool as_bool() const + { + return evaluate().as_bool(); + } + + double as_double() const + { + return evaluate().as_double(); + } + + template + T as_integer() const + { + return evaluate().template as_integer(); + } + + template + proxy& operator=(T&& val) + { + parent_.evaluate_with_default().insert_or_assign(key_, std::forward(val)); + return *this; + } + + basic_json& operator[](std::size_t i) + { + return evaluate_with_default().at(i); + } + + const basic_json& operator[](std::size_t i) const + { + return evaluate().at(i); + } + + proxy_type operator[](const string_view_type& key) + { + return proxy_type(*this,key); + } + + 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_or_null(const string_view_type& name) const + { + return evaluate().at_or_null(name); + } + + const basic_json& at(std::size_t index) + { + return evaluate().at(index); + } + + const basic_json& at(std::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 + T get_value_or(const string_view_type& name, U&& default_value) const + { + static_assert(std::is_copy_constructible::value, + "get_value_or: T must be copy constructible"); + static_assert(std::is_convertible::value, + "get_value_or: U must be convertible to T"); + return evaluate().template get_value_or(name,std::forward(default_value)); + } + + void shrink_to_fit() + { + evaluate_with_default().shrink_to_fit(); + } + + void clear() + { + evaluate().clear(); + } + // Remove all elements from an array or object + + object_iterator erase(const_object_iterator pos) + { + return evaluate().erase(pos); + } + // Remove a range of elements from an object + + object_iterator erase(const_object_iterator first, const_object_iterator last) + { + return evaluate().erase(first, last); + } + // Remove a range of elements from an object + + void erase(const string_view_type& name) + { + evaluate().erase(name); + } + + array_iterator erase(const_array_iterator pos) + { + return evaluate().erase(pos); + } + // Removes the element at pos + + array_iterator erase(const_array_iterator first, const_array_iterator last) + { + return 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(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(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(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(source)); + } + + template + std::pair insert_or_assign(const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(name,std::forward(val)); + } + + // emplace + + template + std::pair try_emplace(const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(name,std::forward(args)...); + } + + template + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(hint, name, std::forward(val)); + } + + template + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(hint, name, std::forward(args)...); + } + + template + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + evaluate_with_default().emplace(pos, std::forward(args)...); + } + + template + basic_json& emplace_back(Args&&... args) + { + return evaluate_with_default().emplace_back(std::forward(args)...); + } + + template + void push_back(T&& val) + { + evaluate_with_default().push_back(std::forward(val)); + } + + template + array_iterator insert(const_array_iterator pos, T&& val) + { + return evaluate_with_default().insert(pos, std::forward(val)); + } + + template + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + return evaluate_with_default().insert(pos, first, last); + } + + template + void insert(InputIt first, InputIt last) + { + evaluate_with_default().insert(first, last); + } + + template + void insert(sorted_unique_range_tag tag, InputIt first, InputIt last) + { + evaluate_with_default().insert(tag, first, last); + } + + template + void dump(Args&& ... args) const + { + evaluate().dump(std::forward(args)...); + } + + template + void dump_pretty(Args&& ... args) const + { + evaluate().dump_pretty(std::forward(args)...); + } + + void swap(basic_json& val) + { + evaluate_with_default().swap(val); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const proxy& o) + { + o.dump(os); + return os; + } + + template + T get_with_default(const string_view_type& name, const T& default_value) const + { + return evaluate().template get_with_default(name,default_value); + } + + template > + T get_with_default(const string_view_type& name, const char_type* default_value) const + { + return evaluate().template get_with_default(name,default_value); + } + + std::basic_string to_string() const + { + return evaluate().to_string(); + } + + template + bool is_integer() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().template is_integer(); + } + + #if !defined(JSONCONS_NO_DEPRECATED) + + const basic_json& get_with_default(const string_view_type& name) const + { + return evaluate().at_or_null(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use tag()") + semantic_tag get_semantic_tag() const + { + return evaluate().tag(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use tag() == semantic_tag::datetime") + bool is_datetime() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().tag() == semantic_tag::datetime; + } + + JSONCONS_DEPRECATED_MSG("Instead, use tag() == semantic_tag::epoch_second") + bool is_epoch_time() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().tag() == semantic_tag::epoch_second; + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use push_back(T&&)") + void add(T&& val) + { + evaluate_with_default().push_back(std::forward(val)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use insert(const_array_iterator, T&&)") + array_iterator add(const_array_iterator pos, T&& val) + { + return evaluate_with_default().insert(pos, std::forward(val)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use insert_or_assign(const string_view_type&, T&&)") + std::pair set(const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(name,std::forward(val)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use insert_or_assign(object_iterator, const string_view_type&, T&&)") + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(hint, name, std::forward(val)); + } + + JSONCONS_DEPRECATED_MSG("Instead, use contains(const string_view_type&)") + bool has_key(const string_view_type& name) const noexcept + { + return contains(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use is()") + bool is_ulonglong() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().template is(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use is()") + bool is_longlong() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return evaluate().template is(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + int as_int() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + unsigned int as_uint() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + long as_long() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + unsigned long as_ulong() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + long long as_longlong() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + unsigned long long as_ulonglong() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + uint64_t as_uinteger() const + { + return evaluate().template as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void write(basic_json_visitor& visitor) const + { + evaluate().dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&)") + void write(std::basic_ostream& os) const + { + evaluate().dump(os); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&)") + void write(std::basic_ostream& os, const basic_json_encode_options& options) const + { + evaluate().dump(os, options); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump_pretty(std::basic_ostream&, const basic_json_encode_options&)") + void write(std::basic_ostream& os, const basic_json_encode_options& options, bool pprint) const + { + if (pprint) + { + evaluate().dump_pretty(os, options); + } + else + { + evaluate().dump(os, options); + } + } + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void to_stream(basic_json_visitor& visitor) const + { + evaluate().dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&)") + void to_stream(std::basic_ostream& os) const + { + evaluate().dump(os); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&)") + void to_stream(std::basic_ostream& os, const basic_json_encode_options& options) const + { + evaluate().dump(os,options); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump_pretty(std::basic_ostream&, const basic_json_encode_options&)") + void to_stream(std::basic_ostream& os, const basic_json_encode_options& options, bool pprint) const + { + if (pprint) + { + evaluate().dump_pretty(os,options); + } + else + { + evaluate().dump(os,options); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use resize(std::size_t)") + void resize_array(std::size_t n) + { + evaluate().resize(n); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use resize(std::size_t, T)") + void resize_array(std::size_t n, T val) + { + evaluate().resize(n,val); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range()") + range members() + { + return evaluate().object_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range()") + range members() const + { + return evaluate().object_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range()") + range elements() + { + return evaluate().array_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range()") + range elements() const + { + return evaluate().array_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().begin()") + object_iterator begin_members() + { + return evaluate().object_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().begin()") + const_object_iterator begin_members() const + { + return evaluate().object_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().end()") + object_iterator end_members() + { + return evaluate().object_range().end(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().end()") + const_object_iterator end_members() const + { + return evaluate().object_range().end(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().begin()") + array_iterator begin_elements() + { + return evaluate().array_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().begin()") + const_array_iterator begin_elements() const + { + return evaluate().array_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().end()") + array_iterator end_elements() + { + return evaluate().array_range().end(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().end()") + const_array_iterator end_elements() const + { + return evaluate().array_range().end(); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use get_with_default(const string_view_type&, T&&)") + basic_json get(const string_view_type& name, T&& default_value) const + { + return evaluate().get_with_default(name,std::forward(default_value)); + } + + JSONCONS_DEPRECATED_MSG("Instead, use at_or_null(const string_view_type&)") + const basic_json& get(const string_view_type& name) const + { + return evaluate().at_or_null(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use contains(const string_view_type&)") + bool has_member(const string_view_type& name) const noexcept + { + return contains(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use erase(const_object_iterator, const_object_iterator)") + void remove_range(std::size_t from_index, std::size_t to_index) + { + evaluate().remove_range(from_index, to_index); + } + JSONCONS_DEPRECATED_MSG("Instead, use erase(const string_view_type& name)") + void remove(const string_view_type& name) + { + evaluate().remove(name); + } + JSONCONS_DEPRECATED_MSG("Instead, use erase(const string_view_type& name)") + void remove_member(const string_view_type& name) + { + evaluate().remove(name); + } + JSONCONS_DEPRECATED_MSG("Instead, use empty()") + bool is_empty() const noexcept + { + return empty(); + } + JSONCONS_DEPRECATED_MSG("Instead, use is_number()") + bool is_numeric() const noexcept + { + if (!parent_.contains(key_)) + { + return false; + } + return is_number(); + } + #endif + }; + + using proxy_type = proxy; + + union + { + common_storage common_stor_; + null_storage null_stor_; + bool_storage bool_stor_; + int64_storage int64_stor_; + uint64_storage uint64_stor_; + half_storage half_stor_; + double_storage double_stor_; + short_string_storage short_string_stor_; + long_string_storage long_string_stor_; + byte_string_storage byte_string_stor_; + array_storage array_stor_; + object_storage object_stor_; + empty_object_storage empty_object_stor_; + json_const_pointer_storage json_const_pointer_stor_; + }; + + void Destroy_() + { + switch (storage_kind()) + { + case json_storage_kind::long_string_value: + destroy_var(); + break; + case json_storage_kind::byte_string_value: + destroy_var(); + break; + case json_storage_kind::array_value: + destroy_var(); + break; + case json_storage_kind::object_value: + destroy_var(); + break; + default: + break; + } + } + + template + void construct(Args&&... args) + { + ::new (&cast()) VariantType(std::forward(args)...); + } + + template + void destroy_var() + { + cast().~T(); + } + + template + struct identity { using type = T*; }; + + template + T& cast() + { + return cast(identity()); + } + + template + const T& cast() const + { + return cast(identity()); + } + + null_storage& cast(identity) + { + return null_stor_; + } + + const null_storage& cast(identity) const + { + return null_stor_; + } + + empty_object_storage& cast(identity) + { + return empty_object_stor_; + } + + const empty_object_storage& cast(identity) const + { + return empty_object_stor_; + } + + bool_storage& cast(identity) + { + return bool_stor_; + } + + const bool_storage& cast(identity) const + { + return bool_stor_; + } + + int64_storage& cast(identity) + { + return int64_stor_; + } + + const int64_storage& cast(identity) const + { + return int64_stor_; + } + + uint64_storage& cast(identity) + { + return uint64_stor_; + } + + const uint64_storage& cast(identity) const + { + return uint64_stor_; + } + + half_storage& cast(identity) + { + return half_stor_; + } + + const half_storage& cast(identity) const + { + return half_stor_; + } + + double_storage& cast(identity) + { + return double_stor_; + } + + const double_storage& cast(identity) const + { + return double_stor_; + } + + short_string_storage& cast(identity) + { + return short_string_stor_; + } + + const short_string_storage& cast(identity) const + { + return short_string_stor_; + } + + long_string_storage& cast(identity) + { + return long_string_stor_; + } + + const long_string_storage& cast(identity) const + { + return long_string_stor_; + } + + byte_string_storage& cast(identity) + { + return byte_string_stor_; + } + + const byte_string_storage& cast(identity) const + { + return byte_string_stor_; + } + + object_storage& cast(identity) + { + return object_stor_; + } + + const object_storage& cast(identity) const + { + return object_stor_; + } + + array_storage& cast(identity) + { + return array_stor_; + } + + const array_storage& cast(identity) const + { + return array_stor_; + } + + json_const_pointer_storage& cast(identity) + { + return json_const_pointer_stor_; + } + + const json_const_pointer_storage& cast(identity) const + { + return json_const_pointer_stor_; + } + + template + void swap_a_b(basic_json& other) + { + TypeA& curA = cast(); + TypeB& curB = other.cast(); + TypeB tmpB(std::move(curB)); + other.construct(std::move(curA)); + construct(std::move(tmpB)); + } + + template + void swap_a(basic_json& other) + { + switch (other.storage_kind()) + { + case json_storage_kind::null_value : swap_a_b(other); break; + case json_storage_kind::empty_object_value : swap_a_b(other); break; + case json_storage_kind::bool_value : swap_a_b(other); break; + case json_storage_kind::int64_value : swap_a_b(other); break; + case json_storage_kind::uint64_value : swap_a_b(other); break; + case json_storage_kind::half_value : swap_a_b(other); break; + case json_storage_kind::double_value : swap_a_b(other); break; + case json_storage_kind::short_string_value : swap_a_b(other); break; + case json_storage_kind::long_string_value : swap_a_b(other); break; + case json_storage_kind::byte_string_value : swap_a_b(other); break; + case json_storage_kind::array_value : swap_a_b(other); break; + case json_storage_kind::object_value : swap_a_b(other); break; + case json_storage_kind::json_const_pointer : swap_a_b(other); break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + void Init_(const basic_json& val) + { + switch (val.storage_kind()) + { + case json_storage_kind::null_value: + construct(val.cast()); + break; + case json_storage_kind::empty_object_value: + construct(val.cast()); + break; + case json_storage_kind::bool_value: + construct(val.cast()); + break; + case json_storage_kind::int64_value: + construct(val.cast()); + break; + case json_storage_kind::uint64_value: + construct(val.cast()); + break; + case json_storage_kind::half_value: + construct(val.cast()); + break; + case json_storage_kind::double_value: + construct(val.cast()); + break; + case json_storage_kind::short_string_value: + construct(val.cast()); + break; + case json_storage_kind::long_string_value: + construct(val.cast()); + break; + case json_storage_kind::byte_string_value: + construct(val.cast()); + break; + case json_storage_kind::object_value: + construct(val.cast()); + break; + case json_storage_kind::array_value: + construct(val.cast()); + break; + case json_storage_kind::json_const_pointer: + construct(val.cast()); + break; + default: + break; + } + } + + void Init_(const basic_json& val, const Allocator& a) + { + switch (val.storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + case json_storage_kind::bool_value: + case json_storage_kind::int64_value: + case json_storage_kind::uint64_value: + case json_storage_kind::half_value: + case json_storage_kind::double_value: + case json_storage_kind::short_string_value: + case json_storage_kind::json_const_pointer: + Init_(val); + break; + case json_storage_kind::long_string_value: + construct(val.cast(),a); + break; + case json_storage_kind::byte_string_value: + construct(val.cast(),a); + break; + case json_storage_kind::array_value: + construct(val.cast(),a); + break; + case json_storage_kind::object_value: + construct(val.cast(),a); + break; + default: + break; + } + } + + void Init_rv_(basic_json&& val) noexcept + { + switch (val.storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + case json_storage_kind::half_value: + case json_storage_kind::double_value: + case json_storage_kind::int64_value: + case json_storage_kind::uint64_value: + case json_storage_kind::bool_value: + case json_storage_kind::short_string_value: + case json_storage_kind::json_const_pointer: + Init_(val); + break; + case json_storage_kind::long_string_value: + case json_storage_kind::byte_string_value: + case json_storage_kind::array_value: + case json_storage_kind::object_value: + { + construct(); + swap(val); + break; + } + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + void Init_rv_(basic_json&& val, const Allocator&, std::true_type) noexcept + { + Init_rv_(std::forward(val)); + } + + void Init_rv_(basic_json&& val, const Allocator& a, std::false_type) noexcept + { + switch (val.storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + case json_storage_kind::half_value: + case json_storage_kind::double_value: + case json_storage_kind::int64_value: + case json_storage_kind::uint64_value: + case json_storage_kind::bool_value: + case json_storage_kind::short_string_value: + case json_storage_kind::json_const_pointer: + Init_(std::forward(val)); + break; + case json_storage_kind::long_string_value: + { + if (a == val.cast().get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + break; + } + case json_storage_kind::byte_string_value: + { + if (a == val.cast().get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + break; + } + case json_storage_kind::object_value: + { + if (a == val.cast().get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + break; + } + case json_storage_kind::array_value: + { + if (a == val.cast().get_allocator()) + { + Init_rv_(std::forward(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + break; + } + default: + break; + } + } + + basic_json& evaluate_with_default() + { + 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); + } + + public: + + basic_json& evaluate() + { + return *this; + } + + const basic_json& evaluate() const + { + return *this; + } + + basic_json& operator=(const basic_json& val) + { + if (this != &val) + { + Destroy_(); + Init_(val); + } + return *this; + } + + basic_json& operator=(basic_json&& val) noexcept + { + if (this !=&val) + { + swap(val); + } + return *this; + } + + json_storage_kind storage_kind() const + { + // It is legal to access 'common_stor_.storage_kind_' even though + // common_stor_ is not the active member of the union because 'storage_kind_' + // is a part of the common initial sequence of all union members + // as defined in 11.4-25 of the Standard. + return static_cast(common_stor_.storage_kind_); + } + + json_type type() const + { + switch(storage_kind()) + { + case json_storage_kind::null_value: + return json_type::null_value; + case json_storage_kind::bool_value: + return json_type::bool_value; + case json_storage_kind::int64_value: + return json_type::int64_value; + case json_storage_kind::uint64_value: + return json_type::uint64_value; + case json_storage_kind::half_value: + return json_type::half_value; + case json_storage_kind::double_value: + return json_type::double_value; + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + return json_type::string_value; + case json_storage_kind::byte_string_value: + return json_type::byte_string_value; + case json_storage_kind::array_value: + return json_type::array_value; + case json_storage_kind::empty_object_value: + case json_storage_kind::object_value: + return json_type::object_value; + case json_storage_kind::json_const_pointer: + return cast().value()->type(); + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + semantic_tag tag() const + { + // It is legal to access 'common_stor_.tag_' even though + // common_stor_ is not the active member of the union because 'tag_' + // is a part of the common initial sequence of all union members + // as defined in 11.4-25 of the Standard. + switch(storage_kind()) + { + case json_storage_kind::json_const_pointer: + return cast().value()->tag(); + default: + return common_stor_.tag_; + } + } + + std::size_t size() const + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return cast().value().size(); + case json_storage_kind::empty_object_value: + return 0; + case json_storage_kind::object_value: + return cast().value().size(); + case json_storage_kind::json_const_pointer: + return cast().value()->size(); + default: + return 0; + } + } + + string_view_type as_string_view() const + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + return string_view_type(cast().data(),cast().length()); + case json_storage_kind::long_string_value: + return string_view_type(cast().data(),cast().length()); + case json_storage_kind::json_const_pointer: + return cast().value()->as_string_view(); + default: + JSONCONS_THROW(json_runtime_error("Not a string")); + } + } + + template > + basic_byte_string as_byte_string() const + { + using byte_string_type = basic_byte_string; + converter convert; + std::error_code ec; + + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + byte_string_type v = convert.from(as_string_view(),tag(),ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + return v; + } + case json_storage_kind::byte_string_value: + return basic_byte_string(cast().data(),cast().length()); + case json_storage_kind::json_const_pointer: + return cast().value()->as_byte_string(); + default: + JSONCONS_THROW(json_runtime_error("Not a byte string")); + } + } + + byte_string_view as_byte_string_view() const + { + switch (storage_kind()) + { + case json_storage_kind::byte_string_value: + return byte_string_view(cast().data(),cast().length()); + case json_storage_kind::json_const_pointer: + return cast().value()->as_byte_string_view(); + default: + JSONCONS_THROW(json_runtime_error("Not a byte string")); + } + } + + int compare(const basic_json& rhs) const noexcept + { + if (this == &rhs) + { + return 0; + } + switch (storage_kind()) + { + case json_storage_kind::json_const_pointer: + switch (rhs.storage_kind()) + { + case json_storage_kind::json_const_pointer: + return (cast().value())->compare(*(rhs.cast().value())); + default: + return (cast().value())->compare(rhs); + } + break; + case json_storage_kind::null_value: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + case json_storage_kind::empty_object_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::empty_object_value: + return 0; + case json_storage_kind::object_value: + return rhs.empty() ? 0 : -1; + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::bool_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::bool_value: + return static_cast(cast().value()) - static_cast(rhs.cast().value()); + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::int64_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::int64_value: + { + if (cast().value() == rhs.cast().value()) + return 0; + return cast().value() < rhs.cast().value() ? -1 : 1; + } + case json_storage_kind::uint64_value: + if (cast().value() < 0) + return -1; + else if (static_cast(cast().value()) == rhs.cast().value()) + return 0; + else + return static_cast(cast().value()) < rhs.cast().value() ? -1 : 1; + case json_storage_kind::double_value: + { + double r = static_cast(cast().value()) - rhs.cast().value(); + return r == 0.0 ? 0 : (r < 0.0 ? -1 : 1); + } + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::uint64_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::int64_value: + if (rhs.cast().value() < 0) + return 1; + else if (cast().value() == static_cast(rhs.cast().value())) + return 0; + else + return cast().value() < static_cast(rhs.cast().value()) ? -1 : 1; + case json_storage_kind::uint64_value: + if (cast().value() == static_cast(rhs.cast().value())) + return 0; + else + return cast().value() < static_cast(rhs.cast().value()) ? -1 : 1; + case json_storage_kind::double_value: + { + auto r = static_cast(cast().value()) - rhs.cast().value(); + return r == 0 ? 0 : (r < 0.0 ? -1 : 1); + } + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::double_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::int64_value: + { + auto r = cast().value() - static_cast(rhs.cast().value()); + return r == 0 ? 0 : (r < 0.0 ? -1 : 1); + } + case json_storage_kind::uint64_value: + { + auto r = cast().value() - static_cast(rhs.cast().value()); + return r == 0 ? 0 : (r < 0.0 ? -1 : 1); + } + case json_storage_kind::double_value: + { + auto r = cast().value() - rhs.cast().value(); + return r == 0 ? 0 : (r < 0.0 ? -1 : 1); + } + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::short_string_value: + return as_string_view().compare(rhs.as_string_view()); + case json_storage_kind::long_string_value: + return as_string_view().compare(rhs.as_string_view()); + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::byte_string_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::byte_string_value: + { + return as_byte_string_view().compare(rhs.as_byte_string_view()); + } + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::array_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::array_value: + { + if (cast().value() == rhs.cast().value()) + return 0; + else + return cast().value() < rhs.cast().value() ? -1 : 1; + } + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + case json_storage_kind::object_value: + switch (rhs.storage_kind()) + { + case json_storage_kind::empty_object_value: + return empty() ? 0 : 1; + case json_storage_kind::object_value: + { + if (cast().value() == rhs.cast().value()) + return 0; + else + return cast().value() < rhs.cast().value() ? -1 : 1; + } + case json_storage_kind::json_const_pointer: + return compare(*(rhs.cast().value())); + default: + return static_cast(storage_kind()) - static_cast((int)rhs.storage_kind()); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + void swap(basic_json& other) noexcept + { + if (this == &other) + { + return; + } + + switch (storage_kind()) + { + case json_storage_kind::null_value: swap_a(other); break; + case json_storage_kind::empty_object_value : swap_a(other); break; + case json_storage_kind::bool_value: swap_a(other); break; + case json_storage_kind::int64_value: swap_a(other); break; + case json_storage_kind::uint64_value: swap_a(other); break; + case json_storage_kind::half_value: swap_a(other); break; + case json_storage_kind::double_value: swap_a(other); break; + case json_storage_kind::short_string_value: swap_a(other); break; + case json_storage_kind::long_string_value: swap_a(other); break; + case json_storage_kind::byte_string_value: swap_a(other); break; + case json_storage_kind::array_value: swap_a(other); break; + case json_storage_kind::object_value: swap_a(other); break; + case json_storage_kind::json_const_pointer: swap_a(other); break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + // from string + + template + static + typename std::enable_if::value,basic_json>::type + parse(const Source& s, + const basic_json_decode_options& options = basic_json_decode_options(), + std::function err_handler = default_json_parsing()) + { + json_decoder decoder; + basic_json_parser parser(options,err_handler); + + auto r = unicode_traits::detect_encoding_from_bom(s.data(), s.size()); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser.line(),parser.column())); + } + std::size_t offset = (r.ptr - s.data()); + parser.update(s.data()+offset,s.size()-offset); + parser.parse_some(decoder); + parser.finish_parse(decoder); + parser.check_done(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(json_errc::source_error, "Failed to parse json string")); + } + return decoder.get_result(); + } + + template + static + typename std::enable_if::value,basic_json>::type + parse(const Source& s, + std::function err_handler) + { + return parse(s, basic_json_decode_options(), err_handler); + } + + static basic_json parse(const char_type* s, + const basic_json_decode_options& options = basic_json_decode_options(), + std::function err_handler = default_json_parsing()) + { + return parse(jsoncons::basic_string_view(s), options, err_handler); + } + + static basic_json parse(const char_type* s, + std::function err_handler) + { + return parse(jsoncons::basic_string_view(s), basic_json_decode_options(), err_handler); + } + + // from stream + + static basic_json parse(std::basic_istream& is, + const basic_json_decode_options& options = basic_json_decode_options(), + std::function err_handler = default_json_parsing()) + { + json_decoder visitor; + basic_json_reader> reader(is, visitor, options, err_handler); + reader.read_next(); + reader.check_done(); + if (!visitor.is_valid()) + { + JSONCONS_THROW(ser_error(json_errc::source_error, "Failed to parse json stream")); + } + return visitor.get_result(); + } + + static basic_json parse(std::basic_istream& is, std::function err_handler) + { + return parse(is, basic_json_decode_options(), err_handler); + } + + // from iterator + + template + static basic_json parse(InputIt first, InputIt last, + const basic_json_decode_options& options = basic_json_decode_options(), + std::function err_handler = default_json_parsing()) + { + json_decoder visitor; + basic_json_reader> reader(iterator_source(std::forward(first),std::forward(last)), visitor, options, err_handler); + reader.read_next(); + reader.check_done(); + if (!visitor.is_valid()) + { + JSONCONS_THROW(ser_error(json_errc::source_error, "Failed to parse json from iterator pair")); + } + return visitor.get_result(); + } + + template + static basic_json parse(InputIt first, InputIt last, + std::function err_handler) + { + return parse(first, last, basic_json_decode_options(), err_handler); + } + + static basic_json make_array() + { + return basic_json(array()); + } + + static basic_json make_array(const array& a) + { + return basic_json(a); + } + + static basic_json make_array(const array& a, allocator_type alloc) + { + return basic_json(a, semantic_tag::none, alloc); + } + + static basic_json make_array(std::initializer_list init, const Allocator& alloc = Allocator()) + { + return array(std::move(init),alloc); + } + + static basic_json make_array(std::size_t n, const Allocator& alloc = Allocator()) + { + return array(n,alloc); + } + + template + static basic_json make_array(std::size_t n, const T& val, const Allocator& alloc = Allocator()) + { + return basic_json::array(n, val,alloc); + } + + template + static typename std::enable_if::type make_array(std::size_t n) + { + return array(n); + } + + template + static typename std::enable_if::type make_array(std::size_t n, const T& val, const Allocator& alloc = Allocator()) + { + return array(n,val,alloc); + } + + template + static typename std::enable_if<(dim>1),basic_json>::type make_array(std::size_t n, Args... args) + { + const size_t dim1 = dim - 1; + + basic_json val = make_array(std::forward(args)...); + val.resize(n); + for (std::size_t i = 0; i < n; ++i) + { + val[i] = make_array(std::forward(args)...); + } + return val; + } + + static const basic_json& null() + { + static const basic_json a_null = basic_json(null_type(), semantic_tag::none); + return a_null; + } + + basic_json() + { + construct(semantic_tag::none); + } + + basic_json(semantic_tag tag) + { + construct(tag); + } + + #if !defined(JSONCONS_NO_DEPRECATED) + + JSONCONS_DEPRECATED_MSG("Instead, use basic_json(json_object_t,semantic_tag,const Allocator&)") + explicit basic_json(const Allocator& alloc, semantic_tag tag = semantic_tag::none) + { + construct(object(alloc), tag); + } + + #endif + + basic_json(const basic_json& other) + { + Init_(other); + } + + basic_json(const basic_json& other, const Allocator& alloc) + { + Init_(other,alloc); + } + + basic_json(basic_json&& other) noexcept + { + Init_rv_(std::forward(other)); + } + + basic_json(basic_json&& other, const Allocator&) noexcept + { + Init_rv_(std::forward(other)); + } + + explicit basic_json(json_object_arg_t, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator()) + { + construct(object(alloc), tag); + } + + template + basic_json(json_object_arg_t, + InputIt first, InputIt last, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator()) + { + construct(object(first,last,alloc), tag); + } + + basic_json(json_object_arg_t, + std::initializer_list,basic_json>> init, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator()) + { + construct(object(init,alloc), tag); + } + + explicit basic_json(json_array_arg_t, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator()) + { + construct(array(alloc), tag); + } + + template + basic_json(json_array_arg_t, + InputIt first, InputIt last, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator()) + { + construct(array(first,last,alloc), tag); + } + + basic_json(json_array_arg_t, + std::initializer_list init, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator()) + { + construct(array(init,alloc), tag); + } + + basic_json(json_const_pointer_arg_t, const basic_json* p) noexcept + { + if (p == nullptr) + { + construct(semantic_tag::none); + } + else + { + construct(p); + } + } + + basic_json(const array& val, semantic_tag tag = semantic_tag::none) + { + construct(val, tag); + } + + basic_json(array&& val, semantic_tag tag = semantic_tag::none) + { + construct(std::forward(val), tag); + } + + basic_json(const object& val, semantic_tag tag = semantic_tag::none) + { + construct(val, tag); + } + + basic_json(object&& val, semantic_tag tag = semantic_tag::none) + { + construct(std::forward(val), tag); + } + + template ::value && !type_traits::is_basic_json::value>::type> + basic_json(const T& val) + : basic_json(json_type_traits::to_json(val)) + { + } + + template ::value && !type_traits::is_basic_json::value>::type> + basic_json(const T& val, const Allocator& alloc) + : basic_json(json_type_traits::to_json(val,alloc)) + { + } + + basic_json(const char_type* s, semantic_tag tag = semantic_tag::none) + : basic_json(s, char_traits_type::length(s), tag) + { + } + + basic_json(const char_type* s, const Allocator& alloc) + : basic_json(s, char_traits_type::length(s), semantic_tag::none, alloc) + { + } + + basic_json(const char_type* s, std::size_t length, semantic_tag tag = semantic_tag::none) + { + if (length <= short_string_storage::max_length) + { + construct(tag, s, static_cast(length)); + } + else + { + construct(tag, s, length, char_allocator_type()); + } + } + + basic_json(const char_type* s, std::size_t length, semantic_tag tag, const Allocator& alloc) + { + if (length <= short_string_storage::max_length) + { + construct(tag, s, static_cast(length)); + } + else + { + construct(tag, s, length, alloc); + } + } + + basic_json(half_arg_t, uint16_t val, semantic_tag tag = semantic_tag::none) + { + construct(val, tag); + } + + basic_json(double val, semantic_tag tag) + { + construct(val, tag); + } + + template + basic_json(IntegerType val, semantic_tag tag, + typename std::enable_if::value && sizeof(IntegerType) <= sizeof(uint64_t), int>::type = 0) + { + construct(val, tag); + } + + template + basic_json(IntegerType val, semantic_tag tag, Allocator, + typename std::enable_if::value && sizeof(IntegerType) <= sizeof(uint64_t), int>::type = 0) + { + construct(val, tag); + } + + template + basic_json(IntegerType val, semantic_tag, Allocator alloc = Allocator(), + typename std::enable_if::value && sizeof(uint64_t) < sizeof(IntegerType), int>::type = 0) + { + std::basic_string s; + jsoncons::detail::from_integer(val, s); + if (s.length() <= short_string_storage::max_length) + { + construct(semantic_tag::bigint, s.data(), static_cast(s.length())); + } + else + { + construct(semantic_tag::bigint, s.data(), s.length(), alloc); + } + } + + template + basic_json(IntegerType val, semantic_tag tag, + typename std::enable_if::value && sizeof(IntegerType) <= sizeof(int64_t),int>::type = 0) + { + construct(val, tag); + } + + template + basic_json(IntegerType val, semantic_tag tag, Allocator, + typename std::enable_if::value && sizeof(IntegerType) <= sizeof(int64_t),int>::type = 0) + { + construct(val, tag); + } + + template + basic_json(IntegerType val, semantic_tag, Allocator alloc = Allocator(), + typename std::enable_if::value && sizeof(int64_t) < sizeof(IntegerType),int>::type = 0) + { + std::basic_string s; + jsoncons::detail::from_integer(val, s); + if (s.length() <= short_string_storage::max_length) + { + construct(semantic_tag::bigint, s.data(), static_cast(s.length())); + } + else + { + construct(semantic_tag::bigint, s.data(), s.length(), alloc); + } + } + + basic_json(const string_view_type& sv, semantic_tag tag) + : basic_json(sv.data(), sv.length(), tag) + { + } + + basic_json(null_type, semantic_tag tag) + { + construct(tag); + } + + basic_json(bool val, semantic_tag tag) + { + construct(val,tag); + } + + basic_json(const string_view_type& sv, semantic_tag tag, const Allocator& alloc) + : basic_json(sv.data(), sv.length(), tag, alloc) + { + } + + template + basic_json(byte_string_arg_t, const Source& source, + semantic_tag tag = semantic_tag::none, + const Allocator& alloc = Allocator(), + typename std::enable_if::value,int>::type = 0) + { + auto bytes = jsoncons::span(reinterpret_cast(source.data()), source.size()); + construct(tag, bytes.data(), bytes.size(), 0, alloc); + } + + template + basic_json(byte_string_arg_t, const Source& source, + uint64_t ext_tag, + const Allocator& alloc = Allocator(), + typename std::enable_if::value,int>::type = 0) + { + auto bytes = jsoncons::span(reinterpret_cast(source.data()), source.size()); + construct(semantic_tag::ext, bytes.data(), bytes.size(), ext_tag, alloc); + } + + ~basic_json() noexcept + { + Destroy_(); + } + + template + basic_json& operator=(const T& val) + { + *this = json_type_traits::to_json(val); + return *this; + } + + basic_json& operator=(const char_type* s) + { + *this = basic_json(s, char_traits_type::length(s), semantic_tag::none); + return *this; + } + + basic_json& operator[](std::size_t i) + { + return at(i); + } + + const basic_json& operator[](std::size_t i) const + { + return at(i); + } + + proxy_type operator[](const string_view_type& name) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + return proxy_type(*this, name); + 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 + typename std::enable_if::value>::type + dump(Container& s, + const basic_json_encode_options& options = basic_json_encode_options()) const + { + std::error_code ec; + dump(s, options, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + template + typename std::enable_if::value>::type + dump_pretty(Container& s, + const basic_json_encode_options& options = basic_json_encode_options()) const + { + std::error_code ec; + dump_pretty(s, options, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + void dump(std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_encode_options()) const + { + std::error_code ec; + dump(os, options, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + void dump_pretty(std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_encode_options()) const + { + std::error_code ec; + dump_pretty(os, options, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + // Legacy + + template + typename std::enable_if::value>::type + dump(Container& s, + indenting line_indent) const + { + std::error_code ec; + + dump(s, line_indent, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + template + typename std::enable_if::value>::type + dump(Container& s, + const basic_json_encode_options& options, + indenting line_indent) const + { + std::error_code ec; + + dump(s, options, line_indent, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + void dump(std::basic_ostream& os, + indenting line_indent) const + { + std::error_code ec; + + dump(os, line_indent, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + void dump(std::basic_ostream& os, + const basic_json_encode_options& options, + indenting line_indent) const + { + std::error_code ec; + + dump(os, options, line_indent, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + // end legacy + + void dump(basic_json_visitor& visitor) const + { + std::error_code ec; + dump(visitor, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + } + + // dump + template + typename std::enable_if::value>::type + dump(Container& s, + const basic_json_encode_options& options, + std::error_code& ec) const + { + basic_compact_json_encoder> encoder(s, options); + dump(encoder, ec); + } + + template + typename std::enable_if::value>::type + dump(Container& s, + std::error_code& ec) const + { + basic_compact_json_encoder> encoder(s); + dump(encoder, ec); + } + + void dump(std::basic_ostream& os, + const basic_json_encode_options& options, + std::error_code& ec) const + { + basic_compact_json_encoder encoder(os, options); + dump(encoder, ec); + } + + void dump(std::basic_ostream& os, + std::error_code& ec) const + { + basic_compact_json_encoder encoder(os); + dump(encoder, ec); + } + + // dump_pretty + + template + typename std::enable_if::value>::type + dump_pretty(Container& s, + const basic_json_encode_options& options, + std::error_code& ec) const + { + basic_json_encoder> encoder(s, options); + dump(encoder, ec); + } + + template + typename std::enable_if::value>::type + dump_pretty(Container& s, + std::error_code& ec) const + { + dump_pretty(s, basic_json_encode_options(), ec); + } + + void dump_pretty(std::basic_ostream& os, + const basic_json_encode_options& options, + std::error_code& ec) const + { + basic_json_encoder encoder(os, options); + dump(encoder, ec); + } + + void dump_pretty(std::basic_ostream& os, + std::error_code& ec) const + { + dump_pretty(os, basic_json_encode_options(), ec); + } + + // legacy + template + typename std::enable_if::value>::type + dump(Container& s, + const basic_json_encode_options& options, + indenting line_indent, + std::error_code& ec) const + { + if (line_indent == indenting::indent) + { + dump_pretty(s, options, ec); + } + else + { + dump(s, options, ec); + } + } + + template + typename std::enable_if::value>::type + dump(Container& s, + indenting line_indent, + std::error_code& ec) const + { + if (line_indent == indenting::indent) + { + dump_pretty(s, ec); + } + else + { + dump(s, ec); + } + } + + void dump(std::basic_ostream& os, + const basic_json_encode_options& options, + indenting line_indent, + std::error_code& ec) const + { + if (line_indent == indenting::indent) + { + dump_pretty(os, options, ec); + } + else + { + dump(os, options, ec); + } + } + + void dump(std::basic_ostream& os, + indenting line_indent, + std::error_code& ec) const + { + if (line_indent == indenting::indent) + { + dump_pretty(os, ec); + } + else + { + dump(os, ec); + } + } + // end legacy + + void dump(basic_json_visitor& visitor, + std::error_code& ec) const + { + dump_noflush(visitor, ec); + if (ec) + { + return; + } + visitor.flush(); + } + + bool is_null() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::null_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_null(); + default: + return false; + } + } + + allocator_type get_allocator() const + { + switch (storage_kind()) + { + case json_storage_kind::long_string_value: + { + return cast().get_allocator(); + } + case json_storage_kind::byte_string_value: + { + return cast().get_allocator(); + } + case json_storage_kind::array_value: + { + return cast().get_allocator(); + } + case json_storage_kind::object_value: + { + return cast().get_allocator(); + } + default: + return allocator_type(); + } + } + + uint64_t ext_tag() const + { + switch (storage_kind()) + { + case json_storage_kind::byte_string_value: + { + return cast().ext_tag(); + } + case json_storage_kind::json_const_pointer: + return cast().value()->ext_tag(); + default: + return 0; + } + } + + bool contains(const string_view_type& key) const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + return it != object_value().end(); + } + case json_storage_kind::json_const_pointer: + return cast().value()->contains(key); + default: + return false; + } + } + + std::size_t count(const string_view_type& key) const + { + switch (storage_kind()) + { + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + if (it == object_value().end()) + { + return 0; + } + std::size_t count = 0; + while (it != object_value().end()&& it->key() == key) + { + ++count; + ++it; + } + return count; + } + case json_storage_kind::json_const_pointer: + return cast().value()->count(key); + default: + return 0; + } + } + + template + bool is(Args&&... args) const noexcept + { + return json_type_traits::is(*this,std::forward(args)...); + } + + bool is_string() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_string(); + default: + return false; + } + } + + bool is_string_view() const noexcept + { + return is_string(); + } + + bool is_byte_string() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::byte_string_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_byte_string(); + default: + return false; + } + } + + bool is_byte_string_view() const noexcept + { + return is_byte_string(); + } + + bool is_bignum() const + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + return jsoncons::detail::is_base10(as_string_view().data(), as_string_view().length()); + case json_storage_kind::int64_value: + case json_storage_kind::uint64_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_bignum(); + default: + return false; + } + } + + bool is_bool() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::bool_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_bool(); + default: + return false; + } + } + + bool is_object() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + case json_storage_kind::object_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_object(); + default: + return false; + } + } + + bool is_array() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_array(); + default: + return false; + } + } + + bool is_int64() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::int64_value: + return true; + case json_storage_kind::uint64_value: + return as_integer() <= static_cast((std::numeric_limits::max)()); + case json_storage_kind::json_const_pointer: + return cast().value()->is_int64(); + default: + return false; + } + } + + bool is_uint64() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::uint64_value: + return true; + case json_storage_kind::int64_value: + return as_integer() >= 0; + case json_storage_kind::json_const_pointer: + return cast().value()->is_uint64(); + default: + return false; + } + } + + bool is_half() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::half_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_half(); + default: + return false; + } + } + + bool is_double() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::double_value: + return true; + case json_storage_kind::json_const_pointer: + return cast().value()->is_double(); + default: + return false; + } + } + + bool is_number() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::int64_value: + case json_storage_kind::uint64_value: + case json_storage_kind::half_value: + case json_storage_kind::double_value: + return true; + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + return tag() == semantic_tag::bigint || + tag() == semantic_tag::bigdec || + tag() == semantic_tag::bigfloat; + case json_storage_kind::json_const_pointer: + return cast().value()->is_number(); + default: + return false; + } + } + + bool empty() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::byte_string_value: + return cast().length() == 0; + break; + case json_storage_kind::short_string_value: + return cast().length() == 0; + case json_storage_kind::long_string_value: + return cast().length() == 0; + case json_storage_kind::array_value: + return array_value().empty(); + case json_storage_kind::empty_object_value: + return true; + case json_storage_kind::object_value: + return object_value().empty(); + case json_storage_kind::json_const_pointer: + return cast().value()->empty(); + default: + return false; + } + } + + std::size_t capacity() const + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().capacity(); + case json_storage_kind::object_value: + return object_value().capacity(); + case json_storage_kind::json_const_pointer: + return cast().value()->capacity(); + default: + return 0; + } + } + + template + void create_object_implicitly() + { + create_object_implicitly(type_traits::is_stateless()); + } + + void create_object_implicitly(std::false_type) + { + static_assert(std::true_type::value, "Cannot create object implicitly - alloc is stateful."); + } + + void create_object_implicitly(std::true_type) + { + *this = basic_json(json_object_arg, tag()); + } + + void reserve(std::size_t n) + { + if (n > 0) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().reserve(n); + break; + case json_storage_kind::empty_object_value: + { + create_object_implicitly(); + object_value().reserve(n); + } + break; + case json_storage_kind::object_value: + { + object_value().reserve(n); + } + break; + default: + break; + } + } + } + + void resize(std::size_t n) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().resize(n); + break; + default: + break; + } + } + + template + void resize(std::size_t n, T val) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().resize(n, val); + break; + default: + break; + } + } + + template + typename std::enable_if::value,T>::type + as() const + { + T val = json_type_traits::as(*this); + return val; + } + + template + typename std::enable_if<(!type_traits::is_basic_string::value && + type_traits::is_back_insertable_byte_container::value) || + type_traits::is_basic_byte_string::value,T>::type + as(byte_string_arg_t, semantic_tag hint) const + { + converter convert; + std::error_code ec; + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + switch (tag()) + { + case semantic_tag::base16: + case semantic_tag::base64: + case semantic_tag::base64url: + { + T v = convert.from(as_string_view(),tag(),ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + return v; + } + default: + { + T v = convert.from(as_string_view(), hint, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + return T(v.begin(),v.end()); + } + break; + } + break; + } + case json_storage_kind::byte_string_value: + return T(as_byte_string_view().begin(), as_byte_string_view().end()); + case json_storage_kind::json_const_pointer: + return cast().value()->template as(byte_string_arg, hint); + default: + JSONCONS_THROW(json_runtime_error("Not a byte string")); + } + } + + bool as_bool() const + { + switch (storage_kind()) + { + case json_storage_kind::bool_value: + return cast().value(); + case json_storage_kind::int64_value: + return cast().value() != 0; + case json_storage_kind::uint64_value: + return cast().value() != 0; + case json_storage_kind::json_const_pointer: + return cast().value()->as_bool(); + default: + JSONCONS_THROW(json_runtime_error("Not a bool")); + } + } + + template + IntegerType as_integer() const + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + IntegerType val; + auto result = jsoncons::detail::to_integer(as_string_view().data(), as_string_view().length(), val); + if (!result) + { + JSONCONS_THROW(json_runtime_error(result.error_code().message())); + } + return val; + } + case json_storage_kind::half_value: + return static_cast(cast().value()); + case json_storage_kind::double_value: + return static_cast(cast().value()); + case json_storage_kind::int64_value: + return static_cast(cast().value()); + case json_storage_kind::uint64_value: + return static_cast(cast().value()); + case json_storage_kind::bool_value: + return static_cast(cast().value() ? 1 : 0); + case json_storage_kind::json_const_pointer: + return cast().value()->template as_integer(); + default: + JSONCONS_THROW(json_runtime_error("Not an integer")); + } + } + + template + typename std::enable_if::value && sizeof(IntegerType) <= sizeof(int64_t),bool>::type + is_integer() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::int64_value: + return (as_integer() >= (type_traits::integer_limits::lowest)()) && (as_integer() <= (type_traits::integer_limits::max)()); + case json_storage_kind::uint64_value: + return as_integer() <= static_cast((type_traits::integer_limits::max)()); + case json_storage_kind::json_const_pointer: + return cast().value()->template is_integer(); + default: + return false; + } + } + + template + typename std::enable_if::value && sizeof(int64_t) < sizeof(IntegerType),bool>::type + is_integer() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + IntegerType val; + auto result = jsoncons::detail::to_integer(as_string_view().data(), as_string_view().length(), val); + return result ? true : false; + } + case json_storage_kind::int64_value: + return (as_integer() >= (type_traits::integer_limits::lowest)()) && (as_integer() <= (type_traits::integer_limits::max)()); + case json_storage_kind::uint64_value: + return as_integer() <= static_cast((type_traits::integer_limits::max)()); + case json_storage_kind::json_const_pointer: + return cast().value()->template is_integer(); + default: + return false; + } + } + + template + typename std::enable_if::value && sizeof(IntegerType) <= sizeof(int64_t),bool>::type + is_integer() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::int64_value: + return as_integer() >= 0 && static_cast(as_integer()) <= (type_traits::integer_limits::max)(); + case json_storage_kind::uint64_value: + return as_integer() <= (type_traits::integer_limits::max)(); + case json_storage_kind::json_const_pointer: + return cast().value()->template is_integer(); + default: + return false; + } + } + + template + typename std::enable_if::value && sizeof(int64_t) < sizeof(IntegerType),bool>::type + is_integer() const noexcept + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + IntegerType val; + auto result = jsoncons::detail::to_integer(as_string_view().data(), as_string_view().length(), val); + return result ? true : false; + } + case json_storage_kind::int64_value: + return as_integer() >= 0 && static_cast(as_integer()) <= (type_traits::integer_limits::max)(); + case json_storage_kind::uint64_value: + return as_integer() <= (type_traits::integer_limits::max)(); + case json_storage_kind::json_const_pointer: + return cast().value()->template is_integer(); + default: + return false; + } + } + + double as_double() const + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + jsoncons::detail::chars_to to_double; + // to_double() throws std::invalid_argument if conversion fails + return to_double(as_cstring(), as_string_view().length()); + } + case json_storage_kind::half_value: + return binary::decode_half(cast().value()); + case json_storage_kind::double_value: + return cast().value(); + case json_storage_kind::int64_value: + return static_cast(cast().value()); + case json_storage_kind::uint64_value: + return static_cast(cast().value()); + case json_storage_kind::json_const_pointer: + return cast().value()->as_double(); + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + template > + std::basic_string as_string() const + { + return as_string(SAllocator()); + } + + template > + std::basic_string as_string(const SAllocator& alloc) const + { + using string_type = std::basic_string; + + converter convert; + std::error_code ec; + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + { + return string_type(as_string_view().data(),as_string_view().length(),alloc); + } + case json_storage_kind::byte_string_value: + { + auto s = convert.from(as_byte_string_view(), tag(), alloc, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + return s; + } + case json_storage_kind::array_value: + { + string_type s(alloc); + { + basic_compact_json_encoder> encoder(s); + dump(encoder); + } + return s; + } + case json_storage_kind::json_const_pointer: + return cast().value()->as_string(alloc); + default: + { + string_type s(alloc); + basic_compact_json_encoder> encoder(s); + dump(encoder); + return s; + } + } + } + + const char_type* as_cstring() const + { + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + return cast().c_str(); + case json_storage_kind::long_string_value: + return cast().c_str(); + case json_storage_kind::json_const_pointer: + return cast().value()->as_cstring(); + default: + JSONCONS_THROW(json_runtime_error("Not a cstring")); + } + } + + basic_json& at(const string_view_type& name) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case json_storage_kind::object_value: + { + auto it = object_value().find(name); + if (it == object_value().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const basic_json& at(const string_view_type& key) const + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + JSONCONS_THROW(key_not_found(key.data(),key.length())); + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + if (it == object_value().end()) + { + JSONCONS_THROW(key_not_found(key.data(),key.length())); + } + return it->value(); + } + case json_storage_kind::json_const_pointer: + return cast().value()->at(key); + default: + { + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } + } + } + + basic_json& at(std::size_t i) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return array_value().operator[](i); + case json_storage_kind::object_value: + return object_value().at(i); + default: + JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); + } + } + + const basic_json& at(std::size_t i) const + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return array_value().operator[](i); + case json_storage_kind::object_value: + return object_value().at(i); + case json_storage_kind::json_const_pointer: + return cast().value()->at(i); + default: + JSONCONS_THROW(json_runtime_error("Index on non-array value not supported")); + } + } + + object_iterator find(const string_view_type& name) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return object_range().end(); + case json_storage_kind::object_value: + return object_iterator(object_value().find(name)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const_object_iterator find(const string_view_type& key) const + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return object_range().end(); + case json_storage_kind::object_value: + return const_object_iterator(object_value().find(key)); + case json_storage_kind::json_const_pointer: + return cast().value()->find(key); + default: + { + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } + } + } + + const basic_json& at_or_null(const string_view_type& key) const + { + switch (storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + { + return null(); + } + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + if (it != object_value().end()) + { + return it->value(); + } + else + { + return null(); + } + } + case json_storage_kind::json_const_pointer: + return cast().value()->at_or_null(key); + default: + { + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } + } + } + + template + T get_value_or(const string_view_type& key, U&& default_value) const + { + static_assert(std::is_copy_constructible::value, + "get_value_or: T must be copy constructible"); + static_assert(std::is_convertible::value, + "get_value_or: U must be convertible to T"); + switch (storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + { + return static_cast(std::forward(default_value)); + } + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + if (it != object_value().end()) + { + return it->value().template as(); + } + else + { + return static_cast(std::forward(default_value)); + } + } + case json_storage_kind::json_const_pointer: + return cast().value()->template get_value_or(key,std::forward(default_value)); + default: + { + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } + } + } + + // Modifiers + + void shrink_to_fit() + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().shrink_to_fit(); + break; + case json_storage_kind::object_value: + object_value().shrink_to_fit(); + break; + default: + break; + } + } + + void clear() + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().clear(); + break; + case json_storage_kind::object_value: + object_value().clear(); + break; + default: + break; + } + } + + object_iterator erase(const_object_iterator pos) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return object_range().end(); + case json_storage_kind::object_value: + return object_iterator(object_value().erase(pos)); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + break; + } + } + + object_iterator erase(const_object_iterator first, const_object_iterator last) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return object_range().end(); + case json_storage_kind::object_value: + return object_iterator(object_value().erase(first, last)); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + break; + } + } + + array_iterator erase(const_array_iterator pos) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().erase(pos); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + } + } + + array_iterator erase(const_array_iterator first, const_array_iterator last) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().erase(first, last); + default: + JSONCONS_THROW(json_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 (storage_kind()) + { + case json_storage_kind::empty_object_value: + break; + case json_storage_kind::object_value: + object_value().erase(name); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + template + std::pair insert_or_assign(const string_view_type& name, T&& val) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + { + auto result = object_value().insert_or_assign(name, std::forward(val)); + return std::make_pair(object_iterator(result.first), result.second); + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + std::pair try_emplace(const string_view_type& name, Args&&... args) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + { + auto result = object_value().try_emplace(name, std::forward(args)...); + return std::make_pair(object_iterator(result.first),result.second); + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // merge + + void merge(const basic_json& source) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge(source.object_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + void merge(basic_json&& source) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge(std::move(source.object_value())); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, const basic_json& source) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge(hint, source.object_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, basic_json&& source) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge(hint, std::move(source.object_value())); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge a value that is not an object")); + } + } + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge_or_update(source.object_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(basic_json&& source) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge_or_update(std::move(source.object_value())); + break; + default: + { + JSONCONS_THROW(json_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 (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge_or_update(hint, source.object_value()); + break; + default: + { + JSONCONS_THROW(json_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 (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + object_value().merge_or_update(hint, std::move(source.object_value())); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to merge or update a value that is not an object")); + } + } + } + + template + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + return object_iterator(object_value().insert_or_assign(hint, name, std::forward(val))); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + return object_iterator(object_value().try_emplace(hint, name, std::forward(args)...)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template + array_iterator insert(const_array_iterator pos, T&& val) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().insert(pos, std::forward(val)); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().insert(pos, first, last); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + void insert(InputIt first, InputIt last) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + case json_storage_kind::object_value: + object_value().insert(first, last, get_key_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); + } + } + } + + template + void insert(sorted_unique_range_tag tag, InputIt first, InputIt last) + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + case json_storage_kind::object_value: + object_value().insert(tag, first, last, get_key_value()); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an object")); + } + } + } + + template + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().emplace(pos, std::forward(args)...); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + basic_json& emplace_back(Args&&... args) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return array_value().emplace_back(std::forward(args)...); + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + friend void swap(basic_json& a, basic_json& b) noexcept + { + a.swap(b); + } + + template + void push_back(T&& val) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().push_back(std::forward(val)); + break; + default: + { + JSONCONS_THROW(json_runtime_error("Attempting to insert into a value that is not an array")); + } + } + } + + template + T get_with_default(const string_view_type& key, const T& default_value) const + { + switch (storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + { + return default_value; + } + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + if (it != object_value().end()) + { + return it->value().template as(); + } + else + { + return default_value; + } + } + case json_storage_kind::json_const_pointer: + return cast().value()->get_with_default(key, default_value); + default: + { + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } + } + } + + template> + T get_with_default(const string_view_type& key, const char_type* default_value) const + { + switch (storage_kind()) + { + case json_storage_kind::null_value: + case json_storage_kind::empty_object_value: + { + return T(default_value); + } + case json_storage_kind::object_value: + { + auto it = object_value().find(key); + if (it != object_value().end()) + { + return it->value().template as(); + } + else + { + return T(default_value); + } + } + case json_storage_kind::json_const_pointer: + return cast().value()->get_with_default(key, default_value); + default: + { + JSONCONS_THROW(not_an_object(key.data(),key.length())); + } + } + } + + std::basic_string to_string() const noexcept + { + using string_type = std::basic_string; + string_type s; + basic_compact_json_encoder> encoder(s); + dump(encoder); + return s; + } + + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use basic_json(byte_string_arg_t, const Source&, semantic_tag=semantic_tag::none,const Allocator& = Allocator())") + basic_json(const byte_string_view& bytes, + semantic_tag tag, + const Allocator& alloc = Allocator()) + : basic_json(byte_string_arg, bytes, tag, alloc) + { + } + + JSONCONS_DEPRECATED_MSG("Instead, use at_or_null(const string_view_type&)") + const basic_json& get_with_default(const string_view_type& name) const + { + return at_or_null(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(const string_view_type&)") + static basic_json parse(const char_type* s, std::size_t length) + { + parse_error_handler_type err_handler; + return parse(s,length,err_handler); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(const string_view_type&, parse_error_handler)") + static basic_json parse(const char_type* s, std::size_t length, std::function err_handler) + { + return parse(string_view_type(s,length),err_handler); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(std::basic_istream&)") + static basic_json parse_file(const std::basic_string& filename) + { + parse_error_handler_type err_handler; + return parse_file(filename,err_handler); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(std::basic_istream&, std::function)") + static basic_json parse_file(const std::basic_string& filename, + std::function err_handler) + { + std::basic_ifstream is(filename); + return parse(is,err_handler); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(std::basic_istream&)") + static basic_json parse_stream(std::basic_istream& is) + { + return parse(is); + } + JSONCONS_DEPRECATED_MSG("Instead, use parse(std::basic_istream&, std::function)") + static basic_json parse_stream(std::basic_istream& is, std::function err_handler) + { + return parse(is,err_handler); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(const string_view_type&)") + static basic_json parse_string(const string_view_type& s) + { + return parse(s); + } + + JSONCONS_DEPRECATED_MSG("Instead, use parse(parse(const string_view_type&, std::function)") + static const basic_json parse_string(const string_view_type& s, std::function err_handler) + { + return parse(s,err_handler); + } + + JSONCONS_DEPRECATED_MSG("Instead, use basic_json(double)") + basic_json(double val, uint8_t) + : basic_json(val, semantic_tag::none) + { + } + + JSONCONS_DEPRECATED_MSG("Instead, use basic_json(const byte_string_view& ,semantic_tag)") + basic_json(const byte_string_view& bytes, + byte_string_chars_format encoding_hint, + semantic_tag tag = semantic_tag::none) + : basic_json(bytes, tag) + { + switch (encoding_hint) + { + case byte_string_chars_format::base16: + *this = basic_json(bytes, semantic_tag::base16); + break; + case byte_string_chars_format::base64: + *this = basic_json(bytes, semantic_tag::base64); + break; + case byte_string_chars_format::base64url: + *this = basic_json(bytes, semantic_tag::base64url); + break; + default: + break; + } + } + + template + basic_json(InputIterator first, InputIterator last, const Allocator& alloc = Allocator()) + : basic_json(json_array_arg,first,last,alloc) + { + } + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void dump_fragment(basic_json_visitor& visitor) const + { + dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void dump_body(basic_json_visitor& visitor) const + { + dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, indenting)") + void dump(std::basic_ostream& os, bool pprint) const + { + if (pprint) + { + basic_json_encoder encoder(os); + dump(encoder); + } + else + { + basic_compact_json_encoder encoder(os); + dump(encoder); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&, indenting)") + void dump(std::basic_ostream& os, const basic_json_encode_options& options, bool pprint) const + { + if (pprint) + { + basic_json_encoder encoder(os, options); + dump(encoder); + } + else + { + basic_compact_json_encoder encoder(os, options); + dump(encoder); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void write_body(basic_json_visitor& visitor) const + { + dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void write(basic_json_visitor& visitor) const + { + dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&)") + void write(std::basic_ostream& os) const + { + dump(os); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&)") + void write(std::basic_ostream& os, const basic_json_encode_options& options) const + { + dump(os,options); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&, indenting)") + void write(std::basic_ostream& os, const basic_json_encode_options& options, bool pprint) const + { + dump(os,options,pprint); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(basic_json_visitor&)") + void to_stream(basic_json_visitor& visitor) const + { + dump(visitor); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&)") + void to_stream(std::basic_ostream& os) const + { + dump(os); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&)") + void to_stream(std::basic_ostream& os, const basic_json_encode_options& options) const + { + dump(os,options); + } + + JSONCONS_DEPRECATED_MSG("Instead, use dump(std::basic_ostream&, const basic_json_encode_options&, indenting)") + void to_stream(std::basic_ostream& os, const basic_json_encode_options& options, bool pprint) const + { + dump(os,options,pprint ? indenting::indent : indenting::no_indent); + } + + JSONCONS_DEPRECATED_MSG("No replacement") + std::size_t precision() const + { + switch (storage_kind()) + { + case json_storage_kind::double_value: + return 0; + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + JSONCONS_DEPRECATED_MSG("No replacement") + std::size_t decimal_places() const + { + switch (storage_kind()) + { + case json_storage_kind::double_value: + return 0; + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use tag() == semantic_tag::datetime") + bool is_datetime() const noexcept + { + return tag() == semantic_tag::datetime; + } + + JSONCONS_DEPRECATED_MSG("Instead, use tag() == semantic_tag::epoch_second") + bool is_epoch_time() const noexcept + { + return tag() == semantic_tag::epoch_second; + } + + JSONCONS_DEPRECATED_MSG("Instead, use contains(const string_view_type&)") + bool has_key(const string_view_type& name) const noexcept + { + return contains(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + uint64_t as_uinteger() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("No replacement") + std::size_t double_precision() const + { + switch (storage_kind()) + { + case json_storage_kind::double_value: + return 0; + default: + JSONCONS_THROW(json_runtime_error("Not a double")); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use insert(const_array_iterator, T&&)") + void add(std::size_t index, const basic_json& value) + { + evaluate_with_default().add(index, value); + } + + JSONCONS_DEPRECATED_MSG("Instead, use insert(const_array_iterator, T&&)") + void add(std::size_t index, basic_json&& value) + { + evaluate_with_default().add(index, std::forward(value)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use push_back(T&&)") + void add(T&& val) + { + push_back(std::forward(val)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use insert(const_array_iterator, T&&)") + array_iterator add(const_array_iterator pos, T&& val) + { + return insert(pos, std::forward(val)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use insert_or_assign(const string_view_type&, T&&)") + std::pair set(const string_view_type& name, T&& val) + { + return insert_or_assign(name, std::forward(val)); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use insert_or_assign(const string_view_type&, T&&)") + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return insert_or_assign(hint, name, std::forward(val)); + } + + JSONCONS_DEPRECATED_MSG("Instead, use resize(std::size_t)") + void resize_array(std::size_t n) + { + resize(n); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use resize(std::size_t, T)") + void resize_array(std::size_t n, T val) + { + resize(n,val); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().begin()") + object_iterator begin_members() + { + return object_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().begin()") + const_object_iterator begin_members() const + { + return object_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().end()") + object_iterator end_members() + { + return object_range().end(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range().end()") + const_object_iterator end_members() const + { + return object_range().end(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().begin()") + array_iterator begin_elements() + { + return array_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().begin()") + const_array_iterator begin_elements() const + { + return array_range().begin(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().end()") + array_iterator end_elements() + { + return array_range().end(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range().end()") + const_array_iterator end_elements() const + { + return array_range().end(); + } + + template + JSONCONS_DEPRECATED_MSG("Instead, use get_with_default(const string_view_type&, T&&)") + basic_json get(const string_view_type& name, T&& default_value) const + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + { + return basic_json(std::forward(default_value)); + } + case json_storage_kind::object_value: + { + auto it = object_value().find(name); + if (it != object_value().end()) + { + return it->value(); + } + else + { + return basic_json(std::forward(default_value)); + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use at_or_null(const string_view_type&)") + const basic_json& get(const string_view_type& name) const + { + static const basic_json a_null = null_type(); + + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return a_null; + case json_storage_kind::object_value: + { + auto it = object_value().find(name); + return it != object_value().end() ? it->value() : a_null; + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use is()") + bool is_longlong() const noexcept + { + return is(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use is()") + bool is_ulonglong() const noexcept + { + return is(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + long long as_longlong() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + unsigned long long as_ulonglong() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + int as_int() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + unsigned int as_uint() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + long as_long() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use as()") + unsigned long as_ulong() const + { + return as(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use contains(const string_view_type&)") + bool has_member(const string_view_type& key) const noexcept + { + return contains(key); + } + + JSONCONS_DEPRECATED_MSG("Instead, use erase(const_object_iterator, const_object_iterator)") + void remove_range(std::size_t from_index, std::size_t to_index) + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + array_value().remove_range(from_index, to_index); + break; + default: + break; + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use erase(const string_view_type& name)") + void remove(const string_view_type& name) + { + erase(name); + } + + JSONCONS_DEPRECATED_MSG("Instead, use erase(const string_view_type& name)") + void remove_member(const string_view_type& name) + { + erase(name); + } + // Removes a member from an object value + + JSONCONS_DEPRECATED_MSG("Instead, use empty()") + bool is_empty() const noexcept + { + return empty(); + } + JSONCONS_DEPRECATED_MSG("Instead, use is_number()") + bool is_numeric() const noexcept + { + return is_number(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range()") + range members() + { + return object_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_range()") + range members() const + { + return object_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range()") + range elements() + { + return array_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use array_range()") + range elements() const + { + return array_range(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use storage_kind()") + json_storage_kind get_stor_type() const + { + return storage_kind(); + } + #endif + + range object_range() + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return range(object_iterator(), object_iterator()); + case json_storage_kind::object_value: + return range(object_iterator(object_value().begin()), + object_iterator(object_value().end())); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + } + } + + range object_range() const + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + return range(const_object_iterator(), const_object_iterator()); + case json_storage_kind::object_value: + return range(const_object_iterator(object_value().begin()), + const_object_iterator(object_value().end())); + case json_storage_kind::json_const_pointer: + return cast().value()->object_range(); + default: + JSONCONS_THROW(json_runtime_error("Not an object")); + } + } + + range array_range() + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return range(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + } + } + + range array_range() const + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return range(array_value().begin(),array_value().end()); + case json_storage_kind::json_const_pointer: + return cast().value()->array_range(); + default: + JSONCONS_THROW(json_runtime_error("Not an array")); + } + } + + array& array_value() + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return cast().value(); + default: + JSONCONS_THROW(json_runtime_error("Bad array cast")); + break; + } + } + + const array& array_value() const + { + switch (storage_kind()) + { + case json_storage_kind::array_value: + return cast().value(); + case json_storage_kind::json_const_pointer: + return cast().value()->array_value(); + default: + JSONCONS_THROW(json_runtime_error("Bad array cast")); + break; + } + } + + object& object_value() + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + create_object_implicitly(); + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + return cast().value(); + default: + JSONCONS_THROW(json_runtime_error("Bad object cast")); + break; + } + } + + const object& object_value() const + { + switch (storage_kind()) + { + case json_storage_kind::empty_object_value: + const_cast(this)->create_object_implicitly(); // HERE + JSONCONS_FALLTHROUGH; + case json_storage_kind::object_value: + return cast().value(); + case json_storage_kind::json_const_pointer: + return cast().value()->object_value(); + default: + JSONCONS_THROW(json_runtime_error("Bad object cast")); + break; + } + } + + private: + + void dump_noflush(basic_json_visitor& visitor, std::error_code& ec) const + { + const ser_context context{}; + switch (storage_kind()) + { + case json_storage_kind::short_string_value: + case json_storage_kind::long_string_value: + visitor.string_value(as_string_view(), tag(), context, ec); + break; + case json_storage_kind::byte_string_value: + if (tag() == semantic_tag::ext) + { + visitor.byte_string_value(as_byte_string_view(), ext_tag(), context, ec); + } + else + { + visitor.byte_string_value(as_byte_string_view(), tag(), context, ec); + } + break; + case json_storage_kind::half_value: + visitor.half_value(cast().value(), tag(), context, ec); + break; + case json_storage_kind::double_value: + visitor.double_value(cast().value(), + tag(), context, ec); + break; + case json_storage_kind::int64_value: + visitor.int64_value(cast().value(), tag(), context, ec); + break; + case json_storage_kind::uint64_value: + visitor.uint64_value(cast().value(), tag(), context, ec); + break; + case json_storage_kind::bool_value: + visitor.bool_value(cast().value(), tag(), context, ec); + break; + case json_storage_kind::null_value: + visitor.null_value(tag(), context, ec); + break; + case json_storage_kind::empty_object_value: + visitor.begin_object(0, tag(), context, ec); + visitor.end_object(context, ec); + break; + case json_storage_kind::object_value: + { + bool more = visitor.begin_object(size(), tag(), context, ec); + const object& o = object_value(); + for (auto it = o.begin(); more && it != o.end(); ++it) + { + visitor.key(string_view_type((it->key()).data(),it->key().length()), context, ec); + it->value().dump_noflush(visitor, ec); + } + if (more) + { + visitor.end_object(context, ec); + } + break; + } + case json_storage_kind::array_value: + { + bool more = visitor.begin_array(size(), tag(), context, ec); + const array& o = array_value(); + for (const_array_iterator it = o.begin(); more && it != o.end(); ++it) + { + it->dump_noflush(visitor, ec); + } + if (more) + { + visitor.end_array(context, ec); + } + break; + } + case json_storage_kind::json_const_pointer: + return cast().value()->dump_noflush(visitor, ec); + default: + break; + } + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_json& o) + { + o.dump(os); + return os; + } + + friend std::basic_istream& operator>>(std::basic_istream& is, basic_json& o) + { + json_decoder visitor; + basic_json_reader> reader(is, visitor); + reader.read_next(); + reader.check_done(); + if (!visitor.is_valid()) + { + JSONCONS_THROW(json_runtime_error("Failed to parse json stream")); + } + o = visitor.get_result(); + return is; + } + + friend basic_json deep_copy(const basic_json& other) + { + switch (other.storage_kind()) + { + case json_storage_kind::array_value: + { + basic_json j(json_array_arg, other.tag(), other.get_allocator()); + j.reserve(other.size()); + + for (const auto& item : other.array_range()) + { + j.push_back(deep_copy(item)); + } + return j; + } + case json_storage_kind::object_value: + { + basic_json j(json_object_arg, other.tag(), other.get_allocator()); + j.reserve(other.size()); + + for (const auto& item : other.object_range()) + { + j.try_emplace(item.key(), deep_copy(item.value())); + } + return j; + } + case json_storage_kind::json_const_pointer: + return deep_copy(*(other.cast().value())); + default: + return other; + } + } + }; + + // operator== + + template + typename std::enable_if::value,bool>::type + operator==(const Json& lhs, const Json& rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator==(const Json& lhs, const T& rhs) + { + return lhs.compare(rhs) == 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator==(const Json& lhs, const T& rhs) + { + return lhs.evaluate().compare(rhs) == 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator==(const T& lhs, const Json& rhs) + { + return rhs.compare(lhs) == 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator==(const T& lhs, const Json& rhs) + { + return rhs.evaluate().compare(lhs) == 0; + } + + // operator!= + + template + typename std::enable_if::value,bool>::type + operator!=(const Json& lhs, const Json& rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator!=(const Json& lhs, const T& rhs) + { + return lhs.compare(rhs) != 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator!=(const Json& lhs, const T& rhs) + { + return lhs.evaluate().compare(rhs) != 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator!=(const T& lhs, const Json& rhs) + { + return rhs.compare(lhs) != 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator!=(const T& lhs, const Json& rhs) + { + return rhs.evaluate().compare(lhs) != 0; + } + + // operator< + + template + typename std::enable_if::value,bool>::type + operator<(const Json& lhs, const Json& rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator<(const Json& lhs, const T& rhs) + { + return lhs.compare(rhs) < 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator<(const Json& lhs, const T& rhs) + { + return lhs.evaluate().compare(rhs) < 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator<(const T& lhs, const Json& rhs) + { + return rhs.compare(lhs) > 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator<(const T& lhs, const Json& rhs) + { + return rhs.evaluate().compare(lhs) > 0; + } + + // operator<= + + template + typename std::enable_if::value,bool>::type + operator<=(const Json& lhs, const Json& rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator<=(const Json& lhs, const T& rhs) + { + return lhs.compare(rhs) <= 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator<=(const Json& lhs, const T& rhs) + { + return lhs.evaluate().compare(rhs) <= 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator<=(const T& lhs, const Json& rhs) + { + return rhs.compare(lhs) >= 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator<=(const T& lhs, const Json& rhs) + { + return rhs.evaluate().compare(lhs) >= 0; + } + + // operator> + + template + typename std::enable_if::value,bool>::type + operator>(const Json& lhs, const Json& rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator>(const Json& lhs, const T& rhs) + { + return lhs.compare(rhs) > 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator>(const Json& lhs, const T& rhs) + { + return lhs.evaluate().compare(rhs) > 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator>(const T& lhs, const Json& rhs) + { + return rhs.compare(lhs) < 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator>(const T& lhs, const Json& rhs) + { + return rhs.evaluate().compare(lhs) < 0; + } + + // operator>= + + template + typename std::enable_if::value,bool>::type + operator>=(const Json& lhs, const Json& rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator>=(const Json& lhs, const T& rhs) + { + return lhs.compare(rhs) >= 0; + } + + template + typename std::enable_if::value && std::is_convertible::value,bool>::type + operator>=(const Json& lhs, const T& rhs) + { + return lhs.evaluate().compare(rhs) >= 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator>=(const T& lhs, const Json& rhs) + { + return rhs.compare(lhs) <= 0; + } + + template + typename std::enable_if::value && !is_proxy::value && !type_traits::is_basic_json::value && std::is_convertible::value,bool>::type + operator>=(const T& lhs, const Json& rhs) + { + return rhs.evaluate().compare(lhs) <= 0; + } + + // swap + + template + void swap(typename Json::key_value_type& a, typename Json::key_value_type& b) noexcept + { + a.swap(b); + } + + using json = basic_json>; + using wjson = basic_json>; + using ojson = basic_json>; + using wojson = basic_json>; + + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use wojson") typedef basic_json> owjson; + JSONCONS_DEPRECATED_MSG("Instead, use json_decoder") typedef json_decoder json_deserializer; + JSONCONS_DEPRECATED_MSG("Instead, use json_decoder") typedef json_decoder wjson_deserializer; + JSONCONS_DEPRECATED_MSG("Instead, use json_decoder") typedef json_decoder ojson_deserializer; + JSONCONS_DEPRECATED_MSG("Instead, use json_decoder") typedef json_decoder wojson_deserializer; + #endif + + inline namespace literals { + + inline + jsoncons::json operator "" _json(const char* s, std::size_t n) + { + return jsoncons::json::parse(jsoncons::json::string_view_type(s, n)); + } + + inline + jsoncons::wjson operator "" _json(const wchar_t* s, std::size_t n) + { + return jsoncons::wjson::parse(jsoncons::wjson::string_view_type(s, n)); + } + + inline + jsoncons::ojson operator "" _ojson(const char* s, std::size_t n) + { + return jsoncons::ojson::parse(jsoncons::ojson::string_view_type(s, n)); + } + + inline + jsoncons::wojson operator "" _ojson(const wchar_t* s, std::size_t n) + { + return jsoncons::wojson::parse(jsoncons::wojson::string_view_type(s, n)); + } + + } // inline namespace literals + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/bigint.hpp b/include/jsoncons/bigint.hpp new file mode 100644 index 0000000..223b697 --- /dev/null +++ b/include/jsoncons/bigint.hpp @@ -0,0 +1,1611 @@ +// Copyright 2018 vDaniel 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_BIGINT_HPP +#define JSONCONS_BIGINT_HPP + +#include +#include // std::vector +#include +#include +#include // assert +#include // std::numeric_limits +#include // std::max, std::min, std::reverse +#include // std::string +#include // std::memcpy +#include // std::fmod +#include // std::allocator +#include // std::initializer_list +#include // std::enable_if +#include + +namespace jsoncons { + +/* +This implementation is based on Chapter 2 and Appendix A of +Ammeraal, L. (1996) Algorithms and Data Structures in C++, +Chichester: John Wiley. + +*/ + + +namespace detail { + + template + class basic_bigint_base + { + public: + using allocator_type = Allocator; + using basic_type_allocator_type = typename std::allocator_traits:: template rebind_alloc; + + private: + basic_type_allocator_type alloc_; + public: + using allocator_traits_type = std::allocator_traits; + using stored_allocator_type = allocator_type; + using pointer = typename allocator_traits_type::pointer; + using value_type = typename allocator_traits_type::value_type; + using size_type = typename allocator_traits_type::size_type; + using pointer_traits = std::pointer_traits; + + basic_bigint_base() + : alloc_() + { + } + explicit basic_bigint_base(const allocator_type& alloc) + : alloc_(basic_type_allocator_type(alloc)) + { + } + + basic_type_allocator_type get_allocator() const + { + return alloc_; + } + }; + +} // namespace detail + +template > +class basic_bigint : protected detail::basic_bigint_base +{ + using base_t = detail::basic_bigint_base; + +public: + + using size_type = typename base_t::size_type; + using value_type = typename base_t::value_type; + using base_t::get_allocator; + using bigint_type = basic_bigint; + + static constexpr uint64_t max_basic_type = (std::numeric_limits::max)(); + static constexpr uint64_t basic_type_bits = sizeof(uint64_t) * 8; // Number of bits + static constexpr uint64_t basic_type_halfBits = basic_type_bits/2; + + static constexpr uint16_t word_length = 4; // Use multiples of word_length words + static constexpr uint64_t r_mask = (uint64_t(1) << basic_type_halfBits) - 1; + static constexpr uint64_t l_mask = max_basic_type - r_mask; + static constexpr uint64_t l_bit = max_basic_type - (max_basic_type >> 1); + +private: + + struct common_storage + { + uint8_t is_dynamic_:1; + uint8_t is_negative_:1; + size_type length_; + }; + + struct short_storage + { + uint8_t is_dynamic_:1; + uint8_t is_negative_:1; + size_type length_; + uint64_t values_[2]; + + short_storage() + : is_dynamic_(false), + is_negative_(false), + length_(0), + values_{0,0} + { + } + + template + short_storage(T n, + typename std::enable_if::value && + sizeof(T) <= sizeof(int64_t) && + std::is_signed::value>::type* = 0) + : is_dynamic_(false), + is_negative_(n < 0), + length_(n == 0 ? 0 : 1) + { + values_[0] = n < 0 ? (uint64_t(0)-static_cast(n)) : static_cast(n); + values_[1] = 0; + } + + template + short_storage(T n, + typename std::enable_if::value && + sizeof(T) <= sizeof(int64_t) && + !std::is_signed::value>::type* = 0) + : is_dynamic_(false), + is_negative_(false), + length_(n == 0 ? 0 : 1) + { + values_[0] = n; + values_[1] = 0; + } + + template + short_storage(T n, + typename std::enable_if::value && + sizeof(int64_t) < sizeof(T) && + std::is_signed::value>::type* = 0) + : is_dynamic_(false), + is_negative_(n < 0), + length_(n == 0 ? 0 : 2) + { + using unsigned_type = typename std::make_unsigned::type; + + auto u = n < 0 ? (unsigned_type(0)-static_cast(n)) : static_cast(n); + values_[0] = uint64_t(u & max_basic_type);; + u >>= basic_type_bits; + values_[1] = uint64_t(u & max_basic_type);; + } + + template + short_storage(T n, + typename std::enable_if::value && + sizeof(int64_t) < sizeof(T) && + !std::is_signed::value>::type* = 0) + : is_dynamic_(false), + is_negative_(false), + length_(n == 0 ? 0 : 2) + { + values_[0] = uint64_t(n & max_basic_type);; + n >>= basic_type_bits; + values_[1] = uint64_t(n & max_basic_type);; + } + + short_storage(const short_storage& stor) + : is_dynamic_(false), + is_negative_(stor.is_negative_), + length_(stor.length_) + { + values_[0] = stor.values_[0]; + values_[1] = stor.values_[1]; + } + + short_storage& operator=(const short_storage& stor) = delete; + }; + + struct dynamic_storage + { + using real_allocator_type = typename std::allocator_traits:: template rebind_alloc; + using pointer = typename std::allocator_traits::pointer; + + uint8_t is_dynamic_:1; + uint8_t is_negative_:1; + size_type length_; + size_type capacity_; + pointer data_; + + dynamic_storage() + : is_dynamic_(true), + is_negative_(false), + length_(0), + capacity_(0), + data_(nullptr) + { + } + + dynamic_storage(const dynamic_storage& stor, const real_allocator_type& alloc) + : is_dynamic_(true), + is_negative_(stor.is_negative_), + length_(stor.length_), + capacity_(0), + data_(nullptr) + { + create(stor.length_, alloc); + std::memcpy(data_, stor.data_, stor.length_*sizeof(uint64_t)); + } + + dynamic_storage(dynamic_storage&& stor) noexcept + : is_dynamic_(true), + is_negative_(stor.is_negative_), + length_(stor.length_), + capacity_(stor.capacity_), + data_(stor.data_) + { + stor.length_ = 0; + stor.capacity_ = 0; + stor.data_ = nullptr; + } + + void create(size_type length, real_allocator_type alloc) + { + capacity_ = round_up(length); + data_ = std::allocator_traits::allocate(alloc, capacity_); + JSONCONS_TRY + { + std::allocator_traits::construct(alloc, type_traits::to_plain_pointer(data_)); + } + JSONCONS_CATCH(...) + { + std::allocator_traits::deallocate(alloc, data_, capacity_); + JSONCONS_RETHROW; + } + } + + void destroy(const real_allocator_type& a) noexcept + { + if (data_ != nullptr) + { + real_allocator_type alloc(a); + + std::allocator_traits::destroy(alloc, type_traits::to_plain_pointer(data_)); + std::allocator_traits::deallocate(alloc, data_,capacity_); + } + } + + void reserve(size_type n, const real_allocator_type& a) + { + real_allocator_type alloc(a); + + size_type capacity_new = round_up(n); + uint64_t* data_old = data_; + data_ = std::allocator_traits::allocate(alloc, capacity_new); + if (length_ > 0) + { + std::memcpy( data_, data_old, length_*sizeof(uint64_t)); + } + if (capacity_ > 0 && data_ != nullptr) + { + std::allocator_traits::deallocate(alloc, data_old, capacity_); + } + capacity_ = capacity_new; + } + + // Find suitable new block size + constexpr size_type round_up(size_type i) const + { + return (i/word_length + 1) * word_length; + } + }; + + union + { + common_storage common_stor_; + short_storage short_stor_; + dynamic_storage dynamic_stor_; + }; + +public: + basic_bigint() + { + ::new (&short_stor_) short_storage(); + } + + explicit basic_bigint(const Allocator& alloc) + : base_t(alloc) + { + ::new (&short_stor_) short_storage(); + } + + + basic_bigint(const basic_bigint& n) + : base_t(n.get_allocator()) + { + if (!n.is_dynamic()) + { + ::new (&short_stor_) short_storage(n.short_stor_); + } + else + { + ::new (&dynamic_stor_) dynamic_storage(n.dynamic_stor_, get_allocator()); + } + } + + basic_bigint(basic_bigint&& other) noexcept + : base_t(other.get_allocator()) + { + if (!other.is_dynamic()) + { + ::new (&short_stor_) short_storage(other.short_stor_); + } + else + { + ::new (&dynamic_stor_) dynamic_storage(std::move(other.dynamic_stor_)); + } + } + + template + basic_bigint(Integer n, + typename std::enable_if::value>::type* = 0) + { + ::new (&short_stor_) short_storage(n); + } + + ~basic_bigint() noexcept + { + destroy(); + } + + constexpr bool is_dynamic() const + { + return common_stor_.is_dynamic_; + } + + constexpr size_type length() const + { + return common_stor_.length_; + } + + constexpr size_type capacity() const + { + return is_dynamic() ? dynamic_stor_.capacity_ : 2; + } + + bool is_negative() const + { + return common_stor_.is_negative_; + } + + void is_negative(bool value) + { + common_stor_.is_negative_ = value; + } + + constexpr const uint64_t* data() const + { + return is_dynamic() ? dynamic_stor_.data_ : short_stor_.values_; + } + + uint64_t* data() + { + return is_dynamic() ? dynamic_stor_.data_ : short_stor_.values_; + } + + template + static basic_bigint from_string(const std::basic_string& s) + { + return from_string(s.data(), s.length()); + } + + template + static basic_bigint from_string(const CharT* s) + { + return from_string(s, std::char_traits::length(s)); + } + + template + static basic_bigint from_string(const CharT* data, size_type length) + { + bool neg; + if (*data == '-') + { + neg = true; + data++; + --length; + } + else + { + neg = false; + } + + basic_bigint v = 0; + for (size_type i = 0; i < length; i++) + { + CharT c = data[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + v = (v * 10) + (uint64_t)(c - '0'); + break; + default: + JSONCONS_THROW(std::runtime_error(std::string("Invalid digit ") + "\'" + (char)c + "\'")); + } + } + + if (neg) + { + v.common_stor_.is_negative_ = true; + } + + return v; + } + + template + static basic_bigint from_string_radix(const CharT* data, size_type length, uint8_t radix) + { + if (!(radix >= 2 && radix <= 16)) + { + JSONCONS_THROW(std::runtime_error("Unsupported radix")); + } + + bool neg; + if (*data == '-') + { + neg = true; + data++; + --length; + } + else + { + neg = false; + } + + basic_bigint v = 0; + for (size_type i = 0; i < length; i++) + { + CharT c = data[i]; + uint64_t d; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + d = (uint64_t)(c - '0'); + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + d = (uint64_t)(c - ('a' - 10)); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + d = (uint64_t)(c - ('A' - 10)); + break; + default: + JSONCONS_THROW(std::runtime_error(std::string("Invalid digit in radix ") + std::to_string(radix) + ": \'" + (char)c + "\'")); + } + if (d >= radix) + { + JSONCONS_THROW(std::runtime_error(std::string("Invalid digit in radix ") + std::to_string(radix) + ": \'" + (char)c + "\'")); + } + v = (v * radix) + d; + } + + if ( neg ) + { + v.common_stor_.is_negative_ = true; + } + return v; + } + + static basic_bigint from_bytes_be(int signum, const uint8_t* str, std::size_t n) + { + static const double radix_log2 = std::log2(next_power_of_two(256)); + // Estimate how big the result will be, so we can pre-allocate it. + double bits = radix_log2 * n; + double big_digits = std::ceil(bits / 64.0); + //std::cout << "ESTIMATED: " << big_digits << "\n"; + + bigint_type v = 0; + v.reserve(static_cast(big_digits)); + + if (n > 0) + { + for (std::size_t i = 0; i < n; i++) + { + v = (v * 256) + (uint64_t)(str[i]); + } + } + //std::cout << "ACTUAL: " << v.length() << "\n"; + + if (signum < 0) + { + v.common_stor_.is_negative_ = true; + } + + return v; + } + + uint64_t* begin() { return is_dynamic() ? dynamic_stor_.data_ : short_stor_.values_; } + const uint64_t* begin() const { return is_dynamic() ? dynamic_stor_.data_ : short_stor_.values_; } + uint64_t* end() { return begin() + length(); } + const uint64_t* end() const { return begin() + length(); } + + void resize(size_type n) + { + size_type len_old = common_stor_.length_; + reserve(n); + common_stor_.length_ = n; + if ( common_stor_.length_ > len_old ) + { + memset( data()+len_old, 0, (common_stor_.length_ - len_old)*sizeof(uint64_t) ); + } + } + + void reserve(size_type n) + { + if (capacity() < n) + { + if (!is_dynamic()) + { + size_type size = short_stor_.length_; + size_type is_neg = short_stor_.is_negative_; + uint64_t values[2] = {short_stor_.values_[0], short_stor_.values_[1]}; + + ::new (&dynamic_stor_) dynamic_storage(); + dynamic_stor_.reserve(n, get_allocator()); + dynamic_stor_.length_ = size; + dynamic_stor_.is_negative_ = is_neg; + dynamic_stor_.data_[0] = values[0]; + dynamic_stor_.data_[1] = values[1]; + } + else + { + dynamic_stor_.reserve(n, get_allocator()); + } + } + } + + // operators + + bool operator!() const + { + return length() == 0 ? true : false; + } + + basic_bigint operator-() const + { + basic_bigint v(*this); + v.common_stor_.is_negative_ = !v.is_negative(); + return v; + } + + basic_bigint& operator=( const basic_bigint& y ) + { + if ( this != &y ) + { + resize( y.length() ); + common_stor_.is_negative_ = y.is_negative(); + if ( y.length() > 0 ) + { + std::memcpy( data(), y.data(), y.length()*sizeof(uint64_t) ); + } + } + return *this; + } + + basic_bigint& operator+=( const basic_bigint& y ) + { + if ( is_negative() != y.is_negative() ) + return *this -= -y; + uint64_t d; + uint64_t carry = 0; + + resize( (std::max)(y.length(), length()) + 1 ); + + for (size_type i = 0; i < length(); i++ ) + { + if ( i >= y.length() && carry == 0 ) + break; + d = data()[i] + carry; + carry = d < carry; + if ( i < y.length() ) + { + data()[i] = d + y.data()[i]; + if ( data()[i] < d ) + carry = 1; + } + else + data()[i] = d; + } + reduce(); + return *this; + } + + basic_bigint& operator-=( const basic_bigint& y ) + { + if ( is_negative() != y.is_negative() ) + return *this += -y; + if ( (!is_negative() && y > *this) || (is_negative() && y < *this) ) + return *this = -(y - *this); + uint64_t borrow = 0; + uint64_t d; + for (size_type i = 0; i < length(); i++ ) + { + if ( i >= y.length() && borrow == 0 ) + break; + d = data()[i] - borrow; + borrow = d > data()[i]; + if ( i < y.length()) + { + data()[i] = d - y.data()[i]; + if ( data()[i] > d ) + borrow = 1; + } + else + data()[i] = d; + } + reduce(); + return *this; + } + + basic_bigint& operator*=( int64_t y ) + { + *this *= uint64_t(y < 0 ? -y : y); + if ( y < 0 ) + common_stor_.is_negative_ = !is_negative(); + return *this; + } + + basic_bigint& operator*=( uint64_t y ) + { + size_type len0 = length(); + uint64_t hi; + uint64_t lo; + uint64_t dig = data()[0]; + uint64_t carry = 0; + + resize( length() + 1 ); + + size_type i = 0; + for (i = 0; i < len0; i++ ) + { + DDproduct( dig, y, hi, lo ); + data()[i] = lo + carry; + dig = data()[i+1]; + carry = hi + (data()[i] < lo); + } + data()[i] = carry; + reduce(); + return *this; + } + + basic_bigint& operator*=( basic_bigint y ) + { + if ( length() == 0 || y.length() == 0 ) + return *this = 0; + bool difSigns = is_negative() != y.is_negative(); + if ( length() + y.length() == 2 ) // length() = y.length() = 1 + { + uint64_t a = data()[0], b = y.data()[0]; + data()[0] = a * b; + if ( data()[0] / a != b ) + { + resize( 2 ); + DDproduct( a, b, data()[1], data()[0] ); + } + common_stor_.is_negative_ = difSigns; + return *this; + } + if ( length() == 1 ) // && y.length() > 1 + { + uint64_t digit = data()[0]; + *this = y; + *this *= digit; + } + else + { + if ( y.length() == 1 ) + *this *= y.data()[0]; + else + { + size_type lenProd = length() + y.length(), jA, jB; + uint64_t sumHi = 0, sumLo, hi, lo, + sumLo_old, sumHi_old, carry=0; + basic_bigint x = *this; + resize( lenProd ); // Give *this length lenProd + + for (size_type i = 0; i < lenProd; i++ ) + { + sumLo = sumHi; + sumHi = carry; + carry = 0; + for ( jA=0; jA < x.length(); jA++ ) + { + jB = i - jA; + if ( jB >= 0 && jB < y.length() ) + { + DDproduct( x.data()[jA], y.data()[jB], hi, lo ); + sumLo_old = sumLo; + sumHi_old = sumHi; + sumLo += lo; + if ( sumLo < sumLo_old ) + sumHi++; + sumHi += hi; + carry += (sumHi < sumHi_old); + } + } + data()[i] = sumLo; + } + } + } + reduce(); + common_stor_.is_negative_ = difSigns; + return *this; + } + + basic_bigint& operator/=( const basic_bigint& divisor ) + { + basic_bigint r; + divide( divisor, *this, r, false ); + return *this; + } + + basic_bigint& operator%=( const basic_bigint& divisor ) + { + basic_bigint q; + divide( divisor, q, *this, true ); + return *this; + } + + basic_bigint& operator<<=( uint64_t k ) + { + size_type q = (size_type)(k / basic_type_bits); + if ( q ) // Increase common_stor_.length_ by q: + { + resize(length() + q); + for (size_type i = length(); i-- > 0; ) + data()[i] = ( i < q ? 0 : data()[i - q]); + k %= basic_type_bits; + } + if ( k ) // 0 < k < basic_type_bits: + { + uint64_t k1 = basic_type_bits - k; + uint64_t mask = (uint64_t(1) << k) - uint64_t(1); + resize( length() + 1 ); + for (size_type i = length(); i-- > 0; ) + { + data()[i] <<= k; + if ( i > 0 ) + data()[i] |= (data()[i-1] >> k1) & mask; + } + } + reduce(); + return *this; + } + + basic_bigint& operator>>=(uint64_t k) + { + size_type q = (size_type)(k / basic_type_bits); + if ( q >= length() ) + { + resize( 0 ); + return *this; + } + if (q > 0) + { + memmove( data(), data()+q, (size_type)((length() - q)*sizeof(uint64_t)) ); + resize( length() - q ); + k %= basic_type_bits; + if ( k == 0 ) + { + reduce(); + return *this; + } + } + + size_type n = (size_type)(length() - 1); + int64_t k1 = basic_type_bits - k; + uint64_t mask = (uint64_t(1) << k) - 1; + for (size_type i = 0; i <= n; i++) + { + data()[i] >>= k; + if ( i < n ) + data()[i] |= ((data()[i+1] & mask) << k1); + } + reduce(); + return *this; + } + + basic_bigint& operator++() + { + *this += 1; + return *this; + } + + basic_bigint operator++(int) + { + basic_bigint old = *this; + ++(*this); + return old; + } + + basic_bigint& operator--() + { + *this -= 1; + return *this; + } + + basic_bigint operator--(int) + { + basic_bigint old = *this; + --(*this); + return old; + } + + basic_bigint& operator|=( const basic_bigint& a ) + { + if ( length() < a.length() ) + { + resize( a.length() ); + } + + const uint64_t* qBegin = a.begin(); + const uint64_t* q = a.end() - 1; + uint64_t* p = begin() + a.length() - 1; + + while ( q >= qBegin ) + { + *p-- |= *q--; + } + + reduce(); + + return *this; + } + + basic_bigint& operator^=( const basic_bigint& a ) + { + if ( length() < a.length() ) + { + resize( a.length() ); + } + + const uint64_t* qBegin = a.begin(); + const uint64_t* q = a.end() - 1; + uint64_t* p = begin() + a.length() - 1; + + while ( q >= qBegin ) + { + *p-- ^= *q--; + } + + reduce(); + + return *this; + } + + basic_bigint& operator&=( const basic_bigint& a ) + { + size_type old_length = length(); + + resize( (std::min)( length(), a.length() ) ); + + const uint64_t* pBegin = begin(); + uint64_t* p = end() - 1; + const uint64_t* q = a.begin() + length() - 1; + + while ( p >= pBegin ) + { + *p-- &= *q--; + } + + if ( old_length > length() ) + { + memset( data() + length(), 0, old_length - length() ); + } + + reduce(); + + return *this; + } + + explicit operator bool() const + { + return length() != 0 ? true : false; + } + + explicit operator int64_t() const + { + int64_t x = 0; + if ( length() > 0 ) + { + x = data() [0]; + } + + return is_negative() ? -x : x; + } + + explicit operator uint64_t() const + { + uint64_t u = 0; + if ( length() > 0 ) + { + u = data() [0]; + } + + return u; + } + + explicit operator double() const + { + double x = 0.0; + double factor = 1.0; + double values = (double)max_basic_type + 1.0; + + const uint64_t* p = begin(); + const uint64_t* pEnd = end(); + while ( p < pEnd ) + { + x += *p*factor; + factor *= values; + ++p; + } + + return is_negative() ? -x : x; + } + + explicit operator long double() const + { + long double x = 0.0; + long double factor = 1.0; + long double values = (long double)max_basic_type + 1.0; + + const uint64_t* p = begin(); + const uint64_t* pEnd = end(); + while ( p < pEnd ) + { + x += *p*factor; + factor *= values; + ++p; + } + + return is_negative() ? -x : x; + } + + template + void write_bytes_be(int& signum, std::vector& data) const + { + basic_bigint n(*this); + signum = (n < 0) ? -1 : (n > 0 ? 1 : 0); + + basic_bigint divisor(256); + + while (n >= 256) + { + basic_bigint q; + basic_bigint r; + n.divide(divisor, q, r, true); + n = q; + data.push_back((uint8_t)(uint64_t)r); + } + if (n >= 0) + { + data.push_back((uint8_t)(uint64_t)n); + } + std::reverse(data.begin(),data.end()); + } + + std::string to_string() const + { + std::string s; + write_string(s); + return s; + } + + template + void write_string(std::basic_string& data) const + { + basic_bigint v(*this); + + size_t len = (v.length() * basic_type_bits / 3) + 2; + data.reserve(len); + + static uint64_t p10 = 1; + static uint64_t ip10 = 0; + + if ( v.length() == 0 ) + { + data.push_back('0'); + } + else + { + uint64_t r; + if ( p10 == 1 ) + { + while ( p10 <= (std::numeric_limits::max)()/10 ) + { + p10 *= 10; + ip10++; + } + } + // p10 is max unsigned power of 10 + basic_bigint R; + basic_bigint LP10 = p10; // LP10 = p10 = ::pow(10, ip10) + + do + { + v.divide( LP10, v, R, true ); + r = (R.length() ? R.data()[0] : 0); + for ( size_type j=0; j < ip10; j++ ) + { + data.push_back(char(r % 10 + '0')); + r /= 10; + if ( r + v.length() == 0 ) + break; + } + } + while ( v.length() ); + if (is_negative()) + { + data.push_back('-'); + } + std::reverse(data.begin(),data.end()); + } + } + + std::string to_string_hex() const + { + std::string s; + write_string_hex(s); + return s; + } + + template + void write_string_hex(std::basic_string& data) const + { + basic_bigint v(*this); + + std::size_t len = (v.length() * basic_bigint::basic_type_bits / 3) + 2; + data.reserve(len); + // 1/3 > ln(2)/ln(10) + static uint64_t p10 = 1; + static uint64_t ip10 = 0; + + if ( v.length() == 0 ) + { + data.push_back('0'); + } + else + { + uint64_t r; + if ( p10 == 1 ) + { + while ( p10 <= (std::numeric_limits::max)()/16 ) + { + p10 *= 16; + ip10++; + } + } // p10 is max unsigned power of 16 + basic_bigint R; + basic_bigint LP10 = p10; // LP10 = p10 = ::pow(16, ip10) + do + { + v.divide( LP10, v, R, true ); + r = (R.length() ? R.data()[0] : 0); + for ( size_type j=0; j < ip10; j++ ) + { + uint8_t c = r % 16; + data.push_back((c < 10) ? ('0' + c) : ('A' - 10 + c)); + r /= 16; + if ( r + v.length() == 0 ) + break; + } + } + while (v.length()); + + if (is_negative()) + { + data.push_back('-'); + } + std::reverse(data.begin(),data.end()); + } + } + +// Global Operators + + friend bool operator==( const basic_bigint& x, const basic_bigint& y ) noexcept + { + return x.compare(y) == 0 ? true : false; + } + + friend bool operator==( const basic_bigint& x, int y ) noexcept + { + return x.compare(y) == 0 ? true : false; + } + + friend bool operator!=( const basic_bigint& x, const basic_bigint& y ) noexcept + { + return x.compare(y) != 0 ? true : false; + } + + friend bool operator!=( const basic_bigint& x, int y ) noexcept + { + return x.compare(basic_bigint(y)) != 0 ? true : false; + } + + friend bool operator<( const basic_bigint& x, const basic_bigint& y ) noexcept + { + return x.compare(y) < 0 ? true : false; + } + + friend bool operator<( const basic_bigint& x, int64_t y ) noexcept + { + return x.compare(y) < 0 ? true : false; + } + + friend bool operator>( const basic_bigint& x, const basic_bigint& y ) noexcept + { + return x.compare(y) > 0 ? true : false; + } + + friend bool operator>( const basic_bigint& x, int y ) noexcept + { + return x.compare(basic_bigint(y)) > 0 ? true : false; + } + + friend bool operator<=( const basic_bigint& x, const basic_bigint& y ) noexcept + { + return x.compare(y) <= 0 ? true : false; + } + + friend bool operator<=( const basic_bigint& x, int y ) noexcept + { + return x.compare(y) <= 0 ? true : false; + } + + friend bool operator>=( const basic_bigint& x, const basic_bigint& y ) noexcept + { + return x.compare(y) >= 0 ? true : false; + } + + friend bool operator>=( const basic_bigint& x, int y ) noexcept + { + return x.compare(y) >= 0 ? true : false; + } + + friend basic_bigint operator+( basic_bigint x, const basic_bigint& y ) + { + return x += y; + } + + friend basic_bigint operator+( basic_bigint x, int64_t y ) + { + return x += y; + } + + friend basic_bigint operator-( basic_bigint x, const basic_bigint& y ) + { + return x -= y; + } + + friend basic_bigint operator-( basic_bigint x, int64_t y ) + { + return x -= y; + } + + friend basic_bigint operator*( int64_t x, const basic_bigint& y ) + { + return basic_bigint(y) *= x; + } + + friend basic_bigint operator*( basic_bigint x, const basic_bigint& y ) + { + return x *= y; + } + + friend basic_bigint operator*( basic_bigint x, int64_t y ) + { + return x *= y; + } + + friend basic_bigint operator/( basic_bigint x, const basic_bigint& y ) + { + return x /= y; + } + + friend basic_bigint operator/( basic_bigint x, int y ) + { + return x /= y; + } + + friend basic_bigint operator%( basic_bigint x, const basic_bigint& y ) + { + return x %= y; + } + + friend basic_bigint operator<<( basic_bigint u, unsigned k ) + { + return u <<= k; + } + + friend basic_bigint operator<<( basic_bigint u, int k ) + { + return u <<= k; + } + + friend basic_bigint operator>>( basic_bigint u, unsigned k ) + { + return u >>= k; + } + + friend basic_bigint operator>>( basic_bigint u, int k ) + { + return u >>= k; + } + + friend basic_bigint operator|( basic_bigint x, const basic_bigint& y ) + { + return x |= y; + } + + friend basic_bigint operator|( basic_bigint x, int y ) + { + return x |= y; + } + + friend basic_bigint operator|( basic_bigint x, unsigned y ) + { + return x |= y; + } + + friend basic_bigint operator^( basic_bigint x, const basic_bigint& y ) + { + return x ^= y; + } + + friend basic_bigint operator^( basic_bigint x, int y ) + { + return x ^= y; + } + + friend basic_bigint operator^( basic_bigint x, unsigned y ) + { + return x ^= y; + } + + friend basic_bigint operator&( basic_bigint x, const basic_bigint& y ) + { + return x &= y; + } + + friend basic_bigint operator&( basic_bigint x, int y ) + { + return x &= y; + } + + friend basic_bigint operator&( basic_bigint x, unsigned y ) + { + return x &= y; + } + + friend basic_bigint abs( const basic_bigint& a ) + { + if ( a.is_negative() ) + { + return -a; + } + return a; + } + + friend basic_bigint power( basic_bigint x, unsigned n ) + { + basic_bigint y = 1; + + while ( n ) + { + if ( n & 1 ) + { + y *= x; + } + x *= x; + n >>= 1; + } + + return y; + } + + friend basic_bigint sqrt( const basic_bigint& a ) + { + basic_bigint x = a; + basic_bigint b = a; + basic_bigint q; + + b <<= 1; + while ( b >>= 2, b > 0 ) + { + x >>= 1; + } + while ( x > (q = a/x) + 1 || x < q - 1 ) + { + x += q; + x >>= 1; + } + return x < q ? x : q; + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_bigint& v) + { + std::basic_string s; + v.write_string(s); + os << s; + + return os; + } + + int compare( const basic_bigint& y ) const noexcept + { + if ( is_negative() != y.is_negative() ) + return y.is_negative() - is_negative(); + int code = 0; + if ( length() == 0 && y.length() == 0 ) + code = 0; + else if ( length() < y.length() ) + code = -1; + else if ( length() > y.length() ) + code = +1; + else + { + for (size_type i = length(); i-- > 0; ) + { + if (data()[i] > y.data()[i]) + { + code = 1; + break; + } + else if (data()[i] < y.data()[i]) + { + code = -1; + break; + } + } + } + return is_negative() ? -code : code; + } + + void divide( basic_bigint denom, basic_bigint& quot, basic_bigint& rem, bool remDesired ) const + { + if ( denom.length() == 0 ) + { + JSONCONS_THROW(std::runtime_error( "Zero divide." )); + } + bool quot_neg = is_negative() ^ denom.is_negative(); + bool rem_neg = is_negative(); + int x = 0; + basic_bigint num = *this; + num.common_stor_.is_negative_ = denom.common_stor_.is_negative_ = false; + if ( num < denom ) + { + quot = uint64_t(0); + rem = num; + rem.common_stor_.is_negative_ = rem_neg; + return; + } + if ( denom.length() == 1 && num.length() == 1 ) + { + quot = uint64_t( num.data()[0]/denom.data()[0] ); + rem = uint64_t( num.data()[0]%denom.data()[0] ); + quot.common_stor_.is_negative_ = quot_neg; + rem.common_stor_.is_negative_ = rem_neg; + return; + } + else if (denom.length() == 1 && (denom.data()[0] & l_mask) == 0 ) + { + // Denominator fits into a half word + uint64_t divisor = denom.data()[0], dHi = 0, + q1, r, q2, dividend; + quot.resize(length()); + for (size_type i=length(); i-- > 0; ) + { + dividend = (dHi << basic_type_halfBits) | (data()[i] >> basic_type_halfBits); + q1 = dividend/divisor; + r = dividend % divisor; + dividend = (r << basic_type_halfBits) | (data()[i] & r_mask); + q2 = dividend/divisor; + dHi = dividend % divisor; + quot.data()[i] = (q1 << basic_type_halfBits) | q2; + } + quot.reduce(); + rem = dHi; + quot.common_stor_.is_negative_ = quot_neg; + rem.common_stor_.is_negative_ = rem_neg; + return; + } + basic_bigint num0 = num, denom0 = denom; + int second_done = normalize(denom, num, x); + size_type l = denom.length() - 1; + size_type n = num.length() - 1; + quot.resize(n - l); + for (size_type i=quot.length(); i-- > 0; ) + quot.data()[i] = 0; + rem = num; + if ( rem.data()[n] >= denom.data()[l] ) + { + rem.resize(rem.length() + 1); + n++; + quot.resize(quot.length() + 1); + } + uint64_t d = denom.data()[l]; + for ( size_type k = n; k > l; k-- ) + { + uint64_t q = DDquotient(rem.data()[k], rem.data()[k-1], d); + subtractmul( rem.data() + k - l - 1, denom.data(), l + 1, q ); + quot.data()[k - l - 1] = q; + } + quot.reduce(); + quot.common_stor_.is_negative_ = quot_neg; + if ( remDesired ) + { + unnormalize(rem, x, second_done); + rem.common_stor_.is_negative_ = rem_neg; + } + } +private: + void destroy() noexcept + { + if (is_dynamic()) + { + dynamic_stor_.destroy(get_allocator()); + } + } + void DDproduct( uint64_t A, uint64_t B, + uint64_t& hi, uint64_t& lo ) const + // Multiplying two digits: (hi, lo) = A * B + { + uint64_t hiA = A >> basic_type_halfBits, loA = A & r_mask, + hiB = B >> basic_type_halfBits, loB = B & r_mask, + mid1, mid2, old; + + lo = loA * loB; + hi = hiA * hiB; + mid1 = loA * hiB; + mid2 = hiA * loB; + old = lo; + lo += mid1 << basic_type_halfBits; + hi += (lo < old) + (mid1 >> basic_type_halfBits); + old = lo; + lo += mid2 << basic_type_halfBits; + hi += (lo < old) + (mid2 >> basic_type_halfBits); + } + + uint64_t DDquotient( uint64_t A, uint64_t B, uint64_t d ) const + // Divide double word (A, B) by d. Quotient = (qHi, qLo) + { + uint64_t left, middle, right, qHi, qLo, x, dLo1, + dHi = d >> basic_type_halfBits, dLo = d & r_mask; + qHi = A/(dHi + 1); + // This initial guess of qHi may be too small. + middle = qHi * dLo; + left = qHi * dHi; + x = B - (middle << basic_type_halfBits); + A -= (middle >> basic_type_halfBits) + left + (x > B); + B = x; + dLo1 = dLo << basic_type_halfBits; + // Increase qHi if necessary: + while ( A > dHi || (A == dHi && B >= dLo1) ) + { + x = B - dLo1; + A -= dHi + (x > B); + B = x; + qHi++; + } + qLo = ((A << basic_type_halfBits) | (B >> basic_type_halfBits))/(dHi + 1); + // This initial guess of qLo may be too small. + right = qLo * dLo; + middle = qLo * dHi; + x = B - right; + A -= (x > B); + B = x; + x = B - (middle << basic_type_halfBits); + A -= (middle >> basic_type_halfBits) + (x > B); + B = x; + // Increase qLo if necessary: + while ( A || B >= d ) + { + x = B - d; + A -= (x > B); + B = x; + qLo++; + } + return (qHi << basic_type_halfBits) + qLo; + } + + void subtractmul( uint64_t* a, uint64_t* b, size_type n, uint64_t& q ) const + // a -= q * b: b in n positions; correct q if necessary + { + uint64_t hi, lo, d, carry = 0; + size_type i; + for ( i = 0; i < n; i++ ) + { + DDproduct( b[i], q, hi, lo ); + d = a[i]; + a[i] -= lo; + if ( a[i] > d ) + carry++; + d = a[i + 1]; + a[i + 1] -= hi + carry; + carry = a[i + 1] > d; + } + if ( carry ) // q was too large + { + q--; + carry = 0; + for ( i = 0; i < n; i++ ) + { + d = a[i] + carry; + carry = d < carry; + a[i] = d + b[i]; + if ( a[i] < d ) + carry = 1; + } + a[n] = 0; + } + } + + int normalize( basic_bigint& denom, basic_bigint& num, int& x ) const + { + size_type r = denom.length() - 1; + uint64_t y = denom.data()[r]; + + x = 0; + while ( (y & l_bit) == 0 ) + { + y <<= 1; + x++; + } + denom <<= x; + num <<= x; + if ( r > 0 && denom.data()[r] < denom.data()[r-1] ) + { + denom *= max_basic_type; + num *= max_basic_type; + return 1; + } + return 0; + } + + void unnormalize( basic_bigint& rem, int x, int secondDone ) const + { + if ( secondDone ) + { + rem /= max_basic_type; + } + if ( x > 0 ) + { + rem >>= x; + } + else + { + rem.reduce(); + } + } + + size_type round_up(size_type i) const // Find suitable new block size + { + return (i/word_length + 1) * word_length; + } + + void reduce() + { + uint64_t* p = end() - 1; + uint64_t* pBegin = begin(); + while ( p >= pBegin ) + { + if ( *p ) + { + break; + } + --common_stor_.length_; + --p; + } + if ( length() == 0 ) + { + common_stor_.is_negative_ = false; + } + } + + static uint64_t next_power_of_two(uint64_t n) { + n = n - 1; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n |= n >> 32; + return n + 1; + } +}; + +using bigint = basic_bigint>; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use bigint") typedef bigint bignum; +#endif + +} + +#endif diff --git a/include/jsoncons/byte_string.hpp b/include/jsoncons/byte_string.hpp new file mode 100644 index 0000000..159dff9 --- /dev/null +++ b/include/jsoncons/byte_string.hpp @@ -0,0 +1,820 @@ +// 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_BYTE_STRING_HPP +#define JSONCONS_BYTE_STRING_HPP + +#include +#include +#include +#include +#include // std::memcmp +#include // std::allocator +#include +#include +#include // std::setw +#include +#include // std::move +#include +#include +#include +#include + +namespace jsoncons { + + // Algorithms + +namespace detail { + + template + typename std::enable_if::value_type,uint8_t>::value,size_t>::type + encode_base64_generic(InputIt first, InputIt last, const char alphabet[65], Container& result) + { + std::size_t count = 0; + unsigned char a3[3]; + unsigned char a4[4]; + unsigned char fill = alphabet[64]; + 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]]); + ++count; + } + 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]]); + ++count; + } + + if (fill != 0) + { + while (i++ < 3) + { + result.push_back(fill); + ++count; + } + } + } + + return count; + } + + template + typename std::enable_if::value,decode_result>::type + decode_base64_generic(InputIt first, InputIt last, + const uint8_t reverse_alphabet[256], + F f, + Container& result) + { + uint8_t a4[4], a3[3]; + uint8_t i = 0; + uint8_t j = 0; + + while (first != last && *first != '=') + { + if (!f(*first)) + { + return decode_result{first, conv_errc::conversion_failed}; + } + + a4[i++] = *first++; + if (i == 4) + { + for (i = 0; i < 4; ++i) + { + a4[i] = reverse_alphabet[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] = reverse_alphabet[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 decode_result{last, conv_errc::success}; + } + +} // namespace detail + + template + typename std::enable_if::value_type,uint8_t>::value,size_t>::type + encode_base16(InputIt first, InputIt last, Container& result) + { + static constexpr char characters[] = "0123456789ABCDEF"; + + for (auto it = first; it != last; ++it) + { + uint8_t c = *it; + result.push_back(characters[c >> 4]); + result.push_back(characters[c & 0xf]); + } + return (last-first)*2; + } + + template + typename std::enable_if::value_type,uint8_t>::value,size_t>::type + encode_base64url(InputIt first, InputIt last, Container& result) + { + static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_" + "\0"; + return detail::encode_base64_generic(first, last, alphabet, result); + } + + template + typename std::enable_if::value_type,uint8_t>::value,size_t>::type + encode_base64(InputIt first, InputIt last, Container& result) + { + static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" + "="; + return detail::encode_base64_generic(first, last, alphabet, result); + } + + template + bool is_base64(Char c) + { + return (c >= 0 && c < 128) && (isalnum((int)c) || c == '+' || c == '/'); + } + + template + bool is_base64url(Char c) + { + return (c >= 0 && c < 128) && (isalnum((int)c) || c == '-' || c == '_'); + } + + inline + static bool is_base64url(int c) + { + return isalnum(c) || c == '-' || c == '_'; + } + + // decode + + template + typename std::enable_if::value,decode_result>::type + decode_base64url(InputIt first, InputIt last, Container& result) + { + static constexpr uint8_t reverse_alphabet[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 63, + 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + auto retval = jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet, + is_base64url::value_type>, + result); + return retval.ec == conv_errc::success ? retval : decode_result{retval.it, conv_errc::not_base64url}; + } + + template + typename std::enable_if::value,decode_result>::type + decode_base64(InputIt first, InputIt last, Container& result) + { + static constexpr uint8_t reverse_alphabet[256] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + auto retval = jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet, + is_base64::value_type>, + result); + return retval.ec == conv_errc::success ? retval : decode_result{retval.it, conv_errc::not_base64}; + } + + template + typename std::enable_if::value,decode_result>::type + decode_base16(InputIt first, InputIt last, Container& result) + { + std::size_t len = std::distance(first,last); + if (len & 1) + { + return decode_result{first, conv_errc::not_base16}; + } + + InputIt it = first; + while (it != last) + { + uint8_t val; + auto a = *it++; + if (a >= '0' && a <= '9') + { + val = (a - '0') << 4; + } + else if ((a | 0x20) >= 'a' && (a | 0x20) <= 'f') + { + val = ((a | 0x20) - 'a' + 10) << 4; + } + else + { + return decode_result{first, conv_errc::not_base16}; + } + + auto b = *it++; + if (b >= '0' && b <= '9') + { + val |= (b - '0'); + } + else if ((b | 0x20) >= 'a' && (b | 0x20) <= 'f') + { + val |= ((b | 0x20) - 'a' + 10); + } + else + { + return decode_result{first, conv_errc::not_base16}; + } + + result.push_back(val); + } + return decode_result{last, conv_errc::success}; + } + + struct byte_traits + { + using char_type = uint8_t; + + static constexpr int eof() + { + return std::char_traits::eof(); + } + + static int compare(const char_type* s1, const char_type* s2, std::size_t count) noexcept + { + return std::memcmp(s1,s2,count); + } + }; + + // basic_byte_string + + template + class basic_byte_string; + + // byte_string_view + class byte_string_view + { + const uint8_t* data_; + std::size_t size_; + public: + using traits_type = byte_traits; + + using const_iterator = const uint8_t*; + using iterator = const_iterator; + using size_type = std::size_t; + using value_type = uint8_t; + using reference = uint8_t&; + using const_reference = const uint8_t&; + using difference_type = std::ptrdiff_t; + using pointer = uint8_t*; + using const_pointer = const uint8_t*; + + constexpr byte_string_view() noexcept + : data_(nullptr), size_(0) + { + } + + constexpr byte_string_view(const uint8_t* data, std::size_t length) noexcept + : data_(data), size_(length) + { + } + + template + constexpr explicit byte_string_view(const Container& cont, + typename std::enable_if::value,int>::type = 0) + : data_(reinterpret_cast(cont.data())), size_(cont.size()) + { + } + + template + constexpr byte_string_view(const basic_byte_string& bytes); + + constexpr byte_string_view(const byte_string_view&) noexcept = default; + + JSONCONS_CPP14_CONSTEXPR byte_string_view(byte_string_view&& other) noexcept + : data_(nullptr), size_(0) + { + const_pointer temp_data = data_; + data_ = other.data_; + other.data_ = temp_data; + + size_type temp_size = size_; + size_ = other.size_; + other.size_ = temp_size; + } + + byte_string_view& operator=(const byte_string_view&) = default; + + byte_string_view& operator=(byte_string_view&& other) noexcept + { + std::swap(data_, other.data_); + std::swap(size_, other.size_); + return *this; + } + + constexpr const uint8_t* data() const noexcept + { + return data_; + } + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use size()") + std::size_t length() const + { + return size_; + } + #endif + constexpr size_t size() const noexcept + { + return size_; + } + + // iterator support + constexpr const_iterator begin() const noexcept + { + return data_; + } + constexpr const_iterator end() const noexcept + { + return data_ + size_; + } + constexpr const_iterator cbegin() const noexcept + { + return data_; + } + constexpr const_iterator cend() const noexcept + { + return data_ + size_; + } + + constexpr uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + JSONCONS_CPP14_CONSTEXPR byte_string_view substr(size_type pos) const + { + if (pos > size_) + { + JSONCONS_THROW(std::out_of_range("pos exceeds size")); + } + std::size_t n = size_ - pos; + return byte_string_view(data_ + pos, n); + } + + byte_string_view substr(size_type pos, size_type n) const + { + if (pos > size_) + { + JSONCONS_THROW(std::out_of_range("pos exceeds size")); + } + if (pos + n > size_) + { + n = size_ - pos; + } + return byte_string_view(data_ + pos, n); + } + + int compare(const byte_string_view& s) const noexcept + { + const int rc = traits_type::compare(data_, s.data(), (std::min)(size_, s.size())); + return rc != 0 ? rc : (size_ == s.size() ? 0 : size_ < s.size() ? -1 : 1); + } + + template + int compare(const basic_byte_string& s) const noexcept + { + const int rc = traits_type::compare(data_, s.data(), (std::min)(size_, s.size())); + return rc != 0 ? rc : (size_ == s.size() ? 0 : size_ < s.size() ? -1 : 1); + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const byte_string_view& bstr) + { + std::basic_ostringstream ss; + ss.flags(std::ios::hex); + ss.fill('0'); + + bool first = true; + for (auto b : bstr) + { + if (first) + { + first = false; + } + else + { + ss << ','; + } + ss << std::setw(2) << static_cast(b); + } + os << ss.str(); + return os; + } + }; + + // basic_byte_string + template > + class basic_byte_string + { + using byte_allocator_type = typename std::allocator_traits:: template rebind_alloc; + std::vector data_; + public: + using traits_type = byte_traits; + using allocator_type = byte_allocator_type; + + using value_type = typename std::vector::value_type; + using size_type = typename std::vector::size_type; + using difference_type = typename std::vector::difference_type; + using reference = typename std::vector::reference; + using const_reference = typename std::vector::const_reference; + using pointer = typename std::vector::pointer; + using const_pointer = typename std::vector::const_pointer; + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; + + basic_byte_string() = default; + + explicit basic_byte_string(const Allocator& alloc) + : data_(alloc) + { + } + + basic_byte_string(std::initializer_list init) + : data_(std::move(init)) + { + } + + basic_byte_string(std::initializer_list 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 basic_byte_string& v) + : data_(v.data_) + { + } + + basic_byte_string(basic_byte_string&& v) noexcept + : data_(std::move(v.data_)) + { + } + + basic_byte_string(const byte_string_view& v, const Allocator& alloc) + : data_(v.begin(),v.end(),alloc) + { + } + + basic_byte_string(const uint8_t* data, std::size_t length, const Allocator& alloc = Allocator()) + : data_(data, data+length,alloc) + { + } + + Allocator get_allocator() const + { + return data_.get_allocator(); + } + + basic_byte_string& operator=(const basic_byte_string& s) = default; + + basic_byte_string& operator=(basic_byte_string&& other) noexcept + { + data_.swap(other.data_); + return *this; + } + + void reserve(std::size_t new_cap) + { + data_.reserve(new_cap); + } + + void push_back(uint8_t b) + { + data_.push_back(b); + } + + void assign(const uint8_t* s, std::size_t count) + { + data_.clear(); + data_.insert(s, s+count); + } + + void append(const uint8_t* s, std::size_t count) + { + data_.insert(s, s+count); + } + + void clear() + { + data_.clear(); + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + // iterator support + iterator begin() noexcept + { + return data_.begin(); + } + iterator end() noexcept + { + return data_.end(); + } + + const_iterator begin() const noexcept + { + return data_.begin(); + } + const_iterator end() const noexcept + { + return data_.end(); + } + + uint8_t* data() + { + return data_.data(); + } + + const uint8_t* data() const + { + return data_.data(); + } + + std::size_t size() const + { + return data_.size(); + } + + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use size()") + std::size_t length() const + { + return data_.size(); + } + #endif + + int compare(const byte_string_view& s) const noexcept + { + const int rc = traits_type::compare(data(), s.data(), (std::min)(size(), s.size())); + return rc != 0 ? rc : (size() == s.size() ? 0 : size() < s.size() ? -1 : 1); + } + + int compare(const basic_byte_string& s) const noexcept + { + const int rc = traits_type::compare(data(), s.data(), (std::min)(size(), s.size())); + return rc != 0 ? rc : (size() == s.size() ? 0 : size() < s.size() ? -1 : 1); + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_byte_string& o) + { + os << byte_string_view(o); + return os; + } + }; + + template + constexpr byte_string_view::byte_string_view(const basic_byte_string& bytes) + : data_(bytes.data()), size_(bytes.size()) + { + } + + // == + inline + bool operator==(const byte_string_view& lhs, const byte_string_view& rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + template + bool operator==(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + template + bool operator==(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept + { + return rhs.compare(lhs) == 0; + } + template + bool operator==(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept + { + return rhs.compare(lhs) == 0; + } + + // != + + inline + bool operator!=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + template + bool operator!=(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + template + bool operator!=(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept + { + return rhs.compare(lhs) != 0; + } + template + bool operator!=(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept + { + return rhs.compare(lhs) != 0; + } + + // <= + + inline + bool operator<=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + template + bool operator<=(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + template + bool operator<=(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept + { + return rhs.compare(lhs) >= 0; + } + template + bool operator<=(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept + { + return rhs.compare(lhs) >= 0; + } + + // < + + inline + bool operator<(const byte_string_view& lhs, const byte_string_view& rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + template + bool operator<(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + template + bool operator<(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept + { + return rhs.compare(lhs) > 0; + } + template + bool operator<(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept + { + return rhs.compare(lhs) > 0; + } + + // >= + + inline + bool operator>=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + template + bool operator>=(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + template + bool operator>=(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept + { + return rhs.compare(lhs) <= 0; + } + template + bool operator>=(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept + { + return rhs.compare(lhs) <= 0; + } + + // > + + inline + bool operator>(const byte_string_view& lhs, const byte_string_view& rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + template + bool operator>(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + template + bool operator>(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept + { + return rhs.compare(lhs) < 0; + } + template + bool operator>(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept + { + return rhs.compare(lhs) < 0; + } + + using byte_string = basic_byte_string>; + + namespace type_traits { + + template + struct is_basic_byte_string + : std::false_type + {}; + + template + struct is_basic_byte_string> + : std::true_type + {}; + + } // namespace type_traits + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/config/binary_config.hpp b/include/jsoncons/config/binary_config.hpp new file mode 100644 index 0000000..51b52a8 --- /dev/null +++ b/include/jsoncons/config/binary_config.hpp @@ -0,0 +1,226 @@ +// 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_CONFIG_BINARY_CONFIG_HPP +#define JSONCONS_CONFIG_BINARY_CONFIG_HPP + +#include +#include +#include +#include // std::memcpy +#include +#include // std::enable_if + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +#ifdef __F16C__ +# include +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if defined(__GNUC__) +#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) || (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32)) +# define JSONCONS_BYTE_SWAP_64 __builtin_bswap64 +# define JSONCONS_BYTE_SWAP_32 __builtin_bswap32 +# ifdef __INTEL_COMPILER +# define JSONCONS_BYTE_SWAP_16 _bswap16 +# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16) +# define JSONCONS_BYTE_SWAP_16 __builtin_bswap16 +# endif +#endif +#elif defined(__sun) +# include +#elif defined(_MSC_VER) +// MSVC, which implies sizeof(long) == 4 +# define JSONCONS_BYTE_SWAP_64 _byteswap_uint64 +# define JSONCONS_BYTE_SWAP_32 _byteswap_ulong +# define JSONCONS_BYTE_SWAP_16 _byteswap_ushort +#endif + +namespace jsoncons { +namespace binary { + + struct uint128_holder + { + uint64_t lo; + uint64_t hi; + }; + + static inline bool add_check_overflow(std::size_t v1, std::size_t v2, std::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 + } + + #if defined(__apple_build_version__) && ((__clang_major__ < 8) || ((__clang_major__ == 8) && (__clang_minor__ < 1))) + #define APPLE_MISSING_INTRINSICS 1 + #endif + + inline + uint16_t encode_half(double val) + { + #if defined(__F16C__) && !defined(APPLE_MISSING_INTRINSICS) + return _cvtss_sh((float)val, 3); + #else + uint64_t v; + std::memcpy(&v, &val, sizeof(v)); + int64_t sign = static_cast(v >> 63 << 15); + int64_t exp = (v >> 52) & 0x7ff; + int64_t 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 static_cast(sign | ((exp + 15) << 10) | mant); + #endif + } + + /* this function was copied & adapted from RFC 7049 Appendix D */ + inline + double decode_half(uint16_t half) + { + #if defined(__F16C__) && !defined(APPLE_MISSING_INTRINSICS) + return _cvtsh_ss(half); + #else + int64_t exp = (half >> 10) & 0x1f; + int64_t mant = half & 0x3ff; + double val; + if (exp == 0) + { + val = ldexp(static_cast(mant), -24); + } + else if (exp != 31) + { + val = ldexp(static_cast(mant) + 1024.0, static_cast(exp - 25)); + } + else + { + val = mant == 0 ? std::numeric_limits::infinity() : std::nan(""); + } + return half & 0x8000 ? -val : val; + #endif + } + + // byte_swap + + template + typename std::enable_if::value && sizeof(T) == sizeof(uint8_t),T>::type + byte_swap(T val) + { + return val; + } + + template + typename std::enable_if::value && sizeof(T) == sizeof(uint16_t),T>::type + byte_swap(T val) + { + #if defined(JSONCONS_BYTE_SWAP_16) + return JSONCONS_BYTE_SWAP_16(val); + #else + return (static_cast(val) >> 8) | (static_cast(val) << 8); + #endif + } + + template + typename std::enable_if::value && sizeof(T) == sizeof(uint32_t),T>::type + byte_swap(T val) + { + #if defined(JSONCONS_BYTE_SWAP_32) + return JSONCONS_BYTE_SWAP_32(val); + #else + uint32_t tmp = ((static_cast(val) << 8) & 0xff00ff00) | ((static_cast(val) >> 8) & 0xff00ff); + return (tmp << 16) | (tmp >> 16); + #endif + } + + template + typename std::enable_if::value && sizeof(T) == sizeof(uint64_t),T>::type + byte_swap(T val) + { + #if defined(JSONCONS_BYTE_SWAP_64) + return JSONCONS_BYTE_SWAP_64(val); + #else + uint64_t tmp = ((static_cast(val) & 0x00000000ffffffffull) << 32) | ((static_cast(val) & 0xffffffff00000000ull) >> 32); + tmp = ((tmp & 0x0000ffff0000ffffull) << 16) | ((tmp & 0xffff0000ffff0000ull) >> 16); + return ((tmp & 0x00ff00ff00ff00ffull) << 8) | ((tmp & 0xff00ff00ff00ff00ull) >> 8); + #endif + } + + template + typename std::enable_if::value && sizeof(T) == sizeof(uint32_t),T>::type + byte_swap(T val) + { + uint32_t x; + std::memcpy(&x,&val,sizeof(uint32_t)); + uint32_t y = byte_swap(x); + T val2; + std::memcpy(&val2,&y,sizeof(uint32_t)); + return val2; + } + + template + typename std::enable_if::value && sizeof(T) == sizeof(uint64_t),T>::type + byte_swap(T val) + { + uint64_t x; + std::memcpy(&x,&val,sizeof(uint64_t)); + uint64_t y = byte_swap(x); + T val2; + std::memcpy(&val2,&y,sizeof(uint64_t)); + return val2; + } + + template + typename std::enable_if::value && sizeof(T) == 2*sizeof(uint64_t),T>::type + byte_swap(T val) + { + uint128_holder x; + uint8_t buf[2*sizeof(uint64_t)]; + std::memcpy(buf,&val,2*sizeof(uint64_t)); + std::memcpy(&x.lo,buf,sizeof(uint64_t)); + std::memcpy(&x.hi,buf+sizeof(uint64_t),sizeof(uint64_t)); + + uint128_holder y; + y.lo = byte_swap(x.hi); + y.hi = byte_swap(x.lo); + + T val2; + std::memcpy(&val2,&y,2*sizeof(uint64_t)); + + return val2; + } + +} // binary +} // jsoncons + +#endif diff --git a/include/jsoncons/config/compiler_support.hpp b/include/jsoncons/config/compiler_support.hpp new file mode 100644 index 0000000..15d30cf --- /dev/null +++ b/include/jsoncons/config/compiler_support.hpp @@ -0,0 +1,389 @@ +// 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_COMPILER_SUPPORT_HPP +#define JSONCONS_COMPILER_SUPPORT_HPP + +#include +#include +#include +#include +#include + +#if defined (__clang__) +#define JSONCONS_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif + +// 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 + +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 +#define JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR 1 +#define JSONCONS_NO_MAP_CONS_TAKES_ALLOCATOR 1 +#endif + +#if defined(__clang__) +# define JSONCONS_FALLTHROUGH [[clang::fallthrough]] +#elif defined(__GNUC__) && ((__GNUC__ >= 7)) +# define JSONCONS_FALLTHROUGH __attribute__((fallthrough)) +#elif defined (__GNUC__) +# define JSONCONS_FALLTHROUGH // FALLTHRU +#else +# define JSONCONS_FALLTHROUGH +#endif + +#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 + +// Deprecated symbols markup +#if (defined(__cplusplus) && __cplusplus >= 201402L) +#define JSONCONS_DEPRECATED_MSG(msg) [[deprecated(msg)]] +#endif + +#if !defined(JSONCONS_DEPRECATED_MSG) && defined(__GNUC__) && defined(__has_extension) +#if __has_extension(attribute_deprecated_with_message) +#define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#endif +#endif + +#if !defined(JSONCONS_DEPRECATED_MSG) && defined(_MSC_VER) +#if (_MSC_VER) >= 1920 +#define JSONCONS_DEPRECATED_MSG(msg) [[deprecated(msg)]] +#else +#define JSONCONS_DEPRECATED_MSG(msg) __declspec(deprecated(msg)) +#endif +#endif + +// Following boost/atomic/detail/config.hpp +#if !defined(JSONCONS_DEPRECATED_MSG) && (\ + (defined(__GNUC__) && ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0)) >= 405) ||\ + (defined(__SUNPRO_CC) && (__SUNPRO_CC + 0) >= 0x5130)) + #define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) +#endif + +#if !defined(JSONCONS_DEPRECATED_MSG) && defined(__clang__) && defined(__has_extension) + #if __has_extension(attribute_deprecated_with_message) + #define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) + #else + #define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated)) + #endif +#endif + +#if !defined(JSONCONS_DEPRECATED_MSG) +#define JSONCONS_DEPRECATED_MSG(msg) +#endif + +#if defined(ANDROID) || defined(__ANDROID__) +#if __ANDROID_API__ >= 21 +#define JSONCONS_HAS_STRTOLD_L +#else +#define JSONCONS_NO_LOCALECONV +#endif +#endif + +#if defined(_MSC_VER) +#define JSONCONS_HAS_MSC_STRTOD_L +#define JSONCONS_HAS_FOPEN_S +#endif + +#ifndef JSONCONS_HAS_CP14 + #if defined(_MSVC_LANG) + #if _MSVC_LANG >= 201402L + #define JSONCONS_HAS_CP14 + #endif + #elif __cplusplus >= 201402L + #define JSONCONS_HAS_CP14 + #endif +#endif + +#if !defined(JSONCONS_HAS_STD_FROM_CHARS) +# if defined(__GNUC__) +# if (__GNUC__ >= 11) +# if (__cplusplus >= 201703) +# define JSONCONS_HAS_STD_FROM_CHARS 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 11) +# endif // defined(__GNUC__) +# if defined(_MSC_VER) +# if (_MSC_VER >= 1924 && _MSVC_LANG >= 201703) +# define JSONCONS_HAS_STD_FROM_CHARS 1 +# endif // (_MSC_VER >= 1924 && MSVC_LANG >= 201703) +# endif // defined(_MSC_VER) +#endif +#if defined(JSONCONS_HAS_STD_FROM_CHARS) +#include +#endif + +#if !defined(JSONCONS_HAS_2017) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# define JSONCONS_HAS_2017 1 +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define JSONCONS_HAS_2017 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(_MSC_VER) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define JSONCONS_HAS_2017 1 +# endif // (_MSC_VER >= 1910 && MSVC_LANG >= 201703) +# endif // defined(_MSC_VER) +#endif + +#if defined(JSONCONS_HAS_2017) + #define JSONCONS_NODISCARD [[nodiscard]] + #define JSONCONS_IF_CONSTEXPR if constexpr +#else + #define JSONCONS_NODISCARD + #define JSONCONS_IF_CONSTEXPR if +#endif + +#if !defined(JSONCONS_HAS_STD_STRING_VIEW) +# if (defined JSONCONS_HAS_2017) +# if defined(__clang__) +# if __has_include() +# define JSONCONS_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# else +# define JSONCONS_HAS_STD_STRING_VIEW 1 +# endif +# endif // defined(JSONCONS_HAS_2017) +#endif // !defined(JSONCONS_HAS_STD_STRING_VIEW) + +#if !defined(JSONCONS_HAS_STD_BYTE) +# if (defined JSONCONS_HAS_2017) +# define JSONCONS_HAS_STD_BYTE 1 +# endif // defined(JSONCONS_HAS_2017) +#endif // !defined(JSONCONS_HAS_STD_BYTE) + +#if !defined(JSONCONS_HAS_STD_OPTIONAL) +# if (defined JSONCONS_HAS_2017) +# if defined(__clang__) +# if __has_include() +# define JSONCONS_HAS_STD_OPTIONAL 1 +# endif // __has_include() +# else +# define JSONCONS_HAS_STD_OPTIONAL 1 +# endif +# endif // defined(JSONCONS_HAS_2017) +#endif // !defined(JSONCONS_HAS_STD_OPTIONAL) + +#if !defined(JSONCONS_HAS_STD_VARIANT) +# if (defined JSONCONS_HAS_2017) +# if defined(__clang__) +# if defined(__APPLE__) +# if JSONCONS_CLANG_VERSION >= 100001 +# define JSONCONS_HAS_STD_VARIANT 1 +# endif +# elif __has_include() +# define JSONCONS_HAS_STD_VARIANT 1 +# endif // __has_include() +# else +# define JSONCONS_HAS_STD_VARIANT 1 +# endif +# endif // defined(JSONCONS_HAS_2017) +#endif // !defined(JSONCONS_HAS_STD_VARIANT) + +#if !defined(JSONCONS_HAS_FILESYSTEM) +# if (defined JSONCONS_HAS_2017) +# if defined(__clang__) +# if __has_include() +# define JSONCONS_HAS_FILESYSTEM 1 +# endif // __has_include() +# else +# define JSONCONS_HAS_FILESYSTEM 1 +# endif +# endif // defined(JSONCONS_HAS_2017) +#endif // !defined(JSONCONS_HAS_FILESYSTEM) + +#if (!defined(JSONCONS_NO_EXCEPTIONS)) +// Check if exceptions are disabled. +# if defined( __cpp_exceptions) && __cpp_exceptions == 0 +# define JSONCONS_NO_EXCEPTIONS 1 +# endif +#endif + +#if !defined(JSONCONS_NO_EXCEPTIONS) + +#if defined(__GNUC__) && !__EXCEPTIONS +# define JSONCONS_NO_EXCEPTIONS 1 +#elif _MSC_VER +#if defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS == 0 +# define JSONCONS_NO_EXCEPTIONS 1 +#elif !defined(_CPPUNWIND) +# define JSONCONS_NO_EXCEPTIONS 1 +#endif +#endif +#endif + +// allow to disable exceptions +#if !defined(JSONCONS_NO_EXCEPTIONS) + #define JSONCONS_THROW(exception) throw exception + #define JSONCONS_RETHROW throw + #define JSONCONS_TRY try + #define JSONCONS_CATCH(exception) catch(exception) +#else + #define JSONCONS_THROW(exception) std::terminate() + #define JSONCONS_RETHROW std::terminate() + #define JSONCONS_TRY if (true) + #define JSONCONS_CATCH(exception) if (false) +#endif + +#if !defined(JSONCONS_HAS_STD_MAKE_UNIQUE) + #if defined(__clang__) && defined(__cplusplus) + #if defined(__APPLE__) + #if __clang_major__ >= 6 && __cplusplus >= 201402L // Xcode 6 + #define JSONCONS_HAS_STD_MAKE_UNIQUE + #endif + #elif ((__clang_major__*100 +__clang_minor__) >= 340) && __cplusplus >= 201402L + #define JSONCONS_HAS_STD_MAKE_UNIQUE + #endif + #elif defined(__GNUC__) + #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409 && __cplusplus > 201103L + #define JSONCONS_HAS_STD_MAKE_UNIQUE + #endif + #elif defined(_MSC_VER) + #if _MSC_VER >= 1800 + #define JSONCONS_HAS_STD_MAKE_UNIQUE + #endif + #endif +#endif // !defined(JSONCONS_HAS_STD_MAKE_UNIQUE) + +#ifndef JSONCONS_HAS_CP14_CONSTEXPR + #if defined(_MSC_VER) + #if _MSC_VER >= 1910 + #define JSONCONS_HAS_CP14_CONSTEXPR + #endif + #elif defined(__GNUC__) + #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 600 && __cplusplus >= 201402L + #define JSONCONS_HAS_CP14_CONSTEXPR + #endif + #endif +#endif + +#if defined(JSONCONS_HAS_CP14_CONSTEXPR) +# define JSONCONS_CPP14_CONSTEXPR constexpr +#else +# define JSONCONS_CPP14_CONSTEXPR +#endif + +// Follows boost + +// gcc and clang +#if (defined(__clang__) || defined(__GNUC__)) && defined(__cplusplus) +#if defined(__SIZEOF_INT128__) && !defined(_MSC_VER) +# define JSONCONS_HAS_INT128 +#endif + +#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) +#if (__clang_major__ >= 4) && defined(__has_include) +#if __has_include() +# define JSONCONS_HAS_FLOAT128 +#endif +#endif +#endif +#endif + +#if defined(__GNUC__) +#if defined(_GLIBCXX_USE_FLOAT128) +# define JSONCONS_HAS_FLOAT128 +#endif +#endif + +#if defined(__clang__) +#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) +#if (__clang_major__ >= 4) && defined(__has_include) +#if __has_include() +# define JSONCONS_HAS_FLOAT128 +#endif +#endif +#endif +#endif + +// Follows boost config/detail/suffix.hpp +#if defined(JSONCONS_HAS_INT128) && defined(__cplusplus) +namespace jsoncons{ +# ifdef __GNUC__ + __extension__ typedef __int128 int128_type; + __extension__ typedef unsigned __int128 uint128_type; +# else + typedef __int128 int128_type; + typedef unsigned __int128 uint128_type; +# endif +} +#endif +#if defined(JSONCONS_HAS_FLOAT128) && defined(__cplusplus) +namespace jsoncons { +# ifdef __GNUC__ + __extension__ typedef __float128 float128_type; +# else + typedef __float128 float128_type; +# endif +} +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1900 + #define JSONCONS_COPY(first,last,d_first) std::copy(first, last, stdext::make_checked_array_iterator(d_first, static_cast(std::distance(first, last)))) +#else + #define JSONCONS_COPY(first,last,d_first) std::copy(first, last, d_first) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +#define JSONCONS_CONSTEXPR +#else +#define JSONCONS_CONSTEXPR constexpr +#endif + +namespace jsoncons { + + class assertion_error : public std::runtime_error + { + public: + assertion_error(const std::string& s) noexcept + : std::runtime_error(s) + { + } + const char* what() const noexcept override + { + return std::runtime_error::what(); + } + }; + +} // namespace jsoncons + +#define JSONCONS_STR2(x) #x +#define JSONCONS_STR(x) JSONCONS_STR2(x) + +#ifdef _DEBUG +#define JSONCONS_ASSERT(x) if (!(x)) { \ + JSONCONS_THROW(jsoncons::assertion_error("assertion '" #x "' failed at " __FILE__ ":" \ + JSONCONS_STR(__LINE__))); } +#else +#define JSONCONS_ASSERT(x) if (!(x)) { \ + JSONCONS_THROW(jsoncons::assertion_error("assertion '" #x "' failed at <> :" \ + JSONCONS_STR( 0 ))); } +#endif // _DEBUG + +#endif // JSONCONS_COMPILER_SUPPORT_HPP diff --git a/include/jsoncons/config/jsoncons_config.hpp b/include/jsoncons/config/jsoncons_config.hpp new file mode 100644 index 0000000..63c437b --- /dev/null +++ b/include/jsoncons/config/jsoncons_config.hpp @@ -0,0 +1,308 @@ +// Copyright 2019 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_CONFIG_JSONCONS_CONFIG_HPP +#define JSONCONS_CONFIG_JSONCONS_CONFIG_HPP + +#include +#include +#include +#include + +#if !defined(JSONCONS_HAS_STD_STRING_VIEW) +#include +namespace jsoncons { +using jsoncons::detail::basic_string_view; +using string_view = basic_string_view>; +using wstring_view = basic_string_view>; +} +#else +#include +namespace jsoncons { +using std::basic_string_view; +using std::string_view; +using std::wstring_view; +} +#endif + +#if !defined(JSONCONS_HAS_STD_SPAN) +#include +namespace jsoncons { +using jsoncons::detail::span; +} +#else +#include +namespace jsoncons { +using std::span; +} +#endif + +#if defined(JSONCONS_HAS_STD_OPTIONAL) + #include + namespace jsoncons { + using std::optional; + } +#elif defined(JSONCONS_HAS_BOOST_OPTIONAL) + #include + namespace jsoncons { + using boost::optional; + } +#else + #include + namespace jsoncons { + using jsoncons::detail::optional; +} +#endif // !defined(JSONCONS_HAS_STD_OPTIONAL) + +#if !defined(JSONCONS_HAS_STD_ENDIAN) +#include +namespace jsoncons { +using jsoncons::detail::endian; +} +#else +#include +namespace jsoncons +{ + using std::endian; +} +#endif + +#if !defined(JSONCONS_HAS_STD_MAKE_UNIQUE) + +#include +#include +#include +#include + +namespace jsoncons { + + template + struct unique_if + { + using value_is_not_array = std::unique_ptr; + }; + + template + struct unique_if + { + typedef std::unique_ptr value_is_array_of_unknown_bound; + }; + + template + struct unique_if { + using value_is_array_of_known_bound = void; + }; + + template + typename unique_if::value_is_not_array + make_unique(Args&&... args) + { + return std::unique_ptr(new T(std::forward(args)...)); + } + + template + typename unique_if::value_is_array_of_unknown_bound + make_unique(std::size_t n) + { + using U = typename std::remove_extent::type; + return std::unique_ptr(new U[n]()); + } + + template + typename unique_if::value_is_array_of_known_bound + make_unique(Args&&...) = delete; +} // jsoncons + +#else + +#include +namespace jsoncons +{ + using std::make_unique; +} + +#endif // !defined(JSONCONS_HAS_STD_MAKE_UNIQUE) + +namespace jsoncons { +namespace binary { + + // native_to_big + + template + typename std::enable_if::type + native_to_big(T val, OutputIt d_first) + { + uint8_t buf[sizeof(T)]; + std::memcpy(buf, &val, sizeof(T)); + for (auto item : buf) + { + *d_first++ = item; + } + } + + template + typename std::enable_if::type + native_to_big(T val, OutputIt d_first) + { + T val2 = byte_swap(val); + uint8_t buf[sizeof(T)]; + std::memcpy(buf, &val2, sizeof(T)); + for (auto item : buf) + { + *d_first++ = item; + } + } + + // native_to_little + + template + typename std::enable_if::type + native_to_little(T val, OutputIt d_first) + { + uint8_t buf[sizeof(T)]; + std::memcpy(buf, &val, sizeof(T)); + for (auto item : buf) + { + *d_first++ = item; + } + } + + template + typename std::enable_if::type + native_to_little(T val, OutputIt d_first) + { + T val2 = byte_swap(val); + uint8_t buf[sizeof(T)]; + std::memcpy(buf, &val2, sizeof(T)); + for (auto item : buf) + { + *d_first++ = item; + } + } + + // big_to_native + + template + typename std::enable_if::type + big_to_native(const uint8_t* first, std::size_t count) + { + if (sizeof(T) > count) + { + return T{}; + } + T val; + std::memcpy(&val,first,sizeof(T)); + return val; + } + + template + typename std::enable_if::type + big_to_native(const uint8_t* first, std::size_t count) + { + if (sizeof(T) > count) + { + return T{}; + } + T val; + std::memcpy(&val,first,sizeof(T)); + return byte_swap(val); + } + + // little_to_native + + template + typename std::enable_if::type + little_to_native(const uint8_t* first, std::size_t count) + { + if (sizeof(T) > count) + { + return T{}; + } + T val; + std::memcpy(&val,first,sizeof(T)); + return val; + } + + template + typename std::enable_if::type + little_to_native(const uint8_t* first, std::size_t count) + { + if (sizeof(T) > count) + { + return T{}; + } + T val; + std::memcpy(&val,first,sizeof(T)); + return byte_swap(val); + } + +} // binary +} // jsoncons + +namespace jsoncons { + + template + constexpr const CharT* cstring_constant_of_type(const char* c, const wchar_t* w); + + template<> inline + constexpr const char* cstring_constant_of_type(const char* c, const wchar_t*) + { + return c; + } + template<> inline + constexpr const wchar_t* cstring_constant_of_type(const char*, const wchar_t* w) + { + return w; + } + + template + std::basic_string string_constant_of_type(const char* c, const wchar_t* w); + + template<> inline + std::string string_constant_of_type(const char* c, const wchar_t*) + { + return std::string(c); + } + template<> inline + std::wstring string_constant_of_type(const char*, const wchar_t* w) + { + return std::wstring(w); + } + + template + jsoncons::basic_string_view string_view_constant_of_type(const char* c, const wchar_t* w); + + template<> inline + jsoncons::string_view string_view_constant_of_type(const char* c, const wchar_t*) + { + return jsoncons::string_view(c); + } + template<> inline + jsoncons::wstring_view string_view_constant_of_type(const char*, const wchar_t* w) + { + return jsoncons::wstring_view(w); + } + +} // jsoncons + +#define JSONCONS_EXPAND(X) X +#define JSONCONS_QUOTE(Prefix, A) JSONCONS_EXPAND(Prefix ## #A) + +#define JSONCONS_CSTRING_CONSTANT(CharT, Str) cstring_constant_of_type(Str, JSONCONS_QUOTE(L, Str)) +#define JSONCONS_STRING_CONSTANT(CharT, Str) string_constant_of_type(Str, JSONCONS_QUOTE(L, Str)) +#define JSONCONS_STRING_VIEW_CONSTANT(CharT, Str) string_view_constant_of_type(Str, JSONCONS_QUOTE(L, Str)) + +#if defined(__clang__) +#define JSONCONS_HAS_STD_REGEX 1 +#elif (defined(__GNUC__) && (__GNUC__ == 4)) && (defined(__GNUC__) && __GNUC_MINOR__ < 9) +// GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631 +#else +#define JSONCONS_HAS_STD_REGEX 1 +#endif + +#endif // JSONCONS_CONFIG_JSONCONS_CONFIG_HPP + + diff --git a/include/jsoncons/config/version.hpp b/include/jsoncons/config/version.hpp new file mode 100644 index 0000000..7f11eef --- /dev/null +++ b/include/jsoncons/config/version.hpp @@ -0,0 +1,40 @@ +// 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 + +#define JSONCONS_VERSION_MAJOR 0 +#define JSONCONS_VERSION_MINOR 168 +#define JSONCONS_VERSION_PATCH 7 + +namespace jsoncons { + +struct versioning_info +{ + 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; + } +}; + +constexpr versioning_info version() +{ + return versioning_info{JSONCONS_VERSION_MAJOR, JSONCONS_VERSION_MINOR, JSONCONS_VERSION_PATCH}; +} + +} + +#endif diff --git a/include/jsoncons/conv_error.hpp b/include/jsoncons/conv_error.hpp new file mode 100644 index 0000000..cad5460 --- /dev/null +++ b/include/jsoncons/conv_error.hpp @@ -0,0 +1,218 @@ +/// Copyright 2019 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_CONV_ERROR_HPP +#define JSONCONS_CONV_ERROR_HPP + +#include +#include + +namespace jsoncons { + + class conv_error : public std::system_error, public virtual json_exception + { + std::size_t line_number_; + std::size_t column_number_; + mutable std::string what_; + public: + conv_error(std::error_code ec) + : std::system_error(ec), line_number_(0), column_number_(0) + { + } + conv_error(std::error_code ec, const std::string& what_arg) + : std::system_error(ec, what_arg), line_number_(0), column_number_(0) + { + } + conv_error(std::error_code ec, std::size_t position) + : std::system_error(ec), line_number_(0), column_number_(position) + { + } + conv_error(std::error_code ec, std::size_t line, std::size_t column) + : std::system_error(ec), line_number_(line), column_number_(column) + { + } + conv_error(const conv_error& other) = default; + + conv_error(conv_error&& other) = default; + + const char* what() const noexcept override + { + if (what_.empty()) + { + JSONCONS_TRY + { + what_.append(std::system_error::what()); + if (line_number_ != 0 && column_number_ != 0) + { + what_.append(" at line "); + what_.append(std::to_string(line_number_)); + what_.append(" and column "); + what_.append(std::to_string(column_number_)); + } + else if (column_number_ != 0) + { + what_.append(" at position "); + what_.append(std::to_string(column_number_)); + } + return what_.c_str(); + } + JSONCONS_CATCH(...) + { + return std::system_error::what(); + } + } + else + { + return what_.c_str(); + } + } + + std::size_t line() const noexcept + { + return line_number_; + } + + std::size_t column() const noexcept + { + return column_number_; + } + }; + + enum class conv_errc + { + success = 0, + conversion_failed, + not_utf8, + not_wide_char, + not_vector, + not_array, + not_map, + not_pair, + not_string, + not_string_view, + not_byte_string, + not_byte_string_view, + not_integer, + not_signed_integer, + not_unsigned_integer, + not_bigint, + not_double, + not_bool, + not_variant, + not_nullptr, + not_jsoncons_null_type, + not_bitset, + not_base64, + not_base64url, + not_base16 + }; + + template + struct decode_result + { + InputIt it; + conv_errc ec; + }; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use conv_error") typedef conv_error convert_error; +#endif + +} // namespace jsoncons + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +namespace jsoncons { + +namespace detail { + class conv_error_category_impl + : public std::error_category + { + public: + const char* name() const noexcept override + { + return "jsoncons/convert"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case conv_errc::conversion_failed: + return "Unable to convert into the provided type"; + case conv_errc::not_utf8: + return "Cannot convert string to UTF-8"; + case conv_errc::not_wide_char: + return "Cannot convert string to wide characters"; + case conv_errc::not_vector: + return "Cannot convert to vector"; + case conv_errc::not_array: + return "Cannot convert to std::array"; + case conv_errc::not_map: + return "Cannot convert to map"; + case conv_errc::not_pair: + return "Cannot convert to std::pair"; + case conv_errc::not_string: + return "Cannot convert to string"; + case conv_errc::not_string_view: + return "Cannot convert to string_view"; + case conv_errc::not_byte_string: + return "Cannot convert to byte_string"; + case conv_errc::not_byte_string_view: + return "Cannot convert to byte_string_view"; + case conv_errc::not_integer: + return "Cannot convert to integer"; + case conv_errc::not_signed_integer: + return "Cannot convert to signed integer"; + case conv_errc::not_unsigned_integer: + return "Cannot convert to unsigned integer"; + case conv_errc::not_bigint: + return "Cannot convert to bigint"; + case conv_errc::not_double: + return "Cannot convert to double"; + case conv_errc::not_bool: + return "Cannot convert to bool"; + case conv_errc::not_variant: + return "Cannot convert to std::variant"; + case conv_errc::not_nullptr: + return "Cannot convert to std::nullptr_t"; + case conv_errc::not_jsoncons_null_type: + return "Cannot convert to jsoncons::null_type"; + case conv_errc::not_bitset: + return "Cannot convert to std::bitset"; + case conv_errc::not_base64: + return "Input is not a base64 encoded string"; + case conv_errc::not_base64url: + return "Input is not a base64url encoded string"; + case conv_errc::not_base16: + return "Input is not a base16 encoded string"; + default: + return "Unknown conversion error"; + } + } + }; +} // detail + +extern inline +const std::error_category& conv_error_category() +{ + static detail::conv_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(conv_errc result) +{ + return std::error_code(static_cast(result),conv_error_category()); +} + +} + +#endif diff --git a/include/jsoncons/converter.hpp b/include/jsoncons/converter.hpp new file mode 100644 index 0000000..15d1917 --- /dev/null +++ b/include/jsoncons/converter.hpp @@ -0,0 +1,296 @@ +// Copyright 2020 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_CONVERTER_HPP +#define JSONCONS_CONVERTER_HPP + +#include // std::error_code +#include +#include +#include +#include +#include // from_integer + +namespace jsoncons { + + template + class converter + { + }; + + // Into list like of bytes + template + class converter::value && + type_traits::is_back_insertable_byte_container::value) || + type_traits::is_basic_byte_string::value>::type> + { + using value_type = typename Into::value_type; + using allocator_type = typename Into::allocator_type; + + public: + + JSONCONS_CPP14_CONSTEXPR + Into from(const byte_string_view& bstr, semantic_tag tag, std::error_code& ec) const + { + Into bytes; + from_(bytes, bstr, tag, ec); + return bytes; + } + + JSONCONS_CPP14_CONSTEXPR + Into from(const byte_string_view& bstr, semantic_tag tag, const allocator_type& alloc, std::error_code& ec) const + { + Into bytes(alloc); + from_(bytes, bstr, tag, ec); + return bytes; + } + + template + JSONCONS_CPP14_CONSTEXPR + Into from(const jsoncons::basic_string_view& s, semantic_tag tag, std::error_code& ec) const + { + Into bytes; + from_(bytes, s, tag, ec); + return bytes; + } + + template + JSONCONS_CPP14_CONSTEXPR + Into from(const jsoncons::basic_string_view& s, semantic_tag tag, const allocator_type& alloc, std::error_code& ec) const + { + Into bytes(alloc); + from_(bytes, s, tag, ec); + return bytes; + } + + private: + JSONCONS_CPP14_CONSTEXPR + void from_(Into& bytes, const byte_string_view& bstr, semantic_tag, std::error_code&) const + { + for (auto ch : bstr) + { + bytes.push_back(static_cast(ch)); + } + } + + template + JSONCONS_CPP14_CONSTEXPR + typename std::enable_if::value>::type + from_(Into& bytes, const jsoncons::basic_string_view& s, semantic_tag tag, std::error_code& ec) const + { + switch (tag) + { + case semantic_tag::base16: + { + auto res = decode_base16(s.begin(), s.end(), bytes); + if (res.ec != conv_errc::success) + { + ec = conv_errc::not_byte_string; + } + break; + } + case semantic_tag::base64: + { + decode_base64(s.begin(), s.end(), bytes); + break; + } + case semantic_tag::base64url: + { + decode_base64url(s.begin(), s.end(), bytes); + break; + } + default: + { + ec = conv_errc::not_byte_string; + break; + } + } + } + + template + typename std::enable_if::value>::type + from_(Into& bytes, const jsoncons::basic_string_view& s, semantic_tag tag, std::error_code& ec) const + { + std::string u; + auto retval = unicode_traits::convert(s.data(), s.size(), u); + if (retval.ec != unicode_traits::conv_errc()) + { + ec = conv_errc::not_utf8; + return; + } + from_(bytes, jsoncons::string_view(u), tag, ec); + } + }; + + // Into string + template + class converter::value>::type> + { + using char_type = typename Into::value_type; + using allocator_type = typename Into::allocator_type; + int dummy_; + public: + explicit converter(int dummy = int()) + : dummy_(dummy) + {} + template + JSONCONS_CPP14_CONSTEXPR + typename std::enable_if::value,Into>::type + from(Integer val, semantic_tag, std::error_code&) const + { + Into s; + jsoncons::detail::from_integer(val, s); + return s; + } + + template + JSONCONS_CPP14_CONSTEXPR + typename std::enable_if::value,Into>::type + from(Integer val, semantic_tag, const allocator_type& alloc, std::error_code&) const + { + Into s(alloc); + jsoncons::detail::from_integer(val, s); + return s; + } + + Into from(double val, semantic_tag, std::error_code&) const + { + Into s; + jsoncons::detail::write_double f{float_chars_format::general,0}; + f(val, s); + return s; + } + + Into from(double val, semantic_tag, const allocator_type& alloc, std::error_code&) const + { + Into s(alloc); + jsoncons::detail::write_double f{float_chars_format::general,0}; + f(val, s); + return s; + } + + Into from(half_arg_t, uint16_t val, semantic_tag, std::error_code&) const + { + Into s; + jsoncons::detail::write_double f{float_chars_format::general,0}; + double x = binary::decode_half(val); + f(x, s); + return s; + } + + Into from(half_arg_t, uint16_t val, semantic_tag, const allocator_type& alloc, std::error_code&) const + { + Into s(alloc); + jsoncons::detail::write_double f{float_chars_format::general,0}; + double x = binary::decode_half(val); + f(x, s); + return s; + } + + template + JSONCONS_CPP14_CONSTEXPR + Into from(const byte_string_view& bytes, semantic_tag tag, std::error_code& ec) const + { + Into s; + from_(s, bytes, tag, ec); + return s; + } + + template + JSONCONS_CPP14_CONSTEXPR + Into from(const byte_string_view& bytes, semantic_tag tag, const allocator_type& alloc, std::error_code& ec) const + { + Into s(alloc); + from_(s, bytes, tag, ec); + return s; + } + + constexpr + Into from(const jsoncons::basic_string_view& s, semantic_tag, std::error_code&) const + { + return Into(s.data(), s.size()); + } + + constexpr + Into from(const jsoncons::basic_string_view& s, semantic_tag, const allocator_type& alloc, std::error_code&) const + { + return Into(s.data(), s.size(), alloc); + } + + JSONCONS_CPP14_CONSTEXPR + Into from(bool val, semantic_tag, std::error_code&) const + { + constexpr const char_type* true_constant = JSONCONS_CSTRING_CONSTANT(char_type,"true"); + constexpr const char_type* false_constant = JSONCONS_CSTRING_CONSTANT(char_type,"false"); + + return val ? Into(true_constant,4) : Into(false_constant,5); + } + + JSONCONS_CPP14_CONSTEXPR + Into from(bool val, semantic_tag, const allocator_type& alloc, std::error_code&) const + { + constexpr const char_type* true_constant = JSONCONS_CSTRING_CONSTANT(char_type,"true"); + constexpr const char_type* false_constant = JSONCONS_CSTRING_CONSTANT(char_type,"false"); + + return val ? Into(true_constant,4,alloc) : Into(false_constant,5,alloc); + } + + JSONCONS_CPP14_CONSTEXPR + Into from(null_type, semantic_tag, std::error_code&) const + { + constexpr const char_type* null_constant = JSONCONS_CSTRING_CONSTANT(char_type,"null"); + + return Into(null_constant,4); + } + + JSONCONS_CPP14_CONSTEXPR + Into from(null_type, semantic_tag, const allocator_type& alloc, std::error_code&) const + { + constexpr const char_type* null_constant = JSONCONS_CSTRING_CONSTANT(char_type,"null"); + + return Into(null_constant,4,alloc); + } + private: + + template + JSONCONS_CPP14_CONSTEXPR + typename std::enable_if::value>::type + from_(Into& s, const byte_string_view& bytes, semantic_tag tag, std::error_code&) const + { + switch (tag) + { + case semantic_tag::base64: + encode_base64(bytes.begin(), bytes.end(), s); + break; + case semantic_tag::base16: + encode_base16(bytes.begin(), bytes.end(), s); + break; + default: + encode_base64url(bytes.begin(), bytes.end(), s); + break; + } + } + + template + typename std::enable_if::value>::type + from_(Into& s, const byte_string_view& bytes, semantic_tag tag, std::error_code& ec) const + { + converter convert{ dummy_ }; + std::string u = convert.from(bytes, tag, ec); + + auto retval = unicode_traits::convert(u.data(), u.size(), s); + if (retval.ec != unicode_traits::conv_errc()) + { + ec = conv_errc::not_wide_char; + } + } + + }; + +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons/decode_json.hpp b/include/jsoncons/decode_json.hpp new file mode 100644 index 0000000..e6ce1a1 --- /dev/null +++ b/include/jsoncons/decode_json.hpp @@ -0,0 +1,209 @@ +// 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_DECODE_JSON_HPP +#define JSONCONS_DECODE_JSON_HPP + +#include +#include +#include +#include +#include // std::basic_istream +#include +#include + +namespace jsoncons { + + // decode_json + + template + typename std::enable_if::value && + type_traits::is_sequence_of::value,T>::type + decode_json(const Source& s, + const basic_json_decode_options& options = basic_json_decode_options()) + { + using char_type = typename Source::value_type; + + jsoncons::json_decoder decoder; + basic_json_reader> reader(s, decoder, options); + reader.read(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); + } + return decoder.get_result(); + } + + template + typename std::enable_if::value && + type_traits::is_char_sequence::value,T>::type + decode_json(const Source& s, + const basic_json_decode_options& options = basic_json_decode_options()) + { + using char_type = typename Source::value_type; + + basic_json_cursor> cursor(s, options, default_json_parsing()); + jsoncons::json_decoder> decoder; + std::error_code ec; + T val = decode_traits::decode(cursor, decoder, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); + } + return val; + } + + template + typename std::enable_if::value,T>::type + decode_json(std::basic_istream& is, + const basic_json_decode_options& options = basic_json_decode_options()) + { + jsoncons::json_decoder decoder; + basic_json_reader> reader(is, decoder, options); + reader.read(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); + } + return decoder.get_result(); + } + + template + typename std::enable_if::value,T>::type + decode_json(std::basic_istream& is, + const basic_json_decode_options& options = basic_json_decode_options()) + { + basic_json_cursor cursor(is, options, default_json_parsing()); + json_decoder> decoder{}; + + std::error_code ec; + T val = decode_traits::decode(cursor, decoder, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, cursor.line(), cursor.column())); + } + return val; + } + + template + typename std::enable_if::value,T>::type + decode_json(InputIt first, InputIt last, + const basic_json_decode_options::value_type>& options = + basic_json_decode_options::value_type>()) + { + using char_type = typename std::iterator_traits::value_type; + + jsoncons::json_decoder decoder; + basic_json_reader> reader(iterator_source(first,last), decoder, options); + reader.read(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); + } + return decoder.get_result(); + } + + template + typename std::enable_if::value,T>::type + decode_json(InputIt first, InputIt last, + const basic_json_decode_options::value_type>& options = + basic_json_decode_options::value_type>()) + { + using char_type = typename std::iterator_traits::value_type; + + basic_json_cursor> cursor(iterator_source(first, last), options, default_json_parsing()); + jsoncons::json_decoder> decoder; + std::error_code ec; + T val = decode_traits::decode(cursor, decoder, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, cursor.line(), cursor.column())); + } + return val; + } + + // With leading allocator parameter + + template + typename std::enable_if::value && + type_traits::is_sequence_of::value,T>::type + decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const Source& s, + const basic_json_decode_options& options = basic_json_decode_options()) + { + using char_type = typename Source::value_type; + + json_decoder decoder(temp_alloc); + + basic_json_reader,TempAllocator> reader(s, decoder, options, temp_alloc); + reader.read(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); + } + return decoder.get_result(); + } + + template + typename std::enable_if::value && + type_traits::is_char_sequence::value,T>::type + decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const Source& s, + const basic_json_decode_options& options = basic_json_decode_options()) + { + using char_type = typename Source::value_type; + + basic_json_cursor,TempAllocator> cursor(s, options, default_json_parsing(), temp_alloc); + json_decoder,TempAllocator> decoder(result_allocator_arg, temp_alloc, temp_alloc); + + std::error_code ec; + T val = decode_traits::decode(cursor, decoder, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); + } + return val; + } + + template + typename std::enable_if::value,T>::type + decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + std::basic_istream& is, + const basic_json_decode_options& options = basic_json_decode_options()) + { + json_decoder decoder(temp_alloc); + + basic_json_reader,TempAllocator> reader(is, decoder, options, temp_alloc); + reader.read(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); + } + return decoder.get_result(); + } + + template + typename std::enable_if::value,T>::type + decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + std::basic_istream& is, + const basic_json_decode_options& options = basic_json_decode_options()) + { + basic_json_cursor,TempAllocator> cursor(is, options, default_json_parsing(), temp_alloc); + json_decoder,TempAllocator> decoder(result_allocator_arg, temp_alloc,temp_alloc); + + std::error_code ec; + T val = decode_traits::decode(cursor, decoder, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); + } + return val; + } + +} // jsoncons + +#endif + diff --git a/include/jsoncons/decode_traits.hpp b/include/jsoncons/decode_traits.hpp new file mode 100644 index 0000000..2c9ee6e --- /dev/null +++ b/include/jsoncons/decode_traits.hpp @@ -0,0 +1,651 @@ +// 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_DECODE_TRAITS_HPP +#define JSONCONS_DECODE_TRAITS_HPP + +#include +#include +#include +#include +#include // std::enable_if, std::true_type, std::false_type +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + // decode_traits + + template + struct decode_traits + { + template + static T decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + decoder.reset(); + cursor.read_to(decoder, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); + } + else if (!decoder.is_valid()) + { + JSONCONS_THROW(ser_error(conv_errc::conversion_failed, cursor.context().line(), cursor.context().column())); + } + return decoder.get_result().template as(); + } + }; + + // specializations + + // primitive + + template + struct decode_traits::value + >::type> + { + template + static T decode(basic_staj_cursor& cursor, + json_decoder&, + std::error_code& ec) + { + T v = cursor.current().template get(ec); + return v; + } + }; + + // string + + template + struct decode_traits::value && + std::is_same::value + >::type> + { + template + static T decode(basic_staj_cursor& cursor, + json_decoder&, + std::error_code& ec) + { + T v = cursor.current().template get(ec); + return v; + } + }; + + template + struct decode_traits::value && + !std::is_same::value + >::type> + { + template + static T decode(basic_staj_cursor& cursor, + json_decoder&, + std::error_code& ec) + { + auto val = cursor.current().template get>(ec); + T s; + if (!ec) + { + unicode_traits::convert(val.data(), val.size(), s); + } + return s; + } + }; + + // std::pair + + template + struct decode_traits, CharT> + { + template + static std::pair decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + using value_type = std::pair; + cursor.array_expected(ec); + if (ec) + { + return value_type{}; + } + if (cursor.current().event_type() != staj_event_type::begin_array) + { + ec = conv_errc::not_pair; + return value_type(); + } + cursor.next(ec); // skip past array + if (ec) + { + return value_type(); + } + + T1 v1 = decode_traits::decode(cursor, decoder, ec); + if (ec) {return value_type();} + cursor.next(ec); + if (ec) {return value_type();} + T2 v2 = decode_traits::decode(cursor, decoder, ec); + if (ec) {return value_type();} + cursor.next(ec); + + if (cursor.current().event_type() != staj_event_type::end_array) + { + ec = conv_errc::not_pair; + return value_type(); + } + return std::make_pair(v1, v2); + } + }; + + // vector like + template + struct decode_traits::value && + type_traits::is_list_like::value && + type_traits::is_back_insertable::value && + !type_traits::is_typed_array::value + >::type> + { + using value_type = typename T::value_type; + + template + static T decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + T v; + + cursor.array_expected(ec); + if (ec) + { + return T{}; + } + if (cursor.current().event_type() != staj_event_type::begin_array) + { + ec = conv_errc::not_vector; + return v; + } + cursor.next(ec); + while (cursor.current().event_type() != staj_event_type::end_array && !ec) + { + v.push_back(decode_traits::decode(cursor, decoder, ec)); + if (ec) {return T{};} + cursor.next(ec); + } + return v; + } + }; + + template + struct typed_array_visitor : public default_json_visitor + { + T& v_; + int level_; + public: + using value_type = typename T::value_type; + + typed_array_visitor(T& v) + : default_json_visitor(false,conv_errc::not_vector), v_(v), level_(0) + { + } + private: + bool visit_begin_array(semantic_tag, + const ser_context&, + std::error_code& ec) override + { + if (++level_ != 1) + { + ec = conv_errc::not_vector; + return false; + } + return true; + } + + bool visit_begin_array(std::size_t size, + semantic_tag, + const ser_context&, + std::error_code& ec) override + { + if (++level_ != 1) + { + ec = conv_errc::not_vector; + return false; + } + if (size > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), v_, size); + } + return true; + } + + bool visit_end_array(const ser_context&, + std::error_code& ec) override + { + if (level_ != 1) + { + ec = conv_errc::not_vector; + return false; + } + return false; + } + + bool visit_uint64(uint64_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + v_.push_back(static_cast(value)); + return true; + } + + bool visit_int64(int64_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + v_.push_back(static_cast(value)); + return true; + } + + bool visit_half(uint16_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + return visit_half_(typename std::integral_constant::value>::type(), value); + } + + bool visit_half_(std::true_type, uint16_t value) + { + v_.push_back(static_cast(value)); + return true; + } + + bool visit_half_(std::false_type, uint16_t value) + { + v_.push_back(static_cast(binary::decode_half(value))); + return true; + } + + bool visit_double(double value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + v_.push_back(static_cast(value)); + return true; + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag, + const ser_context&, + std::error_code&) override + { + v_ = std::vector(data.begin(),data.end()); + return false; + } + + static + void reserve_storage(std::true_type, T& v, std::size_t new_cap) + { + v.reserve(new_cap); + } + + static + void reserve_storage(std::false_type, T&, std::size_t) + { + } + }; + + template + struct decode_traits::value && + type_traits::is_list_like::value && + type_traits::is_back_insertable_byte_container::value && + type_traits::is_typed_array::value + >::type> + { + using value_type = typename T::value_type; + + template + static T decode(basic_staj_cursor& cursor, + json_decoder&, + std::error_code& ec) + { + cursor.array_expected(ec); + if (ec) + { + return T{}; + } + switch (cursor.current().event_type()) + { + case staj_event_type::byte_string_value: + { + auto bytes = cursor.current().template get(ec); + if (!ec) + { + T v; + if (cursor.current().size() > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); + } + for (auto ch : bytes) + { + v.push_back(static_cast(ch)); + } + cursor.next(ec); + return v; + } + else + { + return T{}; + } + } + case staj_event_type::begin_array: + { + T v; + if (cursor.current().size() > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); + } + typed_array_visitor visitor(v); + cursor.read_to(visitor, ec); + return v; + } + default: + { + ec = conv_errc::not_vector; + return T{}; + } + } + } + + static void reserve_storage(std::true_type, T& v, std::size_t new_cap) + { + v.reserve(new_cap); + } + + static void reserve_storage(std::false_type, T&, std::size_t) + { + } + }; + + template + struct decode_traits::value && + type_traits::is_list_like::value && + type_traits::is_back_insertable::value && + !type_traits::is_back_insertable_byte_container::value && + type_traits::is_typed_array::value + >::type> + { + using value_type = typename T::value_type; + + template + static T decode(basic_staj_cursor& cursor, + json_decoder&, + std::error_code& ec) + { + cursor.array_expected(ec); + if (ec) + { + return T{}; + } + switch (cursor.current().event_type()) + { + case staj_event_type::begin_array: + { + T v; + if (cursor.current().size() > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); + } + typed_array_visitor visitor(v); + cursor.read_to(visitor, ec); + return v; + } + default: + { + ec = conv_errc::not_vector; + return T{}; + } + } + } + + static void reserve_storage(std::true_type, T& v, std::size_t new_cap) + { + v.reserve(new_cap); + } + + static void reserve_storage(std::false_type, T&, std::size_t) + { + } + }; + + // set like + template + struct decode_traits::value && + type_traits::is_list_like::value && + !type_traits::is_back_insertable::value && + type_traits::is_insertable::value + >::type> + { + using value_type = typename T::value_type; + + template + static T decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + T v; + + cursor.array_expected(ec); + if (ec) + { + return T{}; + } + if (cursor.current().event_type() != staj_event_type::begin_array) + { + ec = conv_errc::not_vector; + return v; + } + if (cursor.current().size() > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), v, cursor.current().size()); + } + cursor.next(ec); + while (cursor.current().event_type() != staj_event_type::end_array && !ec) + { + v.insert(decode_traits::decode(cursor, decoder, ec)); + if (ec) {return T{};} + cursor.next(ec); + if (ec) {return T{};} + } + return v; + } + + static void reserve_storage(std::true_type, T& v, std::size_t new_cap) + { + v.reserve(new_cap); + } + + static void reserve_storage(std::false_type, T&, std::size_t) + { + } + }; + + // std::array + + template + struct decode_traits,CharT> + { + using value_type = typename std::array::value_type; + + template + static std::array decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + std::array v; + cursor.array_expected(ec); + if (ec) + { + v.fill(T()); + return v; + } + v.fill(T{}); + if (cursor.current().event_type() != staj_event_type::begin_array) + { + ec = conv_errc::not_vector; + return v; + } + cursor.next(ec); + for (std::size_t i = 0; i < N && cursor.current().event_type() != staj_event_type::end_array && !ec; ++i) + { + v[i] = decode_traits::decode(cursor, decoder, ec); + if (ec) {return v;} + cursor.next(ec); + if (ec) {return v;} + } + return v; + } + }; + + // map like + + template + struct decode_traits::value && + type_traits::is_map_like::value && + type_traits::is_constructible_from_const_pointer_and_size::value + >::type> + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + + template + static T decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + T val; + if (cursor.current().event_type() != staj_event_type::begin_object) + { + ec = conv_errc::not_map; + return val; + } + if (cursor.current().size() > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), val, cursor.current().size()); + } + cursor.next(ec); + + while (cursor.current().event_type() != staj_event_type::end_object && !ec) + { + if (cursor.current().event_type() != staj_event_type::key) + { + ec = json_errc::expected_key; + return val; + } + auto key = cursor.current().template get(ec); + if (ec) return val; + cursor.next(ec); + if (ec) return val; + val.emplace(std::move(key),decode_traits::decode(cursor, decoder, ec)); + if (ec) {return val;} + cursor.next(ec); + if (ec) {return val;} + } + return val; + } + + static void reserve_storage(std::true_type, T& v, std::size_t new_cap) + { + v.reserve(new_cap); + } + + static void reserve_storage(std::false_type, T&, std::size_t) + { + } + }; + + template + struct decode_traits::value && + type_traits::is_map_like::value && + std::is_integral::value + >::type> + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + + template + static T decode(basic_staj_cursor& cursor, + json_decoder& decoder, + std::error_code& ec) + { + T val; + if (cursor.current().event_type() != staj_event_type::begin_object) + { + ec = conv_errc::not_map; + return val; + } + if (cursor.current().size() > 0) + { + reserve_storage(typename std::integral_constant::value>::type(), val, cursor.current().size()); + } + cursor.next(ec); + + while (cursor.current().event_type() != staj_event_type::end_object && !ec) + { + if (cursor.current().event_type() != staj_event_type::key) + { + ec = json_errc::expected_key; + return val; + } + auto s = cursor.current().template get>(ec); + if (ec) return val; + key_type n{0}; + auto r = jsoncons::detail::to_integer(s.data(), s.size(), n); + if (r.ec != jsoncons::detail::to_integer_errc()) + { + ec = json_errc::invalid_number; + return val; + } + cursor.next(ec); + if (ec) return val; + val.emplace(n, decode_traits::decode(cursor, decoder, ec)); + if (ec) {return val;} + cursor.next(ec); + if (ec) {return val;} + } + return val; + } + + static void reserve_storage(std::true_type, T& v, std::size_t new_cap) + { + v.reserve(new_cap); + } + + static void reserve_storage(std::false_type, T&, std::size_t) + { + } + }; + +} // jsoncons + +#endif + diff --git a/include/jsoncons/detail/endian.hpp b/include/jsoncons/detail/endian.hpp new file mode 100644 index 0000000..d47a0f7 --- /dev/null +++ b/include/jsoncons/detail/endian.hpp @@ -0,0 +1,44 @@ +// Copyright 2020 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_ENDIAN_HPP +#define JSONCONS_DETAIL_ENDIAN_HPP + +#if defined(__sun) +# include +#endif + +namespace jsoncons { +namespace detail { + + enum class endian + { + #if defined(_MSC_VER) + // MSVC, which implies Windows, which implies little-endian + little = 0, + big = 1, + native = little + #elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__) + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__ + #elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) + little = 0, + big = 1, + native = big + #elif !defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) + little = 0, + big = 1, + native = little + #else + #error "Unable to determine byte order!" + #endif + }; + +} // namespace detail +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/detail/grisu3.hpp b/include/jsoncons/detail/grisu3.hpp new file mode 100644 index 0000000..771cf1d --- /dev/null +++ b/include/jsoncons/detail/grisu3.hpp @@ -0,0 +1,312 @@ +/* +Implements the Grisu3 algorithm for printing floating-point numbers. + +Follows Florian Loitsch's grisu3_59_56 implementation, available at +http://florian.loitsch.com/publications, in bench.tar.gz, with +minor modifications. +*/ + +/* + Copyright (c) 2009 Florian Loitsch + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef JSONCONS_GRISU3_HPP +#define JSONCONS_GRISU3_HPP + +#pragma once +#include +#include +#include +#include +#include +#include // std::memmove +#include + +namespace jsoncons { namespace detail { + +// diy_fp + +typedef struct diy_fp_t { + uint64_t f; + int e; +} diy_fp_t; + +inline +diy_fp_t minus(diy_fp_t x, diy_fp_t y) +{ + assert(x.e == y.e); + assert(x.f >= y.f); + diy_fp_t r = { x.f = x.f - y.f, x.e }; + return r; +} + +inline +diy_fp_t multiply(diy_fp_t x, diy_fp_t y) +{ + uint64_t a, b, c, d, ac, bc, ad, bd, tmp; + diy_fp_t r; uint64_t M32 = 0xFFFFFFFF; + a = x.f >> 32; b = x.f & M32; + c = y.f >> 32; d = y.f & M32; + ac = a * c; bc = b * c; ad = a * d; bd = b * d; + tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + r.f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + r.e = x.e + y.e + 64; + return r; +} + +// k_comp + +inline +int k_comp(int e, int alpha, int /*gamma*/) +{ + constexpr double d_1_log2_10 = 0.30102999566398114; // 1 / lg(10) + int x = alpha - e + 63; + return static_cast(std::ceil(x * d_1_log2_10)); +} + +// powers_ten_round64 + +constexpr int diy_significand_size = 64; + +static constexpr uint64_t powers_ten[] = { 0xbf29dcaba82fdeae, 0xeef453d6923bd65a, 0x9558b4661b6565f8, 0xbaaee17fa23ebf76, 0xe95a99df8ace6f54, 0x91d8a02bb6c10594, 0xb64ec836a47146fa, 0xe3e27a444d8d98b8, 0x8e6d8c6ab0787f73, 0xb208ef855c969f50, 0xde8b2b66b3bc4724, 0x8b16fb203055ac76, 0xaddcb9e83c6b1794, 0xd953e8624b85dd79, 0x87d4713d6f33aa6c, 0xa9c98d8ccb009506, 0xd43bf0effdc0ba48, 0x84a57695fe98746d, 0xa5ced43b7e3e9188, 0xcf42894a5dce35ea, 0x818995ce7aa0e1b2, 0xa1ebfb4219491a1f, 0xca66fa129f9b60a7, 0xfd00b897478238d1, 0x9e20735e8cb16382, 0xc5a890362fddbc63, 0xf712b443bbd52b7c, 0x9a6bb0aa55653b2d, 0xc1069cd4eabe89f9, 0xf148440a256e2c77, 0x96cd2a865764dbca, 0xbc807527ed3e12bd, 0xeba09271e88d976c, 0x93445b8731587ea3, 0xb8157268fdae9e4c, 0xe61acf033d1a45df, 0x8fd0c16206306bac, 0xb3c4f1ba87bc8697, 0xe0b62e2929aba83c, 0x8c71dcd9ba0b4926, 0xaf8e5410288e1b6f, 0xdb71e91432b1a24b, 0x892731ac9faf056f, 0xab70fe17c79ac6ca, 0xd64d3d9db981787d, 0x85f0468293f0eb4e, 0xa76c582338ed2622, 0xd1476e2c07286faa, 0x82cca4db847945ca, 0xa37fce126597973d, 0xcc5fc196fefd7d0c, 0xff77b1fcbebcdc4f, 0x9faacf3df73609b1, 0xc795830d75038c1e, 0xf97ae3d0d2446f25, 0x9becce62836ac577, 0xc2e801fb244576d5, 0xf3a20279ed56d48a, 0x9845418c345644d7, 0xbe5691ef416bd60c, 0xedec366b11c6cb8f, 0x94b3a202eb1c3f39, 0xb9e08a83a5e34f08, 0xe858ad248f5c22ca, 0x91376c36d99995be, 0xb58547448ffffb2e, 0xe2e69915b3fff9f9, 0x8dd01fad907ffc3c, 0xb1442798f49ffb4b, 0xdd95317f31c7fa1d, 0x8a7d3eef7f1cfc52, 0xad1c8eab5ee43b67, 0xd863b256369d4a41, 0x873e4f75e2224e68, 0xa90de3535aaae202, 0xd3515c2831559a83, 0x8412d9991ed58092, 0xa5178fff668ae0b6, 0xce5d73ff402d98e4, 0x80fa687f881c7f8e, 0xa139029f6a239f72, 0xc987434744ac874f, 0xfbe9141915d7a922, 0x9d71ac8fada6c9b5, 0xc4ce17b399107c23, 0xf6019da07f549b2b, 0x99c102844f94e0fb, 0xc0314325637a193a, 0xf03d93eebc589f88, 0x96267c7535b763b5, 0xbbb01b9283253ca3, 0xea9c227723ee8bcb, 0x92a1958a7675175f, 0xb749faed14125d37, 0xe51c79a85916f485, 0x8f31cc0937ae58d3, 0xb2fe3f0b8599ef08, 0xdfbdcece67006ac9, 0x8bd6a141006042be, 0xaecc49914078536d, 0xda7f5bf590966849, 0x888f99797a5e012d, 0xaab37fd7d8f58179, 0xd5605fcdcf32e1d7, 0x855c3be0a17fcd26, 0xa6b34ad8c9dfc070, 0xd0601d8efc57b08c, 0x823c12795db6ce57, 0xa2cb1717b52481ed, 0xcb7ddcdda26da269, 0xfe5d54150b090b03, 0x9efa548d26e5a6e2, 0xc6b8e9b0709f109a, 0xf867241c8cc6d4c1, 0x9b407691d7fc44f8, 0xc21094364dfb5637, 0xf294b943e17a2bc4, 0x979cf3ca6cec5b5b, 0xbd8430bd08277231, 0xece53cec4a314ebe, 0x940f4613ae5ed137, 0xb913179899f68584, 0xe757dd7ec07426e5, 0x9096ea6f3848984f, 0xb4bca50b065abe63, 0xe1ebce4dc7f16dfc, 0x8d3360f09cf6e4bd, 0xb080392cc4349ded, 0xdca04777f541c568, 0x89e42caaf9491b61, 0xac5d37d5b79b6239, 0xd77485cb25823ac7, 0x86a8d39ef77164bd, 0xa8530886b54dbdec, 0xd267caa862a12d67, 0x8380dea93da4bc60, 0xa46116538d0deb78, 0xcd795be870516656, 0x806bd9714632dff6, 0xa086cfcd97bf97f4, 0xc8a883c0fdaf7df0, 0xfad2a4b13d1b5d6c, 0x9cc3a6eec6311a64, 0xc3f490aa77bd60fd, 0xf4f1b4d515acb93c, 0x991711052d8bf3c5, 0xbf5cd54678eef0b7, 0xef340a98172aace5, 0x9580869f0e7aac0f, 0xbae0a846d2195713, 0xe998d258869facd7, 0x91ff83775423cc06, 0xb67f6455292cbf08, 0xe41f3d6a7377eeca, 0x8e938662882af53e, 0xb23867fb2a35b28e, 0xdec681f9f4c31f31, 0x8b3c113c38f9f37f, 0xae0b158b4738705f, 0xd98ddaee19068c76, 0x87f8a8d4cfa417ca, 0xa9f6d30a038d1dbc, 0xd47487cc8470652b, 0x84c8d4dfd2c63f3b, 0xa5fb0a17c777cf0a, 0xcf79cc9db955c2cc, 0x81ac1fe293d599c0, 0xa21727db38cb0030, 0xca9cf1d206fdc03c, 0xfd442e4688bd304b, 0x9e4a9cec15763e2f, 0xc5dd44271ad3cdba, 0xf7549530e188c129, 0x9a94dd3e8cf578ba, 0xc13a148e3032d6e8, 0xf18899b1bc3f8ca2, 0x96f5600f15a7b7e5, 0xbcb2b812db11a5de, 0xebdf661791d60f56, 0x936b9fcebb25c996, 0xb84687c269ef3bfb, 0xe65829b3046b0afa, 0x8ff71a0fe2c2e6dc, 0xb3f4e093db73a093, 0xe0f218b8d25088b8, 0x8c974f7383725573, 0xafbd2350644eead0, 0xdbac6c247d62a584, 0x894bc396ce5da772, 0xab9eb47c81f5114f, 0xd686619ba27255a3, 0x8613fd0145877586, 0xa798fc4196e952e7, 0xd17f3b51fca3a7a1, 0x82ef85133de648c5, 0xa3ab66580d5fdaf6, 0xcc963fee10b7d1b3, 0xffbbcfe994e5c620, 0x9fd561f1fd0f9bd4, 0xc7caba6e7c5382c9, 0xf9bd690a1b68637b, 0x9c1661a651213e2d, 0xc31bfa0fe5698db8, 0xf3e2f893dec3f126, 0x986ddb5c6b3a76b8, 0xbe89523386091466, 0xee2ba6c0678b597f, 0x94db483840b717f0, 0xba121a4650e4ddec, 0xe896a0d7e51e1566, 0x915e2486ef32cd60, 0xb5b5ada8aaff80b8, 0xe3231912d5bf60e6, 0x8df5efabc5979c90, 0xb1736b96b6fd83b4, 0xddd0467c64bce4a1, 0x8aa22c0dbef60ee4, 0xad4ab7112eb3929e, 0xd89d64d57a607745, 0x87625f056c7c4a8b, 0xa93af6c6c79b5d2e, 0xd389b47879823479, 0x843610cb4bf160cc, 0xa54394fe1eedb8ff, 0xce947a3da6a9273e, 0x811ccc668829b887, 0xa163ff802a3426a9, 0xc9bcff6034c13053, 0xfc2c3f3841f17c68, 0x9d9ba7832936edc1, 0xc5029163f384a931, 0xf64335bcf065d37d, 0x99ea0196163fa42e, 0xc06481fb9bcf8d3a, 0xf07da27a82c37088, 0x964e858c91ba2655, 0xbbe226efb628afeb, 0xeadab0aba3b2dbe5, 0x92c8ae6b464fc96f, 0xb77ada0617e3bbcb, 0xe55990879ddcaabe, 0x8f57fa54c2a9eab7, 0xb32df8e9f3546564, 0xdff9772470297ebd, 0x8bfbea76c619ef36, 0xaefae51477a06b04, 0xdab99e59958885c5, 0x88b402f7fd75539b, 0xaae103b5fcd2a882, 0xd59944a37c0752a2, 0x857fcae62d8493a5, 0xa6dfbd9fb8e5b88f, 0xd097ad07a71f26b2, 0x825ecc24c8737830, 0xa2f67f2dfa90563b, 0xcbb41ef979346bca, 0xfea126b7d78186bd, 0x9f24b832e6b0f436, 0xc6ede63fa05d3144, 0xf8a95fcf88747d94, 0x9b69dbe1b548ce7d, 0xc24452da229b021c, 0xf2d56790ab41c2a3, 0x97c560ba6b0919a6, 0xbdb6b8e905cb600f, 0xed246723473e3813, 0x9436c0760c86e30c, 0xb94470938fa89bcf, 0xe7958cb87392c2c3, 0x90bd77f3483bb9ba, 0xb4ecd5f01a4aa828, 0xe2280b6c20dd5232, 0x8d590723948a535f, 0xb0af48ec79ace837, 0xdcdb1b2798182245, 0x8a08f0f8bf0f156b, 0xac8b2d36eed2dac6, 0xd7adf884aa879177, 0x86ccbb52ea94baeb, 0xa87fea27a539e9a5, 0xd29fe4b18e88640f, 0x83a3eeeef9153e89, 0xa48ceaaab75a8e2b, 0xcdb02555653131b6, 0x808e17555f3ebf12, 0xa0b19d2ab70e6ed6, 0xc8de047564d20a8c, 0xfb158592be068d2f, 0x9ced737bb6c4183d, 0xc428d05aa4751e4d, 0xf53304714d9265e0, 0x993fe2c6d07b7fac, 0xbf8fdb78849a5f97, 0xef73d256a5c0f77d, 0x95a8637627989aae, 0xbb127c53b17ec159, 0xe9d71b689dde71b0, 0x9226712162ab070e, 0xb6b00d69bb55c8d1, 0xe45c10c42a2b3b06, 0x8eb98a7a9a5b04e3, 0xb267ed1940f1c61c, 0xdf01e85f912e37a3, 0x8b61313bbabce2c6, 0xae397d8aa96c1b78, 0xd9c7dced53c72256, 0x881cea14545c7575, 0xaa242499697392d3, 0xd4ad2dbfc3d07788, 0x84ec3c97da624ab5, 0xa6274bbdd0fadd62, 0xcfb11ead453994ba, 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3e, 0xfd87b5f28300ca0e, 0x9e74d1b791e07e48, 0xc612062576589ddb, 0xf79687aed3eec551, 0x9abe14cd44753b53, 0xc16d9a0095928a27, 0xf1c90080baf72cb1, 0x971da05074da7bef, 0xbce5086492111aeb, 0xec1e4a7db69561a5, 0x9392ee8e921d5d07, 0xb877aa3236a4b449, 0xe69594bec44de15b, 0x901d7cf73ab0acd9, 0xb424dc35095cd80f, 0xe12e13424bb40e13, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, 0xdbe6fecebdedd5bf, 0x89705f4136b4a597, 0xabcc77118461cefd, 0xd6bf94d5e57a42bc, 0x8637bd05af6c69b6, 0xa7c5ac471b478423, 0xd1b71758e219652c, 0x83126e978d4fdf3b, 0xa3d70a3d70a3d70a, 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, 0xa18f07d736b90be5, 0xc9f2c9cd04674edf, 0xfc6f7c4045812296, 0x9dc5ada82b70b59e, 0xc5371912364ce305, 0xf684df56c3e01bc7, 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, 0x92efd1b8d0cf37be, 0xb7abc627050305ae, 0xe596b7b0c643c719, 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f, 0x8c213d9da502de45, 0xaf298d050e4395d7, 0xdaf3f04651d47b4c, 0x88d8762bf324cd10, 0xab0e93b6efee0054, 0xd5d238a4abe98068, 0x85a36366eb71f041, 0xa70c3c40a64e6c52, 0xd0cf4b50cfe20766, 0x82818f1281ed44a0, 0xa321f2d7226895c8, 0xcbea6f8ceb02bb3a, 0xfee50b7025c36a08, 0x9f4f2726179a2245, 0xc722f0ef9d80aad6, 0xf8ebad2b84e0d58c, 0x9b934c3b330c8577, 0xc2781f49ffcfa6d5, 0xf316271c7fc3908b, 0x97edd871cfda3a57, 0xbde94e8e43d0c8ec, 0xed63a231d4c4fb27, 0x945e455f24fb1cf9, 0xb975d6b6ee39e437, 0xe7d34c64a9c85d44, 0x90e40fbeea1d3a4b, 0xb51d13aea4a488dd, 0xe264589a4dcdab15, 0x8d7eb76070a08aed, 0xb0de65388cc8ada8, 0xdd15fe86affad912, 0x8a2dbf142dfcc7ab, 0xacb92ed9397bf996, 0xd7e77a8f87daf7fc, 0x86f0ac99b4e8dafd, 0xa8acd7c0222311bd, 0xd2d80db02aabd62c, 0x83c7088e1aab65db, 0xa4b8cab1a1563f52, 0xcde6fd5e09abcf27, 0x80b05e5ac60b6178, 0xa0dc75f1778e39d6, 0xc913936dd571c84c, 0xfb5878494ace3a5f, 0x9d174b2dcec0e47b, 0xc45d1df942711d9a, 0xf5746577930d6501, 0x9968bf6abbe85f20, 0xbfc2ef456ae276e9, 0xefb3ab16c59b14a3, 0x95d04aee3b80ece6, 0xbb445da9ca61281f, 0xea1575143cf97227, 0x924d692ca61be758, 0xb6e0c377cfa2e12e, 0xe498f455c38b997a, 0x8edf98b59a373fec, 0xb2977ee300c50fe7, 0xdf3d5e9bc0f653e1, 0x8b865b215899f46d, 0xae67f1e9aec07188, 0xda01ee641a708dea, 0x884134fe908658b2, 0xaa51823e34a7eedf, 0xd4e5e2cdc1d1ea96, 0x850fadc09923329e, 0xa6539930bf6bff46, 0xcfe87f7cef46ff17, 0x81f14fae158c5f6e, 0xa26da3999aef774a, 0xcb090c8001ab551c, 0xfdcb4fa002162a63, 0x9e9f11c4014dda7e, 0xc646d63501a1511e, 0xf7d88bc24209a565, 0x9ae757596946075f, 0xc1a12d2fc3978937, 0xf209787bb47d6b85, 0x9745eb4d50ce6333, 0xbd176620a501fc00, 0xec5d3fa8ce427b00, 0x93ba47c980e98ce0, 0xb8a8d9bbe123f018, 0xe6d3102ad96cec1e, 0x9043ea1ac7e41393, 0xb454e4a179dd1877, 0xe16a1dc9d8545e95, 0x8ce2529e2734bb1d, 0xb01ae745b101e9e4, 0xdc21a1171d42645d, 0x899504ae72497eba, 0xabfa45da0edbde69, 0xd6f8d7509292d603, 0x865b86925b9bc5c2, 0xa7f26836f282b733, 0xd1ef0244af2364ff, 0x8335616aed761f1f, 0xa402b9c5a8d3a6e7, 0xcd036837130890a1, 0x802221226be55a65, 0xa02aa96b06deb0fe, 0xc83553c5c8965d3d, 0xfa42a8b73abbf48d, 0x9c69a97284b578d8, 0xc38413cf25e2d70e, 0xf46518c2ef5b8cd1, 0x98bf2f79d5993803, 0xbeeefb584aff8604, 0xeeaaba2e5dbf6785, 0x952ab45cfa97a0b3, 0xba756174393d88e0, 0xe912b9d1478ceb17, 0x91abb422ccb812ef, 0xb616a12b7fe617aa, 0xe39c49765fdf9d95, 0x8e41ade9fbebc27d, 0xb1d219647ae6b31c, 0xde469fbd99a05fe3, 0x8aec23d680043bee, 0xada72ccc20054aea, 0xd910f7ff28069da4, 0x87aa9aff79042287, 0xa99541bf57452b28, 0xd3fa922f2d1675f2, 0x847c9b5d7c2e09b7, 0xa59bc234db398c25, 0xcf02b2c21207ef2f, 0x8161afb94b44f57d, 0xa1ba1ba79e1632dc, 0xca28a291859bbf93, 0xfcb2cb35e702af78, 0x9defbf01b061adab, 0xc56baec21c7a1916, 0xf6c69a72a3989f5c, 0x9a3c2087a63f6399, 0xc0cb28a98fcf3c80, 0xf0fdf2d3f3c30b9f, 0x969eb7c47859e744, 0xbc4665b596706115, 0xeb57ff22fc0c795a, 0x9316ff75dd87cbd8, 0xb7dcbf5354e9bece, 0xe5d3ef282a242e82, 0x8fa475791a569d11, 0xb38d92d760ec4455, 0xe070f78d3927556b, 0x8c469ab843b89563, 0xaf58416654a6babb, 0xdb2e51bfe9d0696a, 0x88fcf317f22241e2, 0xab3c2fddeeaad25b, 0xd60b3bd56a5586f2, 0x85c7056562757457, 0xa738c6bebb12d16d, 0xd106f86e69d785c8, 0x82a45b450226b39d, 0xa34d721642b06084, 0xcc20ce9bd35c78a5, 0xff290242c83396ce, 0x9f79a169bd203e41, 0xc75809c42c684dd1, 0xf92e0c3537826146, 0x9bbcc7a142b17ccc, 0xc2abf989935ddbfe, 0xf356f7ebf83552fe, 0x98165af37b2153df, 0xbe1bf1b059e9a8d6, 0xeda2ee1c7064130c, 0x9485d4d1c63e8be8, 0xb9a74a0637ce2ee1, 0xe8111c87c5c1ba9a, 0x910ab1d4db9914a0, 0xb54d5e4a127f59c8, 0xe2a0b5dc971f303a, 0x8da471a9de737e24, 0xb10d8e1456105dad, 0xdd50f1996b947519, 0x8a5296ffe33cc930, 0xace73cbfdc0bfb7b, 0xd8210befd30efa5a, 0x8714a775e3e95c78, 0xa8d9d1535ce3b396, 0xd31045a8341ca07c, 0x83ea2b892091e44e, 0xa4e4b66b68b65d61, 0xce1de40642e3f4b9, 0x80d2ae83e9ce78f4, 0xa1075a24e4421731, 0xc94930ae1d529cfd, 0xfb9b7cd9a4a7443c, 0x9d412e0806e88aa6, 0xc491798a08a2ad4f, 0xf5b5d7ec8acb58a3, 0x9991a6f3d6bf1766, 0xbff610b0cc6edd3f, 0xeff394dcff8a948f, 0x95f83d0a1fb69cd9, 0xbb764c4ca7a44410, 0xea53df5fd18d5514, 0x92746b9be2f8552c, 0xb7118682dbb66a77, 0xe4d5e82392a40515, 0x8f05b1163ba6832d, 0xb2c71d5bca9023f8, 0xdf78e4b2bd342cf7, 0x8bab8eefb6409c1a, 0xae9672aba3d0c321, 0xda3c0f568cc4f3e9, 0x8865899617fb1871, 0xaa7eebfb9df9de8e, 0xd51ea6fa85785631, 0x8533285c936b35df, 0xa67ff273b8460357, 0xd01fef10a657842c, 0x8213f56a67f6b29c, 0xa298f2c501f45f43, 0xcb3f2f7642717713, 0xfe0efb53d30dd4d8, 0x9ec95d1463e8a507, 0xc67bb4597ce2ce49, 0xf81aa16fdc1b81db, 0x9b10a4e5e9913129, 0xc1d4ce1f63f57d73, 0xf24a01a73cf2dcd0, 0x976e41088617ca02, 0xbd49d14aa79dbc82, 0xec9c459d51852ba3, 0x93e1ab8252f33b46, 0xb8da1662e7b00a17, 0xe7109bfba19c0c9d, 0x906a617d450187e2, 0xb484f9dc9641e9db, 0xe1a63853bbd26451, 0x8d07e33455637eb3, 0xb049dc016abc5e60, 0xdc5c5301c56b75f7, 0x89b9b3e11b6329bb, 0xac2820d9623bf429, 0xd732290fbacaf134, 0x867f59a9d4bed6c0, 0xa81f301449ee8c70, 0xd226fc195c6a2f8c, 0x83585d8fd9c25db8, 0xa42e74f3d032f526, 0xcd3a1230c43fb26f, 0x80444b5e7aa7cf85, 0xa0555e361951c367, 0xc86ab5c39fa63441, 0xfa856334878fc151, 0x9c935e00d4b9d8d2, 0xc3b8358109e84f07, 0xf4a642e14c6262c9, 0x98e7e9cccfbd7dbe, 0xbf21e44003acdd2d, 0xeeea5d5004981478, 0x95527a5202df0ccb, 0xbaa718e68396cffe, 0xe950df20247c83fd, 0x91d28b7416cdd27e, 0xb6472e511c81471e, 0xe3d8f9e563a198e5, 0x8e679c2f5e44ff8f, 0xb201833b35d63f73, 0xde81e40a034bcf50, 0x8b112e86420f6192, 0xadd57a27d29339f6, 0xd94ad8b1c7380874, 0x87cec76f1c830549, 0xa9c2794ae3a3c69b, 0xd433179d9c8cb841, 0x849feec281d7f329, 0xa5c7ea73224deff3, 0xcf39e50feae16bf0, 0x81842f29f2cce376, 0xa1e53af46f801c53, 0xca5e89b18b602368, 0xfcf62c1dee382c42, 0x9e19db92b4e31ba9, 0xc5a05277621be294, 0xf70867153aa2db39, 0x9a65406d44a5c903, 0xc0fe908895cf3b44, 0xf13e34aabb430a15, 0x96c6e0eab509e64d, 0xbc789925624c5fe1, 0xeb96bf6ebadf77d9, 0x933e37a534cbaae8, 0xb80dc58e81fe95a1, 0xe61136f2227e3b0a, 0x8fcac257558ee4e6, 0xb3bd72ed2af29e20, 0xe0accfa875af45a8, 0x8c6c01c9498d8b89, 0xaf87023b9bf0ee6b, 0xdb68c2ca82ed2a06, 0x892179be91d43a44, 0xab69d82e364948d4 }; +static constexpr int powers_ten_e[] = { -1203, -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166, -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130, -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093, -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057, -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020, -1017, -1014, -1010, -1007, -1004, -1000, -997, -994, -990, -987, -984, -980, -977, -974, -970, -967, -964, -960, -957, -954, -950, -947, -944, -940, -937, -934, -931, -927, -924, -921, -917, -914, -911, -907, -904, -901, -897, -894, -891, -887, -884, -881, -877, -874, -871, -867, -864, -861, -857, -854, -851, -847, -844, -841, -838, -834, -831, -828, -824, -821, -818, -814, -811, -808, -804, -801, -798, -794, -791, -788, -784, -781, -778, -774, -771, -768, -764, -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, -728, -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, -651, -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, -615, -612, -608, -605, -602, -598, -595, -592, -588, -585, -582, -578, -575, -572, -568, -565, -562, -558, -555, -552, -549, -545, -542, -539, -535, -532, -529, -525, -522, -519, -515, -512, -509, -505, -502, -499, -495, -492, -489, -485, -482, -479, -475, -472, -469, -465, -462, -459, -455, -452, -449, -446, -442, -439, -436, -432, -429, -426, -422, -419, -416, -412, -409, -406, -402, -399, -396, -392, -389, -386, -382, -379, -376, -372, -369, -366, -362, -359, -356, -353, -349, -346, -343, -339, -336, -333, -329, -326, -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, -289, -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, -213, -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, -176, -173, -170, -166, -163, -160, -157, -153, -150, -147, -143, -140, -137, -133, -130, -127, -123, -120, -117, -113, -110, -107, -103, -100, -97, -93, -90, -87, -83, -80, -77, -73, -70, -67, -63, -60, -57, -54, -50, -47, -44, -40, -37, -34, -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, 6, 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, 43, 46, 49, 53, 56, 59, 63, 66, 69, 73, 76, 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, 116, 119, 123, 126, 129, 132, 136, 139, 142, 146, 149, 152, 156, 159, 162, 166, 169, 172, 176, 179, 182, 186, 189, 192, 196, 199, 202, 206, 209, 212, 216, 219, 222, 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, 299, 302, 305, 309, 312, 315, 319, 322, 325, 328, 332, 335, 338, 342, 345, 348, 352, 355, 358, 362, 365, 368, 372, 375, 378, 382, 385, 388, 392, 395, 398, 402, 405, 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, 445, 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, 481, 485, 488, 491, 495, 498, 501, 505, 508, 511, 515, 518, 521, 524, 528, 531, 534, 538, 541, 544, 548, 551, 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, 588, 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, 627, 631, 634, 637, 641, 644, 647, 651, 654, 657, 661, 664, 667, 671, 674, 677, 681, 684, 687, 691, 694, 697, 701, 704, 707, 711, 714, 717, 720, 724, 727, 730, 734, 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, 810, 813, 817, 820, 823, 827, 830, 833, 837, 840, 843, 847, 850, 853, 857, 860, 863, 867, 870, 873, 877, 880, 883, 887, 890, 893, 897, 900, 903, 907, 910, 913, 916, 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, 956, 960, 963, 966, 970, 973, 976, 980, 983, 986, 990, 993, 996, 1000, 1003, 1006, 1009, 1013, 1016, 1019, 1023, 1026, 1029, 1033, 1036, 1039, 1043, 1046, 1049, 1053, 1056, 1059, 1063, 1066, 1069, 1073, 1076 }; + +inline +diy_fp_t cached_power(int k) +{ + diy_fp_t res; + int index = 343 + k; + res.f = powers_ten[index]; + res.e = powers_ten_e[index]; + return res; +} + +// double + +/* +typedef union { + double d; + uint64_t n; +} converter_t; + +inline +uint64_t double_to_uint64(double d) { converter_t tmp; tmp.d = d; return tmp.n; } + +inline +double uint64_to_double(uint64_t d64) { converter_t tmp; tmp.n = d64; return tmp.d; } +*/ +inline +uint64_t double_to_uint64(double d) {uint64_t d64; std::memcpy(&d64,&d,sizeof(double)); return d64; } + +inline +double uint64_to_double(uint64_t d64) {double d; std::memcpy(&d,&d64,sizeof(double)); return d; } + +constexpr int dp_significand_size = 52; +constexpr int dp_exponent_bias = (0x3FF + dp_significand_size); +constexpr int dp_min_exponent = (-dp_exponent_bias); +constexpr uint64_t dp_exponent_mask = 0x7FF0000000000000; +constexpr uint64_t dp_significand_mask = 0x000FFFFFFFFFFFFF; +constexpr uint64_t dp_hidden_bit = 0x0010000000000000; + +inline +diy_fp_t normalize_diy_fp(diy_fp_t in) +{ + diy_fp_t res = in; + /* Normalize now */ + /* the original number could have been a denormal. */ + while (!(res.f & dp_hidden_bit)) + { + res.f <<= 1; + res.e--; + } + /* do the final shifts in one go. Don't forget the hidden bit (the '-1') */ + res.f <<= (diy_significand_size - dp_significand_size - 1); + res.e = res.e - (diy_significand_size - dp_significand_size - 1); + return res; +} + +inline +diy_fp_t double2diy_fp(double d) +{ + uint64_t d64 = double_to_uint64(d); + int biased_e = (d64 & dp_exponent_mask) >> dp_significand_size; + uint64_t significand = (d64 & dp_significand_mask); + diy_fp_t res; + if (biased_e != 0) + { + res.f = significand + dp_hidden_bit; + res.e = biased_e - dp_exponent_bias; + } + else + { + res.f = significand; + res.e = dp_min_exponent + 1; + } + return res; +} + +inline +diy_fp_t normalize_boundary(diy_fp_t in) +{ + diy_fp_t res = in; + /* Normalize now */ + /* the original number could have been a denormal. */ + while (!(res.f & (dp_hidden_bit << 1))) + { + res.f <<= 1; + res.e--; + } + /* do the final shifts in one go. Don't forget the hidden bit (the '-1') */ + res.f <<= (diy_significand_size - dp_significand_size - 2); + res.e = res.e - (diy_significand_size - dp_significand_size - 2); + return res; +} + +inline +void normalized_boundaries(double d, diy_fp_t *out_m_minus, diy_fp_t *out_m_plus) +{ + diy_fp_t v = double2diy_fp(d); + diy_fp_t pl, mi; + bool significand_is_zero = v.f == dp_hidden_bit; + pl.f = (v.f << 1) + 1; pl.e = v.e - 1; + pl = normalize_boundary(pl); + if (significand_is_zero) + { + mi.f = (v.f << 2) - 1; + mi.e = v.e - 2; + } else + { + mi.f = (v.f << 1) - 1; + mi.e = v.e - 1; + } + int x = mi.e - pl.e; + mi.f <<= x; + mi.e = pl.e; + *out_m_plus = pl; + *out_m_minus = mi; +} + +inline +double random_double() +{ + uint64_t tmp = 0; + int i; + for (i = 0; i < 8; i++) + { + tmp <<= 8; + tmp += rand() % 256; + } + return uint64_to_double(tmp); +} + +// grisu3 + +inline +bool round_weed(char *buffer, int len, + uint64_t wp_W, uint64_t Delta, + uint64_t rest, uint64_t ten_kappa, + uint64_t ulp) +{ + uint64_t wp_Wup = wp_W - ulp; + uint64_t wp_Wdown = wp_W + ulp; + while (rest < wp_Wup && /// round1 + Delta - rest >= ten_kappa && + (rest + ten_kappa < wp_Wup || /// closer + wp_Wup - rest >= rest + ten_kappa - wp_Wup)) + { + buffer[len - 1]--; rest += ten_kappa; + } + if (rest < wp_Wdown && /// round2 + Delta - rest >= ten_kappa && + (rest + ten_kappa < wp_Wdown || + wp_Wdown - rest > rest + ten_kappa - wp_Wdown)) return 0; + return 2 * ulp <= rest && rest <= Delta - 4 * ulp; /// weed +} + +inline +bool digit_gen(diy_fp_t Wm, diy_fp_t W, diy_fp_t Wp, + char *buffer, int *len, int *K) +{ + const uint32_t TEN2 = 100; + + uint32_t div, p1; uint64_t p2, tmp, unit = 1; + int d, kappa; + diy_fp_t one, wp_W, Delta; + Delta = minus(Wp, Wm); Delta.f += 2 * unit; + wp_W = minus(Wp, W); wp_W.f += unit; + one.f = ((uint64_t)1) << -Wp.e; one.e = Wp.e; + p1 = static_cast((Wp.f + 1) >> -one.e); + p2 = (Wp.f + 1) & (one.f - 1); + *len = 0; kappa = 3; div = TEN2; + while (kappa > 0) + { + d = p1 / div; + if (d || *len) buffer[(*len)++] = (char)('0' + d); + p1 %= div; kappa--; + tmp = (((uint64_t)p1) << -one.e) + p2; + if (tmp < Delta.f) + { + *K += kappa; + return round_weed(buffer, *len, wp_W.f, Delta.f, tmp, + ((uint64_t)div) << -one.e, unit); + } + div /= 10; + } + while (1) + { + p2 *= 10; Delta.f *= 10; unit *= 10; + d = static_cast(p2 >> -one.e); + if (d || *len) buffer[(*len)++] = (char)('0' + d); + p2 &= one.f - 1; kappa--; + if (p2 < Delta.f) + { + *K += kappa; + return round_weed(buffer, *len, wp_W.f * unit, Delta.f, p2, + one.f, unit); + } + } +} + +inline +bool grisu3(double v, char *buffer, int *length, int *K) +{ + diy_fp_t w_m, w_p; + int q = 64, alpha = -59, gamma = -56; + normalized_boundaries(v, &w_m, &w_p); + diy_fp_t w = normalize_diy_fp(double2diy_fp(v)); + int mk = k_comp(w_p.e + q, alpha, gamma); + diy_fp_t c_mk = cached_power(mk); + diy_fp_t W = multiply(w, c_mk); + diy_fp_t Wp = multiply(w_p, c_mk); + diy_fp_t Wm = multiply(w_m, c_mk); + *K = -mk; + bool result = digit_gen(Wm, W, Wp, buffer, length, K); + buffer[*length] = 0; + return result; +} + +}} // namespace detail namespace jsoncons + +#endif diff --git a/include/jsoncons/detail/optional.hpp b/include/jsoncons/detail/optional.hpp new file mode 100644 index 0000000..492cd76 --- /dev/null +++ b/include/jsoncons/detail/optional.hpp @@ -0,0 +1,483 @@ +// Copyright 2019 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_OPTIONAL_HPP +#define JSONCONS_DETAIL_OPTIONAL_HPP + +#include // placement new +#include +#include // std::swap +#include +#include + +namespace jsoncons +{ +namespace detail +{ + template + class optional; + + template + struct is_constructible_or_convertible_from_optional + : std::integral_constant< + bool, std::is_constructible&>::value || + std::is_constructible&&>::value || + std::is_constructible&>::value || + std::is_constructible&&>::value || + std::is_convertible&, T1>::value || + std::is_convertible&&, T1>::value || + std::is_convertible&, T1>::value || + std::is_convertible&&, T1>::value> {}; + + template + struct is_constructible_convertible_or_assignable_from_optional + : std::integral_constant< + bool, is_constructible_or_convertible_from_optional::value || + std::is_assignable&>::value || + std::is_assignable&&>::value || + std::is_assignable&>::value || + std::is_assignable&&>::value> {}; + + template + class optional + { + public: + using value_type = T; + private: + bool has_value_; + union { + char dummy_; + T value_; + }; + public: + constexpr optional() noexcept + : has_value_(false), dummy_{} + { + } + + // copy constructors + optional(const optional& other) + : has_value_(false), dummy_{} + { + if (other) + { + construct(*other); + } + } + + // converting + template ::value && + std::is_constructible::value && + std::is_convertible::value && + !is_constructible_or_convertible_from_optional::value && + std::is_copy_constructible::type>::value,int>::type = 0> + optional(const optional& other) + : has_value_(false), dummy_{} + { + if (other) + { + construct(*other); + } + } + + template ::value && + std::is_constructible::value && + !std::is_convertible::value && + !is_constructible_or_convertible_from_optional::value && + std::is_copy_constructible::type>::value,int>::type = 0> + explicit optional(const optional& other) + : has_value_(false), dummy_{} + { + if (other) + { + construct(*other); + } + } + + // move constructors + template + optional(optional&& other, + typename std::enable_if::type>::value>::type* = 0) + : has_value_(false), dummy_{} + { + if (other) + { + construct(std::move(other.value_)); + } + } + + // converting + template + optional(optional&& value, + typename std::enable_if::value && + std::is_constructible::value && + !is_constructible_or_convertible_from_optional::value && + std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + template + explicit optional(optional&& value, + typename std::enable_if::value && + std::is_constructible::value && + !is_constructible_or_convertible_from_optional::value && + !std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + + // value constructors + template + optional(T2&& value, + typename std::enable_if,typename std::decay::type>::value && + std::is_constructible::value && + std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + template + explicit optional(T2&& value, + typename std::enable_if,typename std::decay::type>::value && + std::is_constructible::value && + !std::is_convertible::value,int>::type = 0) // (8) + : has_value_(true), value_(std::forward(value)) + { + } + + ~optional() noexcept + { + destroy(); + } + + optional& operator=(const optional& other) + { + if (other) + { + assign(*other); + } + else + { + reset(); + } + return *this; + } + + optional& operator=(optional&& other ) + { + if (other) + { + assign(std::move(*other)); + } + else + { + reset(); + } + return *this; + } + + template + typename std::enable_if, U>::value && + std::is_constructible::value && + !is_constructible_convertible_or_assignable_from_optional::value && + std::is_assignable::value, + optional&>::type + operator=(const optional& other) + { + if (other) + { + assign(*other); + } + else + { + destroy(); + } + return *this; + } + + template + typename std::enable_if, U>::value && + std::is_constructible::value && + !is_constructible_convertible_or_assignable_from_optional::value && + std::is_assignable::value, + optional&>::type + operator=(optional&& other) + { + if (other) + { + assign(std::move(*other)); + } + else + { + destroy(); + } + return *this; + } + + // value assignment + template + typename std::enable_if, typename std::decay::type>::value && + std::is_constructible::value && + std::is_assignable::value && + !(std::is_scalar::value && std::is_same::type>::value), + optional&>::type + operator=(T2&& v) + { + assign(std::forward(v)); + return *this; + } + + constexpr explicit operator bool() const noexcept + { + return has_value_; + } + constexpr bool has_value() const noexcept + { + return has_value_; + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4702) +#endif // _MSC_VER + + T& value() & + { + return static_cast(*this) + ? get() + : JSONCONS_THROW(std::runtime_error("Bad optional access")), get(); + } + + constexpr const T& value() const & + { + return static_cast(*this) + ? get() + : JSONCONS_THROW(std::runtime_error("Bad optional access")), get(); + } + + template + constexpr T value_or(U&& default_value) const & + { + static_assert(std::is_copy_constructible::value, + "get_value_or: T must be copy constructible"); + static_assert(std::is_convertible::value, + "get_value_or: U must be convertible to T"); + return static_cast(*this) + ? **this + : static_cast(std::forward(default_value)); + } + + template + T value_or(U&& default_value) && + { + static_assert(std::is_move_constructible::value, + "get_value_or: T must be move constructible"); + static_assert(std::is_convertible::value, + "get_value_or: U must be convertible to T"); + return static_cast(*this) ? std::move(**this) + : static_cast(std::forward(default_value)); + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + + const T* operator->() const + { + return std::addressof(this->value_); + } + + T* operator->() + { + return std::addressof(this->value_); + } + + constexpr const T& operator*() const& + { + return value(); + } + + T& operator*() & + { + return value(); + } + + void reset() noexcept + { + destroy(); + } + + void swap(optional& other) noexcept(std::is_nothrow_move_constructible::value /*&& + std::is_nothrow_swappable::value*/) + { + const bool contains_a_value = has_value(); + if (contains_a_value == other.has_value()) + { + if (contains_a_value) + { + using std::swap; + swap(**this, *other); + } + } + else + { + optional& source = contains_a_value ? *this : other; + optional& target = contains_a_value ? other : *this; + target = optional(*source); + source.reset(); + } + } + private: + constexpr const T& get() const { return this->value_; } + T& get() { return this->value_; } + + template + void construct(Args&&... args) + { + ::new (static_cast(&this->value_)) T(std::forward(args)...); + has_value_ = true; + } + + void destroy() noexcept + { + if (has_value_) + { + value_.~T(); + has_value_ = false; + } + } + + template + void assign(U&& u) + { + if (has_value_) + { + value_ = std::forward(u); + } + else + { + construct(std::forward(u)); + } + } + }; + + template + typename std::enable_if::value,void>::type + swap(optional& lhs, optional& rhs) noexcept + { + lhs.swap(rhs); + } + + template + constexpr bool operator==(const optional& lhs, const optional& rhs) noexcept + { + return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs); + } + + template + constexpr bool operator!=(const optional& lhs, const optional& rhs) noexcept + { + return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs); + } + + template + constexpr bool operator<(const optional& lhs, const optional& rhs) noexcept + { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); + } + + template + constexpr bool operator>(const optional& lhs, const optional& rhs) noexcept + { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); + } + + template + constexpr bool operator<=(const optional& lhs, const optional& rhs) noexcept + { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); + } + + template + constexpr bool operator>=(const optional& lhs, const optional& rhs) noexcept + { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); + } + + template + constexpr bool operator==(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs == rhs : false; + } + template + constexpr bool operator==(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs == *rhs : false; + } + + template + constexpr bool operator!=(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs != rhs : true; + } + template + constexpr bool operator!=(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs != *rhs : true; + } + + template + constexpr bool operator<(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs < rhs : true; + } + template + constexpr bool operator<(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs < *rhs : false; + } + + template + constexpr bool operator<=(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs <= rhs : true; + } + template + constexpr bool operator<=(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs <= *rhs : false; + } + + template + constexpr bool operator>(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs > rhs : false; + } + + template + constexpr bool operator>(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs > *rhs : true; + } + + template + constexpr bool operator>=(const optional& lhs, const T2& rhs) noexcept + { + return lhs ? *lhs >= rhs : false; + } + template + constexpr bool operator>=(const T1& lhs, const optional& rhs) noexcept + { + return rhs ? lhs >= *rhs : true; + } + +} // namespace detail +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/detail/parse_number.hpp b/include/jsoncons/detail/parse_number.hpp new file mode 100644 index 0000000..7417ff2 --- /dev/null +++ b/include/jsoncons/detail/parse_number.hpp @@ -0,0 +1,1133 @@ +// 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_PARSE_NUMBER_HPP +#define JSONCONS_DETAIL_PARSE_NUMBER_HPP + +#include +#include +#include +#include +#include +#include +#include // std::numeric_limits +#include // std::enable_if +#include +#include +#include +#include + +namespace jsoncons { namespace detail { + + enum class to_integer_errc : uint8_t {success=0, overflow, invalid_digit, invalid_number}; + + class to_integer_error_category_impl + : public std::error_category + { + public: + const char* name() const noexcept override + { + return "jsoncons/to_integer_unchecked"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case to_integer_errc::overflow: + return "Integer overflow"; + case to_integer_errc::invalid_digit: + return "Invalid digit"; + case to_integer_errc::invalid_number: + return "Invalid number"; + default: + return "Unknown to_integer_unchecked error"; + } + } + }; + + inline + const std::error_category& to_integer_error_category() + { + static to_integer_error_category_impl instance; + return instance; + } + + inline + std::error_code make_error_code(to_integer_errc e) + { + return std::error_code(static_cast(e),to_integer_error_category()); + } + +} // namespace detail +} // namespace jsoncons + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +namespace jsoncons { namespace detail { + +template +struct to_integer_result +{ + const CharT* ptr; + to_integer_errc ec; + constexpr to_integer_result(const CharT* ptr_) + : ptr(ptr_), ec(to_integer_errc()) + { + } + constexpr to_integer_result(const CharT* ptr_, to_integer_errc ec_) + : ptr(ptr_), ec(ec_) + { + } + + to_integer_result(const to_integer_result&) = default; + + to_integer_result& operator=(const to_integer_result&) = default; + + constexpr explicit operator bool() const noexcept + { + return ec == to_integer_errc(); + } + std::error_code error_code() const + { + return make_error_code(ec); + } +}; + +enum class integer_chars_format : uint8_t {decimal=1,hex}; +enum class integer_chars_state {initial,minus,integer,binary,octal,decimal,base16}; + +template +bool is_base10(const CharT* s, std::size_t length) +{ + integer_chars_state state = integer_chars_state::initial; + + const CharT* end = s + length; + for (;s < end; ++s) + { + switch(state) + { + case integer_chars_state::initial: + { + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + state = integer_chars_state::decimal; + break; + case '-': + state = integer_chars_state::minus; + break; + default: + return false; + } + break; + } + case integer_chars_state::minus: + { + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + state = integer_chars_state::decimal; + break; + default: + return false; + } + break; + } + case integer_chars_state::decimal: + { + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + break; + default: + return false; + } + break; + } + default: + break; + } + } + return state == integer_chars_state::decimal ? true : false; +} + +template +typename std::enable_if::is_specialized && !type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer_decimal(const CharT* s, std::size_t length, T& n) +{ + n = 0; + + integer_chars_state state = integer_chars_state::initial; + + const CharT* end = s + length; + while (s < end) + { + switch(state) + { + case integer_chars_state::initial: + { + switch(*s) + { + case '0': + if (++s == end) + { + return (++s == end) ? to_integer_result(s) : to_integer_result(s, to_integer_errc()); + } + else + { + return to_integer_result(s, to_integer_errc::invalid_digit); + } + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': // Must be decimal + state = integer_chars_state::decimal; + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + break; + } + case integer_chars_state::decimal: + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + T x = 0; + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = static_cast(*s) - static_cast('0'); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_10) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 10; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n += x; + } + break; + } + default: + JSONCONS_UNREACHABLE(); + break; + } + } + return (state == integer_chars_state::initial) ? to_integer_result(s, to_integer_errc::invalid_number) : to_integer_result(s, to_integer_errc()); +} + +template +typename std::enable_if::is_specialized && type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer_decimal(const CharT* s, std::size_t length, T& n) +{ + n = 0; + + if (length == 0) + { + return to_integer_result(s, to_integer_errc::invalid_number); + } + + bool is_negative = *s == '-' ? true : false; + if (is_negative) + { + ++s; + --length; + } + + using U = typename type_traits::make_unsigned::type; + + U u; + auto ru = to_integer_decimal(s, length, u); + if (ru.ec != to_integer_errc()) + { + return to_integer_result(ru.ptr, ru.ec); + } + if (is_negative) + { + if (u > static_cast(-((type_traits::integer_limits::lowest)()+T(1))) + U(1)) + { + return to_integer_result(ru.ptr, to_integer_errc::overflow); + } + else + { + n = static_cast(U(0) - u); + return to_integer_result(ru.ptr, to_integer_errc()); + } + } + else + { + if (u > static_cast((type_traits::integer_limits::max)())) + { + return to_integer_result(ru.ptr, to_integer_errc::overflow); + } + else + { + n = static_cast(u); + return to_integer_result(ru.ptr, to_integer_errc()); + } + } +} + +template +typename std::enable_if::is_specialized && !type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer_base16(const CharT* s, std::size_t length, T& n) +{ + n = 0; + + integer_chars_state state = integer_chars_state::initial; + + const CharT* end = s + length; + while (s < end) + { + switch(state) + { + case integer_chars_state::initial: + { + switch(*s) + { + case '0': + if (++s == end) + { + return (++s == end) ? to_integer_result(s) : to_integer_result(s, to_integer_errc()); + } + else + { + return to_integer_result(s, to_integer_errc::invalid_digit); + } + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': // Must be base16 + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + state = integer_chars_state::base16; + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + break; + } + case integer_chars_state::base16: + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_16 = max_value / 16; + for (; s < end; ++s) + { + CharT c = *s; + T x = 0; + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_16) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 16; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n += x; + } + break; + } + default: + JSONCONS_UNREACHABLE(); + break; + } + } + return (state == integer_chars_state::initial) ? to_integer_result(s, to_integer_errc::invalid_number) : to_integer_result(s, to_integer_errc()); +} + +template +typename std::enable_if::is_specialized && type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer_base16(const CharT* s, std::size_t length, T& n) +{ + n = 0; + + if (length == 0) + { + return to_integer_result(s, to_integer_errc::invalid_number); + } + + bool is_negative = *s == '-' ? true : false; + if (is_negative) + { + ++s; + --length; + } + + using U = typename type_traits::make_unsigned::type; + + U u; + auto ru = to_integer_base16(s, length, u); + if (ru.ec != to_integer_errc()) + { + return to_integer_result(ru.ptr, ru.ec); + } + if (is_negative) + { + if (u > static_cast(-((type_traits::integer_limits::lowest)()+T(1))) + U(1)) + { + return to_integer_result(ru.ptr, to_integer_errc::overflow); + } + else + { + n = static_cast(U(0) - u); + return to_integer_result(ru.ptr, to_integer_errc()); + } + } + else + { + if (u > static_cast((type_traits::integer_limits::max)())) + { + return to_integer_result(ru.ptr, to_integer_errc::overflow); + } + else + { + n = static_cast(u); + return to_integer_result(ru.ptr, to_integer_errc()); + } + } +} + +template +typename std::enable_if::is_specialized && !type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer(const CharT* s, std::size_t length, T& n) +{ + n = 0; + + integer_chars_state state = integer_chars_state::initial; + + const CharT* end = s + length; + while (s < end) + { + switch(state) + { + case integer_chars_state::initial: + { + switch(*s) + { + case '0': + state = integer_chars_state::integer; // Could be binary, octal, hex + ++s; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': // Must be decimal + state = integer_chars_state::decimal; + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + break; + } + case integer_chars_state::integer: + { + switch(*s) + { + case 'b':case 'B': + { + state = integer_chars_state::binary; + ++s; + break; + } + case 'x':case 'X': + { + state = integer_chars_state::base16; + ++s; + break; + } + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + { + state = integer_chars_state::octal; + break; + } + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + break; + } + case integer_chars_state::binary: + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_2 = max_value / 2; + for (; s < end; ++s) + { + T x = 0; + switch(*s) + { + case '0':case '1': + x = static_cast(*s) - static_cast('0'); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_2) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 2; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n += x; + } + break; + } + case integer_chars_state::octal: + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_8 = max_value / 8; + for (; s < end; ++s) + { + T x = 0; + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7': + x = static_cast(*s) - static_cast('0'); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_8) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 8; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n += x; + } + break; + } + case integer_chars_state::decimal: + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + T x = 0; + switch(*s) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = static_cast(*s) - static_cast('0'); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_10) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 10; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n += x; + } + break; + } + case integer_chars_state::base16: + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_16 = max_value / 16; + for (; s < end; ++s) + { + CharT c = *s; + T x = 0; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_16) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 16; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n += x; + } + break; + } + default: + JSONCONS_UNREACHABLE(); + break; + } + } + return (state == integer_chars_state::initial) ? to_integer_result(s, to_integer_errc::invalid_number) : to_integer_result(s, to_integer_errc()); +} + +template +typename std::enable_if::is_specialized && type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer(const CharT* s, std::size_t length, T& n) +{ + n = 0; + + if (length == 0) + { + return to_integer_result(s, to_integer_errc::invalid_number); + } + + bool is_negative = *s == '-' ? true : false; + if (is_negative) + { + ++s; + --length; + } + + using U = typename type_traits::make_unsigned::type; + + U u; + auto ru = to_integer(s, length, u); + if (ru.ec != to_integer_errc()) + { + return to_integer_result(ru.ptr, ru.ec); + } + if (is_negative) + { + if (u > static_cast(-((type_traits::integer_limits::lowest)()+T(1))) + U(1)) + { + return to_integer_result(ru.ptr, to_integer_errc::overflow); + } + else + { + n = static_cast(U(0) - u); + return to_integer_result(ru.ptr, to_integer_errc()); + } + } + else + { + if (u > static_cast((type_traits::integer_limits::max)())) + { + return to_integer_result(ru.ptr, to_integer_errc::overflow); + } + else + { + n = static_cast(u); + return to_integer_result(ru.ptr, to_integer_errc()); + } + } +} + +template +typename std::enable_if::is_specialized,to_integer_result>::type +to_integer(const CharT* s, T& n) +{ + return to_integer(s, std::char_traits::length(s), n); +} + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template +typename std::enable_if::is_specialized && !type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer_unchecked(const CharT* s, std::size_t length, T& n) +{ + static_assert(type_traits::integer_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + n = 0; + const CharT* end = s + length; + if (*s == '-') + { + static constexpr T min_value = (type_traits::integer_limits::lowest)(); + static constexpr T min_value_div_10 = min_value / 10; + ++s; + for (; s < end; ++s) + { + T x = (T)*s - (T)('0'); + if (n < min_value_div_10) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 10; + if (n < min_value + x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n -= x; + } + } + else + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + T x = static_cast(*s) - static_cast('0'); + if (n > max_value_div_10) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 10; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n += x; + } + } + + return to_integer_result(s, to_integer_errc()); +} + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template +typename std::enable_if::is_specialized && type_traits::integer_limits::is_signed,to_integer_result>::type +to_integer_unchecked(const CharT* s, std::size_t length, T& n) +{ + static_assert(type_traits::integer_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + n = 0; + + const CharT* end = s + length; + if (*s == '-') + { + static constexpr T min_value = (type_traits::integer_limits::lowest)(); + static constexpr T min_value_div_10 = min_value / 10; + ++s; + for (; s < end; ++s) + { + T x = (T)*s - (T)('0'); + if (n < min_value_div_10) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 10; + if (n < min_value + x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n -= x; + } + } + else + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + T x = static_cast(*s) - static_cast('0'); + if (n > max_value_div_10) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 10; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n += x; + } + } + + return to_integer_result(s, to_integer_errc()); +} + +// base16_to_integer + +template +typename std::enable_if::is_specialized && type_traits::integer_limits::is_signed,to_integer_result>::type +base16_to_integer(const CharT* s, std::size_t length, T& n) +{ + static_assert(type_traits::integer_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + n = 0; + + const CharT* end = s + length; + if (*s == '-') + { + static constexpr T min_value = (type_traits::integer_limits::lowest)(); + static constexpr T min_value_div_16 = min_value / 16; + ++s; + for (; s < end; ++s) + { + CharT c = *s; + T x = 0; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n < min_value_div_16) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 16; + if (n < min_value + x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n -= x; + } + } + else + { + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_16 = max_value / 16; + for (; s < end; ++s) + { + CharT c = *s; + T x = 0; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_16) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 16; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n += x; + } + } + + return to_integer_result(s, to_integer_errc()); +} + +template +typename std::enable_if::is_specialized && !type_traits::integer_limits::is_signed,to_integer_result>::type +base16_to_integer(const CharT* s, std::size_t length, T& n) +{ + static_assert(type_traits::integer_limits::is_specialized, "Integer type not specialized"); + JSONCONS_ASSERT(length > 0); + + n = 0; + const CharT* end = s + length; + + static constexpr T max_value = (type_traits::integer_limits::max)(); + static constexpr T max_value_div_16 = max_value / 16; + for (; s < end; ++s) + { + CharT c = *s; + T x = *s; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + x = c - '0'; + break; + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + x = c - ('a' - 10); + break; + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + x = c - ('A' - 10); + break; + default: + return to_integer_result(s, to_integer_errc::invalid_digit); + } + if (n > max_value_div_16) + { + return to_integer_result(s, to_integer_errc::overflow); + } + n = n * 16; + if (n > max_value - x) + { + return to_integer_result(s, to_integer_errc::overflow); + } + + n += x; + } + + return to_integer_result(s, to_integer_errc()); +} + + +#if defined(JSONCONS_HAS_STD_FROM_CHARS) + +class chars_to +{ +public: + + char get_decimal_point() const + { + return '.'; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t len) const + { + double val = 0; + const auto res = std::from_chars(s, s+len, val); + if (res.ec != std::errc()) + { + JSONCONS_THROW(json_runtime_error("Convert chars to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t len) const + { + std::string input(len,'0'); + for (size_t i = 0; i < len; ++i) + { + input[i] = static_cast(s[i]); + } + + double val = 0; + const auto res = std::from_chars(input.data(), input.data() + len, val); + if (res.ec != std::errc()) + { + JSONCONS_THROW(json_runtime_error("Convert chars to double failed")); + } + return val; + } +}; +#elif defined(JSONCONS_HAS_MSC_STRTOD_L) + +class chars_to +{ +private: + _locale_t locale_; +public: + chars_to() + { + locale_ = _create_locale(LC_NUMERIC, "C"); + } + ~chars_to() noexcept + { + _free_locale(locale_); + } + + chars_to(const chars_to&) + { + locale_ = _create_locale(LC_NUMERIC, "C"); + } + + chars_to& operator=(const chars_to&) + { + // Don't assign locale + return *this; + } + + char get_decimal_point() const + { + return '.'; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t) const + { + CharT *end = nullptr; + double val = _strtod_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t) const + { + CharT *end = nullptr; + double val = _wcstod_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } +}; + +#elif defined(JSONCONS_HAS_STRTOLD_L) + +class chars_to +{ +private: + locale_t locale_; +public: + chars_to() + { + locale_ = newlocale(LC_ALL_MASK, "C", (locale_t) 0); + } + ~chars_to() noexcept + { + freelocale(locale_); + } + + chars_to(const chars_to&) + { + locale_ = newlocale(LC_ALL_MASK, "C", (locale_t) 0); + } + + chars_to& operator=(const chars_to&) + { + return *this; + } + + char get_decimal_point() const + { + return '.'; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t) const + { + char *end = nullptr; + double val = strtold_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t) const + { + CharT *end = nullptr; + double val = wcstold_l(s, &end, locale_); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } +}; + +#else +class chars_to +{ +private: + std::vector buffer_; + char decimal_point_; +public: + chars_to() + : 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); + } + + chars_to(const chars_to&) = default; + chars_to& operator=(const chars_to&) = default; + + char get_decimal_point() const + { + return decimal_point_; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t /*length*/) const + { + CharT *end = nullptr; + double val = strtod(s, &end); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } + + template + typename std::enable_if::value,double>::type + operator()(const CharT* s, std::size_t /*length*/) const + { + CharT *end = nullptr; + double val = wcstod(s, &end); + if (s == end) + { + JSONCONS_THROW(json_runtime_error("Convert string to double failed")); + } + return val; + } +}; +#endif + +}} + +#endif diff --git a/include/jsoncons/detail/span.hpp b/include/jsoncons/detail/span.hpp new file mode 100644 index 0000000..02c24ee --- /dev/null +++ b/include/jsoncons/detail/span.hpp @@ -0,0 +1,188 @@ +#ifndef JSONCONS_DETAIL_SPAN_HPP +#define JSONCONS_DETAIL_SPAN_HPP + +#include // std::swap +#include // std::addressof +#include // std::enable_if, std::true_type, std::false_type +#include +#include +#include +#include + +namespace jsoncons +{ +namespace detail +{ + constexpr std::size_t dynamic_extent = (std::numeric_limits::max)(); + + template< class T, std::size_t Extent = dynamic_extent> + class span; + + template + struct is_span : std::false_type{}; + + template< class T> + struct is_span> : std::true_type{}; + + template< + class T, + std::size_t Extent + > class span + { + public: + using element_type = T; + using value_type = typename std::remove_volatile::type>::type; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + private: + pointer data_; + size_type size_; + public: + static constexpr std::size_t extent = Extent; + + constexpr span() noexcept + : data_(nullptr), size_(0) + { + } + constexpr span(pointer data, size_type size) + : data_(data), size_(size) + { + } + + template + constexpr span(C& c, + typename std::enable_if::value && !type_traits::is_std_array::value && type_traits::is_compatible_element::value && type_traits::has_data_and_size::value>::type* = 0) + : data_(c.data()), size_(c.size()) + { + } + + template + span(element_type (&arr)[N]) noexcept + : data_(std::addressof(arr[0])), size_(N) + { + } + + template + span(std::array& arr, + typename std::enable_if<(extent == dynamic_extent || extent == N)>::type* = 0) noexcept + : data_(arr.data()), size_(arr.size()) + { + } + + template + span(const std::array& arr, + typename std::enable_if<(extent == dynamic_extent || extent == N)>::type* = 0) noexcept + : data_(arr.data()), size_(arr.size()) + { + } + + template + constexpr span(const C& c, + typename std::enable_if::value && !type_traits::is_std_array::value && type_traits::is_compatible_element::value && type_traits::has_data_and_size::value>::type* = 0) + : data_(c.data()), size_(c.size()) + { + } + + template + constexpr span(const span& s, + typename std::enable_if<(N == dynamic_extent || N == extent) && std::is_convertible::value>::type* = 0) noexcept + : data_(s.data()), size_(s.size()) + { + } + + constexpr span(const span& other) noexcept = default; + + span& operator=( const span& other ) noexcept = default; + + constexpr pointer data() const noexcept + { + return data_; + } + + constexpr size_type size() const noexcept + { + return size_; + } + + constexpr bool empty() const noexcept + { + return size_ == 0; + } + + constexpr reference operator[](size_type index) const + { + return data_[index]; + } + + // iterator support + const_iterator begin() const noexcept + { + return data_; + } + const_iterator end() const noexcept + { + return data_ + size_; + } + const_iterator cbegin() const noexcept + { + return data_; + } + const_iterator cend() const noexcept + { + return data_ + size_; + } + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(begin()); + } + + span + first(std::size_t count) const + { + JSONCONS_ASSERT(count <= size()); + + return span< element_type, dynamic_extent >( data(), count ); + } + + span + last(std::size_t count) const + { + JSONCONS_ASSERT(count <= size()); + + return span(data() + ( size() - count ), count); + } + + span + subspan(std::size_t offset, std::size_t count = dynamic_extent) const + { + //JSONCONS_ASSERT((offset <= size() && (count == dynamic_extent || (offset + count <= size())))); + + return span( + data() + offset, count == dynamic_extent ? size() - offset : count ); + } + }; + +} // namespace detail +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/detail/string_view.hpp b/include/jsoncons/detail/string_view.hpp new file mode 100644 index 0000000..fc568a1 --- /dev/null +++ b/include/jsoncons/detail/string_view.hpp @@ -0,0 +1,537 @@ +// Copyright 2019 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_STRING_VIEW_HPP +#define JSONCONS_STRING_VIEW_HPP + +#include +#include +#include +#include +#include +#include // std::find, std::min, std::reverse +#include +#include +#include +#include +#include // std::basic_istream +#include + +namespace jsoncons { +namespace detail { + + template > + class basic_string_view + { + private: + const CharT* data_; + std::size_t length_; + public: + using value_type = CharT; + using const_reference = const CharT&; + using traits_type = Traits; + using size_type = std::size_t; + static constexpr size_type npos = size_type(-1); + using const_iterator = const CharT*; + using iterator = const CharT*; + using const_reverse_iterator = std::reverse_iterator; + + constexpr basic_string_view() noexcept + : data_(nullptr), length_(0) + { + } + constexpr basic_string_view(const CharT* data, std::size_t length) + : data_(data), length_(length) + { + } + + basic_string_view(const CharT* data) + : data_(data), length_(Traits::length(data)) + { + } + constexpr basic_string_view(const basic_string_view& other) noexcept = default; + + template + JSONCONS_CPP14_CONSTEXPR basic_string_view(const std::basic_string& s) noexcept + : data_(s.data()), length_(s.length()) + { + } + + JSONCONS_CPP14_CONSTEXPR basic_string_view& operator=( const basic_string_view& view ) noexcept + { + data_ = view.data(); + length_ = view.length(); + + return *this; + } + + template + explicit operator std::basic_string() const + { + return std::basic_string(data_,length_); + } + + // iterator support + const_iterator begin() const noexcept + { + return data_; + } + const_iterator end() const noexcept + { + return data_ + length_; + } + const_iterator cbegin() const noexcept + { + return data_; + } + const_iterator cend() const noexcept + { + return data_ + length_; + } + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(begin()); + } + + // capacity + + std::size_t size() const + { + return length_; + } + + std::size_t length() const + { + return length_; + } + size_type max_size() const noexcept + { + return length_; + } + bool empty() const noexcept + { + return length_ == 0; + } + + // element access + + const_reference operator[](size_type pos) const + { + return data_[pos]; + } + + const_reference at(std::size_t pos) const + { + if (pos >= length_) + { + JSONCONS_THROW(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(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(const basic_string_view& s) const noexcept + { + 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 noexcept + { + 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 + int compare(const std::basic_string& s) const noexcept + { + 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 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 noexcept + { + return find(basic_string_view(&ch, 1), pos); + } + size_type find(const CharT* s, size_type pos, size_type n) const noexcept + { + return find(basic_string_view(s, n), pos); + } + size_type find(const CharT* s, size_type pos = 0) const noexcept + { + return find(basic_string_view(s), pos); + } + + size_type rfind(basic_string_view s, size_type pos = npos) const 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 noexcept + { + return rfind(basic_string_view(&ch, 1), pos); + } + size_type rfind(const CharT* s, size_type pos, size_type n) const noexcept + { + return rfind(basic_string_view(s, n), pos); + } + size_type rfind(const CharT* s, size_type pos = npos) const noexcept + { + return rfind(basic_string_view(s), pos); + } + + size_type find_first_of(basic_string_view s, size_type pos = 0) const 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 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 noexcept + { + return find_first_of(basic_string_view(s, n), pos); + } + size_type find_first_of(const CharT* s, size_type pos = 0) const noexcept + { + return find_first_of(basic_string_view(s), pos); + } + + size_type find_last_of(basic_string_view s, size_type pos = npos) const 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 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 noexcept + { + return find_last_of(basic_string_view(s, n), pos); + } + size_type find_last_of(const CharT* s, size_type pos = npos) const 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 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 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 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 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 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 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 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 noexcept + { + return find_last_not_of(basic_string_view(s), pos); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_string_view& sv) + { + os.write(sv.data_,sv.length_); + return os; + } + }; + + // == + template + bool operator==(const basic_string_view& lhs, + const basic_string_view& rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + template + bool operator==(const basic_string_view& lhs, + const std::basic_string& rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + template + bool operator==(const std::basic_string& lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) == 0; + } + template + bool operator==(const basic_string_view& lhs, + const CharT* rhs) noexcept + { + return lhs.compare(rhs) == 0; + } + template + bool operator==(const CharT* lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) == 0; + } + + // != + template + bool operator!=(const basic_string_view& lhs, + const basic_string_view& rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + template + bool operator!=(const basic_string_view& lhs, + const std::basic_string& rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + template + bool operator!=(const std::basic_string& lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) != 0; + } + template + bool operator!=(const basic_string_view& lhs, + const CharT* rhs) noexcept + { + return lhs.compare(rhs) != 0; + } + template + bool operator!=(const CharT* lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) != 0; + } + + // <= + template + bool operator<=(const basic_string_view& lhs, + const basic_string_view& rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + template + bool operator<=(const basic_string_view& lhs, + const std::basic_string& rhs) noexcept + { + return lhs.compare(rhs) <= 0; + } + template + bool operator<=(const std::basic_string& lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) >= 0; + } + + // < + template + bool operator<(const basic_string_view& lhs, + const basic_string_view& rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + template + bool operator<(const basic_string_view& lhs, + const std::basic_string& rhs) noexcept + { + return lhs.compare(rhs) < 0; + } + template + bool operator<(const std::basic_string& lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) > 0; + } + + // >= + template + bool operator>=(const basic_string_view& lhs, + const basic_string_view& rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + template + bool operator>=(const basic_string_view& lhs, + const std::basic_string& rhs) noexcept + { + return lhs.compare(rhs) >= 0; + } + template + bool operator>=(const std::basic_string& lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) <= 0; + } + + // > + template + bool operator>(const basic_string_view& lhs, + const basic_string_view& rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + template + bool operator>(const basic_string_view& lhs, + const std::basic_string& rhs) noexcept + { + return lhs.compare(rhs) > 0; + } + template + bool operator>(const std::basic_string& lhs, + const basic_string_view& rhs) noexcept + { + return rhs.compare(lhs) < 0; + } + +} // namespace detail +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/detail/string_wrapper.hpp b/include/jsoncons/detail/string_wrapper.hpp new file mode 100644 index 0000000..88634b0 --- /dev/null +++ b/include/jsoncons/detail/string_wrapper.hpp @@ -0,0 +1,370 @@ +// 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_STRING_WRAPPER_HPP +#define JSONCONS_DETAIL_STRING_WRAPPER_HPP + +#include +#include +#include +#include +#include // std::memcpy +#include // std::allocator +#include + +namespace jsoncons { +namespace detail { + + // From boost 1_71 + template + T launder_cast(U* u) + { + #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 + return std::launder(reinterpret_cast(u)); + #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 800 + return __builtin_launder(reinterpret_cast(u)); + #else + return reinterpret_cast(u); + #endif + } + + // string_wrapper + + template + class string_wrapper + { + public: + using char_type = CharT; + private: + struct str_base_t + { + Allocator alloc_; + + Allocator& get_allocator() + { + return alloc_; + } + + const Allocator& get_allocator() const + { + return alloc_; + } + + str_base_t(const Allocator& alloc) + : alloc_(alloc) + { + } + + ~str_base_t() noexcept = default; + }; + + struct str_t : public str_base_t + { + typedef typename std::allocator_traits::template rebind_alloc allocator_type; + using allocator_traits_type = std::allocator_traits; + using pointer = typename allocator_traits_type::pointer; + + pointer p_; + std::size_t length_; + + ~str_t() noexcept = default; + + const char_type* c_str() const { return type_traits::to_plain_pointer(p_); } + const char_type* data() const { return type_traits::to_plain_pointer(p_); } + std::size_t length() const { return length_; } + + str_t(const Allocator& alloc) + : str_base_t(alloc), p_(nullptr), length_(0) + { + + } + + str_t(const str_t&) = delete; + str_t& operator=(const str_t&) = delete; + + }; + + typedef typename std::allocator_traits::template rebind_alloc byte_allocator_type; + using byte_pointer = typename std::allocator_traits::pointer; + + typedef typename std::allocator_traits::template rebind_alloc string_allocator_type; + using string_pointer = typename std::allocator_traits::pointer; + + struct storage_t + { + str_t data; + char_type c[1]; + }; + typedef typename std::aligned_storage::type json_storage_kind; + + string_pointer ptr_; + public: + string_wrapper() = default; + + string_wrapper(string_pointer ptr) + : ptr_(ptr) + { + } + + string_wrapper(const char_type* data, std::size_t length, const Allocator& a) + { + ptr_ = create(data,length,a); + } + + string_wrapper(const string_wrapper& val) + { + ptr_ = create(val.data(),val.length(),val.get_allocator()); + } + + string_wrapper(const string_wrapper& val, const Allocator& a) + { + ptr_ = create(val.data(),val.length(),a); + } + + ~string_wrapper() noexcept + { + if (ptr_ != nullptr) + { + destroy(ptr_); + } + } + + void swap(string_wrapper& other) noexcept + { + std::swap(ptr_,other.ptr_); + } + + const char_type* data() const + { + return ptr_->data(); + } + + const char_type* c_str() const + { + return ptr_->c_str(); + } + + std::size_t length() const + { + return ptr_->length(); + } + + Allocator get_allocator() const + { + return ptr_->get_allocator(); + } + private: + static size_t aligned_size(std::size_t n) + { + return sizeof(json_storage_kind) + n; + } + + static string_pointer create(const char_type* s, std::size_t length, const Allocator& alloc) + { + std::size_t mem_size = aligned_size(length*sizeof(char_type)); + + byte_allocator_type byte_alloc(alloc); + byte_pointer ptr = byte_alloc.allocate(mem_size); + + char* storage = type_traits::to_plain_pointer(ptr); + str_t* ps = new(storage)str_t(byte_alloc); + + auto psa = launder_cast(storage); + + CharT* p = new(&psa->c)char_type[length + 1]; + std::memcpy(p, s, length*sizeof(char_type)); + p[length] = 0; + ps->p_ = std::pointer_traits::pointer_to(*p); + ps->length_ = length; + return std::pointer_traits::pointer_to(*ps); + } + + static void destroy(string_pointer ptr) + { + str_t* rawp = type_traits::to_plain_pointer(ptr); + + char* p = launder_cast(rawp); + + std::size_t mem_size = aligned_size(ptr->length_*sizeof(char_type)); + byte_allocator_type byte_alloc(ptr->get_allocator()); + byte_alloc.deallocate(p,mem_size); + } + }; + + // tagged_string_wrapper + + template + class tagged_string_wrapper + { + public: + using char_type = CharT; + private: + struct str_base_t + { + Allocator alloc_; + + Allocator& get_allocator() + { + return alloc_; + } + + const Allocator& get_allocator() const + { + return alloc_; + } + + str_base_t(const Allocator& alloc) + : alloc_(alloc) + { + } + + ~str_base_t() noexcept = default; + }; + + struct str_t : public str_base_t + { + typedef typename std::allocator_traits::template rebind_alloc allocator_type; + using allocator_traits_type = std::allocator_traits; + using pointer = typename allocator_traits_type::pointer; + + pointer p_; + std::size_t length_; + uint64_t tag_; + + ~str_t() noexcept = default; + + const char_type* c_str() const { return type_traits::to_plain_pointer(p_); } + const char_type* data() const { return type_traits::to_plain_pointer(p_); } + std::size_t length() const { return length_; } + uint64_t tag() const { return tag_; } + + str_t(uint64_t tag, const Allocator& alloc) + : str_base_t(alloc), p_(nullptr), length_(0), tag_(tag) + { + + } + + str_t(const str_t&) = delete; + str_t& operator=(const str_t&) = delete; + + }; + + typedef typename std::allocator_traits::template rebind_alloc byte_allocator_type; + using byte_pointer = typename std::allocator_traits::pointer; + + typedef typename std::allocator_traits::template rebind_alloc string_allocator_type; + using string_pointer = typename std::allocator_traits::pointer; + + struct storage_t + { + str_t data; + char_type c[1]; + }; + typedef typename std::aligned_storage::type json_storage_kind; + + string_pointer ptr_; + public: + tagged_string_wrapper() = default; + + tagged_string_wrapper(string_pointer ptr) + : ptr_(ptr) + { + } + + tagged_string_wrapper(const char_type* data, std::size_t length, uint64_t tag, const Allocator& alloc) + { + ptr_ = create(data, length, tag, alloc); + } + + tagged_string_wrapper(const tagged_string_wrapper& val) + { + ptr_ = create(val.data(), val.length(), val.tag(), val.get_allocator()); + } + + tagged_string_wrapper(const tagged_string_wrapper& val, const Allocator& alloc) + { + ptr_ = create(val.data(), val.length(), val.tag(), alloc); + } + + ~tagged_string_wrapper() noexcept + { + if (ptr_ != nullptr) + { + destroy(ptr_); + } + } + + void swap(tagged_string_wrapper& other) noexcept + { + std::swap(ptr_,other.ptr_); + } + + const char_type* data() const + { + return ptr_->data(); + } + + const char_type* c_str() const + { + return ptr_->c_str(); + } + + std::size_t length() const + { + return ptr_->length(); + } + + uint64_t tag() const + { + return ptr_->tag(); + } + + Allocator get_allocator() const + { + return ptr_->get_allocator(); + } + private: + static size_t aligned_size(std::size_t n) + { + return sizeof(json_storage_kind) + n; + } + + static string_pointer create(const char_type* s, std::size_t length, uint64_t tag, const Allocator& alloc) + { + std::size_t mem_size = aligned_size(length*sizeof(char_type)); + + byte_allocator_type byte_alloc(alloc); + byte_pointer ptr = byte_alloc.allocate(mem_size); + + char* storage = type_traits::to_plain_pointer(ptr); + str_t* ps = new(storage)str_t(tag, byte_alloc); + + auto psa = launder_cast(storage); + + CharT* p = new(&psa->c)char_type[length + 1]; + std::memcpy(p, s, length*sizeof(char_type)); + p[length] = 0; + ps->p_ = std::pointer_traits::pointer_to(*p); + ps->length_ = length; + return std::pointer_traits::pointer_to(*ps); + } + + static void destroy(string_pointer ptr) + { + str_t* rawp = type_traits::to_plain_pointer(ptr); + + char* p = launder_cast(rawp); + + std::size_t mem_size = aligned_size(ptr->length_*sizeof(char_type)); + byte_allocator_type byte_alloc(ptr->get_allocator()); + byte_alloc.deallocate(p,mem_size); + } + }; + +} // namespace detail +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/detail/write_number.hpp b/include/jsoncons/detail/write_number.hpp new file mode 100644 index 0000000..2613467 --- /dev/null +++ b/include/jsoncons/detail/write_number.hpp @@ -0,0 +1,567 @@ +// 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_WRITE_NUMBER_HPP +#define JSONCONS_DETAIL_WRITE_NUMBER_HPP + +#include +#include +#include +#include +#include // std::numeric_limits +#include +#include // snprintf +#include +#include +#include +#include +#include + +namespace jsoncons { +namespace detail { + + inline + char to_hex_character(uint8_t c) + { + return (char)((c < 10) ? ('0' + c) : ('A' - 10 + c)); + } + + // from_integer + + template + typename std::enable_if::value,std::size_t>::type + from_integer(Integer value, Result& result) + { + using char_type = typename Result::value_type; + + char_type buf[255]; + char_type *p = buf; + const char_type* last = buf+255; + + bool is_negative = value < 0; + + if (value < 0) + { + do + { + *p++ = static_cast(48 - (value % 10)); + } + while ((value /= 10) && (p < last)); + } + else + { + + do + { + *p++ = static_cast(48 + value % 10); + } + while ((value /= 10) && (p < last)); + } + JSONCONS_ASSERT(p != last); + + std::size_t count = (p - buf); + if (is_negative) + { + result.push_back('-'); + ++count; + } + while (--p >= buf) + { + result.push_back(*p); + } + + return count; + } + + // integer_to_string_hex + + template + typename std::enable_if::value,std::size_t>::type + integer_to_string_hex(Integer value, Result& result) + { + using char_type = typename Result::value_type; + + char_type buf[255]; + char_type *p = buf; + const char_type* last = buf+255; + + bool is_negative = value < 0; + + if (value < 0) + { + do + { + *p++ = to_hex_character(0-(value % 16)); + } + while ((value /= 16) && (p < last)); + } + else + { + + do + { + *p++ = to_hex_character(value % 16); + } + while ((value /= 16) && (p < last)); + } + JSONCONS_ASSERT(p != last); + + std::size_t count = (p - buf); + if (is_negative) + { + result.push_back('-'); + ++count; + } + while (--p >= buf) + { + result.push_back(*p); + } + + return count; + } + + // write_double + + // fast exponent + template + void fill_exponent(int K, Result& result) + { + if (K < 0) + { + result.push_back('-'); + K = -K; + } + else + { + result.push_back('+'); // compatibility with sprintf + } + + if (K < 10) + { + result.push_back('0'); // compatibility with sprintf + result.push_back((char)('0' + K)); + } + else if (K < 100) + { + result.push_back((char)('0' + K / 10)); K %= 10; + result.push_back((char)('0' + K)); + } + else if (K < 1000) + { + result.push_back((char)('0' + K / 100)); K %= 100; + result.push_back((char)('0' + K / 10)); K %= 10; + result.push_back((char)('0' + K)); + } + else + { + jsoncons::detail::from_integer(K, result); + } + } + + template + void prettify_string(const char *buffer, std::size_t length, int k, int min_exp, int max_exp, Result& result) + { + int nb_digits = (int)length; + int offset; + /* v = buffer * 10^k + kk is such that 10^(kk-1) <= v < 10^kk + this way kk gives the position of the decimal point. + */ + int kk = nb_digits + k; + + if (nb_digits <= kk && kk <= max_exp) + { + /* the first digits are already in. Add some 0s and call it a day. */ + /* the max_exp is a personal choice. Only 16 digits could possibly be relevant. + * Basically we want to print 12340000000 rather than 1234.0e7 or 1.234e10 */ + for (int i = 0; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + for (int i = nb_digits; i < kk; ++i) + { + result.push_back('0'); + } + result.push_back('.'); + result.push_back('0'); + } + else if (0 < kk && kk <= max_exp) + { + /* comma number. Just insert a '.' at the correct location. */ + for (int i = 0; i < kk; ++i) + { + result.push_back(buffer[i]); + } + result.push_back('.'); + for (int i = kk; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + } + else if (min_exp < kk && kk <= 0) + { + offset = 2 - kk; + + result.push_back('0'); + result.push_back('.'); + for (int i = 2; i < offset; ++i) + result.push_back('0'); + for (int i = 0; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + } + else if (nb_digits == 1) + { + result.push_back(buffer[0]); + result.push_back('e'); + fill_exponent(kk - 1, result); + } + else + { + result.push_back(buffer[0]); + result.push_back('.'); + for (int i = 1; i < nb_digits; ++i) + { + result.push_back(buffer[i]); + } + result.push_back('e'); + fill_exponent(kk - 1, result); + } + } + + template + void dump_buffer(const char *buffer, std::size_t length, char decimal_point, Result& result) + { + const char *sbeg = buffer; + const char *send = sbeg + length; + + if (sbeg != send) + { + bool needs_dot = true; + for (const char* q = sbeg; q < send; ++q) + { + switch (*q) + { + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + result.push_back(*q); + break; + case 'e': + case 'E': + result.push_back('e'); + needs_dot = false; + break; + default: + if (*q == decimal_point) + { + needs_dot = false; + result.push_back('.'); + } + break; + } + } + if (needs_dot) + { + result.push_back('.'); + result.push_back('0'); + needs_dot = true; + } + } + } + + template + bool dtoa_scientific(double val, char decimal_point, Result& result) + { + if (val == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + jsoncons::detail::chars_to to_double_; + + char buffer[100]; + int precision = std::numeric_limits::digits10; + int length = snprintf(buffer, sizeof(buffer), "%1.*e", precision, val); + if (length < 0) + { + return false; + } + if (to_double_(buffer, sizeof(buffer)) != val) + { + const int precision2 = std::numeric_limits::max_digits10; + length = snprintf(buffer, sizeof(buffer), "%1.*e", precision2, val); + if (length < 0) + { + return false; + } + } + dump_buffer(buffer, static_cast(length), decimal_point, result); + return true; + } + + template + bool dtoa_general(double val, char decimal_point, Result& result, std::false_type) + { + if (val == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + jsoncons::detail::chars_to to_double_; + + char buffer[100]; + int precision = std::numeric_limits::digits10; + int length = snprintf(buffer, sizeof(buffer), "%1.*g", precision, val); + if (length < 0) + { + return false; + } + if (to_double_(buffer, sizeof(buffer)) != val) + { + const int precision2 = std::numeric_limits::max_digits10; + length = snprintf(buffer, sizeof(buffer), "%1.*g", precision2, val); + if (length < 0) + { + return false; + } + } + dump_buffer(buffer, length, decimal_point, result); + return true; + } + + template + bool dtoa_general(double v, char decimal_point, Result& result, std::true_type) + { + if (v == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + int length = 0; + int k; + + char buffer[100]; + + double u = std::signbit(v) ? -v : v; + if (jsoncons::detail::grisu3(u, buffer, &length, &k)) + { + if (std::signbit(v)) + { + result.push_back('-'); + } + // min exp: -4 is consistent with sprintf + // max exp: std::numeric_limits::max_digits10 + jsoncons::detail::prettify_string(buffer, length, k, -4, std::numeric_limits::max_digits10, result); + return true; + } + else + { + return dtoa_general(v, decimal_point, result, std::false_type()); + } + } + + template + bool dtoa_fixed(double val, char decimal_point, Result& result, std::false_type) + { + if (val == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + jsoncons::detail::chars_to to_double_; + + char buffer[100]; + int precision = std::numeric_limits::digits10; + int length = snprintf(buffer, sizeof(buffer), "%1.*f", precision, val); + if (length < 0) + { + return false; + } + if (to_double_(buffer, sizeof(buffer)) != val) + { + const int precision2 = std::numeric_limits::max_digits10; + length = snprintf(buffer, sizeof(buffer), "%1.*f", precision2, val); + if (length < 0) + { + return false; + } + } + dump_buffer(buffer, length, decimal_point, result); + return true; + } + + template + bool dtoa_fixed(double v, char decimal_point, Result& result, std::true_type) + { + if (v == 0) + { + result.push_back('0'); + result.push_back('.'); + result.push_back('0'); + return true; + } + + int length = 0; + int k; + + char buffer[100]; + + double u = std::signbit(v) ? -v : v; + if (jsoncons::detail::grisu3(u, buffer, &length, &k)) + { + if (std::signbit(v)) + { + result.push_back('-'); + } + jsoncons::detail::prettify_string(buffer, length, k, std::numeric_limits::lowest(), (std::numeric_limits::max)(), result); + return true; + } + else + { + return dtoa_fixed(v, decimal_point, result, std::false_type()); + } + } + + template + bool dtoa_fixed(double v, char decimal_point, Result& result) + { + return dtoa_fixed(v, decimal_point, result, std::integral_constant::is_iec559>()); + } + + template + bool dtoa_general(double v, char decimal_point, Result& result) + { + return dtoa_general(v, decimal_point, result, std::integral_constant::is_iec559>()); + } + + class write_double + { + private: + chars_to to_double_; + float_chars_format float_format_; + int precision_; + char decimal_point_; + public: + write_double(float_chars_format float_format, int precision) + : float_format_(float_format), precision_(precision), decimal_point_('.') + { + #if !defined(JSONCONS_NO_LOCALECONV) + struct lconv *lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + #endif + } + write_double(const write_double&) = default; + + write_double& operator=(const write_double&) = default; + + template + std::size_t operator()(double val, Result& result) + { + std::size_t count = 0; + + char number_buffer[200]; + int length = 0; + + switch (float_format_) + { + case float_chars_format::fixed: + { + if (precision_ > 0) + { + length = snprintf(number_buffer, sizeof(number_buffer), "%1.*f", precision_, val); + if (length < 0) + { + JSONCONS_THROW(json_runtime_error("write_double failed.")); + } + dump_buffer(number_buffer, length, decimal_point_, result); + } + else + { + if (!dtoa_fixed(val, decimal_point_, result)) + { + JSONCONS_THROW(json_runtime_error("write_double failed.")); + } + } + } + break; + case float_chars_format::scientific: + { + if (precision_ > 0) + { + length = snprintf(number_buffer, sizeof(number_buffer), "%1.*e", precision_, val); + if (length < 0) + { + JSONCONS_THROW(json_runtime_error("write_double failed.")); + } + dump_buffer(number_buffer, length, decimal_point_, result); + } + else + { + if (!dtoa_scientific(val, decimal_point_, result)) + { + JSONCONS_THROW(json_runtime_error("write_double failed.")); + } + } + } + break; + case float_chars_format::general: + { + if (precision_ > 0) + { + length = snprintf(number_buffer, sizeof(number_buffer), "%1.*g", precision_, val); + if (length < 0) + { + JSONCONS_THROW(json_runtime_error("write_double failed.")); + } + dump_buffer(number_buffer, length, decimal_point_, result); + } + else + { + if (!dtoa_general(val, decimal_point_, result)) + { + JSONCONS_THROW(json_runtime_error("write_double failed.")); + } + } + break; + } + default: + JSONCONS_THROW(json_runtime_error("write_double failed.")); + break; + } + return count; + } + }; + +} // namespace detail +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/encode_json.hpp b/include/jsoncons/encode_json.hpp new file mode 100644 index 0000000..706dc44 --- /dev/null +++ b/include/jsoncons/encode_json.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_ENCODE_JSON_HPP +#define JSONCONS_ENCODE_JSON_HPP + +#include +#include +#include +#include +#include // std::basic_istream +#include +#include + +namespace jsoncons { + + // to string + + template + typename std::enable_if::value && + type_traits::is_back_insertable_char_container::value>::type + encode_json(const T& val, + Container& s, + const basic_json_encode_options& options = + basic_json_encode_options()) + { + using char_type = typename Container::value_type; + + basic_compact_json_encoder> encoder(s, options); + val.dump(encoder); + } + + template + typename std::enable_if::value && + type_traits::is_back_insertable_char_container::value>::type + encode_json(const T& val, + Container& s, + const basic_json_encode_options& options = basic_json_encode_options()) + { + using char_type = typename Container::value_type; + + basic_compact_json_encoder> encoder(s, options); + encode_json(val, encoder); + } + + // to stream + + template + typename std::enable_if::value>::type + encode_json(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_encode_options()) + { + basic_compact_json_encoder encoder(os, options); + val.dump(encoder); + } + + template + typename std::enable_if::value>::type + encode_json(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_encode_options()) + { + basic_compact_json_encoder encoder(os, options); + encode_json(val, encoder); + } + + // encode_json_pretty + + template + typename std::enable_if::value && + type_traits::is_back_insertable_char_container::value>::type + encode_json_pretty(const T& val, + Container& s, + const basic_json_encode_options& options = basic_json_encode_options()) + { + using char_type = typename Container::value_type; + + basic_json_encoder> encoder(s, options); + val.dump(encoder); + } + + template + typename std::enable_if::value && + type_traits::is_back_insertable_char_container::value>::type + encode_json_pretty(const T& val, + Container& s, + const basic_json_encode_options& options = basic_json_encode_options()) + { + using char_type = typename Container::value_type; + basic_json_encoder> encoder(s, options); + encode_json(val, encoder); + } + + template + typename std::enable_if::value>::type + encode_json_pretty(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_encode_options()) + { + basic_json_encoder encoder(os, options); + val.dump(encoder); + } + + template + typename std::enable_if::value>::type + encode_json_pretty(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options = basic_json_encode_options()) + { + basic_json_encoder encoder(os, options); + encode_json(val, encoder); + } + + template + void encode_json(const T& val, basic_json_visitor& encoder) + { + std::error_code ec; + encode_traits::encode(val, encoder, basic_json(), ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + encoder.flush(); + } + + template + void encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + Container& s, + indenting line_indent = indenting::no_indent) + { + encode_json(temp_allocator_arg, temp_alloc, val, s, basic_json_encode_options(), line_indent); + } + +// legacy + + template + void encode_json(const T& val, Container& s, indenting line_indent) + { + if (line_indent == indenting::indent) + { + encode_json_pretty(val,s); + } + else + { + encode_json(val,s); + } + } + + template + void encode_json(const T& val, + Container& s, + const basic_json_encode_options& options, + indenting line_indent) + { + if (line_indent == indenting::indent) + { + encode_json_pretty(val,s,options); + } + else + { + encode_json(val,s,options); + } + } + + template + void encode_json(const T& val, + std::basic_ostream& os, + indenting line_indent) + { + if (line_indent == indenting::indent) + { + encode_json_pretty(val, os); + } + else + { + encode_json(val, os); + } + } + + template + void encode_json(const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options, + indenting line_indent) + { + if (line_indent == indenting::indent) + { + encode_json_pretty(val, os, options); + } + else + { + encode_json(val, os, options); + } + } + +//end legacy + + template + typename std::enable_if::value && + type_traits::is_back_insertable_char_container::value>::type + encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + Container& s, + const basic_json_encode_options& options, + indenting line_indent = indenting::no_indent) + { + using char_type = typename Container::value_type; + if (line_indent == indenting::indent) + { + basic_json_encoder,TempAllocator> encoder(s, options, temp_alloc); + val.dump(encoder); + } + else + { + basic_compact_json_encoder,TempAllocator> encoder(s, options, temp_alloc); + val.dump(encoder); + } + } + + template + typename std::enable_if::value && + type_traits::is_back_insertable_char_container::value>::type + encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + Container& s, + const basic_json_encode_options& options, + indenting line_indent) + { + using char_type = typename Container::value_type; + if (line_indent == indenting::indent) + { + basic_json_encoder,TempAllocator> encoder(s, options, temp_alloc); + encode_json(temp_allocator_arg, temp_alloc, val, encoder); + } + else + { + basic_compact_json_encoder,TempAllocator> encoder(s, options, temp_alloc); + encode_json(temp_allocator_arg, temp_alloc, val, encoder); + } + } + + template + void encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + std::basic_ostream& os, + indenting line_indent = indenting::no_indent) + { + encode_json(temp_allocator_arg, temp_alloc, val, os, basic_json_encode_options(), line_indent); + } + + template + typename std::enable_if::value>::type + encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options, + indenting line_indent = indenting::no_indent) + { + if (line_indent == indenting::indent) + { + basic_json_encoder,TempAllocator> encoder(os, options, temp_alloc); + val.dump(encoder); + } + else + { + basic_compact_json_encoder,TempAllocator> encoder(os, options, temp_alloc); + val.dump(encoder); + } + } + + template + typename std::enable_if::value>::type + encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + std::basic_ostream& os, + const basic_json_encode_options& options, + indenting line_indent) + { + if (line_indent == indenting::indent) + { + basic_json_encoder encoder(os, options); + encode_json(temp_allocator_arg, temp_alloc, val, encoder); + } + else + { + basic_compact_json_encoder encoder(os, options); + encode_json(temp_allocator_arg, temp_alloc, val, encoder); + } + } + + template + typename std::enable_if::value>::type + encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc, + const T& val, + basic_json_visitor& encoder) + { + std::error_code ec; + basic_json proto(temp_alloc); + encode_traits::encode(val, encoder, proto, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + encoder.flush(); + } + +} // jsoncons + +#endif + diff --git a/include/jsoncons/encode_traits.hpp b/include/jsoncons/encode_traits.hpp new file mode 100644 index 0000000..ae981af --- /dev/null +++ b/include/jsoncons/encode_traits.hpp @@ -0,0 +1,378 @@ +// 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_ENCODE_TRAITS_HPP +#define JSONCONS_ENCODE_TRAITS_HPP + +#include +#include +#include +#include +#include // std::enable_if, std::true_type, std::false_type +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + // encode_traits + + template + struct encode_traits + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encode(std::integral_constant::value>(), + val, encoder, proto, ec); + } + private: + template + static void encode(std::true_type, + const T& val, + basic_json_visitor& encoder, + const Json& /*proto*/, + std::error_code& ec) + { + auto j = json_type_traits::to_json(val); + j.dump(encoder, ec); + } + template + static void encode(std::false_type, + const T& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + auto j = json_type_traits::to_json(val, proto.get_allocator()); + j.dump(encoder, ec); + } + }; + + // specializations + + // bool + template + struct encode_traits::value + >::type> + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + encoder.bool_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // uint + template + struct encode_traits::value + >::type> + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + encoder.uint64_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // int + template + struct encode_traits::value + >::type> + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + encoder.int64_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // float or double + template + struct encode_traits::value + >::type> + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + encoder.double_value(val,semantic_tag::none,ser_context(),ec); + } + }; + + // string + template + struct encode_traits::value && + std::is_same::value + >::type> + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + encoder.string_value(val,semantic_tag::none,ser_context(),ec); + } + }; + template + struct encode_traits::value && + !std::is_same::value + >::type> + { + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + std::basic_string s; + unicode_traits::convert(val.data(), val.size(), s); + encoder.string_value(s,semantic_tag::none,ser_context(),ec); + } + }; + + // std::pair + + template + struct encode_traits, CharT> + { + using value_type = std::pair; + + template + static void encode(const value_type& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_array(2,semantic_tag::none,ser_context(),ec); + if (ec) return; + encode_traits::encode(val.first, encoder, proto, ec); + if (ec) return; + encode_traits::encode(val.second, encoder, proto, ec); + if (ec) return; + encoder.end_array(ser_context(),ec); + } + }; + + // std::tuple + + namespace detail + { + template + struct json_serialize_tuple_helper + { + using char_type = typename Json::char_type; + using element_type = typename std::tuple_element::type; + using next = json_serialize_tuple_helper; + + static void encode(const Tuple& tuple, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encode_traits::encode(std::get(tuple), encoder, proto, ec); + if (ec) return; + next::encode(tuple, encoder, proto, ec); + } + }; + + template + struct json_serialize_tuple_helper<0, Size, Json, Tuple> + { + using char_type = typename Json::char_type; + static void encode(const Tuple&, + basic_json_visitor&, + const Json&, + std::error_code&) + { + } + }; + } // namespace detail + + + template + struct encode_traits, CharT> + { + using value_type = std::tuple; + static constexpr std::size_t size = sizeof...(E); + + template + static void encode(const value_type& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + using helper = jsoncons::detail::json_serialize_tuple_helper>; + encoder.begin_array(size,semantic_tag::none,ser_context(),ec); + if (ec) return; + helper::encode(val, encoder, proto, ec); + if (ec) return; + encoder.end_array(ser_context(),ec); + } + }; + + // vector like + template + struct encode_traits::value && + type_traits::is_list_like::value && + !type_traits::is_typed_array::value + >::type> + { + using value_type = typename T::value_type; + + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_array(val.size(),semantic_tag::none,ser_context(),ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + encode_traits::encode(*it, encoder, proto, ec); + if (ec) return; + } + encoder.end_array(ser_context(), ec); + } + }; + + template + struct encode_traits::value && + type_traits::is_list_like::value && + type_traits::is_typed_array::value + >::type> + { + using value_type = typename T::value_type; + + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json&, + std::error_code& ec) + { + encoder.typed_array(jsoncons::span(val), semantic_tag::none, ser_context(), ec); + } + }; + + // std::array + + template + struct encode_traits,CharT> + { + using value_type = typename std::array::value_type; + + template + static void encode(const std::array& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_array(val.size(),semantic_tag::none,ser_context(),ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + encode_traits::encode(*it, encoder, proto, ec); + if (ec) return; + } + encoder.end_array(ser_context(),ec); + } + }; + + // map like + + template + struct encode_traits::value && + type_traits::is_map_like::value && + type_traits::is_constructible_from_const_pointer_and_size::value + >::type> + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_object(val.size(), semantic_tag::none, ser_context(), ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + encoder.key(it->first); + encode_traits::encode(it->second, encoder, proto, ec); + if (ec) return; + } + encoder.end_object(ser_context(), ec); + if (ec) return; + } + }; + + template + struct encode_traits::value && + type_traits::is_map_like::value && + std::is_integral::value + >::type> + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + + template + static void encode(const T& val, + basic_json_visitor& encoder, + const Json& proto, + std::error_code& ec) + { + encoder.begin_object(val.size(), semantic_tag::none, ser_context(), ec); + if (ec) return; + for (auto it = std::begin(val); it != std::end(val); ++it) + { + std::basic_string s; + jsoncons::detail::from_integer(it->first,s); + encoder.key(s); + encode_traits::encode(it->second, encoder, proto, ec); + if (ec) return; + } + encoder.end_object(ser_context(), ec); + if (ec) return; + } + }; + +} // jsoncons + +#endif + diff --git a/include/jsoncons/json.hpp b/include/jsoncons/json.hpp new file mode 100644 index 0000000..8362e77 --- /dev/null +++ b/include/jsoncons/json.hpp @@ -0,0 +1,18 @@ +// Copyright 2018 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 +#include +#include +#include +#include +#include + +#endif + diff --git a/include/jsoncons/json_array.hpp b/include/jsoncons/json_array.hpp new file mode 100644 index 0000000..5877f4d --- /dev/null +++ b/include/jsoncons/json_array.hpp @@ -0,0 +1,324 @@ +// 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_ARRAY_HPP +#define JSONCONS_JSON_ARRAY_HPP + +#include +#include +#include +#include +#include // std::sort, std::stable_sort, std::lower_bound, std::unique +#include +#include +#include // std::iterator_traits +#include // std::allocator +#include // std::move +#include // assert +#include // std::enable_if +#include +#include + +namespace jsoncons { + + // json_array + + template class SequenceContainer = std::vector> + class json_array : public allocator_holder + { + public: + using allocator_type = typename Json::allocator_type; + using value_type = Json; + private: + using value_allocator_type = typename std::allocator_traits:: template rebind_alloc; + using value_container_type = SequenceContainer; + value_container_type elements_; + public: + using iterator = typename value_container_type::iterator; + using const_iterator = typename value_container_type::const_iterator; + using reference = typename std::iterator_traits::reference; + using const_reference = typename std::iterator_traits::reference; + + using allocator_holder::get_allocator; + + json_array() + { + } + + explicit json_array(const allocator_type& alloc) + : allocator_holder(alloc), + elements_(value_allocator_type(alloc)) + { + } + + explicit json_array(std::size_t n, + const allocator_type& alloc = allocator_type()) + : allocator_holder(alloc), + elements_(n,Json(),value_allocator_type(alloc)) + { + } + + explicit json_array(std::size_t n, + const Json& value, + const allocator_type& alloc = allocator_type()) + : allocator_holder(alloc), + elements_(n,value,value_allocator_type(alloc)) + { + } + + template + json_array(InputIterator begin, InputIterator end, const allocator_type& alloc = allocator_type()) + : allocator_holder(alloc), + elements_(begin,end,value_allocator_type(alloc)) + { + } + json_array(const json_array& val) + : allocator_holder(val.get_allocator()), + elements_(val.elements_) + { + } + json_array(const json_array& val, const allocator_type& alloc) + : allocator_holder(alloc), + elements_(val.elements_,value_allocator_type(alloc)) + { + } + + json_array(json_array&& val) noexcept + : allocator_holder(val.get_allocator()), + elements_(std::move(val.elements_)) + { + } + json_array(json_array&& val, const allocator_type& alloc) + : allocator_holder(alloc), + elements_(std::move(val.elements_),value_allocator_type(alloc)) + { + } + + json_array(const std::initializer_list& init, + const allocator_type& alloc = allocator_type()) + : allocator_holder(alloc), + elements_(init,value_allocator_type(alloc)) + { + } + ~json_array() noexcept + { + flatten_and_destroy(); + } + + reference back() + { + return elements_.back(); + } + + const_reference back() const + { + return elements_.back(); + } + + void pop_back() + { + elements_.pop_back(); + } + + bool empty() const + { + return elements_.empty(); + } + + void swap(json_array& val) noexcept + { + elements_.swap(val.elements_); + } + + std::size_t size() const {return elements_.size();} + + std::size_t capacity() const {return elements_.capacity();} + + void clear() {elements_.clear();} + + void shrink_to_fit() + { + for (std::size_t i = 0; i < elements_.size(); ++i) + { + elements_[i].shrink_to_fit(); + } + elements_.shrink_to_fit(); + } + + void reserve(std::size_t n) {elements_.reserve(n);} + + void resize(std::size_t n) {elements_.resize(n);} + + void resize(std::size_t n, const Json& val) {elements_.resize(n,val);} + + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use erase(const_iterator, const_iterator)") + void remove_range(std::size_t from_index, std::size_t to_index) + { + JSONCONS_ASSERT(from_index <= to_index); + JSONCONS_ASSERT(to_index <= elements_.size()); + elements_.erase(elements_.cbegin()+from_index,elements_.cbegin()+to_index); + } + #endif + + iterator erase(const_iterator pos) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.erase(it); + #else + return elements_.erase(pos); + #endif + } + + iterator erase(const_iterator first, const_iterator last) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it1 = elements_.begin() + (first - elements_.begin()); + iterator it2 = elements_.begin() + (last - elements_.begin()); + return elements_.erase(it1,it2); + #else + return elements_.erase(first,last); + #endif + } + + Json& operator[](std::size_t i) {return elements_[i];} + + const Json& operator[](std::size_t i) const {return elements_[i];} + + // push_back + + template + typename std::enable_if::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward(value)); + } + + template + typename std::enable_if::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward(value),get_allocator()); + } + + template + typename std::enable_if::value,iterator>::type + insert(const_iterator pos, T&& value) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward(value)); + #else + return elements_.emplace(pos, std::forward(value)); + #endif + } + template + typename std::enable_if::value,iterator>::type + insert(const_iterator pos, T&& value) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward(value), get_allocator()); + #else + return elements_.emplace(pos, std::forward(value), get_allocator()); + #endif + } + + template + iterator insert(const_iterator pos, InputIt first, InputIt last) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + elements_.insert(it, first, last); + return first == last ? it : it + 1; + #else + return elements_.insert(pos, first, last); + #endif + } + + template + typename std::enable_if::value,iterator>::type + emplace(const_iterator pos, Args&&... args) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward(args)...); + #else + return elements_.emplace(pos, std::forward(args)...); + #endif + } + + template + Json& emplace_back(Args&&... args) + { + elements_.emplace_back(std::forward(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& rhs) const noexcept + { + return elements_ == rhs.elements_; + } + + bool operator<(const json_array& rhs) const noexcept + { + return elements_ < rhs.elements_; + } + private: + + json_array& operator=(const json_array&) = delete; + + void flatten_and_destroy() noexcept + { + while (!elements_.empty()) + { + value_type current = std::move(elements_.back()); + elements_.pop_back(); + switch (current.storage_kind()) + { + case json_storage_kind::array_value: + { + for (auto&& item : current.array_range()) + { + if (item.size() > 0) // non-empty object or array + { + elements_.push_back(std::move(item)); + } + } + current.clear(); + break; + } + case json_storage_kind::object_value: + { + for (auto&& kv : current.object_range()) + { + if (kv.value().size() > 0) // non-empty object or array + { + elements_.push_back(std::move(kv.value())); + } + } + current.clear(); + break; + } + default: + break; + } + } + } + }; + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/json_content_handler.hpp b/include/jsoncons/json_content_handler.hpp new file mode 100644 index 0000000..edec19e --- /dev/null +++ b/include/jsoncons/json_content_handler.hpp @@ -0,0 +1,12 @@ +// Copyright 2018 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_CONTENT_HANDLER_HPP +#define JSONCONS_JSON_CONTENT_HANDLER_HPP + +#include + +#endif diff --git a/include/jsoncons/json_cursor.hpp b/include/jsoncons/json_cursor.hpp new file mode 100644 index 0000000..a30c351 --- /dev/null +++ b/include/jsoncons/json_cursor.hpp @@ -0,0 +1,448 @@ +// Copyright 2018 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_CURSOR_HPP +#define JSONCONS_JSON_CURSOR_HPP + +#include // std::allocator +#include +#include +#include +#include +#include +#include // std::basic_istream +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +template,class Allocator=std::allocator> +class basic_json_cursor : public basic_staj_cursor, private virtual ser_context +{ +public: + using source_type = Source; + using char_type = CharT; + using allocator_type = Allocator; + using string_view_type = jsoncons::basic_string_view; +private: + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + static constexpr size_t default_max_buffer_size = 16384; + + json_source_adaptor source_; + basic_json_parser parser_; + basic_staj_visitor cursor_visitor_; + bool done_; + + // Noncopyable and nonmoveable + basic_json_cursor(const basic_json_cursor&) = delete; + basic_json_cursor& operator=(const basic_json_cursor&) = delete; + +public: + + // Constructors that throw parse exceptions + + template + basic_json_cursor(Sourceable&& source, + const basic_json_decode_options& options = basic_json_decode_options(), + std::function err_handler = default_json_parsing(), + const Allocator& alloc = Allocator(), + typename std::enable_if,Sourceable>::value>::type* = 0) + : source_(std::forward(source)), + parser_(options,err_handler,alloc), + cursor_visitor_(accept_all), + done_(false) + { + if (!done()) + { + next(); + } + } + + template + basic_json_cursor(Sourceable&& source, + const basic_json_decode_options& options = basic_json_decode_options(), + std::function err_handler = default_json_parsing(), + const Allocator& alloc = Allocator(), + typename std::enable_if,Sourceable>::value>::type* = 0) + : source_(), + parser_(options, err_handler, alloc), + cursor_visitor_(accept_all), + done_(false) + { + initialize_with_string_view(std::forward(source)); + } + + + // Constructors that set parse error codes + template + basic_json_cursor(Sourceable&& source, + std::error_code& ec) + : basic_json_cursor(std::allocator_arg, Allocator(), + std::forward(source), + basic_json_decode_options(), + default_json_parsing(), + ec) + { + } + + template + basic_json_cursor(Sourceable&& source, + const basic_json_decode_options& options, + std::error_code& ec) + : basic_json_cursor(std::allocator_arg, Allocator(), + std::forward(source), + options, + default_json_parsing(), + ec) + { + } + + template + basic_json_cursor(Sourceable&& source, + const basic_json_decode_options& options, + std::function err_handler, + std::error_code& ec) + : basic_json_cursor(std::allocator_arg, Allocator(), + std::forward(source), + options, + err_handler, + ec) + { + } + + template + basic_json_cursor(std::allocator_arg_t, const Allocator& alloc, + Sourceable&& source, + const basic_json_decode_options& options, + std::function err_handler, + std::error_code& ec, + typename std::enable_if,Sourceable>::value>::type* = 0) + : source_(std::forward(source)), + parser_(options,err_handler,alloc), + cursor_visitor_(accept_all), + done_(false) + { + if (!done()) + { + next(ec); + } + } + + template + basic_json_cursor(std::allocator_arg_t, const Allocator& alloc, + Sourceable&& source, + const basic_json_decode_options& options, + std::function err_handler, + std::error_code& ec, + typename std::enable_if,Sourceable>::value>::type* = 0) + : source_(), + parser_(options, err_handler, alloc), + cursor_visitor_(accept_all), + done_(false) + { + initialize_with_string_view(std::forward(source), ec); + } + + void reset() + { + parser_.reset(); + cursor_visitor_.reset(); + done_ = false; + if (!done()) + { + next(); + } + } + + template + typename std::enable_if,Sourceable>::value>::type + reset(Sourceable&& source) + { + source_ = std::forward(source); + parser_.reinitialize(); + cursor_visitor_.reset(); + done_ = false; + if (!done()) + { + next(); + } + } + + template + typename std::enable_if,Sourceable>::value>::type + reset(Sourceable&& source) + { + source_ = {}; + parser_.reinitialize(); + cursor_visitor_.reset(); + done_ = false; + initialize_with_string_view(std::forward(source)); + } + + void reset(std::error_code& ec) + { + parser_.reset(); + cursor_visitor_.reset(); + done_ = false; + if (!done()) + { + next(ec); + } + } + + template + typename std::enable_if,Sourceable>::value>::type + reset(Sourceable&& source, std::error_code& ec) + { + source_ = std::forward(source); + parser_.reinitialize(); + cursor_visitor_.reset(); + done_ = false; + if (!done()) + { + next(ec); + } + } + + template + typename std::enable_if,Sourceable>::value>::type + reset(Sourceable&& source, std::error_code& ec) + { + source_ = {}; + parser_.reinitialize(); + done_ = false; + initialize_with_string_view(std::forward(source), ec); + } + + bool done() const override + { + return parser_.done() || done_; + } + + const basic_staj_event& current() const override + { + return cursor_visitor_.event(); + } + + void read_to(basic_json_visitor& visitor) override + { + std::error_code ec; + read_to(visitor, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + void read_to(basic_json_visitor& visitor, + std::error_code& ec) override + { + if (staj_to_saj_event(cursor_visitor_.event(), visitor, *this, ec)) + { + read_next(visitor, ec); + } + } + + void next() override + { + std::error_code ec; + next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + void next(std::error_code& ec) override + { + read_next(ec); + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + const ser_context& context() const override + { + return *this; + } + + void check_done(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (source_.eof()) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + do + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + if (!parser_.source_exhausted()) + { + parser_.check_done(ec); + if (ec) return; + } + } + while (!eof()); + } + } + + bool eof() const + { + return parser_.source_exhausted() && source_.eof(); + } + + std::size_t line() const override + { + return parser_.line(); + } + + std::size_t column() const override + { + return parser_.column(); + } + + friend + basic_staj_filter_view operator|(basic_json_cursor& cursor, + std::function&, const ser_context&)> pred) + { + return basic_staj_filter_view(cursor, pred); + } + +private: + + static bool accept_all(const basic_staj_event&, const ser_context&) + { + return true; + } + + void initialize_with_string_view(string_view_type sv) + { + auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size()); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column())); + } + std::size_t offset = (r.ptr - sv.data()); + parser_.update(sv.data()+offset,sv.size()-offset); + if (!done()) + { + next(); + } + } + + void initialize_with_string_view(string_view_type sv, std::error_code& ec) + { + auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size()); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + ec = json_errc::illegal_unicode_character; + return; + } + std::size_t offset = (r.ptr - sv.data()); + parser_.update(sv.data()+offset,sv.size()-offset); + if (!done()) + { + next(ec); + } + } + + void read_next(std::error_code& ec) + { + read_next(cursor_visitor_, ec); + } + + void read_next(basic_json_visitor& visitor, std::error_code& ec) + { + parser_.restart(); + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + if (ec) return; + } + } + bool eof = parser_.source_exhausted() && source_.eof(); + parser_.parse_some(visitor, ec); + if (ec) return; + if (eof) + { + if (parser_.enter()) + { + done_ = true; + break; + } + else if (!parser_.accept()) + { + ec = json_errc::unexpected_eof; + return; + } + } + } + } +}; + +using json_stream_cursor = basic_json_cursor>; +using json_string_cursor = basic_json_cursor>; +using wjson_stream_cursor = basic_json_cursor>; +using wjson_string_cursor = basic_json_cursor>; + +using json_cursor = basic_json_cursor; +using wjson_cursor = basic_json_cursor; + +#if !defined(JSONCONS_NO_DEPRECATED) +template> +using basic_json_pull_reader = basic_json_cursor; + +JSONCONS_DEPRECATED_MSG("Instead, use json_cursor") typedef json_cursor json_pull_reader; +JSONCONS_DEPRECATED_MSG("Instead, use wjson_cursor") typedef wjson_cursor wjson_pull_reader; + +template> +using basic_json_stream_reader = basic_json_cursor; + +template> +using basic_json_staj_cursor = basic_json_cursor; + +JSONCONS_DEPRECATED_MSG("Instead, use json_cursor") typedef json_cursor json_staj_cursor; +JSONCONS_DEPRECATED_MSG("Instead, use wjson_cursor") typedef wjson_cursor wjson_staj_cursor; +#endif + +} + +#endif + diff --git a/include/jsoncons/json_decoder.hpp b/include/jsoncons/json_decoder.hpp new file mode 100644 index 0000000..c5aa0b2 --- /dev/null +++ b/include/jsoncons/json_decoder.hpp @@ -0,0 +1,420 @@ +// 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 +#include +#include // std::true_type +#include // std::allocator +#include // std::make_move_iterator +#include // std::move +#include +#include + +namespace jsoncons { + +template > +class json_decoder final : public basic_json_visitor +{ +public: + using char_type = typename Json::char_type; + using typename basic_json_visitor::string_view_type; + + using key_value_type = typename Json::key_value_type; + using key_type = typename Json::key_type; + using array = typename Json::array; + using object = typename Json::object; + using result_allocator_type = typename Json::allocator_type; + using json_string_allocator = typename key_type::allocator_type; + using json_array_allocator = typename array::allocator_type; + using json_object_allocator = typename object::allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc json_byte_allocator_type; +private: + struct stack_item + { + key_type name_; + Json value_; + + template + stack_item(key_type&& name, Args&& ... args) + : name_(std::move(name)), value_(std::forward(args)...) + { + } + + 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; + }; + + enum class structure_type {root_t, array_t, object_t}; + + struct structure_info + { + structure_type type_; + std::size_t container_index_; + + structure_info(structure_type type, std::size_t offset) noexcept + : type_(type), container_index_(offset) + { + } + + }; + + using temp_allocator_type = TempAllocator; + typedef typename std::allocator_traits:: template rebind_alloc stack_item_allocator_type; + typedef typename std::allocator_traits:: template rebind_alloc structure_info_allocator_type; + + result_allocator_type result_allocator_; + temp_allocator_type temp_allocator_; + + Json result_; + + key_type name_; + std::vector item_stack_; + std::vector structure_stack_; + bool is_valid_; + +public: + json_decoder(const temp_allocator_type& temp_alloc = temp_allocator_type()) + : result_allocator_(result_allocator_type()), + temp_allocator_(temp_alloc), + result_(), + name_(result_allocator_), + item_stack_(temp_allocator_), + structure_stack_(temp_allocator_), + is_valid_(false) + { + item_stack_.reserve(1000); + structure_stack_.reserve(100); + structure_stack_.emplace_back(structure_type::root_t, 0); + } + + json_decoder(result_allocator_arg_t, + const result_allocator_type& result_alloc) + : result_allocator_(result_alloc), + temp_allocator_(), + result_(), + name_(result_allocator_), + item_stack_(), + structure_stack_(), + is_valid_(false) + { + item_stack_.reserve(1000); + structure_stack_.reserve(100); + structure_stack_.emplace_back(structure_type::root_t, 0); + } + + json_decoder(result_allocator_arg_t, + const result_allocator_type& result_alloc, + const temp_allocator_type& temp_alloc) + : result_allocator_(result_alloc), + temp_allocator_(temp_alloc), + result_(), + name_(result_allocator_), + item_stack_(temp_allocator_), + structure_stack_(temp_allocator_), + is_valid_(false) + { + item_stack_.reserve(1000); + structure_stack_.reserve(100); + structure_stack_.emplace_back(structure_type::root_t, 0); + } + + void reset() + { + is_valid_ = false; + item_stack_.clear(); + structure_stack_.clear(); + structure_stack_.emplace_back(structure_type::root_t, 0); + } + + bool is_valid() const + { + return is_valid_; + } + + Json get_result() + { + JSONCONS_ASSERT(is_valid_); + is_valid_ = false; + return std::move(result_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use get_result()") + Json& root() + { + return result_; + } +#endif + +private: + + void visit_flush() override + { + } + + bool visit_begin_object(semantic_tag tag, const ser_context&, std::error_code&) override + { + if (structure_stack_.back().type_ == structure_type::root_t) + { + item_stack_.clear(); + is_valid_ = false; + } + item_stack_.emplace_back(std::forward(name_), json_object_arg, tag, result_allocator_); + structure_stack_.emplace_back(structure_type::object_t, item_stack_.size()-1); + return true; + } + + bool visit_end_object(const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(structure_stack_.size() > 0); + JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::object_t); + const size_t structure_index = structure_stack_.back().container_index_; + JSONCONS_ASSERT(item_stack_.size() > structure_index); + const size_t count = item_stack_.size() - (structure_index + 1); + auto first = item_stack_.begin() + (structure_index+1); + auto last = first + count; + item_stack_[structure_index].value_.object_value().insert( + std::make_move_iterator(first), + std::make_move_iterator(last), + [](stack_item&& val){return key_value_type(std::move(val.name_), std::move(val.value_));} + ); + item_stack_.erase(item_stack_.begin()+structure_index+1, item_stack_.end()); + structure_stack_.pop_back(); + if (structure_stack_.back().type_ == structure_type::root_t) + { + result_.swap(item_stack_.front().value_); + item_stack_.pop_back(); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_begin_array(semantic_tag tag, const ser_context&, std::error_code&) override + { + if (structure_stack_.back().type_ == structure_type::root_t) + { + item_stack_.clear(); + is_valid_ = false; + } + item_stack_.emplace_back(std::forward(name_), json_array_arg, tag, result_allocator_); + structure_stack_.emplace_back(structure_type::array_t, item_stack_.size()-1); + return true; + } + + bool visit_end_array(const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(structure_stack_.size() > 1); + JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::array_t); + const size_t container_index = structure_stack_.back().container_index_; + JSONCONS_ASSERT(item_stack_.size() > container_index); + + auto& container = item_stack_[container_index].value_; + + const size_t size = item_stack_.size() - (container_index + 1); + //std::cout << "size on item stack: " << size << "\n"; + + if (size > 0) + { + container.reserve(size); + auto first = item_stack_.begin() + (container_index+1); + auto last = first + size; + for (auto it = first; it != last; ++it) + { + container.push_back(std::move(it->value_)); + } + item_stack_.erase(first, item_stack_.end()); + } + + structure_stack_.pop_back(); + if (structure_stack_.back().type_ == structure_type::root_t) + { + result_.swap(item_stack_.front().value_); + item_stack_.pop_back(); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override + { + name_ = key_type(name.data(),name.length(),result_allocator_); + return true; + } + + bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), sv, tag, result_allocator_); + break; + case structure_type::root_t: + result_ = Json(sv, tag, result_allocator_); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), byte_string_arg, b, tag, result_allocator_); + break; + case structure_type::root_t: + result_ = Json(byte_string_arg, b, tag, result_allocator_); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_byte_string(const byte_string_view& b, + uint64_t ext_tag, + const ser_context&, + std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), byte_string_arg, b, ext_tag, result_allocator_); + break; + case structure_type::root_t: + result_ = Json(byte_string_arg, b, ext_tag, result_allocator_); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), value, tag); + break; + case structure_type::root_t: + result_ = Json(value,tag); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), value, tag); + break; + case structure_type::root_t: + result_ = Json(value,tag); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), half_arg, value, tag); + break; + case structure_type::root_t: + result_ = Json(half_arg, value, tag); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_double(double value, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), value, tag); + break; + case structure_type::root_t: + result_ = Json(value, tag); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context&, std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), value, tag); + break; + case structure_type::root_t: + result_ = Json(value, tag); + is_valid_ = true; + return false; + } + return true; + } + + bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override + { + switch (structure_stack_.back().type_) + { + case structure_type::object_t: + case structure_type::array_t: + item_stack_.emplace_back(std::forward(name_), null_type(), tag); + break; + case structure_type::root_t: + result_ = Json(null_type(), tag); + is_valid_ = true; + return false; + } + return true; + } +}; + +} + +#endif diff --git a/include/jsoncons/json_encoder.hpp b/include/jsoncons/json_encoder.hpp new file mode 100644 index 0000000..df0d3fa --- /dev/null +++ b/include/jsoncons/json_encoder.hpp @@ -0,0 +1,1587 @@ +// 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_ENCODER_HPP +#define JSONCONS_JSON_ENCODER_HPP + +#include // std::array +#include +#include +#include // std::isfinite, std::isnan +#include // std::numeric_limits +#include +#include // std::move +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { +namespace detail { + + 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 + std::size_t escape_string(const CharT* s, std::size_t length, + bool escape_all_non_ascii, bool escape_solidus, + Sink& sink) + { + std::size_t count = 0; + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + switch (c) + { + case '\\': + sink.push_back('\\'); + sink.push_back('\\'); + count += 2; + break; + case '"': + sink.push_back('\\'); + sink.push_back('\"'); + count += 2; + break; + case '\b': + sink.push_back('\\'); + sink.push_back('b'); + count += 2; + break; + case '\f': + sink.push_back('\\'); + sink.push_back('f'); + count += 2; + break; + case '\n': + sink.push_back('\\'); + sink.push_back('n'); + count += 2; + break; + case '\r': + sink.push_back('\\'); + sink.push_back('r'); + count += 2; + break; + case '\t': + sink.push_back('\\'); + sink.push_back('t'); + count += 2; + break; + default: + if (escape_solidus && c == '/') + { + sink.push_back('\\'); + sink.push_back('/'); + count += 2; + } + else if (is_control_character(c) || escape_all_non_ascii) + { + // convert to codepoint + uint32_t cp; + auto r = unicode_traits::to_codepoint(it, end, cp, unicode_traits::conv_flags::strict); + if (r.ec != unicode_traits::conv_errc()) + { + JSONCONS_THROW(ser_error(json_errc::illegal_codepoint)); + } + it = r.ptr - 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); + + sink.push_back('\\'); + sink.push_back('u'); + sink.push_back(jsoncons::detail::to_hex_character(first >> 12 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(first >> 8 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(first >> 4 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(first & 0x000F)); + sink.push_back('\\'); + sink.push_back('u'); + sink.push_back(jsoncons::detail::to_hex_character(second >> 12 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(second >> 8 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(second >> 4 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(second & 0x000F)); + count += 12; + } + else + { + sink.push_back('\\'); + sink.push_back('u'); + sink.push_back(jsoncons::detail::to_hex_character(cp >> 12 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(cp >> 8 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(cp >> 4 & 0x000F)); + sink.push_back(jsoncons::detail::to_hex_character(cp & 0x000F)); + count += 6; + } + } + else + { + sink.push_back(c); + ++count; + } + } + else + { + sink.push_back(c); + ++count; + } + break; + } + } + return count; + } + + inline + byte_string_chars_format resolve_byte_string_chars_format(byte_string_chars_format format1, + byte_string_chars_format format2, + byte_string_chars_format default_format = byte_string_chars_format::base64url) + { + byte_string_chars_format sink; + switch (format1) + { + case byte_string_chars_format::base16: + case byte_string_chars_format::base64: + case byte_string_chars_format::base64url: + sink = format1; + break; + default: + switch (format2) + { + case byte_string_chars_format::base64url: + case byte_string_chars_format::base64: + case byte_string_chars_format::base16: + sink = format2; + break; + default: // base64url + { + sink = default_format; + break; + } + } + break; + } + return sink; + } + +} // namespace detail + + template,class Allocator=std::allocator> + class basic_json_encoder final : public basic_json_visitor + { + static const jsoncons::basic_string_view null_constant() + { + static const jsoncons::basic_string_view k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "null"); + return k; + } + static const jsoncons::basic_string_view true_constant() + { + static const jsoncons::basic_string_view k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "true"); + return k; + } + static const jsoncons::basic_string_view false_constant() + { + static const jsoncons::basic_string_view k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "false"); + return k; + } + public: + using allocator_type = Allocator; + using char_type = CharT; + using typename basic_json_visitor::string_view_type; + using sink_type = Sink; + using string_type = typename basic_json_encode_options::string_type; + + private: + enum class container_type {object, array}; + + class encoding_context + { + container_type type_; + std::size_t count_; + line_split_kind line_splits_; + bool indent_before_; + bool new_line_after_; + std::size_t begin_pos_; + std::size_t data_pos_; + public: + encoding_context(container_type type, line_split_kind split_lines, bool indent_once, + std::size_t begin_pos, std::size_t data_pos) noexcept + : type_(type), count_(0), line_splits_(split_lines), indent_before_(indent_once), new_line_after_(false), + begin_pos_(begin_pos), data_pos_(data_pos) + { + } + + encoding_context(const encoding_context&) = default; + encoding_context& operator=(const encoding_context&) = default; + + void set_position(std::size_t pos) + { + data_pos_ = pos; + } + + std::size_t begin_pos() const + { + return begin_pos_; + } + + std::size_t data_pos() const + { + return data_pos_; + } + + std::size_t count() const + { + return count_; + } + + void increment_count() + { + ++count_; + } + + bool new_line_after() const + { + return new_line_after_; + } + + void new_line_after(bool value) + { + new_line_after_ = value; + } + + bool is_object() const + { + return type_ == container_type::object; + } + + bool is_array() const + { + return type_ == container_type::array; + } + + bool is_same_line() const + { + return line_splits_ == line_split_kind::same_line; + } + + bool is_new_line() const + { + return line_splits_ == line_split_kind::new_line; + } + + bool is_multi_line() const + { + return line_splits_ == line_split_kind::multi_line; + } + + bool is_indent_once() const + { + return count_ == 0 ? indent_before_ : false; + } + + }; + typedef typename std::allocator_traits:: template rebind_alloc encoding_context_allocator_type; + + Sink sink_; + basic_json_encode_options options_; + jsoncons::detail::write_double fp_; + + std::vector stack_; + int indent_amount_; + std::size_t column_; + std::basic_string colon_str_; + std::basic_string comma_str_; + std::basic_string open_object_brace_str_; + std::basic_string close_object_brace_str_; + std::basic_string open_array_bracket_str_; + std::basic_string close_array_bracket_str_; + int nesting_depth_; + + // Noncopyable and nonmoveable + basic_json_encoder(const basic_json_encoder&) = delete; + basic_json_encoder& operator=(const basic_json_encoder&) = delete; + public: + basic_json_encoder(Sink&& sink, + const Allocator& alloc = Allocator()) + : basic_json_encoder(std::forward(sink), basic_json_encode_options(), alloc) + { + } + + basic_json_encoder(Sink&& sink, + const basic_json_encode_options& options, + const Allocator& alloc = Allocator()) + : sink_(std::forward(sink)), + options_(options), + fp_(options.float_format(), options.precision()), + stack_(alloc), + indent_amount_(0), + column_(0), + nesting_depth_(0) + { + switch (options.spaces_around_colon()) + { + case spaces_option::space_after: + colon_str_ = std::basic_string({':',' '}); + break; + case spaces_option::space_before: + colon_str_ = std::basic_string({' ',':'}); + break; + case spaces_option::space_before_and_after: + colon_str_ = std::basic_string({' ',':',' '}); + break; + default: + colon_str_.push_back(':'); + break; + } + switch (options.spaces_around_comma()) + { + case spaces_option::space_after: + comma_str_ = std::basic_string({',',' '}); + break; + case spaces_option::space_before: + comma_str_ = std::basic_string({' ',','}); + break; + case spaces_option::space_before_and_after: + comma_str_ = std::basic_string({' ',',',' '}); + break; + default: + comma_str_.push_back(','); + break; + } + if (options.pad_inside_object_braces()) + { + open_object_brace_str_ = std::basic_string({'{', ' '}); + close_object_brace_str_ = std::basic_string({' ', '}'}); + } + else + { + open_object_brace_str_.push_back('{'); + close_object_brace_str_.push_back('}'); + } + if (options.pad_inside_array_brackets()) + { + open_array_bracket_str_ = std::basic_string({'[', ' '}); + close_array_bracket_str_ = std::basic_string({' ', ']'}); + } + else + { + open_array_bracket_str_.push_back('['); + close_array_bracket_str_.push_back(']'); + } + } + + ~basic_json_encoder() noexcept + { + JSONCONS_TRY + { + sink_.flush(); + } + JSONCONS_CATCH(...) + { + } + } + + void reset() + { + stack_.clear(); + indent_amount_ = 0; + column_ = 0; + nesting_depth_ = 0; + } + + void reset(Sink&& sink) + { + sink_ = std::move(sink); + reset(); + } + + private: + // Implementing methods + void visit_flush() override + { + sink_.flush(); + } + + bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) + { + ec = json_errc::max_nesting_depth_exceeded; + return false; + } + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + + if (!stack_.empty()) // object or array + { + if (stack_.back().is_object()) + { + switch (options_.object_object_line_splits()) + { + case line_split_kind::same_line: + if (column_ >= options_.line_length_limit()) + { + break_line(); + } + break; + case line_split_kind::new_line: + if (column_ >= options_.line_length_limit()) + { + break_line(); + } + break; + default: // multi_line + break; + } + stack_.emplace_back(container_type::object,options_.object_object_line_splits(), false, + column_, column_+open_object_brace_str_.length()); + } + else // array + { + switch (options_.array_object_line_splits()) + { + case line_split_kind::same_line: + if (column_ >= options_.line_length_limit()) + { + //stack_.back().new_line_after(true); + new_line(); + } + break; + case line_split_kind::new_line: + stack_.back().new_line_after(true); + new_line(); + break; + default: // multi_line + stack_.back().new_line_after(true); + new_line(); + break; + } + stack_.emplace_back(container_type::object,options_.array_object_line_splits(), false, + column_, column_+open_object_brace_str_.length()); + } + } + else + { + stack_.emplace_back(container_type::object, line_split_kind::multi_line, false, + column_, column_+open_object_brace_str_.length()); + } + indent(); + + sink_.append(open_object_brace_str_.data(), open_object_brace_str_.length()); + column_ += open_object_brace_str_.length(); + return true; + } + + bool visit_end_object(const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(!stack_.empty()); + --nesting_depth_; + + unindent(); + if (stack_.back().new_line_after()) + { + new_line(); + } + stack_.pop_back(); + sink_.append(close_object_brace_str_.data(), close_object_brace_str_.length()); + column_ += close_object_brace_str_.length(); + + end_value(); + return true; + } + + bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) + { + ec = json_errc::max_nesting_depth_exceeded; + return false; + } + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + if (!stack_.empty()) + { + if (stack_.back().is_object()) + { + switch (options_.object_array_line_splits()) + { + case line_split_kind::same_line: + stack_.emplace_back(container_type::array,options_.object_array_line_splits(),false, + column_, column_ + open_array_bracket_str_.length()); + break; + case line_split_kind::new_line: + { + stack_.emplace_back(container_type::array,options_.object_array_line_splits(),true, + column_, column_+open_array_bracket_str_.length()); + break; + } + default: // multi_line + stack_.emplace_back(container_type::array,options_.object_array_line_splits(),true, + column_, column_+open_array_bracket_str_.length()); + break; + } + } + else // array + { + switch (options_.array_array_line_splits()) + { + case line_split_kind::same_line: + if (stack_.back().is_multi_line()) + { + stack_.back().new_line_after(true); + new_line(); + } + stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false, + column_, column_+open_array_bracket_str_.length()); + break; + case line_split_kind::new_line: + stack_.back().new_line_after(true); + new_line(); + stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false, + column_, column_+open_array_bracket_str_.length()); + break; + default: // multi_line + stack_.back().new_line_after(true); + new_line(); + stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false, + column_, column_+open_array_bracket_str_.length()); + //new_line(); + break; + } + } + } + else + { + stack_.emplace_back(container_type::array, line_split_kind::multi_line, false, + column_, column_+open_array_bracket_str_.length()); + } + indent(); + sink_.append(open_array_bracket_str_.data(), open_array_bracket_str_.length()); + column_ += open_array_bracket_str_.length(); + return true; + } + + bool visit_end_array(const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(!stack_.empty()); + --nesting_depth_; + + unindent(); + if (stack_.back().new_line_after()) + { + new_line(); + } + stack_.pop_back(); + sink_.append(close_array_bracket_str_.data(), close_array_bracket_str_.length()); + column_ += close_array_bracket_str_.length(); + end_value(); + return true; + } + + bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(!stack_.empty()); + if (stack_.back().count() > 0) + { + sink_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + + if (stack_.back().is_multi_line()) + { + stack_.back().new_line_after(true); + new_line(); + } + else if (stack_.back().count() > 0 && column_ >= options_.line_length_limit()) + { + //stack_.back().new_line_after(true); + new_line(stack_.back().data_pos()); + } + + if (stack_.back().count() == 0) + { + stack_.back().set_position(column_); + } + sink_.push_back('\"'); + std::size_t length = jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); + sink_.push_back('\"'); + sink_.append(colon_str_.data(),colon_str_.length()); + column_ += (length+2+colon_str_.length()); + return true; + } + + bool visit_null(semantic_tag, const ser_context&, std::error_code&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + sink_.append(null_constant().data(), null_constant().size()); + column_ += null_constant().size(); + + end_value(); + return true; + } + + bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + switch (tag) + { + case semantic_tag::bigint: + write_bigint_value(sv); + break; + default: + { + sink_.push_back('\"'); + std::size_t length = jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); + sink_.push_back('\"'); + column_ += (length+2); + break; + } + } + + end_value(); + return true; + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + byte_string_chars_format encoding_hint; + switch (tag) + { + case semantic_tag::base16: + encoding_hint = byte_string_chars_format::base16; + break; + case semantic_tag::base64: + encoding_hint = byte_string_chars_format::base64; + break; + case semantic_tag::base64url: + encoding_hint = byte_string_chars_format::base64url; + break; + default: + encoding_hint = byte_string_chars_format::none; + break; + } + + byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), + encoding_hint, + byte_string_chars_format::base64url); + switch (format) + { + case byte_string_chars_format::base16: + { + sink_.push_back('\"'); + std::size_t length = encode_base16(b.begin(),b.end(),sink_); + sink_.push_back('\"'); + column_ += (length + 2); + break; + } + case byte_string_chars_format::base64: + { + sink_.push_back('\"'); + std::size_t length = encode_base64(b.begin(), b.end(), sink_); + sink_.push_back('\"'); + column_ += (length + 2); + break; + } + case byte_string_chars_format::base64url: + { + sink_.push_back('\"'); + std::size_t length = encode_base64url(b.begin(),b.end(),sink_); + sink_.push_back('\"'); + column_ += (length + 2); + break; + } + default: + { + JSONCONS_UNREACHABLE(); + } + } + + end_value(); + return true; + } + + bool visit_double(double value, + semantic_tag, + const ser_context& context, + std::error_code& ec) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + if (!std::isfinite(value)) + { + if ((std::isnan)(value)) + { + if (options_.enable_nan_to_num()) + { + sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length()); + column_ += options_.nan_to_num().length(); + } + else if (options_.enable_nan_to_str()) + { + visit_string(options_.nan_to_str(), semantic_tag::none, context, ec); + } + else + { + sink_.append(null_constant().data(), null_constant().size()); + column_ += null_constant().size(); + } + } + else if (value == std::numeric_limits::infinity()) + { + if (options_.enable_inf_to_num()) + { + sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length()); + column_ += options_.inf_to_num().length(); + } + else if (options_.enable_inf_to_str()) + { + visit_string(options_.inf_to_str(), semantic_tag::none, context, ec); + } + else + { + sink_.append(null_constant().data(), null_constant().size()); + column_ += null_constant().size(); + } + } + else + { + if (options_.enable_neginf_to_num()) + { + sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length()); + column_ += options_.neginf_to_num().length(); + } + else if (options_.enable_neginf_to_str()) + { + visit_string(options_.neginf_to_str(), semantic_tag::none, context, ec); + } + else + { + sink_.append(null_constant().data(), null_constant().size()); + column_ += null_constant().size(); + } + } + } + else + { + std::size_t length = fp_(value, sink_); + column_ += length; + } + + end_value(); + return true; + } + + bool visit_int64(int64_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + std::size_t length = jsoncons::detail::from_integer(value, sink_); + column_ += length; + end_value(); + return true; + } + + bool visit_uint64(uint64_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + std::size_t length = jsoncons::detail::from_integer(value, sink_); + column_ += length; + end_value(); + return true; + } + + bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override + { + if (!stack_.empty()) + { + if (stack_.back().is_array()) + { + begin_scalar_value(); + } + if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) + { + break_line(); + } + } + + if (value) + { + sink_.append(true_constant().data(), true_constant().size()); + column_ += true_constant().size(); + } + else + { + sink_.append(false_constant().data(), false_constant().size()); + column_ += false_constant().size(); + } + + end_value(); + return true; + } + + void begin_scalar_value() + { + if (!stack_.empty()) + { + if (stack_.back().count() > 0) + { + sink_.append(comma_str_.data(),comma_str_.length()); + column_ += comma_str_.length(); + } + if (stack_.back().is_multi_line() || stack_.back().is_indent_once()) + { + stack_.back().new_line_after(true); + new_line(); + } + } + } + + void write_bigint_value(const string_view_type& sv) + { + switch (options_.bigint_format()) + { + case bigint_chars_format::number: + { + sink_.append(sv.data(),sv.size()); + column_ += sv.size(); + break; + } + case bigint_chars_format::base64: + { + bigint n = bigint::from_string(sv.data(), sv.length()); + bool is_neg = n < 0; + if (is_neg) + { + n = - n -1; + } + int signum; + std::vector v; + n.write_bytes_be(signum, v); + + sink_.push_back('\"'); + if (is_neg) + { + sink_.push_back('~'); + ++column_; + } + std::size_t length = encode_base64(v.begin(), v.end(), sink_); + sink_.push_back('\"'); + column_ += (length+2); + break; + } + case bigint_chars_format::base64url: + { + bigint n = bigint::from_string(sv.data(), sv.length()); + bool is_neg = n < 0; + if (is_neg) + { + n = - n -1; + } + int signum; + std::vector v; + n.write_bytes_be(signum, v); + + sink_.push_back('\"'); + if (is_neg) + { + sink_.push_back('~'); + ++column_; + } + std::size_t length = encode_base64url(v.begin(), v.end(), sink_); + sink_.push_back('\"'); + column_ += (length+2); + break; + } + default: + { + sink_.push_back('\"'); + sink_.append(sv.data(),sv.size()); + sink_.push_back('\"'); + column_ += (sv.size() + 2); + break; + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + } + + void indent() + { + indent_amount_ += static_cast(options_.indent_size()); + } + + void unindent() + { + indent_amount_ -= static_cast(options_.indent_size()); + } + + void new_line() + { + sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length()); + for (int i = 0; i < indent_amount_; ++i) + { + sink_.push_back(' '); + } + column_ = indent_amount_; + } + + void new_line(std::size_t len) + { + sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length()); + for (std::size_t i = 0; i < len; ++i) + { + sink_.push_back(' '); + } + column_ = len; + } + + void break_line() + { + stack_.back().new_line_after(true); + new_line(); + } + }; + + template,class Allocator=std::allocator> + class basic_compact_json_encoder final : public basic_json_visitor + { + static const std::array& null_constant() + { + static constexpr std::array k{'n','u','l','l'}; + return k; + } + static const std::array& true_constant() + { + static constexpr std::array k{'t','r','u','e'}; + return k; + } + static const std::array& false_constant() + { + static constexpr std::array k{'f','a','l','s','e'}; + return k; + } + public: + using allocator_type = Allocator; + using char_type = CharT; + using typename basic_json_visitor::string_view_type; + using sink_type = Sink; + using string_type = typename basic_json_encode_options::string_type; + + private: + enum class container_type {object, array}; + + class encoding_context + { + container_type type_; + std::size_t count_; + public: + encoding_context(container_type type) noexcept + : type_(type), count_(0) + { + } + + std::size_t count() const + { + return count_; + } + + void increment_count() + { + ++count_; + } + + bool is_array() const + { + return type_ == container_type::array; + } + }; + typedef typename std::allocator_traits:: template rebind_alloc encoding_context_allocator_type; + + Sink sink_; + basic_json_encode_options options_; + jsoncons::detail::write_double fp_; + std::vector stack_; + int nesting_depth_; + + // Noncopyable + basic_compact_json_encoder(const basic_compact_json_encoder&) = delete; + basic_compact_json_encoder& operator=(const basic_compact_json_encoder&) = delete; + public: + basic_compact_json_encoder(Sink&& sink, + const Allocator& alloc = Allocator()) + : basic_compact_json_encoder(std::forward(sink), basic_json_encode_options(), alloc) + { + } + + basic_compact_json_encoder(Sink&& sink, + const basic_json_encode_options& options, + const Allocator& alloc = Allocator()) + : sink_(std::forward(sink)), + options_(options), + fp_(options.float_format(), options.precision()), + stack_(alloc), + nesting_depth_(0) + { + } + + basic_compact_json_encoder(basic_compact_json_encoder&&) = default; + basic_compact_json_encoder& operator=(basic_compact_json_encoder&&) = default; + + ~basic_compact_json_encoder() noexcept + { + JSONCONS_TRY + { + sink_.flush(); + } + JSONCONS_CATCH(...) + { + } + } + + void reset() + { + stack_.clear(); + nesting_depth_ = 0; + } + + void reset(Sink&& sink) + { + sink_ = std::move(sink); + reset(); + } + + private: + // Implementing methods + void visit_flush() override + { + sink_.flush(); + } + + bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) + { + ec = json_errc::max_nesting_depth_exceeded; + return false; + } + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + stack_.emplace_back(container_type::object); + sink_.push_back('{'); + return true; + } + + bool visit_end_object(const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(!stack_.empty()); + --nesting_depth_; + + stack_.pop_back(); + sink_.push_back('}'); + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + + bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) + { + ec = json_errc::max_nesting_depth_exceeded; + return false; + } + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + stack_.emplace_back(container_type::array); + sink_.push_back('['); + return true; + } + + bool visit_end_array(const ser_context&, std::error_code&) override + { + JSONCONS_ASSERT(!stack_.empty()); + --nesting_depth_; + + stack_.pop_back(); + sink_.push_back(']'); + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override + { + if (!stack_.empty() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + sink_.push_back('\"'); + jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); + sink_.push_back('\"'); + sink_.push_back(':'); + return true; + } + + bool visit_null(semantic_tag, const ser_context&, std::error_code&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + sink_.append(null_constant().data(), null_constant().size()); + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + void write_bigint_value(const string_view_type& sv) + { + switch (options_.bigint_format()) + { + case bigint_chars_format::number: + { + sink_.append(sv.data(),sv.size()); + break; + } + case bigint_chars_format::base64: + { + bigint n = bigint::from_string(sv.data(), sv.length()); + bool is_neg = n < 0; + if (is_neg) + { + n = - n -1; + } + int signum; + std::vector v; + n.write_bytes_be(signum, v); + + sink_.push_back('\"'); + if (is_neg) + { + sink_.push_back('~'); + } + encode_base64(v.begin(), v.end(), sink_); + sink_.push_back('\"'); + break; + } + case bigint_chars_format::base64url: + { + bigint n = bigint::from_string(sv.data(), sv.length()); + bool is_neg = n < 0; + if (is_neg) + { + n = - n -1; + } + int signum; + std::vector v; + n.write_bytes_be(signum, v); + + sink_.push_back('\"'); + if (is_neg) + { + sink_.push_back('~'); + } + encode_base64url(v.begin(), v.end(), sink_); + sink_.push_back('\"'); + break; + } + default: + { + sink_.push_back('\"'); + sink_.append(sv.data(),sv.size()); + sink_.push_back('\"'); + break; + } + } + } + + bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + switch (tag) + { + case semantic_tag::bigint: + write_bigint_value(sv); + break; + default: + { + sink_.push_back('\"'); + jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); + sink_.push_back('\"'); + break; + } + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + byte_string_chars_format encoding_hint; + switch (tag) + { + case semantic_tag::base16: + encoding_hint = byte_string_chars_format::base16; + break; + case semantic_tag::base64: + encoding_hint = byte_string_chars_format::base64; + break; + case semantic_tag::base64url: + encoding_hint = byte_string_chars_format::base64url; + break; + default: + encoding_hint = byte_string_chars_format::none; + break; + } + + byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), + encoding_hint, + byte_string_chars_format::base64url); + switch (format) + { + case byte_string_chars_format::base16: + { + sink_.push_back('\"'); + encode_base16(b.begin(),b.end(),sink_); + sink_.push_back('\"'); + break; + } + case byte_string_chars_format::base64: + { + sink_.push_back('\"'); + encode_base64(b.begin(), b.end(), sink_); + sink_.push_back('\"'); + break; + } + case byte_string_chars_format::base64url: + { + sink_.push_back('\"'); + encode_base64url(b.begin(),b.end(),sink_); + sink_.push_back('\"'); + break; + } + default: + { + JSONCONS_UNREACHABLE(); + } + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool visit_double(double value, + semantic_tag, + const ser_context& context, + std::error_code& ec) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + if (JSONCONS_UNLIKELY(!std::isfinite(value))) + { + if ((std::isnan)(value)) + { + if (options_.enable_nan_to_num()) + { + sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length()); + } + else if (options_.enable_nan_to_str()) + { + visit_string(options_.nan_to_str(), semantic_tag::none, context, ec); + } + else + { + sink_.append(null_constant().data(), null_constant().size()); + } + } + else if (value == std::numeric_limits::infinity()) + { + if (options_.enable_inf_to_num()) + { + sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length()); + } + else if (options_.enable_inf_to_str()) + { + visit_string(options_.inf_to_str(), semantic_tag::none, context, ec); + } + else + { + sink_.append(null_constant().data(), null_constant().size()); + } + } + else + { + if (options_.enable_neginf_to_num()) + { + sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length()); + } + else if (options_.enable_neginf_to_str()) + { + visit_string(options_.neginf_to_str(), semantic_tag::none, context, ec); + } + else + { + sink_.append(null_constant().data(), null_constant().size()); + } + } + } + else + { + fp_(value, sink_); + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool visit_int64(int64_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + jsoncons::detail::from_integer(value, sink_); + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool visit_uint64(uint64_t value, + semantic_tag, + const ser_context&, + std::error_code&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + jsoncons::detail::from_integer(value, sink_); + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + + bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override + { + if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) + { + sink_.push_back(','); + } + + if (value) + { + sink_.append(true_constant().data(), true_constant().size()); + } + else + { + sink_.append(false_constant().data(), false_constant().size()); + } + + if (!stack_.empty()) + { + stack_.back().increment_count(); + } + return true; + } + }; + + using json_stream_encoder = basic_json_encoder>; + using wjson_stream_encoder = basic_json_encoder>; + using compact_json_stream_encoder = basic_compact_json_encoder>; + using compact_wjson_stream_encoder = basic_compact_json_encoder>; + + using json_string_encoder = basic_json_encoder>; + using wjson_string_encoder = basic_json_encoder>; + using compact_json_string_encoder = basic_compact_json_encoder>; + using compact_wjson_string_encoder = basic_compact_json_encoder>; + + #if !defined(JSONCONS_NO_DEPRECATED) + template> + using basic_json_serializer = basic_json_encoder; + + template> + using basic_json_compressed_serializer = basic_compact_json_encoder; + + template> + using basic_json_compressed_encoder = basic_compact_json_encoder; + + JSONCONS_DEPRECATED_MSG("Instead, use compact_json_stream_encoder") typedef basic_compact_json_encoder> json_compressed_stream_encoder; + JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_stream_encoder")typedef basic_compact_json_encoder> wjson_compressed_stream_encoder; + JSONCONS_DEPRECATED_MSG("Instead, use compact_json_string_encoder") typedef basic_compact_json_encoder> json_compressed_string_encoder; + JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_string_encoder")typedef basic_compact_json_encoder> wjson_compressed_string_encoder; + + JSONCONS_DEPRECATED_MSG("Instead, use json_stream_encoder") typedef json_stream_encoder json_encoder; + JSONCONS_DEPRECATED_MSG("Instead, use wjson_stream_encoder") typedef wjson_stream_encoder wjson_encoder; + JSONCONS_DEPRECATED_MSG("Instead, use compact_json_stream_encoder") typedef compact_json_stream_encoder compact_json_encoder; + JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_stream_encoder") typedef compact_wjson_stream_encoder wcompact_json_encoder; + + JSONCONS_DEPRECATED_MSG("Instead, use json_stream_encoder") typedef basic_json_encoder> json_serializer; + JSONCONS_DEPRECATED_MSG("Instead, use wjson_stream_encoder") typedef basic_json_encoder> wjson_serializer; + + JSONCONS_DEPRECATED_MSG("Instead, use compact_json_stream_encoder") typedef basic_compact_json_encoder> json_compressed_serializer; + JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_stream_encoder") typedef basic_compact_json_encoder> wjson_compressed_serializer; + + JSONCONS_DEPRECATED_MSG("Instead, use json_string_encoder") typedef basic_json_encoder> json_string_serializer; + JSONCONS_DEPRECATED_MSG("Instead, use wjson_string_encoder") typedef basic_json_encoder> wjson_string_serializer; + + JSONCONS_DEPRECATED_MSG("Instead, use compact_json_string_encoder") typedef basic_compact_json_encoder> json_compressed_string_serializer; + JSONCONS_DEPRECATED_MSG("Instead, use wcompact_json_string_encoder") typedef basic_compact_json_encoder> wjson_compressed_string_serializer; + #endif + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/json_error.hpp b/include/jsoncons/json_error.hpp new file mode 100644 index 0000000..f305948 --- /dev/null +++ b/include/jsoncons/json_error.hpp @@ -0,0 +1,156 @@ +/// 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_HPP +#define JSONCONS_JSON_ERROR_HPP + +#include +#include + +namespace jsoncons { + + enum class json_errc + { + success = 0, + unexpected_eof = 1, + source_error, + syntax_error, + extra_character, + max_nesting_depth_exceeded, + single_quote, + illegal_character_in_string, + extra_comma, + expected_key, + 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_rbrace, + expected_comma_or_rbracket, + unexpected_rbracket, + unexpected_rbrace, + illegal_comment, + expected_continuation_byte, + over_long_utf8_sequence, + illegal_codepoint, + illegal_surrogate_value, + unpaired_high_surrogate, + illegal_unicode_character + }; + + class json_error_category_impl + : public std::error_category + { + public: + const char* name() const noexcept override + { + return "jsoncons/json"; + } + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case json_errc::unexpected_eof: + return "Unexpected end of file"; + case json_errc::source_error: + return "Source error"; + case json_errc::syntax_error: + return "JSON syntax_error"; + case json_errc::extra_character: + return "Unexpected non-whitespace character after JSON text"; + case json_errc::max_nesting_depth_exceeded: + return "Data item nesting exceeds limit in options"; + case json_errc::single_quote: + return "JSON strings cannot be quoted with single quotes"; + case json_errc::illegal_character_in_string: + return "Illegal character in string"; + case json_errc::extra_comma: + return "Extra comma"; + case json_errc::expected_key: + return "Expected object member key"; + case json_errc::expected_value: + return "Expected value"; + case json_errc::invalid_value: + return "Invalid value"; + case json_errc::expected_colon: + return "Expected name separator ':'"; + case json_errc::illegal_control_character: + return "Illegal control character in string"; + case json_errc::illegal_escaped_character: + return "Illegal escaped character in string"; + case json_errc::expected_codepoint_surrogate_pair: + return "Invalid codepoint, expected another \\u token to begin the second half of a codepoint surrogate pair."; + case json_errc::invalid_hex_escape_sequence: + return "Invalid codepoint, expected hexadecimal digit."; + case json_errc::invalid_unicode_escape_sequence: + return "Invalid codepoint, expected four hexadecimal digits."; + case json_errc::leading_zero: + return "A number cannot have a leading zero"; + case json_errc::invalid_number: + return "Invalid number"; + case json_errc::expected_comma_or_rbrace: + return "Expected comma or right brace '}'"; + case json_errc::expected_comma_or_rbracket: + return "Expected comma or right bracket ']'"; + case json_errc::unexpected_rbrace: + return "Unexpected right brace '}'"; + case json_errc::unexpected_rbracket: + return "Unexpected right bracket ']'"; + case json_errc::illegal_comment: + return "Illegal comment"; + case json_errc::expected_continuation_byte: + return "Expected continuation byte"; + case json_errc::over_long_utf8_sequence: + return "Over long UTF-8 sequence"; + case json_errc::illegal_codepoint: + return "Illegal codepoint (>= 0xd800 && <= 0xdfff)"; + case json_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case json_errc::unpaired_high_surrogate: + return "Expected low surrogate following the high surrogate"; + case json_errc::illegal_unicode_character: + return "Illegal unicode character"; + 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_errc result) + { + return std::error_code(static_cast(result),json_error_category()); + } + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use json_errc") typedef json_errc json_parser_errc; + +JSONCONS_DEPRECATED_MSG("Instead, use json_errc") typedef json_errc json_parse_errc; +#endif + +} // jsoncons + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +#endif diff --git a/include/jsoncons/json_exception.hpp b/include/jsoncons/json_exception.hpp new file mode 100644 index 0000000..e25d401 --- /dev/null +++ b/include/jsoncons/json_exception.hpp @@ -0,0 +1,241 @@ +// 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 // std::string +#include // std::ostringstream +#include // std::error_code +#include // unicode_traits::convert +#include +#include + +namespace jsoncons { + + // json_exception + + class json_exception + { + public: + virtual ~json_exception() noexcept = default; + virtual const char* what() const noexcept = 0; + }; + + // json_runtime_error + + template + class json_runtime_error + { + }; + + template + class json_runtime_error::value && + type_traits::is_constructible_from_string::value>::type> + : public Base, public virtual json_exception + { + public: + json_runtime_error(const std::string& s) noexcept + : Base(s) + { + } + ~json_runtime_error() noexcept + { + } + const char* what() const noexcept override + { + return Base::what(); + } + }; + + class key_not_found : public std::out_of_range, public virtual json_exception + { + std::string name_; + mutable std::string what_; + public: + template + explicit key_not_found(const CharT* key, std::size_t length) noexcept + : std::out_of_range("Key not found") + { + JSONCONS_TRY + { + unicode_traits::convert(key, length, name_, + unicode_traits::conv_flags::strict); + } + JSONCONS_CATCH(...) + { + } + } + + virtual ~key_not_found() noexcept + { + } + + const char* what() const noexcept override + { + if (what_.empty()) + { + JSONCONS_TRY + { + what_.append(std::out_of_range::what()); + what_.append(": '"); + what_.append(name_); + what_.append("'"); + return what_.c_str(); + } + JSONCONS_CATCH(...) + { + return std::out_of_range::what(); + } + } + else + { + return what_.c_str(); + } + } + }; + + class not_an_object : public std::runtime_error, public virtual json_exception + { + std::string name_; + mutable std::string what_; + public: + template + explicit not_an_object(const CharT* key, std::size_t length) noexcept + : std::runtime_error("Attempting to access a member of a value that is not an object") + { + JSONCONS_TRY + { + unicode_traits::convert(key, length, name_, + unicode_traits::conv_flags::strict); + } + JSONCONS_CATCH(...) + { + } + } + + virtual ~not_an_object() noexcept + { + } + const char* what() const noexcept override + { + if (what_.empty()) + { + JSONCONS_TRY + { + what_.append(std::runtime_error::what()); + what_.append(": '"); + what_.append(name_); + what_.append("'"); + return what_.c_str(); + } + JSONCONS_CATCH(...) + { + return std::runtime_error::what(); + } + } + else + { + return what_.c_str(); + } + } + }; + + class ser_error : public std::system_error, public virtual json_exception + { + std::size_t line_number_; + std::size_t column_number_; + mutable std::string what_; + public: + ser_error(std::error_code ec) + : std::system_error(ec), line_number_(0), column_number_(0) + { + } + ser_error(std::error_code ec, const std::string& what_arg) + : std::system_error(ec, what_arg), line_number_(0), column_number_(0) + { + } + ser_error(std::error_code ec, std::size_t position) + : std::system_error(ec), line_number_(0), column_number_(position) + { + } + ser_error(std::error_code ec, std::size_t line, std::size_t column) + : std::system_error(ec), line_number_(line), column_number_(column) + { + } + ser_error(const ser_error& other) = default; + + ser_error(ser_error&& other) = default; + + const char* what() const noexcept override + { + if (what_.empty()) + { + JSONCONS_TRY + { + what_.append(std::system_error::what()); + if (line_number_ != 0 && column_number_ != 0) + { + what_.append(" at line "); + what_.append(std::to_string(line_number_)); + what_.append(" and column "); + what_.append(std::to_string(column_number_)); + } + else if (column_number_ != 0) + { + what_.append(" at position "); + what_.append(std::to_string(column_number_)); + } + return what_.c_str(); + } + JSONCONS_CATCH(...) + { + return std::system_error::what(); + } + } + else + { + return what_.c_str(); + } + } + + std::size_t line() const noexcept + { + return line_number_; + } + + std::size_t column() const noexcept + { + return column_number_; + } + + #if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use line()") + std::size_t line_number() const noexcept + { + return line(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use column()") + std::size_t column_number() const noexcept + { + return column(); + } + #endif + }; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error serialization_error; +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error json_parse_exception; +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error parse_exception; +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error parse_error; +typedef ser_error codec_error; +#endif + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/json_filter.hpp b/include/jsoncons/json_filter.hpp new file mode 100644 index 0000000..cc93c73 --- /dev/null +++ b/include/jsoncons/json_filter.hpp @@ -0,0 +1,653 @@ +// 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 + +#include + +namespace jsoncons { + +template +class basic_json_filter : public basic_json_visitor +{ +public: + using typename basic_json_visitor::char_type; + using typename basic_json_visitor::string_view_type; +private: + basic_json_visitor* destination_; + + // noncopyable + basic_json_filter(const basic_json_filter&) = delete; + basic_json_filter& operator=(const basic_json_filter&) = delete; +public: + basic_json_filter(basic_json_visitor& visitor) + : destination_(std::addressof(visitor)) + { + } + + // moveable + basic_json_filter(basic_json_filter&&) = default; + basic_json_filter& operator=(basic_json_filter&&) = default; + + basic_json_visitor& destination() + { + return *destination_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + JSONCONS_DEPRECATED_MSG("Instead, use destination()") + basic_json_visitor& to_handler() + { + return destination_; + } + JSONCONS_DEPRECATED_MSG("Instead, use destination") + basic_json_visitor& input_handler() + { + return destination_; + } + + JSONCONS_DEPRECATED_MSG("Instead, use destination") + basic_json_visitor& downstream_handler() + { + return destination_; + } + + JSONCONS_DEPRECATED_MSG("Instead, use destination") + basic_json_visitor& destination_handler() + { + return destination_; + } +#endif + +private: + void visit_flush() override + { + destination_->flush(); + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->begin_object(tag, context, ec); + } + + bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->begin_object(length, tag, context, ec); + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + return destination_->end_object(context, ec); + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->begin_array(tag, context, ec); + } + + bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->begin_array(length, tag, context, ec); + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + return destination_->end_array(context, ec); + } + + bool visit_key(const string_view_type& name, + const ser_context& context, + std::error_code& ec) override + { + return destination_->key(name, context, ec); + } + + bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->string_value(value, tag, context, ec); + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->byte_string_value(b, tag, context, ec); + } + + bool visit_byte_string(const byte_string_view& b, + uint64_t ext_tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->byte_string_value(b, ext_tag, context, ec); + } + + bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->uint64_value(value, tag, context, ec); + } + + bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->int64_value(value, tag, context, ec); + } + + bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->half_value(value, tag, context, ec); + } + + bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->double_value(value, tag, context, ec); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->bool_value(value, tag, context, ec); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->null_value(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(half_arg_t, + const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(half_arg, s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->begin_multi_dim(shape, tag, context, ec); + } + + bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) override + { + return destination_->end_multi_dim(context, ec); + } +}; + +template +class basic_rename_object_key_filter : public basic_json_filter +{ +public: + using typename basic_json_filter::string_view_type; + +private: + std::basic_string name_; + std::basic_string new_name_; +public: + basic_rename_object_key_filter(const std::basic_string& name, + const std::basic_string& new_name, + basic_json_visitor& visitor) + : basic_json_filter(visitor), + name_(name), new_name_(new_name) + { + } + +private: + bool visit_key(const string_view_type& name, + const ser_context& context, + std::error_code& ec) override + { + if (name == name_) + { + return this->destination().key(new_name_,context, ec); + } + else + { + return this->destination().key(name,context,ec); + } + } +}; + +template +class json_visitor_adaptor_base : public From +{ +public: + using typename From::string_view_type; +private: + To* destination_; + + // noncopyable + json_visitor_adaptor_base(const json_visitor_adaptor_base&) = delete; + json_visitor_adaptor_base& operator=(const json_visitor_adaptor_base&) = delete; +public: + json_visitor_adaptor_base(To& visitor) + : destination_(std::addressof(visitor)) + { + } + + // moveable + json_visitor_adaptor_base(json_visitor_adaptor_base&&) = default; + json_visitor_adaptor_base& operator=(json_visitor_adaptor_base&&) = default; + + To& destination() + { + return *destination_; + } + +private: + void visit_flush() override + { + destination_->flush(); + } + + bool visit_begin_object(semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->begin_object(tag, context, ec); + } + + bool visit_begin_object(std::size_t length, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->begin_object(length, tag, context, ec); + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + return destination_->end_object(context, ec); + } + + bool visit_begin_array(semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->begin_array(tag, context, ec); + } + + bool visit_begin_array(std::size_t length, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->begin_array(length, tag, context, ec); + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + return destination_->end_array(context, ec); + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->byte_string_value(b, tag, context, ec); + } + + bool visit_byte_string(const byte_string_view& b, + uint64_t ext_tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->byte_string_value(b, ext_tag, context, ec); + } + + bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->half_value(value, tag, context, ec); + } + + bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->double_value(value, tag, context, ec); + } + + bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->int64_value(value, tag, context, ec); + } + + bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->uint64_value(value, tag, context, ec); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->bool_value(value, tag, context, ec); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_->null_value(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(half_arg_t, + const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(half_arg, s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->typed_array(s, tag, context, ec); + } + + bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_->begin_multi_dim(shape, tag, context, ec); + } + + bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) override + { + return destination_->end_multi_dim(context, ec); + } + +}; + +template +class json_visitor_adaptor +{ +}; + +template +class json_visitor_adaptor::value && + type_traits::is_narrow_character::value>::type> : public json_visitor_adaptor_base +{ + using supertype = json_visitor_adaptor_base; + using to_char_type = typename To::char_type; + using from_char_type = typename From::char_type; +public: + using typename From::string_view_type; + using supertype::destination; +private: + + // noncopyable + json_visitor_adaptor(const json_visitor_adaptor&) = delete; + json_visitor_adaptor& operator=(const json_visitor_adaptor&) = delete; +public: + json_visitor_adaptor(To& visitor) + : supertype(visitor) + { + } + + // moveable + json_visitor_adaptor(json_visitor_adaptor&&) = default; + json_visitor_adaptor& operator=(json_visitor_adaptor&&) = default; + +private: + + bool visit_key(const string_view_type& key, + const ser_context& context, + std::error_code& ec) override + { + return destination().key(string_view_type(reinterpret_cast(key.data()),key.size()), context, ec); + } + + bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination().string_value(string_view_type(reinterpret_cast(value.data()),value.size()), tag, context, ec); + } +}; + +template +class json_visitor_adaptor::value && + type_traits::is_narrow_character::value)>::type> : public json_visitor_adaptor_base +{ + using supertype = json_visitor_adaptor_base; +public: + using typename From::string_view_type; + using supertype::destination; +private: + + // noncopyable + json_visitor_adaptor(const json_visitor_adaptor&) = delete; + json_visitor_adaptor& operator=(const json_visitor_adaptor&) = delete; +public: + json_visitor_adaptor(To& visitor) + : supertype(visitor) + { + } + + // moveable + json_visitor_adaptor(json_visitor_adaptor&&) = default; + json_visitor_adaptor& operator=(json_visitor_adaptor&&) = default; + +private: + + bool visit_key(const string_view_type& name, + const ser_context& context, + std::error_code& ec) override + { + std::basic_string target; + auto result = unicode_traits::convert(name.data(), name.size(), target, unicode_traits::conv_flags::strict); + if (result.ec != unicode_traits::conv_errc()) + { + ec = result.ec; + } + return destination().key(target, context, ec); + } + + bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + std::basic_string target; + auto result = unicode_traits::convert(value.data(), value.size(), + target,unicode_traits::conv_flags::strict); + if (result.ec != unicode_traits::conv_errc()) + { + JSONCONS_THROW(ser_error(result.ec)); + } + return destination().string_value(target, tag, context, ec); + } +}; + +template +json_visitor_adaptor make_json_visitor_adaptor(To& to) +{ + return json_visitor_adaptor(to); +} + +using json_filter = basic_json_filter; +using wjson_filter = basic_json_filter; +using rename_object_key_filter = basic_rename_object_key_filter; +using wrename_object_key_filter = basic_rename_object_key_filter; + +#if !defined(JSONCONS_NO_DEPRECATED) +template +using basic_json_content_filter = basic_json_filter; +JSONCONS_DEPRECATED_MSG("Instead, use json_filter") typedef basic_json_filter json_content_filter; +JSONCONS_DEPRECATED_MSG("Instead, use wjson_filter") typedef basic_json_filter wjson_content_filter; +JSONCONS_DEPRECATED_MSG("Instead, use rename_object_key_filter") typedef basic_rename_object_key_filter rename_name_filter; +JSONCONS_DEPRECATED_MSG("Instead, use wrename_object_key_filter") typedef basic_rename_object_key_filter wrename_name_filter; +JSONCONS_DEPRECATED_MSG("Instead, use rename_object_key_filter") typedef basic_rename_object_key_filter rename_object_member_filter; +JSONCONS_DEPRECATED_MSG("Instead, use wrename_object_key_filter") typedef basic_rename_object_key_filter wrename_object_member_filter; +#endif + +} + +#endif diff --git a/include/jsoncons/json_fwd.hpp b/include/jsoncons/json_fwd.hpp new file mode 100644 index 0000000..d9b44cf --- /dev/null +++ b/include/jsoncons/json_fwd.hpp @@ -0,0 +1,23 @@ +// 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_FWD_HPP +#define JSONCONS_JSON_FWD_HPP + +#include // std::allocator + +namespace jsoncons { + +struct sorted_policy; + +template > +class basic_json; + +} + +#endif diff --git a/include/jsoncons/json_object.hpp b/include/jsoncons/json_object.hpp new file mode 100644 index 0000000..76e2cd0 --- /dev/null +++ b/include/jsoncons/json_object.hpp @@ -0,0 +1,1772 @@ +// 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_OBJECT_HPP +#define JSONCONS_JSON_OBJECT_HPP + +#include +#include +#include +#include +#include +#include // std::sort, std::stable_sort, std::lower_bound, std::unique +#include +#include +#include // std::iterator_traits +#include // std::allocator +#include // std::move +#include // assert +#include // std::enable_if +#include +#include +#include + +namespace jsoncons { + + struct sorted_unique_range_tag + { + explicit sorted_unique_range_tag() = default; + }; + + // key_value + + template + class key_value + { + public: + using key_type = KeyT; + using value_type = ValueT; + using allocator_type = typename ValueT::allocator_type; + using string_view_type = typename value_type::string_view_type; + private: + + key_type key_; + value_type value_; + public: + + key_value() noexcept + { + } + + key_value(const key_type& name, const value_type& val) + : key_(name), value_(val) + { + } + + key_value(const string_view_type& name) + : key_(name) + { + } + + template + key_value(const key_type& name, Args&& ... args) + : key_(name), value_(std::forward(args)...) + { + } + + template + key_value(key_type&& name, Args&& ... args) noexcept + : key_(std::forward(name)), value_(std::forward(args)...) + { + } + + key_value(const key_value& member) + : key_(member.key_), value_(member.value_) + { + } + + key_value(key_value&& member) noexcept + : key_(std::move(member.key_)), value_(std::move(member.value_)) + { + } + template + JSONCONS_CONSTEXPR key_value(std::piecewise_construct_t /*unused*/, std::tuple a, + std::tuple + b) noexcept(noexcept(key_value(std::declval&>(), + std::declval&>(), + jsoncons::type_traits::index_sequence_for(), + jsoncons::type_traits::index_sequence_for()))) + : key_value(a, b, jsoncons::type_traits::index_sequence_for(), + jsoncons::type_traits::index_sequence_for()) { + } + + template + key_value(std::tuple& a, std::tuple& b, jsoncons::type_traits::index_sequence /*unused*/, jsoncons::type_traits::index_sequence /*unused*/) noexcept( + noexcept(KeyT(std::forward(std::get( + std::declval&>()))...)) && noexcept(ValueT(std:: + forward(std::get( + std::declval&>()))...))) + : key_(std::forward(std::get(a))...) + , value_(std::forward(std::get(b))...) { + // make visual studio compiler happy about warning about unused a & b. + // Visual studio's key_value implementation disables warning 4100. + (void)a; + (void)b; + } + + const key_type& key() const + { + return key_; + } + + value_type& value() + { + return value_; + } + + const value_type& value() const + { + return value_; + } + + template + void value(T&& value) + { + value_ = std::forward(value); + } + + void swap(key_value& member) noexcept + { + key_.swap(member.key_); + value_.swap(member.value_); + } + + key_value& operator=(const key_value& member) + { + if (this != & member) + { + key_ = member.key_; + value_ = member.value_; + } + return *this; + } + + key_value& operator=(key_value&& member) noexcept + { + 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) + JSONCONS_DEPRECATED_MSG("Instead, use key()") + const key_type& name() const + { + return key_; + } + #endif + + friend bool operator==(const key_value& lhs, const key_value& rhs) noexcept + { + return lhs.key_ == rhs.key_ && lhs.value_ == rhs.value_; + } + + friend bool operator!=(const key_value& lhs, const key_value& rhs) noexcept + { + return !(lhs == rhs); + } + + friend bool operator<(const key_value& lhs, const key_value& rhs) noexcept + { + if (lhs.key_ < rhs.key_) + { + return true; + } + if (lhs.key_ == rhs.key_ && lhs.value_ < rhs.value_) + { + return true; + } + return false; + } + + friend bool operator<=(const key_value& lhs, const key_value& rhs) noexcept + { + return !(rhs < lhs); + } + + friend bool operator>(const key_value& lhs, const key_value& rhs) noexcept + { + return !(lhs <= rhs); + } + + friend bool operator>=(const key_value& lhs, const key_value& rhs) noexcept + { + return !(lhs < rhs); + } + + friend void swap(key_value& a, key_value& b) noexcept( + noexcept(std::declval().swap(std::declval()))) + { + a.swap(b); + } + }; + + template + struct get_key_value + { + using key_value_type = key_value; + + template + key_value_type operator()(const std::pair& p) + { + return key_value_type(p.first,p.second); + } + template + key_value_type operator()(std::pair&& p) + { + return key_value_type(std::forward(p.first),std::forward(p.second)); + } + template + const key_value_type& operator()(const key_value& p) + { + return p; + } + template + key_value_type operator()(key_value&& p) + { + return std::move(p); + } + }; + + struct sort_key_order + { + explicit sort_key_order() = default; + }; + + struct preserve_key_order + { + explicit preserve_key_order() = default; + }; + + + // Sort keys + template class SequenceContainer = std::vector> + class sorted_json_object : public allocator_holder + { + public: + using allocator_type = typename Json::allocator_type; + using key_type = KeyT; + using key_value_type = key_value; + using char_type = typename Json::char_type; + using string_view_type = typename Json::string_view_type; + private: + struct Comp + { + bool operator() (const key_value_type& kv, string_view_type k) const { return kv.key() < k; } + bool operator() (string_view_type k, const key_value_type& kv) const { return k < kv.key(); } + }; + + using key_value_allocator_type = typename std::allocator_traits:: template rebind_alloc; + using key_value_container_type = SequenceContainer; + + key_value_container_type members_; + public: + using iterator = typename key_value_container_type::iterator; + using const_iterator = typename key_value_container_type::const_iterator; + + using allocator_holder::get_allocator; + + sorted_json_object() + { + } + + explicit sorted_json_object(const allocator_type& alloc) + : allocator_holder(alloc), + members_(key_value_allocator_type(alloc)) + { + } + + sorted_json_object(const sorted_json_object& val) + : allocator_holder(val.get_allocator()), + members_(val.members_) + { + } + + sorted_json_object(sorted_json_object&& val) + : allocator_holder(val.get_allocator()), + members_(std::move(val.members_)) + { + } + + sorted_json_object& operator=(const sorted_json_object& val) + { + allocator_holder::operator=(val.get_allocator()); + members_ = val.members_; + return *this; + } + + sorted_json_object& operator=(sorted_json_object&& val) + { + val.swap(*this); + return *this; + } + + sorted_json_object(const sorted_json_object& val, const allocator_type& alloc) + : allocator_holder(alloc), + members_(val.members_,key_value_allocator_type(alloc)) + { + } + + sorted_json_object(sorted_json_object&& val,const allocator_type& alloc) + : allocator_holder(alloc), members_(std::move(val.members_),key_value_allocator_type(alloc)) + { + } + + template + sorted_json_object(InputIt first, InputIt last) + { + std::size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + std::stable_sort(members_.begin(),members_.end(), + [](const key_value_type& a, const key_value_type& b) -> bool {return a.key().compare(b.key()) < 0;}); + auto it = std::unique(members_.begin(), members_.end(), + [](const key_value_type& a, const key_value_type& b) -> bool { return !(a.key().compare(b.key()));}); + members_.erase(it, members_.end()); + } + + template + sorted_json_object(InputIt first, InputIt last, + const allocator_type& alloc) + : allocator_holder(alloc), + members_(key_value_allocator_type(alloc)) + { + std::size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + std::stable_sort(members_.begin(),members_.end(), + [](const key_value_type& a, const key_value_type& b) -> bool {return a.key().compare(b.key()) < 0;}); + auto it = std::unique(members_.begin(), members_.end(), + [](const key_value_type& a, const key_value_type& b) -> bool { return !(a.key().compare(b.key()));}); + members_.erase(it, members_.end()); + } + + sorted_json_object(const std::initializer_list,Json>>& init, + const allocator_type& alloc = allocator_type()) + : allocator_holder(alloc), + members_(key_value_allocator_type(alloc)) + { + members_.reserve(init.size()); + for (auto& item : init) + { + insert_or_assign(item.first, item.second); + } + } + + ~sorted_json_object() noexcept + { + flatten_and_destroy(); + } + + bool empty() const + { + return members_.empty(); + } + + void swap(sorted_json_object& val) noexcept + { + members_.swap(val.members_); + } + + iterator begin() + { + return members_.begin(); + } + + iterator end() + { + return members_.end(); + } + + const_iterator begin() const + { + return members_.begin(); + } + + const_iterator end() const + { + return members_.end(); + } + + std::size_t size() const {return members_.size();} + + std::size_t capacity() const {return members_.capacity();} + + void clear() {members_.clear();} + + void shrink_to_fit() + { + for (std::size_t i = 0; i < members_.size(); ++i) + { + members_[i].shrink_to_fit(); + } + members_.shrink_to_fit(); + } + + void reserve(std::size_t n) {members_.reserve(n);} + + Json& at(std::size_t i) + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + const Json& at(std::size_t i) const + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + iterator find(const string_view_type& name) noexcept + { + auto p = std::equal_range(members_.begin(),members_.end(), name, + Comp()); + return p.first == p.second ? members_.end() : p.first; + } + + const_iterator find(const string_view_type& name) const noexcept + { + auto p = std::equal_range(members_.begin(),members_.end(), name, + Comp()); + return p.first == p.second ? members_.end() : p.first; + } + + iterator erase(const_iterator pos) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = members_.begin() + (pos - members_.begin()); + return members_.erase(it); + #else + return members_.erase(pos); + #endif + } + + iterator erase(const_iterator first, const_iterator last) + { + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it1 = members_.begin() + (first - members_.begin()); + iterator it2 = members_.begin() + (last - members_.begin()); + return members_.erase(it1,it2); + #else + return members_.erase(first,last); + #endif + } + + void erase(const string_view_type& name) + { + auto it = find(name); + if (it != members_.end()) + { + members_.erase(it); + } + } + + template + void insert(InputIt first, InputIt last, Convert convert) + { + std::size_t count = std::distance(first,last); + members_.reserve(members_.size() + count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + std::stable_sort(members_.begin(),members_.end(), + [](const key_value_type& a, const key_value_type& b) -> bool {return a.key().compare(b.key()) < 0;}); + auto it = std::unique(members_.begin(), members_.end(), + [](const key_value_type& a, const key_value_type& b) -> bool { return !(a.key().compare(b.key()));}); + members_.erase(it, members_.end()); + } + + template + void insert(sorted_unique_range_tag, InputIt first, InputIt last, Convert convert) + { + if (first != last) + { + std::size_t count = std::distance(first,last); + members_.reserve(members_.size() + count); + + auto it = find(convert(*first).key()); + if (it != members_.end()) + { + for (auto s = first; s != last; ++s) + { + it = members_.emplace(it, convert(*s)); + } + } + else + { + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + } + } + } + + // insert_or_assign + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(value)); + inserted = true; + it = members_.begin() + members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward(value))); + inserted = false; // assigned + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(value)); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + inserted = true; + it = members_.begin() + members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward(value), get_allocator())); + inserted = false; // assigned + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + inserted = true; + } + return std::make_pair(it,inserted); + } + + // try_emplace + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(args)...); + it = members_.begin() + members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + it = members_.begin() + members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it = hint; + + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + Comp()); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(args)...); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(args)...); + } + + return it; + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it = hint; + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + Comp()); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(args)...); + } + return it; + } + + // insert_or_assign + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + [](const key_value_type& a, const string_view_type& k) -> bool {return string_view_type(a.key()).compare(k) < 0;}); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + [](const key_value_type& a, const string_view_type& k) -> bool {return string_view_type(a.key()).compare(k) < 0;}); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end()), + std::forward(value)); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward(value))); + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end()), + std::forward(value)); + } + return it; + } + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,members_.end(), name, + Comp()); + } + else + { + it = std::lower_bound(members_.begin(),members_.end(), name, + Comp()); + } + + if (it == members_.end()) + { + members_.emplace_back(key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + it = members_.begin() + (members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward(value),get_allocator())); + } + else + { + it = members_.emplace(it, + key_type(name.begin(),name.end(), get_allocator()), + std::forward(value),get_allocator()); + } + return it; + } + + // merge + + void merge(const sorted_json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(sorted_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(members_.begin(),members_.end(), (*it).key(), + Comp()); + if (pos == members_.end() ) + { + members_.emplace_back(*it); + } + else if ((*it).key() != pos->key()) + { + members_.emplace(pos,*it); + } + } + } + + void merge(iterator hint, const sorted_json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, (*it).key(),(*it).value()); + } + } + + void merge(iterator hint, sorted_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 != members_.end() && hint->key() <= (*it).key()) + { + pos = std::lower_bound(hint,members_.end(), (*it).key(), + Comp()); + } + else + { + pos = std::lower_bound(members_.begin(),members_.end(), (*it).key(), + Comp()); + } + if (pos == members_.end() ) + { + members_.emplace_back(*it); + hint = members_.begin() + (members_.size() - 1); + } + else if ((*it).key() != pos->key()) + { + hint = members_.emplace(pos,*it); + } + } + } + + // merge_or_update + + void merge_or_update(const sorted_json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign((*it).key(),(*it).value()); + } + } + + void merge_or_update(sorted_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(members_.begin(),members_.end(), (*it).key(), + Comp()); + if (pos == members_.end() ) + { + members_.emplace_back(*it); + } + else + { + pos->value((*it).value()); + } + } + } + + void merge_or_update(iterator hint, const sorted_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, sorted_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 != members_.end() && hint->key() <= (*it).key()) + { + pos = std::lower_bound(hint,members_.end(), (*it).key(), + Comp()); + } + else + { + pos = std::lower_bound(members_.begin(),members_.end(), (*it).key(), + Comp()); + } + if (pos == members_.end() ) + { + members_.emplace_back(*it); + hint = members_.begin() + (members_.size() - 1); + } + else + { + pos->value((*it).value()); + hint = pos; + } + } + } + + bool operator==(const sorted_json_object& rhs) const + { + return members_ == rhs.members_; + } + + bool operator<(const sorted_json_object& rhs) const + { + return members_ < rhs.members_; + } + private: + + void flatten_and_destroy() noexcept + { + if (!members_.empty()) + { + json_array temp(get_allocator()); + + for (auto& kv : members_) + { + switch (kv.value().storage_kind()) + { + case json_storage_kind::array_value: + case json_storage_kind::object_value: + if (!kv.value().empty()) + { + temp.emplace_back(std::move(kv.value())); + } + break; + default: + break; + } + } + } + } + }; + + // Preserve order + template class SequenceContainer = std::vector> + class order_preserving_json_object : public allocator_holder + { + public: + using allocator_type = typename Json::allocator_type; + using char_type = typename Json::char_type; + using key_type = KeyT; + //using mapped_type = Json; + using string_view_type = typename Json::string_view_type; + using key_value_type = key_value; + //using implementation_policy = typename Json::implementation_policy; + private: + + using key_value_allocator_type = typename std::allocator_traits:: template rebind_alloc; + using key_value_container_type = SequenceContainer; + typedef typename std::allocator_traits:: template rebind_alloc index_allocator_type; + //using index_container_type = typename implementation_policy::template sequence_container_type; + using index_container_type = SequenceContainer; + + key_value_container_type members_; + index_container_type index_; + + struct Comp + { + const key_value_container_type& members_; + + Comp(const key_value_container_type& members_) + : members_(members_) + { + } + + bool operator() (std::size_t i, string_view_type k) const { return members_.at(i).key() < k; } + bool operator() (string_view_type k, std::size_t i) const { return k < members_.at(i).key(); } + }; + public: + using iterator = typename key_value_container_type::iterator; + using const_iterator = typename key_value_container_type::const_iterator; + + using allocator_holder::get_allocator; + + order_preserving_json_object() + { + } + order_preserving_json_object(const allocator_type& alloc) + : allocator_holder(alloc), + members_(key_value_allocator_type(alloc)), + index_(index_allocator_type(alloc)) + { + } + + order_preserving_json_object(const order_preserving_json_object& val) + : allocator_holder(val.get_allocator()), + members_(val.members_), + index_(val.index_) + { + } + + order_preserving_json_object(order_preserving_json_object&& val) + : allocator_holder(val.get_allocator()), + members_(std::move(val.members_)), + index_(std::move(val.index_)) + { + } + + order_preserving_json_object(const order_preserving_json_object& val, const allocator_type& alloc) + : allocator_holder(alloc), + members_(val.members_,key_value_allocator_type(alloc)), + index_(val.index_,index_allocator_type(alloc)) + { + } + + order_preserving_json_object(order_preserving_json_object&& val,const allocator_type& alloc) + : allocator_holder(alloc), + members_(std::move(val.members_),key_value_allocator_type(alloc)), + index_(std::move(val.index_),index_allocator_type(alloc)) + { + } + + template + order_preserving_json_object(InputIt first, InputIt last) + { + std::size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + + build_index(); + auto last_unique = std::unique(index_.begin(), index_.end(), + [&](std::size_t a, std::size_t b) { return !(members_.at(a).key().compare(members_.at(b).key())); }); + + if (last_unique != index_.end()) + { + index_.erase(last_unique, index_.end()); + std::sort(index_.begin(), index_.end()); + + auto result = index_.rbegin(); + if (*result != members_.size()) + { + members_.erase(members_.begin() + (*result + 1), members_.end()); + } + for (auto it = index_.rbegin() + 1; it != index_.rend(); ++it, ++result) + { + if (*result - *it > 1) + { + members_.erase(members_.begin() + (*it + 1), members_.begin() + *result); + } + } + } + build_index(); + } + + template + order_preserving_json_object(InputIt first, InputIt last, + const allocator_type& alloc) + : allocator_holder(alloc), + members_(key_value_allocator_type(alloc)), + index_(index_allocator_type(alloc)) + { + std::size_t count = std::distance(first,last); + members_.reserve(count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(get_key_value()(*s)); + } + + build_index(); + auto last_unique = std::unique(index_.begin(), index_.end(), + [&](std::size_t a, std::size_t b) { return !(members_.at(a).key().compare(members_.at(b).key())); }); + + if (last_unique != index_.end()) + { + index_.erase(last_unique, index_.end()); + std::sort(index_.begin(), index_.end()); + + auto result = index_.rbegin(); + if (*result != members_.size()) + { + members_.erase(members_.begin() + (*result + 1), members_.end()); + } + for (auto it = index_.rbegin() + 1; it != index_.rend(); ++it, ++result) + { + if (*result - *it > 1) + { + members_.erase(members_.begin() + (*it + 1), members_.begin() + *result); + } + } + } + build_index(); + } + + order_preserving_json_object(std::initializer_list,Json>> init, + const allocator_type& alloc = allocator_type()) + : allocator_holder(alloc), + members_(key_value_allocator_type(alloc)), + index_(index_allocator_type(alloc)) + { + members_.reserve(init.size()); + for (auto& item : init) + { + insert_or_assign(item.first, item.second); + } + } + + ~order_preserving_json_object() noexcept + { + flatten_and_destroy(); + } + + order_preserving_json_object& operator=(order_preserving_json_object&& val) + { + val.swap(*this); + return *this; + } + + order_preserving_json_object& operator=(const order_preserving_json_object& val) + { + allocator_holder::operator=(val.get_allocator()); + members_ = val.members_; + index_ = val.index_; + return *this; + } + + void swap(order_preserving_json_object& val) noexcept + { + members_.swap(val.members_); + } + + bool empty() const + { + return members_.empty(); + } + + iterator begin() + { + return members_.begin(); + } + + iterator end() + { + return members_.end(); + } + + const_iterator begin() const + { + return members_.begin(); + } + + const_iterator end() const + { + return members_.end(); + } + + std::size_t size() const {return members_.size();} + + std::size_t capacity() const {return members_.capacity();} + + void clear() + { + members_.clear(); + index_.clear(); + } + + void shrink_to_fit() + { + for (std::size_t i = 0; i < members_.size(); ++i) + { + members_[i].shrink_to_fit(); + } + members_.shrink_to_fit(); + index_.shrink_to_fit(); + } + + void reserve(std::size_t n) {members_.reserve(n);} + + Json& at(std::size_t i) + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + const Json& at(std::size_t i) const + { + if (i >= members_.size()) + { + JSONCONS_THROW(json_runtime_error("Invalid array subscript")); + } + return members_[i].value(); + } + + iterator find(const string_view_type& name) noexcept + { + auto p = std::equal_range(index_.begin(),index_.end(), name, + Comp(members_)); + return p.first == p.second ? members_.end() : members_.begin() + *p.first; + } + + const_iterator find(const string_view_type& name) const noexcept + { + auto p = std::equal_range(index_.begin(),index_.end(), name, + Comp(members_)); + return p.first == p.second ? members_.end() : members_.begin() + *p.first; + } + + iterator erase(const_iterator pos) + { + if (pos != members_.end()) + { + std::size_t pos1 = pos - members_.begin(); + std::size_t pos2 = pos1 + 1; + + erase_index_entries(pos1, pos2); + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = members_.begin() + (pos - members_.begin()); + return members_.erase(it); + #else + return members_.erase(pos); + #endif + } + else + { + return members_.end(); + } + } + + iterator erase(const_iterator first, const_iterator last) + { + std::size_t pos1 = first == members_.end() ? members_.size() : first - members_.begin(); + std::size_t pos2 = last == members_.end() ? members_.size() : last - members_.begin(); + + if (pos1 < members_.size() && pos2 <= members_.size()) + { + erase_index_entries(pos1,pos2); + + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it1 = members_.begin() + (first - members_.begin()); + iterator it2 = members_.begin() + (last - members_.begin()); + return members_.erase(it1,it2); + #else + return members_.erase(first,last); + #endif + } + else + { + return members_.end(); + } + } + + void erase(const string_view_type& name) + { + auto pos = find(name); + if (pos != members_.end()) + { + std::size_t pos1 = pos - members_.begin(); + std::size_t pos2 = pos1 + 1; + + erase_index_entries(pos1, pos2); + #if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR) + iterator it = members_.begin() + (pos - members_.begin()); + members_.erase(it); + #else + members_.erase(pos); + #endif + } + } + + template + void insert(InputIt first, InputIt last, Convert convert) + { + std::size_t count = std::distance(first,last); + members_.reserve(members_.size() + count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + + build_index(); + auto last_unique = std::unique(index_.begin(), index_.end(), + [&](std::size_t a, std::size_t b) { return !(members_.at(a).key().compare(members_.at(b).key())); }); + + if (last_unique != index_.end()) + { + index_.erase(last_unique, index_.end()); + std::sort(index_.begin(), index_.end()); + + auto result = index_.rbegin(); + if (*result != members_.size()) + { + members_.erase(members_.begin() + (*result + 1), members_.end()); + } + for (auto it = index_.rbegin() + 1; it != index_.rend(); ++it, ++result) + { + if (*result - *it > 1) + { + members_.erase(members_.begin() + (*it + 1), members_.begin() + *result); + } + } + } + build_index(); + } + + template + void insert(sorted_unique_range_tag, InputIt first, InputIt last, Convert convert) + { + std::size_t count = std::distance(first,last); + + members_.reserve(members_.size() + count); + for (auto s = first; s != last; ++s) + { + members_.emplace_back(convert(*s)); + } + + build_index(); + } + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + auto result = insert_index_entry(name,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(name.begin(), name.end()), std::forward(value)); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value))); + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,std::pair>::type + insert_or_assign(const string_view_type& name, T&& value) + { + auto result = insert_index_entry(name,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(name.begin(),name.end(),get_allocator()), + std::forward(value),get_allocator()); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value),get_allocator())); + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + if (hint == members_.end()) + { + auto result = insert_or_assign(key, std::forward(value)); + return result.first; + } + else + { + std::size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key,pos); + + if (result.second) + { + auto it = members_.emplace(hint, key_type(key.begin(), key.end()), std::forward(value)); + return it; + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value))); + return it; + } + } + } + + template + typename std::enable_if::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + if (hint == members_.end()) + { + auto result = insert_or_assign(key, std::forward(value)); + return result.first; + } + else + { + std::size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key,pos); + + if (result.second) + { + auto it = members_.emplace(hint, + key_type(key.begin(),key.end(),get_allocator()), + std::forward(value),get_allocator()); + return it; + } + else + { + auto it = members_.begin() + result.first; + it->value(Json(std::forward(value),get_allocator())); + return it; + } + } + } + + // merge + + void merge(const order_preserving_json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace((*it).key(),(*it).value()); + } + } + + void merge(order_preserving_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 = find((*it).key()); + if (pos == members_.end() ) + { + try_emplace((*it).key(),std::move((*it).value())); + } + } + } + + void merge(iterator hint, const order_preserving_json_object& source) + { + std::size_t pos = hint - members_.begin(); + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, (*it).key(),(*it).value()); + std::size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + void merge(iterator hint, order_preserving_json_object&& source) + { + std::size_t pos = hint - members_.begin(); + + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + hint = try_emplace(hint, (*it).key(), std::move((*it).value())); + std::size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + // merge_or_update + + void merge_or_update(const order_preserving_json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign((*it).key(),(*it).value()); + } + } + + void merge_or_update(order_preserving_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 = find((*it).key()); + if (pos == members_.end() ) + { + insert_or_assign((*it).key(),std::move((*it).value())); + } + else + { + pos->value(std::move((*it).value())); + } + } + } + + void merge_or_update(iterator hint, const order_preserving_json_object& source) + { + std::size_t pos = hint - members_.begin(); + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, (*it).key(),(*it).value()); + std::size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + void merge_or_update(iterator hint, order_preserving_json_object&& source) + { + std::size_t pos = hint - members_.begin(); + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + hint = insert_or_assign(hint, (*it).key(), std::move((*it).value())); + std::size_t newpos = hint - members_.begin(); + if (newpos == pos) + { + ++hint; + pos = hint - members_.begin(); + } + else + { + hint = members_.begin() + pos; + } + } + } + + // try_emplace + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& name, Args&&... args) + { + auto result = insert_index_entry(name,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(name.begin(), name.end()), std::forward(args)...); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,std::pair>::type + try_emplace(const string_view_type& key, Args&&... args) + { + auto result = insert_index_entry(key,members_.size()); + if (result.second) + { + members_.emplace_back(key_type(key.begin(),key.end(), get_allocator()), + std::forward(args)...); + auto it = members_.begin() + result.first; + return std::make_pair(it,true); + } + else + { + auto it = members_.begin() + result.first; + return std::make_pair(it,false); + } + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + if (hint == members_.end()) + { + auto result = try_emplace(key, std::forward(args)...); + return result.first; + } + else + { + std::size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key, pos); + + if (result.second) + { + auto it = members_.emplace(hint, key_type(key.begin(), key.end()), std::forward(args)...); + return it; + } + else + { + auto it = members_.begin() + result.first; + return it; + } + } + } + + template + typename std::enable_if::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + if (hint == members_.end()) + { + auto result = try_emplace(key, std::forward(args)...); + return result.first; + } + else + { + std::size_t pos = hint - members_.begin(); + auto result = insert_index_entry(key, pos); + + if (result.second) + { + auto it = members_.emplace(hint, + key_type(key.begin(),key.end(), get_allocator()), + std::forward(args)...); + return it; + } + else + { + auto it = members_.begin() + result.first; + return it; + } + } + } + + bool operator==(const order_preserving_json_object& rhs) const + { + return members_ == rhs.members_; + } + + bool operator<(const order_preserving_json_object& rhs) const + { + return members_ < rhs.members_; + } + private: + + void flatten_and_destroy() noexcept + { + if (!members_.empty()) + { + json_array temp(get_allocator()); + + for (auto&& kv : members_) + { + if (kv.value().size() > 0) + { + temp.emplace_back(std::move(kv.value())); + } + } + } + } + + std::pair insert_index_entry(const string_view_type& key, std::size_t pos) + { + JSONCONS_ASSERT(pos <= index_.size()); + + auto it = std::lower_bound(index_.begin(),index_.end(), key, + Comp(members_)); + + if (it == index_.end()) + { + std::size_t count = index_.size() - pos; + for (std::size_t i = 0; count > 0 && i < index_.size(); ++i) + { + if (index_[i] >= pos) + { + ++index_[i]; + --count; + } + } + index_.push_back(pos); + return std::make_pair(pos,true); + } + else if (members_.at(*it).key() != key) + { + std::size_t count = index_.size() - pos; + for (std::size_t i = 0; count > 0 && i < index_.size(); ++i) + { + if (index_[i] >= pos) + { + ++index_[i]; + --count; + } + } + auto it2 = index_.insert(it, pos); + return std::make_pair(*it2,true); + } + else + { + return std::make_pair(*it,false); + } + } + + void erase_index_entries(std::size_t pos1, std::size_t pos2) + { + JSONCONS_ASSERT(pos1 <= pos2); + JSONCONS_ASSERT(pos2 <= index_.size()); + + const size_t offset = pos2 - pos1; + const size_t n = index_.size() - offset; + for (std::size_t i = 0; i < index_.size(); ++i) + { + if (index_[i] >= pos1 && index_[i] < pos2) + { + index_.erase(index_.begin()+i); + --i; + } + } + for (std::size_t i = 0; i < index_.size(); ++i) + { + if (index_[i] >= pos2) + { + index_[i] -= offset; + } + } + JSONCONS_ASSERT(index_.size() == n); + } + + void build_index() + { + index_.clear(); + index_.reserve(members_.size()); + for (std::size_t i = 0; i < members_.size(); ++i) + { + index_.push_back(i); + } + std::stable_sort(index_.begin(),index_.end(), + [&](std::size_t a, std::size_t b) -> bool {return members_.at(a).key().compare(members_.at(b).key()) < 0;}); + } + }; + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/json_options.hpp b/include/jsoncons/json_options.hpp new file mode 100644 index 0000000..e73f233 --- /dev/null +++ b/include/jsoncons/json_options.hpp @@ -0,0 +1,862 @@ +// 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_OPTIONS_HPP +#define JSONCONS_JSON_OPTIONS_HPP + +#include +#include // std::numeric_limits +#include +#include +#include + +namespace jsoncons { + +enum class float_chars_format : uint8_t {general,fixed,scientific,hex}; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use float_chars_format") typedef float_chars_format chars_format; +#endif + +enum class indenting : uint8_t {no_indent = 0, indent = 1}; + +enum class line_split_kind : uint8_t {same_line,new_line,multi_line}; + +enum class bigint_chars_format : uint8_t {number, base10, base64, base64url +#if !defined(JSONCONS_NO_DEPRECATED) +,integer = number +#endif +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use bigint_chars_format") typedef bigint_chars_format bignum_chars_format; +JSONCONS_DEPRECATED_MSG("Instead, use bigint_chars_format") typedef bigint_chars_format big_integer_chars_format; +#endif + +enum class byte_string_chars_format : uint8_t {none=0,base16,base64,base64url}; + +enum class spaces_option : uint8_t {no_spaces=0,space_after,space_before,space_before_and_after}; + +template +class basic_json_options; + +template +class basic_json_options_common +{ + friend class basic_json_options; +public: + using char_type = CharT; + using string_type = std::basic_string; +private: +#if !defined(JSONCONS_NO_DEPRECATED) + bool can_read_nan_replacement_; + bool can_read_pos_inf_replacement_; + bool can_read_neg_inf_replacement_; + string_type nan_replacement_; + string_type pos_inf_replacement_; + string_type neg_inf_replacement_; +#endif + + bool enable_nan_to_num_:1; + bool enable_inf_to_num_:1; + bool enable_neginf_to_num_:1; + bool enable_nan_to_str_:1; + bool enable_inf_to_str_:1; + bool enable_neginf_to_str_:1; + bool enable_str_to_nan_:1; + bool enable_str_to_inf_:1; + bool enable_str_to_neginf_:1; + + string_type nan_to_num_; + string_type inf_to_num_; + string_type neginf_to_num_; + string_type nan_to_str_; + string_type inf_to_str_; + string_type neginf_to_str_; + int max_nesting_depth_; + +protected: + basic_json_options_common() + : +#if !defined(JSONCONS_NO_DEPRECATED) + can_read_nan_replacement_(false), + can_read_pos_inf_replacement_(false), + can_read_neg_inf_replacement_(false), +#endif + enable_nan_to_num_(false), + enable_inf_to_num_(false), + enable_neginf_to_num_(false), + enable_nan_to_str_(false), + enable_inf_to_str_(false), + enable_neginf_to_str_(false), + enable_str_to_nan_(false), + enable_str_to_inf_(false), + enable_str_to_neginf_(false), + max_nesting_depth_(1024) + {} + + virtual ~basic_json_options_common() noexcept = default; + + basic_json_options_common(const basic_json_options_common&) = default; + basic_json_options_common& operator=(const basic_json_options_common&) = default; + basic_json_options_common(basic_json_options_common&&) = default; + basic_json_options_common& operator=(basic_json_options_common&&) = default; + +public: + + bool enable_nan_to_num() const + { + return enable_nan_to_num_; + } + + bool enable_inf_to_num() const + { + return enable_inf_to_num_; + } + + bool enable_neginf_to_num() const + { + return enable_neginf_to_num_ || enable_inf_to_num_; + } + + bool enable_nan_to_str() const + { + return enable_nan_to_str_; + } + + bool enable_str_to_nan() const + { + return enable_str_to_nan_; + } + + bool enable_inf_to_str() const + { + return enable_inf_to_str_; + } + + bool enable_str_to_inf() const + { + return enable_str_to_inf_; + } + + bool enable_neginf_to_str() const + { + return enable_neginf_to_str_ || enable_inf_to_str_; + } + + bool enable_str_to_neginf() const + { + return enable_str_to_neginf_ || enable_str_to_inf_; + } + + string_type nan_to_num() const + { + if (enable_nan_to_num_) + { + return nan_to_num_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (!can_read_nan_replacement_) // not string + { + return nan_replacement_; + } +#endif + else + { + return nan_to_num_; // empty string + } + } + + string_type inf_to_num() const + { + if (enable_inf_to_num_) + { + return inf_to_num_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (!can_read_pos_inf_replacement_) // not string + { + return pos_inf_replacement_; + } +#endif + else + { + return inf_to_num_; // empty string + } + } + + string_type neginf_to_num() const + { + if (enable_neginf_to_num_) + { + return neginf_to_num_; + } + else if (enable_inf_to_num_) + { + string_type s; + s.push_back('-'); + s.append(inf_to_num_); + return s; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (!can_read_neg_inf_replacement_) // not string + { + return neg_inf_replacement_; + } +#endif + else + { + return neginf_to_num_; // empty string + } + } + + string_type nan_to_str() const + { + if (enable_nan_to_str_) + { + return nan_to_str_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (can_read_nan_replacement_ && nan_replacement_.size() >= 2) // string + { + return nan_replacement_.substr(1, nan_replacement_.size() - 2); // Remove quotes + } +#endif + else + { + return nan_to_str_; // empty string + } + } + + string_type inf_to_str() const + { + if (enable_inf_to_str_) + { + return inf_to_str_; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (can_read_pos_inf_replacement_ && pos_inf_replacement_.size() >= 2) // string + { + return pos_inf_replacement_.substr(1, pos_inf_replacement_.size() - 2); // Strip quotes + } +#endif + else + { + return inf_to_str_; // empty string + } + } + + string_type neginf_to_str() const + { + if (enable_neginf_to_str_) + { + return neginf_to_str_; + } + else if (enable_inf_to_str_) + { + string_type s; + s.push_back('-'); + s.append(inf_to_str_); + return s; + } +#if !defined(JSONCONS_NO_DEPRECATED) + else if (can_read_neg_inf_replacement_ && neg_inf_replacement_.size() >= 2) // string + { + return neg_inf_replacement_.substr(1, neg_inf_replacement_.size() - 2); // Strip quotes + } +#endif + else + { + return neginf_to_str_; // empty string + } + } + + int max_nesting_depth() const + { + return max_nesting_depth_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use enable_nan_to_num() or enable_nan_to_str()") + bool can_read_nan_replacement() const { return can_read_nan_replacement_; } + + JSONCONS_DEPRECATED_MSG("Instead, use enable_inf_to_num() or enable_inf_to_str()") + bool can_read_pos_inf_replacement() const { return can_read_pos_inf_replacement_; } + + JSONCONS_DEPRECATED_MSG("Instead, use enable_neginf_to_num() or enable_neginf_to_str()") + bool can_read_neg_inf_replacement() const { return can_read_neg_inf_replacement_; } + + bool can_write_nan_replacement() const { return !nan_replacement_.empty(); } + + bool can_write_pos_inf_replacement() const { return !pos_inf_replacement_.empty(); } + + bool can_write_neg_inf_replacement() const { return !neg_inf_replacement_.empty(); } + + JSONCONS_DEPRECATED_MSG("Instead, use nan_to_num() or nan_to_str()") + const string_type& nan_replacement() const + { + return nan_replacement_; + } + + JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num() or inf_to_str()") + const string_type& pos_inf_replacement() const + { + return pos_inf_replacement_; + } + + JSONCONS_DEPRECATED_MSG("Instead, use neginf_to_num() or neginf_to_str()") + const string_type& neg_inf_replacement() const + { + return neg_inf_replacement_; + } +#endif +}; + +template +class basic_json_decode_options : public virtual basic_json_options_common +{ + friend class basic_json_options; + using super_type = basic_json_options_common; +public: + using typename super_type::char_type; + using typename super_type::string_type; +private: + bool lossless_number_:1; +public: + basic_json_decode_options() + : lossless_number_(false) + { + } + + basic_json_decode_options(const basic_json_decode_options&) = default; + + basic_json_decode_options(basic_json_decode_options&& other) + : super_type(std::forward(other)), + lossless_number_(other.lossless_number_) + { + } + + basic_json_decode_options& operator=(const basic_json_decode_options&) = default; + + bool lossless_number() const + { + return lossless_number_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use lossless_number()") + bool dec_to_str() const + { + return lossless_number_; + } +#endif +}; + +template +class basic_json_encode_options : public virtual basic_json_options_common +{ + friend class basic_json_options; + using super_type = basic_json_options_common; +public: + using typename super_type::char_type; + using typename super_type::string_type; + + static constexpr uint8_t indent_size_default = 4; + static constexpr size_t line_length_limit_default = 120; +private: + bool escape_all_non_ascii_:1; + bool escape_solidus_:1; + bool pad_inside_object_braces_:1; + bool pad_inside_array_brackets_:1; + float_chars_format float_format_; + byte_string_chars_format byte_string_format_; + bigint_chars_format bigint_format_; + line_split_kind object_object_line_splits_; + line_split_kind object_array_line_splits_; + line_split_kind array_array_line_splits_; + line_split_kind array_object_line_splits_; + spaces_option spaces_around_colon_; + spaces_option spaces_around_comma_; + int8_t precision_; + uint8_t indent_size_; + std::size_t line_length_limit_; + string_type new_line_chars_; +public: + basic_json_encode_options() + : escape_all_non_ascii_(false), + escape_solidus_(false), + pad_inside_object_braces_(false), + pad_inside_array_brackets_(false), + float_format_(float_chars_format::general), + byte_string_format_(byte_string_chars_format::none), + bigint_format_(bigint_chars_format::base10), + object_object_line_splits_(line_split_kind::multi_line), + object_array_line_splits_(line_split_kind::same_line), + array_array_line_splits_(line_split_kind::new_line), + array_object_line_splits_(line_split_kind::multi_line), + spaces_around_colon_(spaces_option::space_after), + spaces_around_comma_(spaces_option::space_after), + precision_(0), + indent_size_(indent_size_default), + line_length_limit_(line_length_limit_default) + { + new_line_chars_.push_back('\n'); + } + + basic_json_encode_options(const basic_json_encode_options&) = default; + + basic_json_encode_options(basic_json_encode_options&& other) + : super_type(std::forward(other)), + escape_all_non_ascii_(other.escape_all_non_ascii_), + escape_solidus_(other.escape_solidus_), + pad_inside_object_braces_(other.pad_inside_object_braces_), + pad_inside_array_brackets_(other.pad_inside_array_brackets_), + float_format_(other.float_format_), + byte_string_format_(other.byte_string_format_), + bigint_format_(other.bigint_format_), + object_object_line_splits_(other.object_object_line_splits_), + object_array_line_splits_(other.object_array_line_splits_), + array_array_line_splits_(other.array_array_line_splits_), + array_object_line_splits_(other.array_object_line_splits_), + spaces_around_colon_(other.spaces_around_colon_), + spaces_around_comma_(other.spaces_around_comma_), + precision_(other.precision_), + indent_size_(other.indent_size_), + line_length_limit_(other.line_length_limit_), + new_line_chars_(std::move(other.new_line_chars_)) + { + } + + basic_json_encode_options& operator=(const basic_json_encode_options&) = default; + + byte_string_chars_format byte_string_format() const {return byte_string_format_;} + + bigint_chars_format bigint_format() const {return bigint_format_;} + + line_split_kind object_object_line_splits() const {return object_object_line_splits_;} + + line_split_kind array_object_line_splits() const {return array_object_line_splits_;} + + line_split_kind object_array_line_splits() const {return object_array_line_splits_;} + + line_split_kind array_array_line_splits() const {return array_array_line_splits_;} + + uint8_t indent_size() const + { + return indent_size_; + } + + spaces_option spaces_around_colon() const + { + return spaces_around_colon_; + } + + spaces_option spaces_around_comma() const + { + return spaces_around_comma_; + } + + bool pad_inside_object_braces() const + { + return pad_inside_object_braces_; + } + + bool pad_inside_array_brackets() const + { + return pad_inside_array_brackets_; + } + + string_type new_line_chars() const + { + return new_line_chars_; + } + + std::size_t line_length_limit() const + { + return line_length_limit_; + } + + float_chars_format float_format() const + { + return float_format_; + } + + int8_t precision() const + { + return precision_; + } + + bool escape_all_non_ascii() const + { + return escape_all_non_ascii_; + } + + bool escape_solidus() const + { + return escape_solidus_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use bigint_format()") + bigint_chars_format bignum_format() const {return bigint_format_;} + + JSONCONS_DEPRECATED_MSG("Instead, use indent_size()") + uint8_t indent() const + { + return indent_size(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_object_line_splits()") + line_split_kind object_object_split_lines() const {return object_object_line_splits_;} + + JSONCONS_DEPRECATED_MSG("Instead, use array_object_line_splits()") + line_split_kind array_object_split_lines() const {return array_object_line_splits_;} + + JSONCONS_DEPRECATED_MSG("Instead, use object_array_line_splits()") + line_split_kind object_array_split_lines() const {return object_array_line_splits_;} + + JSONCONS_DEPRECATED_MSG("Instead, use array_array_line_splits()") + line_split_kind array_array_split_lines() const {return array_array_line_splits_;} +#endif +}; + +template +class basic_json_options final: public basic_json_decode_options, + public basic_json_encode_options +{ +public: + using char_type = CharT; + using string_type = std::basic_string; + + using basic_json_options_common::max_nesting_depth; + + using basic_json_decode_options::enable_str_to_nan; + using basic_json_decode_options::enable_str_to_inf; + using basic_json_decode_options::enable_str_to_neginf; + using basic_json_decode_options::nan_to_str; + using basic_json_decode_options::inf_to_str; + using basic_json_decode_options::neginf_to_str; + using basic_json_decode_options::nan_to_num; + using basic_json_decode_options::inf_to_num; + using basic_json_decode_options::neginf_to_num; + + using basic_json_decode_options::lossless_number; + + using basic_json_encode_options::byte_string_format; + using basic_json_encode_options::bigint_format; + using basic_json_encode_options::object_object_line_splits; + using basic_json_encode_options::array_object_line_splits; + using basic_json_encode_options::object_array_line_splits; + using basic_json_encode_options::array_array_line_splits; + using basic_json_encode_options::indent_size; + using basic_json_encode_options::spaces_around_colon; + using basic_json_encode_options::spaces_around_comma; + using basic_json_encode_options::pad_inside_object_braces; + using basic_json_encode_options::pad_inside_array_brackets; + using basic_json_encode_options::new_line_chars; + using basic_json_encode_options::line_length_limit; + using basic_json_encode_options::float_format; + using basic_json_encode_options::precision; + using basic_json_encode_options::escape_all_non_ascii; + using basic_json_encode_options::escape_solidus; +public: + +// Constructors + + basic_json_options() = default; + basic_json_options(const basic_json_options&) = default; + basic_json_options(basic_json_options&&) = default; + basic_json_options& operator=(const basic_json_options&) = default; + basic_json_options& operator=(basic_json_options&&) = default; + + basic_json_options& nan_to_num(const string_type& value) + { + this->enable_nan_to_num_ = true; + this->nan_to_str_.clear(); + this->nan_to_num_ = value; + return *this; + } + + basic_json_options& inf_to_num(const string_type& value) + { + this->enable_inf_to_num_ = true; + this->inf_to_str_.clear(); + this->inf_to_num_ = value; + return *this; + } + + basic_json_options& neginf_to_num(const string_type& value) + { + this->enable_neginf_to_num_ = true; + this->neginf_to_str_.clear(); + this->neginf_to_num_ = value; + return *this; + } + + basic_json_options& nan_to_str(const string_type& value, bool enable_inverse = true) + { + this->enable_nan_to_str_ = true; + this->enable_str_to_nan_ = enable_inverse; + this->nan_to_num_.clear(); + this->nan_to_str_ = value; + return *this; + } + + basic_json_options& inf_to_str(const string_type& value, bool enable_inverse = true) + { + this->enable_inf_to_str_ = true; + this->enable_inf_to_str_ = enable_inverse; + this->inf_to_num_.clear(); + this->inf_to_str_ = value; + return *this; + } + + basic_json_options& neginf_to_str(const string_type& value, bool enable_inverse = true) + { + this->enable_neginf_to_str_ = true; + this->enable_neginf_to_str_ = enable_inverse; + this->neginf_to_num_.clear(); + this->neginf_to_str_ = value; + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num(const string_type&) or inf_to_str(const string_type&)") + basic_json_options& replace_inf(bool replace) + { + this->can_read_pos_inf_replacement_ = replace; + this->can_read_neg_inf_replacement_ = replace; + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num(const string_type&) or inf_to_str(const string_type&)") + basic_json_options& replace_pos_inf(bool replace) + { + this->can_read_pos_inf_replacement_ = replace; + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use neginf_to_num(const string_type&) or neginf_to_str(const string_type&)") + basic_json_options& replace_neg_inf(bool replace) + { + this->can_read_neg_inf_replacement_ = replace; + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use nan_to_num(const string_type&) or nan_to_str(const string_type&)") + basic_json_options& nan_replacement(const string_type& value) + { + this->nan_replacement_ = value; + + this->can_read_nan_replacement_ = is_string(value); + + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num(const string_type&) or inf_to_str(const string_type&)") + basic_json_options& pos_inf_replacement(const string_type& value) + { + this->pos_inf_replacement_ = value; + this->can_read_pos_inf_replacement_ = is_string(value); + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use neginf_to_num(const string_type&) or neginf_to_str(const string_type&)") + basic_json_options& neg_inf_replacement(const string_type& value) + { + this->neg_inf_replacement_ = value; + this->can_read_neg_inf_replacement_ = is_string(value); + return *this; + } + + basic_json_options& byte_string_format(byte_string_chars_format value) {this->byte_string_format_ = value; return *this;} + + basic_json_options& bigint_format(bigint_chars_format value) {this->bigint_format_ = value; return *this;} + + basic_json_options& object_object_line_splits(line_split_kind value) {this->object_object_line_splits_ = value; return *this;} + + basic_json_options& array_object_line_splits(line_split_kind value) {this->array_object_line_splits_ = value; return *this;} + + basic_json_options& object_array_line_splits(line_split_kind value) {this->object_array_line_splits_ = value; return *this;} + + basic_json_options& array_array_line_splits(line_split_kind value) {this->array_array_line_splits_ = value; return *this;} + + basic_json_options& indent_size(uint8_t value) + { + this->indent_size_ = value; + return *this; + } + + basic_json_options& spaces_around_colon(spaces_option value) + { + this->spaces_around_colon_ = value; + return *this; + } + + basic_json_options& spaces_around_comma(spaces_option value) + { + this->spaces_around_comma_ = value; + return *this; + } + + basic_json_options& pad_inside_object_braces(bool value) + { + this->pad_inside_object_braces_ = value; + return *this; + } + + basic_json_options& pad_inside_array_brackets(bool value) + { + this->pad_inside_array_brackets_ = value; + return *this; + } + + basic_json_options& new_line_chars(const string_type& value) + { + this->new_line_chars_ = value; + return *this; + } + + basic_json_options& lossless_number(bool value) + { + this->lossless_number_ = value; + return *this; + } + + basic_json_options& line_length_limit(std::size_t value) + { + this->line_length_limit_ = value; + return *this; + } + + basic_json_options& float_format(float_chars_format value) + { + this->float_format_ = value; + return *this; + } + + basic_json_options& precision(int8_t value) + { + this->precision_ = value; + return *this; + } + + basic_json_options& escape_all_non_ascii(bool value) + { + this->escape_all_non_ascii_ = value; + return *this; + } + + basic_json_options& escape_solidus(bool value) + { + this->escape_solidus_ = value; + return *this; + } + + basic_json_options& max_nesting_depth(int value) + { + this->max_nesting_depth_ = value; + return *this; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use bigint_format(bigint_chars_format)") + basic_json_options& big_integer_format(bigint_chars_format value) {this->bigint_format_ = value; return *this;} + + JSONCONS_DEPRECATED_MSG("Instead, use bigint_format(bigint_chars_format)") + basic_json_options& bignum_format(bigint_chars_format value) {this->bigint_format_ = value; return *this;} + + JSONCONS_DEPRECATED_MSG("Instead, use float_format(float_chars_format)") + basic_json_options& floating_point_format(float_chars_format value) + { + this->float_format_ = value; + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use lossless_number(bool)") + basic_json_options& dec_to_str(bool value) + { + this->lossless_number_ = value; + return *this; + } + + JSONCONS_DEPRECATED_MSG("Instead, use indent_size(uint8_t_t)") + basic_json_options& indent(uint8_t value) + { + return indent_size(value); + } + + JSONCONS_DEPRECATED_MSG("Instead, use object_object_line_splits(line_split_kind)") + basic_json_options& object_object_split_lines(line_split_kind value) {this->object_object_line_splits_ = value; return *this;} + + JSONCONS_DEPRECATED_MSG("Instead, use array_object_line_splits(line_split_kind)") + basic_json_options& array_object_split_lines(line_split_kind value) {this->array_object_line_splits_ = value; return *this;} + + JSONCONS_DEPRECATED_MSG("Instead, use object_array_line_splits(line_split_kind)") + basic_json_options& object_array_split_lines(line_split_kind value) {this->object_array_line_splits_ = value; return *this;} + + JSONCONS_DEPRECATED_MSG("Instead, use array_array_line_splits(line_split_kind)") + basic_json_options& array_array_split_lines(line_split_kind value) {this->array_array_line_splits_ = value; return *this;} +#endif +private: + enum class input_state {initial,begin_quote,character,end_quote,escape,error}; + bool is_string(const string_type& s) const + { + input_state state = input_state::initial; + for (char_type c : s) + { + switch (c) + { + case '\t': case ' ': case '\n': case'\r': + break; + case '\\': + state = input_state::escape; + break; + case '\"': + switch (state) + { + case input_state::initial: + state = input_state::begin_quote; + break; + case input_state::begin_quote: + state = input_state::end_quote; + break; + case input_state::character: + state = input_state::end_quote; + break; + case input_state::end_quote: + state = input_state::error; + break; + case input_state::escape: + state = input_state::character; + break; + default: + state = input_state::character; + break; + } + break; + default: + break; + } + + } + return state == input_state::end_quote; + } +}; + +using json_options = basic_json_options; +using wjson_options = basic_json_options; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("json_options") typedef json_options output_format; +JSONCONS_DEPRECATED_MSG("wjson_options") typedef wjson_options woutput_format; +JSONCONS_DEPRECATED_MSG("json_options") typedef json_options serialization_options; +JSONCONS_DEPRECATED_MSG("wjson_options") typedef wjson_options wserialization_options; +JSONCONS_DEPRECATED_MSG("json_options") typedef json_options json_serializing_options; +JSONCONS_DEPRECATED_MSG("wjson_options") typedef wjson_options wjson_serializing_options; +#endif + +} +#endif diff --git a/include/jsoncons/json_parser.hpp b/include/jsoncons/json_parser.hpp new file mode 100644 index 0000000..4ba9bf1 --- /dev/null +++ b/include/jsoncons/json_parser.hpp @@ -0,0 +1,2871 @@ +// 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 // std::allocator +#include +#include +#include +#include +#include +#include // std::numeric_limits +#include // std::function +#include +#include +#include +#include +#include +#include + +#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 { + +namespace detail { + +} + +enum class json_parse_state : uint8_t +{ + root, + start, + accept, + 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, + member_name, + escape, + escape_u1, + escape_u2, + escape_u3, + escape_u4, + escape_expect_surrogate_pair1, + escape_expect_surrogate_pair2, + escape_u5, + escape_u6, + escape_u7, + escape_u8, + minus, + zero, + integer, + fraction1, + fraction2, + exp1, + exp2, + exp3, + n, + nu, + nul, + t, + tr, + tru, + f, + fa, + fal, + fals, + cr, + done +}; + +struct default_json_parsing +{ + bool operator()(json_errc ec, const ser_context&) noexcept + { + if (ec == json_errc::illegal_comment) + { + return true; // Recover, allow comments + } + else + { + return false; + } + } +}; + +struct strict_json_parsing +{ + bool operator()(json_errc, const ser_context&) noexcept + { + return false; + } +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use default_json_parsing") typedef default_json_parsing default_parse_error_handler; +JSONCONS_DEPRECATED_MSG("Instead, use strict_json_parsing") typedef strict_json_parsing strict_parse_error_handler; +#endif + +template > +class basic_json_parser : public ser_context +{ +public: + using char_type = CharT; + using string_view_type = typename basic_json_visitor::string_view_type; +private: + struct string_maps_to_double + { + string_view_type s; + + bool operator()(const std::pair& val) const + { + return val.first == s; + } + }; + + using temp_allocator_type = TempAllocator; + using char_allocator_type = typename std::allocator_traits:: template rebind_alloc; + using parse_state_allocator_type = typename std::allocator_traits:: template rebind_alloc; + + static constexpr std::size_t initial_string_buffer_capacity_ = 1024; + static constexpr std::size_t default_initial_stack_capacity_ = 100; + + basic_json_decode_options options_; + + std::function err_handler_; + int initial_stack_capacity_; + int nesting_depth_; + uint32_t cp_; + uint32_t cp2_; + std::size_t line_; + std::size_t position_; + std::size_t mark_position_; + std::size_t saved_position_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* input_ptr_; + json_parse_state state_; + bool more_; + bool done_; + + std::basic_string,char_allocator_type> string_buffer_; + jsoncons::detail::chars_to to_double_; + + std::vector state_stack_; + std::vector> string_double_map_; + + // Noncopyable and nonmoveable + basic_json_parser(const basic_json_parser&) = delete; + basic_json_parser& operator=(const basic_json_parser&) = delete; + +public: + basic_json_parser(const TempAllocator& alloc = TempAllocator()) + : basic_json_parser(basic_json_decode_options(), default_json_parsing(), alloc) + { + } + + basic_json_parser(std::function err_handler, + const TempAllocator& alloc = TempAllocator()) + : basic_json_parser(basic_json_decode_options(), err_handler, alloc) + { + } + + basic_json_parser(const basic_json_decode_options& options, + const TempAllocator& alloc = TempAllocator()) + : basic_json_parser(options, default_json_parsing(), alloc) + { + } + + basic_json_parser(const basic_json_decode_options& options, + std::function err_handler, + const TempAllocator& alloc = TempAllocator()) + : options_(options), + err_handler_(err_handler), + initial_stack_capacity_(default_initial_stack_capacity_), + nesting_depth_(0), + cp_(0), + cp2_(0), + line_(1), + position_(0), + mark_position_(0), + saved_position_(0), + begin_input_(nullptr), + end_input_(nullptr), + input_ptr_(nullptr), + state_(json_parse_state::start), + more_(true), + done_(false), + string_buffer_(alloc), + state_stack_(alloc) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + + state_stack_.reserve(initial_stack_capacity_); + push_state(json_parse_state::root); + + if (options_.enable_str_to_nan()) + { + string_double_map_.emplace_back(options_.nan_to_str(),std::nan("")); + } + if (options_.enable_str_to_inf()) + { + string_double_map_.emplace_back(options_.inf_to_str(),std::numeric_limits::infinity()); + } + if (options_.enable_str_to_neginf()) + { + string_double_map_.emplace_back(options_.neginf_to_str(),-std::numeric_limits::infinity()); + } + } + + bool source_exhausted() const + { + return input_ptr_ == end_input_; + } + + ~basic_json_parser() noexcept + { + } + + json_parse_state parent() const + { + JSONCONS_ASSERT(state_stack_.size() >= 1); + return state_stack_.back(); + } + + bool done() const + { + return done_; + } + + bool enter() const + { + return state_ == json_parse_state::start; + } + + bool accept() const + { + return state_ == json_parse_state::accept || done_; + } + + bool stopped() const + { + return !more_; + } + + json_parse_state state() const + { + return state_; + } + + bool finished() const + { + return !more_ && state_ != json_parse_state::accept; + } + + const char_type* first() const + { + return begin_input_; + } + + const char_type* current() const + { + return input_ptr_; + } + + const char_type* last() const + { + return end_input_; + } + + void skip_space() + { + const char_type* local_input_end = end_input_; + while (input_ptr_ != local_input_end) + { + switch (*input_ptr_) + { + case ' ': + case '\t': + ++input_ptr_; + ++position_; + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::cr; + return; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + return; + default: + return; + } + } + } + + void skip_whitespace() + { + const char_type* local_input_end = end_input_; + + while (input_ptr_ != local_input_end) + { + switch (state_) + { + case json_parse_state::cr: + ++line_; + ++position_; + mark_position_ = position_; + switch (*input_ptr_) + { + case '\n': + ++input_ptr_; + ++position_; + state_ = pop_state(); + break; + default: + state_ = pop_state(); + break; + } + break; + + default: + switch (*input_ptr_) + { + case ' ': + case '\t': + case '\n': + case '\r': + skip_space(); + break; + default: + return; + } + break; + } + } + } + + void begin_object(basic_json_visitor& visitor, std::error_code& ec) + { + if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) + { + more_ = err_handler_(json_errc::max_nesting_depth_exceeded, *this); + if (!more_) + { + ec = json_errc::max_nesting_depth_exceeded; + return; + } + } + + push_state(json_parse_state::object); + state_ = json_parse_state::expect_member_name_or_end; + more_ = visitor.begin_object(semantic_tag::none, *this, ec); + } + + void end_object(basic_json_visitor& visitor, std::error_code& ec) + { + if (JSONCONS_UNLIKELY(nesting_depth_ < 1)) + { + err_handler_(json_errc::unexpected_rbrace, *this); + ec = json_errc::unexpected_rbrace; + more_ = false; + return; + } + --nesting_depth_; + state_ = pop_state(); + if (state_ == json_parse_state::object) + { + more_ = visitor.end_object(*this, ec); + } + else if (state_ == json_parse_state::array) + { + err_handler_(json_errc::expected_comma_or_rbracket, *this); + ec = json_errc::expected_comma_or_rbracket; + more_ = false; + return; + } + else + { + err_handler_(json_errc::unexpected_rbrace, *this); + ec = json_errc::unexpected_rbrace; + more_ = false; + return; + } + + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + + void begin_array(basic_json_visitor& visitor, std::error_code& ec) + { + if (++nesting_depth_ > options_.max_nesting_depth()) + { + more_ = err_handler_(json_errc::max_nesting_depth_exceeded, *this); + if (!more_) + { + ec = json_errc::max_nesting_depth_exceeded; + return; + } + } + + push_state(json_parse_state::array); + state_ = json_parse_state::expect_value_or_end; + more_ = visitor.begin_array(semantic_tag::none, *this, ec); + } + + void end_array(basic_json_visitor& visitor, std::error_code& ec) + { + if (nesting_depth_ < 1) + { + err_handler_(json_errc::unexpected_rbracket, *this); + ec = json_errc::unexpected_rbracket; + more_ = false; + return; + } + --nesting_depth_; + state_ = pop_state(); + if (state_ == json_parse_state::array) + { + more_ = visitor.end_array(*this, ec); + } + else if (state_ == json_parse_state::object) + { + err_handler_(json_errc::expected_comma_or_rbrace, *this); + ec = json_errc::expected_comma_or_rbrace; + more_ = false; + return; + } + else + { + err_handler_(json_errc::unexpected_rbracket, *this); + ec = json_errc::unexpected_rbracket; + more_ = false; + return; + } + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + + void reinitialize() + { + reset(); + cp_ = 0; + cp2_ = 0; + saved_position_ = 0; + begin_input_ = nullptr; + end_input_ = nullptr; + input_ptr_ = nullptr; + string_buffer_.clear(); + } + + void reset() + { + state_stack_.clear(); + state_stack_.reserve(initial_stack_capacity_); + push_state(json_parse_state::root); + state_ = json_parse_state::start; + more_ = true; + done_ = false; + line_ = 1; + position_ = 0; + mark_position_ = 0; + nesting_depth_ = 0; + } + + void restart() + { + more_ = true; + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,line_,column())); + } + } + + void check_done(std::error_code& ec) + { + for (; input_ptr_ != end_input_; ++input_ptr_) + { + char_type curr_char_ = *input_ptr_; + switch (curr_char_) + { + case '\n': + case '\r': + case '\t': + case ' ': + break; + default: + more_ = err_handler_(json_errc::extra_character, *this); + if (!more_) + { + ec = json_errc::extra_character; + return; + } + break; + } + } + } + + void update(const string_view_type sv) + { + update(sv.data(),sv.length()); + } + + void update(const char_type* data, std::size_t length) + { + begin_input_ = data; + end_input_ = data + length; + input_ptr_ = begin_input_; + } + + void parse_some(basic_json_visitor& visitor) + { + std::error_code ec; + parse_some(visitor, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,line_,column())); + } + } + + void parse_some(basic_json_visitor& visitor, std::error_code& ec) + { + parse_some_(visitor, ec); + } + + void finish_parse(basic_json_visitor& visitor) + { + std::error_code ec; + finish_parse(visitor, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,line_,column())); + } + } + + void finish_parse(basic_json_visitor& visitor, std::error_code& ec) + { + while (!finished()) + { + parse_some(visitor, ec); + } + } + + void parse_some_(basic_json_visitor& visitor, std::error_code& ec) + { + if (state_ == json_parse_state::accept) + { + visitor.flush(); + done_ = true; + state_ = json_parse_state::done; + more_ = false; + return; + } + const char_type* local_input_end = end_input_; + + if (input_ptr_ == local_input_end && more_) + { + switch (state_) + { + case json_parse_state::zero: + case json_parse_state::integer: + end_integer_value(visitor, ec); + if (ec) return; + break; + case json_parse_state::fraction2: + end_fraction_value(visitor, ec); + if (ec) return; + break; + case json_parse_state::exp3: + end_fraction_value(visitor, ec); + if (ec) return; + break; + case json_parse_state::accept: + visitor.flush(); + done_ = true; + state_ = json_parse_state::done; + more_ = false; + break; + case json_parse_state::start: + case json_parse_state::done: + more_ = false; + break; + case json_parse_state::cr: + state_ = pop_state(); + break; + default: + err_handler_(json_errc::unexpected_eof, *this); + ec = json_errc::unexpected_eof; + more_ = false; + return; + } + } + + while ((input_ptr_ < local_input_end) && more_) + { + switch (state_) + { + case json_parse_state::accept: + visitor.flush(); + done_ = true; + state_ = json_parse_state::done; + more_ = false; + break; + case json_parse_state::cr: + ++line_; + mark_position_ = position_; + switch (*input_ptr_) + { + case '\n': + ++input_ptr_; + ++position_; + state_ = pop_state(); + break; + default: + state_ = pop_state(); + break; + } + break; + case json_parse_state::start: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '{': + begin_object(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '[': + begin_array(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '\"': + state_ = json_parse_state::string; + ++input_ptr_; + ++position_; + string_buffer_.clear(); + parse_string(visitor, ec); + if (ec) return; + break; + case '-': + string_buffer_.clear(); + string_buffer_.push_back('-'); + ++input_ptr_; + ++position_; + state_ = json_parse_state::minus; + parse_number(visitor, ec); + if (ec) {return;} + break; + case '0': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + state_ = json_parse_state::zero; + ++input_ptr_; + ++position_; + parse_number(visitor, ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + state_ = json_parse_state::integer; + parse_number(visitor, ec); + if (ec) {return;} + break; + case 'n': + parse_null(visitor, ec); + if (ec) {return;} + break; + case 't': + parse_true(visitor, ec); + if (ec) {return;} + break; + case 'f': + parse_false(visitor, ec); + if (ec) {return;} + break; + case '}': + err_handler_(json_errc::unexpected_rbrace, *this); + ec = json_errc::unexpected_rbrace; + more_ = false; + return; + case ']': + err_handler_(json_errc::unexpected_rbracket, *this); + ec = json_errc::unexpected_rbracket; + more_ = false; + return; + default: + err_handler_(json_errc::syntax_error, *this); + ec = json_errc::syntax_error; + more_ = false; + return; + } + } + break; + + case json_parse_state::expect_comma_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++position_; + break; + case '\r': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '}': + end_object(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case ']': + end_array(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case ',': + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + default: + if (parent() == json_parse_state::array) + { + more_ = err_handler_(json_errc::expected_comma_or_rbracket, *this); + if (!more_) + { + ec = json_errc::expected_comma_or_rbracket; + return; + } + } + else if (parent() == json_parse_state::object) + { + more_ = err_handler_(json_errc::expected_comma_or_rbrace, *this); + if (!more_) + { + ec = json_errc::expected_comma_or_rbrace; + return; + } + } + ++input_ptr_; + ++position_; + break; + } + } + break; + case json_parse_state::expect_member_name_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++position_; + break; + case '\r': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '}': + end_object(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '\"': + ++input_ptr_; + ++position_; + push_state(json_parse_state::member_name); + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(visitor, ec); + if (ec) return; + break; + case '\'': + more_ = err_handler_(json_errc::single_quote, *this); + if (!more_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++position_; + break; + default: + more_ = err_handler_(json_errc::expected_key, *this); + if (!more_) + { + ec = json_errc::expected_key; + return; + } + ++input_ptr_; + ++position_; + break; + } + } + break; + case json_parse_state::expect_member_name: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++position_; + break; + case '\r': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '\"': + ++input_ptr_; + ++position_; + push_state(json_parse_state::member_name); + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(visitor, ec); + if (ec) return; + break; + case '}': + more_ = err_handler_(json_errc::extra_comma, *this); + if (!more_) + { + ec = json_errc::extra_comma; + return; + } + end_object(visitor, ec); // Recover + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '\'': + more_ = err_handler_(json_errc::single_quote, *this); + if (!more_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++position_; + break; + default: + more_ = err_handler_(json_errc::expected_key, *this); + if (!more_) + { + ec = json_errc::expected_key; + return; + } + ++input_ptr_; + ++position_; + break; + } + } + break; + case json_parse_state::expect_colon: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++position_; + break; + case '\r': + push_state(state_); + state_ = json_parse_state::cr; + ++input_ptr_; + ++position_; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + push_state(state_); + state_ = json_parse_state::slash; + ++input_ptr_; + ++position_; + break; + case ':': + state_ = json_parse_state::expect_value; + ++input_ptr_; + ++position_; + break; + default: + more_ = err_handler_(json_errc::expected_colon, *this); + if (!more_) + { + ec = json_errc::expected_colon; + return; + } + ++input_ptr_; + ++position_; + break; + } + } + break; + + case json_parse_state::expect_value: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++position_; + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::slash; + break; + case '{': + begin_object(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '[': + begin_array(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '\"': + ++input_ptr_; + ++position_; + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(visitor, ec); + if (ec) return; + break; + case '-': + string_buffer_.clear(); + string_buffer_.push_back('-'); + ++input_ptr_; + ++position_; + state_ = json_parse_state::minus; + parse_number(visitor, ec); + if (ec) {return;} + break; + case '0': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + state_ = json_parse_state::zero; + parse_number(visitor, ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + state_ = json_parse_state::integer; + parse_number(visitor, ec); + if (ec) {return;} + break; + case 'n': + parse_null(visitor, ec); + if (ec) {return;} + break; + case 't': + parse_true(visitor, ec); + if (ec) {return;} + break; + case 'f': + parse_false(visitor, ec); + if (ec) {return;} + break; + case ']': + if (parent() == json_parse_state::array) + { + more_ = err_handler_(json_errc::extra_comma, *this); + if (!more_) + { + ec = json_errc::extra_comma; + return; + } + end_array(visitor, ec); // Recover + if (ec) return; + } + else + { + more_ = err_handler_(json_errc::expected_value, *this); + if (!more_) + { + ec = json_errc::expected_value; + return; + } + } + ++input_ptr_; + ++position_; + break; + case '\'': + more_ = err_handler_(json_errc::single_quote, *this); + if (!more_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++position_; + break; + default: + more_ = err_handler_(json_errc::expected_value, *this); + if (!more_) + { + ec = json_errc::expected_value; + return; + } + ++input_ptr_; + ++position_; + break; + } + } + break; + case json_parse_state::expect_value_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++position_; + break; + case '\r': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case ' ':case '\t': + skip_space(); + break; + case '/': + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::slash; + break; + case '{': + begin_object(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '[': + begin_array(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case ']': + end_array(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + break; + case '\"': + ++input_ptr_; + ++position_; + state_ = json_parse_state::string; + string_buffer_.clear(); + parse_string(visitor, ec); + if (ec) return; + break; + case '-': + string_buffer_.clear(); + string_buffer_.push_back('-'); + ++input_ptr_; + ++position_; + state_ = json_parse_state::minus; + parse_number(visitor, ec); + if (ec) {return;} + break; + case '0': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + state_ = json_parse_state::zero; + parse_number(visitor, ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.clear(); + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + state_ = json_parse_state::integer; + parse_number(visitor, ec); + if (ec) {return;} + break; + case 'n': + parse_null(visitor, ec); + if (ec) {return;} + break; + case 't': + parse_true(visitor, ec); + if (ec) {return;} + break; + case 'f': + parse_false(visitor, ec); + if (ec) {return;} + break; + case '\'': + more_ = err_handler_(json_errc::single_quote, *this); + if (!more_) + { + ec = json_errc::single_quote; + return; + } + ++input_ptr_; + ++position_; + break; + default: + more_ = err_handler_(json_errc::expected_value, *this); + if (!more_) + { + ec = json_errc::expected_value; + return; + } + ++input_ptr_; + ++position_; + break; + } + } + break; + case json_parse_state::string: + case json_parse_state::escape: + case json_parse_state::escape_u1: + case json_parse_state::escape_u2: + case json_parse_state::escape_u3: + case json_parse_state::escape_u4: + case json_parse_state::escape_expect_surrogate_pair1: + case json_parse_state::escape_expect_surrogate_pair2: + case json_parse_state::escape_u5: + case json_parse_state::escape_u6: + case json_parse_state::escape_u7: + case json_parse_state::escape_u8: + parse_string(visitor, ec); + if (ec) return; + break; + case json_parse_state::minus: + case json_parse_state::zero: + case json_parse_state::integer: + case json_parse_state::fraction1: + case json_parse_state::fraction2: + case json_parse_state::exp1: + case json_parse_state::exp2: + case json_parse_state::exp3: + parse_number(visitor, ec); + if (ec) return; + break; + case json_parse_state::t: + switch (*input_ptr_) + { + case 'r': + ++input_ptr_; + ++position_; + state_ = json_parse_state::tr; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + break; + case json_parse_state::tr: + switch (*input_ptr_) + { + case 'u': + state_ = json_parse_state::tru; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::tru: + switch (*input_ptr_) + { + case 'e': + more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::f: + switch (*input_ptr_) + { + case 'a': + ++input_ptr_; + ++position_; + state_ = json_parse_state::fa; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + break; + case json_parse_state::fa: + switch (*input_ptr_) + { + case 'l': + state_ = json_parse_state::fal; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::fal: + switch (*input_ptr_) + { + case 's': + state_ = json_parse_state::fals; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::fals: + switch (*input_ptr_) + { + case 'e': + more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::n: + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++position_; + state_ = json_parse_state::nu; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + break; + case json_parse_state::nu: + switch (*input_ptr_) + { + case 'l': + state_ = json_parse_state::nul; + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::nul: + switch (*input_ptr_) + { + case 'l': + more_ = visitor.null_value(semantic_tag::none, *this, ec); + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + break; + default: + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + ++input_ptr_; + ++position_; + break; + case json_parse_state::slash: + { + switch (*input_ptr_) + { + case '*': + state_ = json_parse_state::slash_star; + more_ = err_handler_(json_errc::illegal_comment, *this); + if (!more_) + { + ec = json_errc::illegal_comment; + return; + } + break; + case '/': + state_ = json_parse_state::slash_slash; + more_ = err_handler_(json_errc::illegal_comment, *this); + if (!more_) + { + ec = json_errc::illegal_comment; + return; + } + break; + default: + more_ = err_handler_(json_errc::syntax_error, *this); + if (!more_) + { + ec = json_errc::syntax_error; + return; + } + break; + } + ++input_ptr_; + ++position_; + break; + } + case json_parse_state::slash_star: + { + switch (*input_ptr_) + { + case '\r': + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + break; + case '*': + ++input_ptr_; + ++position_; + state_ = json_parse_state::slash_star_star; + break; + default: + ++input_ptr_; + ++position_; + break; + } + break; + } + case json_parse_state::slash_slash: + { + switch (*input_ptr_) + { + case '\r': + state_ = pop_state(); + break; + case '\n': + state_ = pop_state(); + break; + default: + ++input_ptr_; + ++position_; + } + break; + } + case json_parse_state::slash_star_star: + { + switch (*input_ptr_) + { + case '/': + state_ = pop_state(); + break; + default: + state_ = json_parse_state::slash_star; + break; + } + ++input_ptr_; + ++position_; + break; + } + default: + JSONCONS_ASSERT(false); + break; + } + } + } + + void parse_true(basic_json_visitor& visitor, std::error_code& ec) + { + saved_position_ = position_; + if (JSONCONS_LIKELY(end_input_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'r' && *(input_ptr_+2) == 'u' && *(input_ptr_+3) == 'e') + { + more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); + input_ptr_ += 4; + position_ += 4; + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + else + { + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + } + else + { + ++input_ptr_; + ++position_; + state_ = json_parse_state::t; + } + } + + void parse_null(basic_json_visitor& visitor, std::error_code& ec) + { + saved_position_ = position_; + if (JSONCONS_LIKELY(end_input_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'u' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 'l') + { + more_ = visitor.null_value(semantic_tag::none, *this, ec); + input_ptr_ += 4; + position_ += 4; + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + else + { + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + } + else + { + ++input_ptr_; + ++position_; + state_ = json_parse_state::n; + } + } + + void parse_false(basic_json_visitor& visitor, std::error_code& ec) + { + saved_position_ = position_; + if (JSONCONS_LIKELY(end_input_ - input_ptr_ >= 5)) + { + if (*(input_ptr_+1) == 'a' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 's' && *(input_ptr_+4) == 'e') + { + more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); + input_ptr_ += 5; + position_ += 5; + if (parent() == json_parse_state::root) + { + state_ = json_parse_state::accept; + } + else + { + state_ = json_parse_state::expect_comma_or_end; + } + } + else + { + err_handler_(json_errc::invalid_value, *this); + ec = json_errc::invalid_value; + more_ = false; + return; + } + } + else + { + ++input_ptr_; + ++position_; + state_ = json_parse_state::f; + } + } + + void parse_number(basic_json_visitor& visitor, std::error_code& ec) + { + saved_position_ = position_ - 1; + const char_type* local_input_end = end_input_; + + switch (state_) + { + case json_parse_state::minus: + goto minus_sign; + case json_parse_state::zero: + goto zero; + case json_parse_state::integer: + goto integer; + case json_parse_state::fraction1: + goto fraction1; + case json_parse_state::fraction2: + goto fraction2; + case json_parse_state::exp1: + goto exp1; + case json_parse_state::exp2: + goto exp2; + case json_parse_state::exp3: + goto exp3; + default: + JSONCONS_UNREACHABLE(); + } +minus_sign: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::minus; + return; + } + switch (*input_ptr_) + { + case '0': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto zero; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto integer; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::expected_value; + more_ = false; + return; + } +zero: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::zero; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::cr; + return; + case '\n': + end_integer_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + return; + case ' ':case '\t': + end_integer_value(visitor, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_integer_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::slash; + return; + case '}': + end_integer_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_integer_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case '.': + string_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++position_; + goto fraction1; + case 'e':case 'E': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp1; + case ',': + end_integer_value(visitor, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++position_; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + err_handler_(json_errc::leading_zero, *this); + ec = json_errc::leading_zero; + more_ = false; + state_ = json_parse_state::zero; + return; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + more_ = false; + state_ = json_parse_state::zero; + return; + } +integer: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::integer; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(visitor, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::cr; + return; + case '\n': + end_integer_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + return; + case ' ':case '\t': + end_integer_value(visitor, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_integer_value(visitor, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::slash; + return; + case '}': + end_integer_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_integer_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto integer; + case '.': + string_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++position_; + goto fraction1; + case 'e':case 'E': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp1; + case ',': + end_integer_value(visitor, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++position_; + return; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + more_ = false; + state_ = json_parse_state::integer; + return; + } +fraction1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_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': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto fraction2; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + more_ = false; + state_ = json_parse_state::fraction1; + return; + } +fraction2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::fraction2; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(visitor, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::cr; + return; + case '\n': + end_fraction_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + return; + case ' ':case '\t': + end_fraction_value(visitor, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_fraction_value(visitor, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::slash; + return; + case '}': + end_fraction_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_fraction_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ',': + end_fraction_value(visitor, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++position_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto fraction2; + case 'e':case 'E': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp1; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + more_ = false; + state_ = json_parse_state::fraction2; + return; + } +exp1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::exp1; + return; + } + switch (*input_ptr_) + { + case '+': + ++input_ptr_; + ++position_; + goto exp2; + case '-': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp2; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp3; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::expected_value; + more_ = false; + state_ = json_parse_state::exp1; + return; + } +exp2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_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': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp3; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::expected_value; + more_ = false; + state_ = json_parse_state::exp2; + return; + } + +exp3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::exp3; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++position_; + push_state(state_); + state_ = json_parse_state::cr; + return; + case '\n': + end_fraction_value(visitor, ec); + if (ec) return; + ++input_ptr_; + ++line_; + ++position_; + mark_position_ = position_; + return; + case ' ':case '\t': + end_fraction_value(visitor, ec); + if (ec) return; + skip_space(); + return; + case '/': + end_fraction_value(visitor, ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++position_; + state_ = json_parse_state::slash; + return; + case '}': + end_fraction_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ']': + end_fraction_value(visitor, ec); + if (ec) return; + state_ = json_parse_state::expect_comma_or_end; + return; + case ',': + end_fraction_value(visitor, ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++position_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + string_buffer_.push_back(static_cast(*input_ptr_)); + ++input_ptr_; + ++position_; + goto exp3; + default: + err_handler_(json_errc::invalid_number, *this); + ec = json_errc::invalid_number; + more_ = false; + state_ = json_parse_state::exp3; + return; + } + + JSONCONS_UNREACHABLE(); + } + + void parse_string(basic_json_visitor& visitor, std::error_code& ec) + { + saved_position_ = position_ - 1; + const char_type* local_input_end = end_input_; + const char_type* sb = input_ptr_; + + switch (state_) + { + case json_parse_state::string: + goto string_u1; + case json_parse_state::escape: + goto escape; + case json_parse_state::escape_u1: + goto escape_u1; + case json_parse_state::escape_u2: + goto escape_u2; + case json_parse_state::escape_u3: + goto escape_u3; + case json_parse_state::escape_u4: + goto escape_u4; + case json_parse_state::escape_expect_surrogate_pair1: + goto escape_expect_surrogate_pair1; + case json_parse_state::escape_expect_surrogate_pair2: + goto escape_expect_surrogate_pair2; + case json_parse_state::escape_u5: + goto escape_u5; + case json_parse_state::escape_u6: + goto escape_u6; + case json_parse_state::escape_u7: + goto escape_u7; + case json_parse_state::escape_u8: + goto escape_u8; + default: + JSONCONS_UNREACHABLE(); + } + +string_u1: + while (input_ptr_ < local_input_end) + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + { + position_ += (input_ptr_ - sb + 1); + more_ = err_handler_(json_errc::illegal_control_character, *this); + if (!more_) + { + ec = json_errc::illegal_control_character; + state_ = json_parse_state::string; + return; + } + // recovery - skip + string_buffer_.append(sb,input_ptr_-sb); + ++input_ptr_; + state_ = json_parse_state::string; + return; + } + case '\r': + { + position_ += (input_ptr_ - sb + 1); + more_ = err_handler_(json_errc::illegal_character_in_string, *this); + if (!more_) + { + ec = json_errc::illegal_character_in_string; + state_ = json_parse_state::string; + return; + } + // recovery - keep + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + push_state(state_); + state_ = json_parse_state::cr; + return; + } + case '\n': + { + ++line_; + ++position_; + mark_position_ = position_; + more_ = err_handler_(json_errc::illegal_character_in_string, *this); + if (!more_) + { + ec = json_errc::illegal_character_in_string; + state_ = json_parse_state::string; + return; + } + // recovery - keep + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + return; + } + case '\t': + { + position_ += (input_ptr_ - sb + 1); + more_ = err_handler_(json_errc::illegal_character_in_string, *this); + if (!more_) + { + ec = json_errc::illegal_character_in_string; + state_ = json_parse_state::string; + return; + } + // recovery - keep + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + state_ = json_parse_state::string; + return; + } + case '\\': + { + string_buffer_.append(sb,input_ptr_-sb); + position_ += (input_ptr_ - sb + 1); + ++input_ptr_; + goto escape; + } + case '\"': + { + if (string_buffer_.length() == 0) + { + end_string_value(sb,input_ptr_-sb, visitor, ec); + if (ec) {return;} + } + else + { + string_buffer_.append(sb,input_ptr_-sb); + end_string_value(string_buffer_.data(),string_buffer_.length(), visitor, ec); + if (ec) {return;} + } + position_ += (input_ptr_ - sb + 1); + ++input_ptr_; + return; + } + default: + break; + } + ++input_ptr_; + } + + // Buffer exhausted + { + string_buffer_.append(sb,input_ptr_-sb); + position_ += (input_ptr_ - sb + 1); + state_ = json_parse_state::string; + return; + } + +escape: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape; + return; + } + switch (*input_ptr_) + { + case '\"': + string_buffer_.push_back('\"'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case '\\': + string_buffer_.push_back('\\'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case '/': + string_buffer_.push_back('/'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case 'b': + string_buffer_.push_back('\b'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case 'f': + string_buffer_.push_back('\f'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case 'n': + string_buffer_.push_back('\n'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case 'r': + string_buffer_.push_back('\r'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case 't': + string_buffer_.push_back('\t'); + sb = ++input_ptr_; + ++position_; + goto string_u1; + case 'u': + cp_ = 0; + ++input_ptr_; + ++position_; + goto escape_u1; + default: + err_handler_(json_errc::illegal_escaped_character, *this); + ec = json_errc::illegal_escaped_character; + more_ = false; + state_ = json_parse_state::escape; + return; + } + +escape_u1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u1; + return; + } + { + cp_ = append_to_codepoint(0, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u1; + return; + } + ++input_ptr_; + ++position_; + goto escape_u2; + } + +escape_u2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u2; + return; + } + { + cp_ = append_to_codepoint(cp_, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u2; + return; + } + ++input_ptr_; + ++position_; + goto escape_u3; + } + +escape_u3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u3; + return; + } + { + cp_ = append_to_codepoint(cp_, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u3; + return; + } + ++input_ptr_; + ++position_; + goto escape_u4; + } + +escape_u4: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u4; + return; + } + { + cp_ = append_to_codepoint(cp_, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u4; + return; + } + if (unicode_traits::is_high_surrogate(cp_)) + { + ++input_ptr_; + ++position_; + goto escape_expect_surrogate_pair1; + } + else + { + unicode_traits::convert(&cp_, 1, string_buffer_); + sb = ++input_ptr_; + ++position_; + state_ = json_parse_state::string; + return; + } + } + +escape_expect_surrogate_pair1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_expect_surrogate_pair1; + return; + } + { + switch (*input_ptr_) + { + case '\\': + cp2_ = 0; + ++input_ptr_; + ++position_; + goto escape_expect_surrogate_pair2; + default: + err_handler_(json_errc::expected_codepoint_surrogate_pair, *this); + ec = json_errc::expected_codepoint_surrogate_pair; + more_ = false; + state_ = json_parse_state::escape_expect_surrogate_pair1; + return; + } + } + +escape_expect_surrogate_pair2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_expect_surrogate_pair2; + return; + } + { + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++position_; + goto escape_u5; + default: + err_handler_(json_errc::expected_codepoint_surrogate_pair, *this); + ec = json_errc::expected_codepoint_surrogate_pair; + more_ = false; + state_ = json_parse_state::escape_expect_surrogate_pair2; + return; + } + } + +escape_u5: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u5; + return; + } + { + cp2_ = append_to_codepoint(0, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u5; + return; + } + } + ++input_ptr_; + ++position_; + goto escape_u6; + +escape_u6: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u6; + return; + } + { + cp2_ = append_to_codepoint(cp2_, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u6; + return; + } + ++input_ptr_; + ++position_; + goto escape_u7; + } + +escape_u7: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u7; + return; + } + { + cp2_ = append_to_codepoint(cp2_, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u7; + return; + } + ++input_ptr_; + ++position_; + goto escape_u8; + } + +escape_u8: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = json_parse_state::escape_u8; + return; + } + { + cp2_ = append_to_codepoint(cp2_, *input_ptr_, ec); + if (ec) + { + state_ = json_parse_state::escape_u8; + return; + } + uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); + unicode_traits::convert(&cp, 1, string_buffer_); + sb = ++input_ptr_; + ++position_; + goto string_u1; + } + + JSONCONS_UNREACHABLE(); + } + + void translate_conv_errc(unicode_traits::conv_errc result, std::error_code& ec) + { + switch (result) + { + case unicode_traits::conv_errc(): + break; + case unicode_traits::conv_errc::over_long_utf8_sequence: + more_ = err_handler_(json_errc::over_long_utf8_sequence, *this); + if (!more_) + { + ec = json_errc::over_long_utf8_sequence; + return; + } + break; + case unicode_traits::conv_errc::unpaired_high_surrogate: + more_ = err_handler_(json_errc::unpaired_high_surrogate, *this); + if (!more_) + { + ec = json_errc::unpaired_high_surrogate; + return; + } + break; + case unicode_traits::conv_errc::expected_continuation_byte: + more_ = err_handler_(json_errc::expected_continuation_byte, *this); + if (!more_) + { + ec = json_errc::expected_continuation_byte; + return; + } + break; + case unicode_traits::conv_errc::illegal_surrogate_value: + more_ = err_handler_(json_errc::illegal_surrogate_value, *this); + if (!more_) + { + ec = json_errc::illegal_surrogate_value; + return; + } + break; + default: + more_ = err_handler_(json_errc::illegal_codepoint, *this); + if (!more_) + { + ec = json_errc::illegal_codepoint; + return; + } + break; + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + JSONCONS_DEPRECATED_MSG("Instead, use finish_parse(basic_json_visitor&)") + void end_parse(basic_json_visitor& visitor) + { + std::error_code ec; + finish_parse(visitor, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,line_,column())); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use finish_parse(basic_json_visitor&, std::error_code&)") + void end_parse(basic_json_visitor& visitor, std::error_code& ec) + { + while (!finished()) + { + parse_some(visitor, ec); + } + } + + JSONCONS_DEPRECATED_MSG("Instead, use update(const char_type*, std::size_t)") + void set_source(const char_type* data, std::size_t length) + { + begin_input_ = data; + end_input_ = data + length; + input_ptr_ = begin_input_; + } +#endif + + std::size_t line() const override + { + return line_; + } + + std::size_t column() const override + { + return (position_ - mark_position_) + 1; + } + + std::size_t position() const override + { + return saved_position_; + } + + std::size_t offset() const + { + return input_ptr_ - begin_input_; + } +private: + + void end_integer_value(basic_json_visitor& visitor, std::error_code& ec) + { + if (string_buffer_[0] == '-') + { + end_negative_value(visitor, ec); + } + else + { + end_positive_value(visitor, ec); + } + } + + void end_negative_value(basic_json_visitor& visitor, std::error_code& ec) + { + int64_t val; + auto result = jsoncons::detail::to_integer_unchecked(string_buffer_.data(), string_buffer_.length(), val); + if (result) + { + more_ = visitor.int64_value(val, semantic_tag::none, *this, ec); + } + else // Must be overflow + { + more_ = visitor.string_value(string_buffer_, semantic_tag::bigint, *this, ec); + } + after_value(ec); + } + + void end_positive_value(basic_json_visitor& visitor, std::error_code& ec) + { + uint64_t val; + auto result = jsoncons::detail::to_integer_unchecked(string_buffer_.data(), string_buffer_.length(), val); + if (result) + { + more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec); + } + else // Must be overflow + { + more_ = visitor.string_value(string_buffer_, semantic_tag::bigint, *this, ec); + } + after_value(ec); + } + + void end_fraction_value(basic_json_visitor& visitor, std::error_code& ec) + { + JSONCONS_TRY + { + if (options_.lossless_number()) + { + more_ = visitor.string_value(string_buffer_, semantic_tag::bigdec, *this, ec); + } + else + { + double d = to_double_(string_buffer_.c_str(), string_buffer_.length()); + more_ = visitor.double_value(d, semantic_tag::none, *this, ec); + } + } + JSONCONS_CATCH(...) + { + more_ = err_handler_(json_errc::invalid_number, *this); + if (!more_) + { + ec = json_errc::invalid_number; + return; + } + more_ = visitor.null_value(semantic_tag::none, *this, ec); // recovery + } + + after_value(ec); + } + + void end_string_value(const char_type* s, std::size_t length, basic_json_visitor& visitor, std::error_code& ec) + { + string_view_type sv(s, length); + auto result = unicode_traits::validate(s, length); + if (result.ec != unicode_traits::conv_errc()) + { + translate_conv_errc(result.ec,ec); + position_ += (result.ptr - s); + return; + } + switch (parent()) + { + case json_parse_state::member_name: + more_ = visitor.key(sv, *this, ec); + pop_state(); + state_ = json_parse_state::expect_colon; + break; + case json_parse_state::object: + case json_parse_state::array: + { + auto it = std::find_if(string_double_map_.begin(), string_double_map_.end(), string_maps_to_double{ sv }); + if (it != string_double_map_.end()) + { + more_ = visitor.double_value(it->second, semantic_tag::none, *this, ec); + } + else + { + more_ = visitor.string_value(sv, semantic_tag::none, *this, ec); + } + state_ = json_parse_state::expect_comma_or_end; + break; + } + case json_parse_state::root: + { + auto it = std::find_if(string_double_map_.begin(),string_double_map_.end(),string_maps_to_double{sv}); + if (it != string_double_map_.end()) + { + more_ = visitor.double_value(it->second, semantic_tag::none, *this, ec); + } + else + { + more_ = visitor.string_value(sv, semantic_tag::none, *this, ec); + } + state_ = json_parse_state::accept; + break; + } + default: + more_ = err_handler_(json_errc::syntax_error, *this); + if (!more_) + { + ec = json_errc::syntax_error; + return; + } + break; + } + } + + void begin_member_or_element(std::error_code& ec) + { + switch (parent()) + { + case json_parse_state::object: + state_ = json_parse_state::expect_member_name; + break; + case json_parse_state::array: + state_ = json_parse_state::expect_value; + break; + case json_parse_state::root: + break; + default: + more_ = err_handler_(json_errc::syntax_error, *this); + if (!more_) + { + ec = json_errc::syntax_error; + return; + } + break; + } + } + + void after_value(std::error_code& ec) + { + switch (parent()) + { + case json_parse_state::array: + case json_parse_state::object: + state_ = json_parse_state::expect_comma_or_end; + break; + case json_parse_state::root: + state_ = json_parse_state::accept; + break; + default: + more_ = err_handler_(json_errc::syntax_error, *this); + if (!more_) + { + ec = json_errc::syntax_error; + return; + } + break; + } + } + + void push_state(json_parse_state state) + { + state_stack_.push_back(state); + } + + json_parse_state pop_state() + { + JSONCONS_ASSERT(!state_stack_.empty()) + json_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 + { + more_ = err_handler_(json_errc::invalid_unicode_escape_sequence, *this); + if (!more_) + { + ec = json_errc::invalid_unicode_escape_sequence; + return cp; + } + } + return cp; + } +}; + +using json_parser = basic_json_parser; +using wjson_parser = basic_json_parser; + +} + +#endif + diff --git a/include/jsoncons/json_reader.hpp b/include/jsoncons/json_reader.hpp new file mode 100644 index 0000000..eeb351f --- /dev/null +++ b/include/jsoncons/json_reader.hpp @@ -0,0 +1,731 @@ +// 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 // std::allocator +#include +#include +#include +#include +#include +#include // std::move +#include +#include +#include +#include +#include + +namespace jsoncons { + + // utf8_other_json_input_adapter + + template + class json_utf8_to_other_visitor_adaptor : public json_visitor + { + public: + using json_visitor::string_view_type; + private: + basic_default_json_visitor default_visitor_; + basic_json_visitor& other_visitor_; + //std::function err_handler_; + + // noncopyable and nonmoveable + json_utf8_to_other_visitor_adaptor(const json_utf8_to_other_visitor_adaptor&) = delete; + json_utf8_to_other_visitor_adaptor& operator=(const json_utf8_to_other_visitor_adaptor&) = delete; + + public: + json_utf8_to_other_visitor_adaptor() + : other_visitor_(default_visitor_) + { + } + + json_utf8_to_other_visitor_adaptor(basic_json_visitor& other_visitor/*, + std::function err_handler*/) + : other_visitor_(other_visitor)/*, + err_handler_(err_handler)*/ + { + } + + private: + + void visit_flush() override + { + other_visitor_.flush(); + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.begin_object(tag, context, ec); + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + return other_visitor_.end_object(context, ec); + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.begin_array(tag, context, ec); + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + return other_visitor_.end_array(context, ec); + } + + bool visit_key(const string_view_type& name, const ser_context& context, std::error_code& ec) override + { + std::basic_string target; + auto result = unicode_traits::convert( + name.data(), name.size(), target, + unicode_traits::conv_flags::strict); + if (result.ec != unicode_traits::conv_errc()) + { + JSONCONS_THROW(ser_error(result.ec,context.line(),context.column())); + } + return other_visitor_.key(target, context, ec); + } + + bool visit_string(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + std::basic_string target; + auto result = unicode_traits::convert( + value.data(), value.size(), target, + unicode_traits::conv_flags::strict); + if (result.ec != unicode_traits::conv_errc()) + { + ec = result.ec; + return false; + } + return other_visitor_.string_value(target, tag, context, ec); + } + + bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.int64_value(value, tag, context, ec); + } + + bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.uint64_value(value, tag, context, ec); + } + + bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.half_value(value, tag, context, ec); + } + + bool visit_double(double value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.double_value(value, tag, context, ec); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.bool_value(value, tag, context, ec); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.null_value(tag, context, ec); + } + }; + + template,class Allocator=std::allocator> + class basic_json_reader + { + public: + using char_type = CharT; + using source_type = Source; + using string_view_type = jsoncons::basic_string_view; + private: + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + + static constexpr size_t default_max_buffer_size = 16384; + + json_source_adaptor source_; + basic_default_json_visitor default_visitor_; + basic_json_visitor& visitor_; + basic_json_parser parser_; + + // Noncopyable and nonmoveable + basic_json_reader(const basic_json_reader&) = delete; + basic_json_reader& operator=(const basic_json_reader&) = delete; + + public: + template + explicit basic_json_reader(Sourceable&& source, const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + default_visitor_, + basic_json_decode_options(), + default_json_parsing(), + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + const basic_json_decode_options& options, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + default_visitor_, + options, + default_json_parsing(), + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + std::function err_handler, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + default_visitor_, + basic_json_decode_options(), + err_handler, + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + const basic_json_decode_options& options, + std::function err_handler, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + default_visitor_, + options, + err_handler, + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + visitor, + basic_json_decode_options(), + default_json_parsing(), + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const basic_json_decode_options& options, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + visitor, + options, + default_json_parsing(), + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + std::function err_handler, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward(source), + visitor, + basic_json_decode_options(), + err_handler, + alloc) + { + } + + template + basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const basic_json_decode_options& options, + std::function err_handler, + const Allocator& alloc = Allocator()) + : source_(std::forward(source)), + visitor_(visitor), + parser_(options,err_handler,alloc) + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth() on options") + int max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth(int) on options") + void max_nesting_depth(int depth) + { + parser_.max_nesting_depth(depth); + } +#endif + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + void read_next(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + parser_.reset(); + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + bool eof = parser_.source_exhausted(); + parser_.parse_some(visitor_, ec); + if (ec) return; + if (eof) + { + if (parser_.enter()) + { + break; + } + else if (!parser_.accept()) + { + ec = json_errc::unexpected_eof; + return; + } + } + } + + while (!source_.eof()) + { + parser_.skip_whitespace(); + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + else + { + break; + } + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + std::size_t line() const + { + return parser_.line(); + } + + std::size_t column() const + { + return parser_.column(); + } + + void check_done(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (source_.eof()) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + do + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + if (!parser_.source_exhausted()) + { + parser_.check_done(ec); + if (ec) return; + } + } + while (!eof()); + } + } + + bool eof() const + { + return parser_.source_exhausted() && source_.eof(); + } + + void read() + { + read_next(); + check_done(); + } + + void read(std::error_code& ec) + { + read_next(ec); + if (!ec) + { + check_done(ec); + } + } + }; + + template,class Allocator=std::allocator> + class legacy_basic_json_reader + { + public: + using char_type = CharT; + using source_type = Source; + using string_view_type = jsoncons::basic_string_view; + private: + typedef typename std::allocator_traits:: template rebind_alloc char_allocator_type; + + static constexpr size_t default_max_buffer_size = 16384; + + json_source_adaptor source_; + basic_default_json_visitor default_visitor_; + basic_json_visitor& visitor_; + basic_json_parser parser_; + + // Noncopyable and nonmoveable + legacy_basic_json_reader(const legacy_basic_json_reader&) = delete; + legacy_basic_json_reader& operator=(const legacy_basic_json_reader&) = delete; + + public: + template + explicit legacy_basic_json_reader(Sourceable&& source, const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + default_visitor_, + basic_json_decode_options(), + default_json_parsing(), + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + const basic_json_decode_options& options, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + default_visitor_, + options, + default_json_parsing(), + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + std::function err_handler, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + default_visitor_, + basic_json_decode_options(), + err_handler, + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + const basic_json_decode_options& options, + std::function err_handler, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + default_visitor_, + options, + err_handler, + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + visitor, + basic_json_decode_options(), + default_json_parsing(), + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const basic_json_decode_options& options, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + visitor, + options, + default_json_parsing(), + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + std::function err_handler, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward(source), + visitor, + basic_json_decode_options(), + err_handler, + alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const basic_json_decode_options& options, + std::function err_handler, + const Allocator& alloc = Allocator(), + typename std::enable_if,Sourceable>::value>::type* = 0) + : source_(std::forward(source)), + visitor_(visitor), + parser_(options,err_handler,alloc) + { + } + + template + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor& visitor, + const basic_json_decode_options& options, + std::function err_handler, + const Allocator& alloc = Allocator(), + typename std::enable_if,Sourceable>::value>::type* = 0) + : source_(), + visitor_(visitor), + parser_(options,err_handler,alloc) + { + jsoncons::basic_string_view sv(std::forward(source)); + + auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size()); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column())); + } + std::size_t offset = (r.ptr - sv.data()); + parser_.update(sv.data()+offset,sv.size()-offset); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth() on options") + int max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth(int) on options") + void max_nesting_depth(int depth) + { + parser_.max_nesting_depth(depth); + } +#endif + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + void read_next(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + parser_.reset(); + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + bool eof = parser_.source_exhausted(); + parser_.parse_some(visitor_, ec); + if (ec) return; + if (eof) + { + if (parser_.enter()) + { + break; + } + else if (!parser_.accept()) + { + ec = json_errc::unexpected_eof; + return; + } + } + } + + while (!source_.eof()) + { + parser_.skip_whitespace(); + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + else + { + break; + } + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + std::size_t line() const + { + return parser_.line(); + } + + std::size_t column() const + { + return parser_.column(); + } + + void check_done(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (source_.eof()) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + do + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + if (!parser_.source_exhausted()) + { + parser_.check_done(ec); + if (ec) return; + } + } + while (!eof()); + } + } + + bool eof() const + { + return parser_.source_exhausted() && source_.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) + using json_reader = legacy_basic_json_reader; + using wjson_reader = legacy_basic_json_reader; +#endif + using json_string_reader = basic_json_reader>; + using wjson_string_reader = basic_json_reader>; + using json_stream_reader = basic_json_reader>; + using wjson_stream_reader = basic_json_reader>; +} + +#endif + diff --git a/include/jsoncons/json_traits_macros.hpp b/include/jsoncons/json_traits_macros.hpp new file mode 100644 index 0000000..321d889 --- /dev/null +++ b/include/jsoncons/json_traits_macros.hpp @@ -0,0 +1,1072 @@ +// Copyright 2019 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_TRAITS_MACROS_HPP +#define JSONCONS_JSON_TRAITS_MACROS_HPP + +#include // std::swap +#include // std::iterator_traits, std::input_iterator_tag +#include // JSONCONS_EXPAND, JSONCONS_QUOTE +#include +#include +#include // std::numeric_limits +#include +#include // std::enable_if +#include +#include + +namespace jsoncons +{ + #define JSONCONS_RDONLY(X) + + #define JSONCONS_RDWR(X) X + + struct always_true + { + template< class T> + constexpr bool operator()(const T&) const noexcept + { + return true; + } + }; + + struct identity + { + template< class T> + constexpr T&& operator()(T&& val) const noexcept + { + return std::forward(val); + } + }; + + template + struct json_traits_macro_names + {}; + + template + struct json_traits_helper + { + using string_view_type = typename Json::string_view_type; + + template + static void set_udt_member(const Json&, const string_view_type&, const OutputType&) + { + } + template + static void set_udt_member(const Json& j, const string_view_type& key, OutputType& val) + { + val = j.at(key).template as(); + } + + template + static void set_udt_member(const Json&, const string_view_type&, From, const OutputType&) + { + } + template + static void set_udt_member(const Json& j, const string_view_type& key, From from, OutputType& val) + { + val = from(j.at(key).template as()); + } + template + static void set_optional_json_member(const string_view_type& key, const std::shared_ptr& val, Json& j) + { + if (val) j.try_emplace(key, val); + } + template + static void set_optional_json_member(const string_view_type& key, const std::unique_ptr& val, Json& j) + { + if (val) j.try_emplace(key, val); + } + template + static void set_optional_json_member(const string_view_type& key, const jsoncons::optional& val, Json& j) + { + if (val) j.try_emplace(key, val); + } + template + static void set_optional_json_member(const string_view_type& key, const U& val, Json& j) + { + j.try_emplace(key, val); + } + }; +} + +#if defined(_MSC_VER) +#pragma warning( disable : 4127) +#endif + +#define JSONCONS_CONCAT_RAW(a, b) a ## b +#define JSONCONS_CONCAT(a, b) JSONCONS_CONCAT_RAW(a, b) + +// Inspired by https://github.com/Loki-Astari/ThorsSerializer/blob/master/src/Serialize/Traits.h + +#define JSONCONS_NARGS(...) JSONCONS_NARG_(__VA_ARGS__, 70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) +#define JSONCONS_NARG_(...) JSONCONS_EXPAND( JSONCONS_ARG_N(__VA_ARGS__) ) +#define JSONCONS_ARG_N(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15,e16,e17,e18,e19,e20,e21,e22,e23,e24,e25,e26,e27,e28,e29,e30,e31,e32,e33,e34,e35,e36,e37,e38,e39,e40,e41,e42,e43,e44,e45,e46,e47,e48,e49,e50,e51,e52,e53,e54,e55,e56,e57,e58,e59,e60,e61,e62,e63,e64,e65,e66,e67,e68,e69,e70,N,...)N + +#define JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, Count) Call(P1, P2, P3, P4, Count) + +#define JSONCONS_VARIADIC_REP_N(Call, P1, P2, P3, ...) JSONCONS_VARIADIC_REP_OF_N(Call, P1,P2, P3, JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) +#define JSONCONS_VARIADIC_REP_OF_N(Call, P1, P2, P3, Count, ...) JSONCONS_VARIADIC_REP_OF_N_(Call, P1, P2, P3, Count, __VA_ARGS__) +#define JSONCONS_VARIADIC_REP_OF_N_(Call, P1, P2, P3, Count, ...) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_ ## Count(Call, P1, P2, P3, __VA_ARGS__)) + +#define JSONCONS_VARIADIC_REP_OF_70(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 70) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_69(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_69(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 69) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_68(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_68(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 68) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_67(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_67(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 67) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_66(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_66(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 66) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_65(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_65(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 65) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_64(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_64(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 64) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_63(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_63(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 63) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_62(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_62(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 62) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_61(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_61(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 61) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_60(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_60(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 60) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_59(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_59(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 59) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_58(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_58(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 58) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_57(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_57(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 57) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_56(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_56(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 56) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_55(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_55(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 55) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_54(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_54(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 54) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_53(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_53(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 53) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_52(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_52(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 52) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_51(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_51(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 51) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_50(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_50(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 50) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_49(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_49(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 49) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_48(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_48(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 48) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_47(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_47(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 47) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_46(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_46(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 46) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_45(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_45(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 45) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_44(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_44(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 44) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_43(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_43(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 43) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_42(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_42(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 42) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_41(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_41(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 41) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_40(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_40(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 40) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_39(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_39(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 39) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_38(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_38(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 38) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_37(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_37(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 37) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_36(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_36(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 36) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_35(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_35(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 35) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_34(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_34(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 34) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_33(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_33(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 33) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_32(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_32(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 32) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_31(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_31(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 31) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_30(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_30(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 30) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_29(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_29(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 29) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_28(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_28(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 28) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_27(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_27(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 27) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_26(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_26(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 26) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_25(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_25(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 25) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_24(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_24(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 24) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_23(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_23(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 23) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_22(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_22(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 22) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_21(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_21(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 21) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_20(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_20(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 20) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_19(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_19(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 19) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_18(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_18(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 18) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_17(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_17(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 17) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_16(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_16(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 16) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_15(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_15(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 15) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_14(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_14(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 14) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_13(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_13(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 13) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_12(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_12(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 12) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_11(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_11(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 11) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_10(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_10(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 10) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_9(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_9(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 9) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_8(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_8(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 8) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_7(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_7(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 7) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_6(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_6(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 6) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_5(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_5(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 5) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_4(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_4(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 4) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_3(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_3(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 3) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_2(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_2(Call, P1, P2, P3, P4, ...) JSONCONS_EXPAND_CALL5(Call, P1, P2, P3, P4, 2) JSONCONS_EXPAND(JSONCONS_VARIADIC_REP_OF_1(Call, P1, P2, P3, __VA_ARGS__)) +#define JSONCONS_VARIADIC_REP_OF_1(Call, P1, P2, P3, P4) JSONCONS_EXPAND(Call ## _LAST(P1, P2, P3, P4, 1)) + +#define JSONCONS_TYPE_TRAITS_FRIEND \ + template \ + friend struct jsoncons::json_type_traits; + +#define JSONCONS_EXPAND_CALL2(Call, Expr, Id) JSONCONS_EXPAND(Call(Expr, Id)) + +#define JSONCONS_REP_OF_N(Call, Expr, Pre, App, Count) JSONCONS_REP_OF_ ## Count(Call, Expr, Pre, App) + +#define JSONCONS_REP_OF_50(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 50) JSONCONS_REP_OF_49(Call, Expr, , App) +#define JSONCONS_REP_OF_49(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 49) JSONCONS_REP_OF_48(Call, Expr, , App) +#define JSONCONS_REP_OF_48(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 48) JSONCONS_REP_OF_47(Call, Expr, , App) +#define JSONCONS_REP_OF_47(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 47) JSONCONS_REP_OF_46(Call, Expr, , App) +#define JSONCONS_REP_OF_46(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 46) JSONCONS_REP_OF_45(Call, Expr, , App) +#define JSONCONS_REP_OF_45(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 45) JSONCONS_REP_OF_44(Call, Expr, , App) +#define JSONCONS_REP_OF_44(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 44) JSONCONS_REP_OF_43(Call, Expr, , App) +#define JSONCONS_REP_OF_43(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 43) JSONCONS_REP_OF_42(Call, Expr, , App) +#define JSONCONS_REP_OF_42(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 42) JSONCONS_REP_OF_41(Call, Expr, , App) +#define JSONCONS_REP_OF_41(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 41) JSONCONS_REP_OF_40(Call, Expr, , App) +#define JSONCONS_REP_OF_40(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 40) JSONCONS_REP_OF_39(Call, Expr, , App) +#define JSONCONS_REP_OF_39(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 39) JSONCONS_REP_OF_38(Call, Expr, , App) +#define JSONCONS_REP_OF_38(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 38) JSONCONS_REP_OF_37(Call, Expr, , App) +#define JSONCONS_REP_OF_37(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 37) JSONCONS_REP_OF_36(Call, Expr, , App) +#define JSONCONS_REP_OF_36(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 36) JSONCONS_REP_OF_35(Call, Expr, , App) +#define JSONCONS_REP_OF_35(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 35) JSONCONS_REP_OF_34(Call, Expr, , App) +#define JSONCONS_REP_OF_34(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 34) JSONCONS_REP_OF_33(Call, Expr, , App) +#define JSONCONS_REP_OF_33(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 33) JSONCONS_REP_OF_32(Call, Expr, , App) +#define JSONCONS_REP_OF_32(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 32) JSONCONS_REP_OF_31(Call, Expr, , App) +#define JSONCONS_REP_OF_31(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 31) JSONCONS_REP_OF_30(Call, Expr, , App) +#define JSONCONS_REP_OF_30(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 30) JSONCONS_REP_OF_29(Call, Expr, , App) +#define JSONCONS_REP_OF_29(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 29) JSONCONS_REP_OF_28(Call, Expr, , App) +#define JSONCONS_REP_OF_28(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 28) JSONCONS_REP_OF_27(Call, Expr, , App) +#define JSONCONS_REP_OF_27(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 27) JSONCONS_REP_OF_26(Call, Expr, , App) +#define JSONCONS_REP_OF_26(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 26) JSONCONS_REP_OF_25(Call, Expr, , App) +#define JSONCONS_REP_OF_25(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 25) JSONCONS_REP_OF_24(Call, Expr, , App) +#define JSONCONS_REP_OF_24(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 24) JSONCONS_REP_OF_23(Call, Expr, , App) +#define JSONCONS_REP_OF_23(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 23) JSONCONS_REP_OF_22(Call, Expr, , App) +#define JSONCONS_REP_OF_22(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 22) JSONCONS_REP_OF_21(Call, Expr, , App) +#define JSONCONS_REP_OF_21(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 21) JSONCONS_REP_OF_20(Call, Expr, , App) +#define JSONCONS_REP_OF_20(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 20) JSONCONS_REP_OF_19(Call, Expr, , App) +#define JSONCONS_REP_OF_19(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 19) JSONCONS_REP_OF_18(Call, Expr, , App) +#define JSONCONS_REP_OF_18(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 18) JSONCONS_REP_OF_17(Call, Expr, , App) +#define JSONCONS_REP_OF_17(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 17) JSONCONS_REP_OF_16(Call, Expr, , App) +#define JSONCONS_REP_OF_16(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 16) JSONCONS_REP_OF_15(Call, Expr, , App) +#define JSONCONS_REP_OF_15(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 15) JSONCONS_REP_OF_14(Call, Expr, , App) +#define JSONCONS_REP_OF_14(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 14) JSONCONS_REP_OF_13(Call, Expr, , App) +#define JSONCONS_REP_OF_13(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 13) JSONCONS_REP_OF_12(Call, Expr, , App) +#define JSONCONS_REP_OF_12(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 12) JSONCONS_REP_OF_11(Call, Expr, , App) +#define JSONCONS_REP_OF_11(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 11) JSONCONS_REP_OF_10(Call, Expr, , App) +#define JSONCONS_REP_OF_10(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 10) JSONCONS_REP_OF_9(Call, Expr, , App) +#define JSONCONS_REP_OF_9(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 9) JSONCONS_REP_OF_8(Call, Expr, , App) +#define JSONCONS_REP_OF_8(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 8) JSONCONS_REP_OF_7(Call, Expr, , App) +#define JSONCONS_REP_OF_7(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 7) JSONCONS_REP_OF_6(Call, Expr, , App) +#define JSONCONS_REP_OF_6(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 6) JSONCONS_REP_OF_5(Call, Expr, , App) +#define JSONCONS_REP_OF_5(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 5) JSONCONS_REP_OF_4(Call, Expr, , App) +#define JSONCONS_REP_OF_4(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 4) JSONCONS_REP_OF_3(Call, Expr, , App) +#define JSONCONS_REP_OF_3(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 3) JSONCONS_REP_OF_2(Call, Expr, , App) +#define JSONCONS_REP_OF_2(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call, Expr, 2) JSONCONS_REP_OF_1(Call, Expr, , App) +#define JSONCONS_REP_OF_1(Call, Expr, Pre, App) Pre JSONCONS_EXPAND_CALL2(Call ## _LAST, Expr, 1) App +#define JSONCONS_REP_OF_0(Call, Expr, Pre, App) + +#define JSONCONS_GENERATE_TPL_PARAMS(Call, Count) JSONCONS_REP_OF_N(Call, , , ,Count) +#define JSONCONS_GENERATE_TPL_ARGS(Call, Count) JSONCONS_REP_OF_N(Call, ,<,>,Count) +#define JSONCONS_GENERATE_TPL_PARAM(Expr, Id) typename T ## Id, +#define JSONCONS_GENERATE_TPL_PARAM_LAST(Expr, Id) typename T ## Id +#define JSONCONS_GENERATE_MORE_TPL_PARAM(Expr, Id) , typename T ## Id +#define JSONCONS_GENERATE_MORE_TPL_PARAM_LAST(Expr, Id) , typename T ## Id +#define JSONCONS_GENERATE_TPL_ARG(Expr, Id) T ## Id, +#define JSONCONS_GENERATE_TPL_ARG_LAST(Ex, Id) T ## Id + +#define JSONCONS_GENERATE_NAME_STR(Prefix, P2, P3, Member, Count) JSONCONS_GENERATE_NAME_STR_LAST(Prefix, P2, P3, Member, Count) +#define JSONCONS_GENERATE_NAME_STR_LAST(Prefix, P2, P3, Member, Count) \ + static inline const char* Member ## _str(char) {return JSONCONS_QUOTE(,Member);} \ + static inline const wchar_t* Member ## _str(wchar_t) {return JSONCONS_QUOTE(L,Member);} \ + /**/ + +#define JSONCONS_N_MEMBER_IS(Prefix, P2, P3, Member, Count) JSONCONS_N_MEMBER_IS_LAST(Prefix, P2, P3, Member, Count) +#define JSONCONS_N_MEMBER_IS_LAST(Prefix, P2, P3, Member, Count) if ((num_params-Count) < num_mandatory_params1 && !ajson.contains(json_traits_macro_names::Member##_str(char_type{}))) return false; + +#define JSONCONS_N_MEMBER_AS(Prefix,P2,P3, Member, Count) JSONCONS_N_MEMBER_AS_LAST(Prefix,P2,P3, Member, Count) +#define JSONCONS_N_MEMBER_AS_LAST(Prefix,P2,P3, Member, Count) \ + if ((num_params-Count) < num_mandatory_params2 || ajson.contains(json_traits_macro_names::Member##_str(char_type{}))) \ + {json_traits_helper::set_udt_member(ajson,json_traits_macro_names::Member##_str(char_type{}),aval.Member);} + +#define JSONCONS_ALL_MEMBER_AS(Prefix, P2,P3,Member, Count) JSONCONS_ALL_MEMBER_AS_LAST(Prefix,P2,P3, Member, Count) +#define JSONCONS_ALL_MEMBER_AS_LAST(Prefix,P2,P3, Member, Count) \ + json_traits_helper::set_udt_member(ajson,json_traits_macro_names::Member##_str(char_type{}),aval.Member); + +#define JSONCONS_TO_JSON(Prefix, P2, P3, Member, Count) JSONCONS_TO_JSON_LAST(Prefix, P2, P3, Member, Count) +#define JSONCONS_TO_JSON_LAST(Prefix, P2, P3, Member, Count) if ((num_params-Count) < num_mandatory_params2) \ + {ajson.try_emplace(json_traits_macro_names::Member##_str(char_type{}), aval.Member);} \ + else {json_traits_helper::set_optional_json_member(json_traits_macro_names::Member##_str(char_type{}), aval.Member, ajson);} + +#define JSONCONS_ALL_TO_JSON(Prefix, P2, P3, Member, Count) JSONCONS_ALL_TO_JSON_LAST(Prefix, P2, P3, Member, Count) +#define JSONCONS_ALL_TO_JSON_LAST(Prefix, P2, P3, Member, Count) \ + ajson.try_emplace(json_traits_macro_names::Member##_str(char_type{}), aval.Member); + +#define JSONCONS_MEMBER_TRAITS_BASE(AsT,ToJ,NumTemplateParams,ValueType,NumMandatoryParams1,NumMandatoryParams2, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_traits_macro_names \ + { \ + JSONCONS_VARIADIC_REP_N(JSONCONS_GENERATE_NAME_STR, ,,, __VA_ARGS__)\ + }; \ + template \ + struct json_type_traits \ + { \ + using value_type = ValueType JSONCONS_GENERATE_TPL_ARGS(JSONCONS_GENERATE_TPL_ARG, NumTemplateParams); \ + using allocator_type = typename Json::allocator_type; \ + using char_type = typename Json::char_type; \ + using string_view_type = typename Json::string_view_type; \ + constexpr static size_t num_params = JSONCONS_NARGS(__VA_ARGS__); \ + constexpr static size_t num_mandatory_params1 = NumMandatoryParams1; \ + constexpr static size_t num_mandatory_params2 = NumMandatoryParams2; \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_N_MEMBER_IS, ,,, __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # ValueType)); \ + value_type aval{}; \ + JSONCONS_VARIADIC_REP_N(AsT, ,,, __VA_ARGS__) \ + return aval; \ + } \ + static Json to_json(const value_type& aval, allocator_type alloc=allocator_type()) \ + { \ + Json ajson(json_object_arg, semantic_tag::none, alloc); \ + JSONCONS_VARIADIC_REP_N(ToJ, ,,, __VA_ARGS__) \ + return ajson; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_N_MEMBER_TRAITS(ValueType,NumMandatoryParams,...) \ + JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_N_MEMBER_AS, JSONCONS_TO_JSON,0, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_N_MEMBER_TRAITS(NumTemplateParams, ValueType,NumMandatoryParams, ...) \ + JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_N_MEMBER_AS, JSONCONS_TO_JSON,NumTemplateParams, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_ALL_MEMBER_TRAITS(ValueType, ...) \ + JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_ALL_MEMBER_AS,JSONCONS_ALL_TO_JSON,0,ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__),__VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_ALL_MEMBER_TRAITS(NumTemplateParams, ValueType, ...) \ + JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_ALL_MEMBER_AS,JSONCONS_ALL_TO_JSON,NumTemplateParams,ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__),__VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_MEMBER_NAME_IS(P1, P2, P3, Seq, Count) JSONCONS_MEMBER_NAME_IS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_MEMBER_NAME_IS_LAST(P1, P2, P3, Seq, Count) if ((num_params-Count) < num_mandatory_params1 && JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_MEMBER_NAME_IS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_MEMBER_NAME_IS_2(Member, Name) !ajson.contains(Name)) return false; +#define JSONCONS_MEMBER_NAME_IS_3(Member, Name, Mode) JSONCONS_MEMBER_NAME_IS_2(Member, Name) +#define JSONCONS_MEMBER_NAME_IS_4(Member, Name, Mode, Match) JSONCONS_MEMBER_NAME_IS_6(Member, Name, Mode, Match, , ) +#define JSONCONS_MEMBER_NAME_IS_5(Member, Name, Mode, Match, Into) JSONCONS_MEMBER_NAME_IS_6(Member, Name, Mode, Match, Into, ) +#define JSONCONS_MEMBER_NAME_IS_6(Member, Name, Mode, Match, Into, From) !ajson.contains(Name)) return false; \ + JSONCONS_TRY{if (!Match(ajson.at(Name).template as())->Member))>::type>())) return false;} \ + JSONCONS_CATCH(...) {return false;} + +#define JSONCONS_N_MEMBER_NAME_AS(P1, P2, P3, Seq, Count) JSONCONS_N_MEMBER_NAME_AS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_N_MEMBER_NAME_AS_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_N_MEMBER_NAME_AS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_N_MEMBER_NAME_AS_2(Member, Name) \ + if (ajson.contains(Name)) {json_traits_helper::set_udt_member(ajson,Name,aval.Member);} +#define JSONCONS_N_MEMBER_NAME_AS_3(Member, Name, Mode) Mode(JSONCONS_N_MEMBER_NAME_AS_2(Member, Name)) +#define JSONCONS_N_MEMBER_NAME_AS_4(Member, Name, Mode, Match) \ + Mode(if (ajson.contains(Name)) {json_traits_helper::set_udt_member(ajson,Name,aval.Member);}) +#define JSONCONS_N_MEMBER_NAME_AS_5(Member, Name, Mode, Match, Into) \ + Mode(if (ajson.contains(Name)) {json_traits_helper::template set_udt_member())->Member))>::type>(ajson,Name,aval.Member);}) +#define JSONCONS_N_MEMBER_NAME_AS_6(Member, Name, Mode, Match, Into, From) \ + Mode(if (ajson.contains(Name)) {json_traits_helper::template set_udt_member())->Member))>::type>(ajson,Name,From,aval.Member);}) + +#define JSONCONS_ALL_MEMBER_NAME_AS(P1, P2, P3, Seq, Count) JSONCONS_ALL_MEMBER_NAME_AS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_ALL_MEMBER_NAME_AS_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_ALL_MEMBER_NAME_AS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_ALL_MEMBER_NAME_AS_2(Member, Name) \ + json_traits_helper::set_udt_member(ajson,Name,aval.Member); +#define JSONCONS_ALL_MEMBER_NAME_AS_3(Member, Name, Mode) Mode(JSONCONS_ALL_MEMBER_NAME_AS_2(Member, Name)) +#define JSONCONS_ALL_MEMBER_NAME_AS_4(Member, Name, Mode, Match) \ + Mode(json_traits_helper::set_udt_member(ajson,Name,aval.Member);) +#define JSONCONS_ALL_MEMBER_NAME_AS_5(Member, Name, Mode, Match, Into) \ + Mode(json_traits_helper::template set_udt_member())->Member))>::type>(ajson,Name,aval.Member);) +#define JSONCONS_ALL_MEMBER_NAME_AS_6(Member, Name, Mode, Match, Into, From) \ + Mode(json_traits_helper::template set_udt_member())->Member))>::type>(ajson,Name,From,aval.Member);) + +#define JSONCONS_N_MEMBER_NAME_TO_JSON(P1, P2, P3, Seq, Count) JSONCONS_N_MEMBER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_N_MEMBER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) if ((num_params-Count) < num_mandatory_params2) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_N_MEMBER_NAME_TO_JSON_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_N_MEMBER_NAME_TO_JSON_2(Member, Name) \ + {ajson.try_emplace(Name, aval.Member);} \ +else \ + {json_traits_helper::set_optional_json_member(Name, aval.Member, ajson);} +#define JSONCONS_N_MEMBER_NAME_TO_JSON_3(Member, Name, Mode) JSONCONS_N_MEMBER_NAME_TO_JSON_2(Member, Name) +#define JSONCONS_N_MEMBER_NAME_TO_JSON_4(Member, Name, Mode, Match) JSONCONS_N_MEMBER_NAME_TO_JSON_6(Member, Name, Mode, Match,,) +#define JSONCONS_N_MEMBER_NAME_TO_JSON_5(Member, Name, Mode, Match, Into) JSONCONS_N_MEMBER_NAME_TO_JSON_6(Member, Name, Mode, Match, Into, ) +#define JSONCONS_N_MEMBER_NAME_TO_JSON_6(Member, Name, Mode, Match, Into, From) \ + {ajson.try_emplace(Name, Into(aval.Member));} \ +else \ + {json_traits_helper::set_optional_json_member(Name, Into(aval.Member), ajson);} + +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON(P1, P2, P3, Seq, Count) JSONCONS_ALL_MEMBER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_ALL_MEMBER_NAME_TO_JSON_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON_2(Member, Name) ajson.try_emplace(Name, aval.Member); +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON_3(Member, Name, Mode) JSONCONS_ALL_MEMBER_NAME_TO_JSON_2(Member, Name) +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON_4(Member, Name, Mode, Match) JSONCONS_ALL_MEMBER_NAME_TO_JSON_6(Member, Name, Mode, Match,,) +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON_5(Member, Name, Mode, Match, Into) JSONCONS_ALL_MEMBER_NAME_TO_JSON_6(Member, Name, Mode, Match, Into, ) +#define JSONCONS_ALL_MEMBER_NAME_TO_JSON_6(Member, Name, Mode, Match, Into, From) ajson.try_emplace(Name, Into(aval.Member)); + +#define JSONCONS_MEMBER_NAME_TRAITS_BASE(AsT,ToJ, NumTemplateParams, ValueType,NumMandatoryParams1,NumMandatoryParams2, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_type_traits \ + { \ + using value_type = ValueType JSONCONS_GENERATE_TPL_ARGS(JSONCONS_GENERATE_TPL_ARG, NumTemplateParams); \ + using allocator_type = typename Json::allocator_type; \ + using char_type = typename Json::char_type; \ + using string_view_type = typename Json::string_view_type; \ + constexpr static size_t num_params = JSONCONS_NARGS(__VA_ARGS__); \ + constexpr static size_t num_mandatory_params1 = NumMandatoryParams1; \ + constexpr static size_t num_mandatory_params2 = NumMandatoryParams2; \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_MEMBER_NAME_IS,,,, __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # ValueType)); \ + value_type aval{}; \ + JSONCONS_VARIADIC_REP_N(AsT,,,, __VA_ARGS__) \ + return aval; \ + } \ + static Json to_json(const value_type& aval, allocator_type alloc=allocator_type()) \ + { \ + Json ajson(json_object_arg, semantic_tag::none, alloc); \ + JSONCONS_VARIADIC_REP_N(ToJ,,,, __VA_ARGS__) \ + return ajson; \ + } \ + }; \ +} \ + /**/ + + +#define JSONCONS_N_MEMBER_NAME_TRAITS(ValueType,NumMandatoryParams, ...) \ + JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_N_MEMBER_NAME_AS, JSONCONS_N_MEMBER_NAME_TO_JSON, 0, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_N_MEMBER_NAME_TRAITS(NumTemplateParams, ValueType,NumMandatoryParams, ...) \ + JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_N_MEMBER_NAME_AS, JSONCONS_N_MEMBER_NAME_TO_JSON, NumTemplateParams, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_ALL_MEMBER_NAME_TRAITS(ValueType, ...) \ + JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_ALL_MEMBER_NAME_AS, JSONCONS_ALL_MEMBER_NAME_TO_JSON, 0, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS(NumTemplateParams, ValueType, ...) \ + JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_ALL_MEMBER_NAME_AS, JSONCONS_ALL_MEMBER_NAME_TO_JSON, NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_CTOR_GETTER_IS(Prefix, P2, P3, Getter, Count) JSONCONS_CTOR_GETTER_IS_LAST(Prefix, P2, P3, Getter, Count) +#define JSONCONS_CTOR_GETTER_IS_LAST(Prefix, P2, P3, Getter, Count) if ((num_params-Count) < num_mandatory_params1 && !ajson.contains(json_traits_macro_names::Getter##_str(char_type{}))) return false; + +#define JSONCONS_CTOR_GETTER_AS(Prefix, P2, P3, Getter, Count) JSONCONS_CTOR_GETTER_AS_LAST(Prefix, P2, P3, Getter, Count), +#define JSONCONS_CTOR_GETTER_AS_LAST(Prefix, P2, P3, Getter, Count) ((num_params-Count) < num_mandatory_params2) ? (ajson.at(json_traits_macro_names::Getter##_str(char_type{}))).template as())->Getter())>::type>() : (ajson.contains(json_traits_macro_names::Getter##_str(char_type{})) ? (ajson.at(json_traits_macro_names::Getter##_str(char_type{}))).template as())->Getter())>::type>() : typename std::decay())->Getter())>::type()) + +#define JSONCONS_CTOR_GETTER_TO_JSON(Prefix, P2, P3, Getter, Count) JSONCONS_CTOR_GETTER_TO_JSON_LAST(Prefix, P2, P3, Getter, Count) + +#define JSONCONS_CTOR_GETTER_TO_JSON_LAST(Prefix, P2, P3, Getter, Count) \ +if ((num_params-Count) < num_mandatory_params2) { \ + ajson.try_emplace(json_traits_macro_names::Getter##_str(char_type{}), aval.Getter() ); \ + } \ +else { \ + json_traits_helper::set_optional_json_member(json_traits_macro_names::Getter##_str(char_type{}), aval.Getter(), ajson); \ +} + +#define JSONCONS_CTOR_GETTER_TRAITS_BASE(NumTemplateParams, ValueType,NumMandatoryParams1,NumMandatoryParams2, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_traits_macro_names \ + { \ + JSONCONS_VARIADIC_REP_N(JSONCONS_GENERATE_NAME_STR, ,,, __VA_ARGS__)\ + }; \ + template \ + struct json_type_traits \ + { \ + using value_type = ValueType JSONCONS_GENERATE_TPL_ARGS(JSONCONS_GENERATE_TPL_ARG, NumTemplateParams); \ + using allocator_type = typename Json::allocator_type; \ + using char_type = typename Json::char_type; \ + using string_view_type = typename Json::string_view_type; \ + constexpr static size_t num_params = JSONCONS_NARGS(__VA_ARGS__); \ + constexpr static size_t num_mandatory_params1 = NumMandatoryParams1; \ + constexpr static size_t num_mandatory_params2 = NumMandatoryParams2; \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_CTOR_GETTER_IS, ,,, __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # ValueType)); \ + return value_type ( JSONCONS_VARIADIC_REP_N(JSONCONS_CTOR_GETTER_AS, ,,, __VA_ARGS__) ); \ + } \ + static Json to_json(const value_type& aval, allocator_type alloc=allocator_type()) \ + { \ + Json ajson(json_object_arg, semantic_tag::none, alloc); \ + JSONCONS_VARIADIC_REP_N(JSONCONS_CTOR_GETTER_TO_JSON, ,,, __VA_ARGS__) \ + return ajson; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_ALL_CTOR_GETTER_TRAITS(ValueType, ...) \ + JSONCONS_CTOR_GETTER_TRAITS_BASE(0, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_ALL_CTOR_GETTER_TRAITS(NumTemplateParams, ValueType, ...) \ + JSONCONS_CTOR_GETTER_TRAITS_BASE(NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_N_CTOR_GETTER_TRAITS(ValueType,NumMandatoryParams, ...) \ + JSONCONS_CTOR_GETTER_TRAITS_BASE(0, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_N_ALL_CTOR_GETTER_TRAITS(NumTemplateParams, ValueType,NumMandatoryParams, ...) \ + JSONCONS_CTOR_GETTER_TRAITS_BASE(NumTemplateParams, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_CTOR_GETTER_NAME_IS(P1, P2, P3, Seq, Count) JSONCONS_CTOR_GETTER_NAME_IS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_CTOR_GETTER_NAME_IS_LAST(P1, P2, P3, Seq, Count) if ((num_params-Count) < num_mandatory_params1 && JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_CTOR_GETTER_NAME_IS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_CTOR_GETTER_NAME_IS_2(Getter, Name) !ajson.contains(Name)) return false; +#define JSONCONS_CTOR_GETTER_NAME_IS_3(Getter, Name, Mode) JSONCONS_CTOR_GETTER_NAME_IS_2(Getter, Name) +#define JSONCONS_CTOR_GETTER_NAME_IS_4(Getter, Name, Mode, Match) JSONCONS_CTOR_GETTER_NAME_IS_6(Getter, Name, Mode, Match, , ) +#define JSONCONS_CTOR_GETTER_NAME_IS_5(Getter, Name, Mode, Match, Into) JSONCONS_CTOR_GETTER_NAME_IS_6(Getter, Name, Mode, Match, Into, ) +#define JSONCONS_CTOR_GETTER_NAME_IS_6(Getter, Name, Mode, Match, Into, From) !ajson.contains(Name)) return false; \ + JSONCONS_TRY{if (!Match(ajson.at(Name).template as())->Getter()))>::type>())) return false;} \ + JSONCONS_CATCH(...) {return false;} + +#define JSONCONS_CTOR_GETTER_NAME_AS(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_CTOR_GETTER_NAME_AS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_CTOR_GETTER_NAME_AS_2(Getter, Name) JSONCONS_CTOR_GETTER_NAME_AS_LAST_2(Getter, Name) JSONCONS_COMMA +#define JSONCONS_CTOR_GETTER_NAME_AS_3(Getter, Name, Mode) Mode(JSONCONS_CTOR_GETTER_NAME_AS_LAST_2(Getter, Name)) Mode(JSONCONS_COMMA) +#define JSONCONS_CTOR_GETTER_NAME_AS_4(Getter, Name, Mode, Match) JSONCONS_CTOR_GETTER_NAME_AS_6(Getter, Name, Mode, Match,,) +#define JSONCONS_CTOR_GETTER_NAME_AS_5(Getter, Name, Mode, Match, Into) JSONCONS_CTOR_GETTER_NAME_AS_6(Getter, Name, Mode, Match, Into, ) +#define JSONCONS_CTOR_GETTER_NAME_AS_6(Getter, Name, Mode, Match, Into, From) JSONCONS_CTOR_GETTER_NAME_AS_LAST_6(Getter,Name,Mode,Match,Into,From) Mode(JSONCONS_COMMA) +#define JSONCONS_COMMA , + +#define JSONCONS_CTOR_GETTER_NAME_AS_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_CTOR_GETTER_NAME_AS_LAST_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_CTOR_GETTER_NAME_AS_LAST_2(Getter, Name) (ajson.contains(Name)) ? (ajson.at(Name)).template as())->Getter())>::type>() : typename std::decay())->Getter())>::type() +#define JSONCONS_CTOR_GETTER_NAME_AS_LAST_3(Getter, Name, Mode) Mode(JSONCONS_CTOR_GETTER_NAME_AS_LAST_2(Getter, Name)) +#define JSONCONS_CTOR_GETTER_NAME_AS_LAST_4(Getter, Name, Mode, Match) JSONCONS_CTOR_GETTER_NAME_AS_LAST_6(Getter, Name, Mode, Match,,) +#define JSONCONS_CTOR_GETTER_NAME_AS_LAST_5(Getter, Name, Mode, Match, Into) JSONCONS_CTOR_GETTER_NAME_AS_LAST_6(Getter, Name, Mode, Match, Into, ) +#define JSONCONS_CTOR_GETTER_NAME_AS_LAST_6(Getter, Name, Mode, Match, Into, From) Mode(ajson.contains(Name) ? From(ajson.at(Name).template as())->Getter()))>::type>()) : From(typename std::decay())->Getter()))>::type())) + +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON(P1, P2, P3, Seq, Count) JSONCONS_CTOR_GETTER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) if ((num_params-Count) < num_mandatory_params2) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_CTOR_GETTER_NAME_TO_JSON_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON_2(Getter, Name) \ +{ \ + ajson.try_emplace(Name, aval.Getter() ); \ +} \ +else { \ + json_traits_helper::set_optional_json_member(Name, aval.Getter(), ajson); \ +} +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON_3(Getter, Name, Mode) JSONCONS_CTOR_GETTER_NAME_TO_JSON_2(Getter, Name) +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON_4(Getter, Name, Mode, Match) JSONCONS_CTOR_GETTER_NAME_TO_JSON_2(Getter, Name) +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON_5(Getter, Name, Mode, Match, Into) JSONCONS_CTOR_GETTER_NAME_TO_JSON_6(Getter, Name, Mode, Match, Into, ) +#define JSONCONS_CTOR_GETTER_NAME_TO_JSON_6(Getter, Name, Mode, Match, Into, From) \ +{ \ + ajson.try_emplace(Name, Into(aval.Getter()) ); \ +} \ +else { \ + json_traits_helper::set_optional_json_member(Name, Into(aval.Getter()), ajson); \ +} + +#define JSONCONS_CTOR_GETTER_NAME_TRAITS_BASE(NumTemplateParams, ValueType,NumMandatoryParams1,NumMandatoryParams2, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_type_traits \ + { \ + using value_type = ValueType JSONCONS_GENERATE_TPL_ARGS(JSONCONS_GENERATE_TPL_ARG, NumTemplateParams); \ + using allocator_type = typename Json::allocator_type; \ + using char_type = typename Json::char_type; \ + using string_view_type = typename Json::string_view_type; \ + constexpr static size_t num_params = JSONCONS_NARGS(__VA_ARGS__); \ + constexpr static size_t num_mandatory_params1 = NumMandatoryParams1; \ + constexpr static size_t num_mandatory_params2 = NumMandatoryParams2; \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_CTOR_GETTER_NAME_IS,,,, __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # ValueType)); \ + return value_type ( JSONCONS_VARIADIC_REP_N(JSONCONS_CTOR_GETTER_NAME_AS,,,, __VA_ARGS__) ); \ + } \ + static Json to_json(const value_type& aval, allocator_type alloc=allocator_type()) \ + { \ + Json ajson(json_object_arg, semantic_tag::none, alloc); \ + JSONCONS_VARIADIC_REP_N(JSONCONS_CTOR_GETTER_NAME_TO_JSON,,,, __VA_ARGS__) \ + return ajson; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_ALL_CTOR_GETTER_NAME_TRAITS(ValueType, ...) \ + JSONCONS_CTOR_GETTER_NAME_TRAITS_BASE(0, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_ALL_CTOR_GETTER_NAME_TRAITS(NumTemplateParams, ValueType, ...) \ + JSONCONS_CTOR_GETTER_NAME_TRAITS_BASE(NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_N_CTOR_GETTER_NAME_TRAITS(ValueType,NumMandatoryParams, ...) \ + JSONCONS_CTOR_GETTER_NAME_TRAITS_BASE(0, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_N_CTOR_GETTER_NAME_TRAITS(NumTemplateParams, ValueType,NumMandatoryParams, ...) \ +JSONCONS_CTOR_GETTER_NAME_TRAITS_BASE(NumTemplateParams, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_ENUM_PAIR(Prefix, P2, P3, Member, Count) JSONCONS_ENUM_PAIR_LAST(Prefix, P2, P3, Member, Count), +#define JSONCONS_ENUM_PAIR_LAST(Prefix, P2, P3, Member, Count) {value_type::Member, json_traits_macro_names::Member##_str(char_type{})} + +#define JSONCONS_ENUM_TRAITS_BASE(EnumType, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_traits_macro_names \ + { \ + JSONCONS_VARIADIC_REP_N(JSONCONS_GENERATE_NAME_STR, ,,, __VA_ARGS__)\ + }; \ + template \ + struct json_type_traits \ + { \ + static_assert(std::is_enum::value, # EnumType " must be an enum"); \ + using value_type = EnumType; \ + using char_type = typename Json::char_type; \ + using string_type = std::basic_string; \ + using string_view_type = jsoncons::basic_string_view; \ + using allocator_type = typename Json::allocator_type; \ + using mapped_type = std::pair; \ + \ + static std::pair get_values() \ + { \ + static const mapped_type v[] = { \ + JSONCONS_VARIADIC_REP_N(JSONCONS_ENUM_PAIR, ,,, __VA_ARGS__)\ + };\ + return std::make_pair(v,v+JSONCONS_NARGS(__VA_ARGS__)); \ + } \ + \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_string()) return false; \ + auto first = get_values().first; \ + auto last = get_values().second; \ + const string_view_type s = ajson.template as(); \ + if (s.empty() && std::find_if(first, last, \ + [](const mapped_type& item) -> bool \ + { return item.first == value_type(); }) == last) \ + { \ + return true; \ + } \ + auto it = std::find_if(first, last, \ + [&](const mapped_type& item) -> bool \ + { return item.second == s; }); \ + return it != last; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # EnumType)); \ + const string_view_type s = ajson.template as(); \ + auto first = get_values().first; \ + auto last = get_values().second; \ + if (s.empty() && std::find_if(first, last, \ + [](const mapped_type& item) -> bool \ + { return item.first == value_type(); }) == last) \ + { \ + return value_type(); \ + } \ + auto it = std::find_if(first, last, \ + [&](const mapped_type& item) -> bool \ + { return item.second == s; }); \ + if (it == last) \ + { \ + if (s.empty()) \ + { \ + return value_type(); \ + } \ + else \ + { \ + JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not an enum")); \ + } \ + } \ + return it->first; \ + } \ + static Json to_json(value_type aval, allocator_type alloc=allocator_type()) \ + { \ + static constexpr char_type empty_string[] = {0}; \ + auto first = get_values().first; \ + auto last = get_values().second; \ + auto it = std::find_if(first, last, \ + [aval](const mapped_type& item) -> bool \ + { return item.first == aval; }); \ + if (it == last) \ + { \ + if (aval == value_type()) \ + { \ + return Json(empty_string); \ + } \ + else \ + { \ + JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not an enum")); \ + } \ + } \ + return Json(it->second,alloc); \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_ENUM_TRAITS(EnumType, ...) \ + JSONCONS_ENUM_TRAITS_BASE(EnumType,__VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_NAME_ENUM_PAIR(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_NAME_ENUM_PAIR_ Seq), +#define JSONCONS_NAME_ENUM_PAIR_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_NAME_ENUM_PAIR_ Seq) +#define JSONCONS_NAME_ENUM_PAIR_(Member, Name) {value_type::Member, Name} + +#define JSONCONS_ENUM_NAME_TRAITS(EnumType, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_type_traits \ + { \ + static_assert(std::is_enum::value, # EnumType " must be an enum"); \ + using value_type = EnumType; \ + using char_type = typename Json::char_type; \ + using string_type = std::basic_string; \ + using string_view_type = jsoncons::basic_string_view; \ + using allocator_type = typename Json::allocator_type; \ + using mapped_type = std::pair; \ + \ + static std::pair get_values() \ + { \ + static const mapped_type v[] = { \ + JSONCONS_VARIADIC_REP_N(JSONCONS_NAME_ENUM_PAIR,,,, __VA_ARGS__)\ + };\ + return std::make_pair(v,v+JSONCONS_NARGS(__VA_ARGS__)); \ + } \ + \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_string()) return false; \ + auto first = get_values().first; \ + auto last = get_values().second; \ + const string_view_type s = ajson.template as(); \ + if (s.empty() && std::find_if(first, last, \ + [](const mapped_type& item) -> bool \ + { return item.first == value_type(); }) == last) \ + { \ + return true; \ + } \ + auto it = std::find_if(first, last, \ + [&](const mapped_type& item) -> bool \ + { return item.second == s; }); \ + return it != last; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # EnumType)); \ + const string_view_type s = ajson.template as(); \ + auto first = get_values().first; \ + auto last = get_values().second; \ + if (s.empty() && std::find_if(first, last, \ + [](const mapped_type& item) -> bool \ + { return item.first == value_type(); }) == last) \ + { \ + return value_type(); \ + } \ + auto it = std::find_if(first, last, \ + [&](const mapped_type& item) -> bool \ + { return item.second == s; }); \ + if (it == last) \ + { \ + if (s.empty()) \ + { \ + return value_type(); \ + } \ + else \ + { \ + JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not an enum")); \ + } \ + } \ + return it->first; \ + } \ + static Json to_json(value_type aval, allocator_type alloc=allocator_type()) \ + { \ + static constexpr char_type empty_string[] = {0}; \ + auto first = get_values().first; \ + auto last = get_values().second; \ + auto it = std::find_if(first, last, \ + [aval](const mapped_type& item) -> bool \ + { return item.first == aval; }); \ + if (it == last) \ + { \ + if (aval == value_type()) \ + { \ + return Json(empty_string); \ + } \ + else \ + { \ + JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not an enum")); \ + } \ + } \ + return Json(it->second,alloc); \ + } \ + }; \ + template <> struct is_json_type_traits_declared : public std::true_type {}; \ +} \ + /**/ + +#define JSONCONS_GETTER_SETTER_AS(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_GETTER_SETTER_AS_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_GETTER_SETTER_AS_LAST(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_GETTER_SETTER_AS_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_GETTER_SETTER_AS_(Prefix, Getter, Setter, Property, Count) if ((num_params-Count) < num_mandatory_params2 || ajson.contains(json_traits_macro_names::Property##_str(char_type{}))) {aval.Setter(ajson.at(json_traits_macro_names::Property##_str(char_type{})).template as::type>());} + +#define JSONCONS_ALL_GETTER_SETTER_AS(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_ALL_GETTER_SETTER_AS_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_ALL_GETTER_SETTER_AS_LAST(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_ALL_GETTER_SETTER_AS_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_ALL_GETTER_SETTER_AS_(Prefix, Getter, Setter, Property, Count) aval.Setter(ajson.at(json_traits_macro_names::Property##_str(char_type{})).template as::type>()); + +#define JSONCONS_GETTER_SETTER_TO_JSON(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_GETTER_SETTER_TO_JSON_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_GETTER_SETTER_TO_JSON_LAST(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_GETTER_SETTER_TO_JSON_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_GETTER_SETTER_TO_JSON_(Prefix, Getter, Setter, Property, Count) \ +if ((num_params-Count) < num_mandatory_params2) \ + {ajson.try_emplace(json_traits_macro_names::Property##_str(char_type{}), aval.Getter());} \ +else \ + {json_traits_helper::set_optional_json_member(json_traits_macro_names::Property##_str(char_type{}), aval.Getter(), ajson);} + +#define JSONCONS_ALL_GETTER_SETTER_TO_JSON(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_ALL_GETTER_SETTER_TO_JSON_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_ALL_GETTER_SETTER_TO_JSON_LAST(Prefix, GetPrefix, SetPrefix, Property, Count) JSONCONS_ALL_GETTER_SETTER_TO_JSON_(Prefix, GetPrefix ## Property, SetPrefix ## Property, Property, Count) +#define JSONCONS_ALL_GETTER_SETTER_TO_JSON_(Prefix, Getter, Setter, Property, Count) ajson.try_emplace(json_traits_macro_names::Property##_str(char_type{}), aval.Getter() ); + +#define JSONCONS_GETTER_SETTER_TRAITS_BASE(AsT,ToJ,NumTemplateParams, ValueType,GetPrefix,SetPrefix,NumMandatoryParams1,NumMandatoryParams2, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_traits_macro_names \ + { \ + JSONCONS_VARIADIC_REP_N(JSONCONS_GENERATE_NAME_STR, ,,, __VA_ARGS__)\ + }; \ + template \ + struct json_type_traits \ + { \ + using value_type = ValueType JSONCONS_GENERATE_TPL_ARGS(JSONCONS_GENERATE_TPL_ARG, NumTemplateParams); \ + using allocator_type = typename Json::allocator_type; \ + using char_type = typename Json::char_type; \ + using string_view_type = typename Json::string_view_type; \ + constexpr static size_t num_params = JSONCONS_NARGS(__VA_ARGS__); \ + constexpr static size_t num_mandatory_params1 = NumMandatoryParams1; \ + constexpr static size_t num_mandatory_params2 = NumMandatoryParams2; \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_N_MEMBER_IS, ,GetPrefix,SetPrefix, __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # ValueType)); \ + value_type aval{}; \ + JSONCONS_VARIADIC_REP_N(AsT, ,GetPrefix,SetPrefix, __VA_ARGS__) \ + return aval; \ + } \ + static Json to_json(const value_type& aval, allocator_type alloc=allocator_type()) \ + { \ + Json ajson(json_object_arg, semantic_tag::none, alloc); \ + JSONCONS_VARIADIC_REP_N(ToJ, ,GetPrefix,SetPrefix, __VA_ARGS__) \ + return ajson; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_N_GETTER_SETTER_TRAITS(ValueType,GetPrefix,SetPrefix,NumMandatoryParams, ...) \ + JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_GETTER_SETTER_AS, JSONCONS_GETTER_SETTER_TO_JSON,0, ValueType,GetPrefix,SetPrefix,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_N_GETTER_SETTER_TRAITS(NumTemplateParams, ValueType,GetPrefix,SetPrefix,NumMandatoryParams, ...) \ + JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_GETTER_SETTER_AS, JSONCONS_GETTER_SETTER_TO_JSON,NumTemplateParams, ValueType,GetPrefix,SetPrefix,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_ALL_GETTER_SETTER_TRAITS(ValueType,GetPrefix,SetPrefix, ...) \ + JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_ALL_GETTER_SETTER_AS, JSONCONS_ALL_GETTER_SETTER_TO_JSON,0,ValueType,GetPrefix,SetPrefix, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__),__VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS(NumTemplateParams, ValueType,GetPrefix,SetPrefix, ...) \ + JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_ALL_GETTER_SETTER_AS, JSONCONS_ALL_GETTER_SETTER_TO_JSON,NumTemplateParams,ValueType,GetPrefix,SetPrefix, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__),__VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_GETTER_SETTER_NAME_IS(P1, P2, P3, Seq, Count) JSONCONS_GETTER_SETTER_NAME_IS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_GETTER_SETTER_NAME_IS_LAST(P1, P2, P3, Seq, Count) if ((num_params-Count) < num_mandatory_params1 && JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_GETTER_SETTER_NAME_IS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_GETTER_SETTER_NAME_IS_3(Getter, Setter, Name) !ajson.contains(Name)) return false; +#define JSONCONS_GETTER_SETTER_NAME_IS_5(Getter, Setter, Name, Mode, Match) JSONCONS_GETTER_SETTER_NAME_IS_7(Getter, Setter, Name, Mode, Match,, ) +#define JSONCONS_GETTER_SETTER_NAME_IS_6(Getter, Setter, Name, Mode, Match, Into) JSONCONS_GETTER_SETTER_NAME_IS_7(Getter, Setter, Name, Mode, Match, Into, ) +#define JSONCONS_GETTER_SETTER_NAME_IS_7(Getter, Setter, Name, Mode, Match, Into, From) !ajson.contains(Name)) return false; \ + JSONCONS_TRY{if (!Match(ajson.at(Name).template as())->Getter()))>::type>())) return false;} \ + JSONCONS_CATCH(...) {return false;} + +#define JSONCONS_N_GETTER_SETTER_NAME_AS(P1, P2, P3, Seq, Count) JSONCONS_N_GETTER_SETTER_NAME_AS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_N_GETTER_SETTER_NAME_AS_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_N_GETTER_SETTER_NAME_AS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_N_GETTER_SETTER_NAME_AS_3(Getter, Setter, Name) if (ajson.contains(Name)) aval.Setter(ajson.at(Name).template as::type>()); +#define JSONCONS_N_GETTER_SETTER_NAME_AS_4(Getter, Setter, Name, Mode) Mode(JSONCONS_N_GETTER_SETTER_NAME_AS_3(Getter, Setter, Name)) +#define JSONCONS_N_GETTER_SETTER_NAME_AS_5(Getter, Setter, Name, Mode, Match) JSONCONS_N_GETTER_SETTER_NAME_AS_7(Getter, Setter, Name, Mode, Match, , ) +#define JSONCONS_N_GETTER_SETTER_NAME_AS_6(Getter, Setter, Name, Mode, Match, Into) JSONCONS_N_GETTER_SETTER_NAME_AS_7(Getter, Setter, Name, Mode, Match, Into, ) +#define JSONCONS_N_GETTER_SETTER_NAME_AS_7(Getter, Setter, Name, Mode, Match, Into, From) Mode(if (ajson.contains(Name)) aval.Setter(From(ajson.at(Name).template as::type>()));) + +#define JSONCONS_N_GETTER_SETTER_NAME_TO_JSON(P1, P2, P3, Seq, Count) JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_3(Getter, Setter, Name) ajson.try_emplace(Name, aval.Getter() ); +#define JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_5(Getter, Setter, Name, Mode, Match) JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_7(Getter, Setter, Name, Mode, Match, , ) +#define JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_6(Getter, Setter, Name, Mode, Match, Into) JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_7(Getter, Setter, Name, Mode, Match, Into, ) +#define JSONCONS_N_GETTER_SETTER_NAME_TO_JSON_7(Getter, Setter, Name, Mode, Match, Into, From) ajson.try_emplace(Name, Into(aval.Getter()) ); + +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS(P1, P2, P3, Seq, Count) JSONCONS_ALL_GETTER_SETTER_NAME_AS_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS_LAST(P1, P2, P3, Seq, Count) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_ALL_GETTER_SETTER_NAME_AS_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS_3(Getter, Setter, Name) aval.Setter(ajson.at(Name).template as::type>()); +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS_4(Getter, Setter, Name, Mode) Mode(JSONCONS_ALL_GETTER_SETTER_NAME_AS_3(Getter, Setter, Name)) +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS_5(Getter, Setter, Name, Mode, Match) JSONCONS_ALL_GETTER_SETTER_NAME_AS_7(Getter, Setter, Name, Mode, Match, , ) +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS_6(Getter, Setter, Name, Mode, Match, Into) JSONCONS_ALL_GETTER_SETTER_NAME_AS_7(Getter, Setter, Name, Mode, Match, Into, ) +#define JSONCONS_ALL_GETTER_SETTER_NAME_AS_7(Getter, Setter, Name, Mode, Match, Into, From) Mode(aval.Setter(From(ajson.at(Name).template as::type>()));) + +#define JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON(P1, P2, P3, Seq, Count) JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) +#define JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_LAST(P1, P2, P3, Seq, Count) if ((num_params-Count) < num_mandatory_params2) JSONCONS_EXPAND(JSONCONS_CONCAT(JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_,JSONCONS_NARGS Seq) Seq) +#define JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_3(Getter, Setter, Name) \ + ajson.try_emplace(Name, aval.Getter()); \ +else \ + {json_traits_helper::set_optional_json_member(Name, aval.Getter(), ajson);} +#define JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_5(Getter, Setter, Name, Mode, Match) JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_7(Getter, Setter, Name, Mode, Match, , ) +#define JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_6(Getter, Setter, Name, Mode, Match, Into) JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_7(Getter, Setter, Name, Mode, Match, Into, ) +#define JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON_7(Getter, Setter, Name, Mode, Match, Into, From) \ + ajson.try_emplace(Name, Into(aval.Getter())); \ +else \ + {json_traits_helper::set_optional_json_member(Name, Into(aval.Getter()), ajson);} + +#define JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(AsT,ToJ, NumTemplateParams, ValueType,NumMandatoryParams1,NumMandatoryParams2, ...) \ +namespace jsoncons \ +{ \ + template \ + struct json_type_traits \ + { \ + using value_type = ValueType JSONCONS_GENERATE_TPL_ARGS(JSONCONS_GENERATE_TPL_ARG, NumTemplateParams); \ + using allocator_type = typename Json::allocator_type; \ + using char_type = typename Json::char_type; \ + using string_view_type = typename Json::string_view_type; \ + constexpr static size_t num_params = JSONCONS_NARGS(__VA_ARGS__); \ + constexpr static size_t num_mandatory_params1 = NumMandatoryParams1; \ + constexpr static size_t num_mandatory_params2 = NumMandatoryParams2; \ + static bool is(const Json& ajson) noexcept \ + { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_GETTER_SETTER_NAME_IS,,,, __VA_ARGS__)\ + return true; \ + } \ + static value_type as(const Json& ajson) \ + { \ + if (!is(ajson)) JSONCONS_THROW(conv_error(conv_errc::conversion_failed, "Not a " # ValueType)); \ + value_type aval{}; \ + JSONCONS_VARIADIC_REP_N(AsT,,,, __VA_ARGS__) \ + return aval; \ + } \ + static Json to_json(const value_type& aval, allocator_type alloc=allocator_type()) \ + { \ + Json ajson(json_object_arg, semantic_tag::none, alloc); \ + JSONCONS_VARIADIC_REP_N(ToJ,,,, __VA_ARGS__) \ + return ajson; \ + } \ + }; \ +} \ + /**/ + +#define JSONCONS_N_GETTER_SETTER_NAME_TRAITS(ValueType,NumMandatoryParams, ...) \ + JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_N_GETTER_SETTER_NAME_AS,JSONCONS_N_GETTER_SETTER_NAME_TO_JSON, 0, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_N_GETTER_SETTER_NAME_TRAITS(NumTemplateParams, ValueType,NumMandatoryParams, ...) \ + JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_N_GETTER_SETTER_NAME_AS,JSONCONS_N_GETTER_SETTER_NAME_TO_JSON, NumTemplateParams, ValueType,NumMandatoryParams,NumMandatoryParams, __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS(ValueType, ...) \ + JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_ALL_GETTER_SETTER_NAME_AS,JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON, 0, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template <> struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS(NumTemplateParams, ValueType, ...) \ + JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_ALL_GETTER_SETTER_NAME_AS,JSONCONS_ALL_GETTER_SETTER_NAME_TO_JSON, NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), JSONCONS_NARGS(__VA_ARGS__), __VA_ARGS__) \ + namespace jsoncons { template struct is_json_type_traits_declared : public std::true_type {}; } \ + /**/ + +#define JSONCONS_POLYMORPHIC_IS(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return true; +#define JSONCONS_POLYMORPHIC_IS_LAST(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return true; + +#define JSONCONS_POLYMORPHIC_AS(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return std::make_shared(ajson.template as()); +#define JSONCONS_POLYMORPHIC_AS_LAST(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return std::make_shared(ajson.template as()); + +#define JSONCONS_POLYMORPHIC_AS_UNIQUE_PTR(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return jsoncons::make_unique(ajson.template as()); +#define JSONCONS_POLYMORPHIC_AS_UNIQUE_PTR_LAST(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return jsoncons::make_unique(ajson.template as()); + +#define JSONCONS_POLYMORPHIC_AS_SHARED_PTR(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return std::make_shared(ajson.template as()); +#define JSONCONS_POLYMORPHIC_AS_SHARED_PTR_LAST(BaseClass, P2, P3, DerivedClass, Count) if (ajson.template is()) return std::make_shared(ajson.template as()); + +#define JSONCONS_POLYMORPHIC_TO_JSON(BaseClass, P2, P3, DerivedClass, Count) if (DerivedClass* p = dynamic_cast(ptr.get())) {return Json(*p);} +#define JSONCONS_POLYMORPHIC_TO_JSON_LAST(BaseClass, P2, P3, DerivedClass, Count) if (DerivedClass* p = dynamic_cast(ptr.get())) {return Json(*p);} + +#define JSONCONS_POLYMORPHIC_TRAITS(BaseClass, ...) \ +namespace jsoncons { \ + template \ + struct json_type_traits> { \ + static bool is(const Json& ajson) noexcept { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_POLYMORPHIC_IS, BaseClass,,, __VA_ARGS__)\ + return false; \ + } \ +\ + static std::shared_ptr as(const Json& ajson) { \ + if (!ajson.is_object()) return std::shared_ptr(); \ + JSONCONS_VARIADIC_REP_N(JSONCONS_POLYMORPHIC_AS_SHARED_PTR, BaseClass,,, __VA_ARGS__)\ + return std::shared_ptr(); \ + } \ +\ + static Json to_json(const std::shared_ptr& ptr) { \ + if (ptr.get() == nullptr) {return Json::null();} \ + JSONCONS_VARIADIC_REP_N(JSONCONS_POLYMORPHIC_TO_JSON, BaseClass,,, __VA_ARGS__)\ + return Json::null(); \ + } \ + }; \ + template \ + struct json_type_traits> { \ + static bool is(const Json& ajson) noexcept { \ + if (!ajson.is_object()) return false; \ + JSONCONS_VARIADIC_REP_N(JSONCONS_POLYMORPHIC_IS, BaseClass,,, __VA_ARGS__)\ + return false; \ + } \ + static std::unique_ptr as(const Json& ajson) { \ + if (!ajson.is_object()) return std::unique_ptr(); \ + JSONCONS_VARIADIC_REP_N(JSONCONS_POLYMORPHIC_AS_UNIQUE_PTR, BaseClass,,, __VA_ARGS__)\ + return std::unique_ptr(); \ + } \ + static Json to_json(const std::unique_ptr& ptr) { \ + if (ptr.get() == nullptr) {return Json::null();} \ + JSONCONS_VARIADIC_REP_N(JSONCONS_POLYMORPHIC_TO_JSON, BaseClass,,, __VA_ARGS__)\ + return Json::null(); \ + } \ + }; \ +} \ + /**/ + +#endif diff --git a/include/jsoncons/json_traits_macros_deprecated.hpp b/include/jsoncons/json_traits_macros_deprecated.hpp new file mode 100644 index 0000000..0d44e38 --- /dev/null +++ b/include/jsoncons/json_traits_macros_deprecated.hpp @@ -0,0 +1,144 @@ +// Copyright 2019 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_TRAITS_MACROS_DEPRECATED_HPP +#define JSONCONS_JSON_TRAITS_MACROS_DEPRECATED_HPP + +#include + +#if !defined(JSONCONS_NO_DEPRECATED) + +#define JSONCONS_MEMBER_TRAITS_DECL(ValueType, ...) \ + JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_AS,JSONCONS_TO_JSON,0, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_TPL_MEMBER_TRAITS_DECL(NumTemplateParams, ValueType, ...) \ + JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_AS,JSONCONS_TO_JSON,NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_MEMBER_NAMED_TRAITS_DECL(ValueType, ...) \ + JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_NAME_AS, JSONCONS_NAME_TO_JSON, 0, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_TPL_MEMBER_NAMED_TRAITS_DECL(NumTemplateParams, ValueType, ...) \ + JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_NAME_AS, JSONCONS_NAME_TO_JSON, NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_GETTER_SETTER_TRAITS_DECL(ValueType,GetPrefix,SetPrefix, ...) \ + JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_GETTER_SETTER_AS, JSONCONS_GETTER_SETTER_TO_JSON,0, ValueType,GetPrefix,SetPrefix, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_TPL_GETTER_SETTER_TRAITS_DECL(NumTemplateParams, ValueType,GetPrefix,SetPrefix, ...) \ + JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_GETTER_SETTER_AS, JSONCONS_GETTER_SETTER_TO_JSON,NumTemplateParams, ValueType,GetPrefix,SetPrefix, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_GETTER_SETTER_NAMED_TRAITS_DECL(ValueType, ...) \ +JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_GETTER_SETTER_NAME_AS,JSONCONS_GETTER_SETTER_NAME_TO_JSON, 0, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_TPL_GETTER_SETTER_NAMED_TRAITS_DECL(NumTemplateParams, ValueType, ...) \ +JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_GETTER_SETTER_NAME_AS,JSONCONS_GETTER_SETTER_NAME_TO_JSON, NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \ + /**/ + +#define JSONCONS_ALL_GETTER_CTOR_TRAITS JSONCONS_ALL_CTOR_GETTER_TRAITS +#define JSONCONS_N_GETTER_CTOR_TRAITS JSONCONS_N_CTOR_GETTER_TRAITS +#define JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS JSONCONS_TPL_ALL_CTOR_GETTER_TRAITS +#define JSONCONS_TPL_N_GETTER_CTOR_TRAITS JSONCONS_TPL_N_CTOR_GETTER_TRAITS + +#define JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS JSONCONS_ALL_CTOR_GETTER_NAME_TRAITS +#define JSONCONS_N_GETTER_CTOR_NAME_TRAITS JSONCONS_N_CTOR_GETTER_NAME_TRAITS +#define JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS JSONCONS_TPL_ALL_CTOR_GETTER_NAME_TRAITS +#define JSONCONS_TPL_N_GETTER_CTOR_NAME_TRAITS JSONCONS_TPL_N_CTOR_GETTER_NAME_TRAITS + +#define JSONCONS_PROPERTY_TRAITS_DECL JSONCONS_GETTER_SETTER_TRAITS_DECL +#define JSONCONS_TPL_PROPERTY_TRAITS_DECL JSONCONS_TPL_GETTER_SETTER_TRAITS_DECL +#define JSONCONS_TYPE_TRAITS_DECL JSONCONS_MEMBER_TRAITS_DECL +#define JSONCONS_MEMBER_TRAITS_NAMED_DECL JSONCONS_MEMBER_NAMED_TRAITS_DECL +#define JSONCONS_TEMPLATE_MEMBER_TRAITS_NAMED_DECL JSONCONS_TPL_MEMBER_NAMED_TRAITS_DECL +#define JSONCONS_TEMPLATE_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_TPL_GETTER_SETTER_NAMED_TRAITS_DECL +#define JSONCONS_TEMPLATE_MEMBER_TRAITS_DECL JSONCONS_TPL_MEMBER_TRAITS_DECL + +#define JSONCONS_N_MEMBER_NAMED_TRAITS JSONCONS_N_MEMBER_NAME_TRAITS +#define JSONCONS_TPL_N_MEMBER_NAMED_TRAITS JSONCONS_TPL_N_MEMBER_NAME_TRAITS +#define JSONCONS_ALL_MEMBER_NAMED_TRAITS JSONCONS_ALL_MEMBER_NAME_TRAITS +#define JSONCONS_TPL_ALL_MEMBER_NAMED_TRAITS JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS + +#define JSONCONS_ALL_GETTER_CTOR_NAMED_TRAITS JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_TPL_ALL_GETTER_CTOR_NAMED_TRAITS JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_N_GETTER_CTOR_NAMED_TRAITS JSONCONS_N_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_TPL_N_GETTER_CTOR_NAMED_TRAITS JSONCONS_TPL_N_GETTER_CTOR_NAME_TRAITS + +#define JSONCONS_ENUM_NAMED_TRAITS JSONCONS_ENUM_NAME_TRAITS + +#define JSONCONS_N_GETTER_SETTER_NAMED_TRAITS JSONCONS_N_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_TPL_N_GETTER_SETTER_NAMED_TRAITS JSONCONS_TPL_N_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_ALL_GETTER_SETTER_NAMED_TRAITS JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_TPL_ALL_GETTER_SETTER_NAMED_TRAITS JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS + +#define JSONCONS_N_MEMBER_TRAITS_DECL JSONCONS_N_MEMBER_TRAITS +#define JSONCONS_TPL_N_MEMBER_TRAITS_DECL JSONCONS_TPL_N_MEMBER_TRAITS +#define JSONCONS_ALL_MEMBER_TRAITS_DECL JSONCONS_ALL_MEMBER_TRAITS +#define JSONCONS_TPL_ALL_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS +#define JSONCONS_N_MEMBER_NAMED_TRAITS_DECL JSONCONS_N_MEMBER_NAMED_TRAITS +#define JSONCONS_TPL_N_MEMBER_NAMED_TRAITS_DECL JSONCONS_TPL_N_MEMBER_NAMED_TRAITS +#define JSONCONS_ALL_MEMBER_NAMED_TRAITS_DECL JSONCONS_ALL_MEMBER_NAMED_TRAITS +#define JSONCONS_TPL_ALL_MEMBER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_NAMED_TRAITS +#define JSONCONS_ALL_GETTER_CTOR_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_TRAITS +#define JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS +#define JSONCONS_N_GETTER_CTOR_TRAITS_DECL JSONCONS_N_GETTER_CTOR_TRAITS +#define JSONCONS_N_ALL_GETTER_CTOR_TRAITS_DECL JSONCONS_N_ALL_GETTER_CTOR_TRAITS +#define JSONCONS_ALL_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_NAMED_TRAITS +#define JSONCONS_TPL_ALL_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_NAMED_TRAITS +#define JSONCONS_N_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_N_GETTER_CTOR_NAMED_TRAITS +#define JSONCONS_TPL_N_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_TPL_N_GETTER_CTOR_NAMED_TRAITS +#define JSONCONS_ENUM_TRAITS_DECL JSONCONS_ENUM_TRAITS +#define JSONCONS_ENUM_NAMED_TRAITS_DECL JSONCONS_ENUM_NAMED_TRAITS +#define JSONCONS_N_GETTER_SETTER_TRAITS_DECL JSONCONS_N_GETTER_SETTER_TRAITS +#define JSONCONS_TPL_N_GETTER_SETTER_TRAITS_DECL JSONCONS_TPL_N_GETTER_SETTER_TRAITS +#define JSONCONS_ALL_GETTER_SETTER_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_TRAITS +#define JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS +#define JSONCONS_N_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_N_GETTER_SETTER_NAMED_TRAITS +#define JSONCONS_TPL_N_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_N_GETTER_SETTER_NAMED_TRAITS +#define JSONCONS_ALL_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_NAMED_TRAITS +#define JSONCONS_TPL_ALL_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAMED_TRAITS +#define JSONCONS_POLYMORPHIC_TRAITS_DECL JSONCONS_POLYMORPHIC_TRAITS +#define JSONCONS_NONDEFAULT_MEMBER_TRAITS_DECL JSONCONS_ALL_MEMBER_TRAITS +#define JSONCONS_TEMPLATE_STRICT_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS + +#define JSONCONS_STRICT_MEMBER_TRAITS_NAMED_DECL JSONCONS_ALL_MEMBER_NAME_TRAITS +#define JSONCONS_STRICT_TEMPLATE_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS +#define JSONCONS_STRICT_TEMPLATE_MEMBER_TRAITS_NAMED_DECL JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS +#define JSONCONS_ENUM_TRAITS_NAMED_DECL JSONCONS_ENUM_NAME_TRAITS +#define JSONCONS_GETTER_CTOR_TRAITS_NAMED_DECL JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_TEMPLATE_GETTER_CTOR_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS +#define JSONCONS_TEMPLATE_GETTER_CTOR_TRAITS_NAMED_DECL JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_STRICT_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_STRICT_TEMPLATE_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_STRICT_TPL_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS +#define JSONCONS_STRICT_TPL_MEMBER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS +#define JSONCONS_STRICT_TPL_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS + +#define JSONCONS_STRICT_MEMBER_TRAITS_DECL JSONCONS_ALL_MEMBER_TRAITS +#define JSONCONS_TPL_STRICT_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS +#define JSONCONS_STRICT_MEMBER_NAMED_TRAITS_DECL JSONCONS_ALL_MEMBER_NAME_TRAITS +#define JSONCONS_TPL_STRICT_MEMBER_NAMED_TRAITS_DECL JSONCONS_ALL_STRICT_MEMBER_NAME_TRAITS +#define JSONCONS_STRICT_PROPERTY_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_TRAITS +#define JSONCONS_TPL_STRICT_PROPERTY_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS +#define JSONCONS_STRICT_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_TPL_STRICT_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS +#define JSONCONS_GETTER_CTOR_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_TRAITS +#define JSONCONS_TPL_GETTER_CTOR_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS +#define JSONCONS_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_TPL_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS +#define JSONCONS_N_PROPERTY_TRAITS_DECL JSONCONS_N_GETTER_SETTER_TRAITS +#define JSONCONS_ALL_PROPERTY_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_TRAITS +#define JSONCONS_TPL_N_PROPERTY_TRAITS_DECL JSONCONS_TPL_N_GETTER_SETTER_TRAITS +#define JSONCONS_TPL_ALL_PROPERTY_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS + +#endif + +#endif diff --git a/include/jsoncons/json_type.hpp b/include/jsoncons/json_type.hpp new file mode 100644 index 0000000..f642d6b --- /dev/null +++ b/include/jsoncons/json_type.hpp @@ -0,0 +1,206 @@ +// 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_HPP +#define JSONCONS_JSON_TYPE_HPP + +#include +#include + +namespace jsoncons { + + enum class json_type : uint8_t + { + null_value, + bool_value, + int64_value, + uint64_value, + half_value, + double_value, + string_value, + byte_string_value, + array_value, + object_value + }; + + template + std::basic_ostream& operator<<(std::basic_ostream& os, json_type type) + { + static constexpr const CharT* null_value = JSONCONS_CSTRING_CONSTANT(CharT, "null"); + static constexpr const CharT* bool_value = JSONCONS_CSTRING_CONSTANT(CharT, "bool"); + static constexpr const CharT* int64_value = JSONCONS_CSTRING_CONSTANT(CharT, "int64"); + static constexpr const CharT* uint64_value = JSONCONS_CSTRING_CONSTANT(CharT, "uint64"); + static constexpr const CharT* half_value = JSONCONS_CSTRING_CONSTANT(CharT, "half"); + static constexpr const CharT* double_value = JSONCONS_CSTRING_CONSTANT(CharT, "double"); + static constexpr const CharT* string_value = JSONCONS_CSTRING_CONSTANT(CharT, "string"); + static constexpr const CharT* byte_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string"); + static constexpr const CharT* array_value = JSONCONS_CSTRING_CONSTANT(CharT, "array"); + static constexpr const CharT* object_value = JSONCONS_CSTRING_CONSTANT(CharT, "object"); + + switch (type) + { + case json_type::null_value: + { + os << null_value; + break; + } + case json_type::bool_value: + { + os << bool_value; + break; + } + case json_type::int64_value: + { + os << int64_value; + break; + } + case json_type::uint64_value: + { + os << uint64_value; + break; + } + case json_type::half_value: + { + os << half_value; + break; + } + case json_type::double_value: + { + os << double_value; + break; + } + case json_type::string_value: + { + os << string_value; + break; + } + case json_type::byte_string_value: + { + os << byte_string_value; + break; + } + case json_type::array_value: + { + os << array_value; + break; + } + case json_type::object_value: + { + os << object_value; + break; + } + } + return os; + } + + enum class json_storage_kind : uint8_t + { + null_value = 0x00, + bool_value = 0x01, + int64_value = 0x02, + uint64_value = 0x03, + half_value = 0x04, + double_value = 0x05, + short_string_value = 0x06, + long_string_value = 0x07, + byte_string_value = 0x08, + array_value = 0x09, + empty_object_value = 0x0a, + object_value = 0x0b, + json_const_pointer = 0x0c + }; + + template + std::basic_ostream& operator<<(std::basic_ostream& os, json_storage_kind storage) + { + static constexpr const CharT* null_value = JSONCONS_CSTRING_CONSTANT(CharT, "null"); + static constexpr const CharT* bool_value = JSONCONS_CSTRING_CONSTANT(CharT, "bool"); + static constexpr const CharT* int64_value = JSONCONS_CSTRING_CONSTANT(CharT, "int64"); + static constexpr const CharT* uint64_value = JSONCONS_CSTRING_CONSTANT(CharT, "uint64"); + static constexpr const CharT* half_value = JSONCONS_CSTRING_CONSTANT(CharT, "half"); + static constexpr const CharT* double_value = JSONCONS_CSTRING_CONSTANT(CharT, "double"); + static constexpr const CharT* short_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "short_string"); + static constexpr const CharT* long_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "string"); + static constexpr const CharT* byte_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string"); + static constexpr const CharT* array_value = JSONCONS_CSTRING_CONSTANT(CharT, "array"); + static constexpr const CharT* empty_object_value = JSONCONS_CSTRING_CONSTANT(CharT, "empty_object"); + static constexpr const CharT* object_value = JSONCONS_CSTRING_CONSTANT(CharT, "object"); + static constexpr const CharT* json_const_pointer = JSONCONS_CSTRING_CONSTANT(CharT, "json_const_pointer"); + + switch (storage) + { + case json_storage_kind::null_value: + { + os << null_value; + break; + } + case json_storage_kind::bool_value: + { + os << bool_value; + break; + } + case json_storage_kind::int64_value: + { + os << int64_value; + break; + } + case json_storage_kind::uint64_value: + { + os << uint64_value; + break; + } + case json_storage_kind::half_value: + { + os << half_value; + break; + } + case json_storage_kind::double_value: + { + os << double_value; + break; + } + case json_storage_kind::short_string_value: + { + os << short_string_value; + break; + } + case json_storage_kind::long_string_value: + { + os << long_string_value; + break; + } + case json_storage_kind::byte_string_value: + { + os << byte_string_value; + break; + } + case json_storage_kind::array_value: + { + os << array_value; + break; + } + case json_storage_kind::empty_object_value: + { + os << empty_object_value; + break; + } + case json_storage_kind::object_value: + { + os << object_value; + break; + } + case json_storage_kind::json_const_pointer: + { + os << json_const_pointer; + break; + } + } + return os; + } + +} // jsoncons + +#endif diff --git a/include/jsoncons/json_type_traits.hpp b/include/jsoncons/json_type_traits.hpp new file mode 100644 index 0000000..7ee26b2 --- /dev/null +++ b/include/jsoncons/json_type_traits.hpp @@ -0,0 +1,1829 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include // std::swap +#include // std::numeric_limits +#include // std::enable_if +#include // std::iterator_traits, std::input_iterator_tag +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::bitset +#include +#include + +#if defined(JSONCONS_HAS_STD_VARIANT) + #include +#endif + +namespace jsoncons { + + template + struct is_json_type_traits_declared : public std::false_type + {}; + + #if !defined(JSONCONS_NO_DEPRECATED) + template + using is_json_type_traits_impl = is_json_type_traits_declared; + #endif + + // json_type_traits + + template + struct unimplemented : std::false_type + {}; + + template + struct json_type_traits + { + using allocator_type = typename Json::allocator_type; + + static constexpr bool is_compatible = false; + + static constexpr bool is(const Json&) noexcept + { + return false; + } + + static T as(const Json&) + { + static_assert(unimplemented::value, "as not implemented"); + } + + static Json to_json(const T&, const allocator_type& = allocator_type()) + { + static_assert(unimplemented::value, "to_json not implemented"); + } + }; + +namespace detail { + +template +using +traits_can_convert_t = decltype(json_type_traits::can_convert(Json())); + +template +using +has_can_convert = type_traits::is_detected; + + template + struct invoke_can_convert + { + template + static + typename std::enable_if::value,bool>::type + can_convert(const Json& j) noexcept + { + return json_type_traits::can_convert(j); + } + template + static + typename std::enable_if::value,bool>::type + can_convert(const Json& j) noexcept + { + return json_type_traits::is(j); + } + }; + + // is_json_type_traits_unspecialized + template + struct is_json_type_traits_unspecialized : std::false_type {}; + + // is_json_type_traits_unspecialized + template + struct is_json_type_traits_unspecialized::is_compatible>::value>::type + > : std::true_type {}; + + // is_compatible_array_type + template + struct is_compatible_array_type : std::false_type {}; + + template + struct is_compatible_array_type::value && + type_traits::is_list_like::value && + !is_json_type_traits_unspecialized::value_type>::value + >::type> : std::true_type {}; + +} // namespace detail + + // is_json_type_traits_specialized + template + struct is_json_type_traits_specialized : std::false_type {}; + + template + struct is_json_type_traits_specialized::value + >::type> : std::true_type {}; + + template + struct json_type_traits::type*> + { + using char_type = typename Json::char_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + static const char_type* as(const Json& j) + { + return j.as_cstring(); + } + template + static Json to_json(const char_type* s, Args&&... args) + { + return Json(s, semantic_tag::none, std::forward(args)...); + } + }; + + template + struct json_type_traits::type*> + { + using char_type = typename Json::char_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + template + static Json to_json(const char_type* s, Args&&... args) + { + return Json(s, semantic_tag::none, std::forward(args)...); + } + }; + + // integer + + template + struct json_type_traits::value + >::type> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.template is_integer(); + } + static T as(const Json& j) + { + return j.template as_integer(); + } + + static Json to_json(T val, allocator_type alloc = allocator_type()) + { + return Json(val, semantic_tag::none, alloc); + } + }; + + template + struct json_type_traits::value + >::type> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_double(); + } + static T as(const Json& j) + { + return static_cast(j.as_double()); + } + static Json to_json(T val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } + }; + + template + struct json_type_traits + { + using json_object = typename Json::object; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_object(); + } + static Json to_json(const json_object& o, const allocator_type& = allocator_type()) + { + return Json(o,semantic_tag::none); + } + }; + + template + struct json_type_traits + { + using json_array = typename Json::array; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_array(); + } + static Json to_json(const json_array& a, const allocator_type& = allocator_type()) + { + return Json(a, semantic_tag::none); + } + }; + + template + struct json_type_traits + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json&) noexcept + { + return true; + } + static Json as(Json j) + { + return j; + } + static Json to_json(const Json& val, allocator_type = allocator_type()) + { + return val; + } + }; + + template + struct json_type_traits + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_null(); + } + static typename jsoncons::null_type as(const Json& j) + { + if (!j.is_null()) + { + JSONCONS_THROW(conv_error(conv_errc::not_jsoncons_null_type)); + } + return jsoncons::null_type(); + } + static Json to_json(jsoncons::null_type, allocator_type = allocator_type()) + { + return Json::null(); + } + }; + + template + struct json_type_traits + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + static Json to_json(bool val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } + }; + + template + struct json_type_traits::const_reference>::value, + std::vector::const_reference, + void>::type>::value>::type> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + static Json to_json(bool val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } + }; + + template + struct json_type_traits::reference> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + static Json to_json(bool val, allocator_type = allocator_type()) + { + return Json(val, semantic_tag::none); + } + }; + + template + struct json_type_traits::value && + type_traits::is_basic_string::value && + std::is_same::value>::type> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + + static T as(const Json& j) + { + return T(j.as_string()); + } + + static Json to_json(const T& val) + { + return Json(val, semantic_tag::none); + } + + static Json to_json(const T& val, const allocator_type& alloc) + { + return Json(val, semantic_tag::none, alloc); + } + }; + + template + struct json_type_traits::value && + type_traits::is_basic_string::value && + !std::is_same::value>::type> + { + using char_type = typename Json::char_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string(); + } + + static T as(const Json& j) + { + auto s = j.as_string(); + T val; + unicode_traits::convert(s.data(), s.size(), val); + return val; + } + + static Json to_json(const T& val) + { + std::basic_string s; + unicode_traits::convert(val.data(), val.size(), s); + + return Json(s, semantic_tag::none); + } + + static Json to_json(const T& val, const allocator_type& alloc) + { + std::basic_string s; + unicode_traits::convert(val.data(), val.size(), s); + return Json(s, semantic_tag::none, alloc); + } + }; + + template + struct json_type_traits::value && + type_traits::is_basic_string_view::value && + std::is_same::value>::type> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_string_view(); + } + + static T as(const Json& j) + { + return T(j.as_string_view().data(),j.as_string_view().size()); + } + + static Json to_json(const T& val) + { + return Json(val, semantic_tag::none); + } + + static Json to_json(const T& val, const allocator_type& alloc) + { + return Json(val, semantic_tag::none, alloc); + } + }; + + // array back insertable + + template + struct json_type_traits::value && + jsoncons::detail::is_compatible_array_type::value && + type_traits::is_back_insertable::value + >::type> + { + typedef typename std::iterator_traits::value_type value_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + // array back insertable non-byte container + + template + static typename std::enable_if::value,Container>::type + as(const Json& j) + { + if (j.is_array()) + { + T result; + visit_reserve_(typename std::integral_constant::value>::type(),result,j.size()); + for (const auto& item : j.array_range()) + { + result.push_back(item.template as()); + } + + return result; + } + else + { + JSONCONS_THROW(conv_error(conv_errc::not_vector)); + } + } + + // array back insertable byte container + + template + static typename std::enable_if::value,Container>::type + as(const Json& j) + { + converter convert; + std::error_code ec; + if (j.is_array()) + { + T result; + visit_reserve_(typename std::integral_constant::value>::type(),result,j.size()); + for (const auto& item : j.array_range()) + { + result.push_back(item.template as()); + } + + return result; + } + else if (j.is_byte_string_view()) + { + auto v = convert.from(j.as_byte_string_view(),j.tag(), ec); + if (ec) + { + JSONCONS_THROW(conv_error(ec)); + } + return v; + } + else if (j.is_string()) + { + auto v = convert.from(j.as_string_view(),j.tag(), ec); + if (ec) + { + JSONCONS_THROW(conv_error(ec)); + } + return v; + } + else + { + JSONCONS_THROW(conv_error(conv_errc::not_vector)); + } + } + + template + static typename std::enable_if::value,Json>::type + to_json(const T& val) + { + Json j(json_array_arg); + auto first = std::begin(val); + auto last = std::end(val); + std::size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + template + static typename std::enable_if::value,Json>::type + to_json(const T& val, const allocator_type& alloc) + { + Json j(json_array_arg, alloc); + auto first = std::begin(val); + auto last = std::end(val); + std::size_t size = std::distance(first, last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + template + static typename std::enable_if::value,Json>::type + to_json(const T& val) + { + Json j(byte_string_arg, val); + return j; + } + + template + static typename std::enable_if::value,Json>::type + to_json(const T& val, const allocator_type& alloc) + { + Json j(byte_string_arg, val, semantic_tag::none, alloc); + return j; + } + + static void visit_reserve_(std::true_type, T& v, std::size_t size) + { + v.reserve(size); + } + + static void visit_reserve_(std::false_type, T&, std::size_t) + { + } + }; + + // array, not back insertable but insertable + + template + struct json_type_traits::value && + jsoncons::detail::is_compatible_array_type::value && + !type_traits::is_back_insertable::value && + type_traits::is_insertable::value>::type> + { + typedef typename std::iterator_traits::value_type value_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + static T as(const Json& j) + { + if (j.is_array()) + { + T result; + for (const auto& item : j.array_range()) + { + result.insert(item.template as()); + } + + return result; + } + else + { + JSONCONS_THROW(conv_error(conv_errc::not_vector)); + } + } + + static Json to_json(const T& val) + { + Json j(json_array_arg); + auto first = std::begin(val); + auto last = std::end(val); + std::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& alloc) + { + Json j(json_array_arg, alloc); + auto first = std::begin(val); + auto last = std::end(val); + std::size_t size = std::distance(first, last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + }; + + // array not back insertable or insertable, but front insertable + + template + struct json_type_traits::value && + jsoncons::detail::is_compatible_array_type::value && + !type_traits::is_back_insertable::value && + !type_traits::is_insertable::value && + type_traits::is_front_insertable::value>::type> + { + typedef typename std::iterator_traits::value_type value_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + static T as(const Json& j) + { + if (j.is_array()) + { + T result; + + auto it = j.array_range().rbegin(); + auto end = j.array_range().rend(); + for (; it != end; ++it) + { + result.push_front((*it).template as()); + } + + return result; + } + else + { + JSONCONS_THROW(conv_error(conv_errc::not_vector)); + } + } + + static Json to_json(const T& val) + { + Json j(json_array_arg); + auto first = std::begin(val); + auto last = std::end(val); + std::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& alloc) + { + Json j(json_array_arg, alloc); + auto first = std::begin(val); + auto last = std::end(val); + std::size_t size = std::distance(first, last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + }; + + // std::array + + template + struct json_type_traits> + { + using allocator_type = typename Json::allocator_type; + + using value_type = E; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array() && j.size() == N; + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + static std::array as(const Json& j) + { + std::array buff; + if (j.size() != N) + { + JSONCONS_THROW(conv_error(conv_errc::not_array)); + } + for (std::size_t i = 0; i < N; i++) + { + buff[i] = j[i].template as(); + } + return buff; + } + + static Json to_json(const std::array& val) + { + Json j(json_array_arg); + 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& val, + const allocator_type& alloc) + { + Json j(json_array_arg, alloc); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } + }; + + // map like + template + struct json_type_traits::value && + type_traits::is_map_like::value && + type_traits::is_constructible_from_const_pointer_and_size::value && + is_json_type_traits_specialized::value>::type + > + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_object(); + for (auto member : j.object_range()) + { + if (!member.value().template is()) + { + result = false; + } + } + return result; + } + + static T as(const Json& j) + { + if (!j.is_object()) + { + JSONCONS_THROW(conv_error(conv_errc::not_map)); + } + T result; + for (const auto& item : j.object_range()) + { + result.emplace(key_type(item.key().data(),item.key().size()), item.value().template as()); + } + + return result; + } + + static Json to_json(const T& val) + { + Json j(json_object_arg, val.begin(), val.end()); + return j; + } + + static Json to_json(const T& val, const allocator_type& alloc) + { + Json j(json_object_arg, val.begin(), val.end(), alloc); + return j; + } + }; + + template + struct json_type_traits::value && + type_traits::is_map_like::value && + !type_traits::is_constructible_from_const_pointer_and_size::value && + is_json_type_traits_specialized::value && + is_json_type_traits_specialized::value>::type + > + { + using mapped_type = typename T::mapped_type; + using value_type = typename T::value_type; + using key_type = typename T::key_type; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& val) noexcept + { + if (!val.is_object()) + return false; + for (const auto& item : val.object_range()) + { + Json j(item.key()); + if (!j.template is()) + { + return false; + } + if (!item.value().template is()) + { + return false; + } + } + return true; + } + + static T as(const Json& val) + { + T result; + for (const auto& item : val.object_range()) + { + Json j(item.key()); + auto key = json_type_traits::as(j); + result.emplace(std::move(key), item.value().template as()); + } + + return result; + } + + static Json to_json(const T& val) + { + Json j(json_object_arg); + j.reserve(val.size()); + for (const auto& item : val) + { + auto temp = json_type_traits::to_json(item.first); + typename Json::key_type key; + temp.dump(key); + j.try_emplace(std::move(key), item.second); + } + return j; + } + + static Json to_json(const T& val, const allocator_type& alloc) + { + Json j(json_object_arg, semantic_tag::none, alloc); + j.reserve(val.size()); + for (const auto& item : val) + { + auto temp = json_type_traits::to_json(item.first, alloc); + typename Json::key_type key(alloc); + temp.dump(key); + j.try_emplace(std::move(key), item.second, alloc); + } + return j; + } + }; + + namespace tuple_detail + { + template + struct json_tuple_helper + { + using element_type = typename std::tuple_element::type; + using next = json_tuple_helper; + + static bool is(const Json& j) noexcept + { + if (j[Size-Pos].template is()) + { + return next::is(j); + } + else + { + return false; + } + } + + static void as(Tuple& tuple, const Json& j) + { + std::get(tuple) = j[Size-Pos].template as(); + next::as(tuple, j); + } + + static void to_json(const Tuple& tuple, Json& j) + { + j.push_back(json_type_traits::to_json(std::get(tuple))); + next::to_json(tuple, j); + } + }; + + template + struct json_tuple_helper<0, Size, Json, Tuple> + { + static bool is(const Json&) noexcept + { + return true; + } + + static void as(Tuple&, const Json&) + { + } + + static void to_json(const Tuple&, Json&) + { + } + }; + } // namespace detail + + template + struct json_type_traits> + { + private: + using helper = tuple_detail::json_tuple_helper>; + + public: + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return helper::is(j); + } + + static std::tuple as(const Json& j) + { + std::tuple buff; + helper::as(buff, j); + return buff; + } + + static Json to_json(const std::tuple& val) + { + Json j(json_array_arg); + j.reserve(sizeof...(E)); + helper::to_json(val, j); + return j; + } + + static Json to_json(const std::tuple& val, + const allocator_type& alloc) + { + Json j(json_array_arg, alloc); + j.reserve(sizeof...(E)); + helper::to_json(val, j); + return j; + } + }; + + template + struct json_type_traits> + { + public: + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_array() && j.size() == 2; + } + + static std::pair as(const Json& j) + { + return std::make_pair(j[0].template as(),j[1].template as()); + } + + static Json to_json(const std::pair& val) + { + Json j(json_array_arg); + j.reserve(2); + j.push_back(val.first); + j.push_back(val.second); + return j; + } + + static Json to_json(const std::pair& val, const allocator_type& alloc) + { + Json j(json_array_arg, alloc); + j.reserve(2); + j.push_back(val.first); + j.push_back(val.second); + return j; + } + }; + + template + struct json_type_traits::value>::type> + { + public: + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_byte_string(); + } + + static T as(const Json& j) + { + return j.template as_byte_string(); + } + + static Json to_json(const T& val, + const allocator_type& alloc = allocator_type()) + { + return Json(byte_string_arg, val, semantic_tag::none, alloc); + } + }; + + template + struct json_type_traits, + typename std::enable_if>::value && + !std::is_polymorphic::value + >::type> + { + static bool is(const Json& j) noexcept + { + return j.is_null() || j.template is(); + } + + static std::shared_ptr as(const Json& j) + { + return j.is_null() ? std::shared_ptr(nullptr) : std::make_shared(j.template as()); + } + + static Json to_json(const std::shared_ptr& ptr) + { + if (ptr.get() != nullptr) + { + Json j(*ptr); + return j; + } + else + { + return Json::null(); + } + } + }; + + template + struct json_type_traits, + typename std::enable_if>::value && + !std::is_polymorphic::value + >::type> + { + static bool is(const Json& j) noexcept + { + return j.is_null() || j.template is(); + } + + static std::unique_ptr as(const Json& j) + { + return j.is_null() ? std::unique_ptr(nullptr) : jsoncons::make_unique(j.template as()); + } + + static Json to_json(const std::unique_ptr& ptr) + { + if (ptr.get() != nullptr) + { + Json j(*ptr); + return j; + } + else + { + return Json::null(); + } + } + }; + + template + struct json_type_traits, + typename std::enable_if>::value>::type> + { + public: + static bool is(const Json& j) noexcept + { + return j.is_null() || j.template is(); + } + + static jsoncons::optional as(const Json& j) + { + return j.is_null() ? jsoncons::optional() : jsoncons::optional(j.template as()); + } + + static Json to_json(const jsoncons::optional& val) + { + return val.has_value() ? Json(*val) : Json::null(); + } + }; + + template + struct json_type_traits + { + using allocator_type = typename Json::allocator_type; + + public: + static bool is(const Json& j) noexcept + { + return j.is_byte_string_view(); + } + + static byte_string_view as(const Json& j) + { + return j.as_byte_string_view(); + } + + static Json to_json(const byte_string_view& val, const allocator_type& alloc = allocator_type()) + { + return Json(byte_string_arg, val, semantic_tag::none, alloc); + } + }; + + // basic_bigint + + template + struct json_type_traits> + { + public: + using char_type = typename Json::char_type; + + static bool is(const Json& j) noexcept + { + switch (j.type()) + { + case json_type::string_value: + return jsoncons::detail::is_base10(j.as_string_view().data(), j.as_string_view().length()); + case json_type::int64_value: + case json_type::uint64_value: + return true; + default: + return false; + } + } + + static basic_bigint as(const Json& j) + { + switch (j.type()) + { + case json_type::string_value: + if (!jsoncons::detail::is_base10(j.as_string_view().data(), j.as_string_view().length())) + { + JSONCONS_THROW(conv_error(conv_errc::not_bigint)); + } + return basic_bigint::from_string(j.as_string_view().data(), j.as_string_view().length()); + case json_type::half_value: + case json_type::double_value: + return basic_bigint(j.template as()); + case json_type::int64_value: + return basic_bigint(j.template as()); + case json_type::uint64_value: + return basic_bigint(j.template as()); + default: + JSONCONS_THROW(conv_error(conv_errc::not_bigint)); + } + } + + static Json to_json(const basic_bigint& val) + { + std::basic_string s; + val.write_string(s); + return Json(s,semantic_tag::bigint); + } + }; + + // std::valarray + + template + struct json_type_traits> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is()) + { + result = false; + break; + } + } + } + return result; + } + + static std::valarray as(const Json& j) + { + if (j.is_array()) + { + std::valarray v(j.size()); + for (std::size_t i = 0; i < j.size(); ++i) + { + v[i] = j[i].template as(); + } + return v; + } + else + { + JSONCONS_THROW(conv_error(conv_errc::not_array)); + } + } + + static Json to_json(const std::valarray& val) + { + Json j(json_array_arg); + auto first = std::begin(val); + auto last = std::end(val); + std::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& val, const allocator_type& alloc) + { + Json j(json_array_arg, alloc); + auto first = std::begin(val); + auto last = std::end(val); + std::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(JSONCONS_HAS_STD_VARIANT) + +namespace variant_detail +{ + template + typename std::enable_if, bool>::type + is_variant(const Json& /*j*/) + { + return false; + } + + template + typename std::enable_if, bool>::type + is_variant(const Json& j) + { + if (j.template is()) + { + return true; + } + else + { + return is_variant(j); + } + } + + template + typename std::enable_if, Variant>::type + as_variant(const Json& /*j*/) + { + JSONCONS_THROW(conv_error(conv_errc::not_variant)); + } + + template + typename std::enable_if, Variant>::type + as_variant(const Json& j) + { + if (j.template is()) + { + Variant var(j.template as()); + return var; + } + else + { + return as_variant(j); + } + } + + template + struct variant_to_json_visitor + { + Json& j_; + + variant_to_json_visitor(Json& j) : j_(j) {} + + template + void operator()(const T& value) const + { + j_ = value; + } + }; + +} // namespace variant_detail + + template + struct json_type_traits> + { + public: + using variant_type = typename std::variant; + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return variant_detail::is_variant<0,Json,variant_type, VariantTypes...>(j); + } + + static std::variant as(const Json& j) + { + return variant_detail::as_variant<0,Json,variant_type, VariantTypes...>(j); + } + + static Json to_json(const std::variant& var) + { + Json j(json_array_arg); + variant_detail::variant_to_json_visitor visitor(j); + std::visit(visitor, var); + return j; + } + + static Json to_json(const std::variant& var, + const allocator_type& alloc) + { + Json j(json_array_arg, alloc); + variant_detail::variant_to_json_visitor visitor(j); + std::visit(visitor, var); + return j; + } + }; +#endif + + // std::chrono::duration + template + struct json_type_traits> + { + using duration_type = std::chrono::duration; + + using allocator_type = typename Json::allocator_type; + + static constexpr int64_t nanos_in_milli = 1000000; + static constexpr int64_t nanos_in_second = 1000000000; + static constexpr int64_t millis_in_second = 1000; + + static bool is(const Json& j) noexcept + { + return (j.tag() == semantic_tag::epoch_second || j.tag() == semantic_tag::epoch_milli || j.tag() == semantic_tag::epoch_nano); + } + + static duration_type as(const Json& j) + { + return from_json_(j); + } + + static Json to_json(const duration_type& val, allocator_type = allocator_type()) + { + return to_json_(val); + } + + template + static + typename std::enable_if>::value, duration_type>::type + from_json_(const Json& j) + { + if (j.is_int64() || j.is_uint64() || j.is_double()) + { + auto count = j.template as(); + switch (j.tag()) + { + case semantic_tag::epoch_second: + return duration_type(count); + case semantic_tag::epoch_milli: + return duration_type(count == 0 ? 0 : count/millis_in_second); + case semantic_tag::epoch_nano: + return duration_type(count == 0 ? 0 : count/nanos_in_second); + default: + return duration_type(count); + } + } + else if (j.is_string()) + { + switch (j.tag()) + { + case semantic_tag::epoch_second: + { + auto count = j.template as(); + return duration_type(count); + } + case semantic_tag::epoch_milli: + { + auto sv = j.as_string_view(); + bigint n = bigint::from_string(sv.data(), sv.length()); + if (n != 0) + { + n = n / millis_in_second; + } + return duration_type(static_cast(n)); + } + case semantic_tag::epoch_nano: + { + auto sv = j.as_string_view(); + bigint n = bigint::from_string(sv.data(), sv.length()); + if (n != 0) + { + n = n / nanos_in_second; + } + return duration_type(static_cast(n)); + } + default: + { + auto count = j.template as(); + return duration_type(count); + } + } + } + else + { + return duration_type(); + } + } + + template + static + typename std::enable_if::value, duration_type>::type + from_json_(const Json& j) + { + if (j.is_int64() || j.is_uint64()) + { + auto count = j.template as(); + switch (j.tag()) + { + case semantic_tag::epoch_second: + return duration_type(count*millis_in_second); + case semantic_tag::epoch_milli: + return duration_type(count); + case semantic_tag::epoch_nano: + return duration_type(count == 0 ? 0 : count/nanos_in_milli); + default: + return duration_type(count); + } + } + else if (j.is_double()) + { + auto count = j.template as(); + switch (j.tag()) + { + case semantic_tag::epoch_second: + return duration_type(static_cast(count * millis_in_second)); + case semantic_tag::epoch_milli: + return duration_type(static_cast(count)); + case semantic_tag::epoch_nano: + return duration_type(count == 0 ? 0 : static_cast(count / nanos_in_milli)); + default: + return duration_type(static_cast(count)); + } + } + else if (j.is_string()) + { + switch (j.tag()) + { + case semantic_tag::epoch_second: + { + auto count = j.template as(); + return duration_type(count*millis_in_second); + } + case semantic_tag::epoch_milli: + { + auto sv = j.as_string_view(); + Rep n{0}; + auto result = jsoncons::detail::to_integer_decimal(sv.data(), sv.size(), n); + if (!result) + { + return duration_type(); + } + return duration_type(n); + } + case semantic_tag::epoch_nano: + { + auto sv = j.as_string_view(); + bigint n = bigint::from_string(sv.data(), sv.length()); + if (n != 0) + { + n = n / nanos_in_milli; + } + return duration_type(static_cast(n)); + } + default: + { + auto count = j.template as(); + return duration_type(count); + } + } + } + else + { + return duration_type(); + } + } + + template + static + typename std::enable_if::value, duration_type>::type + from_json_(const Json& j) + { + if (j.is_int64() || j.is_uint64() || j.is_double()) + { + auto count = j.template as(); + switch (j.tag()) + { + case semantic_tag::epoch_second: + return duration_type(count*nanos_in_second); + case semantic_tag::epoch_milli: + return duration_type(count*nanos_in_milli); + case semantic_tag::epoch_nano: + return duration_type(count); + default: + return duration_type(count); + } + } + else if (j.is_double()) + { + auto count = j.template as(); + switch (j.tag()) + { + case semantic_tag::epoch_second: + return duration_type(static_cast(count * nanos_in_second)); + case semantic_tag::epoch_milli: + return duration_type(static_cast(count * nanos_in_milli)); + case semantic_tag::epoch_nano: + return duration_type(static_cast(count)); + default: + return duration_type(static_cast(count)); + } + } + else if (j.is_string()) + { + auto count = j.template as(); + switch (j.tag()) + { + case semantic_tag::epoch_second: + return duration_type(count*nanos_in_second); + case semantic_tag::epoch_milli: + return duration_type(count*nanos_in_milli); + case semantic_tag::epoch_nano: + return duration_type(count); + default: + return duration_type(count); + } + } + else + { + return duration_type(); + } + } + + template + static + typename std::enable_if>::value,Json>::type + to_json_(const duration_type& val) + { + return Json(val.count(), semantic_tag::epoch_second); + } + + template + static + typename std::enable_if::value,Json>::type + to_json_(const duration_type& val) + { + return Json(val.count(), semantic_tag::epoch_milli); + } + + template + static + typename std::enable_if::value,Json>::type + to_json_(const duration_type& val) + { + return Json(val.count(), semantic_tag::epoch_nano); + } + }; + + // std::nullptr_t + template + struct json_type_traits + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + return j.is_null(); + } + + static std::nullptr_t as(const Json& j) + { + if (!j.is_null()) + { + JSONCONS_THROW(conv_error(conv_errc::not_nullptr)); + } + return nullptr; + } + + static Json to_json(const std::nullptr_t&, allocator_type = allocator_type()) + { + return Json::null(); + } + }; + + // std::bitset + + struct null_back_insertable_byte_container + { + using value_type = uint8_t; + + void push_back(value_type) + { + } + }; + + template + struct json_type_traits> + { + using allocator_type = typename Json::allocator_type; + + static bool is(const Json& j) noexcept + { + if (j.is_byte_string()) + { + return true; + } + else if (j.is_string()) + { + jsoncons::string_view sv = j.as_string_view(); + null_back_insertable_byte_container cont; + auto result = decode_base16(sv.begin(), sv.end(), cont); + return result.ec == conv_errc::success ? true : false; + } + return false; + } + + static std::bitset as(const Json& j) + { + if (j.template is()) + { + auto bits = j.template as(); + std::bitset bs = static_cast(bits); + return bs; + } + else if (j.is_byte_string() || j.is_string()) + { + std::bitset bs; + std::vector bits; + if (j.is_byte_string()) + { + bits = j.template as>(); + } + else + { + jsoncons::string_view sv = j.as_string_view(); + auto result = decode_base16(sv.begin(), sv.end(), bits); + if (result.ec != conv_errc::success) + { + JSONCONS_THROW(conv_error(conv_errc::not_bitset)); + } + } + std::uint8_t byte = 0; + std::uint8_t mask = 0; + + std::size_t pos = 0; + for (std::size_t i = 0; i < N; ++i) + { + if (mask == 0) + { + if (pos >= bits.size()) + { + JSONCONS_THROW(conv_error(conv_errc::not_bitset)); + } + byte = bits.at(pos++); + mask = 0x80; + } + + if (byte & mask) + { + bs[i] = 1; + } + + mask = static_cast(mask >> 1); + } + return bs; + } + else + { + JSONCONS_THROW(conv_error(conv_errc::not_bitset)); + } + } + + static Json to_json(const std::bitset& val, + const allocator_type& alloc = allocator_type()) + { + std::vector bits; + + uint8_t byte = 0; + uint8_t mask = 0x80; + + for (std::size_t i = 0; i < N; ++i) + { + if (val[i]) + { + byte |= mask; + } + + mask = static_cast(mask >> 1); + + if (mask == 0) + { + bits.push_back(byte); + byte = 0; + mask = 0x80; + } + } + + // Encode remainder + if (mask != 0x80) + { + bits.push_back(byte); + } + + Json j(byte_string_arg, bits, semantic_tag::base16, alloc); + return j; + } + }; + +} // jsoncons + +#endif diff --git a/include/jsoncons/json_visitor.hpp b/include/jsoncons/json_visitor.hpp new file mode 100644 index 0000000..8be5900 --- /dev/null +++ b/include/jsoncons/json_visitor.hpp @@ -0,0 +1,1560 @@ +// Copyright 2018 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_VISITOR_HPP +#define JSONCONS_JSON_VISITOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + template + class basic_json_visitor + { + public: + using char_type = CharT; + using char_traits_type = std::char_traits; + + using string_view_type = jsoncons::basic_string_view; + + basic_json_visitor(basic_json_visitor&&) = default; + + basic_json_visitor& operator=(basic_json_visitor&&) = default; + + basic_json_visitor() = default; + + virtual ~basic_json_visitor() noexcept = default; + + void flush() + { + visit_flush(); + } + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_object(tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_object(std::size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context = ser_context()) + { + std::error_code ec; + bool more = visit_begin_object(length, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool end_object(const ser_context& context = ser_context()) + { + std::error_code ec; + bool more = visit_end_object(context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_array(tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_array(std::size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_array(length, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool end_array(const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_end_array(context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool key(const string_view_type& name, const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_key(name, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_null(tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_bool(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_string(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + template + bool byte_string_value(const Source& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context(), + typename std::enable_if::value,int>::type = 0) + { + std::error_code ec; + bool more = visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + template + bool byte_string_value(const Source& b, + uint64_t ext_tag, + const ser_context& context=ser_context(), + typename std::enable_if::value,int>::type = 0) + { + std::error_code ec; + bool more = visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), ext_tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_uint64(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_int64(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool half_value(uint16_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_half(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_double(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_object(semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_object(tag, context, ec); + } + + bool begin_object(std::size_t length, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_object(length, tag, context, ec); + } + + bool end_object(const ser_context& context, std::error_code& ec) + { + return visit_end_object(context, ec); + } + + bool begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) + { + return visit_begin_array(tag, context, ec); + } + + bool begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) + { + return visit_begin_array(length, tag, context, ec); + } + + bool end_array(const ser_context& context, std::error_code& ec) + { + return visit_end_array(context, ec); + } + + bool key(const string_view_type& name, const ser_context& context, std::error_code& ec) + { + return visit_key(name, context, ec); + } + + bool null_value(semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_null(tag, context, ec); + } + + bool bool_value(bool value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_bool(value, tag, context, ec); + } + + bool string_value(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_string(value, tag, context, ec); + } + + template + bool byte_string_value(const Source& b, + semantic_tag tag, + const ser_context& context, + std::error_code& ec, + typename std::enable_if::value,int>::type = 0) + { + return visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), tag, context, ec); + } + + template + bool byte_string_value(const Source& b, + uint64_t ext_tag, + const ser_context& context, + std::error_code& ec, + typename std::enable_if::value,int>::type = 0) + { + return visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), ext_tag, context, ec); + } + + bool uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_uint64(value, tag, context, ec); + } + + bool int64_value(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_int64(value, tag, context, ec); + } + + bool half_value(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_half(value, tag, context, ec); + } + + bool double_value(double value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_double(value, tag, context, ec); + } + + template + bool typed_array(const jsoncons::span& data, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_typed_array(data, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + template + bool typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_typed_array(data, tag, context, ec); + } + + bool typed_array(half_arg_t, const jsoncons::span& s, + semantic_tag tag = semantic_tag::none, + const ser_context& context = ser_context()) + { + std::error_code ec; + bool more = visit_typed_array(half_arg, s, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool typed_array(half_arg_t, const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_typed_array(half_arg, s, tag, context, ec); + } + + bool begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag = semantic_tag::multi_dim_row_major, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_multi_dim(shape, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_multi_dim(shape, tag, context, ec); + } + + bool end_multi_dim(const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_end_multi_dim(context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool end_multi_dim(const ser_context& context, + std::error_code& ec) + { + return visit_end_multi_dim(context, ec); + } + + #if !defined(JSONCONS_NO_DEPRECATED) + + JSONCONS_DEPRECATED_MSG("Instead, use byte_string_value(const Source&,semantic_tag=semantic_tag::none, const ser_context&=ser_context()") + bool byte_string_value(const uint8_t* p, std::size_t size, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + return byte_string_value(byte_string(p, size), tag, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use byte_string_value(const Source&, semantic_tag, const ser_context&, std::error_code&") + bool byte_string_value(const uint8_t* p, std::size_t size, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return byte_string_value(byte_string(p, size), tag, context, ec); + } + + JSONCONS_DEPRECATED_MSG("Instead, use key(const string_view_type&, const ser_context&=ser_context())") + bool name(const string_view_type& name, const ser_context& context=ser_context()) + { + return key(name, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use key(const string_view_type&, const ser_context&, std::error_code&)") + bool name(const string_view_type& name, const ser_context& context, std::error_code& ec) + { + return key(name, context, ec); + } + + JSONCONS_DEPRECATED_MSG("Instead, use byte_string_value(const byte_string_view&, semantic_tag=semantic_tag::none, const ser_context&=ser_context()") + bool byte_string_value(const byte_string_view& b, + byte_string_chars_format encoding_hint, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + switch (encoding_hint) + { + case byte_string_chars_format::base16: + tag = semantic_tag::base16; + break; + case byte_string_chars_format::base64: + tag = semantic_tag::base64; + break; + case byte_string_chars_format::base64url: + tag = semantic_tag::base64url; + break; + default: + break; + } + return byte_string_value(b, tag, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use byte_string_value(const byte_string_view&, semantic_tag=semantic_tag::none, const ser_context&=ser_context()") + bool byte_string_value(const uint8_t* p, std::size_t size, + byte_string_chars_format encoding_hint, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + switch (encoding_hint) + { + case byte_string_chars_format::base16: + tag = semantic_tag::base16; + break; + case byte_string_chars_format::base64: + tag = semantic_tag::base64; + break; + case byte_string_chars_format::base64url: + tag = semantic_tag::base64url; + break; + default: + break; + } + return byte_string_value(byte_string(p, size), tag, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use string_value with semantic_tag::bigint") + bool big_integer_value(const string_view_type& value, const ser_context& context=ser_context()) + { + return string_value(value, semantic_tag::bigint, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use string_value with semantic_tag::bigdec") + bool big_decimal_value(const string_view_type& value, const ser_context& context=ser_context()) + { + return string_value(value, semantic_tag::bigdec, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use string_value with semantic_tag::datetime") + bool date_time_value(const string_view_type& value, const ser_context& context=ser_context()) + { + return string_value(value, semantic_tag::datetime, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use int64_value with semantic_tag::epoch_second") + bool timestamp_value(int64_t val, const ser_context& context=ser_context()) + { + return int64_value(val, semantic_tag::epoch_second, context); + } + + JSONCONS_DEPRECATED_MSG("Remove calls to this method, it doesn't do anything") + bool begin_document() + { + return true; + } + + JSONCONS_DEPRECATED_MSG("Instead, use flush() when serializing") + bool end_document() + { + flush(); + return true; + } + + JSONCONS_DEPRECATED_MSG("Remove calls to this method, it doesn't do anything") + void begin_json() + { + } + + JSONCONS_DEPRECATED_MSG("Instead, use flush() when serializing") + void end_json() + { + end_document(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use key(const string_view_type&, const ser_context&=ser_context())") + void name(const char_type* p, std::size_t length, const ser_context& context) + { + name(string_view_type(p, length), context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use uint64_value(uint64_t, semantic_tag = semantic_tag::none, const ser_context&=ser_context())") + void integer_value(int64_t value) + { + int64_value(value); + } + + JSONCONS_DEPRECATED_MSG("Instead, use int64_value(int64_t, semantic_tag = semantic_tag::none, const ser_context&=ser_context())") + void integer_value(int64_t value, const ser_context& context) + { + int64_value(value,context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use uint64_value(uint64_t, semantic_tag = semantic_tag::none, const ser_context&=ser_context())") + void uinteger_value(uint64_t value) + { + uint64_value(value); + } + + JSONCONS_DEPRECATED_MSG("Instead, use uint64_value(uint64_t, semantic_tag = semantic_tag::none, const ser_context&=ser_context())") + void uinteger_value(uint64_t value, const ser_context& context) + { + uint64_value(value,context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use string_value with semantic_tag::bigint") + bool bignum_value(const string_view_type& value, const ser_context& context=ser_context()) + { + return string_value(value, semantic_tag::bigint, context); + } + + JSONCONS_DEPRECATED_MSG("Instead, use string_value with semantic_tag::bigdec") + bool decimal_value(const string_view_type& value, const ser_context& context=ser_context()) + { + return string_value(value, semantic_tag::bigdec, context); + } + + #endif + private: + + virtual void visit_flush() = 0; + + virtual bool visit_begin_object(semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_begin_object(std::size_t /*length*/, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_object(tag, context, ec); + } + + virtual bool visit_end_object(const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_begin_array(semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_begin_array(std::size_t /*length*/, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_array(tag, context, ec); + } + + virtual bool visit_end_array(const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_key(const string_view_type& name, + const ser_context& context, + std::error_code&) = 0; + + virtual bool visit_null(semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_bool(bool value, + semantic_tag tag, + const ser_context& context, + std::error_code&) = 0; + + virtual bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_byte_string(const byte_string_view& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_byte_string(const byte_string_view& value, + uint64_t /* ext_tag */, + const ser_context& context, + std::error_code& ec) + { + return visit_byte_string(value, semantic_tag::none, context, ec); + } + + virtual bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_double(binary::decode_half(value), + tag, + context, + ec); + } + + virtual bool visit_double(double value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(half_arg_t, + const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = half_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = double_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = double_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = visit_begin_array(2, tag, context, ec); + if (more) + { + more = visit_begin_array(shape.size(), tag, context, ec); + for (auto it = shape.begin(); more && it != shape.end(); ++it) + { + visit_uint64(*it, semantic_tag::none, context, ec); + } + if (more) + { + more = visit_end_array(context, ec); + } + } + return more; + } + + virtual bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) + { + return visit_end_array(context, ec); + } + }; + + template + class basic_default_json_visitor : public basic_json_visitor + { + bool parse_more_; + std::error_code ec_; + public: + using typename basic_json_visitor::string_view_type; + + basic_default_json_visitor(bool accept_more = true, + std::error_code ec = std::error_code()) + : parse_more_(accept_more), ec_(ec) + { + } + private: + void visit_flush() override + { + } + + bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_end_object(const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_end_array(const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_key(const string_view_type&, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_null(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_string(const string_view_type&, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_byte_string(const byte_string_view&, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_uint64(uint64_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_int64(int64_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_half(uint16_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_double(double, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_bool(bool, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + }; + + template + class basic_json_tee_visitor : public basic_json_visitor + { + public: + using typename basic_json_visitor::char_type; + using typename basic_json_visitor::string_view_type; + private: + basic_json_visitor& destination0_; + basic_json_visitor& destination1_; + + // noncopyable and nonmoveable + basic_json_tee_visitor(const basic_json_tee_visitor&) = delete; + basic_json_tee_visitor& operator=(const basic_json_tee_visitor&) = delete; + public: + basic_json_tee_visitor(basic_json_visitor& destination0, + basic_json_visitor& destination1) + : destination0_(destination0), destination1_(destination1) + { + } + + basic_json_visitor& destination1() + { + return destination0_; + } + + basic_json_visitor& destination2() + { + return destination1_; + } + + private: + void visit_flush() override + { + destination0_.flush(); + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.begin_object(tag, context, ec); + bool more1 = destination1_.begin_object(tag, context, ec); + + return more0 && more1; + } + + bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.begin_object(length, tag, context, ec); + bool more1 = destination1_.begin_object(length, tag, context, ec); + + return more0 && more1; + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.end_object(context, ec); + bool more1 = destination1_.end_object(context, ec); + + return more0 && more1; + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.begin_array(tag, context, ec); + bool more1 = destination1_.begin_array(tag, context, ec); + + return more0 && more1; + } + + bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.begin_array(length, tag, context, ec); + bool more1 = destination1_.begin_array(length, tag, context, ec); + + return more0 && more1; + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.end_array(context, ec); + bool more1 = destination1_.end_array(context, ec); + + return more0 && more1; + } + + bool visit_key(const string_view_type& name, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.key(name, context, ec); + bool more1 = destination1_.key(name, context, ec); + + return more0 && more1; + } + + bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.string_value(value, tag, context, ec); + bool more1 = destination1_.string_value(value, tag, context, ec); + + return more0 && more1; + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.byte_string_value(b, tag, context, ec); + bool more1 = destination1_.byte_string_value(b, tag, context, ec); + + return more0 && more1; + } + + bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.uint64_value(value, tag, context, ec); + bool more1 = destination1_.uint64_value(value, tag, context, ec); + + return more0 && more1; + } + + bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.int64_value(value, tag, context, ec); + bool more1 = destination1_.int64_value(value, tag, context, ec); + + return more0 && more1; + } + + bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.half_value(value, tag, context, ec); + bool more1 = destination1_.half_value(value, tag, context, ec); + + return more0 && more1; + } + + bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.double_value(value, tag, context, ec); + bool more1 = destination1_.double_value(value, tag, context, ec); + + return more0 && more1; + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.bool_value(value, tag, context, ec); + bool more1 = destination1_.bool_value(value, tag, context, ec); + + return more0 && more1; + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool more0 = destination0_.null_value(tag, context, ec); + bool more1 = destination1_.null_value(tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(half_arg_t, + const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(half_arg, s, tag, context, ec); + bool more1 = destination1_.typed_array(half_arg, s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.typed_array(s, tag, context, ec); + bool more1 = destination1_.typed_array(s, tag, context, ec); + + return more0 && more1; + } + + bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.begin_multi_dim(shape, tag, context, ec); + bool more1 = destination1_.begin_multi_dim(shape, tag, context, ec); + + return more0 && more1; + } + + bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) override + { + bool more0 = destination0_.end_multi_dim(context, ec); + bool more1 = destination1_.end_multi_dim(context, ec); + + return more0 && more1; + } + + }; + + template + class basic_json_diagnostics_visitor : public basic_default_json_visitor + { + public: + using stream_type = std::basic_ostream; + using string_type = std::basic_string; + + private: + using supertype = basic_default_json_visitor; + using string_view_type = typename supertype::string_view_type; + + struct enabler {}; + + static constexpr CharT visit_begin_array_name[] = {'v','i','s','i','t','_','b','e','g','i','n','_','a','r','r','a','y', 0}; + static constexpr CharT visit_end_array_name[] = {'v','i','s','i','t','_','e','n','d','_','a','r','r','a','y', 0}; + static constexpr CharT visit_begin_object_name[] = {'v','i','s','i','t','_','b','e','g','i','n','_','o','b','j','e','c','t', 0}; + static constexpr CharT visit_end_object_name[] = {'v','i','s','i','t','_','e','n','d','_','o','b','j','e','c','t', 0}; + static constexpr CharT visit_key_name[] = {'v','i','s','i','t','_','k','e','y', 0}; + static constexpr CharT visit_string_name[] = {'v','i','s','i','t','_','s','t','r','i','n','g', 0}; + static constexpr CharT visit_byte_string_name[] = {'v','i','s','i','t','_','b','y','t','e','_','s','t','r','i','n','g', 0}; + static constexpr CharT visit_null_name[] = {'v','i','s','i','t','_','n','u','l','l', 0}; + static constexpr CharT visit_bool_name[] = {'v','i','s','i','t','_','b','o','o','l', 0}; + static constexpr CharT visit_uint64_name[] = {'v','i','s','i','t','_','u','i','n','t','6','4', 0}; + static constexpr CharT visit_int64_name[] = {'v','i','s','i','t','_','i','n','t','6','4', 0}; + static constexpr CharT visit_half_name[] = {'v','i','s','i','t','_','h','a','l','f', 0}; + static constexpr CharT visit_double_name[] = {'v','i','s','i','t','_','d','o','u','b','l','e', 0}; + + static constexpr CharT separator_ = ':'; + + stream_type& output_; + string_type indentation_; + long level_; + + public: + // If CharT is char, then enable the default constructor which binds to + // std::cout. + template + basic_json_diagnostics_visitor( + typename std::enable_if::value, U>::type = enabler{}) + : basic_json_diagnostics_visitor(std::cout) + { + } + + // If CharT is wchar_t, then enable the default constructor which binds + // to std::wcout. + template + basic_json_diagnostics_visitor( + typename std::enable_if::value, U>::type = enabler{}) + : basic_json_diagnostics_visitor(std::wcout) + { + } + + explicit basic_json_diagnostics_visitor( + stream_type& output, + string_type indentation = string_type()) + : output_(output), + indentation_(std::move(indentation)), + level_(0) + { + } + + private: + void indent() + { + for (long i=0; i constexpr C basic_json_diagnostics_visitor::visit_begin_array_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_end_array_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_begin_object_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_end_object_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_key_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_string_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_byte_string_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_null_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_bool_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_uint64_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_int64_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_half_name[]; + template constexpr C basic_json_diagnostics_visitor::visit_double_name[]; + + using json_visitor = basic_json_visitor; + using wjson_visitor = basic_json_visitor; + + using json_tee_visitor = basic_json_tee_visitor; + using wjson_tee_visitor = basic_json_tee_visitor; + + using default_json_visitor = basic_default_json_visitor; + using wdefault_json_visitor = basic_default_json_visitor; + + using json_diagnostics_visitor = basic_json_diagnostics_visitor; + using wjson_diagnostics_visitor = basic_json_diagnostics_visitor; + +#if !defined(JSONCONS_NO_DEPRECATED) +template +using basic_json_content_handler = basic_json_visitor; + +JSONCONS_DEPRECATED_MSG("Instead, use json_visitor") typedef json_visitor json_content_handler; +JSONCONS_DEPRECATED_MSG("Instead, use wjson_visitor") typedef wjson_visitor wjson_content_handler; + +template +using basic_default_json_content_handler = basic_default_json_visitor; + +JSONCONS_DEPRECATED_MSG("Instead, use default_json_visitor") typedef default_json_visitor default_json_content_handler; +JSONCONS_DEPRECATED_MSG("Instead, use default_wjson_visitor") typedef wdefault_json_visitor default_wjson_content_handler; +#endif + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/json_visitor2.hpp b/include/jsoncons/json_visitor2.hpp new file mode 100644 index 0000000..26096aa --- /dev/null +++ b/include/jsoncons/json_visitor2.hpp @@ -0,0 +1,2079 @@ +// Copyright 2018 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_VISITOR2_HPP +#define JSONCONS_JSON_VISITOR2_HPP + +#include +#include + +namespace jsoncons { + + template > + class basic_json_visitor2_to_visitor_adaptor; + + template + class basic_json_visitor2 + { + template + friend class basic_json_visitor2_to_visitor_adaptor; + public: + using char_type = CharT; + using char_traits_type = std::char_traits; + + using string_view_type = jsoncons::basic_string_view; + + basic_json_visitor2(basic_json_visitor2&&) = default; + + basic_json_visitor2& operator=(basic_json_visitor2&&) = default; + + basic_json_visitor2() = default; + + virtual ~basic_json_visitor2() noexcept = default; + + void flush() + { + visit_flush(); + } + + bool begin_object(semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_object(tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_object(std::size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context = ser_context()) + { + std::error_code ec; + bool more = visit_begin_object(length, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool end_object(const ser_context& context = ser_context()) + { + std::error_code ec; + bool more = visit_end_object(context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_array(semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_array(tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_array(std::size_t length, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_array(length, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool end_array(const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_end_array(context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool key(const string_view_type& name, const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_string(name, semantic_tag::none, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool null_value(semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_null(tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool bool_value(bool value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_bool(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool string_value(const string_view_type& value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_string(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + template + bool byte_string_value(const Source& b, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context(), + typename std::enable_if::value,int>::type = 0) + { + std::error_code ec; + bool more = visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + template + bool byte_string_value(const Source& b, + uint64_t ext_tag, + const ser_context& context=ser_context(), + typename std::enable_if::value,int>::type = 0) + { + std::error_code ec; + bool more = visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), ext_tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool uint64_value(uint64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_uint64(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool int64_value(int64_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_int64(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool half_value(uint16_t value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_half(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool double_value(double value, + semantic_tag tag = semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_double(value, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_object(semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_object(tag, context, ec); + } + + bool begin_object(std::size_t length, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_object(length, tag, context, ec); + } + + bool end_object(const ser_context& context, std::error_code& ec) + { + return visit_end_object(context, ec); + } + + bool begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) + { + return visit_begin_array(tag, context, ec); + } + + bool begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) + { + return visit_begin_array(length, tag, context, ec); + } + + bool end_array(const ser_context& context, std::error_code& ec) + { + return visit_end_array(context, ec); + } + + bool key(const string_view_type& name, const ser_context& context, std::error_code& ec) + { + return visit_string(name, semantic_tag::none, context, ec); + } + + bool null_value(semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_null(tag, context, ec); + } + + bool bool_value(bool value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_bool(value, tag, context, ec); + } + + bool string_value(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_string(value, tag, context, ec); + } + + template + bool byte_string_value(const Source& b, + semantic_tag tag, + const ser_context& context, + std::error_code& ec, + typename std::enable_if::value,int>::type = 0) + { + return visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), tag, context, ec); + } + + template + bool byte_string_value(const Source& b, + uint64_t ext_tag, + const ser_context& context, + std::error_code& ec, + typename std::enable_if::value,int>::type = 0) + { + return visit_byte_string(byte_string_view(reinterpret_cast(b.data()),b.size()), ext_tag, context, ec); + } + + bool uint64_value(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_uint64(value, tag, context, ec); + } + + bool int64_value(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_int64(value, tag, context, ec); + } + + bool half_value(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_half(value, tag, context, ec); + } + + bool double_value(double value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_double(value, tag, context, ec); + } + + template + bool typed_array(const jsoncons::span& data, + semantic_tag tag=semantic_tag::none, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_typed_array(data, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + template + bool typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_typed_array(data, tag, context, ec); + } + + bool typed_array(half_arg_t, const jsoncons::span& s, + semantic_tag tag = semantic_tag::none, + const ser_context& context = ser_context()) + { + std::error_code ec; + bool more = visit_typed_array(half_arg, s, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool typed_array(half_arg_t, const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_typed_array(half_arg, s, tag, context, ec); + } + + bool begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag = semantic_tag::multi_dim_row_major, + const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_begin_multi_dim(shape, tag, context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_multi_dim(shape, tag, context, ec); + } + + bool end_multi_dim(const ser_context& context=ser_context()) + { + std::error_code ec; + bool more = visit_end_multi_dim(context, ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, context.line(), context.column())); + } + return more; + } + + bool end_multi_dim(const ser_context& context, + std::error_code& ec) + { + return visit_end_multi_dim(context, ec); + } + + private: + + virtual void visit_flush() = 0; + + virtual bool visit_begin_object(semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_begin_object(std::size_t /*length*/, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_object(tag, context, ec); + } + + virtual bool visit_end_object(const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_begin_array(semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_begin_array(std::size_t /*length*/, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_begin_array(tag, context, ec); + } + + virtual bool visit_end_array(const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_null(semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_bool(bool value, + semantic_tag tag, + const ser_context& context, + std::error_code&) = 0; + + virtual bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_byte_string(const byte_string_view& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_byte_string(const byte_string_view& value, + uint64_t /*ext_tag*/, + const ser_context& context, + std::error_code& ec) + { + return visit_byte_string(value, semantic_tag::none, context, ec); + } + + virtual bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + return visit_double(binary::decode_half(value), + tag, + context, + ec); + } + + virtual bool visit_double(double value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) = 0; + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = uint64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = int64_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(half_arg_t, + const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag, context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = half_value(*p, semantic_tag::none, context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = double_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = begin_array(s.size(), tag,context, ec); + for (auto p = s.begin(); more && p != s.end(); ++p) + { + more = double_value(*p,semantic_tag::none,context, ec); + } + if (more) + { + more = end_array(context, ec); + } + return more; + } + + virtual bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) + { + bool more = visit_begin_array(2, tag, context, ec); + if (more) + { + more = visit_begin_array(shape.size(), tag, context, ec); + for (auto it = shape.begin(); more && it != shape.end(); ++it) + { + visit_uint64(*it, semantic_tag::none, context, ec); + } + if (more) + { + more = visit_end_array(context, ec); + } + } + return more; + } + + virtual bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) + { + return visit_end_array(context, ec); + } + }; + + template + class basic_json_visitor2_to_visitor_adaptor : public basic_json_visitor2 + { + public: + using typename basic_json_visitor2::char_type; + using typename basic_json_visitor2::string_view_type; + private: + using char_allocator_type = typename std::allocator_traits:: template rebind_alloc; + + using string_type = std::basic_string,char_allocator_type>; + + enum class container_t {root, array, object}; + enum class target_t {destination, buffer}; + + struct level + { + private: + target_t state_; + container_t type_; + int even_odd_; + std::size_t count_; + public: + + level(target_t state, container_t type) noexcept + : state_(state), type_(type), even_odd_(type == container_t::object ? 0 : 1), count_(0) + { + } + + void advance() + { + if (!is_key()) + { + ++count_; + } + if (is_object()) + { + even_odd_ = !even_odd_; + } + } + + bool is_key() const + { + return even_odd_ == 0; + } + + bool is_object() const + { + return type_ == container_t::object; + } + + target_t target() const + { + return state_; + } + + std::size_t count() const + { + return count_; + } + }; + using level_allocator_type = typename std::allocator_traits:: template rebind_alloc; + + basic_default_json_visitor default_visitor_; + basic_json_visitor* destination_; + string_type key_; + string_type key_buffer_; + std::vector level_stack_; + + const std::basic_string null_constant = {'n','u','l','l'}; + const std::basic_string true_constant = { 't','r','u','e' }; + const std::basic_string false_constant = { 'f', 'a', 'l', 's', 'e' }; + + // noncopyable and nonmoveable + basic_json_visitor2_to_visitor_adaptor(const basic_json_visitor2_to_visitor_adaptor&) = delete; + basic_json_visitor2_to_visitor_adaptor& operator=(const basic_json_visitor2_to_visitor_adaptor&) = delete; + public: + explicit basic_json_visitor2_to_visitor_adaptor(const Allocator& alloc = Allocator()) + : default_visitor_(), destination_(std::addressof(default_visitor_)), + key_(alloc), key_buffer_(alloc), level_stack_(alloc) + { + level_stack_.emplace_back(target_t::destination,container_t::root); // root + } + + explicit basic_json_visitor2_to_visitor_adaptor(basic_json_visitor& visitor, + const Allocator& alloc = Allocator()) + : destination_(std::addressof(visitor)), + key_(alloc), key_buffer_(alloc), level_stack_(alloc) + { + level_stack_.emplace_back(target_t::destination,container_t::root); // root + } + + void reset() + { + key_.clear(); + key_buffer_.clear(); + level_stack_.clear(); + level_stack_.emplace_back(target_t::destination,container_t::root); // root + } + + basic_json_visitor& destination() + { + return *destination_; + } + + void destination(basic_json_visitor& dest) + { + destination_ = std::addressof(dest); + } + + private: + void visit_flush() override + { + destination_->flush(); + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + if (level_stack_.back().is_key()) + { + if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::object); + key_buffer_.push_back('{'); + return true; + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + level_stack_.emplace_back(target_t::buffer, container_t::object); + key_buffer_.push_back('{'); + return true; + default: + level_stack_.emplace_back(target_t::destination, container_t::object); + return destination_->begin_object(tag, context, ec); + } + } + } + + bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + if (level_stack_.back().is_key()) + { + if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::object); + key_buffer_.push_back('{'); + return true; + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::object); + key_buffer_.push_back('{'); + return true; + default: + level_stack_.emplace_back(target_t::destination, container_t::object); + return destination_->begin_object(length, tag, context, ec); + } + } + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + bool retval = true; + switch (level_stack_.back().target()) + { + case target_t::buffer: + key_buffer_.push_back('}'); + JSONCONS_ASSERT(level_stack_.size() > 1); + level_stack_.pop_back(); + + if (level_stack_.back().target() == target_t::destination) + { + retval = destination_->key(key_buffer_,context, ec); + key_buffer_.clear(); + } + else if (level_stack_.back().is_key()) + { + key_buffer_.push_back(':'); + } + level_stack_.back().advance(); + break; + default: + JSONCONS_ASSERT(level_stack_.size() > 1); + level_stack_.pop_back(); + level_stack_.back().advance(); + retval = destination_->end_object(context, ec); + break; + } + return retval; + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + if (level_stack_.back().is_key()) + { + if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::array); + key_buffer_.push_back('['); + return true; + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::array); + key_buffer_.push_back('['); + return true; + default: + level_stack_.emplace_back(target_t::destination, container_t::array); + return destination_->begin_array(tag, context, ec); + } + } + } + + bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + if (level_stack_.back().is_key()) + { + if (level_stack_.back().target() == target_t::buffer && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::array); + key_buffer_.push_back('['); + return true; + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + level_stack_.emplace_back(target_t::buffer, container_t::array); + key_buffer_.push_back('['); + return true; + default: + level_stack_.emplace_back(target_t::destination, container_t::array); + return destination_->begin_array(length, tag, context, ec); + } + } + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + bool retval = true; + switch (level_stack_.back().target()) + { + case target_t::buffer: + key_buffer_.push_back(']'); + JSONCONS_ASSERT(level_stack_.size() > 1); + level_stack_.pop_back(); + if (level_stack_.back().target() == target_t::destination) + { + retval = destination_->key(key_buffer_, context, ec); + key_buffer_.clear(); + } + else if (level_stack_.back().is_key()) + { + key_buffer_.push_back(':'); + } + level_stack_.back().advance(); + break; + default: + JSONCONS_ASSERT(level_stack_.size() > 1); + level_stack_.pop_back(); + level_stack_.back().advance(); + retval = destination_->end_array(context, ec); + break; + } + return retval; + } + + bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.push_back('\"'); + key_buffer_.insert(key_buffer_.end(), value.begin(), value.end()); + key_buffer_.push_back('\"'); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(value, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.push_back('\"'); + key_buffer_.insert(key_buffer_.end(), value.begin(), value.end()); + key_buffer_.push_back('\"'); + retval = true; + break; + default: + retval = destination_->string_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_byte_string(const byte_string_view& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_.clear(); + switch (tag) + { + case semantic_tag::base64: + encode_base64(value.begin(), value.end(), key_); + break; + case semantic_tag::base16: + encode_base16(value.begin(), value.end(),key_); + break; + default: + encode_base64url(value.begin(), value.end(),key_); + break; + } + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.push_back('\"'); + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back('\"'); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.push_back('\"'); + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back('\"'); + retval = true; + break; + default: + retval = destination_->byte_string_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_byte_string(const byte_string_view& value, + uint64_t ext_tag, + const ser_context& context, + std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_.clear(); + encode_base64url(value.begin(), value.end(),key_); + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.push_back('\"'); + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back('\"'); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.push_back('\"'); + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back('\"'); + retval = true; + break; + default: + retval = destination_->byte_string_value(value, ext_tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_.clear(); + jsoncons::detail::from_integer(value,key_); + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + retval = true; + break; + default: + retval = destination_->uint64_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_.clear(); + jsoncons::detail::from_integer(value,key_); + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + retval = true; + break; + default: + retval = destination_->int64_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_.clear(); + jsoncons::string_sink sink(key_); + jsoncons::detail::write_double f{float_chars_format::general,0}; + double x = binary::decode_half(value); + f(x, sink); + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + retval = true; + break; + default: + retval = destination_->half_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_.clear(); + string_sink sink(key_); + jsoncons::detail::write_double f{float_chars_format::general,0}; + f(value, sink); + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + retval = true; + break; + default: + retval = destination_->double_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_ = value ? true_constant : false_constant; + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + retval = true; + break; + default: + retval = destination_->bool_value(value, tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + bool retval = true; + + if (level_stack_.back().is_key() || level_stack_.back().target() == target_t::buffer) + { + key_ = null_constant; + } + + if (level_stack_.back().is_key()) + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + key_buffer_.push_back(':'); + retval = true; + break; + default: + retval = destination_->key(key_, context, ec); + break; + } + } + else + { + switch (level_stack_.back().target()) + { + case target_t::buffer: + if (!level_stack_.back().is_object() && level_stack_.back().count() > 0) + { + key_buffer_.push_back(','); + } + key_buffer_.insert(key_buffer_.end(), key_.begin(), key_.end()); + retval = true; + break; + default: + retval = destination_->null_value(tag, context, ec); + break; + } + } + + level_stack_.back().advance(); + return retval; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(half_arg_t, + const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(half_arg,s,tag,context,ec); + } + else + { + return destination_->typed_array(half_arg, s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + bool is_key = level_stack_.back().is_key(); + level_stack_.back().advance(); + + if (is_key || level_stack_.back().target() == target_t::buffer) + { + return basic_json_visitor2::visit_typed_array(s,tag,context,ec); + } + else + { + return destination_->typed_array(s, tag, context, ec); + } + } + }; + + template + class basic_default_json_visitor2 : public basic_json_visitor2 + { + bool parse_more_; + std::error_code ec_; + public: + using typename basic_json_visitor2::string_view_type; + + basic_default_json_visitor2(bool accept_more = true, + std::error_code ec = std::error_code()) + : parse_more_(accept_more), ec_(ec) + { + } + private: + void visit_flush() override + { + } + + bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_begin_object(std::size_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_end_object(const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_begin_array(std::size_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_end_array(const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_null(semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_string(const string_view_type&, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_byte_string(const byte_string_view&, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_uint64(uint64_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_int64(int64_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_half(uint16_t, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_double(double, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + + bool visit_bool(bool, semantic_tag, const ser_context&, std::error_code& ec) override + { + if (ec_) + { + ec = ec_; + } + return parse_more_; + } + }; + + // basic_json_visitor_to_visitor2_adaptor + + template + class basic_json_visitor_to_visitor2_adaptor : public basic_json_visitor + { + public: + using typename basic_json_visitor::char_type; + using typename basic_json_visitor::string_view_type; + private: + basic_json_visitor2& destination_; + + // noncopyable and nonmoveable + basic_json_visitor_to_visitor2_adaptor(const basic_json_visitor_to_visitor2_adaptor&) = delete; + basic_json_visitor_to_visitor2_adaptor& operator=(const basic_json_visitor_to_visitor2_adaptor&) = delete; + public: + basic_json_visitor_to_visitor2_adaptor(basic_json_visitor2& visitor) + : destination_(visitor) + { + } + + basic_json_visitor2& destination() + { + return destination_; + } + + private: + void visit_flush() override + { + destination_.flush(); + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.begin_object(tag, context, ec); + } + + bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.begin_object(length, tag, context, ec); + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + return destination_.end_object(context, ec); + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.begin_array(tag, context, ec); + } + + bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.begin_array(length, tag, context, ec); + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + return destination_.end_array(context, ec); + } + + bool visit_key(const string_view_type& name, + const ser_context& context, + std::error_code& ec) override + { + return destination_.visit_string(name, context, ec); + } + + bool visit_string(const string_view_type& value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_.string_value(value, tag, context, ec); + } + + bool visit_byte_string(const byte_string_view& b, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return destination_.byte_string_value(b, tag, context, ec); + } + + bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.uint64_value(value, tag, context, ec); + } + + bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.int64_value(value, tag, context, ec); + } + + bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.half_value(value, tag, context, ec); + } + + bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.double_value(value, tag, context, ec); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.bool_value(value, tag, context, ec); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return destination_.null_value(tag, context, ec); + } + }; + + class diagnostics_visitor2 : public basic_default_json_visitor2 + { + bool visit_begin_object(semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_begin_object" << std::endl; + return true; + } + + bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_begin_object " << length << std::endl; + return true; + } + + bool visit_end_object(const ser_context&, std::error_code&) override + { + std::cout << "visit_end_object" << std::endl; + return true; + } + + bool visit_begin_array(semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_begin_array" << std::endl; + return true; + } + + bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_begin_array " << length << std::endl; + return true; + } + + bool visit_end_array(const ser_context&, std::error_code&) override + { + std::cout << "visit_end_array" << std::endl; + return true; + } + + bool visit_string(const string_view_type& s, semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_string " << s << std::endl; + return true; + } + bool visit_int64(int64_t val, semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_int64 " << val << std::endl; + return true; + } + bool visit_uint64(uint64_t val, semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_uint64 " << val << std::endl; + return true; + } + bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_bool " << val << std::endl; + return true; + } + bool visit_null(semantic_tag, const ser_context&, std::error_code&) override + { + std::cout << "visit_null " << std::endl; + return true; + } + + bool visit_typed_array(const jsoncons::span& s, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + std::cout << "visit_typed_array uint16_t " << tag << std::endl; + for (auto val : s) + { + std::cout << val << "" << std::endl; + } + std::cout << "" << std::endl; + return true; + } + + bool visit_typed_array(half_arg_t, const jsoncons::span& s, + semantic_tag tag, + const ser_context&, + std::error_code&) override + { + std::cout << "visit_typed_array half_arg_t uint16_t " << tag << "" << std::endl; + for (auto val : s) + { + std::cout << val << "" << std::endl; + } + std::cout << "" << std::endl; + return true; + } + }; + + using json_visitor2 = basic_json_visitor2; + using default_json_visitor2 = basic_default_json_visitor2; + using json_visitor2_to_visitor_adaptor = basic_json_visitor2_to_visitor_adaptor; + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/more_type_traits.hpp b/include/jsoncons/more_type_traits.hpp new file mode 100644 index 0000000..8e6b6c2 --- /dev/null +++ b/include/jsoncons/more_type_traits.hpp @@ -0,0 +1,874 @@ +// 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_MORE_TYPE_TRAITS_HPP +#define JSONCONS_MORE_TYPE_TRAITS_HPP + +#include +#include +#include +#include // std::enable_if, std::true_type +#include +#include // std::iterator_traits +#include +#include // std::array +#include // std::byte +#include // std::declval +#include // CHAR_BIT +#include + +namespace jsoncons { +namespace type_traits { + + // is_char8 + template + struct is_char8 : std::false_type {}; + + template + struct is_char8::value && + !std::is_same::value && + sizeof(uint8_t) == sizeof(CharT)>::type> : std::true_type {}; + + // is_char16 + template + struct is_char16 : std::false_type {}; + + template + struct is_char16::value && + !std::is_same::value && + (std::is_same::value || sizeof(uint16_t) == sizeof(CharT))>::type> : std::true_type {}; + + // is_char32 + template + struct is_char32 : std::false_type {}; + + template + struct is_char32::value && + !std::is_same::value && + (std::is_same::value || (!std::is_same::value && sizeof(uint32_t) == sizeof(CharT)))>::type> : std::true_type {}; + + // is_int128 + + template + struct is_int128_type : std::false_type {}; + +#if defined(JSONCONS_HAS_INT128) + template + struct is_int128_type::value>::type> : std::true_type {}; +#endif + + // is_unsigned_integer + + template + struct is_uint128_type : std::false_type {}; + +#if defined (JSONCONS_HAS_INT128) + template + struct is_uint128_type::value>::type> : std::true_type {}; +#endif + + template + class integer_limits + { + public: + static constexpr bool is_specialized = false; + }; + + template + class integer_limits::value && !std::is_same::value>::type> + { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr int digits = std::numeric_limits::digits; + static constexpr std::size_t buffer_size = static_cast(sizeof(T)*CHAR_BIT*0.302) + 3; + + static constexpr T(max)() noexcept + { + return (std::numeric_limits::max)(); + } + static constexpr T(min)() noexcept + { + return (std::numeric_limits::min)(); + } + static constexpr T lowest() noexcept + { + return std::numeric_limits::lowest(); + } + }; + + template + class integer_limits::value && is_int128_type::value>::type> + { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr int digits = sizeof(T)*CHAR_BIT - 1; + static constexpr std::size_t buffer_size = (sizeof(T)*CHAR_BIT*0.302) + 3; + + static constexpr T(max)() noexcept + { + return (((((T)1 << (digits - 1)) - 1) << 1) + 1); + } + static constexpr T(min)() noexcept + { + return -(max)() - 1; + } + static constexpr T lowest() noexcept + { + return (min)(); + } + }; + + template + class integer_limits::value && is_uint128_type::value>::type> + { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr int digits = sizeof(T)*CHAR_BIT; + + static constexpr T(max)() noexcept + { + return T(T(~0)); + } + static constexpr T(min)() noexcept + { + return 0; + } + static constexpr T lowest() noexcept + { + return std::numeric_limits::lowest(); + } + }; + + #ifndef JSONCONS_HAS_VOID_T + // follows https://en.cppreference.com/w/cpp/types/void_t + template struct make_void { typedef void type;}; + template using void_t = typename make_void::type; + #else + using void_t = std::void_t; + #endif + + // follows http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf + + // detector + + // primary template handles all types not supporting the archetypal Op + template< + class Default, + class, // always void; supplied externally + template class Op, + class... Args + > + struct detector + { + constexpr static auto value = false; + using type = Default; + }; + + // specialization recognizes and handles only types supporting Op + template< + class Default, + template class Op, + class... Args + > + struct detector>, Op, Args...> + { + constexpr static auto value = true; + using type = Op; + }; + + // is_detected, is_detected_t + + template< template class Op, class... Args > + using + is_detected = detector; + + template< template class Op, class... Args > + using + is_detected_t = typename is_detected::type; + + // detected_or, detected_or_t + + template< class Default, template class Op, class... Args > + using + detected_or = detector; + + template< class Default, template class Op, class... Args > + using + detected_or_t = typename detected_or::type; + + // is_detected_exact + + template< class Expected, template class Op, class... Args > + using + is_detected_exact = std::is_same< Expected, is_detected_t >; + + // is_detected_convertible + + template< class To, template class Op, class... Args > + using + is_detected_convertible = std::is_convertible< is_detected_t, To >; + + template + struct is_stateless + : public std::integral_constant::value && + std::is_empty::value)> + {}; + + // to_plain_pointer + + template inline + typename std::pointer_traits::element_type* to_plain_pointer(Pointer ptr) + { + return (std::addressof(*ptr)); + } + + template inline + T * to_plain_pointer(T * ptr) + { + return (ptr); + } + + // is_std_byte + + template + struct is_std_byte : std::false_type {}; +#if defined(JSONCONS_HAS_STD_BYTE) + template + struct is_std_byte::value + >::type> : std::true_type {}; +#endif + // is_byte + + template + struct is_byte : std::false_type {}; + + template + struct is_byte::value || + std::is_same::value || + std::is_same::value || + is_std_byte::value + >::type> : std::true_type {}; + + // is_character + + template + struct is_character : std::false_type {}; + + template + struct is_character::value || + std::is_same::value + >::type> : std::true_type {}; + + // is_narrow_character + + template + struct is_narrow_character : std::false_type {}; + + template + struct is_narrow_character::value && (sizeof(T) == sizeof(char)) + >::type> : std::true_type {}; + + // is_wide_character + + template + struct is_wide_character : std::false_type {}; + + template + struct is_wide_character::value && (sizeof(T) != sizeof(char)) + >::type> : std::true_type {}; + + // From boost + namespace ut_detail { + + template + struct is_cstring_impl : public std::false_type {}; + + template + struct is_cstring_impl : public is_cstring_impl {}; + + template + struct is_cstring_impl : public is_cstring_impl {}; + + template<> + struct is_cstring_impl : public std::true_type {}; + + template<> + struct is_cstring_impl : public std::true_type {}; + + } // namespace ut_detail + + template + struct is_cstring : public ut_detail::is_cstring_impl::type> {}; + + // is_bool + + template + struct is_bool : std::false_type {}; + + template + struct is_bool::value + >::type> : std::true_type {}; + + // is_u8_u16_u32_or_u64 + + template + struct is_u8_u16_u32_or_u64 : std::false_type {}; + + template + struct is_u8_u16_u32_or_u64::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + >::type> : std::true_type {}; + + // is_int + + template + struct is_i8_i16_i32_or_i64 : std::false_type {}; + + template + struct is_i8_i16_i32_or_i64::value || + std::is_same::value || + std::is_same::value || + std::is_same::value + >::type> : std::true_type {}; + + // is_float_or_double + + template + struct is_float_or_double : std::false_type {}; + + template + struct is_float_or_double::value || + std::is_same::value + >::type> : std::true_type {}; + + // make_unsigned + template + struct make_unsigned_impl {using type = typename std::make_unsigned::type;}; + + #if defined(JSONCONS_HAS_INT128) + template <> + struct make_unsigned_impl {using type = uint128_type;}; + template <> + struct make_unsigned_impl {using type = uint128_type;}; + #endif + + template + struct make_unsigned + : make_unsigned_impl::type> + {}; + + // is_integer + + template + struct is_integer : std::false_type {}; + + template + struct is_integer::is_specialized>::type> : std::true_type {}; + + // is_signed_integer + + template + struct is_signed_integer : std::false_type {}; + + template + struct is_signed_integer::is_specialized && + integer_limits::is_signed>::type> : std::true_type {}; + + // is_unsigned_integer + + template + struct is_unsigned_integer : std::false_type {}; + + template + struct is_unsigned_integer::is_specialized && + !integer_limits::is_signed>::type> : std::true_type {}; + + // is_primitive + + template + struct is_primitive : std::false_type {}; + + template + struct is_primitive::value || + is_bool::value || + std::is_floating_point::value + >::type> : std::true_type {}; + + // Containers + + template + using + container_npos_t = decltype(Container::npos); + + template + using + container_allocator_type_t = typename Container::allocator_type; + + template + using + container_mapped_type_t = typename Container::mapped_type; + + template + using + container_key_type_t = typename Container::key_type; + + template + using + container_value_type_t = typename std::iterator_traits::value_type; + + template + using + container_char_traits_t = typename Container::traits_type::char_type; + + template + using + container_push_back_t = decltype(std::declval().push_back(std::declval())); + + template + using + container_push_front_t = decltype(std::declval().push_front(std::declval())); + + template + using + container_insert_t = decltype(std::declval().insert(std::declval())); + + template + using + container_reserve_t = decltype(std::declval().reserve(typename Container::size_type())); + + template + using + container_data_t = decltype(std::declval().data()); + + template + using + container_size_t = decltype(std::declval().size()); + + // is_string_or_string_view + + template + struct is_string_or_string_view : std::false_type {}; + + template + struct is_string_or_string_view::value && + is_detected_exact::value && + is_detected::value + >::type> : std::true_type {}; + + // is_basic_string + + template + struct is_basic_string : std::false_type {}; + + template + struct is_basic_string::value && + is_detected::value + >::type> : std::true_type {}; + + // is_basic_string_view + + template + struct is_basic_string_view : std::false_type {}; + + template + struct is_basic_string_view::value && + !is_detected::value + >::type> : std::true_type {}; + + // is_map_like + + template + struct is_map_like : std::false_type {}; + + template + struct is_map_like::value && + is_detected::value && + is_detected::value && + is_detected::value + >::type> + : std::true_type {}; + + // is_std_array + template + struct is_std_array : std::false_type {}; + + template + struct is_std_array> : std::true_type {}; + + // is_list_like + + template + struct is_list_like : std::false_type {}; + + template + struct is_list_like::value && + is_detected::value && + !is_std_array::value && + !is_detected_exact::value && + !is_map_like::value + >::type> + : std::true_type {}; + + // is_constructible_from_const_pointer_and_size + + template + struct is_constructible_from_const_pointer_and_size : std::false_type {}; + + template + struct is_constructible_from_const_pointer_and_size::value + >::type> + : std::true_type {}; + + // has_reserve + + template + using + has_reserve = is_detected; + + // is_back_insertable + + template + using + is_back_insertable = is_detected; + + // is_front_insertable + + template + using + is_front_insertable = is_detected; + + // is_insertable + + template + using + is_insertable = is_detected; + + // has_data, has_data_exact + + template + using + has_data = is_detected; + + template + using + has_data_exact = is_detected_exact; + + // has_size + + template + using + has_size = is_detected; + + // has_data_and_size + + template + struct has_data_and_size + { + static constexpr bool value = has_data::value && has_size::value; + }; + + // is_byte_sequence + + template + struct is_byte_sequence : std::false_type {}; + + template + struct is_byte_sequence::value && + has_size::value && + is_byte::value + >::type> : std::true_type {}; + + // is_char_sequence + + template + struct is_char_sequence : std::false_type {}; + + template + struct is_char_sequence::value && + has_size::value && + is_character::value + >::type> : std::true_type {}; + + // is_sequence_of + + template + struct is_sequence_of : std::false_type {}; + + template + struct is_sequence_of::value && + has_size::value && + std::is_same::value + >::type> : std::true_type {}; + + // is_back_insertable_byte_container + + template + struct is_back_insertable_byte_container : std::false_type {}; + + template + struct is_back_insertable_byte_container::value && + is_byte::value + >::type> : std::true_type {}; + + // is_back_insertable_char_container + + template + struct is_back_insertable_char_container : std::false_type {}; + + template + struct is_back_insertable_char_container::value && + is_character::value + >::type> : std::true_type {}; + + // is_back_insertable_container_of + + template + struct is_back_insertable_container_of : std::false_type {}; + + template + struct is_back_insertable_container_of::value && + std::is_same::value + >::type> : std::true_type {}; + + // is_c_array + + template + struct is_c_array : std::false_type {}; + + template + struct is_c_array : std::true_type {}; + + template + struct is_c_array : std::true_type {}; + +namespace impl { + + template + struct is_typed_array : std::false_type {}; + + template + struct is_typed_array + < + T, + typename std::enable_if::value && + (std::is_same::type,uint8_t>::value || + std::is_same::type,uint16_t>::value || + std::is_same::type,uint32_t>::value || + std::is_same::type,uint64_t>::value || + std::is_same::type,int8_t>::value || + std::is_same::type,int16_t>::value || + std::is_same::type,int32_t>::value || + std::is_same::type,int64_t>::value || + std::is_same::type,float_t>::value || + std::is_same::type,double_t>::value)>::type + > : std::true_type{}; + +} // namespace impl + + template + using is_typed_array = impl::is_typed_array::type>; + + // is_compatible_element + + template + struct is_compatible_element : std::false_type {}; + + template + struct is_compatible_element + < + Container, Element, + typename std::enable_if::value>::type> + : std::is_convertible< typename std::remove_pointer().data() )>::type(*)[], Element(*)[]> + {}; + + template + using + construct_from_string_t = decltype(T(std::string{})); + + + template + using + is_constructible_from_string = is_detected; + + template + using + construct_from_data_size_t = decltype(T(static_cast(nullptr),Size{})); + + + template + using + is_constructible_from_data_size = is_detected; + + // is_unary_function_object + // is_unary_function_object_exact + + template + using + unary_function_object_t = decltype(std::declval()(std::declval())); + + template + using + is_unary_function_object = is_detected; + + template + using + is_unary_function_object_exact = is_detected_exact; + + // is_binary_function_object + // is_binary_function_object_exact + + template + using + binary_function_object_t = decltype(std::declval()(std::declval(),std::declval())); + + template + using + is_binary_function_object = is_detected; + + template + using + is_binary_function_object_exact = is_detected_exact; + + template + struct is_convertible_to_string_view : std::false_type {}; + + template + struct is_convertible_to_string_view::value || + is_cstring::value + >::type> : std::true_type {}; + + #if defined(JSONCONS_HAS_2017) + template + using is_nothrow_swappable = std::is_nothrow_swappable; + #else + template + struct is_nothrow_swappable { + static const bool value = noexcept(swap(std::declval(), std::declval())); + }; + #endif + + #if defined(JSONCONS_HAS_2014) + template + using alignment_of = std::alignment_of; + + template< class T, T... Ints > + using integer_sequence = std::integer_sequence; + + template + using index_sequence = std::index_sequence; + + template + using make_integer_sequence = std::make_integer_sequence; + + template + using make_index_sequence = std::make_index_sequence; + + template + using index_sequence_for = std::index_sequence_for; + + #else + template + struct alignment_of + : std::integral_constant::type)> {}; + + template + class integer_sequence + { + public: + using value_type = T; + static_assert(std::is_integral::value, "not integral type"); + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } + }; + + template + using index_sequence = integer_sequence; + namespace detail_ { + template + struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)"); + + template + struct IntSeqCombiner; + + template + struct IntSeqCombiner, integer_sequence> { + using TResult = integer_sequence; + }; + + using TResult = + typename IntSeqCombiner::TResult, + typename IntSeqImpl::TResult>::TResult; + }; + + template + struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence; + }; + + template + struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence; + }; + } // namespace detail_ + + template + using make_integer_sequence = typename detail_::IntSeqImpl::TResult; + + template + using make_index_sequence = make_integer_sequence; + + template + using index_sequence_for = make_index_sequence; + + + #endif + +} // type_traits +} // jsoncons + +#endif diff --git a/include/jsoncons/pretty_print.hpp b/include/jsoncons/pretty_print.hpp new file mode 100644 index 0000000..599c1ce --- /dev/null +++ b/include/jsoncons/pretty_print.hpp @@ -0,0 +1,89 @@ +// 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_PRETTY_PRINT_HPP +#define JSONCONS_PRETTY_PRINT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +template +class json_printable +{ +public: + using char_type = typename Json::char_type; + + json_printable(const Json& j, indenting line_indent) + : j_(&j), indenting_(line_indent) + { + } + + json_printable(const Json& j, + const basic_json_encode_options& options, + indenting line_indent) + : j_(&j), options_(options), indenting_(line_indent) + { + } + + void dump(std::basic_ostream& os) const + { + j_->dump(os, options_, indenting_); + } + + friend std::basic_ostream& operator<<(std::basic_ostream& os, const json_printable& pr) + { + pr.dump(os); + return os; + } + + const Json *j_; + basic_json_encode_options options_; + indenting indenting_; +private: + json_printable(); +}; + +template +json_printable print(const Json& j) +{ + return json_printable(j, indenting::no_indent); +} + +template +json_printable print(const Json& j, + const basic_json_encode_options& options) +{ + return json_printable(j, options, indenting::no_indent); +} + +template +json_printable pretty_print(const Json& j) +{ + return json_printable(j, indenting::indent); +} + +template +json_printable pretty_print(const Json& j, + const basic_json_encode_options& options) +{ + return json_printable(j, options, indenting::indent); +} + +} + +#endif diff --git a/include/jsoncons/ser_context.hpp b/include/jsoncons/ser_context.hpp new file mode 100644 index 0000000..f5b9d14 --- /dev/null +++ b/include/jsoncons/ser_context.hpp @@ -0,0 +1,57 @@ +/// Copyright 2013-2018 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_SER_CONTEXT_HPP +#define JSONCONS_SER_CONTEXT_HPP + +namespace jsoncons { + +class ser_context +{ +public: + virtual ~ser_context() noexcept = default; + + virtual size_t line() const + { + return 0; + } + + virtual size_t column() const + { + return 0; + } + + virtual size_t position() const + { + return 0; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use line()") + std::size_t line_number() const + { + return line(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use column()") + std::size_t column_number() const + { + return column(); + } +#endif +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context null_ser_context; + +JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context parsing_context; +JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context serializing_context; +JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context null_parsing_context; +JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context null_serializing_context; +#endif + +} +#endif diff --git a/include/jsoncons/sink.hpp b/include/jsoncons/sink.hpp new file mode 100644 index 0000000..84771a3 --- /dev/null +++ b/include/jsoncons/sink.hpp @@ -0,0 +1,289 @@ +// Copyright 2018 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_SINK_HPP +#define JSONCONS_SINK_HPP + +#include +#include +#include +#include +#include +#include +#include // std::addressof +#include // std::memcpy +#include +#include + +namespace jsoncons { + + // stream_sink + + template + class stream_sink + { + public: + using value_type = CharT; + using container_type = std::basic_ostream; + + private: + static constexpr size_t default_buffer_length = 16384; + + std::basic_ostream* stream_ptr_; + std::vector buffer_; + CharT * begin_buffer_; + const CharT* end_buffer_; + CharT* p_; + + // Noncopyable + stream_sink(const stream_sink&) = delete; + stream_sink& operator=(const stream_sink&) = delete; + + public: + stream_sink(stream_sink&&) = default; + + stream_sink(std::basic_ostream& os) + : stream_ptr_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + stream_sink(std::basic_ostream& os, std::size_t buflen) + : stream_ptr_(std::addressof(os)), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + ~stream_sink() noexcept + { + stream_ptr_->write(begin_buffer_, buffer_length()); + stream_ptr_->flush(); + } + + // Movable + stream_sink& operator=(stream_sink&&) = default; + + void flush() + { + stream_ptr_->write(begin_buffer_, buffer_length()); + stream_ptr_->flush(); + p_ = buffer_.data(); + } + + void append(const CharT* s, std::size_t length) + { + std::size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(CharT)); + p_ += length; + } + else + { + stream_ptr_->write(begin_buffer_, buffer_length()); + stream_ptr_->write(s,length); + p_ = begin_buffer_; + } + } + + void push_back(CharT ch) + { + if (p_ < end_buffer_) + { + *p_++ = ch; + } + else + { + stream_ptr_->write(begin_buffer_, buffer_length()); + p_ = begin_buffer_; + push_back(ch); + } + } + private: + + std::size_t buffer_length() const + { + return p_ - begin_buffer_; + } + }; + + // binary_stream_sink + + class binary_stream_sink + { + public: + typedef uint8_t value_type; + using container_type = std::basic_ostream; + private: + static constexpr size_t default_buffer_length = 16384; + + std::basic_ostream* stream_ptr_; + std::vector buffer_; + uint8_t * begin_buffer_; + const uint8_t* end_buffer_; + uint8_t* p_; + + // Noncopyable + binary_stream_sink(const binary_stream_sink&) = delete; + binary_stream_sink& operator=(const binary_stream_sink&) = delete; + + public: + binary_stream_sink(binary_stream_sink&&) = default; + + binary_stream_sink(std::basic_ostream& os) + : stream_ptr_(std::addressof(os)), + buffer_(default_buffer_length), + begin_buffer_(buffer_.data()), + end_buffer_(begin_buffer_+buffer_.size()), + p_(begin_buffer_) + { + } + binary_stream_sink(std::basic_ostream& os, std::size_t buflen) + : stream_ptr_(std::addressof(os)), + buffer_(buflen), + begin_buffer_(buffer_.data()), + end_buffer_(begin_buffer_+buffer_.size()), + p_(begin_buffer_) + { + } + ~binary_stream_sink() noexcept + { + stream_ptr_->write((char*)begin_buffer_, buffer_length()); + stream_ptr_->flush(); + } + + binary_stream_sink& operator=(binary_stream_sink&&) = default; + + void flush() + { + stream_ptr_->write((char*)begin_buffer_, buffer_length()); + p_ = buffer_.data(); + } + + void append(const uint8_t* s, std::size_t length) + { + std::size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(uint8_t)); + p_ += length; + } + else + { + stream_ptr_->write((char*)begin_buffer_, buffer_length()); + stream_ptr_->write((const char*)s,length); + p_ = begin_buffer_; + } + } + + void push_back(uint8_t ch) + { + if (p_ < end_buffer_) + { + *p_++ = ch; + } + else + { + stream_ptr_->write((char*)begin_buffer_, buffer_length()); + p_ = begin_buffer_; + push_back(ch); + } + } + private: + + std::size_t buffer_length() const + { + return p_ - begin_buffer_; + } + }; + + // string_sink + + template + class string_sink + { + public: + using value_type = typename StringT::value_type; + using container_type = StringT; + private: + container_type* buf_ptr; + + // Noncopyable + string_sink(const string_sink&) = delete; + string_sink& operator=(const string_sink&) = delete; + public: + string_sink(string_sink&& val) noexcept + : buf_ptr(nullptr) + { + std::swap(buf_ptr,val.buf_ptr); + } + + string_sink(container_type& buf) + : buf_ptr(std::addressof(buf)) + { + } + + string_sink& operator=(string_sink&& val) noexcept + { + // TODO: Shouldn't val.buf_ptr be nullified? + // Also see move constructor above. + std::swap(buf_ptr,val.buf_ptr); + return *this; + } + + void flush() + { + } + + void append(const value_type* s, std::size_t length) + { + buf_ptr->insert(buf_ptr->end(), s, s+length); + } + + void push_back(value_type ch) + { + buf_ptr->push_back(ch); + } + }; + + // bytes_sink + + template + class bytes_sink + { + }; + + template + class bytes_sink::value>::type> + { + public: + using container_type = Container; + using value_type = typename Container::value_type; + private: + container_type* buf_ptr; + + // Noncopyable + bytes_sink(const bytes_sink&) = delete; + bytes_sink& operator=(const bytes_sink&) = delete; + public: + bytes_sink(bytes_sink&&) = default; + + bytes_sink(container_type& buf) + : buf_ptr(std::addressof(buf)) + { + } + + bytes_sink& operator=(bytes_sink&&) = default; + + void flush() + { + } + + void push_back(uint8_t ch) + { + buf_ptr->push_back(static_cast(ch)); + } + }; + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/source.hpp b/include/jsoncons/source.hpp new file mode 100644 index 0000000..e9c0735 --- /dev/null +++ b/include/jsoncons/source.hpp @@ -0,0 +1,777 @@ +// Copyright 2018 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_SOURCE_HPP +#define JSONCONS_SOURCE_HPP + +#include +#include +#include +#include +#include // std::addressof +#include // std::memcpy +#include +#include +#include // std::enable_if +#include +#include // jsoncons::byte_traits +#include + +namespace jsoncons { + + template + class basic_null_istream : public std::basic_istream + { + class null_buffer : public std::basic_streambuf + { + null_buffer(const null_buffer&) = delete; + null_buffer& operator=(const null_buffer&) = delete; + public: + using typename std::basic_streambuf::int_type; + using typename std::basic_streambuf::traits_type; + + null_buffer() = default; + null_buffer(null_buffer&&) = default; + null_buffer& operator=(null_buffer&&) = default; + + int_type overflow( int_type ch = typename std::basic_streambuf::traits_type::eof() ) override + { + return ch; + } + } nb_; + public: + basic_null_istream() + : std::basic_istream(&nb_) + { + } + + basic_null_istream(const null_buffer&) = delete; + basic_null_istream& operator=(const null_buffer&) = delete; + basic_null_istream(basic_null_istream&&) noexcept + : std::basic_istream(&nb_) + { + } + basic_null_istream& operator=(basic_null_istream&&) noexcept + { + return *this; + } + }; + + template + struct char_result + { + CharT value; + bool eof; + }; + + // text sources + + template + class stream_source + { + static constexpr std::size_t default_max_buffer_size = 16384; + public: + using value_type = CharT; + private: + using char_type = typename std::conditional::type; + basic_null_istream null_is_; + std::basic_istream* stream_ptr_; + std::basic_streambuf* sbuf_; + std::size_t position_; + std::vector buffer_; + const value_type* buffer_data_; + std::size_t buffer_length_; + + // Noncopyable + stream_source(const stream_source&) = delete; + stream_source& operator=(const stream_source&) = delete; + public: + stream_source() + : stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0), + buffer_(1), buffer_data_(buffer_.data()), buffer_length_(0) + { + } + + stream_source(std::basic_istream& is, std::size_t buf_size = default_max_buffer_size) + : stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()), position_(0), + buffer_(buf_size), buffer_data_(buffer_.data()), buffer_length_(0) + { + } + + stream_source(stream_source&& other) noexcept + : stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0), + buffer_(), buffer_data_(buffer_.data()), buffer_length_(0) + { + if (other.stream_ptr_ != &other.null_is_) + { + stream_ptr_ = other.stream_ptr_; + sbuf_ = other.sbuf_; + position_ = other.position_; + buffer_ = std::move(other.buffer_); + buffer_data_ = buffer_.data() + (other.buffer_data_ - other.buffer_.data()); + buffer_length_ = other.buffer_length_; + other = stream_source(); + } + } + + ~stream_source() + { + } + + stream_source& operator=(stream_source&& other) noexcept + { + if (other.stream_ptr_ != &other.null_is_) + { + stream_ptr_ = other.stream_ptr_; + sbuf_ = other.sbuf_; + position_ = other.position_; + buffer_ = std::move(other.buffer_); + buffer_data_ = buffer_.data() + (other.buffer_data_ - other.buffer_.data()); + buffer_length_ = other.buffer_length_; + other = stream_source(); + } + else + { + stream_ptr_ = &null_is_; + sbuf_ = null_is_.rdbuf(); + position_ = 0; + buffer_data_ = buffer_.data(); + buffer_length_ = 0; + } + return *this; + } + + bool eof() const + { + return buffer_length_ == 0 && stream_ptr_->eof(); + } + + bool is_error() const + { + return stream_ptr_->bad(); + } + + std::size_t position() const + { + return position_; + } + + void ignore(std::size_t length) + { + std::size_t len = 0; + if (buffer_length_ > 0) + { + len = (std::min)(buffer_length_, length); + position_ += len; + buffer_data_ += len; + buffer_length_ -= len; + } + while (length - len > 0) + { + fill_buffer(); + if (buffer_length_ == 0) + { + break; + } + std::size_t len2 = (std::min)(buffer_length_, length-len); + position_ += len2; + buffer_data_ += len2; + buffer_length_ -= len2; + len += len2; + } + } + + char_result peek() + { + if (buffer_length_ == 0) + { + fill_buffer(); + } + if (buffer_length_ > 0) + { + value_type c = *buffer_data_; + return char_result{c, false}; + } + else + { + return char_result{0, true}; + } + } + + span read_buffer() + { + if (buffer_length_ == 0) + { + fill_buffer(); + } + const value_type* data = buffer_data_; + std::size_t length = buffer_length_; + buffer_data_ += buffer_length_; + position_ += buffer_length_; + buffer_length_ = 0; + + return span(data, length); + } + + std::size_t read(value_type* p, std::size_t length) + { + std::size_t len = 0; + if (buffer_length_ > 0) + { + len = (std::min)(buffer_length_, length); + std::memcpy(p, buffer_data_, len*sizeof(value_type)); + buffer_data_ += len; + buffer_length_ -= len; + position_ += len; + } + if (length - len == 0) + { + return len; + } + else if (length - len < buffer_.size()) + { + fill_buffer(); + if (buffer_length_ > 0) + { + std::size_t len2 = (std::min)(buffer_length_, length-len); + std::memcpy(p+len, buffer_data_, len2*sizeof(value_type)); + buffer_data_ += len2; + buffer_length_ -= len2; + position_ += len2; + len += len2; + } + return len; + } + else + { + if (stream_ptr_->eof()) + { + buffer_length_ = 0; + return 0; + } + JSONCONS_TRY + { + std::streamsize count = sbuf_->sgetn(reinterpret_cast(p+len), length-len); + std::size_t len2 = static_cast(count); + if (len2 < length-len) + { + stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit); + } + len += len2; + position_ += len2; + return len; + } + JSONCONS_CATCH(const std::exception&) + { + stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit); + return 0; + } + } + } + private: + void fill_buffer() + { + if (stream_ptr_->eof()) + { + buffer_length_ = 0; + return; + } + + buffer_data_ = buffer_.data(); + JSONCONS_TRY + { + std::streamsize count = sbuf_->sgetn(reinterpret_cast(buffer_.data()), buffer_.size()); + buffer_length_ = static_cast(count); + + if (buffer_length_ < buffer_.size()) + { + stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit); + } + } + JSONCONS_CATCH(const std::exception&) + { + stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit); + buffer_length_ = 0; + } + } + }; + + // string_source + + template + class string_source + { + public: + using value_type = CharT; + using string_view_type = jsoncons::basic_string_view; + private: + const value_type* data_; + const value_type* current_; + const value_type* end_; + + // Noncopyable + string_source(const string_source&) = delete; + string_source& operator=(const string_source&) = delete; + public: + string_source() + : data_(nullptr), current_(nullptr), end_(nullptr) + { + } + + template + string_source(const Sourceable& s, + typename std::enable_if::value>::type* = 0) + : data_(s.data()), current_(s.data()), end_(s.data()+s.size()) + { + } + + string_source(const value_type* data) + : data_(data), current_(data), end_(data+std::char_traits::length(data)) + { + } + + string_source(string_source&& val) = default; + + string_source& operator=(string_source&& val) = default; + + bool eof() const + { + return current_ == end_; + } + + bool is_error() const + { + return false; + } + + std::size_t position() const + { + return (current_ - data_)/sizeof(value_type); + } + + void ignore(std::size_t count) + { + std::size_t len; + if ((std::size_t)(end_ - current_) < count) + { + len = end_ - current_; + } + else + { + len = count; + } + current_ += len; + } + + char_result peek() + { + return current_ < end_ ? char_result{*current_, false} : char_result{0, true}; + } + + span read_buffer() + { + const value_type* data = current_; + std::size_t length = end_ - current_; + current_ = end_; + + return span(data, length); + } + + std::size_t read(value_type* p, std::size_t length) + { + std::size_t len; + if ((std::size_t)(end_ - current_) < length) + { + len = end_ - current_; + } + else + { + len = length; + } + std::memcpy(p, current_, len*sizeof(value_type)); + current_ += len; + return len; + } + }; + + // iterator source + + template + class iterator_source + { + public: + using value_type = typename std::iterator_traits::value_type; + private: + static constexpr std::size_t default_max_buffer_size = 16384; + + IteratorT current_; + IteratorT end_; + std::size_t position_; + std::vector buffer_; + std::size_t buffer_length_; + + using difference_type = typename std::iterator_traits::difference_type; + using iterator_category = typename std::iterator_traits::iterator_category; + + // Noncopyable + iterator_source(const iterator_source&) = delete; + iterator_source& operator=(const iterator_source&) = delete; + public: + + iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_buffer_size) + : current_(first), end_(last), position_(0), buffer_(buf_size), buffer_length_(0) + { + } + + iterator_source(iterator_source&& other) = default; + + iterator_source& operator=(iterator_source&& other) = default; + + bool eof() const + { + return !(current_ != end_); + } + + bool is_error() const + { + return false; + } + + std::size_t position() const + { + return position_; + } + + void ignore(std::size_t count) + { + while (count-- > 0 && current_ != end_) + { + ++position_; + ++current_; + } + } + + char_result peek() + { + return current_ != end_ ? char_result{*current_, false} : char_result{0, true}; + } + + span read_buffer() + { + if (buffer_length_ == 0) + { + buffer_length_ = read(buffer_.data(), buffer_.size()); + } + std::size_t length = buffer_length_; + buffer_length_ = 0; + + return span(buffer_.data(), length); + } + + template + typename std::enable_if::value, std::size_t>::type + read(value_type* data, std::size_t length) + { + std::size_t count = (std::min)(length, static_cast(std::distance(current_, end_))); + + JSONCONS_COPY(current_, current_ + count, data); + current_ += count; + position_ += count; + + return count; + } + + template + typename std::enable_if::value, std::size_t>::type + read(value_type* data, std::size_t length) + { + value_type* p = data; + value_type* pend = data + length; + + while (p < pend && current_ != end_) + { + *p = static_cast(*current_); + ++p; + ++current_; + } + + position_ += (p - data); + + return p - data; + } + }; + + // binary sources + + using binary_stream_source = stream_source; + + class bytes_source + { + public: + typedef uint8_t value_type; + private: + const value_type* data_; + const value_type* current_; + const value_type* end_; + + // Noncopyable + bytes_source(const bytes_source&) = delete; + bytes_source& operator=(const bytes_source&) = delete; + public: + bytes_source() + : data_(nullptr), current_(nullptr), end_(nullptr) + { + } + + template + bytes_source(const Sourceable& source, + typename std::enable_if::value,int>::type = 0) + : data_(reinterpret_cast(source.data())), + current_(data_), + end_(data_+source.size()) + { + } + + bytes_source(bytes_source&&) = default; + + bytes_source& operator=(bytes_source&&) = default; + + bool eof() const + { + return current_ == end_; + } + + bool is_error() const + { + return false; + } + + std::size_t position() const + { + return current_ - data_; + } + + void ignore(std::size_t count) + { + std::size_t len; + if ((std::size_t)(end_ - current_) < count) + { + len = end_ - current_; + } + else + { + len = count; + } + current_ += len; + } + + char_result peek() + { + return current_ < end_ ? char_result{*current_, false} : char_result{0, true}; + } + + span read_buffer() + { + const value_type* data = current_; + std::size_t length = end_ - current_; + current_ = end_; + + return span(data, length); + } + + std::size_t read(value_type* p, std::size_t length) + { + std::size_t len; + if ((std::size_t)(end_ - current_) < length) + { + len = end_ - current_; + } + else + { + len = length; + } + std::memcpy(p, current_, len*sizeof(value_type)); + current_ += len; + return len; + } + }; + + // binary_iterator source + + template + class binary_iterator_source + { + public: + using value_type = uint8_t; + private: + static constexpr std::size_t default_max_buffer_size = 16384; + + IteratorT current_; + IteratorT end_; + std::size_t position_; + std::vector buffer_; + std::size_t buffer_length_; + + using difference_type = typename std::iterator_traits::difference_type; + using iterator_category = typename std::iterator_traits::iterator_category; + + // Noncopyable + binary_iterator_source(const binary_iterator_source&) = delete; + binary_iterator_source& operator=(const binary_iterator_source&) = delete; + public: + binary_iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_buffer_size) + : current_(first), end_(last), position_(0), buffer_(buf_size), buffer_length_(0) + { + } + + binary_iterator_source(binary_iterator_source&& other) = default; + + binary_iterator_source& operator=(binary_iterator_source&& other) = default; + + bool eof() const + { + return !(current_ != end_); + } + + bool is_error() const + { + return false; + } + + std::size_t position() const + { + return position_; + } + + void ignore(std::size_t count) + { + while (count-- > 0 && current_ != end_) + { + ++position_; + ++current_; + } + } + + char_result peek() + { + return current_ != end_ ? char_result{static_cast(*current_), false} : char_result{0, true}; + } + + span read_buffer() + { + if (buffer_length_ == 0) + { + buffer_length_ = read(buffer_.data(), buffer_.size()); + } + std::size_t length = buffer_length_; + buffer_length_ = 0; + + return span(buffer_.data(), length); + } + + template + typename std::enable_if::value, std::size_t>::type + read(value_type* data, std::size_t length) + { + std::size_t count = (std::min)(length, static_cast(std::distance(current_, end_))); + JSONCONS_COPY(current_, current_ + count, data); + current_ += count; + position_ += count; + + return count; + } + + template + typename std::enable_if::value, std::size_t>::type + read(value_type* data, std::size_t length) + { + value_type* p = data; + value_type* pend = data + length; + + while (p < pend && current_ != end_) + { + *p = static_cast(*current_); + ++p; + ++current_; + } + + position_ += (p - data); + + return p - data; + } + }; + + template + struct source_reader + { + using value_type = typename Source::value_type; + static constexpr std::size_t max_buffer_length = 16384; + + template + static + typename std::enable_if::value && + type_traits::has_reserve::value && + type_traits::has_data_exact::value + , std::size_t>::type + read(Source& source, Container& v, std::size_t length) + { + std::size_t unread = length; + + std::size_t n = (std::min)(max_buffer_length, unread); + while (n > 0 && !source.eof()) + { + std::size_t offset = v.size(); + v.resize(v.size()+n); + std::size_t actual = source.read(v.data()+offset, n); + unread -= actual; + n = (std::min)(max_buffer_length, unread); + } + + return length - unread; + } + + template + static + typename std::enable_if::value && + type_traits::has_reserve::value && + !type_traits::has_data_exact::value + , std::size_t>::type + read(Source& source, Container& v, std::size_t length) + { + std::size_t unread = length; + + std::size_t n = (std::min)(max_buffer_length, unread); + while (n > 0 && !source.eof()) + { + v.reserve(v.size()+n); + std::size_t actual = 0; + while (actual < n) + { + typename Source::value_type c; + if (source.read(&c,1) != 1) + { + break; + } + v.push_back(c); + ++actual; + } + unread -= actual; + n = (std::min)(max_buffer_length, unread); + } + + return length - unread; + } + }; + template + constexpr std::size_t source_reader::max_buffer_length; + + #if !defined(JSONCONS_NO_DEPRECATED) + using bin_stream_source = binary_stream_source; + #endif + +} // namespace jsoncons + +#endif diff --git a/include/jsoncons/source_adaptor.hpp b/include/jsoncons/source_adaptor.hpp new file mode 100644 index 0000000..51c74a3 --- /dev/null +++ b/include/jsoncons/source_adaptor.hpp @@ -0,0 +1,148 @@ +// Copyright 2021 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_BUFFER_READER_HPP +#define JSONCONS_BUFFER_READER_HPP + +#include +#include +#include +#include +#include +#include // std::allocator_traits +#include // std::vector +#include +#include // json_errc +#include +#include + +namespace jsoncons { + + // text_source_adaptor + + template + class text_source_adaptor + { + public: + using value_type = typename Source::value_type; + private: + Source source_; + bool bof_; + + public: + text_source_adaptor() + : bof_(true) + { + } + + template + text_source_adaptor(Sourceable&& source) + : source_(std::forward(source)), bof_(true) + { + } + + bool eof() const + { + return source_.eof(); + } + + bool is_error() const + { + return source_.is_error(); + } + + span read_buffer(std::error_code& ec) + { + if (source_.eof()) + { + return span(); + } + + auto s = source_.read_buffer(); + const value_type* data = s.data(); + std::size_t length = s.size(); + + if (bof_ && length > 0) + { + auto r = unicode_traits::detect_encoding_from_bom(data, length); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + ec = json_errc::illegal_unicode_character; + return span(); + } + length -= (r.ptr - data); + data = r.ptr; + bof_ = false; + } + return span(data, length); + } + }; + + // json_source_adaptor + + template + class json_source_adaptor + { + public: + using value_type = typename Source::value_type; + private: + Source source_; + bool bof_; + + public: + json_source_adaptor() + : bof_(true) + { + } + + template + json_source_adaptor(Sourceable&& source) + : source_(std::forward(source)), bof_(true) + { + } + + bool eof() const + { + return source_.eof(); + } + + bool is_error() const + { + return source_.is_error(); + } + + span read_buffer(std::error_code& ec) + { + if (source_.eof()) + { + return span(); + } + + auto s = source_.read_buffer(); + const value_type* data = s.data(); + std::size_t length = s.size(); + + if (bof_ && length > 0) + { + auto r = unicode_traits::detect_json_encoding(data, length); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + ec = json_errc::illegal_unicode_character; + return span(); + } + length -= (r.ptr - data); + data = r.ptr; + bof_ = false; + } + + return span(data, length); + } + }; + +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons/staj2_cursor.hpp b/include/jsoncons/staj2_cursor.hpp new file mode 100644 index 0000000..4cbbc2f --- /dev/null +++ b/include/jsoncons/staj2_cursor.hpp @@ -0,0 +1,1178 @@ +// Copyright 2018 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_STAJ2_CURSOR_HPP +#define JSONCONS_STAJ2_CURSOR_HPP + +#include // std::allocator +#include +#include +#include +#include +#include // std::enable_if +#include // std::array +#include // std::function +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + enum class staj2_event_type + { + begin_array, + end_array, + begin_object, + end_object, + string_value, + byte_string_value, + null_value, + bool_value, + int64_value, + uint64_value, + half_value, + double_value + }; + + template + std::basic_ostream& operator<<(std::basic_ostream& os, staj2_event_type tag) + { + static constexpr const CharT* begin_array_name = JSONCONS_CSTRING_CONSTANT(CharT, "begin_array"); + static constexpr const CharT* end_array_name = JSONCONS_CSTRING_CONSTANT(CharT, "end_array"); + static constexpr const CharT* begin_object_name = JSONCONS_CSTRING_CONSTANT(CharT, "begin_object"); + static constexpr const CharT* end_object_name = JSONCONS_CSTRING_CONSTANT(CharT, "end_object"); + static constexpr const CharT* string_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "string_value"); + static constexpr const CharT* byte_string_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string_value"); + static constexpr const CharT* null_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "null_value"); + static constexpr const CharT* bool_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "bool_value"); + static constexpr const CharT* uint64_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "uint64_value"); + static constexpr const CharT* int64_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "int64_value"); + static constexpr const CharT* half_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "half_value"); + static constexpr const CharT* double_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "double_value"); + + switch (tag) + { + case staj2_event_type::begin_array: + { + os << begin_array_name; + break; + } + case staj2_event_type::end_array: + { + os << end_array_name; + break; + } + case staj2_event_type::begin_object: + { + os << begin_object_name; + break; + } + case staj2_event_type::end_object: + { + os << end_object_name; + break; + } + case staj2_event_type::string_value: + { + os << string_value_name; + break; + } + case staj2_event_type::byte_string_value: + { + os << byte_string_value_name; + break; + } + case staj2_event_type::null_value: + { + os << null_value_name; + break; + } + case staj2_event_type::bool_value: + { + os << bool_value_name; + break; + } + case staj2_event_type::int64_value: + { + os << int64_value_name; + break; + } + case staj2_event_type::uint64_value: + { + os << uint64_value_name; + break; + } + case staj2_event_type::half_value: + { + os << half_value_name; + break; + } + case staj2_event_type::double_value: + { + os << double_value_name; + break; + } + } + return os; + } + + template + class basic_staj2_event + { + staj2_event_type event_type_; + semantic_tag tag_; + uint64_t ext_tag_; + union + { + bool bool_value_; + int64_t int64_value_; + uint64_t uint64_value_; + uint16_t half_value_; + double double_value_; + const CharT* string_data_; + const uint8_t* byte_string_data_; + } value_; + std::size_t length_; + public: + using string_view_type = jsoncons::basic_string_view; + + basic_staj2_event(staj2_event_type event_type, semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), value_(), length_(0) + { + } + + basic_staj2_event(staj2_event_type event_type, std::size_t length, semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), value_(), length_(length) + { + } + + basic_staj2_event(null_type, semantic_tag tag) + : event_type_(staj2_event_type::null_value), tag_(tag), ext_tag_(0), value_(), length_(0) + { + } + + basic_staj2_event(bool value, semantic_tag tag) + : event_type_(staj2_event_type::bool_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.bool_value_ = value; + } + + basic_staj2_event(int64_t value, semantic_tag tag) + : event_type_(staj2_event_type::int64_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.int64_value_ = value; + } + + basic_staj2_event(uint64_t value, semantic_tag tag) + : event_type_(staj2_event_type::uint64_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.uint64_value_ = value; + } + + basic_staj2_event(half_arg_t, uint16_t value, semantic_tag tag) + : event_type_(staj2_event_type::half_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.half_value_ = value; + } + + basic_staj2_event(double value, semantic_tag tag) + : event_type_(staj2_event_type::double_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.double_value_ = value; + } + + basic_staj2_event(const string_view_type& s, + staj2_event_type event_type, + semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), length_(s.length()) + { + value_.string_data_ = s.data(); + } + + basic_staj2_event(const byte_string_view& s, + staj2_event_type event_type, + semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), length_(s.size()) + { + value_.byte_string_data_ = s.data(); + } + + basic_staj2_event(const byte_string_view& s, + staj2_event_type event_type, + uint64_t ext_tag) + : event_type_(event_type), tag_(semantic_tag::ext), ext_tag_(ext_tag), length_(s.size()) + { + value_.byte_string_data_ = s.data(); + } + + std::size_t size() const + { + return length_; + } + + template + T get() const + { + std::error_code ec; + T val = get(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + return val; + } + + template + typename std::enable_if::value && std::is_same::value, T>::type + get(std::error_code& ec) const + { + converter conv; + switch (event_type_) + { + case staj2_event_type::string_value: + return conv.from(jsoncons::basic_string_view(value_.string_data_, length_), tag(), ec); + case staj2_event_type::byte_string_value: + { + return conv.from(byte_string_view(value_.byte_string_data_,length_), + tag(), + ec); + } + case staj2_event_type::uint64_value: + { + return conv.from(value_.uint64_value_, tag(), ec); + } + case staj2_event_type::int64_value: + { + return conv.from(value_.int64_value_, tag(), ec); + } + case staj2_event_type::half_value: + { + return conv.from(half_arg, value_.half_value_, tag(), ec); + } + case staj2_event_type::double_value: + { + return conv.from(value_.double_value_, tag(), ec); + } + case staj2_event_type::bool_value: + { + return conv.from(value_.bool_value_,tag(),ec); + } + case staj2_event_type::null_value: + { + return conv.from(null_type(),tag(),ec); + } + default: + { + ec = conv_errc::not_string; + return T{}; + } + } + } + + template + typename std::enable_if::value && std::is_same::value, T>::type + get(std::error_code& ec) const + { + T s; + switch (event_type_) + { + case staj2_event_type::string_value: + s = T(value_.string_data_, length_); + break; + default: + ec = conv_errc::not_string_view; + break; + } + return s; + } + + template + typename std::enable_if::value, T>::type + get(std::error_code& ec) const + { + T s; + switch (event_type_) + { + case staj2_event_type::byte_string_value: + s = T(value_.byte_string_data_, length_); + break; + default: + ec = conv_errc::not_byte_string_view; + break; + } + return s; + } + + template + typename std::enable_if::value && + std::is_same::value,T>::type + get(std::error_code& ec) const + { + converter conv; + switch (event_type_) + { + case staj2_event_type::byte_string_value: + return conv.from(byte_string_view(value_.byte_string_data_, length_), tag(), ec); + case staj2_event_type::string_value: + return conv.from(jsoncons::basic_string_view(value_.string_data_, length_), tag(), ec); + default: + ec = conv_errc::not_byte_string; + return T{}; + } + } + + template + typename std::enable_if::value, IntegerType>::type + get(std::error_code& ec) const + { + switch (event_type_) + { + case staj2_event_type::string_value: + { + IntegerType val; + auto result = jsoncons::detail::to_integer(value_.string_data_, length_, val); + if (!result) + { + ec = conv_errc::not_integer; + return IntegerType(); + } + return val; + } + case staj2_event_type::half_value: + return static_cast(value_.half_value_); + case staj2_event_type::double_value: + return static_cast(value_.double_value_); + case staj2_event_type::int64_value: + return static_cast(value_.int64_value_); + case staj2_event_type::uint64_value: + return static_cast(value_.uint64_value_); + case staj2_event_type::bool_value: + return static_cast(value_.bool_value_ ? 1 : 0); + default: + ec = conv_errc::not_integer; + return IntegerType(); + } + } + + template + typename std::enable_if::value, T>::type + get(std::error_code& ec) const + { + return static_cast(as_double(ec)); + } + + template + typename std::enable_if::value, T>::type + get(std::error_code& ec) const + { + return as_bool(ec); + } + + staj2_event_type event_type() const noexcept { return event_type_; } + + semantic_tag tag() const noexcept { return tag_; } + + uint64_t ext_tag() const noexcept { return ext_tag_; } + + private: + + double as_double(std::error_code& ec) const + { + switch (event_type_) + { + case staj2_event_type::string_value: + { + jsoncons::detail::chars_to f; + return f(value_.string_data_, length_); + } + case staj2_event_type::double_value: + return value_.double_value_; + case staj2_event_type::int64_value: + return static_cast(value_.int64_value_); + case staj2_event_type::uint64_value: + return static_cast(value_.uint64_value_); + case staj2_event_type::half_value: + { + double x = binary::decode_half(value_.half_value_); + return static_cast(x); + } + default: + ec = conv_errc::not_double; + return double(); + } + } + + bool as_bool(std::error_code& ec) const + { + switch (event_type_) + { + case staj2_event_type::bool_value: + return value_.bool_value_; + case staj2_event_type::double_value: + return value_.double_value_ != 0.0; + case staj2_event_type::int64_value: + return value_.int64_value_ != 0; + case staj2_event_type::uint64_value: + return value_.uint64_value_ != 0; + default: + ec = conv_errc::not_bool; + return bool(); + } + } + }; + + // basic_staj2_visitor + + enum class staj2_cursor_state + { + typed_array = 1, + multi_dim, + shape + }; + + template + class basic_staj2_visitor : public basic_json_visitor2 + { + using super_type = basic_json_visitor2; + public: + using char_type = CharT; + using typename super_type::string_view_type; + private: + std::function&, const ser_context&)> pred_; + basic_staj2_event event_; + + staj2_cursor_state state_; + typed_array_view data_; + jsoncons::span shape_; + std::size_t index_; + public: + basic_staj2_visitor() + : pred_(accept), event_(staj2_event_type::null_value), + state_(), data_(), shape_(), index_(0) + { + } + + basic_staj2_visitor(std::function&, const ser_context&)> pred) + : pred_(pred), event_(staj2_event_type::null_value), + state_(), data_(), shape_(), index_(0) + { + } + + void reset() + { + event_ = staj2_event_type::null_value; + state_ = {}; + data_ = {}; + shape_ = {}; + index_ = 0; + } + + const basic_staj2_event& event() const + { + return event_; + } + + bool in_available() const + { + return state_ != staj2_cursor_state(); + } + + void send_available(std::error_code& ec) + { + switch (state_) + { + case staj2_cursor_state::typed_array: + advance_typed_array(ec); + break; + case staj2_cursor_state::multi_dim: + case staj2_cursor_state::shape: + advance_multi_dim(ec); + break; + default: + break; + } + } + + bool is_typed_array() const + { + return data_.type() != typed_array_type(); + } + + staj2_cursor_state state() const + { + return state_; + } + + void advance_typed_array(std::error_code& ec) + { + if (is_typed_array()) + { + if (index_ < data_.size()) + { + switch (data_.type()) + { + case typed_array_type::uint8_value: + { + this->uint64_value(data_.data(uint8_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::uint16_value: + { + this->uint64_value(data_.data(uint16_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::uint32_value: + { + this->uint64_value(data_.data(uint32_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::uint64_value: + { + this->uint64_value(data_.data(uint64_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int8_value: + { + this->int64_value(data_.data(int8_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int16_value: + { + this->int64_value(data_.data(int16_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int32_value: + { + this->int64_value(data_.data(int32_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int64_value: + { + this->int64_value(data_.data(int64_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::half_value: + { + this->half_value(data_.data(half_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::float_value: + { + this->double_value(data_.data(float_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::double_value: + { + this->double_value(data_.data(double_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + default: + break; + } + ++index_; + } + else + { + this->end_array(); + state_ = staj2_cursor_state(); + data_ = typed_array_view(); + index_ = 0; + } + } + } + + void advance_multi_dim(std::error_code& ec) + { + if (shape_.size() != 0) + { + if (state_ == staj2_cursor_state::multi_dim) + { + this->begin_array(shape_.size(), semantic_tag::none, ser_context(), ec); + state_ = staj2_cursor_state::shape; + } + else if (index_ < shape_.size()) + { + this->uint64_value(shape_[index_], semantic_tag::none, ser_context(), ec); + ++index_; + } + else + { + state_ = staj2_cursor_state(); + this->end_array(ser_context(), ec); + shape_ = jsoncons::span(); + index_ = 0; + } + } + } + + bool dump(basic_json_visitor2& visitor, const ser_context& context, std::error_code& ec) + { + bool more = true; + if (is_typed_array()) + { + if (index_ != 0) + { + more = staj2_to_saj_event(event(), visitor, context, ec); + while (more && is_typed_array()) + { + if (index_ < data_.size()) + { + switch (data_.type()) + { + case typed_array_type::uint8_value: + { + more = visitor.uint64_value(data_.data(uint8_array_arg)[index_]); + break; + } + case typed_array_type::uint16_value: + { + more = visitor.uint64_value(data_.data(uint16_array_arg)[index_]); + break; + } + case typed_array_type::uint32_value: + { + more = visitor.uint64_value(data_.data(uint32_array_arg)[index_]); + break; + } + case typed_array_type::uint64_value: + { + more = visitor.uint64_value(data_.data(uint64_array_arg)[index_]); + break; + } + case typed_array_type::int8_value: + { + more = visitor.int64_value(data_.data(int8_array_arg)[index_]); + break; + } + case typed_array_type::int16_value: + { + more = visitor.int64_value(data_.data(int16_array_arg)[index_]); + break; + } + case typed_array_type::int32_value: + { + more = visitor.int64_value(data_.data(int32_array_arg)[index_]); + break; + } + case typed_array_type::int64_value: + { + more = visitor.int64_value(data_.data(int64_array_arg)[index_]); + break; + } + case typed_array_type::float_value: + { + more = visitor.double_value(data_.data(float_array_arg)[index_]); + break; + } + case typed_array_type::double_value: + { + more = visitor.double_value(data_.data(double_array_arg)[index_]); + break; + } + default: + break; + } + ++index_; + } + else + { + more = visitor.end_array(); + state_ = staj2_cursor_state(); + data_ = typed_array_view(); + index_ = 0; + } + } + } + else + { + switch (data_.type()) + { + case typed_array_type::uint8_value: + { + more = visitor.typed_array(data_.data(uint8_array_arg)); + break; + } + case typed_array_type::uint16_value: + { + more = visitor.typed_array(data_.data(uint16_array_arg)); + break; + } + case typed_array_type::uint32_value: + { + more = visitor.typed_array(data_.data(uint32_array_arg)); + break; + } + case typed_array_type::uint64_value: + { + more = visitor.typed_array(data_.data(uint64_array_arg)); + break; + } + case typed_array_type::int8_value: + { + more = visitor.typed_array(data_.data(int8_array_arg)); + break; + } + case typed_array_type::int16_value: + { + more = visitor.typed_array(data_.data(int16_array_arg)); + break; + } + case typed_array_type::int32_value: + { + more = visitor.typed_array(data_.data(int32_array_arg)); + break; + } + case typed_array_type::int64_value: + { + more = visitor.typed_array(data_.data(int64_array_arg)); + break; + } + case typed_array_type::float_value: + { + more = visitor.typed_array(data_.data(float_array_arg)); + break; + } + case typed_array_type::double_value: + { + more = visitor.typed_array(data_.data(double_array_arg)); + break; + } + default: + break; + } + + state_ = staj2_cursor_state(); + data_ = typed_array_view(); + } + } + else + { + more = staj2_to_saj_event(event(), visitor, context, ec); + } + return more; + } + + private: + static constexpr bool accept(const basic_staj2_event&, const ser_context&) + { + return true; + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::begin_object, tag); + return !pred_(event_, context); + } + + bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::begin_object, length, tag); + return !pred_(event_, context); + } + + bool visit_end_object(const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::end_object); + return !pred_(event_, context); + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::begin_array, tag); + return !pred_(event_, context); + } + + bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::begin_array, length, tag); + return !pred_(event_, context); + } + + bool visit_end_array(const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::end_array); + return !pred_(event_, context); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(staj2_event_type::null_value, tag); + return !pred_(event_, context); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(value, tag); + return !pred_(event_, context); + } + + bool visit_string(const string_view_type& s, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj2_event(s, staj2_event_type::string_value, tag); + return !pred_(event_, context); + } + + bool visit_byte_string(const byte_string_view& s, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj2_event(s, staj2_event_type::byte_string_value, tag); + return !pred_(event_, context); + } + + bool visit_byte_string(const byte_string_view& s, + uint64_t ext_tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj2_event(s, staj2_event_type::byte_string_value, ext_tag); + return !pred_(event_, context); + } + + bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj2_event(value, tag); + return !pred_(event_, context); + } + + bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj2_event(value, tag); + return !pred_(event_, context); + } + + bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj2_event(half_arg, value, tag); + return !pred_(event_, context); + } + + bool visit_double(double value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj2_event(value, tag); + return !pred_(event_, context); + } + + bool visit_typed_array(const jsoncons::span& v, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(v.data(), v.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(half_arg_t, const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + /* + bool visit_typed_array(const jsoncons::span&, + semantic_tag, + const ser_context&, + std::error_code&) override + { + return true; + } + */ + bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj2_cursor_state::multi_dim; + shape_ = shape; + return this->begin_array(2, tag, context, ec); + } + + bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) override + { + return this->end_array(context, ec); + } + + void visit_flush() override + { + } + }; + + template + bool staj2_to_saj_event(const basic_staj2_event& ev, + basic_json_visitor2& visitor, + const ser_context& context, + std::error_code& ec) + { + switch (ev.event_type()) + { + case staj2_event_type::begin_array: + return visitor.begin_array(ev.tag(), context); + case staj2_event_type::end_array: + return visitor.end_array(context); + case staj2_event_type::begin_object: + return visitor.begin_object(ev.tag(), context, ec); + case staj2_event_type::end_object: + return visitor.end_object(context, ec); + case staj2_event_type::string_value: + return visitor.string_value(ev.template get>(), ev.tag(), context); + case staj2_event_type::byte_string_value: + return visitor.byte_string_value(ev.template get(), ev.tag(), context); + case staj2_event_type::null_value: + return visitor.null_value(ev.tag(), context); + case staj2_event_type::bool_value: + return visitor.bool_value(ev.template get(), ev.tag(), context); + case staj2_event_type::int64_value: + return visitor.int64_value(ev.template get(), ev.tag(), context); + case staj2_event_type::uint64_value: + return visitor.uint64_value(ev.template get(), ev.tag(), context); + case staj2_event_type::half_value: + return visitor.half_value(ev.template get(), ev.tag(), context); + case staj2_event_type::double_value: + return visitor.double_value(ev.template get(), ev.tag(), context); + default: + return false; + } + } + + // basic_staj2_cursor + + template + class basic_staj2_cursor + { + public: + virtual ~basic_staj2_cursor() noexcept = default; + + virtual void array_expected(std::error_code& ec) + { + if (!(current().event_type() == staj2_event_type::begin_array || current().event_type() == staj2_event_type::byte_string_value)) + { + ec = conv_errc::not_vector; + } + } + + virtual bool done() const = 0; + + virtual const basic_staj2_event& current() const = 0; + + virtual void read_to(basic_json_visitor2& visitor) = 0; + + virtual void read_to(basic_json_visitor2& visitor, + std::error_code& ec) = 0; + + virtual void next() = 0; + + virtual void next(std::error_code& ec) = 0; + + virtual const ser_context& context() const = 0; + }; + + template + class basic_staj2_filter_view : basic_staj2_cursor + { + basic_staj2_cursor* cursor_; + std::function&, const ser_context&)> pred_; + public: + basic_staj2_filter_view(basic_staj2_cursor& cursor, + std::function&, const ser_context&)> pred) + : cursor_(std::addressof(cursor)), pred_(pred) + { + while (!done() && !pred_(current(),context())) + { + cursor_->next(); + } + } + + bool done() const override + { + return cursor_->done(); + } + + const basic_staj2_event& current() const override + { + return cursor_->current(); + } + + void read_to(basic_json_visitor2& visitor) override + { + cursor_->read_to(visitor); + } + + void read_to(basic_json_visitor2& visitor, + std::error_code& ec) override + { + cursor_->read_to(visitor, ec); + } + + void next() override + { + cursor_->next(); + while (!done() && !pred_(current(),context())) + { + cursor_->next(); + } + } + + void next(std::error_code& ec) override + { + cursor_->next(ec); + while (!done() && !pred_(current(),context()) && !ec) + { + cursor_->next(ec); + } + } + + const ser_context& context() const override + { + return cursor_->context(); + } + + friend + basic_staj2_filter_view operator|(basic_staj2_filter_view& cursor, + std::function&, const ser_context&)> pred) + { + return basic_staj2_filter_view(cursor, pred); + } + }; + + using staj2_event = basic_staj2_event; + using wstaj2_event = basic_staj2_event; + + using staj2_cursor = basic_staj2_cursor; + using wstaj2_cursor = basic_staj2_cursor; + + using staj2_filter_view = basic_staj2_filter_view; + using wstaj2_filter_view = basic_staj2_filter_view; + +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons/staj_cursor.hpp b/include/jsoncons/staj_cursor.hpp new file mode 100644 index 0000000..4594ba1 --- /dev/null +++ b/include/jsoncons/staj_cursor.hpp @@ -0,0 +1,1233 @@ +// Copyright 2018 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_STAJ_CURSOR_HPP +#define JSONCONS_STAJ_CURSOR_HPP + +#include // std::allocator +#include +#include +#include +#include +#include // std::enable_if +#include // std::array +#include // std::function +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + +enum class staj_event_type +{ + begin_array, + end_array, + begin_object, + end_object, + key, + string_value, + byte_string_value, + null_value, + bool_value, + int64_value, + uint64_value, + half_value, + double_value +#if !defined(JSONCONS_NO_DEPRECATED) + ,name = key +#endif +}; + +template +std::basic_ostream& operator<<(std::basic_ostream& os, staj_event_type tag) +{ + static constexpr const CharT* begin_array_name = JSONCONS_CSTRING_CONSTANT(CharT, "begin_array"); + static constexpr const CharT* end_array_name = JSONCONS_CSTRING_CONSTANT(CharT, "end_array"); + static constexpr const CharT* begin_object_name = JSONCONS_CSTRING_CONSTANT(CharT, "begin_object"); + static constexpr const CharT* end_object_name = JSONCONS_CSTRING_CONSTANT(CharT, "end_object"); + static constexpr const CharT* key_name = JSONCONS_CSTRING_CONSTANT(CharT, "key"); + static constexpr const CharT* string_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "string_value"); + static constexpr const CharT* byte_string_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string_value"); + static constexpr const CharT* null_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "null_value"); + static constexpr const CharT* bool_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "bool_value"); + static constexpr const CharT* uint64_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "uint64_value"); + static constexpr const CharT* int64_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "int64_value"); + static constexpr const CharT* half_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "half_value"); + static constexpr const CharT* double_value_name = JSONCONS_CSTRING_CONSTANT(CharT, "double_value"); + + switch (tag) + { + case staj_event_type::begin_array: + { + os << begin_array_name; + break; + } + case staj_event_type::end_array: + { + os << end_array_name; + break; + } + case staj_event_type::begin_object: + { + os << begin_object_name; + break; + } + case staj_event_type::end_object: + { + os << end_object_name; + break; + } + case staj_event_type::key: + { + os << key_name; + break; + } + case staj_event_type::string_value: + { + os << string_value_name; + break; + } + case staj_event_type::byte_string_value: + { + os << byte_string_value_name; + break; + } + case staj_event_type::null_value: + { + os << null_value_name; + break; + } + case staj_event_type::bool_value: + { + os << bool_value_name; + break; + } + case staj_event_type::int64_value: + { + os << int64_value_name; + break; + } + case staj_event_type::uint64_value: + { + os << uint64_value_name; + break; + } + case staj_event_type::half_value: + { + os << half_value_name; + break; + } + case staj_event_type::double_value: + { + os << double_value_name; + break; + } + } + return os; +} + +template +class basic_staj_event +{ + staj_event_type event_type_; + semantic_tag tag_; + uint64_t ext_tag_; + union + { + bool bool_value_; + int64_t int64_value_; + uint64_t uint64_value_; + uint16_t half_value_; + double double_value_; + const CharT* string_data_; + const uint8_t* byte_string_data_; + } value_; + std::size_t length_; +public: + using string_view_type = jsoncons::basic_string_view; + + basic_staj_event(staj_event_type event_type, semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), value_(), length_(0) + { + } + + basic_staj_event(staj_event_type event_type, std::size_t length, semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), value_(), length_(length) + { + } + + basic_staj_event(null_type, semantic_tag tag) + : event_type_(staj_event_type::null_value), tag_(tag), ext_tag_(0), value_(), length_(0) + { + } + + basic_staj_event(bool value, semantic_tag tag) + : event_type_(staj_event_type::bool_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.bool_value_ = value; + } + + basic_staj_event(int64_t value, semantic_tag tag) + : event_type_(staj_event_type::int64_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.int64_value_ = value; + } + + basic_staj_event(uint64_t value, semantic_tag tag) + : event_type_(staj_event_type::uint64_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.uint64_value_ = value; + } + + basic_staj_event(half_arg_t, uint16_t value, semantic_tag tag) + : event_type_(staj_event_type::half_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.half_value_ = value; + } + + basic_staj_event(double value, semantic_tag tag) + : event_type_(staj_event_type::double_value), tag_(tag), ext_tag_(0), length_(0) + { + value_.double_value_ = value; + } + + basic_staj_event(const string_view_type& s, + staj_event_type event_type, + semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), length_(s.length()) + { + value_.string_data_ = s.data(); + } + + basic_staj_event(const byte_string_view& s, + staj_event_type event_type, + semantic_tag tag = semantic_tag::none) + : event_type_(event_type), tag_(tag), ext_tag_(0), length_(s.size()) + { + value_.byte_string_data_ = s.data(); + } + + basic_staj_event(const byte_string_view& s, + staj_event_type event_type, + uint64_t ext_tag) + : event_type_(event_type), tag_(semantic_tag::ext), ext_tag_(ext_tag), length_(s.size()) + { + value_.byte_string_data_ = s.data(); + } + + std::size_t size() const + { + return length_; + } + + template + T get() const + { + std::error_code ec; + T val = get(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec)); + } + return val; + } + + template + typename std::enable_if::value && std::is_same::value, T>::type + get(std::error_code& ec) const + { + converter conv; + switch (event_type_) + { + case staj_event_type::key: + case staj_event_type::string_value: + return conv.from(jsoncons::basic_string_view(value_.string_data_, length_), tag(), ec); + case staj_event_type::byte_string_value: + { + return conv.from(byte_string_view(value_.byte_string_data_,length_), + tag(), + ec); + } + case staj_event_type::uint64_value: + { + return conv.from(value_.uint64_value_, tag(), ec); + } + case staj_event_type::int64_value: + { + return conv.from(value_.int64_value_, tag(), ec); + } + case staj_event_type::half_value: + { + return conv.from(half_arg, value_.half_value_, tag(), ec); + } + case staj_event_type::double_value: + { + return conv.from(value_.double_value_, tag(), ec); + } + case staj_event_type::bool_value: + { + return conv.from(value_.bool_value_,tag(),ec); + } + case staj_event_type::null_value: + { + return conv.from(null_type(),tag(),ec); + } + default: + { + ec = conv_errc::not_string; + return T{}; + } + } + } + + template + typename std::enable_if::value && std::is_same::value, T>::type + get(std::error_code& ec) const + { + T s; + switch (event_type_) + { + case staj_event_type::key: + case staj_event_type::string_value: + s = T(value_.string_data_, length_); + break; + default: + ec = conv_errc::not_string_view; + break; + } + return s; + } + + template + typename std::enable_if::value, T>::type + get(std::error_code& ec) const + { + T s; + switch (event_type_) + { + case staj_event_type::byte_string_value: + s = T(value_.byte_string_data_, length_); + break; + default: + ec = conv_errc::not_byte_string_view; + break; + } + return s; + } + + template + typename std::enable_if::value && + std::is_same::value,T>::type + get(std::error_code& ec) const + { + converter conv; + switch (event_type_) + { + case staj_event_type::byte_string_value: + return conv.from(byte_string_view(value_.byte_string_data_, length_), tag(), ec); + case staj_event_type::string_value: + return conv.from(jsoncons::basic_string_view(value_.string_data_, length_), tag(), ec); + default: + ec = conv_errc::not_byte_string; + return T{}; + } + } + + template + typename std::enable_if::value, IntegerType>::type + get(std::error_code& ec) const + { + switch (event_type_) + { + case staj_event_type::string_value: + { + IntegerType val; + auto result = jsoncons::detail::to_integer(value_.string_data_, length_, val); + if (!result) + { + ec = conv_errc::not_integer; + return IntegerType(); + } + return val; + } + case staj_event_type::half_value: + return static_cast(value_.half_value_); + case staj_event_type::double_value: + return static_cast(value_.double_value_); + case staj_event_type::int64_value: + return static_cast(value_.int64_value_); + case staj_event_type::uint64_value: + return static_cast(value_.uint64_value_); + case staj_event_type::bool_value: + return static_cast(value_.bool_value_ ? 1 : 0); + default: + ec = conv_errc::not_integer; + return IntegerType(); + } + } + + template + typename std::enable_if::value, T>::type + get(std::error_code& ec) const + { + return static_cast(as_double(ec)); + } + + template + typename std::enable_if::value, T>::type + get(std::error_code& ec) const + { + return as_bool(ec); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + template + JSONCONS_DEPRECATED_MSG("Instead, use get()") + T as() const + { + return get(); + } + semantic_tag get_semantic_tag() const noexcept { return tag_; } +#endif + + staj_event_type event_type() const noexcept { return event_type_; } + + semantic_tag tag() const noexcept { return tag_; } + + uint64_t ext_tag() const noexcept { return ext_tag_; } + +private: + + double as_double(std::error_code& ec) const + { + switch (event_type_) + { + case staj_event_type::key: + case staj_event_type::string_value: + { + jsoncons::detail::chars_to f; + return f(value_.string_data_, length_); + } + case staj_event_type::double_value: + return value_.double_value_; + case staj_event_type::int64_value: + return static_cast(value_.int64_value_); + case staj_event_type::uint64_value: + return static_cast(value_.uint64_value_); + case staj_event_type::half_value: + { + double x = binary::decode_half(value_.half_value_); + return static_cast(x); + } + default: + ec = conv_errc::not_double; + return double(); + } + } + + bool as_bool(std::error_code& ec) const + { + switch (event_type_) + { + case staj_event_type::bool_value: + return value_.bool_value_; + case staj_event_type::double_value: + return value_.double_value_ != 0.0; + case staj_event_type::int64_value: + return value_.int64_value_ != 0; + case staj_event_type::uint64_value: + return value_.uint64_value_ != 0; + default: + ec = conv_errc::not_bool; + return bool(); + } + } +}; + +// basic_staj_visitor + +enum class staj_cursor_state +{ + typed_array = 1, + multi_dim, + shape +}; + +template +class basic_staj_visitor : public basic_json_visitor +{ + using super_type = basic_json_visitor; +public: + using char_type = CharT; + using typename super_type::string_view_type; +private: + std::function&, const ser_context&)> pred_; + basic_staj_event event_; + + staj_cursor_state state_; + typed_array_view data_; + jsoncons::span shape_; + std::size_t index_; +public: + basic_staj_visitor() + : pred_(accept), event_(staj_event_type::null_value), + state_(), data_(), shape_(), index_(0) + { + } + + basic_staj_visitor(std::function&, const ser_context&)> pred) + : pred_(pred), event_(staj_event_type::null_value), + state_(), data_(), shape_(), index_(0) + { + } + + void reset() + { + event_ = staj_event_type::null_value; + state_ = {}; + data_ = {}; + shape_ = {}; + index_ = 0; + } + + const basic_staj_event& event() const + { + return event_; + } + + bool in_available() const + { + return state_ != staj_cursor_state(); + } + + void send_available(std::error_code& ec) + { + switch (state_) + { + case staj_cursor_state::typed_array: + advance_typed_array(ec); + break; + case staj_cursor_state::multi_dim: + case staj_cursor_state::shape: + advance_multi_dim(ec); + break; + default: + break; + } + } + + bool is_typed_array() const + { + return data_.type() != typed_array_type(); + } + + staj_cursor_state state() const + { + return state_; + } + + void advance_typed_array(std::error_code& ec) + { + if (is_typed_array()) + { + if (index_ < data_.size()) + { + switch (data_.type()) + { + case typed_array_type::uint8_value: + { + this->uint64_value(data_.data(uint8_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::uint16_value: + { + this->uint64_value(data_.data(uint16_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::uint32_value: + { + this->uint64_value(data_.data(uint32_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::uint64_value: + { + this->uint64_value(data_.data(uint64_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int8_value: + { + this->int64_value(data_.data(int8_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int16_value: + { + this->int64_value(data_.data(int16_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int32_value: + { + this->int64_value(data_.data(int32_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::int64_value: + { + this->int64_value(data_.data(int64_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::half_value: + { + this->half_value(data_.data(half_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::float_value: + { + this->double_value(data_.data(float_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + case typed_array_type::double_value: + { + this->double_value(data_.data(double_array_arg)[index_], semantic_tag::none, ser_context(), ec); + break; + } + default: + break; + } + ++index_; + } + else + { + this->end_array(); + state_ = staj_cursor_state(); + data_ = typed_array_view(); + index_ = 0; + } + } + } + + void advance_multi_dim(std::error_code& ec) + { + if (shape_.size() != 0) + { + if (state_ == staj_cursor_state::multi_dim) + { + this->begin_array(shape_.size(), semantic_tag::none, ser_context(), ec); + state_ = staj_cursor_state::shape; + } + else if (index_ < shape_.size()) + { + this->uint64_value(shape_[index_], semantic_tag::none, ser_context(), ec); + ++index_; + } + else + { + state_ = staj_cursor_state(); + this->end_array(ser_context(), ec); + shape_ = jsoncons::span(); + index_ = 0; + } + } + } + + bool dump(basic_json_visitor& visitor, const ser_context& context, std::error_code& ec) + { + bool more = true; + if (is_typed_array()) + { + if (index_ != 0) + { + more = staj_to_saj_event(event(), visitor, context, ec); + while (more && is_typed_array()) + { + if (index_ < data_.size()) + { + switch (data_.type()) + { + case typed_array_type::uint8_value: + { + more = visitor.uint64_value(data_.data(uint8_array_arg)[index_]); + break; + } + case typed_array_type::uint16_value: + { + more = visitor.uint64_value(data_.data(uint16_array_arg)[index_]); + break; + } + case typed_array_type::uint32_value: + { + more = visitor.uint64_value(data_.data(uint32_array_arg)[index_]); + break; + } + case typed_array_type::uint64_value: + { + more = visitor.uint64_value(data_.data(uint64_array_arg)[index_]); + break; + } + case typed_array_type::int8_value: + { + more = visitor.int64_value(data_.data(int8_array_arg)[index_]); + break; + } + case typed_array_type::int16_value: + { + more = visitor.int64_value(data_.data(int16_array_arg)[index_]); + break; + } + case typed_array_type::int32_value: + { + more = visitor.int64_value(data_.data(int32_array_arg)[index_]); + break; + } + case typed_array_type::int64_value: + { + more = visitor.int64_value(data_.data(int64_array_arg)[index_]); + break; + } + case typed_array_type::float_value: + { + more = visitor.double_value(data_.data(float_array_arg)[index_]); + break; + } + case typed_array_type::double_value: + { + more = visitor.double_value(data_.data(double_array_arg)[index_]); + break; + } + default: + break; + } + ++index_; + } + else + { + more = visitor.end_array(); + state_ = staj_cursor_state(); + data_ = typed_array_view(); + index_ = 0; + } + } + } + else + { + switch (data_.type()) + { + case typed_array_type::uint8_value: + { + more = visitor.typed_array(data_.data(uint8_array_arg)); + break; + } + case typed_array_type::uint16_value: + { + more = visitor.typed_array(data_.data(uint16_array_arg)); + break; + } + case typed_array_type::uint32_value: + { + more = visitor.typed_array(data_.data(uint32_array_arg)); + break; + } + case typed_array_type::uint64_value: + { + more = visitor.typed_array(data_.data(uint64_array_arg)); + break; + } + case typed_array_type::int8_value: + { + more = visitor.typed_array(data_.data(int8_array_arg)); + break; + } + case typed_array_type::int16_value: + { + more = visitor.typed_array(data_.data(int16_array_arg)); + break; + } + case typed_array_type::int32_value: + { + more = visitor.typed_array(data_.data(int32_array_arg)); + break; + } + case typed_array_type::int64_value: + { + more = visitor.typed_array(data_.data(int64_array_arg)); + break; + } + case typed_array_type::float_value: + { + more = visitor.typed_array(data_.data(float_array_arg)); + break; + } + case typed_array_type::double_value: + { + more = visitor.typed_array(data_.data(double_array_arg)); + break; + } + default: + break; + } + + state_ = staj_cursor_state(); + data_ = typed_array_view(); + } + } + else + { + more = staj_to_saj_event(event(), visitor, context, ec); + } + return more; + } + +private: + static constexpr bool accept(const basic_staj_event&, const ser_context&) + { + return true; + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::begin_object, tag); + return !pred_(event_, context); + } + + bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::begin_object, length, tag); + return !pred_(event_, context); + } + + bool visit_end_object(const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::end_object); + return !pred_(event_, context); + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::begin_array, tag); + return !pred_(event_, context); + } + + bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::begin_array, length, tag); + return !pred_(event_, context); + } + + bool visit_end_array(const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::end_array); + return !pred_(event_, context); + } + + bool visit_key(const string_view_type& name, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(name, staj_event_type::key); + return !pred_(event_, context); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(staj_event_type::null_value, tag); + return !pred_(event_, context); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(value, tag); + return !pred_(event_, context); + } + + bool visit_string(const string_view_type& s, semantic_tag tag, const ser_context& context, std::error_code&) override + { + event_ = basic_staj_event(s, staj_event_type::string_value, tag); + return !pred_(event_, context); + } + + bool visit_byte_string(const byte_string_view& s, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj_event(s, staj_event_type::byte_string_value, tag); + return !pred_(event_, context); + } + + bool visit_byte_string(const byte_string_view& s, + uint64_t ext_tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj_event(s, staj_event_type::byte_string_value, ext_tag); + return !pred_(event_, context); + } + + bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj_event(value, tag); + return !pred_(event_, context); + } + + bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj_event(value, tag); + return !pred_(event_, context); + } + + bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj_event(half_arg, value, tag); + return !pred_(event_, context); + } + + bool visit_double(double value, + semantic_tag tag, + const ser_context& context, + std::error_code&) override + { + event_ = basic_staj_event(value, tag); + return !pred_(event_, context); + } + + bool visit_typed_array(const jsoncons::span& v, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(v.data(), v.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(half_arg_t, const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } + + bool visit_typed_array(const jsoncons::span& data, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::typed_array; + data_ = typed_array_view(data.data(), data.size()); + index_ = 0; + return this->begin_array(tag, context, ec); + } +/* + bool visit_typed_array(const jsoncons::span&, + semantic_tag, + const ser_context&, + std::error_code&) override + { + return true; + } +*/ + bool visit_begin_multi_dim(const jsoncons::span& shape, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + state_ = staj_cursor_state::multi_dim; + shape_ = shape; + return this->begin_array(2, tag, context, ec); + } + + bool visit_end_multi_dim(const ser_context& context, + std::error_code& ec) override + { + return this->end_array(context, ec); + } + + void visit_flush() override + { + } +}; + +template +bool staj_to_saj_event(const basic_staj_event& ev, + basic_json_visitor& visitor, + const ser_context& context, + std::error_code& ec) +{ + switch (ev.event_type()) + { + case staj_event_type::begin_array: + return visitor.begin_array(ev.tag(), context); + case staj_event_type::end_array: + return visitor.end_array(context); + case staj_event_type::begin_object: + return visitor.begin_object(ev.tag(), context, ec); + case staj_event_type::end_object: + return visitor.end_object(context, ec); + case staj_event_type::key: + return visitor.key(ev.template get>(), context); + case staj_event_type::string_value: + return visitor.string_value(ev.template get>(), ev.tag(), context); + case staj_event_type::byte_string_value: + return visitor.byte_string_value(ev.template get(), ev.tag(), context); + case staj_event_type::null_value: + return visitor.null_value(ev.tag(), context); + case staj_event_type::bool_value: + return visitor.bool_value(ev.template get(), ev.tag(), context); + case staj_event_type::int64_value: + return visitor.int64_value(ev.template get(), ev.tag(), context); + case staj_event_type::uint64_value: + return visitor.uint64_value(ev.template get(), ev.tag(), context); + case staj_event_type::half_value: + return visitor.half_value(ev.template get(), ev.tag(), context); + case staj_event_type::double_value: + return visitor.double_value(ev.template get(), ev.tag(), context); + default: + return false; + } +} + +// basic_staj_cursor + +template +class basic_staj_cursor +{ +public: + virtual ~basic_staj_cursor() noexcept = default; + + virtual void array_expected(std::error_code& ec) + { + if (!(current().event_type() == staj_event_type::begin_array || current().event_type() == staj_event_type::byte_string_value)) + { + ec = conv_errc::not_vector; + } + } + + virtual bool done() const = 0; + + virtual const basic_staj_event& current() const = 0; + + virtual void read_to(basic_json_visitor& visitor) = 0; + + virtual void read_to(basic_json_visitor& visitor, + std::error_code& ec) = 0; + + virtual void next() = 0; + + virtual void next(std::error_code& ec) = 0; + + virtual const ser_context& context() const = 0; +}; + +template +class basic_staj_filter_view : basic_staj_cursor +{ + basic_staj_cursor* cursor_; + std::function&, const ser_context&)> pred_; +public: + basic_staj_filter_view(basic_staj_cursor& cursor, + std::function&, const ser_context&)> pred) + : cursor_(std::addressof(cursor)), pred_(pred) + { + while (!done() && !pred_(current(),context())) + { + cursor_->next(); + } + } + + bool done() const override + { + return cursor_->done(); + } + + const basic_staj_event& current() const override + { + return cursor_->current(); + } + + void read_to(basic_json_visitor& visitor) override + { + cursor_->read_to(visitor); + } + + void read_to(basic_json_visitor& visitor, + std::error_code& ec) override + { + cursor_->read_to(visitor, ec); + } + + void next() override + { + cursor_->next(); + while (!done() && !pred_(current(),context())) + { + cursor_->next(); + } + } + + void next(std::error_code& ec) override + { + cursor_->next(ec); + while (!done() && !pred_(current(),context()) && !ec) + { + cursor_->next(ec); + } + } + + const ser_context& context() const override + { + return cursor_->context(); + } + + friend + basic_staj_filter_view operator|(basic_staj_filter_view& cursor, + std::function&, const ser_context&)> pred) + { + return basic_staj_filter_view(cursor, pred); + } +}; + +using staj_event = basic_staj_event; +using wstaj_event = basic_staj_event; + +using staj_cursor = basic_staj_cursor; +using wstaj_cursor = basic_staj_cursor; + +using staj_filter_view = basic_staj_filter_view; +using wstaj_filter_view = basic_staj_filter_view; + +#if !defined(JSONCONS_NO_DEPRECATED) + +JSONCONS_DEPRECATED_MSG("Instead, use staj_event_type") typedef staj_event_type stream_event_type; + +template +using basic_stream_event = basic_staj_event; + +template +using basic_stream_reader = basic_staj_cursor; + +template +using basic_staj_reader = basic_staj_cursor; + +JSONCONS_DEPRECATED_MSG("Instead, use staj_event") typedef basic_staj_event stream_event; +JSONCONS_DEPRECATED_MSG("Instead, use wstaj_event") typedef basic_staj_event wstream_event; + +JSONCONS_DEPRECATED_MSG("Instead, use staj_cursor") typedef basic_staj_cursor stream_reader; +JSONCONS_DEPRECATED_MSG("Instead, use wstaj_cursor") typedef basic_staj_cursor wstream_reader; + +JSONCONS_DEPRECATED_MSG("Instead, use staj_cursor") typedef basic_staj_cursor staj_reader; +JSONCONS_DEPRECATED_MSG("Instead, use wstaj_cursor") typedef basic_staj_cursor wstaj_reader; + +#endif + +} + +#endif + diff --git a/include/jsoncons/staj_iterator.hpp b/include/jsoncons/staj_iterator.hpp new file mode 100644 index 0000000..a6897f7 --- /dev/null +++ b/include/jsoncons/staj_iterator.hpp @@ -0,0 +1,449 @@ +// Copyright 2018 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_STAJ_ITERATOR_HPP +#define JSONCONS_STAJ_ITERATOR_HPP + +#include // placement new +#include +#include +#include +#include +#include +#include // std::input_iterator_tag +#include +#include +#include +#include + +namespace jsoncons { + + template + class staj_array_view; + + template + class staj_array_iterator + { + using char_type = typename Json::char_type; + + staj_array_view* view_; + std::exception_ptr eptr_; + + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + using iterator_category = std::input_iterator_tag; + + staj_array_iterator() noexcept + : view_(nullptr) + { + } + + staj_array_iterator(staj_array_view& view) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_array) + { + next(); + } + else + { + view_->cursor_ = nullptr; + } + } + + staj_array_iterator(staj_array_view& view, + std::error_code& ec) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_array) + { + next(ec); + if (ec) {view_ = nullptr;} + } + else + { + view_ = nullptr; + } + } + + ~staj_array_iterator() noexcept + { + } + + bool has_value() const + { + return !eptr_; + } + + const T& operator*() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return *view_->value_; + } + } + + const T* operator->() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return view_->value_.operator->(); + } + } + + staj_array_iterator& operator++() + { + next(); + return *this; + } + + staj_array_iterator& increment(std::error_code& ec) + { + next(ec); + if (ec) {view_ = nullptr;} + return *this; + } + + staj_array_iterator operator++(int) // postfix increment + { + staj_array_iterator temp(*this); + next(); + return temp; + } + + friend bool operator==(const staj_array_iterator& a, const staj_array_iterator& b) + { + return (!a.view_ && !b.view_) + || (!a.view_ && b.done()) + || (!b.view_ && a.done()); + } + + friend bool operator!=(const staj_array_iterator& a, const staj_array_iterator& b) + { + return !(a == b); + } + + private: + + bool done() const + { + return view_->cursor_->done() || view_->cursor_->current().event_type() == staj_event_type::end_array; + } + + void next() + { + std::error_code ec; + next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, view_->cursor_->context().line(), view_->cursor_->context().column())); + } + } + + void next(std::error_code& ec) + { + using char_type = typename Json::char_type; + + if (!done()) + { + view_->cursor_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + eptr_ = std::exception_ptr(); + JSONCONS_TRY + { + view_->value_ = decode_traits::decode(*view_->cursor_, view_->decoder_, ec); + } + JSONCONS_CATCH(const conv_error&) + { + eptr_ = std::current_exception(); + } + } + } + } + }; + + template + class staj_object_view; + + template + class staj_object_iterator + { + using char_type = typename Json::char_type; + + staj_object_view* view_; + std::exception_ptr eptr_; + public: + using key_type = std::basic_string; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::input_iterator_tag; + + public: + + staj_object_iterator() noexcept + : view_(nullptr) + { + } + + staj_object_iterator(staj_object_view& view) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_object) + { + next(); + } + else + { + view_ = nullptr; + } + } + + staj_object_iterator(staj_object_view& view, + std::error_code& ec) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_object) + { + next(ec); + if (ec) {view_ = nullptr;} + } + else + { + view_ = nullptr; + } + } + + ~staj_object_iterator() noexcept + { + } + + bool has_value() const + { + return !eptr_; + } + + const value_type& operator*() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return *view_->key_value_; + } + } + + const value_type* operator->() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return view_->key_value_.operator->(); + } + } + + staj_object_iterator& operator++() + { + next(); + return *this; + } + + staj_object_iterator& increment(std::error_code& ec) + { + next(ec); + if (ec) + { + view_ = nullptr; + } + return *this; + } + + staj_object_iterator operator++(int) // postfix increment + { + staj_object_iterator temp(*this); + next(); + return temp; + } + + friend bool operator==(const staj_object_iterator& a, const staj_object_iterator& b) + { + return (!a.view_ && !b.view_) + || (!a.view_ && b.done()) + || (!b.view_ && a.done()); + } + + friend bool operator!=(const staj_object_iterator& a, const staj_object_iterator& b) + { + return !(a == b); + } + + private: + + bool done() const + { + return view_->cursor_->done() || view_->cursor_->current().event_type() == staj_event_type::end_object; + } + + void next() + { + std::error_code ec; + next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, view_->cursor_->context().line(), view_->cursor_->context().column())); + } + } + + void next(std::error_code& ec) + { + using char_type = typename Json::char_type; + + view_->cursor_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + JSONCONS_ASSERT(view_->cursor_->current().event_type() == staj_event_type::key); + auto key = view_->cursor_->current(). template get(); + view_->cursor_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + eptr_ = std::exception_ptr(); + JSONCONS_TRY + { + view_->key_value_ = value_type(std::move(key),decode_traits::decode(*view_->cursor_, view_->decoder_, ec)); + } + JSONCONS_CATCH(const conv_error&) + { + eptr_ = std::current_exception(); + } + } + } + } + }; + + // staj_array_view + + template + class staj_array_view + { + friend class staj_array_iterator; + public: + using char_type = typename Json::char_type; + using iterator = staj_array_iterator; + private: + basic_staj_cursor* cursor_; + json_decoder decoder_; + jsoncons::optional value_; + public: + staj_array_view(basic_staj_cursor& cursor) + : cursor_(std::addressof(cursor)) + { + } + + iterator begin() + { + return staj_array_iterator(*this); + } + + iterator end() + { + return staj_array_iterator(); + } + }; + + // staj_object_view + + template + class staj_object_view + { + friend class staj_object_iterator; + public: + using char_type = typename Json::char_type; + using iterator = staj_object_iterator; + using key_type = std::basic_string; + using value_type = std::pair; + private: + basic_staj_cursor* cursor_; + json_decoder decoder_; + jsoncons::optional key_value_; + public: + staj_object_view(basic_staj_cursor& cursor) + : cursor_(std::addressof(cursor)) + { + } + + iterator begin() + { + return staj_object_iterator(*this); + } + + iterator end() + { + return staj_object_iterator(); + } + }; + + template ::value,T,basic_json>::type> + staj_array_view staj_array(basic_staj_cursor& cursor) + { + return staj_array_view(cursor); + } + + template ::value,T,basic_json>::type> + staj_object_view staj_object(basic_staj_cursor& cursor) + { + return staj_object_view(cursor); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + template ::value,T,basic_json>::type> + JSONCONS_DEPRECATED_MSG("Instead, use staj_array()") + staj_array_view make_array_iterator(basic_staj_cursor& cursor) + { + return staj_array_view(cursor); + } + + template ::value,T,basic_json>::type> + JSONCONS_DEPRECATED_MSG("Instead, use staj_object()") + staj_object_view, T, Json> make_object_iterator(basic_staj_cursor& cursor) + { + return staj_object_view, T, Json>(cursor); + } +#endif + +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons/tag_type.hpp b/include/jsoncons/tag_type.hpp new file mode 100644 index 0000000..ffefd8a --- /dev/null +++ b/include/jsoncons/tag_type.hpp @@ -0,0 +1,245 @@ +// Copyright 2019 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_TAG_TYPE_HPP +#define JSONCONS_TAG_TYPE_HPP + +#include +#include + +namespace jsoncons { + +struct null_type +{ + explicit null_type() = default; +}; + +struct temp_allocator_arg_t +{ + explicit temp_allocator_arg_t() = default; +}; + +constexpr temp_allocator_arg_t temp_allocator_arg{}; + +struct result_allocator_arg_t +{ + explicit result_allocator_arg_t() = default; +}; + +constexpr result_allocator_arg_t result_allocator_arg{}; + +struct half_arg_t +{ + explicit half_arg_t() = default; +}; + +constexpr half_arg_t half_arg{}; + +struct json_array_arg_t +{ + explicit json_array_arg_t() = default; +}; + +constexpr json_array_arg_t json_array_arg{}; + +struct json_object_arg_t +{ + explicit json_object_arg_t() = default; +}; + +constexpr json_object_arg_t json_object_arg{}; + +struct byte_string_arg_t +{ + explicit byte_string_arg_t() = default; +}; + +constexpr byte_string_arg_t byte_string_arg{}; + +struct json_const_pointer_arg_t +{ + explicit json_const_pointer_arg_t() = default; +}; + +constexpr json_const_pointer_arg_t json_const_pointer_arg{}; + +enum class semantic_tag : uint8_t +{ + none = 0, + undefined = 0x01, + datetime = 0x02, + epoch_second = 0x03, + epoch_milli = 0x04, + epoch_nano = 0x05, + bigint = 0x06, + bigdec = 0x07, + bigfloat = 0x08, + float128 = 0x09, + base16 = 0x1a, + base64 = 0x1b, + base64url = 0x1c, + uri = 0x0d, + clamped = 0x0e, + multi_dim_row_major = 0x0f, + multi_dim_column_major = 0x10, + ext = 0x11, + id = 0x12, + regex = 0x13, + code = 0x14 +#if !defined(JSONCONS_NO_DEPRECATED) + , big_integer = bigint + , big_decimal = bigdec + , big_float = bigfloat + , date_time = datetime + , timestamp = epoch_second +#endif +}; + +template +std::basic_ostream& operator<<(std::basic_ostream& os, semantic_tag tag) +{ + static constexpr const CharT* na_name = JSONCONS_CSTRING_CONSTANT(CharT, "n/a"); + static constexpr const CharT* undefined_name = JSONCONS_CSTRING_CONSTANT(CharT, "undefined"); + static constexpr const CharT* datetime_name = JSONCONS_CSTRING_CONSTANT(CharT, "datetime"); + static constexpr const CharT* epoch_second_name = JSONCONS_CSTRING_CONSTANT(CharT, "epoch-second"); + static constexpr const CharT* epoch_milli_name = JSONCONS_CSTRING_CONSTANT(CharT, "epoch-milli"); + static constexpr const CharT* epoch_nano_name = JSONCONS_CSTRING_CONSTANT(CharT, "epoch-nano"); + static constexpr const CharT* bigint_name = JSONCONS_CSTRING_CONSTANT(CharT, "bigint"); + static constexpr const CharT* bigdec_name = JSONCONS_CSTRING_CONSTANT(CharT, "bigdec"); + static constexpr const CharT* bigfloat_name = JSONCONS_CSTRING_CONSTANT(CharT, "bigfloat"); + static constexpr const CharT* base16_name = JSONCONS_CSTRING_CONSTANT(CharT, "base16"); + static constexpr const CharT* base64_name = JSONCONS_CSTRING_CONSTANT(CharT, "base64"); + static constexpr const CharT* base64url_name = JSONCONS_CSTRING_CONSTANT(CharT, "base64url"); + static constexpr const CharT* uri_name = JSONCONS_CSTRING_CONSTANT(CharT, "uri"); + static constexpr const CharT* clamped_name = JSONCONS_CSTRING_CONSTANT(CharT, "clamped"); + static constexpr const CharT* multi_dim_row_major_name = JSONCONS_CSTRING_CONSTANT(CharT, "multi-dim-row-major"); + static constexpr const CharT* multi_dim_column_major_name = JSONCONS_CSTRING_CONSTANT(CharT, "multi-dim-column-major"); + static constexpr const CharT* ext_name = JSONCONS_CSTRING_CONSTANT(CharT, "ext"); + static constexpr const CharT* id_name = JSONCONS_CSTRING_CONSTANT(CharT, "id"); + static constexpr const CharT* float128_name = JSONCONS_CSTRING_CONSTANT(CharT, "float128"); + static constexpr const CharT* regex_name = JSONCONS_CSTRING_CONSTANT(CharT, "regex"); + static constexpr const CharT* code_name = JSONCONS_CSTRING_CONSTANT(CharT, "code"); + + switch (tag) + { + case semantic_tag::none: + { + os << na_name; + break; + } + case semantic_tag::undefined: + { + os << undefined_name; + break; + } + case semantic_tag::datetime: + { + os << datetime_name; + break; + } + case semantic_tag::epoch_second: + { + os << epoch_second_name; + break; + } + case semantic_tag::epoch_milli: + { + os << epoch_milli_name; + break; + } + case semantic_tag::epoch_nano: + { + os << epoch_nano_name; + break; + } + case semantic_tag::bigint: + { + os << bigint_name; + break; + } + case semantic_tag::bigdec: + { + os << bigdec_name; + break; + } + case semantic_tag::bigfloat: + { + os << bigfloat_name; + break; + } + case semantic_tag::float128: + { + os << float128_name; + break; + } + case semantic_tag::base16: + { + os << base16_name; + break; + } + case semantic_tag::base64: + { + os << base64_name; + break; + } + case semantic_tag::base64url: + { + os << base64url_name; + break; + } + case semantic_tag::uri: + { + os << uri_name; + break; + } + case semantic_tag::clamped: + { + os << clamped_name; + break; + } + case semantic_tag::multi_dim_row_major: + { + os << multi_dim_row_major_name; + break; + } + case semantic_tag::multi_dim_column_major: + { + os << multi_dim_column_major_name; + break; + } + case semantic_tag::ext: + { + os << ext_name; + break; + } + case semantic_tag::id: + { + os << id_name; + break; + } + case semantic_tag::regex: + { + os << regex_name; + break; + } + case semantic_tag::code: + { + os << code_name; + break; + } + } + return os; +} + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use semantic_tag") typedef semantic_tag semantic_tag_type; + JSONCONS_DEPRECATED_MSG("Instead, use byte_string_arg_t") typedef byte_string_arg_t bstr_arg_t; + constexpr byte_string_arg_t bstr_arg{}; +#endif + +} + +#endif diff --git a/include/jsoncons/text_source_adaptor.hpp b/include/jsoncons/text_source_adaptor.hpp new file mode 100644 index 0000000..491e8a6 --- /dev/null +++ b/include/jsoncons/text_source_adaptor.hpp @@ -0,0 +1,144 @@ +// Copyright 2021 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_TEXT_SOURCE_ADAPTOR_HPP +#define JSONCONS_TEXT_SOURCE_ADAPTOR_HPP + +#include +#include +#include +#include +#include +#include // std::allocator_traits +#include // std::vector +#include +#include // json_errc +#include +#include + +namespace jsoncons { + + // unicode_source_adaptor + + template + class unicode_source_adaptor + { + public: + using value_type = typename Source::value_type; + using source_type = Source; + private: + source_type source_; + bool bof_; + + + public: + template + unicode_source_adaptor(Sourceable&& source) + : source_(std::forward(source)), + bof_(true) + { + } + + bool is_error() const + { + return source_.is_error(); + } + + bool eof() const + { + return source_.eof(); + } + + span read_buffer(std::error_code& ec) + { + if (source_.eof()) + { + return span(); + } + + auto s = source_.read_buffer(); + const value_type* data = s.data(); + std::size_t length = s.size(); + + if (bof_ && length > 0) + { + auto r = unicode_traits::detect_encoding_from_bom(data, length); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + ec = json_errc::illegal_unicode_character; + return; + } + length -= (r.ptr - data); + data = r.ptr; + bof_ = false; + } + return span(data, length); + } + }; + + // json_source_adaptor + + template + class json_source_adaptor + { + public: + using value_type = typename Source::value_type; + using value_type = typename Source::value_type; + using source_type = Source; + private: + source_type source_; + bool bof_; + + public: + + template + json_source_adaptor(Sourceable&& source) + : source_(std::forward(source)), + bof_(true) + { + } + + bool is_error() const + { + return source_.is_error(); + } + + bool eof() const + { + return source_.eof(); + } + + span read_buffer(std::error_code& ec) + { + if (source_.eof()) + { + return span(); + } + + auto s = source_.read_buffer(); + const value_type* data = s.data(); + std::size_t length = s.size(); + + if (bof_ && length > 0) + { + auto r = unicode_traits::detect_json_encoding(data, length); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + ec = json_errc::illegal_unicode_character; + return span(); + } + length -= (r.ptr - data); + data = r.ptr; + bof_ = false; + } + return span(data, length); + } + }; + +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons/typed_array_view.hpp b/include/jsoncons/typed_array_view.hpp new file mode 100644 index 0000000..d1b4906 --- /dev/null +++ b/include/jsoncons/typed_array_view.hpp @@ -0,0 +1,250 @@ +// Copyright 2018 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_TYPED_ARRAY_VIEW_HPP +#define JSONCONS_TYPED_ARRAY_VIEW_HPP + +#include // std::allocator +#include +#include +#include +#include +#include // std::enable_if +#include // std::array +#include // std::function +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { + + struct uint8_array_arg_t {explicit uint8_array_arg_t() = default; }; + constexpr uint8_array_arg_t uint8_array_arg = uint8_array_arg_t(); + struct uint16_array_arg_t {explicit uint16_array_arg_t() = default; }; + struct uint32_array_arg_t {explicit uint32_array_arg_t() = default; }; + constexpr uint32_array_arg_t uint32_array_arg = uint32_array_arg_t(); + struct uint64_array_arg_t {explicit uint64_array_arg_t() = default; }; + constexpr uint64_array_arg_t uint64_array_arg = uint64_array_arg_t(); + struct int8_array_arg_t {explicit int8_array_arg_t() = default; }; + constexpr int8_array_arg_t int8_array_arg = int8_array_arg_t(); + struct int16_array_arg_t {explicit int16_array_arg_t() = default; }; + constexpr int16_array_arg_t int16_array_arg = int16_array_arg_t(); + struct int32_array_arg_t {explicit int32_array_arg_t() = default; }; + constexpr int32_array_arg_t int32_array_arg = int32_array_arg_t(); + struct int64_array_arg_t {explicit int64_array_arg_t() = default; }; + constexpr int64_array_arg_t int64_array_arg = int64_array_arg_t(); + constexpr uint16_array_arg_t uint16_array_arg = uint16_array_arg_t(); + struct half_array_arg_t {explicit half_array_arg_t() = default; }; + constexpr half_array_arg_t half_array_arg = half_array_arg_t(); + struct float_array_arg_t {explicit float_array_arg_t() = default; }; + constexpr float_array_arg_t float_array_arg = float_array_arg_t(); + struct double_array_arg_t {explicit double_array_arg_t() = default; }; + constexpr double_array_arg_t double_array_arg = double_array_arg_t(); + struct float128_array_arg_t {explicit float128_array_arg_t() = default; }; + constexpr float128_array_arg_t float128_array_arg = float128_array_arg_t(); + + enum class typed_array_type{uint8_value=1,uint16_value,uint32_value,uint64_value, + int8_value,int16_value,int32_value,int64_value, + half_value, float_value,double_value}; + + class typed_array_view + { + typed_array_type type_; + union + { + const uint8_t* uint8_data_; + const uint16_t* uint16_data_; + const uint32_t* uint32_data_; + const uint64_t* uint64_data_; + const int8_t* int8_data_; + const int16_t* int16_data_; + const int32_t* int32_data_; + const int64_t* int64_data_; + const float* float_data_; + const double* double_data_; + } data_; + std::size_t size_; + public: + + typed_array_view() + : type_(), data_(), size_(0) + { + } + + typed_array_view(const typed_array_view& other) + : type_(other.type_), data_(other.data_), size_(other.size()) + { + } + + typed_array_view(typed_array_view&& other) noexcept + { + swap(*this,other); + } + + typed_array_view(const uint8_t* data, std::size_t size) + : type_(typed_array_type::uint8_value), size_(size) + { + data_.uint8_data_ = data; + } + + typed_array_view(const uint16_t* data, std::size_t size) + : type_(typed_array_type::uint16_value), size_(size) + { + data_.uint16_data_ = data; + } + + typed_array_view(const uint32_t* data, std::size_t size) + : type_(typed_array_type::uint32_value), size_(size) + { + data_.uint32_data_ = data; + } + + typed_array_view(const uint64_t* data, std::size_t size) + : type_(typed_array_type::uint64_value), size_(size) + { + data_.uint64_data_ = data; + } + + typed_array_view(const int8_t* data, std::size_t size) + : type_(typed_array_type::int8_value), size_(size) + { + data_.int8_data_ = data; + } + + typed_array_view(const int16_t* data, std::size_t size) + : type_(typed_array_type::int16_value), size_(size) + { + data_.int16_data_ = data; + } + + typed_array_view(const int32_t* data, std::size_t size) + : type_(typed_array_type::int32_value), size_(size) + { + data_.int32_data_ = data; + } + + typed_array_view(const int64_t* data, std::size_t size) + : type_(typed_array_type::int64_value), size_(size) + { + data_.int64_data_ = data; + } + + typed_array_view(half_array_arg_t, const uint16_t* data, std::size_t size) + : type_(typed_array_type::half_value), size_(size) + { + data_.uint16_data_ = data; + } + + typed_array_view(const float* data, std::size_t size) + : type_(typed_array_type::float_value), size_(size) + { + data_.float_data_ = data; + } + + typed_array_view(const double* data, std::size_t size) + : type_(typed_array_type::double_value), size_(size) + { + data_.double_data_ = data; + } + + typed_array_view& operator=(const typed_array_view& other) + { + typed_array_view temp(other); + swap(*this,temp); + return *this; + } + + typed_array_type type() const {return type_;} + + std::size_t size() const + { + return size_; + } + + jsoncons::span data(uint8_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::uint8_value); + return jsoncons::span(data_.uint8_data_, size_); + } + + jsoncons::span data(uint16_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::uint16_value); + return jsoncons::span(data_.uint16_data_, size_); + } + + jsoncons::span data(uint32_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::uint32_value); + return jsoncons::span(data_.uint32_data_, size_); + } + + jsoncons::span data(uint64_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::uint64_value); + return jsoncons::span(data_.uint64_data_, size_); + } + + jsoncons::span data(int8_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::int8_value); + return jsoncons::span(data_.int8_data_, size_); + } + + jsoncons::span data(int16_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::int16_value); + return jsoncons::span(data_.int16_data_, size_); + } + + jsoncons::span data(int32_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::int32_value); + return jsoncons::span(data_.int32_data_, size_); + } + + jsoncons::span data(int64_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::int64_value); + return jsoncons::span(data_.int64_data_, size_); + } + + jsoncons::span data(half_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::half_value); + return jsoncons::span(data_.uint16_data_, size_); + } + + jsoncons::span data(float_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::float_value); + return jsoncons::span(data_.float_data_, size_); + } + + jsoncons::span data(double_array_arg_t) const + { + JSONCONS_ASSERT(type_ == typed_array_type::double_value); + return jsoncons::span(data_.double_data_, size_); + } + + friend void swap(typed_array_view& a, typed_array_view& b) noexcept + { + std::swap(a.data_,b.data_); + std::swap(a.type_,b.type_); + std::swap(a.size_,b.size_); + } + }; + +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons/unicode_traits.hpp b/include/jsoncons/unicode_traits.hpp new file mode 100644 index 0000000..f45bafe --- /dev/null +++ b/include/jsoncons/unicode_traits.hpp @@ -0,0 +1,1330 @@ +// 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 JSONCONS_UNICODE_TRAITS_HPP +#define JSONCONS_UNICODE_TRAITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace jsoncons { namespace unicode_traits { + + enum class encoding_kind {undetected,utf8,utf16le,utf16be,utf32le,utf32be}; + + inline + std::string to_string(encoding_kind encoding) + { + switch (encoding) + { + case encoding_kind::utf8: + return "utf8"; + case encoding_kind::utf16le: + return "utf16le"; + case encoding_kind::utf16be: + return "utf16be"; + case encoding_kind::utf32le: + return "utf32le"; + case encoding_kind::utf32be: + return "utf32be"; + default: + return "undetected"; + } + } + + template + struct detect_encoding_result + { + const Byte* ptr; + encoding_kind encoding; + }; + + template + typename std::enable_if::value,detect_encoding_result>::type + detect_encoding_from_bom(const CharT* data, std::size_t length) + { + const uint8_t bom_utf8[] = {0xef,0xbb,0xbf}; + const uint8_t bom_utf16le[] = {0xff,0xfe}; + const uint8_t bom_utf16be[] = {0xfe,0xff}; + const uint8_t bom_utf32le[] = {0xff,0xfe,0x00,0x00}; + const uint8_t bom_utf32be[] = {0x00,0x00,0xfe,0xff}; + + if (length >= 4 && !memcmp(data,bom_utf32le,4)) + { + return detect_encoding_result{data+4,encoding_kind::utf32le}; + } + else if (length >= 4 && !memcmp(data,bom_utf32be,4)) + { + return detect_encoding_result{data+4,encoding_kind::utf32be}; + } + else if (length >= 2 && !memcmp(data,bom_utf16le,2)) + { + return detect_encoding_result{data+2,encoding_kind::utf16le}; + } + else if (length >= 2 && !memcmp(data,bom_utf16be,2)) + { + return detect_encoding_result{data+2,encoding_kind::utf16be}; + } + else if (length >= 3 && !memcmp(data,bom_utf8,3)) + { + return detect_encoding_result{data+3,encoding_kind::utf8}; + } + else + { + return detect_encoding_result{data,encoding_kind::undetected}; + } + } + + template + typename std::enable_if::value || type_traits::is_char32::value,detect_encoding_result>::type + detect_encoding_from_bom(const CharT* data, std::size_t) + { + return detect_encoding_result{data,encoding_kind::undetected}; + } + + template + typename std::enable_if::value,detect_encoding_result>::type + detect_json_encoding(const CharT* data, std::size_t length) + { + detect_encoding_result r = detect_encoding_from_bom(data,length); + if (r.encoding != encoding_kind::undetected) + { + return r; + } + else if (length < 4) + { + return detect_encoding_result{data,encoding_kind::utf8}; + } + else if (*data == 0 && *(data+1) == 0 && *(data+2) == 0) + { + return detect_encoding_result{data,encoding_kind::utf32be}; + } + else if (*data == 0 && *(data+2) == 0) + { + return detect_encoding_result{data,encoding_kind::utf16be}; + } + else if (*(data+1) == 0 && *(data+2) == 0 && *(data+3) == 0) + { + return detect_encoding_result{data,encoding_kind::utf32le}; + } + else if (*(data+1) == 0 && *(data+3) == 0) + { + return detect_encoding_result{data,encoding_kind::utf16le}; + } + else + { + return detect_encoding_result{data,encoding_kind::utf8}; + } + } + + template + typename std::enable_if::value || type_traits::is_char32::value,detect_encoding_result>::type + detect_json_encoding(const CharT* data, std::size_t) + { + return detect_encoding_result{data,encoding_kind::undetected}; + } + + /* + * 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) noexcept + { + return (ch >= sur_high_start && ch <= sur_high_end); + } + + inline + bool is_low_surrogate(uint32_t ch) noexcept + { + return (ch >= sur_low_start && ch <= sur_low_end); + } + + inline + bool is_surrogate(uint32_t ch) noexcept + { + return (ch >= sur_high_start && ch <= sur_low_end); + } + + enum class conv_flags + { + strict = 0, + lenient + }; + + // conv_errc + + enum class conv_errc + { + success = 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 noexcept + { + return "unicode_traits conversion error"; + } + virtual std::string message(int ev) const + { + switch (static_cast(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(result),unicode_traits_error_category()); + } + +} // unicode_traits +} // jsoncons + +namespace std { + template<> + struct is_error_code_enum : public true_type + { + }; +} + +namespace jsoncons { namespace unicode_traits { + + // utf8 + + template + typename std::enable_if::value, conv_errc>::type + is_legal_utf8(const CharT* first, std::size_t length) + { + uint8_t a; + const CharT* 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; + JSONCONS_FALLTHROUGH; + case 3: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + JSONCONS_FALLTHROUGH; + case 2: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + + switch (static_cast(*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; + } + + JSONCONS_FALLTHROUGH; + case 1: + if (static_cast(*first) >= 0x80 && static_cast(*first) < 0xC2) + return conv_errc::source_illegal; + break; + } + if (static_cast(*first) > 0xF4) + return conv_errc::source_illegal; + + return conv_errc(); + } + + template using void_t = void; + + template + struct is_output_iterator : std::false_type {}; + + template + struct is_output_iterator::iterator_category, + decltype(*std::declval() = std::declval())>> : std::true_type {}; + + // is_same_size fixes issue with vs2013 + + // primary template + template + struct is_same_size : std::false_type + { + }; + + // specialization for non void types + template + struct is_same_size::value && !std::is_void::value>::type> + { + static constexpr bool value = (sizeof(T1) == sizeof(T2)); + }; + + // convert + + template + struct convert_result + { + const CharT* ptr; + conv_errc ec; + }; + + // to_codepoint + + template + typename std::enable_if::value && type_traits::is_char32::value, + convert_result>::type + to_codepoint(const CharT* first, const CharT* last, + CodepointT& ch, + conv_flags flags = conv_flags::strict) noexcept + { + ch = 0; + if (first >= last) + { + return convert_result{first, conv_errc::source_exhausted}; + } + conv_errc result = conv_errc(); + + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + return convert_result{first, result}; + } + // Do this check whether lenient or strict + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) + { + return convert_result{first, result}; + } + // The cases all fall through. See "Note A" below. + switch (extra_bytes_to_read) + { + case 5: + ch += static_cast(*first++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 4: + ch += static_cast(*first++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 3: + ch += static_cast(*first++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 2: + ch += static_cast(*first++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 1: + ch += static_cast(*first++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 0: + ch += static_cast(*first++); + break; + } + 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; + return convert_result{first, result}; + } + else + { + ch = replacement_char; + } + } + } + else // i.e., ch > max_legal_utf32 + { + result = conv_errc::source_illegal; + ch = replacement_char; + } + + return convert_result{first,result} ; + } + + template + typename std::enable_if::value && type_traits::is_char32::value, + convert_result>::type + to_codepoint(const CharT* first, const CharT* last, + CodepointT& ch, + conv_flags flags = conv_flags::strict) noexcept + { + ch = 0; + if (first >= last) + { + return convert_result{first, conv_errc::source_exhausted}; + } + conv_errc result = conv_errc(); + + 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 ptr'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) // ptr's an unpaired high surrogate + { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + return convert_result{first, result}; + } + } + else + { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + return convert_result{first, result}; + } + } 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; + return convert_result{first, result}; + } + } + + return convert_result{first,result} ; + } + + template + typename std::enable_if::value && type_traits::is_char32::value, + convert_result>::type + to_codepoint(const CharT* first, const CharT* last, + CodepointT& ch, + conv_flags flags = conv_flags::strict) noexcept + { + ch = 0; + if (first >= last) + { + return convert_result{first, conv_errc::source_exhausted}; + } + conv_errc result = conv_errc(); + + 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; + return convert_result{first,result} ; + } + } + if (!(ch <= max_legal_utf32)) + { + ch = replacement_char; + result = conv_errc::source_illegal; + } + + return convert_result{first,result} ; + } + + // convert + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char8::value, + convert_result>::type + convert(const CharT* data, std::size_t length, Container& target, conv_flags flags=conv_flags::strict) + { + (void)flags; + + conv_errc result = conv_errc(); + const CharT* last = data + length; + while (data != last) + { + std::size_t len = trailing_bytes_for_utf8[static_cast(*data)] + 1; + if (len > (std::size_t)(last - data)) + { + return convert_result{data, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(data, len)) != conv_errc()) + { + return convert_result{data,result}; + } + + switch (len) { + case 4: target.push_back(static_cast(*data++)); + JSONCONS_FALLTHROUGH; + case 3: target.push_back(static_cast(*data++)); + JSONCONS_FALLTHROUGH; + case 2: target.push_back(static_cast(*data++)); + JSONCONS_FALLTHROUGH; + case 1: target.push_back(static_cast(*data++)); + } + } + return convert_result{data,result} ; + } + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char16::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast(*data)]; + if (extra_bytes_to_read >= last - data) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(data, extra_bytes_to_read+1)) != conv_errc()) + { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + uint32_t ch = 0; + switch (extra_bytes_to_read) { + case 5: ch += static_cast(*data++); ch <<= 6; /* remember, illegal UTF-8 */ + JSONCONS_FALLTHROUGH; + case 4: ch += static_cast(*data++); ch <<= 6; /* remember, illegal UTF-8 */ + JSONCONS_FALLTHROUGH; + case 3: ch += static_cast(*data++); ch <<= 6; + JSONCONS_FALLTHROUGH; + case 2: ch += static_cast(*data++); ch <<= 6; + JSONCONS_FALLTHROUGH; + case 1: ch += static_cast(*data++); ch <<= 6; + JSONCONS_FALLTHROUGH; + case 0: ch += static_cast(*data++); + break; + } + 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) { + data -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + target.push_back(replacement_char); + } + } else { + target.push_back((uint16_t)ch); /* normal case */ + } + } else if (ch > max_utf16) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + data -= (extra_bytes_to_read+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + target.push_back(replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + target.push_back((uint16_t)((ch >> half_shift) + sur_high_start)); + target.push_back((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result{data,result} ; + } + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char32::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data < last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast(*data)]; + if (extra_bytes_to_read >= last - data) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(data, 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(*data++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 4: + ch += static_cast(*data++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 3: + ch += static_cast(*data++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 2: + ch += static_cast(*data++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 1: + ch += static_cast(*data++); + ch <<= 6; + JSONCONS_FALLTHROUGH; + case 0: + ch += static_cast(*data++); + break; + } + 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) { + data -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + target.push_back(replacement_char); + } + } else { + target.push_back(ch); + } + } else { /* i.e., ch > max_legal_utf32 */ + result = conv_errc::source_illegal; + target.push_back(replacement_char); + } + } + return convert_result{data,result} ; + } + + // utf16 + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char8::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *data++; + /* If we have a surrogate pair, convert to uint32_t data. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the data buffer... */ + if (data < last) { + uint32_t ch2 = *data; + /* If ptr'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; + ++data; + } else if (flags == conv_flags::strict) { /* ptr's an unpaired high surrogate */ + --data; /* 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. */ + --data; /* 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)) + { + --data; /* 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; + JSONCONS_FALLTHROUGH; + case 3: byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + JSONCONS_FALLTHROUGH; + case 2: byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + JSONCONS_FALLTHROUGH; + case 1: byte1 = (uint8_t)(ch | first_byte_mark[bytes_to_write]); + break; + } + switch (bytes_to_write) + { + case 4: + target.push_back(byte1); + target.push_back(byte2); + target.push_back(byte3); + target.push_back(byte4); + break; + case 3: + target.push_back(byte1); + target.push_back(byte2); + target.push_back(byte3); + break; + case 2: + target.push_back(byte1); + target.push_back(byte2); + break; + case 1: + target.push_back(byte1); + break; + } + } + return convert_result{data,result} ; + } + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char16::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + uint32_t ch = *data++; + /* If we have a surrogate pair, convert to uint32_t data. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the data buffer... */ + if (data < last) { + uint32_t ch2 = *data; + /* If ptr's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + target.push_back((uint16_t)ch); + target.push_back((uint16_t)ch2); + ++data; + } else if (flags == conv_flags::strict) { /* ptr's an unpaired high surrogate */ + --data; /* 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. */ + --data; /* 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) { + --data; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + else + { + target.push_back((uint16_t)ch); + } + } + else + { + target.push_back((uint16_t)ch); + } + } + return convert_result{data,result} ; + } + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char32::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + uint32_t ch = *data++; + /* If we have a surrogate pair, convert to UTF32 data. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the data buffer... */ + if (data < last) { + uint32_t ch2 = *data; + /* If ptr'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; + ++data; + } else if (flags == conv_flags::strict) { /* ptr's an unpaired high surrogate */ + --data; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --data; /* 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) ) + { + --data; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + target.push_back(ch); + } + return convert_result{data,result} ; + } + + // utf32 + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char8::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + const CharT* last = data + length; + while (data < last) + { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *data++; + if (flags == conv_flags::strict ) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) + { + --data; /* 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; + JSONCONS_FALLTHROUGH; + case 3: + byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + JSONCONS_FALLTHROUGH; + case 2: + byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + JSONCONS_FALLTHROUGH; + case 1: + byte1 = (uint8_t) (ch | first_byte_mark[bytes_to_write]); + break; + } + + switch (bytes_to_write) + { + case 4: + target.push_back(byte1); + target.push_back(byte2); + target.push_back(byte3); + target.push_back(byte4); + break; + case 3: + target.push_back(byte1); + target.push_back(byte2); + target.push_back(byte3); + break; + case 2: + target.push_back(byte1); + target.push_back(byte2); + break; + case 1: + target.push_back(byte1); + break; + } + } + return convert_result{data,result} ; + } + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char16::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + uint32_t ch = *data++; + 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) { + --data; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + target.push_back(replacement_char); + } + } else { + target.push_back((uint16_t)ch); /* normal case */ + } + } else if (ch > max_legal_utf32) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + } else { + target.push_back(replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + target.push_back((uint16_t)((ch >> half_shift) + sur_high_start)); + target.push_back((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result{data,result} ; + } + + template + typename std::enable_if::value + && type_traits::is_back_insertable::value + && type_traits::is_char32::value, + convert_result>::type + convert(const CharT* data, std::size_t length, + Container& target, + conv_flags flags = conv_flags::strict) + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + uint32_t ch = *data++; + if (flags == conv_flags::strict ) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) + { + --data; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + if (ch <= max_legal_utf32) + { + target.push_back(ch); + } + else + { + target.push_back(replacement_char); + result = conv_errc::source_illegal; + } + } + return convert_result{data,result} ; + } + + // validate + + template + typename std::enable_if::value, + convert_result>::type + validate(const CharT* data, std::size_t length) noexcept + { + conv_errc result = conv_errc(); + const CharT* last = data + length; + while (data != last) + { + std::size_t len = static_cast(trailing_bytes_for_utf8[static_cast(*data)]) + 1; + if (len > (std::size_t)(last - data)) + { + return convert_result{data, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(data, len)) != conv_errc()) + { + return convert_result{data,result} ; + } + data += len; + } + return convert_result{data,result} ; + } + + // utf16 + + template + typename std::enable_if::value, + convert_result>::type + validate(const CharT* data, std::size_t length) noexcept + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + uint32_t ch = *data++; + /* If we have a surrogate pair, validate to uint32_t data. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the data buffer... */ + if (data < last) { + uint32_t ch2 = *data; + /* If ptr's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ++data; + } else { + --data; /* 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. + { + --data; /* 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 */ + --data; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + return convert_result{data,result} ; + } + + // utf32 + + template + typename std::enable_if::value, + convert_result>::type + validate(const CharT* data, std::size_t length) noexcept + { + conv_errc result = conv_errc(); + + const CharT* last = data + length; + while (data != last) + { + uint32_t ch = *data++; + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) + { + --data; /* 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{data, result} ; + } + + enum class encoding {u8,u16le,u16be,u32le,u32be,undetected}; + + template + struct determine_encoding_result + { + Iterator it; + encoding ec; + }; + + template + typename std::enable_if::value_type>::value && sizeof(typename std::iterator_traits::value_type) == sizeof(uint8_t), + determine_encoding_result>::type + detect_encoding(Iterator first, Iterator last) 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(*it1) == 0xEF && static_cast(*it2) == 0xBB && static_cast(*it3) == 0xBF) + { + return determine_encoding_result{last,encoding::u8}; + } + } + return determine_encoding_result{it1,encoding::undetected}; + } + else + { + Iterator it2 = ++first; + Iterator it3 = ++first; + Iterator it4 = ++first; + + uint32_t bom = static_cast(*it1) | (static_cast(*it2) << 8) | (static_cast(*it3) << 16) | (static_cast(*it4) << 24); + if (bom == 0xFFFE0000) + { + return determine_encoding_result{it4++,encoding::u32be}; + } + else if (bom == 0x0000FEFF) + { + return determine_encoding_result{first,encoding::u32le}; + } + else if ((bom & 0xFFFF) == 0xFFFE) + { + return determine_encoding_result{it3,encoding::u16be}; + } + else if ((bom & 0xFFFF) == 0xFEFF) + { + return determine_encoding_result{it3,encoding::u16le}; + } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) + { + return determine_encoding_result{it4,encoding::u8}; + } + else + { + uint32_t pattern = (static_cast(*it1) ? 1 : 0) | (static_cast(*it2) ? 2 : 0) | (static_cast(*it3) ? 4 : 0) | (static_cast(*it4) ? 8 : 0); + switch (pattern) { + case 0x08: + return determine_encoding_result{it1,encoding::u32be}; + case 0x0A: + return determine_encoding_result{it1,encoding::u16be}; + case 0x01: + return determine_encoding_result{it1,encoding::u32le}; + case 0x05: + return determine_encoding_result{it1,encoding::u16le}; + case 0x0F: + return determine_encoding_result{it1,encoding::u8}; + default: + return determine_encoding_result{it1,encoding::undetected}; + } + } + } + } + + // count_codepoints + + template + typename std::enable_if::value || type_traits::is_char16::value || type_traits::is_char32::value, std::size_t>::type + count_codepoints(const CharT* data, std::size_t length, + conv_flags flags = conv_flags::strict) noexcept + { + conv_errc ec = conv_errc(); + + std::size_t count = 0; + const CharT* ptr = data; + const CharT* last = data + length; + + for (; ptr < last; ++count) + { + uint32_t cp = 0; + auto r = to_codepoint(ptr, last, cp, flags); + if (r.ec != conv_errc()) + { + ec = r.ec; + break; + } + ptr = r.ptr; + } + return ec == conv_errc() && ptr == last ? count : 0; + } + +} // unicode_traits +} // jsoncons + +#endif + diff --git a/include/jsoncons/uri.hpp b/include/jsoncons/uri.hpp new file mode 100644 index 0000000..51249ef --- /dev/null +++ b/include/jsoncons/uri.hpp @@ -0,0 +1,635 @@ +// Copyright 2020 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_URI_HPP +#define JSONCONS_URI_HPP + +#include // std::string +#include +#include +#include +#include + +namespace jsoncons { + + class uri + { + using part_type = std::pair; + + std::string uri_; + part_type scheme_; + part_type userinfo_; + part_type host_; + part_type port_; + part_type path_; + part_type query_; + part_type fragment_; + public: + + uri() = default; + + uri(const std::string& uri) + { + *this = parse(uri); + } + + uri(jsoncons::string_view scheme, + jsoncons::string_view userinfo, + jsoncons::string_view host, + jsoncons::string_view port, + jsoncons::string_view path, + jsoncons::string_view query, + jsoncons::string_view fragment) + { + if (!scheme.empty()) + { + uri_.append(std::string(scheme)); + scheme_.second = uri_.length(); + } + if (!userinfo.empty() || !host.empty() || !port.empty()) + { + if (!scheme.empty()) + { + uri_.append("://"); + } + + if (!userinfo.empty()) + { + userinfo_.first = uri_.length(); + uri_.append(std::string(userinfo)); + userinfo_.second = uri_.length(); + uri_.append("@"); + } + else + { + userinfo_.first = userinfo_.second = uri_.length(); + } + + if (!host.empty()) + { + host_.first = uri_.length(); + uri_.append(std::string(host)); + host_.second = uri_.length(); + } + else + { + JSONCONS_THROW(json_runtime_error("uri error.")); + } + + if (!port.empty()) + { + uri_.append(":"); + port_.first = uri_.length(); + uri_.append(std::string(port)); + port_.second = uri_.length(); + } + else + { + port_.first = port_.second = uri_.length(); + } + } + else + { + userinfo_.first = userinfo_.second = uri_.length(); + host_.first = host_.second = uri_.length(); + port_.first = port_.second = uri_.length(); + if (!scheme.empty()) + { + if (!path.empty() || !query.empty() || !fragment.empty()) + { + uri_.append(":"); + } + else + { + JSONCONS_THROW(json_runtime_error("uri error.")); + } + } + } + + if (!path.empty()) + { + // if the URI is not opaque and the path is not already prefixed + // with a '/', add one. + path_.first = uri_.length(); + if (!host.empty() && (path.front() != '/')) + { + uri_.push_back('/'); + } + uri_.append(std::string(path)); + path_.second = uri_.length(); + } + else + { + path_.first = path_.second = uri_.length(); + } + + if (!query.empty()) + { + uri_.append("?"); + query_.first = uri_.length(); + uri_.append(std::string(query)); + query_.second = uri_.length(); + } + else + { + query_.first = query_.second = uri_.length(); + } + + if (!fragment.empty()) + { + uri_.append("#"); + fragment_.first = uri_.length(); + uri_.append(std::string(fragment)); + fragment_.second = uri_.length(); + } + else + { + fragment_.first = fragment_.second = uri_.length(); + } + } + + const std::string& string() const + { + return uri_; + } + + bool is_absolute() const noexcept + { + return scheme_.first != scheme_.second; + } + + bool is_opaque() const noexcept + { + return is_absolute() && !authority().empty(); + } + + string_view base() const noexcept { return string_view(uri_.data()+scheme_.first,(path_.second-scheme_.first)); } + + string_view scheme() const noexcept { return string_view(uri_.data()+scheme_.first,(scheme_.second-scheme_.first)); } + + string_view userinfo() const noexcept { return string_view(uri_.data()+userinfo_.first,(userinfo_.second-userinfo_.first)); } + + string_view host() const noexcept { return string_view(uri_.data()+host_.first,(host_.second-host_.first)); } + + string_view port() const noexcept { return string_view(uri_.data()+port_.first,(port_.second-port_.first)); } + + string_view path() const noexcept { return string_view(uri_.data()+path_.first,(path_.second-path_.first)); } + + string_view query() const noexcept { return string_view(uri_.data()+query_.first,(query_.second-query_.first)); } + + string_view fragment() const noexcept { return string_view(uri_.data()+fragment_.first,(fragment_.second-fragment_.first)); } + + string_view authority() const noexcept { return string_view(uri_.data()+userinfo_.first,(port_.second-userinfo_.first)); } + + uri resolve(const uri& base) const + { + // This implementation uses the psuedo-code given in + // http://tools.ietf.org/html/rfc3986#section-5.2.2 + + if (is_absolute() && !is_opaque()) + { + return *this; + } + + if (is_opaque()) + { + return *this; + } + + std::string userinfo, host, port, path, query, fragment; + + if (!authority().empty()) + { + // g -> http://g + if (!this->userinfo().empty()) + { + userinfo = std::string(this->userinfo()); + } + + if (!this->host().empty()) + { + host = std::string(this->host()); + } + + if (!this->port().empty()) + { + port = std::string(this->port()); + } + + if (!this->path().empty()) + { + path = remove_dot_segments(this->path()); + } + + if (!this->query().empty()) + { + query = std::string(this->query()); + } + } + else + { + if (this->path().empty()) + { + if (!base.path().empty()) + { + path = std::string(base.path()); + } + + if (!this->query().empty()) + { + query = std::string(this->query()); + } + else if (!base.query().empty()) + { + query = std::string(base.query()); + } + } + else + { + if (this->path().front() == '/') + { + path = remove_dot_segments(this->path()); + } + else + { + path = merge_paths(base, *this); + } + + if (!this->query().empty()) + { + query = std::string(this->query()); + } + } + + if (!base.userinfo().empty()) + { + userinfo = std::string(base.userinfo()); + } + + if (!base.host().empty()) + { + host = std::string(base.host()); + } + + if (!base.port().empty()) + { + port = std::string(base.port()); + } + } + + if (!this->fragment().empty()) + { + fragment = std::string(this->fragment()); + } + + return uri(std::string(base.scheme()), userinfo, host, port, path, query, fragment); + } + + int compare(const uri& other) const + { + int result = scheme().compare(other.scheme()); + if (result != 0) return result; + result = userinfo().compare(other.userinfo()); + if (result != 0) return result; + result = host().compare(other.host()); + if (result != 0) return result; + result = port().compare(other.port()); + if (result != 0) return result; + result = path().compare(other.path()); + if (result != 0) return result; + result = query().compare(other.query()); + if (result != 0) return result; + result = fragment().compare(other.fragment()); + + return result; + } + + friend bool operator==(const uri& lhs, const uri& rhs) + { + return lhs.compare(rhs) == 0; + } + + friend bool operator!=(const uri& lhs, const uri& rhs) + { + return lhs.compare(rhs) != 0; + } + + friend bool operator<(const uri& lhs, const uri& rhs) + { + return lhs.compare(rhs) < 0; + } + + friend bool operator<=(const uri& lhs, const uri& rhs) + { + return lhs.compare(rhs) <= 0; + } + + friend bool operator>(const uri& lhs, const uri& rhs) + { + return lhs.compare(rhs) > 0; + } + + friend bool operator>=(const uri& lhs, const uri& rhs) + { + return lhs.compare(rhs) >= 0; + } + + private: + enum class parse_state {expect_scheme, + expect_first_slash, + expect_second_slash, + expect_authority, + expect_host_ipv6, + expect_userinfo, + expect_host, + expect_port, + expect_path, + expect_query, + expect_fragment}; + + uri(const std::string& uri, part_type scheme, part_type userinfo, + part_type host, part_type port, part_type path, + part_type query, part_type fragment) + : uri_(uri), scheme_(scheme), userinfo_(userinfo), + host_(host), port_(port), path_(path), + query_(query), fragment_(fragment) + { + } + + static uri parse(const std::string& s) + { + part_type scheme; + part_type userinfo; + part_type host; + part_type port; + part_type path; + part_type query; + part_type fragment; + + std::size_t start = 0; + + parse_state state = parse_state::expect_scheme; + for (std::size_t i = 0; i < s.size(); ++i) + { + char c = s[i]; + switch (state) + { + case parse_state::expect_scheme: + switch (c) + { + case ':': + scheme = std::make_pair(start,i); + state = parse_state::expect_first_slash; + start = i; + break; + case '#': + userinfo = std::make_pair(start,start); + host = std::make_pair(start,start); + port = std::make_pair(start,start); + path = std::make_pair(start,i); + query = std::make_pair(i,i); + state = parse_state::expect_fragment; + start = i+1; + break; + default: + break; + } + break; + case parse_state::expect_first_slash: + switch (c) + { + case '/': + state = parse_state::expect_second_slash; + break; + default: + start = i; + state = parse_state::expect_path; + break; + } + break; + case parse_state::expect_second_slash: + switch (c) + { + case '/': + state = parse_state::expect_authority; + start = i+1; + break; + default: + break; + } + break; + case parse_state::expect_authority: + switch (c) + { + case '[': + state = parse_state::expect_host_ipv6; + start = i+1; + break; + default: + state = parse_state::expect_userinfo; + start = i; + --i; + break; + } + break; + case parse_state::expect_host_ipv6: + switch (c) + { + case ']': + userinfo = std::make_pair(start,start); + host = std::make_pair(start,i); + port = std::make_pair(i,i); + state = parse_state::expect_path; + start = i+1; + break; + default: + break; + } + break; + case parse_state::expect_userinfo: + switch (c) + { + case '@': + userinfo = std::make_pair(start,i); + state = parse_state::expect_host; + start = i+1; + break; + case ':': + userinfo = std::make_pair(start,start); + host = std::make_pair(start,i); + state = parse_state::expect_port; + start = i+1; + break; + case '/': + userinfo = std::make_pair(start,start); + host = std::make_pair(start,i); + port = std::make_pair(i,i); + state = parse_state::expect_path; + start = i; + break; + default: + break; + } + break; + case parse_state::expect_host: + switch (c) + { + case ':': + host = std::make_pair(start,i); + state = parse_state::expect_port; + start = i+1; + break; + default: + break; + } + break; + case parse_state::expect_port: + switch (c) + { + case '/': + port = std::make_pair(start,i); + state = parse_state::expect_path; + start = i; + break; + default: + break; + } + break; + case parse_state::expect_path: + switch (c) + { + case '?': + path = std::make_pair(start,i); + state = parse_state::expect_query; + start = i+1; + break; + case '#': + path = std::make_pair(start,i); + query = std::make_pair(start,start); + state = parse_state::expect_fragment; + start = i+1; + break; + default: + break; + } + break; + case parse_state::expect_query: + switch (c) + { + case '#': + query = std::make_pair(start,i); + state = parse_state::expect_fragment; + start = i+1; + break; + default: + break; + } + break; + case parse_state::expect_fragment: + break; + } + } + switch (state) + { + case parse_state::expect_scheme: + userinfo = std::make_pair(start,start); + host = std::make_pair(start,start); + port = std::make_pair(start,start); + path = std::make_pair(start,s.size()); + break; + case parse_state::expect_userinfo: + userinfo = std::make_pair(start,start); + host = std::make_pair(start,start); + port = std::make_pair(start,start); + path = std::make_pair(start,s.size()); + break; + case parse_state::expect_path: + path = std::make_pair(start,s.size()); + break; + case parse_state::expect_query: + query = std::make_pair(start,s.size()); + break; + case parse_state::expect_fragment: + fragment = std::make_pair(start,s.size()); + break; + default: + JSONCONS_THROW(std::invalid_argument("Invalid uri")); + break; + } + + return uri(s, scheme, userinfo, host, port, path, query, fragment); + } + + static std::string remove_dot_segments(const jsoncons::string_view& input) + { + std::string result = std::string(input); +/* + std::size_t pos = 0; + while (pos < input.size()) + { + if (input.compare(0, 3, "../")) + { + network_boost::erase_head(input, 3); + } else if (network_boost::starts_with(input, "./")) { + network_boost::erase_head(input, 2); + } else if (network_boost::starts_with(input, "/./")) { + network_boost::replace_head(input, 3, "/"); + } else if (input == "/.") { + network_boost::replace_head(input, 2, "/"); + } else if (network_boost::starts_with(input, "/../")) { + network_boost::erase_head(input, 3); + remove_last_segment(result); + } else if (network_boost::starts_with(input, "/..")) { + network_boost::replace_head(input, 3, "/"); + remove_last_segment(result); + } else if (network_boost::algorithm::all(input, [](char ch) { return ch == '.'; })) { + input.clear(); + } + else { + int n = (input.front() == '/')? 1 : 0; + auto slash = network_boost::find_nth(input, "/", n); + result.append(std::begin(input), std::begin(slash)); + input.erase(std::begin(input), std::begin(slash)); + } + } +*/ + return result; + } + + static std::string merge_paths(const uri& base, const uri& relative) + { + std::string result; + + if (base.path().empty()) + { + result = "/"; + } + else + { + const auto& base_path = base.path(); + auto last_slash = base_path.rfind('/'); + result.append(std::string(base_path.substr(0,last_slash+1))); + } + if (!relative.path().empty()) + { + result.append(relative.path().begin(), relative.path().end()); + } + return remove_dot_segments(jsoncons::string_view(result)); + } + + static void remove_last_segment(std::string& path) + { + auto last_slash = path.rfind('/'); + if (last_slash != std::string::npos) + { + path.erase(last_slash); + } + } + }; + +} // namespace jsoncons + +#endif -- cgit v1.2.3