| // |
| // MessagePack for C++ static resolution routine |
| // |
| // Copyright (C) 2008-2014 FURUHASHI Sadayuki and KONDO Takatoshi |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| // (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| #ifndef MSGPACK_OBJECT_HPP |
| #define MSGPACK_OBJECT_HPP |
| |
| #include "msgpack/versioning.hpp" |
| #include "msgpack/pack.hpp" |
| #include "msgpack/zone.hpp" |
| #include "msgpack/adaptor/adaptor_base.hpp" |
| |
| #include <cstring> |
| #include <stdexcept> |
| #include <typeinfo> |
| #include <limits> |
| #include <ostream> |
| #include <typeinfo> |
| #include <iomanip> |
| |
| namespace msgpack { |
| |
| /// @cond |
| MSGPACK_API_VERSION_NAMESPACE(v1) { |
| /// @endcond |
| |
| /// The class holds object and zone |
| class object_handle { |
| public: |
| /// Constructor that creates nil object and null zone. |
| object_handle() {} |
| |
| /// Constructor that creates an object_handle holding object `obj` and zone `z`. |
| /** |
| * @param obj object |
| * @param z zone |
| */ |
| object_handle(msgpack::object const& obj, msgpack::unique_ptr<msgpack::zone> z) : |
| m_obj(obj), m_zone(msgpack::move(z)) { } |
| |
| // obsolete |
| void set(msgpack::object const& obj) |
| { m_obj = obj; } |
| |
| /// Get object reference |
| /** |
| * @return object |
| */ |
| const msgpack::object& get() const |
| { return m_obj; } |
| |
| /// Get unique_ptr reference of zone. |
| /** |
| * @return unique_ptr reference of zone |
| */ |
| msgpack::unique_ptr<msgpack::zone>& zone() |
| { return m_zone; } |
| |
| /// Get unique_ptr const reference of zone. |
| /** |
| * @return unique_ptr const reference of zone |
| */ |
| const msgpack::unique_ptr<msgpack::zone>& zone() const |
| { return m_zone; } |
| |
| #if defined(MSGPACK_USE_CPP03) |
| struct object_handle_ref { |
| object_handle_ref(object_handle* oh):m_oh(oh) {} |
| object_handle* m_oh; |
| }; |
| |
| object_handle(object_handle& other): |
| m_obj(other.m_obj), |
| m_zone(msgpack::move(other.m_zone)) { |
| } |
| |
| object_handle(object_handle_ref ref): |
| m_obj(ref.m_oh->m_obj), |
| m_zone(msgpack::move(ref.m_oh->m_zone)) { |
| } |
| |
| object_handle& operator=(object_handle& other) { |
| m_obj = other.m_obj; |
| m_zone = msgpack::move(other.m_zone); |
| return *this; |
| } |
| |
| object_handle& operator=(object_handle_ref ref) { |
| m_obj = ref.m_oh->m_obj; |
| m_zone = msgpack::move(ref.m_oh->m_zone); |
| return *this; |
| } |
| |
| operator object_handle_ref() { |
| return object_handle_ref(this); |
| } |
| #endif // defined(MSGPACK_USE_CPP03) |
| |
| private: |
| msgpack::object m_obj; |
| msgpack::unique_ptr<msgpack::zone> m_zone; |
| }; |
| |
| namespace detail { |
| |
| template <std::size_t N> |
| inline std::size_t add_ext_type_size(std::size_t size) { |
| return size + 1; |
| } |
| |
| template <> |
| inline std::size_t add_ext_type_size<4>(std::size_t size) { |
| return size == 0xffffffff ? size : size + 1; |
| } |
| |
| } // namespace detail |
| |
| inline std::size_t aligned_zone_size(msgpack::object const& obj) { |
| std::size_t s = 0; |
| switch (obj.type) { |
| case msgpack::type::ARRAY: |
| s += sizeof(msgpack::object) * obj.via.array.size; |
| for (uint32_t i = 0; i < obj.via.array.size; ++i) { |
| s += msgpack::aligned_zone_size(obj.via.array.ptr[i]); |
| } |
| break; |
| case msgpack::type::MAP: |
| s += sizeof(msgpack::object_kv) * obj.via.map.size; |
| for (uint32_t i = 0; i < obj.via.map.size; ++i) { |
| s += msgpack::aligned_zone_size(obj.via.map.ptr[i].key); |
| s += msgpack::aligned_zone_size(obj.via.map.ptr[i].val); |
| } |
| break; |
| case msgpack::type::EXT: |
| s += msgpack::aligned_size( |
| detail::add_ext_type_size<sizeof(std::size_t)>(obj.via.ext.size)); |
| break; |
| case msgpack::type::STR: |
| s += msgpack::aligned_size(obj.via.str.size); |
| break; |
| case msgpack::type::BIN: |
| s += msgpack::aligned_size(obj.via.bin.size); |
| break; |
| default: |
| break; |
| } |
| return s; |
| } |
| |
| /// clone object |
| /** |
| * Clone (deep copy) object. |
| * The copied object is located on newly allocated zone. |
| * @param obj copy source object |
| * |
| * @return object_handle that holds deep copied object and zone. |
| */ |
| inline object_handle clone(msgpack::object const& obj) { |
| std::size_t size = msgpack::aligned_zone_size(obj); |
| msgpack::unique_ptr<msgpack::zone> z(size == 0 ? nullptr : new msgpack::zone(size)); |
| msgpack::object newobj = z.get() ? msgpack::object(obj, *z) : obj; |
| return object_handle(newobj, msgpack::move(z)); |
| } |
| |
| struct object::implicit_type { |
| implicit_type(object const& o) : obj(o) { } |
| ~implicit_type() { } |
| |
| template <typename T> |
| operator T() { return obj.as<T>(); } |
| |
| private: |
| msgpack::object const& obj; |
| }; |
| |
| namespace detail { |
| template <typename Stream, typename T> |
| struct packer_serializer { |
| static msgpack::packer<Stream>& pack(msgpack::packer<Stream>& o, const T& v) { |
| v.msgpack_pack(o); |
| return o; |
| } |
| }; |
| } // namespace detail |
| |
| // Adaptor functors' member functions definitions. |
| template <typename T, typename Enabler> |
| inline |
| msgpack::object const& |
| msgpack::adaptor::convert<T, Enabler>::operator()(msgpack::object const& o, T& v) const { |
| v.msgpack_unpack(o.convert()); |
| return o; |
| } |
| |
| template <typename T, typename Enabler> |
| template <typename Stream> |
| inline |
| msgpack::packer<Stream>& |
| msgpack::adaptor::pack<T, Enabler>::operator()(msgpack::packer<Stream>& o, T const& v) const { |
| return msgpack::detail::packer_serializer<Stream, T>::pack(o, v); |
| } |
| |
| template <typename T, typename Enabler> |
| inline |
| void |
| msgpack::adaptor::object_with_zone<T, Enabler>::operator()(msgpack::object::with_zone& o, T const& v) const { |
| v.msgpack_object(static_cast<msgpack::object*>(&o), o.zone); |
| } |
| |
| // Adaptor functor specialization to object |
| namespace adaptor { |
| |
| template <> |
| struct convert<msgpack::object> { |
| msgpack::object const& operator()(msgpack::object const& o, msgpack::object& v) const { |
| v = o; |
| return o; |
| } |
| }; |
| |
| template <> |
| struct pack<msgpack::object> { |
| template <typename Stream> |
| msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, msgpack::object const& v) const { |
| switch(v.type) { |
| case msgpack::type::NIL: |
| o.pack_nil(); |
| return o; |
| |
| case msgpack::type::BOOLEAN: |
| if(v.via.boolean) { |
| o.pack_true(); |
| } else { |
| o.pack_false(); |
| } |
| return o; |
| |
| case msgpack::type::POSITIVE_INTEGER: |
| o.pack_uint64(v.via.u64); |
| return o; |
| |
| case msgpack::type::NEGATIVE_INTEGER: |
| o.pack_int64(v.via.i64); |
| return o; |
| |
| case msgpack::type::FLOAT: |
| o.pack_double(v.via.f64); |
| return o; |
| |
| case msgpack::type::STR: |
| o.pack_str(v.via.str.size); |
| o.pack_str_body(v.via.str.ptr, v.via.str.size); |
| return o; |
| |
| case msgpack::type::BIN: |
| o.pack_bin(v.via.bin.size); |
| o.pack_bin_body(v.via.bin.ptr, v.via.bin.size); |
| return o; |
| |
| case msgpack::type::EXT: |
| o.pack_ext(v.via.ext.size, v.via.ext.type()); |
| o.pack_ext_body(v.via.ext.data(), v.via.ext.size); |
| return o; |
| |
| case msgpack::type::ARRAY: |
| o.pack_array(v.via.array.size); |
| for(msgpack::object* p(v.via.array.ptr), |
| * const pend(v.via.array.ptr + v.via.array.size); |
| p < pend; ++p) { |
| msgpack::operator<<(o, *p); |
| } |
| return o; |
| |
| case msgpack::type::MAP: |
| o.pack_map(v.via.map.size); |
| for(msgpack::object_kv* p(v.via.map.ptr), |
| * const pend(v.via.map.ptr + v.via.map.size); |
| p < pend; ++p) { |
| msgpack::operator<<(o, p->key); |
| msgpack::operator<<(o, p->val); |
| } |
| return o; |
| |
| default: |
| throw msgpack::type_error(); |
| } |
| } |
| }; |
| |
| template <> |
| struct object_with_zone<msgpack::object> { |
| void operator()(msgpack::object::with_zone& o, msgpack::object const& v) const { |
| o.type = v.type; |
| |
| switch(v.type) { |
| case msgpack::type::NIL: |
| case msgpack::type::BOOLEAN: |
| case msgpack::type::POSITIVE_INTEGER: |
| case msgpack::type::NEGATIVE_INTEGER: |
| case msgpack::type::FLOAT: |
| std::memcpy(&o.via, &v.via, sizeof(v.via)); |
| return; |
| |
| case msgpack::type::STR: { |
| char* ptr = static_cast<char*>(o.zone.allocate_align(v.via.str.size)); |
| o.via.str.ptr = ptr; |
| o.via.str.size = v.via.str.size; |
| std::memcpy(ptr, v.via.str.ptr, v.via.str.size); |
| return; |
| } |
| |
| case msgpack::type::BIN: { |
| char* ptr = static_cast<char*>(o.zone.allocate_align(v.via.bin.size)); |
| o.via.bin.ptr = ptr; |
| o.via.bin.size = v.via.bin.size; |
| std::memcpy(ptr, v.via.bin.ptr, v.via.bin.size); |
| return; |
| } |
| |
| case msgpack::type::EXT: { |
| char* ptr = static_cast<char*>(o.zone.allocate_align(v.via.ext.size + 1)); |
| o.via.ext.ptr = ptr; |
| o.via.ext.size = v.via.ext.size; |
| std::memcpy(ptr, v.via.ext.ptr, v.via.ext.size + 1); |
| return; |
| } |
| |
| case msgpack::type::ARRAY: |
| o.via.array.ptr = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object) * v.via.array.size)); |
| o.via.array.size = v.via.array.size; |
| for (msgpack::object |
| * po(o.via.array.ptr), |
| * pv(v.via.array.ptr), |
| * const pvend(v.via.array.ptr + v.via.array.size); |
| pv < pvend; |
| ++po, ++pv) { |
| new (po) msgpack::object(*pv, o.zone); |
| } |
| return; |
| |
| case msgpack::type::MAP: |
| o.via.map.ptr = (msgpack::object_kv*)o.zone.allocate_align(sizeof(msgpack::object_kv) * v.via.map.size); |
| o.via.map.size = v.via.map.size; |
| for(msgpack::object_kv |
| * po(o.via.map.ptr), |
| * pv(v.via.map.ptr), |
| * const pvend(v.via.map.ptr + v.via.map.size); |
| pv < pvend; |
| ++po, ++pv) { |
| msgpack::object_kv* kv = new (po) msgpack::object_kv; |
| new (&kv->key) msgpack::object(pv->key, o.zone); |
| new (&kv->val) msgpack::object(pv->val, o.zone); |
| } |
| return; |
| |
| default: |
| throw msgpack::type_error(); |
| } |
| |
| } |
| }; |
| |
| // Adaptor functor specialization to object::with_zone |
| |
| template <> |
| struct object_with_zone<msgpack::object::with_zone> { |
| void operator()( |
| msgpack::object::with_zone& o, |
| msgpack::object::with_zone const& v) const { |
| o << static_cast<msgpack::object const&>(v); |
| } |
| }; |
| |
| |
| } // namespace adaptor |
| |
| |
| // obsolete |
| template <typename Type> |
| class define : public Type { |
| public: |
| typedef Type msgpack_type; |
| typedef define<Type> define_type; |
| |
| define() {} |
| define(const msgpack_type& v) : msgpack_type(v) {} |
| |
| template <typename Packer> |
| void msgpack_pack(Packer& o) const |
| { |
| msgpack::operator<<(o, static_cast<const msgpack_type&>(*this)); |
| } |
| |
| void msgpack_unpack(object const& o) |
| { |
| msgpack::operator>>(o, static_cast<msgpack_type&>(*this)); |
| } |
| }; |
| |
| // deconvert operator |
| |
| template <typename Stream> |
| template <typename T> |
| inline msgpack::packer<Stream>& packer<Stream>::pack(const T& v) |
| { |
| msgpack::operator<<(*this, v); |
| return *this; |
| } |
| |
| inline bool operator==(const msgpack::object& x, const msgpack::object& y) |
| { |
| if(x.type != y.type) { return false; } |
| |
| switch(x.type) { |
| case msgpack::type::NIL: |
| return true; |
| |
| case msgpack::type::BOOLEAN: |
| return x.via.boolean == y.via.boolean; |
| |
| case msgpack::type::POSITIVE_INTEGER: |
| return x.via.u64 == y.via.u64; |
| |
| case msgpack::type::NEGATIVE_INTEGER: |
| return x.via.i64 == y.via.i64; |
| |
| case msgpack::type::FLOAT: |
| return x.via.f64 == y.via.f64; |
| |
| case msgpack::type::STR: |
| return x.via.str.size == y.via.str.size && |
| std::memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0; |
| |
| case msgpack::type::BIN: |
| return x.via.bin.size == y.via.bin.size && |
| std::memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0; |
| |
| case msgpack::type::EXT: |
| return x.via.ext.size == y.via.ext.size && |
| std::memcmp(x.via.ext.ptr, y.via.ext.ptr, x.via.ext.size) == 0; |
| |
| case msgpack::type::ARRAY: |
| if(x.via.array.size != y.via.array.size) { |
| return false; |
| } else if(x.via.array.size == 0) { |
| return true; |
| } else { |
| msgpack::object* px = x.via.array.ptr; |
| msgpack::object* const pxend = x.via.array.ptr + x.via.array.size; |
| msgpack::object* py = y.via.array.ptr; |
| do { |
| if(!(*px == *py)) { |
| return false; |
| } |
| ++px; |
| ++py; |
| } while(px < pxend); |
| return true; |
| } |
| |
| case msgpack::type::MAP: |
| if(x.via.map.size != y.via.map.size) { |
| return false; |
| } else if(x.via.map.size == 0) { |
| return true; |
| } else { |
| msgpack::object_kv* px = x.via.map.ptr; |
| msgpack::object_kv* const pxend = x.via.map.ptr + x.via.map.size; |
| msgpack::object_kv* py = y.via.map.ptr; |
| do { |
| if(!(px->key == py->key) || !(px->val == py->val)) { |
| return false; |
| } |
| ++px; |
| ++py; |
| } while(px < pxend); |
| return true; |
| } |
| |
| default: |
| return false; |
| } |
| } |
| |
| template <typename T> |
| inline bool operator==(const msgpack::object& x, const T& y) |
| try { |
| return x == msgpack::object(y); |
| } catch (msgpack::type_error&) { |
| return false; |
| } |
| |
| inline bool operator!=(const msgpack::object& x, const msgpack::object& y) |
| { return !(x == y); } |
| |
| template <typename T> |
| inline bool operator==(const T& y, const msgpack::object& x) |
| { return x == y; } |
| |
| template <typename T> |
| inline bool operator!=(const msgpack::object& x, const T& y) |
| { return !(x == y); } |
| |
| template <typename T> |
| inline bool operator!=(const T& y, const msgpack::object& x) |
| { return x != y; } |
| |
| |
| inline msgpack::object::implicit_type object::convert() const |
| { |
| return msgpack::object::implicit_type(*this); |
| } |
| |
| template <typename T> |
| inline T& object::convert(T& v) const |
| { |
| msgpack::operator>>(*this, v); |
| return v; |
| } |
| |
| #if !defined(MSGPACK_DISABLE_LEGACY_CONVERT) |
| template <typename T> |
| inline T* object::convert(T* v) const |
| { |
| convert(*v); |
| return v; |
| } |
| #endif // !defined(MSGPACK_DISABLE_LEGACY_CONVERT) |
| |
| template <typename T> |
| inline bool object::convert_if_not_nil(T& v) const |
| { |
| if (is_nil()) { |
| return false; |
| } |
| convert(v); |
| return true; |
| } |
| |
| #if defined(MSGPACK_USE_CPP03) |
| |
| template <typename T> |
| inline T object::as() const |
| { |
| T v; |
| convert(v); |
| return v; |
| } |
| |
| #else // defined(MSGPACK_USE_CPP03) |
| |
| template <typename T> |
| inline typename std::enable_if<msgpack::has_as<T>::value, T>::type object::as() const { |
| return msgpack::adaptor::as<T>()(*this); |
| } |
| |
| template <typename T> |
| inline typename std::enable_if<!msgpack::has_as<T>::value, T>::type object::as() const { |
| T v; |
| convert(v); |
| return v; |
| } |
| |
| #endif // defined(MSGPACK_USE_CPP03) |
| |
| inline object::object() |
| { |
| type = msgpack::type::NIL; |
| } |
| |
| template <typename T> |
| inline object::object(const T& v) |
| { |
| msgpack::operator<<(*this, v); |
| } |
| |
| template <typename T> |
| inline object& object::operator=(const T& v) |
| { |
| *this = object(v); |
| return *this; |
| } |
| |
| template <typename T> |
| object::object(const T& v, msgpack::zone& z) |
| { |
| with_zone oz(z); |
| msgpack::operator<<(oz, v); |
| type = oz.type; |
| via = oz.via; |
| } |
| |
| template <typename T> |
| object::object(const T& v, msgpack::zone* z) |
| { |
| with_zone oz(*z); |
| msgpack::operator<<(oz, v); |
| type = oz.type; |
| via = oz.via; |
| } |
| |
| |
| inline object::object(const msgpack_object& o) |
| { |
| // FIXME beter way? |
| std::memcpy(this, &o, sizeof(o)); |
| } |
| |
| inline void operator<< (msgpack::object& o, const msgpack_object& v) |
| { |
| // FIXME beter way? |
| std::memcpy(&o, &v, sizeof(v)); |
| } |
| |
| inline object::operator msgpack_object() const |
| { |
| // FIXME beter way? |
| msgpack_object obj; |
| std::memcpy(&obj, this, sizeof(obj)); |
| return obj; |
| } |
| |
| |
| // obsolete |
| template <typename T> |
| inline void convert(T& v, msgpack::object const& o) |
| { |
| o.convert(v); |
| } |
| |
| // obsolete |
| template <typename Stream, typename T> |
| inline void pack(msgpack::packer<Stream>& o, const T& v) |
| { |
| o.pack(v); |
| } |
| |
| // obsolete |
| template <typename Stream, typename T> |
| inline void pack_copy(msgpack::packer<Stream>& o, T v) |
| { |
| pack(o, v); |
| } |
| |
| |
| template <typename Stream> |
| inline msgpack::packer<Stream>& operator<< (msgpack::packer<Stream>& o, const msgpack::object& v) |
| { |
| switch(v.type) { |
| case msgpack::type::NIL: |
| o.pack_nil(); |
| return o; |
| |
| case msgpack::type::BOOLEAN: |
| if(v.via.boolean) { |
| o.pack_true(); |
| } else { |
| o.pack_false(); |
| } |
| return o; |
| |
| case msgpack::type::POSITIVE_INTEGER: |
| o.pack_uint64(v.via.u64); |
| return o; |
| |
| case msgpack::type::NEGATIVE_INTEGER: |
| o.pack_int64(v.via.i64); |
| return o; |
| |
| case msgpack::type::FLOAT: |
| o.pack_double(v.via.f64); |
| return o; |
| |
| case msgpack::type::STR: |
| o.pack_str(v.via.str.size); |
| o.pack_str_body(v.via.str.ptr, v.via.str.size); |
| return o; |
| |
| case msgpack::type::BIN: |
| o.pack_bin(v.via.bin.size); |
| o.pack_bin_body(v.via.bin.ptr, v.via.bin.size); |
| return o; |
| |
| case msgpack::type::EXT: |
| o.pack_ext(v.via.ext.size, v.via.ext.type()); |
| o.pack_ext_body(v.via.ext.data(), v.via.ext.size); |
| return o; |
| |
| case msgpack::type::ARRAY: |
| o.pack_array(v.via.array.size); |
| for(msgpack::object* p(v.via.array.ptr), |
| * const pend(v.via.array.ptr + v.via.array.size); |
| p < pend; ++p) { |
| msgpack::operator<<(o, *p); |
| } |
| return o; |
| |
| case msgpack::type::MAP: |
| o.pack_map(v.via.map.size); |
| for(msgpack::object_kv* p(v.via.map.ptr), |
| * const pend(v.via.map.ptr + v.via.map.size); |
| p < pend; ++p) { |
| msgpack::operator<<(o, p->key); |
| msgpack::operator<<(o, p->val); |
| } |
| return o; |
| |
| default: |
| throw msgpack::type_error(); |
| } |
| } |
| |
| template <typename Stream> |
| msgpack::packer<Stream>& operator<< (msgpack::packer<Stream>& o, const msgpack::object::with_zone& v) |
| { |
| return o << static_cast<msgpack::object>(v); |
| } |
| |
| inline std::ostream& operator<< (std::ostream& s, const msgpack::object& o) |
| { |
| switch(o.type) { |
| case msgpack::type::NIL: |
| s << "nil"; |
| break; |
| |
| case msgpack::type::BOOLEAN: |
| s << (o.via.boolean ? "true" : "false"); |
| break; |
| |
| case msgpack::type::POSITIVE_INTEGER: |
| s << o.via.u64; |
| break; |
| |
| case msgpack::type::NEGATIVE_INTEGER: |
| s << o.via.i64; |
| break; |
| |
| case msgpack::type::FLOAT: |
| s << o.via.f64; |
| break; |
| |
| case msgpack::type::STR: |
| s << '"'; |
| for (uint32_t i = 0; i < o.via.str.size; ++i) { |
| char c = o.via.str.ptr[i]; |
| switch (c) { |
| case '\\': |
| s << "\\\\"; |
| break; |
| case '"': |
| s << "\\\""; |
| break; |
| case '/': |
| s << "\\/"; |
| break; |
| case '\b': |
| s << "\\b"; |
| break; |
| case '\f': |
| s << "\\f"; |
| break; |
| case '\n': |
| s << "\\n"; |
| break; |
| case '\r': |
| s << "\\r"; |
| break; |
| case '\t': |
| s << "\\t"; |
| break; |
| default: { |
| unsigned int code = static_cast<unsigned int>(c); |
| if (code < 0x20 || code == 0x7f) { |
| s << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (code & 0xff); |
| } |
| else { |
| s << c; |
| } |
| } break; |
| } |
| } |
| s << '"'; |
| break; |
| |
| case msgpack::type::BIN: |
| (s << '"').write(o.via.bin.ptr, o.via.bin.size) << '"'; |
| break; |
| |
| case msgpack::type::EXT: |
| s << "EXT"; |
| break; |
| |
| case msgpack::type::ARRAY: |
| s << "["; |
| if(o.via.array.size != 0) { |
| msgpack::object* p(o.via.array.ptr); |
| s << *p; |
| ++p; |
| for(msgpack::object* const pend(o.via.array.ptr + o.via.array.size); |
| p < pend; ++p) { |
| s << ", " << *p; |
| } |
| } |
| s << "]"; |
| break; |
| |
| case msgpack::type::MAP: |
| s << "{"; |
| if(o.via.map.size != 0) { |
| msgpack::object_kv* p(o.via.map.ptr); |
| s << p->key << ':' << p->val; |
| ++p; |
| for(msgpack::object_kv* const pend(o.via.map.ptr + o.via.map.size); |
| p < pend; ++p) { |
| s << ", " << p->key << ':' << p->val; |
| } |
| } |
| s << "}"; |
| break; |
| |
| default: |
| // FIXME |
| s << "#<UNKNOWN " << static_cast<uint16_t>(o.type) << ">"; |
| } |
| return s; |
| } |
| |
| /// @cond |
| } // MSGPACK_API_VERSION_NAMESPACE(v1) |
| /// @endcond |
| |
| } // namespace msgpack |
| |
| #include "msgpack/type.hpp" |
| |
| #endif /* msgpack/object.hpp */ |