msgpack/cpp/object.cpp

416 lines
14 KiB
C++
Raw Normal View History

#include "msgpack/object.hpp"
#include "msgpack/pack.hpp"
namespace msgpack {
namespace {
template <typename T, typename X, bool TSigned, bool XSigned>
struct numeric_overflow_signed_impl;
template <typename T, typename X>
struct numeric_overflow_signed_impl<T, X, true, true> {
static int test(X x) {
if( ( std::numeric_limits<T>::is_integer && std::numeric_limits<X>::is_integer) ||
(!std::numeric_limits<T>::is_integer && !std::numeric_limits<X>::is_integer) ) {
if( sizeof(T) < sizeof(X) ) {
if( static_cast<X>( std::numeric_limits<T>::max()) < x ) { return 1; }
if( static_cast<X>(-std::numeric_limits<T>::max()) > x ) { return -1; }
}
} else if(std::numeric_limits<T>::is_integer) {
if( static_cast<X>( std::numeric_limits<T>::max()) < x) { return 1; }
if( static_cast<X>(-std::numeric_limits<T>::max()) > x) { return -1; }
}
return 0;
}
};
template <typename T, typename X>
struct numeric_overflow_signed_impl<T, X, true, false> {
static int test(X x) {
if( ( std::numeric_limits<T>::is_integer && std::numeric_limits<X>::is_integer) ||
(!std::numeric_limits<T>::is_integer && !std::numeric_limits<X>::is_integer) ) {
if( sizeof(T) <= sizeof(X) ) {
if( static_cast<X>(std::numeric_limits<T>::max()) < x ) { return 1; }
}
} else if(std::numeric_limits<T>::is_integer) {
if( static_cast<X>( std::numeric_limits<T>::max()) < x) { return 1; }
}
return 0;
}
};
template <typename T, typename X>
struct numeric_overflow_signed_impl<T, X, false, true> {
static int test(X x) {
if( static_cast<X>(0) > x ) { return -1; }
if( ( std::numeric_limits<T>::is_integer && std::numeric_limits<X>::is_integer) ||
(!std::numeric_limits<T>::is_integer && !std::numeric_limits<X>::is_integer) ) {
if( sizeof(T) < sizeof(X) ) {
if( static_cast<X>(std::numeric_limits<T>::max()) < x ) { return 1; }
}
} else if(std::numeric_limits<T>::is_integer) {
if( static_cast<X>( std::numeric_limits<T>::max()) < x) { return 1; }
}
return 0;
}
};
template <typename T, typename X>
struct numeric_overflow_signed_impl<T, X, false, false> {
static int test(X x) {
if( ( std::numeric_limits<T>::is_integer && std::numeric_limits<X>::is_integer) ||
(!std::numeric_limits<T>::is_integer && !std::numeric_limits<X>::is_integer) ) {
if( sizeof(T) < sizeof(X) ) {
if( static_cast<X>(std::numeric_limits<T>::max()) < x ) { return 1; }
}
} else if(std::numeric_limits<T>::is_integer) {
if( static_cast<X>(std::numeric_limits<T>::max()) < x ) { return 1; }
}
return 0;
}
};
template <typename T, typename X>
struct numeric_overflow {
static int test(X x) {
return numeric_overflow_signed_impl<T, X, std::numeric_limits<T>::is_signed, std::numeric_limits<X>::is_signed>::test(x);
}
static void check(X x) {
int r = test(x);
if(r == 1) { throw positive_overflow_error(); }
if(r == -1) { throw negative_overflow_error(); }
}
};
template <typename T, typename X>
struct numeric_underflow {
static bool test(X x) {
return static_cast<X>(static_cast<T>(x)) != x;
}
static void check(X x) {
if(test(x)) { throw underflow_error(); }
}
};
template <typename T, typename X>
inline T integer_cast(X x) {
numeric_overflow<T,X>::check(x);
return static_cast<T>(x); }
template <typename T, typename X>
inline T float_cast(X x) {
numeric_overflow<T,X>::check(x);
numeric_underflow<T,X>::check(x);
return static_cast<T>(x); }
template <typename V>
inline bool numequal(V v, const object_class* x)
try { return v == static_cast<V>(*x); }
catch (type_error&) { return false; }
template <typename V>
inline bool numless(V v, const object_class* x)
try { return v < static_cast<V>(*x); }
catch (positive_overflow_error&) { return true; }
catch (overflow_error&) { return false; }
template <typename V>
inline bool numgreater(V v, const object_class* x)
try { return v > static_cast<V>(*x); }
catch (negative_overflow_error&) { return true; }
catch (overflow_error&) { return false; }
template <typename V>
inline void numeric_inspect(V v, std::ostream& s)
{ s << v; }
template <>
inline void numeric_inspect<uint8_t>(uint8_t v, std::ostream& s)
{ s << (uint16_t)v; }
template <>
inline void numeric_inspect<int8_t>(int8_t v, std::ostream& s)
{ s << (int16_t)v; }
template <typename V>
inline void numeric_pack(dynamic_packer& p, V v);
template <>
inline void numeric_pack<uint8_t>(dynamic_packer& p, uint8_t v)
{ p.pack_unsigned_int_8(v); }
template <>
inline void numeric_pack<uint16_t>(dynamic_packer& p, uint16_t v)
{ p.pack_unsigned_int_16(v); }
template <>
inline void numeric_pack<uint32_t>(dynamic_packer& p, uint32_t v)
{ p.pack_unsigned_int_32(v); }
template <>
inline void numeric_pack<uint64_t>(dynamic_packer& p, uint64_t v)
{ p.pack_unsigned_int_64(v); }
template <>
inline void numeric_pack<int8_t>(dynamic_packer& p, int8_t v)
{ p.pack_unsigned_int_8(v); }
template <>
inline void numeric_pack<int16_t>(dynamic_packer& p, int16_t v)
{ p.pack_unsigned_int_16(v); }
template <>
inline void numeric_pack<int32_t>(dynamic_packer& p, int32_t v)
{ p.pack_unsigned_int_32(v); }
template <>
inline void numeric_pack<int64_t>(dynamic_packer& p, int64_t v)
{ p.pack_unsigned_int_64(v); }
template <>
inline void numeric_pack<float>(dynamic_packer& p, float v)
{ p.pack_float(v); }
template <>
inline void numeric_pack<double>(dynamic_packer& p, double v)
{ p.pack_double(v); }
} // noname namespace
bool object_nil::isnil() const { return true; }
bool object_nil::operator== (const object_class* x) const
{ return typeid(*this) == typeid(*x); }
void object_nil::pack(dynamic_packer& p) const
{ p.pack_nil(); }
const object_class* object_nil::inspect(std::ostream& s) const
{ s << "nil"; return this; }
bool object_true::xbool() const { return true; }
bool object_true::operator== (const object_class* x) const
{ return typeid(*this) == typeid(*x); }
void object_true::pack(dynamic_packer& p) const
{ p.pack_true(); }
const object_class* object_true::inspect(std::ostream& s) const
{ s << "true"; return this; }
bool object_false::xbool() const { return false; }
bool object_false::operator== (const object_class* x) const
{ return typeid(*this) == typeid(*x); }
void object_false::pack(dynamic_packer& p) const
{ p.pack_false(); }
const object_class* object_false::inspect(std::ostream& s) const
{ s << "false"; return this; }
#define INTEGER_OBJECT(NAME) \
uint8_t object_##NAME::xu8 () const { return val; } \
uint16_t object_##NAME::xu16 () const { return integer_cast<uint16_t>(val); } \
uint32_t object_##NAME::xu32 () const { return integer_cast<uint32_t>(val); } \
uint64_t object_##NAME::xu64 () const { return integer_cast<uint64_t>(val); } \
int8_t object_##NAME::xi8 () const { return integer_cast<int8_t>(val); } \
int16_t object_##NAME::xi16 () const { return integer_cast<int16_t>(val); } \
int32_t object_##NAME::xi32 () const { return integer_cast<int32_t>(val); } \
int64_t object_##NAME::xi64 () const { return integer_cast<int64_t>(val); } \
float object_##NAME::xfloat () const { return integer_cast<float>(val); } \
double object_##NAME::xdouble() const { return integer_cast<double>(val); } \
bool object_##NAME::operator== (const object_class* x) const \
try { return val == x->x##NAME(); } \
catch (type_error&) { return false; } \
bool object_##NAME::operator< (const object_class* x) const \
try { return val < x->x##NAME(); } \
catch (positive_overflow_error&) { return true; } \
catch (overflow_error&) { return false; } \
bool object_##NAME::operator> (const object_class* x) const \
try { return val > x->x##NAME(); } \
catch (negative_overflow_error&) { return true; } \
catch (overflow_error&) { return false; } \
void object_##NAME::pack(dynamic_packer& p) const \
{ numeric_pack(p, val); } \
const object_class* object_##NAME::inspect(std::ostream& s) const \
{ numeric_inspect(val, s); return this; } \
INTEGER_OBJECT(u8)
INTEGER_OBJECT(u16)
INTEGER_OBJECT(u32)
INTEGER_OBJECT(u64)
INTEGER_OBJECT(i8)
INTEGER_OBJECT(i16)
INTEGER_OBJECT(i32)
INTEGER_OBJECT(i64)
#undef INTEGER_OBJECT(NAME)
#define FLOAT_OBJECT(NAME) \
uint8_t object_##NAME::xu8 () const { return val; } \
uint16_t object_##NAME::xu16 () const { return integer_cast<uint16_t>(val); } \
uint32_t object_##NAME::xu32 () const { return integer_cast<uint32_t>(val); } \
uint64_t object_##NAME::xu64 () const { return integer_cast<uint64_t>(val); } \
int8_t object_##NAME::xi8 () const { return integer_cast<int8_t>(val); } \
int16_t object_##NAME::xi16 () const { return integer_cast<int16_t>(val); } \
int32_t object_##NAME::xi32 () const { return integer_cast<int32_t>(val); } \
int64_t object_##NAME::xi64 () const { return integer_cast<int64_t>(val); } \
float object_##NAME::xfloat () const { return float_cast<float>(val); } \
double object_##NAME::xdouble() const { return float_cast<double>(val); } \
bool object_##NAME::operator== (const object_class* x) const \
try { return val == x->x##NAME(); } \
catch (type_error&) { return false; } \
bool object_##NAME::operator< (const object_class* x) const { \
try { return val < x->xdouble(); } \
catch (positive_overflow_error&) { return true; } \
catch (overflow_error&) { return false; } \
catch (underflow_error&) { \
if(val < 0.0) { \
if(numeric_overflow<int64_t, double>::test(val) == -1) { return true; } \
try { return static_cast<int64_t>(val) < x->xi64(); } \
catch (type_error&) { return true; } \
} else { \
if(numeric_overflow<uint64_t, double>::test(val) == 1) { return false; } \
try { return static_cast<uint64_t>(val) < x->xu64(); } \
catch (type_error&) { return false; } \
} \
} } \
bool object_##NAME::operator> (const object_class* x) const { \
try { return val > x->xdouble(); } \
catch (negative_overflow_error&) { return true; } \
catch (overflow_error&) { return false; } \
catch (underflow_error&) { \
if(val < 0.0) { \
if(numeric_overflow<int64_t, double>::test(val) == -1) { return false; } \
try { return static_cast<int64_t>(val) > x->xi64(); } \
catch (type_error&) { return false; } \
} else { \
if(numeric_overflow<uint64_t, double>::test(val) == 1) { return true; } \
try { return static_cast<uint64_t>(val) > x->xu64(); } \
catch (type_error&) { return true; } \
} \
} } \
void object_##NAME::pack(dynamic_packer& p) const \
{ numeric_pack(p, val); } \
const object_class* object_##NAME::inspect(std::ostream& s) const \
{ s << val; return this; } \
FLOAT_OBJECT(float)
FLOAT_OBJECT(double)
#undef FLOAT_OBJECT(NAME)
#define RAW_OBJECT(NAME, EXTRA) \
EXTRA \
bool object_##NAME::operator== (const object_class* x) const \
try { \
const_raw xr(x->xraw()); \
return len == xr.len && (ptr == xr.ptr || memcmp(ptr, xr.ptr, len) == 0); \
} catch (type_error&) { return false; } \
bool object_##NAME::operator< (const object_class* x) const { \
const_raw xr(x->xraw()); \
if(len == xr.len) { return ptr != xr.ptr && memcmp(ptr, xr.ptr, len) < 0; } \
else { return len < xr.len; } } \
bool object_##NAME::operator> (const object_class* x) const { \
const_raw xr(x->xraw()); \
if(len == xr.len) { return ptr != xr.ptr && memcmp(ptr, xr.ptr, len) > 0; } \
else { return len > xr.len; } } \
void object_##NAME::pack(dynamic_packer& p) const \
{ p.pack_raw(ptr, len); } \
const object_class* object_##NAME::inspect(std::ostream& s) const \
{ (s << '"').write((const char*)ptr, len) << '"'; return this; } // FIXME escape
RAW_OBJECT(raw,
raw object_raw::xraw() { return raw(ptr, len); }
const_raw object_raw::xraw() const { return const_raw(ptr, len); } )
RAW_OBJECT(const_raw,
const_raw object_const_raw::xraw() const { return const_raw(ptr, len); } )
#undef RAW_OBJECT(NAME, EXTRA)
array& object_array::xarray() { return val; }
const array& object_array::xarray() const { return val; }
bool object_array::operator== (const object_class* x) const
try {
const std::vector<object>& xa(x->xarray());
if(val.size() != xa.size()) { return false; }
for(std::vector<object>::const_iterator iv(val.begin()), iv_end(val.end()), ix(xa.begin());
iv != iv_end;
++iv, ++ix) {
if(*iv != *ix) { return false; }
}
return true;
} catch (type_error&) { return false; }
const object_class* object_array::inspect(std::ostream& s) const
{
s << '[';
if(!val.empty()) {
std::vector<object>::const_iterator it(val.begin());
s << *it;
++it;
for(std::vector<object>::const_iterator it_end(val.end());
it != it_end;
++it) {
s << ", " << *it;
}
}
s << ']';
return this;
}
void object_array::pack(dynamic_packer& p) const
{
p.pack_array(val.size());
for(std::vector<object>::const_iterator it(val.begin()), it_end(val.end());
it != it_end;
++it) {
it->pack(p);
}
}
map& object_map::xmap() { return val; }
const map& object_map::xmap() const { return val; }
bool object_map::operator== (const object_class* x) const
try {
const std::map<object, object>& xm(x->xmap());
if(val.size() != xm.size()) { return false; }
for(std::map<object, object>::const_iterator iv(val.begin()), iv_end(val.end()), ix(xm.begin());
iv != iv_end;
++iv, ++ix) {
if(iv->first != ix->first || iv->second != ix->first) { return false; }
}
return true;
} catch (type_error&) { return false; }
const object_class* object_map::inspect(std::ostream& s) const
{
s << '{';
if(!val.empty()) {
std::map<object, object>::const_iterator it(val.begin());
s << it->first << "=>" << it->second;
++it;
for(std::map<object, object>::const_iterator it_end(val.end());
it != it_end;
++it) {
s << ", " << it->first << "=>" << it->second;
}
}
s << '}';
return this;
}
void object_map::pack(dynamic_packer& p) const
{
p.pack_map(val.size());
for(std::map<object, object>::const_iterator it(val.begin()), it_end(val.end());
it != it_end;
++it) {
it->first.pack(p);
it->second.pack(p);
}
}
} // namespace msgpack