From 9162610682adf5596ec18c1de4caed650fa7de37 Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Fri, 5 Dec 2014 15:40:33 +0900 Subject: [PATCH] Added adaptors for the C++11 version of unordered containers. (Fixed https://github.com/msgpack/msgpack-c/issues/168) --- CMakeLists.txt | 4 + .../msgpack/adaptor/cpp11/unordered_map.hpp | 137 ++++++++++++++++++ .../adaptor/cpp11/unordered_map_fwd.hpp | 53 +++++++ .../msgpack/adaptor/cpp11/unordered_set.hpp | 129 +++++++++++++++++ .../adaptor/cpp11/unordered_set_fwd.hpp | 52 +++++++ include/msgpack/object.hpp | 11 +- include/msgpack/type.hpp | 9 +- src/Makefile.am | 4 + test/msgpack_cpp11.cpp | 65 +++++++++ 9 files changed, 460 insertions(+), 4 deletions(-) create mode 100644 include/msgpack/adaptor/cpp11/unordered_map.hpp create mode 100644 include/msgpack/adaptor/cpp11/unordered_map_fwd.hpp create mode 100644 include/msgpack/adaptor/cpp11/unordered_set.hpp create mode 100644 include/msgpack/adaptor/cpp11/unordered_set_fwd.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ccfdde2f..58661a53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,10 @@ IF (MSGPACK_ENABLE_CXX) include/msgpack/adaptor/cpp11/forward_list_fwd.hpp include/msgpack/adaptor/cpp11/tuple.hpp include/msgpack/adaptor/cpp11/tuple_fwd.hpp + include/msgpack/adaptor/cpp11/unordered_map.hpp + include/msgpack/adaptor/cpp11/unordered_map_fwd.hpp + include/msgpack/adaptor/cpp11/unordered_set.hpp + include/msgpack/adaptor/cpp11/unordered_set_fwd.hpp include/msgpack/adaptor/define.hpp include/msgpack/adaptor/deque.hpp include/msgpack/adaptor/deque_fwd.hpp diff --git a/include/msgpack/adaptor/cpp11/unordered_map.hpp b/include/msgpack/adaptor/cpp11/unordered_map.hpp new file mode 100644 index 00000000..6d31cf86 --- /dev/null +++ b/include/msgpack/adaptor/cpp11/unordered_map.hpp @@ -0,0 +1,137 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2014 KONDO Takatoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef MSGPACK_TYPE_UNORDERED_MAP_HPP +#define MSGPACK_TYPE_UNORDERED_MAP_HPP + +#include "msgpack/versioning.hpp" +#include "msgpack/object_fwd.hpp" + +#include + +namespace msgpack { + +MSGPACK_API_VERSION_NAMESPACE(v1) { + +template +inline object const& operator>> (object const& o, std::unordered_map& v) +{ + if(o.type != type::MAP) { throw type_error(); } + object_kv* p(o.via.map.ptr); + object_kv* const pend(o.via.map.ptr + o.via.map.size); + std::unordered_map tmp; + for(; p != pend; ++p) { + K key; + p->key.convert(key); + p->val.convert(tmp[key]); + } + tmp.swap(v); + return o; +} + +template +inline packer& operator<< (packer& o, const std::unordered_map& v) +{ + o.pack_map(v.size()); + for(typename std::unordered_map::const_iterator it(v.begin()), it_end(v.end()); + it != it_end; ++it) { + o.pack(it->first); + o.pack(it->second); + } + return o; +} + +template +inline void operator<< (object::with_zone& o, const std::unordered_map& v) +{ + o.type = type::MAP; + if(v.empty()) { + o.via.map.ptr = nullptr; + o.via.map.size = 0; + } else { + object_kv* p = static_cast(o.zone.allocate_align(sizeof(object_kv)*v.size())); + object_kv* const pend = p + v.size(); + o.via.map.ptr = p; + o.via.map.size = v.size(); + typename std::unordered_map::const_iterator it(v.begin()); + do { + p->key = object(it->first, o.zone); + p->val = object(it->second, o.zone); + ++p; + ++it; + } while(p < pend); + } +} + + +template +inline object const& operator>> (object const& o, std::unordered_multimap& v) +{ + if(o.type != type::MAP) { throw type_error(); } + object_kv* p(o.via.map.ptr); + object_kv* const pend(o.via.map.ptr + o.via.map.size); + std::unordered_multimap tmp; + for(; p != pend; ++p) { + std::pair value; + p->key.convert(value.first); + p->val.convert(value.second); + tmp.insert(value); + } + tmp.swap(v); + return o; +} + +template +inline packer& operator<< (packer& o, const std::unordered_multimap& v) +{ + o.pack_map(v.size()); + for(typename std::unordered_multimap::const_iterator it(v.begin()), it_end(v.end()); + it != it_end; ++it) { + o.pack(it->first); + o.pack(it->second); + } + return o; +} + +template +inline void operator<< (object::with_zone& o, const std::unordered_multimap& v) +{ + o.type = type::MAP; + if(v.empty()) { + o.via.map.ptr = nullptr; + o.via.map.size = 0; + } else { + object_kv* p = static_cast(o.zone.allocate_align(sizeof(object_kv)*v.size())); + object_kv* const pend = p + v.size(); + o.via.map.ptr = p; + o.via.map.size = v.size(); + typename std::unordered_multimap::const_iterator it(v.begin()); + do { + p->key = object(it->first, o.zone); + p->val = object(it->second, o.zone); + ++p; + ++it; + } while(p < pend); + } +} + +} // MSGPACK_API_VERSION_NAMESPACE(v1) + +} // namespace msgpack + + +#endif // MSGPACK_TYPE_UNORDERED_MAP_HPP diff --git a/include/msgpack/adaptor/cpp11/unordered_map_fwd.hpp b/include/msgpack/adaptor/cpp11/unordered_map_fwd.hpp new file mode 100644 index 00000000..b6c66696 --- /dev/null +++ b/include/msgpack/adaptor/cpp11/unordered_map_fwd.hpp @@ -0,0 +1,53 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2014 KONDO Takatoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef MSGPACK_TYPE_UNORDERED_MAP_FWD_HPP +#define MSGPACK_TYPE_UNORDERED_MAP_FWD_HPP + +#include "msgpack/versioning.hpp" +#include "msgpack/object_fwd.hpp" + +#include + +namespace msgpack { + +MSGPACK_API_VERSION_NAMESPACE(v1) { + +template +object const& operator>> (object const& o, std::unordered_map& v); + +template +packer& operator<< (packer& o, const std::unordered_map& v); + +template +void operator<< (object::with_zone& o, const std::unordered_map& v); + +template +object const& operator>> (object const& o, std::unordered_multimap& v); + +template +packer& operator<< (packer& o, const std::unordered_multimap& v); + +template +void operator<< (object::with_zone& o, const std::unordered_multimap& v); + +} // MSGPACK_API_VERSION_NAMESPACE(v1) + +} // namespace msgpack + + +#endif // MSGPACK_TYPE_UNORDERED_MAP_FWD_HPP diff --git a/include/msgpack/adaptor/cpp11/unordered_set.hpp b/include/msgpack/adaptor/cpp11/unordered_set.hpp new file mode 100644 index 00000000..fe8eb3b1 --- /dev/null +++ b/include/msgpack/adaptor/cpp11/unordered_set.hpp @@ -0,0 +1,129 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2014 KONDO Takatoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef MSGPACK_TYPE_UNORDERED_SET_HPP +#define MSGPACK_TYPE_UNORDERED_SET_HPP + +#include "msgpack/versioning.hpp" +#include "msgpack/object_fwd.hpp" + +#include + +namespace msgpack { + +MSGPACK_API_VERSION_NAMESPACE(v1) { + +template +inline object const& operator>> (object const& o, std::unordered_set& v) +{ + if(o.type != type::ARRAY) { throw type_error(); } + object* p = o.via.array.ptr + o.via.array.size; + object* const pbegin = o.via.array.ptr; + std::unordered_set tmp; + while(p > pbegin) { + --p; + tmp.insert(p->as()); + } + tmp.swap(v); + return o; +} + +template +inline packer& operator<< (packer& o, const std::unordered_set& v) +{ + o.pack_array(v.size()); + for(typename std::unordered_set::const_iterator it(v.begin()), it_end(v.end()); + it != it_end; ++it) { + o.pack(*it); + } + return o; +} + +template +inline void operator<< (object::with_zone& o, const std::unordered_set& v) +{ + o.type = type::ARRAY; + if(v.empty()) { + o.via.array.ptr = nullptr; + o.via.array.size = 0; + } else { + object* p = static_cast(o.zone.allocate_align(sizeof(object)*v.size())); + object* const pend = p + v.size(); + o.via.array.ptr = p; + o.via.array.size = v.size(); + typename std::unordered_set::const_iterator it(v.begin()); + do { + *p = object(*it, o.zone); + ++p; + ++it; + } while(p < pend); + } +} + + +template +inline object const& operator>> (object const& o, std::unordered_multiset& v) +{ + if(o.type != type::ARRAY) { throw type_error(); } + object* p = o.via.array.ptr + o.via.array.size; + object* const pbegin = o.via.array.ptr; + std::unordered_multiset tmp; + while(p > pbegin) { + --p; + tmp.insert(p->as()); + } + tmp.swap(v); + return o; +} + +template +inline packer& operator<< (packer& o, const std::unordered_multiset& v) +{ + o.pack_array(v.size()); + for(typename std::unordered_multiset::const_iterator it(v.begin()), it_end(v.end()); + it != it_end; ++it) { + o.pack(*it); + } + return o; +} + +template +inline void operator<< (object::with_zone& o, const std::unordered_multiset& v) +{ + o.type = type::ARRAY; + if(v.empty()) { + o.via.array.ptr = nullptr; + o.via.array.size = 0; + } else { + object* p = static_cast(o.zone.allocate_align(sizeof(object)*v.size())); + object* const pend = p + v.size(); + o.via.array.ptr = p; + o.via.array.size = v.size(); + typename std::unordered_multiset::const_iterator it(v.begin()); + do { + *p = object(*it, o.zone); + ++p; + ++it; + } while(p < pend); + } +} + +} // MSGPACK_API_VERSION_NAMESPACE(v1) + +} // namespace msgpack + +#endif // MSGPACK_TYPE_UNORDERED_SET_HPP diff --git a/include/msgpack/adaptor/cpp11/unordered_set_fwd.hpp b/include/msgpack/adaptor/cpp11/unordered_set_fwd.hpp new file mode 100644 index 00000000..7e03b5e0 --- /dev/null +++ b/include/msgpack/adaptor/cpp11/unordered_set_fwd.hpp @@ -0,0 +1,52 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2014 KONDO Takatoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef MSGPACK_TYPE_UNORDERED_SET_FWD_HPP +#define MSGPACK_TYPE_UNORDERED_SET_FWD_HPP + +#include "msgpack/versioning.hpp" +#include "msgpack/object_fwd.hpp" + +#include + +namespace msgpack { + +MSGPACK_API_VERSION_NAMESPACE(v1) { + +template +object const& operator>> (object const& o, std::unordered_set& v); + +template +packer& operator<< (packer& o, const std::unordered_set& v); + +template +void operator<< (object::with_zone& o, const std::unordered_set& v); + +template +object const& operator>> (object const& o, std::unordered_multiset& v); + +template +packer& operator<< (packer& o, const std::unordered_multiset& v); + +template +void operator<< (object::with_zone& o, const std::unordered_multiset& v); + +} // MSGPACK_API_VERSION_NAMESPACE(v1) + +} // namespace msgpack + +#endif // MSGPACK_TYPE_UNORDERED_SET_FWD_HPP diff --git a/include/msgpack/object.hpp b/include/msgpack/object.hpp index 9a1678e8..6421dba8 100644 --- a/include/msgpack/object.hpp +++ b/include/msgpack/object.hpp @@ -39,15 +39,22 @@ #include "msgpack/adaptor/string_fwd.hpp" #include "msgpack/adaptor/vector_fwd.hpp" #include "msgpack/adaptor/vector_char_fwd.hpp" + +#if defined(MSGPACK_USE_CPP03) + #include "msgpack/adaptor/tr1/unordered_map_fwd.hpp" #include "msgpack/adaptor/tr1/unordered_set_fwd.hpp" -#if !defined(MSGPACK_USE_CPP03) +#else // defined(MSGPACK_USE_CPP03) + #include "adaptor/cpp11/array_fwd.hpp" #include "adaptor/cpp11/array_char_fwd.hpp" #include "adaptor/cpp11/forward_list_fwd.hpp" #include "adaptor/cpp11/tuple_fwd.hpp" -#endif // !defined(MSGPACK_USE_CPP03) +#include "adaptor/cpp11/unordered_map_fwd.hpp" +#include "adaptor/cpp11/unordered_set_fwd.hpp" + +#endif // defined(MSGPACK_USE_CPP03) #include #include diff --git a/include/msgpack/type.hpp b/include/msgpack/type.hpp index ab10d9ed..e2963fab 100644 --- a/include/msgpack/type.hpp +++ b/include/msgpack/type.hpp @@ -16,14 +16,19 @@ #include "adaptor/vector_char.hpp" #include "adaptor/msgpack_tuple.hpp" #include "adaptor/define.hpp" + +#if defined(MSGPACK_USE_CPP03) + #include "adaptor/tr1/unordered_map.hpp" #include "adaptor/tr1/unordered_set.hpp" -#if !defined(MSGPACK_USE_CPP03) +#else // defined(MSGPACK_USE_CPP03) #include "adaptor/cpp11/array.hpp" #include "adaptor/cpp11/array_char.hpp" #include "adaptor/cpp11/forward_list.hpp" #include "adaptor/cpp11/tuple.hpp" +#include "adaptor/cpp11/unordered_map.hpp" +#include "adaptor/cpp11/unordered_set.hpp" -#endif // !defined(MSGPACK_USE_CPP03) +#endif // defined(MSGPACK_USE_CPP03) diff --git a/src/Makefile.am b/src/Makefile.am index 2c1ba1d7..fe950eaf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,6 +66,10 @@ nobase_include_HEADERS += \ ../include/msgpack/adaptor/cpp11/forward_list_fwd.hpp \ ../include/msgpack/adaptor/cpp11/tuple.hpp \ ../include/msgpack/adaptor/cpp11/tuple_fwd.hpp \ + ../include/msgpack/adaptor/cpp11/unordered_map.hpp \ + ../include/msgpack/adaptor/cpp11/unordered_map_fwd.hpp \ + ../include/msgpack/adaptor/cpp11/unordered_set.hpp \ + ../include/msgpack/adaptor/cpp11/unordered_set_fwd.hpp \ ../include/msgpack/adaptor/define.hpp \ ../include/msgpack/adaptor/deque.hpp \ ../include/msgpack/adaptor/deque_fwd.hpp \ diff --git a/test/msgpack_cpp11.cpp b/test/msgpack_cpp11.cpp index 2d48043e..47ebe195 100644 --- a/test/msgpack_cpp11.cpp +++ b/test/msgpack_cpp11.cpp @@ -86,6 +86,71 @@ TEST(MSGPACK_STL, simple_buffer_forward_list) } } +TEST(MSGPACK_STL, simple_buffer_unordered_map) +{ + for (unsigned int k = 0; k < kLoop; k++) { + unordered_map val1; + for (unsigned int i = 0; i < kElements; i++) + val1[rand()] = rand(); + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, val1); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + unordered_map val2 = ret.get().as >(); + EXPECT_EQ(val1, val2); + } +} + +TEST(MSGPACK_STL, simple_buffer_unordered_multimap) +{ + for (unsigned int k = 0; k < kLoop; k++) { + unordered_multimap val1; + for (unsigned int i = 0; i < kElements; i++) { + int i1 = rand(); + val1.insert(make_pair(i1, rand())); + val1.insert(make_pair(i1, rand())); + } + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, val1); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + unordered_multimap val2 = ret.get().as >(); + + EXPECT_EQ(val1, val2); + } +} + +TEST(MSGPACK_STL, simple_buffer_unordered_set) +{ + for (unsigned int k = 0; k < kLoop; k++) { + unordered_set val1; + for (unsigned int i = 0; i < kElements; i++) + val1.insert(rand()); + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, val1); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + unordered_set val2 = ret.get().as >(); + EXPECT_EQ(val1, val2); + } +} + +TEST(MSGPACK_STL, simple_buffer_unordered_multiset) +{ + for (unsigned int k = 0; k < kLoop; k++) { + unordered_multiset val1; + for (unsigned int i = 0; i < kElements; i++) + val1.insert(rand()); + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, val1); + msgpack::unpacked ret; + msgpack::unpack(ret, sbuf.data(), sbuf.size()); + unordered_multiset val2 = ret.get().as >(); + EXPECT_EQ(val1, val2); + } +} + + class TestEnumClassMemberClass {