mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-10-15 15:16:51 +02:00
Reorganized tree.
This commit is contained in:
543
include/msgpack/object.hpp
Normal file
543
include/msgpack/object.hpp
Normal file
@@ -0,0 +1,543 @@
|
||||
//
|
||||
// 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 <string.h>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
|
||||
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 <typename T>
|
||||
T as() const;
|
||||
|
||||
template <typename T>
|
||||
void convert(T& v) const;
|
||||
template <typename T>
|
||||
void convert(T* v) const;
|
||||
|
||||
object();
|
||||
|
||||
object(msgpack_object o);
|
||||
|
||||
template <typename T>
|
||||
explicit object(const T& v);
|
||||
|
||||
template <typename T>
|
||||
object(const T& v, zone* z);
|
||||
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
operator T() { return obj.as<T>(); }
|
||||
|
||||
private:
|
||||
object const& obj;
|
||||
};
|
||||
|
||||
|
||||
// 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
|
||||
{
|
||||
o << static_cast<const msgpack_type&>(*this);
|
||||
}
|
||||
|
||||
void msgpack_unpack(object const& o)
|
||||
{
|
||||
o >> static_cast<msgpack_type&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Stream>
|
||||
template <typename T>
|
||||
inline packer<Stream>& packer<Stream>::pack(const T& v)
|
||||
{
|
||||
*this << v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline object& operator>> (object const& o, object& v)
|
||||
{
|
||||
v = o;
|
||||
return v;
|
||||
}
|
||||
|
||||
// convert operator
|
||||
template <typename T>
|
||||
inline T& operator>> (object const& o, T& v)
|
||||
{
|
||||
v.msgpack_unpack(o.convert());
|
||||
return v;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename Stream, typename T>
|
||||
struct packer_serializer {
|
||||
static packer<Stream>& pack(packer<Stream>& o, const T& v) {
|
||||
v.msgpack_pack(o);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// serialize operator
|
||||
template <typename Stream, typename T>
|
||||
inline packer<Stream>& operator<< (packer<Stream>& o, const T& v)
|
||||
{
|
||||
return detail::packer_serializer<Stream, T>::pack(o, v);
|
||||
}
|
||||
|
||||
// deconvert operator
|
||||
template <typename T>
|
||||
inline void operator<< (object::with_zone& o, const T& v)
|
||||
{
|
||||
v.msgpack_object(static_cast<object*>(&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 <typename T>
|
||||
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 <typename T>
|
||||
inline bool operator==(const T& y, const object x)
|
||||
{ return x == y; }
|
||||
|
||||
template <typename T>
|
||||
inline bool operator!=(const object& x, const T& y)
|
||||
{ return !(x == y); }
|
||||
|
||||
template <typename T>
|
||||
inline bool operator!=(const T& y, const object& x)
|
||||
{ return x != y; }
|
||||
|
||||
|
||||
inline object::implicit_type object::convert() const
|
||||
{
|
||||
return implicit_type(*this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void object::convert(T& v) const
|
||||
{
|
||||
*this >> v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void object::convert(T* v) const
|
||||
{
|
||||
convert(*v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T object::as() const
|
||||
{
|
||||
T v;
|
||||
convert(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
inline object::object()
|
||||
{
|
||||
type = type::NIL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline object::object(const T& v)
|
||||
{
|
||||
*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, 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 <typename T>
|
||||
inline void convert(T& v, object const& o)
|
||||
{
|
||||
o.convert(v);
|
||||
}
|
||||
|
||||
// obsolete
|
||||
template <typename Stream, typename T>
|
||||
inline void pack(packer<Stream>& o, const T& v)
|
||||
{
|
||||
o.pack(v);
|
||||
}
|
||||
|
||||
// obsolete
|
||||
template <typename Stream, typename T>
|
||||
inline void pack_copy(packer<Stream>& o, T v)
|
||||
{
|
||||
pack(o, v);
|
||||
}
|
||||
|
||||
|
||||
template <typename Stream>
|
||||
packer<Stream>& operator<< (packer<Stream>& 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 << "#<UNKNOWN " << static_cast<uint16_t>(o.type) << ">";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace msgpack
|
||||
|
||||
#include "msgpack/type.hpp"
|
||||
|
||||
#endif /* msgpack/object.hpp */
|
||||
|
Reference in New Issue
Block a user