From 1d055261b4144dbf86b2658437015b15d4dd9bff Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 4 Sep 2022 00:32:56 +0100 Subject: initial --- include/jsoncons/decode_traits.hpp | 651 +++++++++++++++++++++++++++++++++++++ 1 file changed, 651 insertions(+) create mode 100644 include/jsoncons/decode_traits.hpp (limited to 'include/jsoncons/decode_traits.hpp') 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 + -- cgit v1.2.3