// // MessagePack for C++ static resolution routine // // Copyright (C) 2008-2010 FURUHASHI Sadayuki // // 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 "object.h" #include "pack.hpp" #include "zone.hpp" #include #include #include #include #include namespace msgpack { class type_error : public std::bad_cast { }; namespace type { enum object_type { NIL = MSGPACK_OBJECT_NIL, BOOLEAN = MSGPACK_OBJECT_BOOLEAN, POSITIVE_INTEGER = MSGPACK_OBJECT_POSITIVE_INTEGER, NEGATIVE_INTEGER = MSGPACK_OBJECT_NEGATIVE_INTEGER, DOUBLE = MSGPACK_OBJECT_DOUBLE, STR = MSGPACK_OBJECT_STR, BIN = MSGPACK_OBJECT_BIN, ARRAY = MSGPACK_OBJECT_ARRAY, MAP = MSGPACK_OBJECT_MAP }; } struct object; struct object_kv; struct object_array { uint32_t size; object* ptr; }; struct object_map { uint32_t size; object_kv* ptr; }; struct object_str { uint32_t size; const char* ptr; }; struct object_bin { uint32_t size; const char* ptr; }; struct object { union union_type { bool boolean; uint64_t u64; int64_t i64; double dec; object_array array; object_map map; object_str str; object_bin bin; }; type::object_type type; union_type via; bool is_nil() const { return type == type::NIL; } template T as() const; template void convert(T& v) const; template void convert(T* v) const; object(); object(msgpack_object o); template explicit object(const T& v); template object(const T& v, zone* z); template object& operator=(const T& v); operator msgpack_object() const; struct with_zone; private: struct implicit_type; public: implicit_type convert() const; }; struct object_kv { object key; object val; }; struct object::with_zone : object { with_zone(msgpack::zone* zone) : zone(zone) { } msgpack::zone* zone; private: with_zone(); }; struct object::implicit_type { implicit_type(object const& o) : obj(o) { } ~implicit_type() { } template operator T() { return obj.as(); } private: object const& obj; }; // 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 { o << static_cast(*this); } void msgpack_unpack(object const& o) { o >> static_cast(*this); } }; template template inline packer& packer::pack(const T& v) { *this << v; return *this; } inline object& operator>> (object const& o, object& v) { v = o; return v; } // convert operator template inline T& operator>> (object const& o, T& v) { v.msgpack_unpack(o.convert()); return v; } namespace detail { template struct packer_serializer { static packer& pack(packer& o, const T& v) { v.msgpack_pack(o); return o; } }; } // serialize operator template inline packer& operator<< (packer& o, const T& v) { return detail::packer_serializer::pack(o, v); } // deconvert operator template inline void operator<< (object::with_zone& o, const T& v) { v.msgpack_object(static_cast(&o), o.zone); } inline bool operator==(const object& x, const object& y) { if(x.type != y.type) { return false; } switch(x.type) { case type::NIL: return true; case type::BOOLEAN: return x.via.boolean == y.via.boolean; case type::POSITIVE_INTEGER: return x.via.u64 == y.via.u64; case type::NEGATIVE_INTEGER: return x.via.i64 == y.via.i64; case type::DOUBLE: return x.via.dec == y.via.dec; case type::STR: return x.via.str.size == y.via.str.size && memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0; case type::BIN: return x.via.bin.size == y.via.bin.size && memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0; case type::ARRAY: if(x.via.array.size != y.via.array.size) { return false; } else if(x.via.array.size == 0) { return true; } else { object* px = x.via.array.ptr; object* const pxend = x.via.array.ptr + x.via.array.size; object* py = y.via.array.ptr; do { if(!(*px == *py)) { return false; } ++px; ++py; } while(px < pxend); return true; } case type::MAP: if(x.via.map.size != y.via.map.size) { return false; } else if(x.via.map.size == 0) { return true; } else { object_kv* px = x.via.map.ptr; object_kv* const pxend = x.via.map.ptr + x.via.map.size; 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 object& x, const T& y) try { return x == object(y); } catch (msgpack::type_error&) { return false; } inline bool operator!=(const object& x, const object& y) { return !(x == y); } template inline bool operator==(const T& y, const object x) { return x == y; } template inline bool operator!=(const object& x, const T& y) { return !(x == y); } template inline bool operator!=(const T& y, const object& x) { return x != y; } inline object::implicit_type object::convert() const { return implicit_type(*this); } template inline void object::convert(T& v) const { *this >> v; } template inline void object::convert(T* v) const { convert(*v); } template inline T object::as() const { T v; convert(v); return v; } inline object::object() { type = type::NIL; } template inline object::object(const T& v) { *this << v; } template inline object& object::operator=(const T& v) { *this = object(v); return *this; } template object::object(const T& v, zone* z) { with_zone oz(z); oz << v; type = oz.type; via = oz.via; } inline object::object(msgpack_object o) { // FIXME beter way? ::memcpy(this, &o, sizeof(o)); } inline void operator<< (object& o, msgpack_object v) { // FIXME beter way? ::memcpy(&o, &v, sizeof(v)); } inline object::operator msgpack_object() const { // FIXME beter way? msgpack_object obj; ::memcpy(&obj, this, sizeof(obj)); return obj; } // obsolete template inline void convert(T& v, object const& o) { o.convert(v); } // obsolete template inline void pack(packer& o, const T& v) { o.pack(v); } // obsolete template inline void pack_copy(packer& o, T v) { pack(o, v); } template packer& operator<< (packer& o, const object& v) { switch(v.type) { case type::NIL: o.pack_nil(); return o; case type::BOOLEAN: if(v.via.boolean) { o.pack_true(); } else { o.pack_false(); } return o; case type::POSITIVE_INTEGER: o.pack_uint64(v.via.u64); return o; case type::NEGATIVE_INTEGER: o.pack_int64(v.via.i64); return o; case type::DOUBLE: o.pack_double(v.via.dec); return o; case type::STR: o.pack_str(v.via.str.size); o.pack_str_body(v.via.str.ptr, v.via.str.size); return o; case type::BIN: o.pack_bin(v.via.bin.size); o.pack_bin_body(v.via.bin.ptr, v.via.bin.size); return o; case type::ARRAY: o.pack_array(v.via.array.size); for(object* p(v.via.array.ptr), * const pend(v.via.array.ptr + v.via.array.size); p < pend; ++p) { o << *p; } return o; case type::MAP: o.pack_map(v.via.map.size); for(object_kv* p(v.via.map.ptr), * const pend(v.via.map.ptr + v.via.map.size); p < pend; ++p) { o << p->key; o << p->val; } return o; default: throw type_error(); } } std::ostream& operator<< (std::ostream& s, const object& o) { switch(o.type) { case type::NIL: s << "nil"; break; case type::BOOLEAN: s << (o.via.boolean ? "true" : "false"); break; case type::POSITIVE_INTEGER: s << o.via.u64; break; case type::NEGATIVE_INTEGER: s << o.via.i64; break; case type::DOUBLE: s << o.via.dec; break; case type::STR: (s << '"').write(o.via.str.ptr, o.via.str.size) << '"'; break; case type::BIN: (s << '"').write(o.via.bin.ptr, o.via.bin.size) << '"'; break; case type::ARRAY: s << "["; if(o.via.array.size != 0) { object* p(o.via.array.ptr); s << *p; ++p; for(object* const pend(o.via.array.ptr + o.via.array.size); p < pend; ++p) { s << ", " << *p; } } s << "]"; break; case type::MAP: s << "{"; if(o.via.map.size != 0) { object_kv* p(o.via.map.ptr); s << p->key << "=>" << p->val; ++p; for(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; } } // namespace msgpack #include "msgpack/type.hpp" #endif /* msgpack/object.hpp */