From e18f5b2d52d9df0ef9b578d725d646b6d864334b Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Wed, 20 May 2015 12:43:03 +0900 Subject: [PATCH] Added a clone function for msgpack::object. The function prepares zone's chunk that has minimal size to deep copy. --- erb/cpp03_zone.hpp.erb | 6 ++ include/msgpack/cpp_config.hpp | 4 +- include/msgpack/detail/cpp03_zone.hpp | 6 ++ include/msgpack/detail/cpp11_zone.hpp | 6 ++ include/msgpack/object.hpp | 83 +++++++++++++++++++++++++++ include/msgpack/unpack.hpp | 25 +------- test/object.cpp | 83 +++++++++++++++++++++++++++ 7 files changed, 187 insertions(+), 26 deletions(-) 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/cpp_config.hpp b/include/msgpack/cpp_config.hpp index f9cf3f3f..6c392799 100644 --- a/include/msgpack/cpp_config.hpp +++ b/include/msgpack/cpp_config.hpp @@ -63,9 +63,9 @@ T& move(T& t) } template -T const& move(T const& t) +T& move(T const& t) { - return t; + return const_cast(t); } template 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 03dd8689..8e893b92 100644 --- a/include/msgpack/object.hpp +++ b/include/msgpack/object.hpp @@ -36,6 +36,89 @@ 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)) { } + + // deprecated + 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; +}; + +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)); +#if defined(MSGPACK_USE_CPP03) + msgpack::object newobj = z.get() ? msgpack::move(msgpack::object(obj, *z)) : msgpack::move(obj); + return msgpack::move(object_handle(newobj, msgpack::move(z))); +#else // defined(MSGPACK_USE_CPP03) + msgpack::object newobj = z ? msgpack::object(obj, *z) : obj; + return object_handle(newobj, msgpack::move(z)); +#endif // defined(MSGPACK_USE_CPP03) +} + 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..cf009d3a 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: diff --git a/test/object.cpp b/test/object.cpp index 148b54b0..be929695 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -340,3 +340,86 @@ 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); +#if defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::move(msgpack::clone(obj)); +#else // defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::clone(obj); +#endif // defined(MSGPACK_USE_CPP03) + 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); +#if defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::move(msgpack::clone(obj)); +#else // defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::clone(obj); +#endif // defined(MSGPACK_USE_CPP03) + 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); +#if defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::move(msgpack::clone(obj)); +#else // defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::clone(obj); +#endif // defined(MSGPACK_USE_CPP03) + 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); +#if defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::move(msgpack::clone(obj)); +#else // defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::clone(obj); +#endif // defined(MSGPACK_USE_CPP03) + 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); +#if defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::move(msgpack::clone(obj)); +#else // defined(MSGPACK_USE_CPP03) + msgpack::object_handle h = msgpack::clone(obj); +#endif // defined(MSGPACK_USE_CPP03) + EXPECT_EQ(h.get(), obj); + EXPECT_EQ(sz1, msgpack::aligned_zone_size(h.get())); +}