aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/cbor/cbor_encoder.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons_ext/cbor/cbor_encoder.hpp')
-rw-r--r--include/jsoncons_ext/cbor/cbor_encoder.hpp1766
1 files changed, 1766 insertions, 0 deletions
diff --git a/include/jsoncons_ext/cbor/cbor_encoder.hpp b/include/jsoncons_ext/cbor/cbor_encoder.hpp
new file mode 100644
index 0000000..f4699ee
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_encoder.hpp
@@ -0,0 +1,1766 @@
+// 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_CBOR_CBOR_ENCODER_HPP
+#define JSONCONS_CBOR_CBOR_ENCODER_HPP
+
+#include <string>
+#include <vector>
+#include <limits> // std::numeric_limits
+#include <memory>
+#include <utility> // std::move
+#include <jsoncons/json_exception.hpp> // jsoncons::ser_error
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/sink.hpp>
+#include <jsoncons/detail/parse_number.hpp>
+#include <jsoncons_ext/cbor/cbor_error.hpp>
+#include <jsoncons_ext/cbor/cbor_options.hpp>
+
+namespace jsoncons { namespace cbor {
+
+enum class cbor_container_type {object, indefinite_length_object, array, indefinite_length_array};
+
+template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
+class basic_cbor_encoder final : public basic_json_visitor<char>
+{
+ using super_type = basic_json_visitor<char>;
+
+ enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 };
+ enum class hexfloat_parse_state { start, expect_0, expect_x, integer, exp1, exp2, fraction1 };
+
+ static constexpr int64_t nanos_in_second = 1000000000;
+ static constexpr int64_t millis_in_second = 1000;
+
+public:
+ using allocator_type = Allocator;
+ using sink_type = Sink;
+ using typename super_type::char_type;
+ using typename super_type::string_view_type;
+
+private:
+ using char_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<char_type>;
+ using byte_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t>;
+
+ using string_type = std::basic_string<char_type,std::char_traits<char_type>,char_allocator_type>;
+ using byte_string_type = basic_byte_string<byte_allocator_type>;
+
+ struct stack_item
+ {
+ cbor_container_type type_;
+ std::size_t length_;
+ std::size_t count_;
+
+ stack_item(cbor_container_type type, std::size_t length = 0) noexcept
+ : type_(type), length_(length), count_(0)
+ {
+ }
+
+ std::size_t length() const
+ {
+ return length_;
+ }
+
+ std::size_t count() const
+ {
+ return count_;
+ }
+
+ bool is_object() const
+ {
+ return type_ == cbor_container_type::object || type_ == cbor_container_type::indefinite_length_object;
+ }
+
+ bool is_indefinite_length() const
+ {
+ return type_ == cbor_container_type::indefinite_length_array || type_ == cbor_container_type::indefinite_length_object;
+ }
+
+ };
+
+ typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,size_t>> string_size_allocator_type;
+ typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const byte_string_type,size_t>> byte_string_size_allocator_type;
+ typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<stack_item> stack_item_allocator_type;
+
+ Sink sink_;
+ const cbor_encode_options options_;
+ allocator_type alloc_;
+
+ std::vector<stack_item,stack_item_allocator_type> stack_;
+ std::map<string_type,size_t,std::less<string_type>,string_size_allocator_type> stringref_map_;
+ std::map<byte_string_type,size_t,std::less<byte_string_type>,byte_string_size_allocator_type> bytestringref_map_;
+ std::size_t next_stringref_ = 0;
+ int nesting_depth_;
+
+ // Noncopyable and nonmoveable
+ basic_cbor_encoder(const basic_cbor_encoder&) = delete;
+ basic_cbor_encoder& operator=(const basic_cbor_encoder&) = delete;
+public:
+ explicit basic_cbor_encoder(Sink&& sink,
+ const Allocator& alloc = Allocator())
+ : basic_cbor_encoder(std::forward<Sink>(sink), cbor_encode_options(), alloc)
+ {
+ }
+ basic_cbor_encoder(Sink&& sink,
+ const cbor_encode_options& options,
+ const Allocator& alloc = Allocator())
+ : sink_(std::forward<Sink>(sink)),
+ options_(options),
+ alloc_(alloc),
+ stack_(alloc),
+#if !defined(JSONCONS_NO_MAP_CONS_TAKES_ALLOCATOR)
+ stringref_map_(alloc),
+ bytestringref_map_(alloc),
+#endif
+ nesting_depth_(0)
+ {
+ if (options.pack_strings())
+ {
+ write_tag(256);
+ }
+ }
+
+ ~basic_cbor_encoder() noexcept
+ {
+ JSONCONS_TRY
+ {
+ sink_.flush();
+ }
+ JSONCONS_CATCH(...)
+ {
+ }
+ }
+
+ void reset()
+ {
+ stack_.clear();
+ stringref_map_.clear();
+ bytestringref_map_.clear();
+ next_stringref_ = 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 = cbor_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ stack_.emplace_back(cbor_container_type::indefinite_length_object);
+
+ sink_.push_back(0xbf);
+ return true;
+ }
+
+ bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = cbor_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ stack_.emplace_back(cbor_container_type::object, length);
+
+ if (length <= 0x17)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xa0 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xb8),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xb9),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xba),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xbb),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(length),
+ std::back_inserter(sink_));
+ }
+
+ return true;
+ }
+
+ bool visit_end_object(const ser_context&, std::error_code& ec) override
+ {
+ JSONCONS_ASSERT(!stack_.empty());
+ --nesting_depth_;
+
+ if (stack_.back().is_indefinite_length())
+ {
+ sink_.push_back(0xff);
+ }
+ else
+ {
+ if (stack_.back().count() < stack_.back().length())
+ {
+ ec = cbor_errc::too_few_items;
+ return false;
+ }
+ if (stack_.back().count() > stack_.back().length())
+ {
+ ec = cbor_errc::too_many_items;
+ return false;
+ }
+ }
+
+ stack_.pop_back();
+ 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 = cbor_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ stack_.emplace_back(cbor_container_type::indefinite_length_array);
+ sink_.push_back(0x9f);
+ return true;
+ }
+
+ bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = cbor_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ stack_.emplace_back(cbor_container_type::array, length);
+ if (length <= 0x17)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x80 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x98),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x99),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x9a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x9b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(length),
+ std::back_inserter(sink_));
+ }
+ return true;
+ }
+
+ bool visit_end_array(const ser_context&, std::error_code& ec) override
+ {
+ JSONCONS_ASSERT(!stack_.empty());
+ --nesting_depth_;
+
+ if (stack_.back().is_indefinite_length())
+ {
+ sink_.push_back(0xff);
+ }
+ else
+ {
+ if (stack_.back().count() < stack_.back().length())
+ {
+ ec = cbor_errc::too_few_items;
+ return false;
+ }
+ if (stack_.back().count() > stack_.back().length())
+ {
+ ec = cbor_errc::too_many_items;
+ return false;
+ }
+ }
+
+ stack_.pop_back();
+ end_value();
+
+ return true;
+ }
+
+ bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
+ {
+ write_string(name);
+ return true;
+ }
+
+ bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override
+ {
+ if (tag == semantic_tag::undefined)
+ {
+ sink_.push_back(0xf7);
+ }
+ else
+ {
+ sink_.push_back(0xf6);
+ }
+
+ end_value();
+ return true;
+ }
+
+ void write_string(const string_view& sv)
+ {
+ auto sink = unicode_traits::validate(sv.data(), sv.size());
+ if (sink.ec != unicode_traits::conv_errc())
+ {
+ JSONCONS_THROW(ser_error(cbor_errc::invalid_utf8_text_string));
+ }
+
+ if (options_.pack_strings() && sv.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_))
+ {
+ string_type s(sv.data(), sv.size(), alloc_);
+ auto it = stringref_map_.find(s);
+ if (it == stringref_map_.end())
+ {
+ stringref_map_.emplace(std::make_pair(std::move(s), next_stringref_++));
+ write_utf8_string(sv);
+ }
+ else
+ {
+ write_tag(25);
+ write_uint64_value(it->second);
+ }
+ }
+ else
+ {
+ write_utf8_string(sv);
+ }
+ }
+
+ void write_utf8_string(const string_view& sv)
+ {
+ const size_t length = sv.size();
+
+ if (length <= 0x17)
+ {
+ // fixstr stores a byte array whose length is upto 31 bytes
+ binary::native_to_big(static_cast<uint8_t>(0x60 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x78),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x79),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x7a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x7b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(length),
+ std::back_inserter(sink_));
+ }
+
+ for (auto c : sv)
+ {
+ sink_.push_back(c);
+ }
+ }
+
+ void write_bignum(bigint& n)
+ {
+ bool is_neg = n < 0;
+ if (is_neg)
+ {
+ n = - n -1;
+ }
+
+ int signum;
+ std::vector<uint8_t> data;
+ n.write_bytes_be(signum, data);
+ std::size_t length = data.size();
+
+ if (is_neg)
+ {
+ write_tag(3);
+ }
+ else
+ {
+ write_tag(2);
+ }
+
+ if (length <= 0x17)
+ {
+ // fixstr stores a byte array whose length is upto 31 bytes
+ binary::native_to_big(static_cast<uint8_t>(0x40 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x58),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x59),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(length),
+ std::back_inserter(sink_));
+ }
+
+ for (auto c : data)
+ {
+ sink_.push_back(c);
+ }
+ }
+
+ bool write_decimal_value(const string_view_type& sv, const ser_context& context, std::error_code& ec)
+ {
+ bool more = true;
+
+ decimal_parse_state state = decimal_parse_state::start;
+ std::basic_string<char> s;
+ std::basic_string<char> exponent;
+ int64_t scale = 0;
+ for (auto c : sv)
+ {
+ switch (state)
+ {
+ case decimal_parse_state::start:
+ {
+ switch (c)
+ {
+ case '-':
+ s.push_back(c);
+ state = decimal_parse_state::integer;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
+ s.push_back(c);
+ state = decimal_parse_state::integer;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ return false;
+ }
+ }
+ break;
+ }
+ case decimal_parse_state::integer:
+ {
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
+ s.push_back(c);
+ break;
+ case 'e': case 'E':
+ state = decimal_parse_state::exp1;
+ break;
+ case '.':
+ state = decimal_parse_state::fraction1;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ return false;
+ }
+ }
+ break;
+ }
+ case decimal_parse_state::exp1:
+ {
+ switch (c)
+ {
+ case '+':
+ state = decimal_parse_state::exp2;
+ break;
+ case '-':
+ exponent.push_back(c);
+ state = decimal_parse_state::exp2;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
+ exponent.push_back(c);
+ state = decimal_parse_state::exp2;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ return false;
+ }
+ }
+ break;
+ }
+ case decimal_parse_state::exp2:
+ {
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
+ exponent.push_back(c);
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ return false;
+ }
+ }
+ break;
+ }
+ case decimal_parse_state::fraction1:
+ {
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
+ s.push_back(c);
+ --scale;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ return false;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ write_tag(4);
+ more = visit_begin_array((std::size_t)2, semantic_tag::none, context, ec);
+ if (!more) {return more;}
+ if (exponent.length() > 0)
+ {
+ int64_t val;
+ auto r = jsoncons::detail::to_integer(exponent.data(), exponent.length(), val);
+ if (!r)
+ {
+ ec = r.error_code();
+ return false;
+ }
+ scale += val;
+ }
+ more = visit_int64(scale, semantic_tag::none, context, ec);
+ if (!more) {return more;}
+
+ int64_t val{ 0 };
+ auto r = jsoncons::detail::to_integer(s.data(),s.length(), val);
+ if (r)
+ {
+ more = visit_int64(val, semantic_tag::none, context, ec);
+ if (!more) {return more;}
+ }
+ else if (r.error_code() == jsoncons::detail::to_integer_errc::overflow)
+ {
+ bigint n = bigint::from_string(s.data(), s.length());
+ write_bignum(n);
+ end_value();
+ }
+ else
+ {
+ ec = r.error_code();
+ return false;
+ }
+ more = visit_end_array(context, ec);
+
+ return more;
+ }
+
+ bool write_hexfloat_value(const string_view_type& sv, const ser_context& context, std::error_code& ec)
+ {
+ bool more = true;
+
+ hexfloat_parse_state state = hexfloat_parse_state::start;
+ std::basic_string<char> s;
+ std::basic_string<char> exponent;
+ int64_t scale = 0;
+
+ for (auto c : sv)
+ {
+ switch (state)
+ {
+ case hexfloat_parse_state::start:
+ {
+ switch (c)
+ {
+ case '-':
+ s.push_back(c);
+ state = hexfloat_parse_state::expect_0;
+ break;
+ case '0':
+ state = hexfloat_parse_state::expect_x;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ case hexfloat_parse_state::expect_0:
+ {
+ switch (c)
+ {
+ case '0':
+ state = hexfloat_parse_state::expect_x;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ case hexfloat_parse_state::expect_x:
+ {
+ switch (c)
+ {
+ case 'x':
+ case 'X':
+ state = hexfloat_parse_state::integer;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ case hexfloat_parse_state::integer:
+ {
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
+ s.push_back(c);
+ break;
+ case 'p': case 'P':
+ state = hexfloat_parse_state::exp1;
+ break;
+ case '.':
+ state = hexfloat_parse_state::fraction1;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ case hexfloat_parse_state::exp1:
+ {
+ switch (c)
+ {
+ case '+':
+ state = hexfloat_parse_state::exp2;
+ break;
+ case '-':
+ exponent.push_back(c);
+ state = hexfloat_parse_state::exp2;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
+ exponent.push_back(c);
+ state = hexfloat_parse_state::exp2;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ case hexfloat_parse_state::exp2:
+ {
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
+ exponent.push_back(c);
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ case hexfloat_parse_state::fraction1:
+ {
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
+ s.push_back(c);
+ scale -= 4;
+ break;
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ return false;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ write_tag(5);
+ more = visit_begin_array((std::size_t)2, semantic_tag::none, context, ec);
+ if (!more) return more;
+
+ if (exponent.length() > 0)
+ {
+ int64_t val{ 0 };
+ auto r = jsoncons::detail::base16_to_integer(exponent.data(), exponent.length(), val);
+ if (!r)
+ {
+ ec = r.error_code();
+ return false;
+ }
+ scale += val;
+ }
+ more = visit_int64(scale, semantic_tag::none, context, ec);
+ if (!more) return more;
+
+ int64_t val{ 0 };
+ auto r = jsoncons::detail::base16_to_integer(s.data(),s.length(), val);
+ if (r)
+ {
+ more = visit_int64(val, semantic_tag::none, context, ec);
+ if (!more) return more;
+ }
+ else if (r.error_code() == jsoncons::detail::to_integer_errc::overflow)
+ {
+ bigint n = bigint::from_string_radix(s.data(), s.length(), 16);
+ write_bignum(n);
+ end_value();
+ }
+ else
+ {
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>(r.error_code().message()));
+ }
+ return visit_end_array(context, ec);
+ }
+
+ bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::bigint:
+ {
+ bigint n = bigint::from_string(sv.data(), sv.length());
+ write_bignum(n);
+ end_value();
+ break;
+ }
+ case semantic_tag::bigdec:
+ {
+ return write_decimal_value(sv, context, ec);
+ }
+ case semantic_tag::bigfloat:
+ {
+ return write_hexfloat_value(sv, context, ec);
+ }
+ case semantic_tag::datetime:
+ {
+ write_tag(0);
+
+ write_string(sv);
+ end_value();
+ break;
+ }
+ case semantic_tag::uri:
+ {
+ write_tag(32);
+ write_string(sv);
+ end_value();
+ break;
+ }
+ case semantic_tag::base64url:
+ {
+ write_tag(33);
+ write_string(sv);
+ end_value();
+ break;
+ }
+ case semantic_tag::base64:
+ {
+ write_tag(34);
+ write_string(sv);
+ end_value();
+ break;
+ }
+ default:
+ {
+ write_string(sv);
+ end_value();
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ 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;
+ }
+ switch (encoding_hint)
+ {
+ case byte_string_chars_format::base64url:
+ write_tag(21);
+ break;
+ case byte_string_chars_format::base64:
+ write_tag(22);
+ break;
+ case byte_string_chars_format::base16:
+ write_tag(23);
+ break;
+ default:
+ break;
+ }
+ if (options_.pack_strings() && b.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_))
+ {
+ byte_string_type bs(b.data(), b.size(), alloc_);
+ auto it = bytestringref_map_.find(bs);
+ if (it == bytestringref_map_.end())
+ {
+ bytestringref_map_.emplace(std::make_pair(bs, next_stringref_++));
+ write_byte_string_value(bs);
+ }
+ else
+ {
+ write_tag(25);
+ write_uint64_value(it->second);
+ }
+ }
+ else
+ {
+ write_byte_string_value(b);
+ }
+
+ end_value();
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ uint64_t ext_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ if (options_.pack_strings() && b.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_))
+ {
+ byte_string_type bs(b.data(), b.size(), alloc_);
+ auto it = bytestringref_map_.find(bs);
+ if (it == bytestringref_map_.end())
+ {
+ bytestringref_map_.emplace(std::make_pair(bs, next_stringref_++));
+ write_tag(ext_tag);
+ write_byte_string_value(bs);
+ }
+ else
+ {
+ write_tag(25);
+ write_uint64_value(it->second);
+ }
+ }
+ else
+ {
+ write_tag(ext_tag);
+ write_byte_string_value(b);
+ }
+
+ end_value();
+ return true;
+ }
+
+ void write_byte_string_value(const byte_string_view& b)
+ {
+ if (b.size() <= 0x17)
+ {
+ // fixstr stores a byte array whose length is upto 31 bytes
+ binary::native_to_big(static_cast<uint8_t>(0x40 + b.size()),
+ std::back_inserter(sink_));
+ }
+ else if (b.size() <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x58),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+ else if (b.size() <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x59),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+ else if (b.size() <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+ else // if (b.size() <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+
+ for (auto c : b)
+ {
+ sink_.push_back(c);
+ }
+ }
+
+ bool visit_double(double val,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::epoch_second:
+ write_tag(1);
+ break;
+ case semantic_tag::epoch_milli:
+ write_tag(1);
+ if (val != 0)
+ {
+ val /= millis_in_second;
+ }
+ break;
+ case semantic_tag::epoch_nano:
+ write_tag(1);
+ if (val != 0)
+ {
+ val /= nanos_in_second;
+ }
+ break;
+ default:
+ break;
+ }
+
+ float valf = (float)val;
+ if ((double)valf == val)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xfa),
+ std::back_inserter(sink_));
+ binary::native_to_big(valf, std::back_inserter(sink_));
+ }
+ else
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xfb),
+ std::back_inserter(sink_));
+ binary::native_to_big(val, std::back_inserter(sink_));
+ }
+
+ // write double
+
+ end_value();
+ return true;
+ }
+
+ bool visit_int64(int64_t value,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::epoch_milli:
+ case semantic_tag::epoch_nano:
+ return visit_double(static_cast<double>(value), tag, context, ec);
+ case semantic_tag::epoch_second:
+ write_tag(1);
+ break;
+ default:
+ break;
+ }
+ if (value >= 0)
+ {
+ if (value <= 0x17)
+ {
+ binary::native_to_big(static_cast<uint8_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<uint8_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x18),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<uint16_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x19),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<uint32_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x1a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<int64_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x1b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<int64_t>(value),
+ std::back_inserter(sink_));
+ }
+ } else
+ {
+ const auto posnum = -1 - value;
+ if (value >= -24)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x20 + posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<uint8_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x38),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<uint16_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x39),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<uint32_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x3a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<int64_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x3b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<int64_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ }
+ end_value();
+ return true;
+ }
+
+ bool visit_uint64(uint64_t value,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::epoch_milli:
+ case semantic_tag::epoch_nano:
+ return visit_double(static_cast<double>(value), tag, context, ec);
+ case semantic_tag::epoch_second:
+ write_tag(1);
+ break;
+ default:
+ break;
+ }
+
+ write_uint64_value(value);
+ end_value();
+ return true;
+ }
+
+ void write_tag(uint64_t value)
+ {
+ if (value <= 0x17)
+ {
+ sink_.push_back(0xc0 | static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint8_t>::max)())
+ {
+ sink_.push_back(0xd8);
+ sink_.push_back(static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint16_t>::max)())
+ {
+ sink_.push_back(0xd9);
+ binary::native_to_big(static_cast<uint16_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <=(std::numeric_limits<uint32_t>::max)())
+ {
+ sink_.push_back(0xda);
+ binary::native_to_big(static_cast<uint32_t>(value),
+ std::back_inserter(sink_));
+ }
+ else
+ {
+ sink_.push_back(0xdb);
+ binary::native_to_big(static_cast<uint64_t>(value),
+ std::back_inserter(sink_));
+ }
+ }
+
+ void write_uint64_value(uint64_t value)
+ {
+ if (value <= 0x17)
+ {
+ sink_.push_back(static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint8_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x18));
+ sink_.push_back(static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint16_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x19));
+ binary::native_to_big(static_cast<uint16_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <=(std::numeric_limits<uint32_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x1a));
+ binary::native_to_big(static_cast<uint32_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <=(std::numeric_limits<uint64_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x1b));
+ binary::native_to_big(static_cast<uint64_t>(value),
+ std::back_inserter(sink_));
+ }
+ }
+
+ bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override
+ {
+ if (value)
+ {
+ sink_.push_back(0xf5);
+ }
+ else
+ {
+ sink_.push_back(0xf4);
+ }
+
+ end_value();
+ return true;
+ }
+
+ bool visit_typed_array(const jsoncons::span<const uint8_t>& v,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ switch (tag)
+ {
+ case semantic_tag::clamped:
+ write_tag(0x44);
+ break;
+ default:
+ write_tag(0x40);
+ break;
+ }
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(v.size(), semantic_tag::none, context, ec);
+ for (auto p = v.begin(); more && p != v.end(); ++p)
+ {
+ more = this->uint64_value(*p, tag, context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const uint16_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ uint16_t(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(uint16_t));
+ std::memcpy(v.data(),data.data(),data.size()*sizeof(uint16_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none, context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->uint64_value(*p, tag, context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const uint32_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ uint32_t(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(uint32_t));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(uint32_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none, context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->uint64_value(*p, semantic_tag::none, context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const uint64_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ uint64_t(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(uint64_t));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(uint64_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none, context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->uint64_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const int8_t>& data,
+ semantic_tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_tag(0x48);
+ std::vector<uint8_t> v(data.size()*sizeof(int8_t));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(int8_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none,context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->int64_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const int16_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ int16_t(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(int16_t));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(int16_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none,context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->int64_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const int32_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ int32_t(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(int32_t));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(int32_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none,context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->int64_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const int64_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ int64_t(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(int64_t));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(int64_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none,context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->int64_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(half_arg_t, const jsoncons::span<const uint16_t>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ half_arg,
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(uint16_t));
+ std::memcpy(v.data(),data.data(),data.size()*sizeof(uint16_t));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none, context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->half_value(*p, tag, context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const float>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ float(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(float));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(float));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none,context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->double_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+
+ bool visit_typed_array(const jsoncons::span<const double>& data,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ double(),
+ tag);
+ std::vector<uint8_t> v(data.size()*sizeof(double));
+ std::memcpy(v.data(), data.data(), data.size()*sizeof(double));
+ write_byte_string_value(byte_string_view(v));
+ return true;
+ }
+ else
+ {
+ bool more = this->begin_array(data.size(), semantic_tag::none,context, ec);
+ for (auto p = data.begin(); more && p != data.end(); ++p)
+ {
+ more = this->double_value(*p,semantic_tag::none,context, ec);
+ }
+ if (more)
+ {
+ more = this->end_array(context, ec);
+ }
+ return more;
+ }
+ }
+/*
+ bool visit_typed_array(const jsoncons::span<const float128_type>&,
+ semantic_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ return true;
+ }
+*/
+ bool visit_begin_multi_dim(const jsoncons::span<const size_t>& shape,
+ semantic_tag tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::multi_dim_column_major:
+ write_tag(1040);
+ break;
+ default:
+ write_tag(40);
+ break;
+ }
+ bool more = visit_begin_array(2, semantic_tag::none, context, ec);
+ if (more)
+ more = visit_begin_array(shape.size(), semantic_tag::none, context, ec);
+ for (auto it = shape.begin(); more && it != shape.end(); ++it)
+ {
+ more = visit_uint64(*it, semantic_tag::none, context, ec);
+ }
+ if (more)
+ {
+ more = visit_end_array(context, ec);
+ }
+ return more;
+ }
+
+ bool visit_end_multi_dim(const ser_context& context,
+ std::error_code& ec) override
+ {
+ bool more = visit_end_array(context, ec);
+ return more;
+ }
+
+ void write_typed_array_tag(std::true_type,
+ uint16_t,
+ semantic_tag)
+ {
+ write_tag(0x41); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ uint16_t,
+ semantic_tag)
+ {
+ write_tag(0x45);
+ }
+
+ void write_typed_array_tag(std::true_type,
+ uint32_t,
+ semantic_tag)
+ {
+ write_tag(0x42); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ uint32_t,
+ semantic_tag)
+ {
+ write_tag(0x46); // little endian
+ }
+
+ void write_typed_array_tag(std::true_type,
+ uint64_t,
+ semantic_tag)
+ {
+ write_tag(0x43); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ uint64_t,
+ semantic_tag)
+ {
+ write_tag(0x47); // little endian
+ }
+
+ void write_typed_array_tag(std::true_type,
+ int16_t,
+ semantic_tag)
+ {
+ write_tag(0x49); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ int16_t,
+ semantic_tag)
+ {
+ write_tag(0x4d); // little endian
+ }
+
+ void write_typed_array_tag(std::true_type,
+ int32_t,
+ semantic_tag)
+ {
+ write_tag(0x4a); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ int32_t,
+ semantic_tag)
+ {
+ write_tag(0x4e); // little endian
+ }
+
+ void write_typed_array_tag(std::true_type,
+ int64_t,
+ semantic_tag)
+ {
+ write_tag(0x4b); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ int64_t,
+ semantic_tag)
+ {
+ write_tag(0x4f); // little endian
+ }
+
+ void write_typed_array_tag(std::true_type,
+ half_arg_t,
+ semantic_tag)
+ {
+ write_tag(0x50);
+ }
+ void write_typed_array_tag(std::false_type,
+ half_arg_t,
+ semantic_tag)
+ {
+ write_tag(0x54);
+ }
+
+ void write_typed_array_tag(std::true_type,
+ float,
+ semantic_tag)
+ {
+ write_tag(0x51); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ float,
+ semantic_tag)
+ {
+ write_tag(0x55); // little endian
+ }
+
+ void write_typed_array_tag(std::true_type,
+ double,
+ semantic_tag)
+ {
+ write_tag(0x52); // big endian
+ }
+ void write_typed_array_tag(std::false_type,
+ double,
+ semantic_tag)
+ {
+ write_tag(0x56); // little endian
+ }
+
+ void end_value()
+ {
+ if (!stack_.empty())
+ {
+ ++stack_.back().count_;
+ }
+ }
+};
+
+using cbor_stream_encoder = basic_cbor_encoder<jsoncons::binary_stream_sink>;
+using cbor_bytes_encoder = basic_cbor_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_bytes_serializer;
+
+template<class Sink=jsoncons::binary_stream_sink>
+using basic_cbor_serializer = basic_cbor_encoder<Sink>;
+
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_encoder") typedef cbor_stream_encoder cbor_encoder;
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_encoder") typedef cbor_stream_encoder cbor_serializer;
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_buffer_serializer;
+#endif
+
+}}
+#endif