diff --git a/erb/cpp03_zone.hpp.erb b/erb/cpp03_zone.hpp.erb index 963c4486..933109af 100644 --- a/erb/cpp03_zone.hpp.erb +++ b/erb/cpp03_zone.hpp.erb @@ -308,6 +308,12 @@ inline void zone::undo_allocate(size_t size) m_chunk_list.m_free += size; } +inline std::size_t aligned_size( + std::size_t size, + std::size_t align = MSGPACK_ZONE_ALIGN) { + return (size + align - 1) / align * align; +} + /// @cond <%0.upto(GENERATION_LIMIT) {|i|%> template , typename A<%=j%><%}%>> diff --git a/include/msgpack/detail/cpp03_zone.hpp b/include/msgpack/detail/cpp03_zone.hpp index 08a29144..e89d7307 100644 --- a/include/msgpack/detail/cpp03_zone.hpp +++ b/include/msgpack/detail/cpp03_zone.hpp @@ -353,6 +353,12 @@ inline void zone::undo_allocate(size_t size) m_chunk_list.m_free += size; } +inline std::size_t aligned_size( + std::size_t size, + std::size_t align = MSGPACK_ZONE_ALIGN) { + return (size + align - 1) / align * align; +} + /// @cond template diff --git a/include/msgpack/detail/cpp11_zone.hpp b/include/msgpack/detail/cpp11_zone.hpp index 4edd8434..8010d760 100644 --- a/include/msgpack/detail/cpp11_zone.hpp +++ b/include/msgpack/detail/cpp11_zone.hpp @@ -363,6 +363,12 @@ T* zone::allocate(Args... args) } } +inline std::size_t aligned_size( + std::size_t size, + std::size_t align = MSGPACK_ZONE_ALIGN) { + return (size + align - 1) / align * align; +} + /// @cond } // MSGPACK_API_VERSION_NAMESPACE(v1) /// @endcond diff --git a/include/msgpack/object.hpp b/include/msgpack/object.hpp index 3a56f262..fe40f844 100644 --- a/include/msgpack/object.hpp +++ b/include/msgpack/object.hpp @@ -36,6 +36,117 @@ namespace msgpack { MSGPACK_API_VERSION_NAMESPACE(v1) { /// @endcond +class object_handle { +public: + object_handle() {} + + object_handle(msgpack::object const& obj, msgpack::unique_ptr z) : + m_obj(obj), m_zone(msgpack::move(z)) { } + + // obsolete + void set(msgpack::object const& obj) + { m_obj = obj; } + + const msgpack::object& get() const + { return m_obj; } + + msgpack::unique_ptr& zone() + { return m_zone; } + + const msgpack::unique_ptr& zone() const + { return m_zone; } + +#if defined(MSGPACK_USE_CPP03) + struct object_handle_ref { + object_handle_ref(object_handle* oh):m_oh(oh) {} + object_handle* m_oh; + }; + + object_handle(object_handle& other): + m_obj(other.m_obj), + m_zone(msgpack::move(other.m_zone)) { + } + + object_handle(object_handle_ref ref): + m_obj(ref.m_oh->m_obj), + m_zone(msgpack::move(ref.m_oh->m_zone)) { + } + + object_handle& operator=(object_handle& other) { + m_obj = other.m_obj; + m_zone = msgpack::move(other.m_zone); + return *this; + } + + object_handle& operator=(object_handle_ref ref) { + m_obj = ref.m_oh->m_obj; + m_zone = msgpack::move(ref.m_oh->m_zone); + return *this; + } + + operator object_handle_ref() { + return object_handle_ref(this); + } +#endif // defined(MSGPACK_USE_CPP03) + +private: + msgpack::object m_obj; + msgpack::unique_ptr m_zone; +}; + +namespace detail { + +template +inline std::size_t add_ext_type_size(std::size_t size) { + return size + 1; +} + +template <> +inline std::size_t add_ext_type_size<4>(std::size_t size) { + return size == 0xffffffff ? size : size + 1; +} + +} // namespace detail + +inline std::size_t aligned_zone_size(msgpack::object const& obj) { + std::size_t s = 0; + switch (obj.type) { + case msgpack::type::ARRAY: + s += sizeof(msgpack::object) * obj.via.array.size; + for (uint32_t i = 0; i < obj.via.array.size; ++i) { + s += msgpack::aligned_zone_size(obj.via.array.ptr[i]); + } + break; + case msgpack::type::MAP: + s += sizeof(msgpack::object_kv) * obj.via.map.size; + for (uint32_t i = 0; i < obj.via.map.size; ++i) { + s += msgpack::aligned_zone_size(obj.via.map.ptr[i].key); + s += msgpack::aligned_zone_size(obj.via.map.ptr[i].val); + } + break; + case msgpack::type::EXT: + s += msgpack::aligned_size( + detail::add_ext_type_size(obj.via.ext.size)); + break; + case msgpack::type::STR: + s += msgpack::aligned_size(obj.via.str.size); + break; + case msgpack::type::BIN: + s += msgpack::aligned_size(obj.via.bin.size); + break; + default: + break; + } + return s; +} + +inline object_handle clone(msgpack::object const& obj) { + std::size_t size = msgpack::aligned_zone_size(obj); + msgpack::unique_ptr z(size == 0 ? nullptr : new msgpack::zone(size)); + msgpack::object newobj = z.get() ? msgpack::object(obj, *z) : obj; + return object_handle(newobj, msgpack::move(z)); +} + struct object::implicit_type { implicit_type(object const& o) : obj(o) { } ~implicit_type() { } diff --git a/include/msgpack/unpack.hpp b/include/msgpack/unpack.hpp index 1b867327..8bd2f510 100644 --- a/include/msgpack/unpack.hpp +++ b/include/msgpack/unpack.hpp @@ -991,30 +991,7 @@ inline int context::execute(const char* data, std::size_t len, std::size_t& off) } // detail -class unpacked { -public: - unpacked() {} - - unpacked(msgpack::object const& obj, msgpack::unique_ptr z) : - m_obj(obj), m_zone(msgpack::move(z)) { } - - void set(msgpack::object const& obj) - { m_obj = obj; } - - const msgpack::object& get() const - { return m_obj; } - - msgpack::unique_ptr& zone() - { return m_zone; } - - const msgpack::unique_ptr& zone() const - { return m_zone; } - -private: - msgpack::object m_obj; - msgpack::unique_ptr m_zone; -}; - +typedef object_handle unpacked; class unpacker { public: @@ -1143,8 +1120,6 @@ private: #endif // defined(MSGPACK_USE_CPP03) }; -#if !defined(MSGPACK_USE_CPP03) - unpacked unpack( const char* data, std::size_t len, std::size_t& off, bool& referenced, unpack_reference_func f = nullptr, void* user_data = nullptr, @@ -1162,8 +1137,6 @@ unpacked unpack( unpack_reference_func f = nullptr, void* user_data = nullptr, unpack_limit const& limit = unpack_limit()); -#endif // !defined(MSGPACK_USE_CPP03) - void unpack(unpacked& result, const char* data, std::size_t len, std::size_t& off, bool& referenced, @@ -1554,8 +1527,6 @@ unpack_imp(const char* data, std::size_t len, std::size_t& off, // reference version -#if !defined(MSGPACK_USE_CPP03) - inline unpacked unpack( const char* data, std::size_t len, std::size_t& off, bool& referenced, unpack_reference_func f, void* user_data, unpack_limit const& limit) @@ -1605,8 +1576,6 @@ inline unpacked unpack( return unpack(data, len, off, referenced, f, user_data, limit); } -#endif // !defined(MSGPACK_USE_CPP03) - inline void unpack(unpacked& result, const char* data, std::size_t len, std::size_t& off, bool& referenced, unpack_reference_func f, void* user_data, unpack_limit const& limit) diff --git a/test/object.cpp b/test/object.cpp index 148b54b0..ec271824 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -340,3 +340,81 @@ TEST(object, construct_class_enum_outer) } #endif // !defined(MSGPACK_USE_CPP03) + +TEST(object, clone_int) +{ + int v = 0; + msgpack::object obj(v); + std::size_t sz1 = msgpack::aligned_zone_size(obj); + msgpack::object_handle h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); + h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); +} + +TEST(object, clone_str) +{ + msgpack::zone z; + std::string v = "123456789"; + msgpack::object obj(v, z); + std::size_t sz1 = msgpack::aligned_zone_size(obj); + msgpack::object_handle h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); + h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); +} + +TEST(object, clone_bin) +{ + msgpack::zone z; + std::vector v; + v.push_back('A'); + v.push_back('B'); + v.push_back('C'); + msgpack::object obj(v, z); + std::size_t sz1 = msgpack::aligned_zone_size(obj); + msgpack::object_handle h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); + h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); +} + +TEST(object, clone_array) +{ + msgpack::zone z; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + msgpack::object obj(v, z); + std::size_t sz1 = msgpack::aligned_zone_size(obj); + msgpack::object_handle h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); + h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); +} + +TEST(object, clone_map) +{ + msgpack::zone z; + std::map v; + v.insert(std::map::value_type(1, "ABC")); + v.insert(std::map::value_type(2, "DEF")); + v.insert(std::map::value_type(3, "GHI")); + msgpack::object obj(v, z); + std::size_t sz1 = msgpack::aligned_zone_size(obj); + msgpack::object_handle h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); + h = msgpack::clone(obj); + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); +} diff --git a/test/pack_unpack.cpp b/test/pack_unpack.cpp index ee909661..9e02e0e1 100644 --- a/test/pack_unpack.cpp +++ b/test/pack_unpack.cpp @@ -50,8 +50,6 @@ TEST(pack, myclass) } -#if !defined(MSGPACK_USE_CPP03) - TEST(unpack, int_ret_no_offset_no_ref) { msgpack::sbuffer sbuf; @@ -97,8 +95,6 @@ TEST(unpack, int_ret_offset_ref) EXPECT_EQ(off, sbuf.size()); } -#endif // !defined(MSGPACK_USE_CPP03) - TEST(unpack, int_no_offset_no_ref) { @@ -290,3 +286,34 @@ TEST(unpack, sequence) EXPECT_EQ(off, sbuf.size()); } + + +TEST(unpack, convert_to_object_handle) +{ + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, 1); + msgpack::unpacked msg; + + msgpack::unpack(msg, sbuf.data(), sbuf.size()); + msgpack::object_handle oh(msgpack::move(msg)); + EXPECT_EQ(1, oh.get().as()); + +} + +TEST(unpack, convert_to_object_handle_direct) +{ + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, 1); + msgpack::object_handle oh(msgpack::unpack(sbuf.data(), sbuf.size())); + EXPECT_EQ(1, oh.get().as()); + +} + +TEST(unpack, convert_to_object_handle_direct_implicit) +{ + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, 1); + msgpack::object_handle oh = msgpack::unpack(sbuf.data(), sbuf.size()); + EXPECT_EQ(1, oh.get().as()); + +}