// // MessagePack for C++ static resolution routine // // Copyright (C) 2008-2014 FURUHASHI Sadayuki and KONDO Takatoshi // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef MSGPACK_OBJECT_HPP #define MSGPACK_OBJECT_HPP #include "rpc/msgpack/versioning.hpp" #include "rpc/msgpack/pack.hpp" #include "rpc/msgpack/zone.hpp" #include "rpc/msgpack/adaptor/adaptor_base.hpp" #include #include #include #include #include #include #include namespace clmdep_msgpack { /// @cond MSGPACK_API_VERSION_NAMESPACE(v1) { /// @endcond class object_handle { public: object_handle() {} object_handle(clmdep_msgpack::object const& obj, clmdep_msgpack::unique_ptr z) : m_obj(obj), m_zone(clmdep_msgpack::move(z)) { } #ifdef _MSC_VER object_handle(clmdep_msgpack::object const& obj, std::unique_ptr&& z) : m_obj(obj), m_zone(z.release()) { } #endif // obsolete void set(clmdep_msgpack::object const& obj) { m_obj = obj; } const clmdep_msgpack::object& get() const { return m_obj; } template T as() const { return m_obj.as(); } template void convert(T&& v) { m_obj.convert(std::forward(v)); } clmdep_msgpack::unique_ptr& zone() { return m_zone; } const clmdep_msgpack::unique_ptr& 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(clmdep_msgpack::move(other.m_zone)) { } object_handle(object_handle_ref ref): m_obj(ref.m_oh->m_obj), m_zone(clmdep_msgpack::move(ref.m_oh->m_zone)) { } object_handle& operator=(object_handle& other) { m_obj = other.m_obj; m_zone = clmdep_msgpack::move(other.m_zone); return *this; } object_handle& operator=(object_handle_ref ref) { m_obj = ref.m_oh->m_obj; m_zone = clmdep_msgpack::move(ref.m_oh->m_zone); return *this; } operator object_handle_ref() { return object_handle_ref(this); } #endif // defined(MSGPACK_USE_CPP03) object_handle& assign(object_handle&& other) { m_obj = other.m_obj; m_zone = clmdep_msgpack::move(other.m_zone); return *this; } private: clmdep_msgpack::object m_obj; clmdep_msgpack::unique_ptr m_zone; }; namespace detail { template 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(clmdep_msgpack::object const& obj) { std::size_t s = 0; switch (obj.type) { case clmdep_msgpack::type::ARRAY: s += sizeof(clmdep_msgpack::object) * obj.via.array.size; for (uint32_t i = 0; i < obj.via.array.size; ++i) { s += clmdep_msgpack::aligned_zone_size(obj.via.array.ptr[i]); } break; case clmdep_msgpack::type::MAP: s += sizeof(clmdep_msgpack::object_kv) * obj.via.map.size; for (uint32_t i = 0; i < obj.via.map.size; ++i) { s += clmdep_msgpack::aligned_zone_size(obj.via.map.ptr[i].key); s += clmdep_msgpack::aligned_zone_size(obj.via.map.ptr[i].val); } break; case clmdep_msgpack::type::EXT: s += clmdep_msgpack::aligned_size( detail::add_ext_type_size(obj.via.ext.size)); break; case clmdep_msgpack::type::STR: s += clmdep_msgpack::aligned_size(obj.via.str.size); break; case clmdep_msgpack::type::BIN: s += clmdep_msgpack::aligned_size(obj.via.bin.size); break; default: break; } return s; } inline object_handle clone(clmdep_msgpack::object const& obj) { std::size_t size = clmdep_msgpack::aligned_zone_size(obj); clmdep_msgpack::unique_ptr z(size == 0 ? nullptr : new clmdep_msgpack::zone(size)); clmdep_msgpack::object newobj = z.get() ? clmdep_msgpack::object(obj, *z) : obj; return object_handle(newobj, clmdep_msgpack::move(z)); } struct object::implicit_type { implicit_type(object const& o) : obj(o) { } ~implicit_type() { } template operator T() { return obj.as(); } private: clmdep_msgpack::object const& obj; }; namespace detail { template struct packer_serializer { static clmdep_msgpack::packer& pack(clmdep_msgpack::packer& o, const T& v) { v.msgpack_pack(o); return o; } }; } // namespace detail // Adaptor functors' member functions definitions. template inline clmdep_msgpack::object const& clmdep_msgpack::adaptor::convert::operator()(clmdep_msgpack::object const& o, T& v) const { v.msgpack_unpack(o.convert()); return o; } template template inline clmdep_msgpack::packer& clmdep_msgpack::adaptor::pack::operator()(clmdep_msgpack::packer& o, T const& v) const { return clmdep_msgpack::detail::packer_serializer::pack(o, v); } template inline void clmdep_msgpack::adaptor::object_with_zone::operator()(clmdep_msgpack::object::with_zone& o, T const& v) const { v.msgpack_object(static_cast(&o), o.zone); } // Adaptor functor specialization to object namespace adaptor { template <> struct convert { clmdep_msgpack::object const& operator()(clmdep_msgpack::object const& o, clmdep_msgpack::object& v) const { v = o; return o; } }; template <> struct pack { template clmdep_msgpack::packer& operator()(clmdep_msgpack::packer& o, clmdep_msgpack::object const& v) const { switch(v.type) { case clmdep_msgpack::type::NIL: o.pack_nil(); return o; case clmdep_msgpack::type::BOOLEAN: if(v.via.boolean) { o.pack_true(); } else { o.pack_false(); } return o; case clmdep_msgpack::type::POSITIVE_INTEGER: o.pack_uint64(v.via.u64); return o; case clmdep_msgpack::type::NEGATIVE_INTEGER: o.pack_int64(v.via.i64); return o; case clmdep_msgpack::type::FLOAT: o.pack_double(v.via.f64); return o; case clmdep_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 clmdep_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 clmdep_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 clmdep_msgpack::type::ARRAY: o.pack_array(v.via.array.size); for(clmdep_msgpack::object* p(v.via.array.ptr), * const pend(v.via.array.ptr + v.via.array.size); p < pend; ++p) { clmdep_msgpack::operator<<(o, *p); } return o; case clmdep_msgpack::type::MAP: o.pack_map(v.via.map.size); for(clmdep_msgpack::object_kv* p(v.via.map.ptr), * const pend(v.via.map.ptr + v.via.map.size); p < pend; ++p) { clmdep_msgpack::operator<<(o, p->key); clmdep_msgpack::operator<<(o, p->val); } return o; default: throw clmdep_msgpack::type_error(); } } }; template <> struct object_with_zone { void operator()(clmdep_msgpack::object::with_zone& o, clmdep_msgpack::object const& v) const { o.type = v.type; switch(v.type) { case clmdep_msgpack::type::NIL: case clmdep_msgpack::type::BOOLEAN: case clmdep_msgpack::type::POSITIVE_INTEGER: case clmdep_msgpack::type::NEGATIVE_INTEGER: case clmdep_msgpack::type::FLOAT: std::memcpy(&o.via, &v.via, sizeof(v.via)); return; case clmdep_msgpack::type::STR: { char* ptr = static_cast(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 clmdep_msgpack::type::BIN: { char* ptr = static_cast(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 clmdep_msgpack::type::EXT: { char* ptr = static_cast(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 clmdep_msgpack::type::ARRAY: o.via.array.ptr = static_cast(o.zone.allocate_align(sizeof(clmdep_msgpack::object) * v.via.array.size)); o.via.array.size = v.via.array.size; for (clmdep_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) clmdep_msgpack::object(*pv, o.zone); } return; case clmdep_msgpack::type::MAP: o.via.map.ptr = (clmdep_msgpack::object_kv*)o.zone.allocate_align(sizeof(clmdep_msgpack::object_kv) * v.via.map.size); o.via.map.size = v.via.map.size; for(clmdep_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) { clmdep_msgpack::object_kv* kv = new (po) clmdep_msgpack::object_kv; new (&kv->key) clmdep_msgpack::object(pv->key, o.zone); new (&kv->val) clmdep_msgpack::object(pv->val, o.zone); } return; default: throw clmdep_msgpack::type_error(); } } }; // Adaptor functor specialization to object::with_zone template <> struct object_with_zone { void operator()( clmdep_msgpack::object::with_zone& o, clmdep_msgpack::object::with_zone const& v) const { o << static_cast(v); } }; } // namespace adaptor // obsolete template class define : public Type { public: typedef Type msgpack_type; typedef define define_type; define() {} define(const msgpack_type& v) : msgpack_type(v) {} template void msgpack_pack(Packer& o) const { clmdep_msgpack::operator<<(o, static_cast(*this)); } void msgpack_unpack(object const& o) { clmdep_msgpack::operator>>(o, static_cast(*this)); } }; // deconvert operator template template inline clmdep_msgpack::packer& packer::pack(const T& v) { clmdep_msgpack::operator<<(*this, v); return *this; } inline bool operator==(const clmdep_msgpack::object& x, const clmdep_msgpack::object& y) { if(x.type != y.type) { return false; } switch(x.type) { case clmdep_msgpack::type::NIL: return true; case clmdep_msgpack::type::BOOLEAN: return x.via.boolean == y.via.boolean; case clmdep_msgpack::type::POSITIVE_INTEGER: return x.via.u64 == y.via.u64; case clmdep_msgpack::type::NEGATIVE_INTEGER: return x.via.i64 == y.via.i64; case clmdep_msgpack::type::FLOAT: return x.via.f64 == y.via.f64; case clmdep_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 clmdep_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 clmdep_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 clmdep_msgpack::type::ARRAY: if(x.via.array.size != y.via.array.size) { return false; } else if(x.via.array.size == 0) { return true; } else { clmdep_msgpack::object* px = x.via.array.ptr; clmdep_msgpack::object* const pxend = x.via.array.ptr + x.via.array.size; clmdep_msgpack::object* py = y.via.array.ptr; do { if(!(*px == *py)) { return false; } ++px; ++py; } while(px < pxend); return true; } case clmdep_msgpack::type::MAP: if(x.via.map.size != y.via.map.size) { return false; } else if(x.via.map.size == 0) { return true; } else { clmdep_msgpack::object_kv* px = x.via.map.ptr; clmdep_msgpack::object_kv* const pxend = x.via.map.ptr + x.via.map.size; clmdep_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 inline bool operator==(const clmdep_msgpack::object& x, const T& y) try { return x == clmdep_msgpack::object(y); } catch (clmdep_msgpack::type_error&) { return false; } inline bool operator!=(const clmdep_msgpack::object& x, const clmdep_msgpack::object& y) { return !(x == y); } template inline bool operator==(const T& y, const clmdep_msgpack::object& x) { return x == y; } template inline bool operator!=(const clmdep_msgpack::object& x, const T& y) { return !(x == y); } template inline bool operator!=(const T& y, const clmdep_msgpack::object& x) { return x != y; } inline clmdep_msgpack::object::implicit_type object::convert() const { return clmdep_msgpack::object::implicit_type(*this); } template inline T& object::convert(T& v) const { clmdep_msgpack::operator>>(*this, v); return v; } template inline T* object::convert(T* v) const { convert(*v); return v; } template 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 inline T object::as() const { T v; convert(v); return v; } #else // defined(MSGPACK_USE_CPP03) template inline typename std::enable_if::value, T>::type object::as() const { return clmdep_msgpack::adaptor::as()(*this); } template inline typename std::enable_if::value, T>::type object::as() const { T v; convert(v); return v; } #endif // defined(MSGPACK_USE_CPP03) inline object::object() { type = clmdep_msgpack::type::NIL; } template inline object::object(const T& v) { clmdep_msgpack::operator<<(*this, v); } template inline object& object::operator=(const T& v) { *this = object(v); return *this; } template object::object(const T& v, clmdep_msgpack::zone& z) { with_zone oz(z); clmdep_msgpack::operator<<(oz, v); type = oz.type; via = oz.via; } template object::object(const T& v, clmdep_msgpack::zone* z) { with_zone oz(*z); clmdep_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<< (clmdep_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 inline void convert(T& v, clmdep_msgpack::object const& o) { o.convert(v); } // obsolete template inline void pack(clmdep_msgpack::packer& o, const T& v) { o.pack(v); } // obsolete template inline void pack_copy(clmdep_msgpack::packer& o, T v) { pack(o, v); } template inline clmdep_msgpack::packer& operator<< (clmdep_msgpack::packer& o, const clmdep_msgpack::object& v) { switch(v.type) { case clmdep_msgpack::type::NIL: o.pack_nil(); return o; case clmdep_msgpack::type::BOOLEAN: if(v.via.boolean) { o.pack_true(); } else { o.pack_false(); } return o; case clmdep_msgpack::type::POSITIVE_INTEGER: o.pack_uint64(v.via.u64); return o; case clmdep_msgpack::type::NEGATIVE_INTEGER: o.pack_int64(v.via.i64); return o; case clmdep_msgpack::type::FLOAT: o.pack_double(v.via.f64); return o; case clmdep_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 clmdep_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 clmdep_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 clmdep_msgpack::type::ARRAY: o.pack_array(v.via.array.size); for(clmdep_msgpack::object* p(v.via.array.ptr), * const pend(v.via.array.ptr + v.via.array.size); p < pend; ++p) { clmdep_msgpack::operator<<(o, *p); } return o; case clmdep_msgpack::type::MAP: o.pack_map(v.via.map.size); for(clmdep_msgpack::object_kv* p(v.via.map.ptr), * const pend(v.via.map.ptr + v.via.map.size); p < pend; ++p) { clmdep_msgpack::operator<<(o, p->key); clmdep_msgpack::operator<<(o, p->val); } return o; default: throw clmdep_msgpack::type_error(); } } template clmdep_msgpack::packer& operator<< (clmdep_msgpack::packer& o, const clmdep_msgpack::object::with_zone& v) { return o << static_cast(v); } inline std::ostream& operator<< (std::ostream& s, const clmdep_msgpack::object& o) { switch(o.type) { case clmdep_msgpack::type::NIL: s << "nil"; break; case clmdep_msgpack::type::BOOLEAN: s << (o.via.boolean ? "true" : "false"); break; case clmdep_msgpack::type::POSITIVE_INTEGER: s << o.via.u64; break; case clmdep_msgpack::type::NEGATIVE_INTEGER: s << o.via.i64; break; case clmdep_msgpack::type::FLOAT: s << o.via.f64; break; case clmdep_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(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 clmdep_msgpack::type::BIN: (s << '"').write(o.via.bin.ptr, o.via.bin.size) << '"'; break; case clmdep_msgpack::type::EXT: s << "EXT"; break; case clmdep_msgpack::type::ARRAY: s << "["; if(o.via.array.size != 0) { clmdep_msgpack::object* p(o.via.array.ptr); s << *p; ++p; for(clmdep_msgpack::object* const pend(o.via.array.ptr + o.via.array.size); p < pend; ++p) { s << ", " << *p; } } s << "]"; break; case clmdep_msgpack::type::MAP: s << "{"; if(o.via.map.size != 0) { clmdep_msgpack::object_kv* p(o.via.map.ptr); s << p->key << ':' << p->val; ++p; for(clmdep_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 << "#(o.type) << ">"; } return s; } /// @cond } // MSGPACK_API_VERSION_NAMESPACE(v1) /// @endcond } // namespace clmdep_msgpack #include "rpc/msgpack/type.hpp" #endif /* msgpack/object.hpp */