summaryrefslogtreecommitdiff
path: root/cpp/object.cpp
diff options
context:
space:
mode:
authorfrsyuki <frsyuki@5a5092ae-2292-43ba-b2d5-dcab9c1a2731>2009-02-15 09:09:56 +0000
committerfrsyuki <frsyuki@5a5092ae-2292-43ba-b2d5-dcab9c1a2731>2009-02-15 09:09:56 +0000
commit7c427400a7071f0cb251edd102430945e142033f (patch)
treed079eada26acb6f2be6977f97d3a032ccf5556aa /cpp/object.cpp
parent529a50633dffc91dd5ce58ae5a905a0ac4a5fdf9 (diff)
downloadmsgpack-python-7c427400a7071f0cb251edd102430945e142033f.tar.gz
lang/c/msgpack: update C++ code
git-svn-id: file:///Users/frsyuki/project/msgpack-git/svn/x@51 5a5092ae-2292-43ba-b2d5-dcab9c1a2731
Diffstat (limited to 'cpp/object.cpp')
-rw-r--r--cpp/object.cpp340
1 files changed, 340 insertions, 0 deletions
diff --git a/cpp/object.cpp b/cpp/object.cpp
new file mode 100644
index 0000000..099b541
--- /dev/null
+++ b/cpp/object.cpp
@@ -0,0 +1,340 @@
+#include "msgpack/object.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; }
+
+} // noname namespace
+
+
+bool object_nil::isnil() const { return true; }
+bool object_nil::operator== (const object_class* x) const
+ { return typeid(*this) == typeid(*x); }
+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); }
+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); }
+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; } \
+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; } \
+ } \
+ } } \
+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; } } \
+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;
+}
+
+
+ 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;
+}
+
+
+} // namespace msgpack
+