// // MessagePack for C++ dynamic typed objects // // Copyright (C) 2008 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. // #include "msgpack/object.hpp" #include "msgpack/pack.hpp" namespace msgpack { namespace { template struct numeric_overflow_signed_impl; template struct numeric_overflow_signed_impl { static int test(X x) { if( ( std::numeric_limits::is_integer && std::numeric_limits::is_integer) || (!std::numeric_limits::is_integer && !std::numeric_limits::is_integer) ) { if( sizeof(T) < sizeof(X) ) { if( static_cast( std::numeric_limits::max()) < x ) { return 1; } if( static_cast(-std::numeric_limits::max()) > x ) { return -1; } } } else if(std::numeric_limits::is_integer) { if( static_cast( std::numeric_limits::max()) < x) { return 1; } if( static_cast(-std::numeric_limits::max()) > x) { return -1; } } return 0; } }; template struct numeric_overflow_signed_impl { static int test(X x) { if( ( std::numeric_limits::is_integer && std::numeric_limits::is_integer) || (!std::numeric_limits::is_integer && !std::numeric_limits::is_integer) ) { if( sizeof(T) <= sizeof(X) ) { if( static_cast(std::numeric_limits::max()) < x ) { return 1; } } } else if(std::numeric_limits::is_integer) { if( static_cast( std::numeric_limits::max()) < x) { return 1; } } return 0; } }; template struct numeric_overflow_signed_impl { static int test(X x) { if( static_cast(0) > x ) { return -1; } if( ( std::numeric_limits::is_integer && std::numeric_limits::is_integer) || (!std::numeric_limits::is_integer && !std::numeric_limits::is_integer) ) { if( sizeof(T) < sizeof(X) ) { if( static_cast(std::numeric_limits::max()) < x ) { return 1; } } } else if(std::numeric_limits::is_integer) { if( static_cast( std::numeric_limits::max()) < x) { return 1; } } return 0; } }; template struct numeric_overflow_signed_impl { static int test(X x) { if( ( std::numeric_limits::is_integer && std::numeric_limits::is_integer) || (!std::numeric_limits::is_integer && !std::numeric_limits::is_integer) ) { if( sizeof(T) < sizeof(X) ) { if( static_cast(std::numeric_limits::max()) < x ) { return 1; } } } else if(std::numeric_limits::is_integer) { if( static_cast(std::numeric_limits::max()) < x ) { return 1; } } return 0; } }; template struct numeric_overflow { static int test(X x) { return numeric_overflow_signed_impl::is_signed, std::numeric_limits::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 struct numeric_underflow { static bool test(X x) { return static_cast(static_cast(x)) != x; } static void check(X x) { if(test(x)) { throw underflow_error(); } } }; template inline T integer_cast(X x) { numeric_overflow::check(x); return static_cast(x); } template inline T float_cast(X x) { numeric_overflow::check(x); numeric_underflow::check(x); return static_cast(x); } template inline bool numequal(V v, const object_class* x) try { return v == static_cast(*x); } catch (type_error&) { return false; } template inline bool numless(V v, const object_class* x) try { return v < static_cast(*x); } catch (positive_overflow_error&) { return true; } catch (overflow_error&) { return false; } template inline bool numgreater(V v, const object_class* x) try { return v > static_cast(*x); } catch (negative_overflow_error&) { return true; } catch (overflow_error&) { return false; } template inline void numeric_inspect(V v, std::ostream& s) { s << v; } template <> inline void numeric_inspect(uint8_t v, std::ostream& s) { s << (uint16_t)v; } template <> inline void numeric_inspect(int8_t v, std::ostream& s) { s << (int16_t)v; } template inline void numeric_pack(dynamic_packer& p, V v); template <> inline void numeric_pack(dynamic_packer& p, uint8_t v) { p.pack_unsigned_int_8(v); } template <> inline void numeric_pack(dynamic_packer& p, uint16_t v) { p.pack_unsigned_int_16(v); } template <> inline void numeric_pack(dynamic_packer& p, uint32_t v) { p.pack_unsigned_int_32(v); } template <> inline void numeric_pack(dynamic_packer& p, uint64_t v) { p.pack_unsigned_int_64(v); } template <> inline void numeric_pack(dynamic_packer& p, int8_t v) { p.pack_unsigned_int_8(v); } template <> inline void numeric_pack(dynamic_packer& p, int16_t v) { p.pack_unsigned_int_16(v); } template <> inline void numeric_pack(dynamic_packer& p, int32_t v) { p.pack_unsigned_int_32(v); } template <> inline void numeric_pack(dynamic_packer& p, int64_t v) { p.pack_unsigned_int_64(v); } template <> inline void numeric_pack(dynamic_packer& p, float v) { p.pack_float(v); } template <> inline void numeric_pack(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(val); } \ uint32_t object_##NAME::xu32 () const { return integer_cast(val); } \ uint64_t object_##NAME::xu64 () const { return integer_cast(val); } \ int8_t object_##NAME::xi8 () const { return integer_cast(val); } \ int16_t object_##NAME::xi16 () const { return integer_cast(val); } \ int32_t object_##NAME::xi32 () const { return integer_cast(val); } \ int64_t object_##NAME::xi64 () const { return integer_cast(val); } \ float object_##NAME::xfloat () const { return integer_cast(val); } \ double object_##NAME::xdouble() const { return integer_cast(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(val); } \ uint32_t object_##NAME::xu32 () const { return integer_cast(val); } \ uint64_t object_##NAME::xu64 () const { return integer_cast(val); } \ int8_t object_##NAME::xi8 () const { return integer_cast(val); } \ int16_t object_##NAME::xi16 () const { return integer_cast(val); } \ int32_t object_##NAME::xi32 () const { return integer_cast(val); } \ int64_t object_##NAME::xi64 () const { return integer_cast(val); } \ float object_##NAME::xfloat () const { return float_cast(val); } \ double object_##NAME::xdouble() const { return float_cast(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::test(val) == -1) { return true; } \ try { return static_cast(val) < x->xi64(); } \ catch (type_error&) { return true; } \ } else { \ if(numeric_overflow::test(val) == 1) { return false; } \ try { return static_cast(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::test(val) == -1) { return false; } \ try { return static_cast(val) > x->xi64(); } \ catch (type_error&) { return false; } \ } else { \ if(numeric_overflow::test(val) == 1) { return true; } \ try { return static_cast(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_ref, raw object_raw_ref::xraw() { return raw(ptr, len); } const_raw object_raw_ref::xraw() const { return const_raw(ptr, len); } ) RAW_OBJECT(const_raw_ref, const_raw object_const_raw_ref::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& xa(x->xarray()); if(val.size() != xa.size()) { return false; } for(std::vector::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::const_iterator it(val.begin()); s << *it; ++it; for(std::vector::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::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& xm(x->xmap()); if(val.size() != xm.size()) { return false; } for(std::map::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::const_iterator it(val.begin()); s << it->first << "=>" << it->second; ++it; for(std::map::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::const_iterator it(val.begin()), it_end(val.end()); it != it_end; ++it) { it->first.pack(p); it->second.pack(p); } } } // namespace msgpack