diff --git a/example/custom.cc b/example/custom.cc index f892a894..63cc4f4b 100644 --- a/example/custom.cc +++ b/example/custom.cc @@ -30,9 +30,9 @@ int main(void) msgpack::sbuffer sbuf; msgpack::pack(sbuf, oc); - msgpack::zone zone; - msgpack::object obj; - msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &zone, &obj); + msgpack::unpacked result; + msgpack::unpack(result, sbuf.data(), sbuf.size()); + msgpack::object obj = result.get(); obj.convert(&nc); @@ -46,9 +46,9 @@ int main(void) msgpack::sbuffer sbuf; msgpack::pack(sbuf, nc); - msgpack::zone zone; - msgpack::object obj; - msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &zone, &obj); + msgpack::unpacked result; + msgpack::unpack(result, sbuf.data(), sbuf.size()); + msgpack::object obj = result.get(); obj.convert(&oc); diff --git a/example/protocol.cc b/example/protocol.cc index efc431f7..5e08b291 100644 --- a/example/protocol.cc +++ b/example/protocol.cc @@ -46,12 +46,12 @@ int main(void) { std::string buffer(stream.str()); - msgpack::zone mempool; - msgpack::object o = - msgpack::unpack(buffer.data(), buffer.size(), mempool); + msgpack::unpacked result; + msgpack::unpack(result, buffer.data(), buffer.size()); + msgpack::object o = result.get(); myprotocol::Get req; - msgpack::convert(req, o); + o.convert(req); std::cout << "received: " << o << std::endl; } @@ -74,12 +74,13 @@ int main(void) { std::string buffer(stream.str()); - msgpack::zone mempool; - msgpack::object o = - msgpack::unpack(buffer.data(), buffer.size(), mempool); + msgpack::unpacked result; + msgpack::unpack(result, buffer.data(), buffer.size()); + msgpack::object o = result.get(); + myprotocol::MultiGet req; - msgpack::convert(req, o); + o.convert(req); std::cout << "received: " << o << std::endl; } } diff --git a/example/simple.cc b/example/simple.cc index 5bfd8278..0dcb9d84 100644 --- a/example/simple.cc +++ b/example/simple.cc @@ -18,11 +18,12 @@ int main(void) // deserialize the buffer into msgpack::object instance. std::string str(buffer.str()); - // deserialized object is valid during the msgpack::zone instance alive. - msgpack::zone mempool; + msgpack::unpacked result; - msgpack::object deserialized; - msgpack::unpack(str.data(), str.size(), NULL, &mempool, &deserialized); + msgpack::unpack(result, str.data(), str.size()); + + // deserialized object is valid during the msgpack::unpacked instance alive. + msgpack::object deserialized = result.get(); // msgpack::object supports ostream. std::cout << deserialized << std::endl; diff --git a/example/speed_test.cc b/example/speed_test.cc index b711c15e..d13eb777 100644 --- a/example/speed_test.cc +++ b/example/speed_test.cc @@ -28,23 +28,11 @@ void test_map_pack_unpack() { buffer.seekg(0); std::string str(buffer.str()); - // deserialized object is valid during the msgpack::zone instance alive. - msgpack::zone mempool; - msgpack::object deserialized; - std::cout << "Start unpacking..." << std::endl; - { - boost::timer::cpu_timer timer; - msgpack::unpack(str.data(), str.size(), NULL, &mempool, &deserialized); - std::string result = timer.format(); - std::cout << result << std::endl; - } - std::cout << "Unpack finished..." << std::endl; - msgpack::unpacked unpacked; - std::cout << "Start unpacking...by void unpack(unpacked* result, const char* data, size_t len, size_t* offset = NULL)" << std::endl; + std::cout << "Start unpacking...by void unpack(unpacked& result, const char* data, size_t len)" << std::endl; { boost::timer::cpu_timer timer; - msgpack::unpack(&unpacked, str.data(), str.size()); + msgpack::unpack(unpacked, str.data(), str.size()); std::string result = timer.format(); std::cout << result << std::endl; } @@ -53,7 +41,7 @@ void test_map_pack_unpack() { std::cout << "Start converting..." << std::endl; { boost::timer::cpu_timer timer; - deserialized.convert(&m2); + unpacked.get().convert(&m2); std::string result = timer.format(); std::cout << result << std::endl; } diff --git a/example/speed_test_nested_array.cc b/example/speed_test_nested_array.cc index 8260f257..40a87a99 100644 --- a/example/speed_test_nested_array.cc +++ b/example/speed_test_nested_array.cc @@ -51,23 +51,11 @@ void test_array_of_array() { buffer.seekg(0); std::string str(buffer.str()); - // deserialized object is valid during the msgpack::zone instance alive. - msgpack::zone mempool; - msgpack::object deserialized; - std::cout << "Start unpacking..." << std::endl; - { - boost::timer::cpu_timer timer; - msgpack::unpack(str.data(), str.size(), NULL, &mempool, &deserialized); - std::string result = timer.format(); - std::cout << result << std::endl; - } - std::cout << "Unpack finished..." << std::endl; - msgpack::unpacked unpacked; - std::cout << "Start unpacking...by void unpack(unpacked* result, const char* data, size_t len, size_t* offset = NULL)" << std::endl; + std::cout << "Start unpacking...by void unpack(unpacked& result, const char* data, size_t len)" << std::endl; { boost::timer::cpu_timer timer; - msgpack::unpack(&unpacked, str.data(), str.size()); + msgpack::unpack(unpacked, str.data(), str.size()); std::string result = timer.format(); std::cout << result << std::endl; } @@ -76,7 +64,7 @@ void test_array_of_array() { std::cout << "Start converting..." << std::endl; { boost::timer::cpu_timer timer; - deserialized.convert(&v2); + unpacked.get().convert(&v2); std::string result = timer.format(); std::cout << result << std::endl; } diff --git a/include/msgpack/object.h b/include/msgpack/object.h index 79859db2..560008fe 100644 --- a/include/msgpack/object.h +++ b/include/msgpack/object.h @@ -41,7 +41,8 @@ typedef enum { MSGPACK_OBJECT_STR = 0x05, MSGPACK_OBJECT_ARRAY = 0x06, MSGPACK_OBJECT_MAP = 0x07, - MSGPACK_OBJECT_BIN = 0x08 + MSGPACK_OBJECT_BIN = 0x08, + MSGPACK_OBJECT_EXT = 0x09 } msgpack_object_type; diff --git a/include/msgpack/object.hpp b/include/msgpack/object.hpp index 8509b96c..f0790279 100644 --- a/include/msgpack/object.hpp +++ b/include/msgpack/object.hpp @@ -43,7 +43,8 @@ namespace type { STR = MSGPACK_OBJECT_STR, BIN = MSGPACK_OBJECT_BIN, ARRAY = MSGPACK_OBJECT_ARRAY, - MAP = MSGPACK_OBJECT_MAP + MAP = MSGPACK_OBJECT_MAP, + EXT = MSGPACK_OBJECT_EXT }; } @@ -71,6 +72,13 @@ struct object_bin { const char* ptr; }; +struct object_ext { + int8_t type() const { return ptr[0]; } + const char* data() const { return &ptr[1]; } + uint32_t size; + const char* ptr; +}; + struct object { union union_type { bool boolean; @@ -81,6 +89,7 @@ struct object { object_map map; object_str str; object_bin bin; + object_ext ext; }; type::object_type type; @@ -242,6 +251,10 @@ inline bool operator==(const object& x, const object& y) 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::EXT: + 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; @@ -444,6 +457,11 @@ packer& operator<< (packer& o, const object& v) o.pack_bin_body(v.via.bin.ptr, v.via.bin.size); return o; + case type::EXT: + o.pack_ext(v.via.ext.size, v.via.ext.type()); + o.pack_ext_body(v.via.ext.data(), v.via.ext.size); + return o; + case type::ARRAY: o.pack_array(v.via.array.size); for(object* p(v.via.array.ptr), diff --git a/include/msgpack/pack.hpp b/include/msgpack/pack.hpp index 47958af3..bfae2dd2 100644 --- a/include/msgpack/pack.hpp +++ b/include/msgpack/pack.hpp @@ -84,6 +84,9 @@ public: packer& pack_bin(size_t l); packer& pack_bin_body(const char* b, size_t l); + packer& pack_ext(size_t l, int8_t type); + packer& pack_ext_body(const char* b, size_t l); + private: template void pack_imp_uint8(T d); @@ -699,6 +702,72 @@ inline packer& packer::pack_bin_body(const char* b, size_t l) return *this; } +template +inline packer& packer::pack_ext(size_t l, int8_t type) +{ + switch(l) { + case 1: { + char buf[2]; + buf[0] = static_cast(0xd4); + buf[1] = static_cast(type); + append_buffer(buf, 2); + } break; + case 2: { + char buf[2]; + buf[0] = static_cast(0xd5); + buf[1] = static_cast(type); + append_buffer(buf, 2); + } break; + case 4: { + char buf[2]; + buf[0] = static_cast(0xd6); + buf[1] = static_cast(type); + append_buffer(buf, 2); + } break; + case 8: { + char buf[2]; + buf[0] = static_cast(0xd7); + buf[1] = static_cast(type); + append_buffer(buf, 2); + } break; + case 16: { + char buf[2]; + buf[0] = static_cast(0xd8); + buf[1] = static_cast(type); + append_buffer(buf, 2); + } break; + default: + if(l < 256) { + char buf[3]; + buf[0] = static_cast(0xc7); + buf[1] = static_cast(l); + buf[2] = static_cast(type); + append_buffer(buf, 3); + } else if(l < 65536) { + char buf[4]; + buf[0] = static_cast(0xc8); + _msgpack_store16(&buf[1], static_cast(l)); + buf[3] = static_cast(type); + append_buffer(buf, 4); + } else { + char buf[6]; + buf[0] = static_cast(0xc9); + _msgpack_store32(&buf[1], static_cast(l)); + buf[5] = static_cast(type); + append_buffer(buf, 6); + } + break; + } + return *this; +} + +template +inline packer& packer::pack_ext_body(const char* b, size_t l) +{ + append_buffer(b, l); + return *this; +} + template template inline void packer::pack_imp_uint8(T d) diff --git a/include/msgpack/unpack.hpp b/include/msgpack/unpack.hpp index e3c7a535..311a107a 100644 --- a/include/msgpack/unpack.hpp +++ b/include/msgpack/unpack.hpp @@ -17,7 +17,6 @@ // #ifndef MSGPACK_UNPACK_HPP #define MSGPACK_UNPACK_HPP - #include "object.hpp" #include "zone.hpp" #include "unpack_define.h" @@ -48,18 +47,26 @@ namespace msgpack { +typedef bool (*unpack_reference_func)(type::object_type, uint64_t, void*); + namespace detail { class unpack_user { public: + unpack_user(unpack_reference_func f = nullptr, void* user_data = nullptr) + :m_func(f), m_user_data(user_data) {} msgpack::zone const& zone() const { return *m_zone; } msgpack::zone& zone() { return *m_zone; } void set_zone(msgpack::zone& zone) { m_zone = &zone; } bool referenced() const { return m_referenced; } void set_referenced(bool referenced) { m_referenced = referenced; } + unpack_reference_func reference_func() const { return m_func; } + void* user_data() const { return m_user_data; } private: msgpack::zone* m_zone; bool m_referenced; + unpack_reference_func m_func; + void* m_user_data; }; inline void unpack_uint8(uint8_t d, object& o) @@ -106,7 +113,7 @@ inline void unpack_false(object& o) { o.type = type::BOOLEAN; o.via.boolean = false; } struct unpack_array { - void operator()(unpack_user&u, unsigned int n, object& o) const { + void operator()(unpack_user& u, uint32_t n, object& o) const { o.type = type::ARRAY; o.via.array.size = 0; o.via.array.ptr = static_cast(u.zone().allocate_align(n*sizeof(object))); @@ -116,14 +123,14 @@ struct unpack_array { inline void unpack_array_item(object& c, object const& o) { #if defined(__GNUC__) && !defined(__clang__) - memcpy(&c.via.array.ptr[c.via.array.size++], &o, sizeof(object)); + std::memcpy(&c.via.array.ptr[c.via.array.size++], &o, sizeof(object)); #else /* __GNUC__ && !__clang__ */ c.via.array.ptr[c.via.array.size++] = o; #endif /* __GNUC__ && !__clang__ */ } struct unpack_map { - void operator()(unpack_user& u, unsigned int n, object& o) const { + void operator()(unpack_user& u, uint32_t n, object& o) const { o.type = type::MAP; o.via.map.size = 0; o.via.map.ptr = static_cast(u.zone().allocate_align(n*sizeof(object_kv))); @@ -133,8 +140,8 @@ struct unpack_map { inline void unpack_map_item(object& c, object const& k, object const& v) { #if defined(__GNUC__) && !defined(__clang__) - memcpy(&c.via.map.ptr[c.via.map.size].key, &k, sizeof(object)); - memcpy(&c.via.map.ptr[c.via.map.size].val, &v, sizeof(object)); + std::memcpy(&c.via.map.ptr[c.via.map.size].key, &k, sizeof(object)); + std::memcpy(&c.via.map.ptr[c.via.map.size].val, &v, sizeof(object)); #else /* __GNUC__ && !__clang__ */ c.via.map.ptr[c.via.map.size].key = k; c.via.map.ptr[c.via.map.size].val = v; @@ -142,20 +149,49 @@ inline void unpack_map_item(object& c, object const& k, object const& v) ++c.via.map.size; } -inline void unpack_str(unpack_user& u, const char* b, const char* p, unsigned int l, object& o) +inline void unpack_str(unpack_user& u, const char* b, const char* p, uint64_t l, object& o) { o.type = type::STR; - o.via.str.ptr = p; + if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { + o.via.str.ptr = p; + u.set_referenced(true); + } + else { + char* tmp = static_cast(u.zone().allocate_align(l)); + std::memcpy(tmp, p, l); + o.via.str.ptr = tmp; + } o.via.str.size = l; - u.set_referenced(true); } -inline void unpack_bin(unpack_user& u, const char* b, const char* p, unsigned int l, object& o) +inline void unpack_bin(unpack_user& u, const char* b, const char* p, uint64_t l, object& o) { o.type = type::BIN; - o.via.bin.ptr = p; + if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { + o.via.bin.ptr = p; + u.set_referenced(true); + } + else { + char* tmp = static_cast(u.zone().allocate_align(l)); + std::memcpy(tmp, p, l); + o.via.bin.ptr = tmp; + } o.via.bin.size = l; - u.set_referenced(true); +} + +inline void unpack_ext(unpack_user& u, const char* p, uint64_t l, object& o) +{ + o.type = type::EXT; + if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { + o.via.ext.ptr = p; + u.set_referenced(true); + } + else { + char* tmp = static_cast(u.zone().allocate_align(l)); + std::memcpy(tmp, p, l); + o.via.ext.ptr = tmp; + } + o.via.ext.size = l - 1; } @@ -167,14 +203,14 @@ public: std::size_t count() const { return m_count; } void set_count(std::size_t count) { m_count = count; } std::size_t decl_count() { return --m_count; } - unsigned int container_type() const { return m_container_type; } - void set_container_type(unsigned int container_type) { m_container_type = container_type; } + uint32_t container_type() const { return m_container_type; } + void set_container_type(uint32_t container_type) { m_container_type = container_type; } object const& map_key() const { return m_map_key; } void set_map_key(object const& map_key) { m_map_key = map_key; } private: object m_obj; std::size_t m_count; - unsigned int m_container_type; + uint32_t m_container_type; object m_map_key; }; @@ -210,12 +246,12 @@ struct value { }; template <> struct value { - typedef unsigned int type; + typedef uint32_t type; }; template -inline void load(unsigned int& dst, const char* n, typename msgpack::enable_if::type* = nullptr) { - dst = static_cast(*reinterpret_cast(n)) & 0x0f; +inline void load(uint32_t& dst, const char* n, typename msgpack::enable_if::type* = nullptr) { + dst = static_cast(*reinterpret_cast(n)) & 0x0f; } template @@ -240,7 +276,7 @@ inline void load(T& dst, const char* n, typename msgpack::enable_if(*m_current) & 0x03); + m_trail = 1 << (static_cast(*m_current) & 0x03); + m_cs = next_cs(m_current); + fixed_trail_again = true; + break; + + case 0xc7: // ext 8 + case 0xc8: // ext 16 + case 0xc9: // ext 32 + m_trail = 1 << ((static_cast(*m_current) + 1) & 0x03); m_cs = next_cs(m_current); fixed_trail_again = true; break; - //case 0xc7: - //case 0xc8: - //case 0xc9: case 0xca: // float case 0xcb: // double case 0xcc: // unsigned int 8 @@ -337,36 +381,49 @@ public: case 0xd1: // signed int 16 case 0xd2: // signed int 32 case 0xd3: // signed int 64 - m_trail = 1 << (static_cast(*m_current) & 0x03); + m_trail = 1 << (static_cast(*m_current) & 0x03); m_cs = next_cs(m_current); fixed_trail_again = true; break; - //case 0xd4: - //case 0xd5: - //case 0xd6: // big integer 16 - //case 0xd7: // big integer 32 - //case 0xd8: // big float 16 + + case 0xd4: // fixext 1 + case 0xd5: // fixext 2 + case 0xd6: // fixext 4 + case 0xd7: // fixext 8 + m_trail = (1 << (static_cast(*m_current) & 0x03)) + 1; + m_cs = next_cs(m_current); + fixed_trail_again = true; + break; + + case 0xd8: // fixext 16 + m_trail = 17; + m_cs = next_cs(m_current); + fixed_trail_again = true; + break; + case 0xd9: // str 8 case 0xda: // str 16 case 0xdb: // str 32 - m_trail = 1 << ((static_cast(*m_current) & 0x03) - 1); + m_trail = 1 << ((static_cast(*m_current) & 0x03) - 1); m_cs = next_cs(m_current); fixed_trail_again = true; break; + case 0xdc: // array 16 case 0xdd: // array 32 case 0xde: // map 16 case 0xdf: // map 32 - m_trail = 2 << (static_cast(*m_current) & 0x01); + m_trail = 2 << (static_cast(*m_current) & 0x01); m_cs = next_cs(m_current); fixed_trail_again = true; break; + default: off = m_current - m_start; return -1; } } else if(0xa0 <= selector && selector <= 0xbf) { // FixStr - m_trail = static_cast(*m_current) & 0x1f; + m_trail = static_cast(*m_current) & 0x1f; if(m_trail == 0) { unpack_str(m_user, data, n, m_trail, obj); int ret = push_proc(obj, off); @@ -479,6 +536,31 @@ public: int ret = push_proc(obj, off); if (ret != 0) return ret; } break; + case CS_FIXEXT_1: { + unpack_ext(m_user, n, 1+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_2: { + unpack_ext(m_user, n, 2+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_4: { + unpack_ext(m_user, n, 4+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_8: { + unpack_ext(m_user, n, 8+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; + case CS_FIXEXT_16: { + unpack_ext(m_user, n, 16+1, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; case CS_STR_8: { uint8_t tmp; load(tmp, n); @@ -507,6 +589,20 @@ public: fixed_trail_again = true; } } break; + case CS_EXT_8: { + uint8_t tmp; + load(tmp, n); + m_trail = tmp + 1; + if(m_trail == 0) { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_EXT_VALUE; + fixed_trail_again = true; + } + } break; case CS_STR_16: { uint16_t tmp; load(tmp, n); @@ -535,8 +631,24 @@ public: fixed_trail_again = true; } } break; - case CS_STR_32: - load(m_trail, n); + case CS_EXT_16: { + uint16_t tmp; + load(tmp, n); + m_trail = tmp + 1; + if(m_trail == 0) { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_EXT_VALUE; + fixed_trail_again = true; + } + } break; + case CS_STR_32: { + uint32_t tmp; + load(tmp, n); + m_trail = tmp; if(m_trail == 0) { unpack_str(m_user, data, n, m_trail, obj); int ret = push_proc(obj, off); @@ -546,9 +658,11 @@ public: m_cs = ACS_STR_VALUE; fixed_trail_again = true; } - break; - case CS_BIN_32: - load(m_trail, n); + } break; + case CS_BIN_32: { + uint32_t tmp; + load(tmp, n); + m_trail = tmp; if(m_trail == 0) { unpack_bin(m_user, data, n, m_trail, obj); int ret = push_proc(obj, off); @@ -558,7 +672,21 @@ public: m_cs = ACS_BIN_VALUE; fixed_trail_again = true; } - break; + } break; + case CS_EXT_32: { + uint32_t tmp; + load(tmp, n); + m_trail = tmp + 1; + if(m_trail == 0) { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } + else { + m_cs = ACS_EXT_VALUE; + fixed_trail_again = true; + } + } break; case ACS_STR_VALUE: { unpack_str(m_user, data, n, m_trail, obj); int ret = push_proc(obj, off); @@ -569,6 +697,11 @@ public: int ret = push_proc(obj, off); if (ret != 0) return ret; } break; + case ACS_EXT_VALUE: { + unpack_ext(m_user, n, m_trail, obj); + int ret = push_proc(obj, off); + if (ret != 0) return ret; + } break; case CS_ARRAY_16: { int ret = push_aggregate( unpack_array(), CT_ARRAY_ITEM, obj, n, off); @@ -604,15 +737,15 @@ public: private: template - static unsigned int next_cs(T p) + static uint32_t next_cs(T p) { - return static_cast(*p) & 0x1f; + return static_cast(*p) & 0x1f; } template int push_aggregate( Func const& f, - unsigned int container_type, + uint32_t container_type, object& obj, const char* load_pos, std::size_t& off) { @@ -706,11 +839,11 @@ private: char const* m_start; char const* m_current; - unsigned int m_trail; + uint64_t m_trail; unpack_user m_user; - unsigned int m_cs; - unsigned int m_top; - unsigned int m_stack_idx; + uint32_t m_cs; + uint32_t m_top; + uint32_t m_stack_idx; unpack_stack m_stack[MSGPACK_EMBED_STACK_SIZE]; }; @@ -730,7 +863,7 @@ struct unpack_error : public std::runtime_error { class unpacked { public: - unpacked() { } + unpacked():m_referenced(false) { } unpacked(object const& obj, msgpack::unique_ptr z) : m_obj(obj), m_zone(msgpack::move(z)) { } @@ -747,15 +880,24 @@ public: const msgpack::unique_ptr& zone() const { return m_zone; } + void set_referenced(bool r) + { m_referenced = r; } + + bool referenced() const + { return m_referenced; } + private: object m_obj; msgpack::unique_ptr m_zone; + bool m_referenced; }; class unpacker { public: - unpacker(std::size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE); + unpacker(unpack_reference_func f = &unpacker::default_reference_func, + void* user_data = nullptr, + std::size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE); #if !defined(MSGPACK_USE_CPP03) unpacker(unpacker&& other); @@ -854,6 +996,7 @@ private: void expand_buffer(std::size_t size); int execute_imp(); bool flush_zone(); + static bool default_reference_func(type::object_type type, uint64_t len, void*); private: char* m_buffer; @@ -871,14 +1014,19 @@ private: }; inline void unpack(unpacked& result, - const char* data, std::size_t len, std::size_t& off); + const char* data, std::size_t len, std::size_t& off, + unpack_reference_func f = nullptr, void* user_data = nullptr); inline void unpack(unpacked& result, - const char* data, std::size_t len); -// obsolete -inline void unpack(unpacked* result, - const char* data, std::size_t len, std::size_t* off = nullptr); + const char* data, std::size_t len, + unpack_reference_func f = nullptr, void* user_data = nullptr); // obsolete +inline void unpack(unpacked* result, + const char* data, std::size_t len, std::size_t* off = nullptr, + unpack_reference_func f = nullptr, void* user_data = nullptr); + + +// for internal use typedef enum { UNPACK_SUCCESS = 2, UNPACK_EXTRA_BYTES = 1, @@ -886,22 +1034,10 @@ typedef enum { UNPACK_PARSE_ERROR = -1 } unpack_return; -// obsolete -static unpack_return unpack(const char* data, std::size_t len, std::size_t& off, - zone& z, object& result); -static unpack_return unpack(const char* data, std::size_t len, - zone& z, object& result); -static unpack_return unpack(const char* data, std::size_t len, std::size_t* off, - zone* z, object* result); - - -// obsolete -static object unpack(const char* data, std::size_t len, zone& z, std::size_t& off); -static object unpack(const char* data, std::size_t len, zone& z); -static object unpack(const char* data, std::size_t len, zone* z, std::size_t* off = nullptr); - - -inline unpacker::unpacker(std::size_t initial_buffer_size) +inline unpacker::unpacker(unpack_reference_func f, + void* user_data, + std::size_t initial_buffer_size) + :m_ctx(f, user_data) { if(initial_buffer_size < COUNTER_SIZE) { initial_buffer_size = COUNTER_SIZE; @@ -1012,7 +1148,7 @@ inline void unpacker::expand_buffer(std::size_t size) detail::init_count(tmp); - ::memcpy(tmp+COUNTER_SIZE, m_buffer + m_off, not_parsed); + std::memcpy(tmp+COUNTER_SIZE, m_buffer + m_off, not_parsed); if(m_ctx.user().referenced()) { try { @@ -1066,6 +1202,7 @@ inline bool unpacker::next(unpacked& result) } else { result.zone().reset( release_zone() ); result.set(data()); + result.set_referenced(m_ctx.user().referenced()); reset(); return true; } @@ -1184,7 +1321,8 @@ namespace detail { inline unpack_return unpack_imp(const char* data, std::size_t len, std::size_t& off, - zone& result_zone, object& result) + zone& result_zone, object& result, bool& referenced, + unpack_reference_func f = nullptr, void* user_data = nullptr) { std::size_t noff = off; @@ -1193,17 +1331,19 @@ unpack_imp(const char* data, std::size_t len, std::size_t& off, return UNPACK_CONTINUE; } - detail::context ctx; + detail::context ctx(f, user_data); ctx.init(); ctx.user().set_zone(result_zone); ctx.user().set_referenced(false); + referenced = false; int e = ctx.execute(data, len, noff); if(e < 0) { return UNPACK_PARSE_ERROR; } + referenced = ctx.user().referenced(); off = noff; if(e == 0) { @@ -1223,29 +1363,28 @@ unpack_imp(const char* data, std::size_t len, std::size_t& off, // reference version inline void unpack(unpacked& result, - const char* data, std::size_t len, std::size_t& off) + const char* data, std::size_t len, std::size_t& off, + unpack_reference_func f, void* user_data) { object obj; msgpack::unique_ptr z(new zone()); - + bool referenced = false; unpack_return ret = detail::unpack_imp( - data, len, off, *z, obj); + data, len, off, *z, obj, referenced); + result.set_referenced(referenced); switch(ret) { case UNPACK_SUCCESS: result.set(obj); result.zone() = msgpack::move(z); return; - case UNPACK_EXTRA_BYTES: result.set(obj); result.zone() = msgpack::move(z); return; - case UNPACK_CONTINUE: throw unpack_error("insufficient bytes"); - case UNPACK_PARSE_ERROR: default: throw unpack_error("parse error"); @@ -1253,88 +1392,29 @@ inline void unpack(unpacked& result, } inline void unpack(unpacked& result, - const char* data, std::size_t len) + const char* data, std::size_t len, + unpack_reference_func f, void* user_data) { std::size_t off = 0; - return unpack(result, data, len, off); + unpack(result, data, len, off, f, user_data); } // obsolete // pointer version inline void unpack(unpacked* result, - const char* data, std::size_t len, std::size_t* off) { + const char* data, std::size_t len, std::size_t* off, + unpack_reference_func f, void* user_data) +{ if (off) unpack(*result, data, len, *off); - else unpack(*result, data, len); + else unpack(*result, data, len, f, user_data); } - -// obsolete -// reference version -inline unpack_return unpack(const char* data, std::size_t len, std::size_t& off, - zone& z, object& result) +bool unpacker::default_reference_func(type::object_type type, uint64_t len, void*) { - return detail::unpack_imp(data, len, off, z, result); -} - -// obsolete -inline unpack_return unpack(const char* data, std::size_t len, - zone& z, object& result) -{ - std::size_t off = 0; - return detail::unpack_imp(data, len, off, z, result); -} - -// obsolete -// pointer version -inline unpack_return unpack(const char* data, std::size_t len, std::size_t* off, - zone* z, object* result) -{ - if (off) return unpack(data, len, *off, *z, *result); - else return unpack(data, len, *z, *result); -} - -// obsolete -// reference version -inline object unpack(const char* data, std::size_t len, zone& z, std::size_t& off) -{ - object result; - - switch( unpack(data, len, off, z, result) ) { - case UNPACK_SUCCESS: - return result; - - case UNPACK_EXTRA_BYTES: - if(off) { - return result; - } else { - throw unpack_error("extra bytes"); - } - - case UNPACK_CONTINUE: - throw unpack_error("insufficient bytes"); - - case UNPACK_PARSE_ERROR: - default: - throw unpack_error("parse error"); - } -} - -// obsolete -inline object unpack(const char* data, std::size_t len, zone& z) -{ - std::size_t off = 0; - return unpack(data, len, z, off); -} - - -// obsolete -// pointer version -inline object unpack(const char* data, std::size_t len, zone* z, std::size_t* off) -{ - if (off) return unpack(data, len, *z, *off); - else return unpack(data, len, *z); + return true; } } // namespace msgpack + #endif /* msgpack/unpack.hpp */ diff --git a/include/msgpack/unpack_define.h b/include/msgpack/unpack_define.h index 182137f8..d37183d3 100644 --- a/include/msgpack/unpack_define.h +++ b/include/msgpack/unpack_define.h @@ -45,9 +45,9 @@ typedef enum { CS_BIN_16 = 0x05, CS_BIN_32 = 0x06, - //CS_EXT_8 = 0x07, - //CS_EXT_16 = 0x08, - //CS_EXT_32 = 0x09, + CS_EXT_8 = 0x07, + CS_EXT_16 = 0x08, + CS_EXT_32 = 0x09, CS_FLOAT = 0x0a, CS_DOUBLE = 0x0b, @@ -60,11 +60,11 @@ typedef enum { CS_INT_32 = 0x12, CS_INT_64 = 0x13, - //CS_FIXEXT_1 = 0x14, - //CS_FIXEXT_2 = 0x15, - //CS_FIXEXT_4 = 0x16, - //CS_FIXEXT_8 = 0x17, - //CS_FIXEXT_16 = 0x18, + CS_FIXEXT_1 = 0x14, + CS_FIXEXT_2 = 0x15, + CS_FIXEXT_4 = 0x16, + CS_FIXEXT_8 = 0x17, + CS_FIXEXT_16 = 0x18, CS_STR_8 = 0x19, // str8 CS_STR_16 = 0x1a, // str16 @@ -77,7 +77,8 @@ typedef enum { //ACS_BIG_INT_VALUE, //ACS_BIG_FLOAT_VALUE, ACS_STR_VALUE, - ACS_BIN_VALUE + ACS_BIN_VALUE, + ACS_EXT_VALUE } msgpack_unpack_state; diff --git a/test/msgpack_test.cpp b/test/msgpack_test.cpp index e678385f..8dda3f39 100644 --- a/test/msgpack_test.cpp +++ b/test/msgpack_test.cpp @@ -274,6 +274,170 @@ TEST(MSGPACK, simple_buffer_false) EXPECT_EQ(val1, val2); } +TEST(MSGPACK, simple_buffer_fixext1) +{ + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char const buf [] = { 2 }; + + packer.pack_ext(sizeof(buf), 1); + packer.pack_ext_body(buf, sizeof(buf)); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(1, ret.get().via.ext.size); + EXPECT_EQ(1, ret.get().via.ext.type()); + EXPECT_EQ(2, ret.get().via.ext.data()[0]); +} + +TEST(MSGPACK, simple_buffer_fixext2) +{ + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char const buf [] = { 2, 3 }; + + packer.pack_ext(sizeof(buf), 0); + packer.pack_ext_body(buf, sizeof(buf)); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(2, ret.get().via.ext.size); + EXPECT_EQ(0, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext4) +{ + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char const buf [] = { 2, 3, 4, 5 }; + + packer.pack_ext(sizeof(buf), 1); + packer.pack_ext_body(buf, sizeof(buf)); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(4, ret.get().via.ext.size); + EXPECT_EQ(1, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext8) +{ + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char const buf [] = { 2, 3, 4, 5, 6, 7, 8, 9 }; + + packer.pack_ext(sizeof(buf), 1); + packer.pack_ext_body(buf, sizeof(buf)); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(8, ret.get().via.ext.size); + EXPECT_EQ(1, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext16) +{ + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char const buf [] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; + + packer.pack_ext(sizeof(buf), 1); + packer.pack_ext_body(buf, sizeof(buf)); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(16, ret.get().via.ext.size); + EXPECT_EQ(1, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext_1byte_0) +{ + std::size_t const size = 0; + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + + packer.pack_ext(size, 77); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(size, ret.get().via.ext.size); + EXPECT_EQ(77, ret.get().via.ext.type()); +} + +TEST(MSGPACK, simple_buffer_fixext_1byte_255) +{ + std::size_t const size = 255; + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char buf[size]; + for (int i = 0; i != size; ++i) buf[i] = static_cast(i); + packer.pack_ext(sizeof(buf), 77); + packer.pack_ext_body(buf, sizeof(buf)); + + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(size, ret.get().via.ext.size); + EXPECT_EQ(77, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext_2byte_256) +{ + std::size_t const size = 256; + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char buf[size]; + for (int i = 0; i != size; ++i) buf[i] = static_cast(i); + packer.pack_ext(sizeof(buf), 77); + packer.pack_ext_body(buf, sizeof(buf)); + + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(size, ret.get().via.ext.size); + EXPECT_EQ(77, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext_2byte_65535) +{ + std::size_t const size = 65535; + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char buf[size]; + for (int i = 0; i != size; ++i) buf[i] = static_cast(i); + packer.pack_ext(sizeof(buf), 77); + packer.pack_ext_body(buf, sizeof(buf)); + + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(size, ret.get().via.ext.size); + EXPECT_EQ(77, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + +TEST(MSGPACK, simple_buffer_fixext_4byte_65536) +{ + std::size_t const size = 65536; + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + char buf[size]; + for (int i = 0; i != size; ++i) buf[i] = static_cast(i); + packer.pack_ext(sizeof(buf), 77); + packer.pack_ext_body(buf, sizeof(buf)); + + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + EXPECT_EQ(size, ret.get().via.ext.size); + EXPECT_EQ(77, ret.get().via.ext.type()); + EXPECT_TRUE( + std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data())); +} + //----------------------------------------------------------------------------- // STL @@ -707,16 +871,9 @@ TEST(MSGPACK_USER_DEFINED, simple_buffer_class_old_to_new) TestClass val1; msgpack::sbuffer sbuf; msgpack::pack(sbuf, val1); - msgpack::zone z; - msgpack::object obj; - msgpack::unpack_return ret = - msgpack::unpack(sbuf.data(), sbuf.size(), z, obj); - EXPECT_EQ(msgpack::UNPACK_SUCCESS, ret); - TestClass2 val2; - val2.i = -1; - val2.s = ""; - val2.v = vector(); - obj.convert(&val2); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + TestClass2 val2 = ret.get().as(); EXPECT_EQ(val1.i, val2.i); EXPECT_EQ(val1.s, val2.s); EXPECT_FALSE(val2.s.empty()); diff --git a/test/pack_unpack.cc b/test/pack_unpack.cc index 7f2afd45..b95bccde 100644 --- a/test/pack_unpack.cc +++ b/test/pack_unpack.cc @@ -49,88 +49,6 @@ TEST(pack, myclass) msgpack::pack(sbuf, m); } - -TEST(unpack, myclass_no_offset) -{ - msgpack::sbuffer sbuf; - myclass m1(1, "phraser"); - msgpack::pack(sbuf, m1); - - msgpack::zone z; - msgpack::object obj; - - // obsolete - msgpack::unpack_return ret = - msgpack::unpack(sbuf.data(), sbuf.size(), z, obj); - - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - - myclass m2 = obj.as(); - EXPECT_EQ(m1.num, m2.num); - EXPECT_EQ(m1.str, m2.str); -} - -TEST(unpack, myclass_offset) -{ - msgpack::sbuffer sbuf; - myclass m1(1, "phraser"); - msgpack::pack(sbuf, m1); - - msgpack::zone z; - msgpack::object obj; - std::size_t off = 0; - // obsolete - msgpack::unpack_return ret = - msgpack::unpack(sbuf.data(), sbuf.size(), off, z, obj); - - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - - myclass m2 = obj.as(); - EXPECT_EQ(m1.num, m2.num); - EXPECT_EQ(m1.str, m2.str); - EXPECT_EQ(off, sbuf.size()); -} - -TEST(unpack, myclass_offset_pointer) -{ - msgpack::sbuffer sbuf; - myclass m1(1, "phraser"); - msgpack::pack(sbuf, m1); - - msgpack::zone z; - msgpack::object obj; - std::size_t off = 0; - // obsolete - msgpack::unpack_return ret = - msgpack::unpack(sbuf.data(), sbuf.size(), &off, &z, &obj); - - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - - myclass m2 = obj.as(); - EXPECT_EQ(m1.num, m2.num); - EXPECT_EQ(m1.str, m2.str); - EXPECT_EQ(off, sbuf.size()); -} - -TEST(unpack, myclass_offset_null_pointer) -{ - msgpack::sbuffer sbuf; - myclass m1(1, "phraser"); - msgpack::pack(sbuf, m1); - - msgpack::zone z; - msgpack::object obj; - // obsolete - msgpack::unpack_return ret = - msgpack::unpack(sbuf.data(), sbuf.size(), nullptr, &z, &obj); - - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - - myclass m2 = obj.as(); - EXPECT_EQ(m1.num, m2.num); - EXPECT_EQ(m1.str, m2.str); -} - TEST(unpack, int_no_offset) { msgpack::sbuffer sbuf; @@ -212,106 +130,3 @@ TEST(unpack, sequence) EXPECT_EQ(off, sbuf.size()); } - -TEST(unpack_return, int_no_offset) -{ - msgpack::sbuffer sbuf; - msgpack::pack(sbuf, 1); - - msgpack::zone z; - msgpack::object obj; - msgpack::unpack_return ret; - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), z, obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - EXPECT_EQ(1, obj.as()); -} - -TEST(unpack_return, int_offset) -{ - msgpack::sbuffer sbuf; - msgpack::pack(sbuf, 1); - - std::size_t off = 0; - - msgpack::zone z; - msgpack::object obj; - msgpack::unpack_return ret; - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), off, z, obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - EXPECT_EQ(1, obj.as()); - EXPECT_EQ(off, sbuf.size()); -} - -TEST(unpack_return, int_pointer) -{ - msgpack::sbuffer sbuf; - msgpack::pack(sbuf, 1); - - std::size_t off = 0; - - msgpack::zone z; - msgpack::object obj; - msgpack::unpack_return ret; - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), &off, &z, &obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - EXPECT_EQ(1, obj.as()); - EXPECT_EQ(off, sbuf.size()); -} - -TEST(unpack_return, int_null_pointer) -{ - msgpack::sbuffer sbuf; - msgpack::pack(sbuf, 1); - - msgpack::zone z; - msgpack::object obj; - msgpack::unpack_return ret; - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), nullptr, &z, &obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - EXPECT_EQ(1, obj.as()); -} - - -TEST(unpack, sequence_compat) -{ - msgpack::sbuffer sbuf; - msgpack::pack(sbuf, 1); - msgpack::pack(sbuf, 2); - msgpack::pack(sbuf, 3); - - std::size_t off = 0; - - msgpack::zone z; - msgpack::object obj; - msgpack::unpack_return ret; - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), off, z, obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_EXTRA_BYTES); - EXPECT_EQ(1, obj.as()); - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), off, z, obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_EXTRA_BYTES); - EXPECT_EQ(2, obj.as()); - - // obsolete - ret = msgpack::unpack(sbuf.data(), sbuf.size(), off, z, obj); - EXPECT_TRUE(ret >= 0); - EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS); - EXPECT_EQ(3, obj.as()); -}