Added a clone function for msgpack::object.

The function prepares zone's chunk that has minimal size to deep copy.
This commit is contained in:
Takatoshi Kondo
2015-05-20 12:43:03 +09:00
parent 432c9cc542
commit e18f5b2d52
7 changed files with 187 additions and 26 deletions

View File

@@ -308,6 +308,12 @@ inline void zone::undo_allocate(size_t size)
m_chunk_list.m_free += 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 /// @cond
<%0.upto(GENERATION_LIMIT) {|i|%> <%0.upto(GENERATION_LIMIT) {|i|%>
template <typename T<%1.upto(i) {|j|%>, typename A<%=j%><%}%>> template <typename T<%1.upto(i) {|j|%>, typename A<%=j%><%}%>>

View File

@@ -63,9 +63,9 @@ T& move(T& t)
} }
template <typename T> template <typename T>
T const& move(T const& t) T& move(T const& t)
{ {
return t; return const_cast<T&>(t);
} }
template <bool P, typename T = void> template <bool P, typename T = void>

View File

@@ -353,6 +353,12 @@ inline void zone::undo_allocate(size_t size)
m_chunk_list.m_free += 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 /// @cond
template <typename T> template <typename T>

View File

@@ -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 /// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v1) } // MSGPACK_API_VERSION_NAMESPACE(v1)
/// @endcond /// @endcond

View File

@@ -36,6 +36,89 @@ namespace msgpack {
MSGPACK_API_VERSION_NAMESPACE(v1) { MSGPACK_API_VERSION_NAMESPACE(v1) {
/// @endcond /// @endcond
class object_handle {
public:
object_handle() {}
object_handle(msgpack::object const& obj, msgpack::unique_ptr<msgpack::zone> 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<msgpack::zone>& zone()
{ return m_zone; }
const msgpack::unique_ptr<msgpack::zone>& zone() const
{ return m_zone; }
private:
msgpack::object m_obj;
msgpack::unique_ptr<msgpack::zone> m_zone;
};
namespace detail {
template <std::size_t N>
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<sizeof(std::size_t)>(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<msgpack::zone> 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 { struct object::implicit_type {
implicit_type(object const& o) : obj(o) { } implicit_type(object const& o) : obj(o) { }
~implicit_type() { } ~implicit_type() { }

View File

@@ -991,30 +991,7 @@ inline int context::execute(const char* data, std::size_t len, std::size_t& off)
} // detail } // detail
class unpacked { typedef object_handle unpacked;
public:
unpacked() {}
unpacked(msgpack::object const& obj, msgpack::unique_ptr<msgpack::zone> 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<msgpack::zone>& zone()
{ return m_zone; }
const msgpack::unique_ptr<msgpack::zone>& zone() const
{ return m_zone; }
private:
msgpack::object m_obj;
msgpack::unique_ptr<msgpack::zone> m_zone;
};
class unpacker { class unpacker {
public: public:

View File

@@ -340,3 +340,86 @@ TEST(object, construct_class_enum_outer)
} }
#endif // !defined(MSGPACK_USE_CPP03) #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<char> 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<int> 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<int, std::string> v;
v.insert(std::map<int, std::string>::value_type(1, "ABC"));
v.insert(std::map<int, std::string>::value_type(2, "DEF"));
v.insert(std::map<int, std::string>::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()));
}