// // MessagePack for C++ static resolution routine // // Copyright (C) 2015-2016 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_V1_TYPE_EXT_HPP #define MSGPACK_V1_TYPE_EXT_HPP #include "rpc/msgpack/v1/adaptor/ext_decl.hpp" #include "rpc/msgpack/adaptor/check_container_size.hpp" #include #include #include namespace clmdep_msgpack { /// @cond MSGPACK_API_VERSION_NAMESPACE(v1) { /// @endcond namespace type { class ext { public: ext() : m_data(1, 0) {} ext(int8_t t, const char* p, uint32_t s) { clmdep_msgpack::detail::check_container_size_for_ext(s); m_data.reserve(static_cast(s) + 1); m_data.push_back(static_cast(t)); m_data.insert(m_data.end(), p, p + s); } ext(int8_t t, uint32_t s) { clmdep_msgpack::detail::check_container_size_for_ext(s); m_data.resize(static_cast(s) + 1); m_data[0] = static_cast(t); } ext(ext_ref const&); int8_t type() const { return static_cast(m_data[0]); } const char* data() const { return &m_data[1]; } char* data() { return &m_data[1]; } uint32_t size() const { return static_cast(m_data.size()) - 1; } bool operator== (const ext& x) const { return m_data == x.m_data; } bool operator!= (const ext& x) const { return !(*this == x); } bool operator< (const ext& x) const { return m_data < x.m_data; } bool operator> (const ext& x) const { return m_data > x.m_data; } private: std::vector m_data; friend class ext_ref; }; } // namespace type namespace adaptor { template <> struct convert { clmdep_msgpack::object const& operator()(clmdep_msgpack::object const& o, clmdep_msgpack::type::ext& v) const { if(o.type != clmdep_msgpack::type::EXT) { throw clmdep_msgpack::type_error(); } v = clmdep_msgpack::type::ext(o.via.ext.type(), o.via.ext.data(), o.via.ext.size); return o; } }; template <> struct pack { template clmdep_msgpack::packer& operator()(clmdep_msgpack::packer& o, const clmdep_msgpack::type::ext& v) const { // size limit has already been checked at ext's constructor uint32_t size = v.size(); o.pack_ext(size, v.type()); o.pack_ext_body(v.data(), size); return o; } }; template <> struct object_with_zone { void operator()(clmdep_msgpack::object::with_zone& o, const clmdep_msgpack::type::ext& v) const { // size limit has already been checked at ext's constructor uint32_t size = v.size(); o.type = clmdep_msgpack::type::EXT; char* ptr = static_cast(o.zone.allocate_align(size + 1, MSGPACK_ZONE_ALIGNOF(char))); o.via.ext.ptr = ptr; o.via.ext.size = size; ptr[0] = static_cast(v.type()); std::memcpy(ptr + 1, v.data(), size); } }; } // namespace adaptor namespace type { class ext_ref { public: // ext_ref should be default constructible to support 'convert'. // A default constructed ext_ref object::m_ptr doesn't have the buffer to point to. // In order to avoid nullptr checking branches, m_ptr points to m_size. // So type() returns unspecified but valid value. It might be a zero because m_size // is initialized as zero, but shouldn't assume that. ext_ref() : m_ptr(static_cast(static_cast(&m_size))), m_size(0) {} ext_ref(const char* p, uint32_t s) : m_ptr(s == 0 ? static_cast(static_cast(&m_size)) : p), m_size(s == 0 ? 0 : s - 1) { clmdep_msgpack::detail::check_container_size_for_ext(s); } // size limit has already been checked at ext's constructor ext_ref(ext const& x) : m_ptr(&x.m_data[0]), m_size(x.size()) {} const char* data() const { return m_ptr + 1; } uint32_t size() const { return m_size; } int8_t type() const { return static_cast(m_ptr[0]); } std::string str() const { return std::string(m_ptr + 1, m_size); } bool operator== (const ext_ref& x) const { return m_size == x.m_size && std::memcmp(m_ptr, x.m_ptr, m_size) == 0; } bool operator!= (const ext_ref& x) const { return !(*this == x); } bool operator< (const ext_ref& x) const { if (m_size < x.m_size) return true; if (m_size > x.m_size) return false; return std::memcmp(m_ptr, x.m_ptr, m_size) < 0; } bool operator> (const ext_ref& x) const { if (m_size > x.m_size) return true; if (m_size < x.m_size) return false; return std::memcmp(m_ptr, x.m_ptr, m_size) > 0; } private: const char* m_ptr; uint32_t m_size; friend struct adaptor::object; }; inline ext::ext(ext_ref const& x) { // size limit has already been checked at ext_ref's constructor m_data.reserve(x.size() + 1); m_data.push_back(x.type()); m_data.insert(m_data.end(), x.data(), x.data() + x.size()); } } // namespace type namespace adaptor { template <> struct convert { clmdep_msgpack::object const& operator()(clmdep_msgpack::object const& o, clmdep_msgpack::type::ext_ref& v) const { if(o.type != clmdep_msgpack::type::EXT) { throw clmdep_msgpack::type_error(); } v = clmdep_msgpack::type::ext_ref(o.via.ext.ptr, o.via.ext.size + 1); return o; } }; template <> struct pack { template clmdep_msgpack::packer& operator()(clmdep_msgpack::packer& o, const clmdep_msgpack::type::ext_ref& v) const { // size limit has already been checked at ext_ref's constructor uint32_t size = v.size(); o.pack_ext(size, v.type()); o.pack_ext_body(v.data(), size); return o; } }; template <> struct object { void operator()(clmdep_msgpack::object& o, const clmdep_msgpack::type::ext_ref& v) const { // size limit has already been checked at ext_ref's constructor uint32_t size = v.size(); o.type = clmdep_msgpack::type::EXT; o.via.ext.ptr = v.m_ptr; o.via.ext.size = size; } }; template <> struct object_with_zone { void operator()(clmdep_msgpack::object::with_zone& o, const clmdep_msgpack::type::ext_ref& v) const { static_cast(o) << v; } }; } // namespace adaptor /// @cond } // MSGPACK_API_VERSION_NAMESPACE(v1) /// @endcond } // namespace clmdep_msgpack #endif // MSGPACK_V1_TYPE_EXT_HPP