1 //
2 // MessagePack for C++ static resolution routine
3 //
4 // Copyright (C) 2008-2016 FURUHASHI Sadayuki and KONDO Takatoshi
5 //
6 //    Distributed under the Boost Software License, Version 1.0.
7 //    (See accompanying file LICENSE_1_0.txt or copy at
8 //    http://www.boost.org/LICENSE_1_0.txt)
9 //
10 #ifndef MSGPACK_V1_TYPE_MAP_HPP
11 #define MSGPACK_V1_TYPE_MAP_HPP
12 
13 #include "msgpack/v1/adaptor/map_decl.hpp"
14 #include "msgpack/adaptor/adaptor_base.hpp"
15 
16 #include <map>
17 #include <vector>
18 
19 namespace msgpack {
20 
21 /// @cond
MSGPACK_API_VERSION_NAMESPACE(v1)22 MSGPACK_API_VERSION_NAMESPACE(v1) {
23 /// @endcond
24 
25 namespace type {
26 
27 template <typename K, typename V, typename Compare, typename Alloc>
28 class assoc_vector : public std::vector< std::pair<K, V>, Alloc > {
29 #if !defined(MSGPACK_USE_CPP03)
30     using std::vector<std::pair<K, V>, Alloc>::vector;
31 #endif // !defined(MSGPACK_USE_CPP03)
32 };
33 
34 namespace detail {
35     template <typename K, typename V, typename Compare, typename Alloc>
36     struct pair_first_less {
37         bool operator() (const std::pair<K, V>& x, const std::pair<K, V>& y) const
38             { return Compare()(x.first, y.first); }
39     };
40 }
41 
42 }  //namespace type
43 
44 namespace adaptor {
45 
46 #if !defined(MSGPACK_USE_CPP03)
47 
48 template <typename K, typename V, typename Compare, typename Alloc>
49 struct as<
50     type::assoc_vector<K, V, Compare, Alloc>,
51     typename std::enable_if<msgpack::has_as<K>::value || msgpack::has_as<V>::value>::type> {
52     type::assoc_vector<K, V, Compare, Alloc> operator()(msgpack::object const& o) const {
53         if (o.type != msgpack::type::MAP) { throw msgpack::type_error(); }
54         type::assoc_vector<K, V, Compare, Alloc> v;
55         v.reserve(o.via.map.size);
56         msgpack::object_kv* p = o.via.map.ptr;
57         msgpack::object_kv* const pend = o.via.map.ptr + o.via.map.size;
58         for (; p < pend; ++p) {
59             v.emplace_back(p->key.as<K>(), p->val.as<V>());
60         }
61         std::sort(v.begin(), v.end(), type::detail::pair_first_less<K, V, Compare, Alloc>());
62         return v;
63     }
64 };
65 
66 #endif // !defined(MSGPACK_USE_CPP03)
67 
68 template <typename K, typename V, typename Compare, typename Alloc>
69 struct convert<type::assoc_vector<K, V, Compare, Alloc> > {
70     msgpack::object const& operator()(msgpack::object const& o, type::assoc_vector<K, V, Compare, Alloc>& v) const {
71         if (o.type != msgpack::type::MAP) { throw msgpack::type_error(); }
72         v.resize(o.via.map.size);
73         if (o.via.map.size != 0) {
74             msgpack::object_kv* p = o.via.map.ptr;
75             msgpack::object_kv* const pend = o.via.map.ptr + o.via.map.size;
76             std::pair<K, V>* it(&v.front());
77             for (; p < pend; ++p, ++it) {
78                 p->key.convert(it->first);
79                 p->val.convert(it->second);
80             }
81             std::sort(v.begin(), v.end(), type::detail::pair_first_less<K, V, Compare, Alloc>());
82         }
83         return o;
84     }
85 };
86 
87 template <typename K, typename V, typename Compare, typename Alloc>
88 struct pack<type::assoc_vector<K, V, Compare, Alloc> > {
89     template <typename Stream>
90     msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const type::assoc_vector<K, V, Compare, Alloc>& v) const {
91         uint32_t size = checked_get_container_size(v.size());
92         o.pack_map(size);
93         for (typename type::assoc_vector<K, V, Compare, Alloc>::const_iterator it(v.begin()), it_end(v.end());
94             it != it_end; ++it) {
95             o.pack(it->first);
96             o.pack(it->second);
97         }
98         return o;
99     }
100 };
101 
102 template <typename K, typename V, typename Compare, typename Alloc>
103 struct object_with_zone<type::assoc_vector<K, V, Compare, Alloc> > {
104     void operator()(msgpack::object::with_zone& o, const type::assoc_vector<K, V, Compare, Alloc>& v) const {
105         o.type = msgpack::type::MAP;
106         if (v.empty()) {
107             o.via.map.ptr  = MSGPACK_NULLPTR;
108             o.via.map.size = 0;
109         }
110         else {
111             uint32_t size = checked_get_container_size(v.size());
112             msgpack::object_kv* p = static_cast<msgpack::object_kv*>(o.zone.allocate_align(sizeof(msgpack::object_kv)*size, MSGPACK_ZONE_ALIGNOF(msgpack::object_kv)));
113             msgpack::object_kv* const pend = p + size;
114             o.via.map.ptr  = p;
115             o.via.map.size = size;
116             typename type::assoc_vector<K, V, Compare, Alloc>::const_iterator it(v.begin());
117             do {
118                 p->key = msgpack::object(it->first, o.zone);
119                 p->val = msgpack::object(it->second, o.zone);
120                 ++p;
121                 ++it;
122             } while(p < pend);
123         }
124     }
125 };
126 
127 #if !defined(MSGPACK_USE_CPP03)
128 
129 template <typename K, typename V, typename Compare, typename Alloc>
130 struct as<
131     std::map<K, V, Compare, Alloc>,
132     typename std::enable_if<msgpack::has_as<K>::value || msgpack::has_as<V>::value>::type> {
133     std::map<K, V, Compare, Alloc> operator()(msgpack::object const& o) const {
134         if (o.type != msgpack::type::MAP) { throw msgpack::type_error(); }
135         msgpack::object_kv* p(o.via.map.ptr);
136         msgpack::object_kv* const pend(o.via.map.ptr + o.via.map.size);
137         std::map<K, V, Compare, Alloc> v;
138         for (; p != pend; ++p) {
139             v.emplace(p->key.as<K>(), p->val.as<V>());
140         }
141         return v;
142     }
143 };
144 
145 #endif // !defined(MSGPACK_USE_CPP03)
146 
147 template <typename K, typename V, typename Compare, typename Alloc>
148 struct convert<std::map<K, V, Compare, Alloc> > {
149     msgpack::object const& operator()(msgpack::object const& o, std::map<K, V, Compare, Alloc>& v) const {
150         if (o.type != msgpack::type::MAP) { throw msgpack::type_error(); }
151         msgpack::object_kv* p(o.via.map.ptr);
152         msgpack::object_kv* const pend(o.via.map.ptr + o.via.map.size);
153         std::map<K, V, Compare, Alloc> tmp;
154         for (; p != pend; ++p) {
155             K key;
156             p->key.convert(key);
157 #if __cplusplus >= 201103L
158             p->val.convert(tmp[std::move(key)]);
159 #else
160             p->val.convert(tmp[key]);
161 #endif
162         }
163 #if __cplusplus >= 201103L
164         v = std::move(tmp);
165 #else
166         tmp.swap(v);
167 #endif
168         return o;
169     }
170 };
171 
172 template <typename K, typename V, typename Compare, typename Alloc>
173 struct pack<std::map<K, V, Compare, Alloc> > {
174     template <typename Stream>
175     msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const std::map<K, V, Compare, Alloc>& v) const {
176         uint32_t size = checked_get_container_size(v.size());
177         o.pack_map(size);
178         for (typename std::map<K, V, Compare, Alloc>::const_iterator it(v.begin()), it_end(v.end());
179             it != it_end; ++it) {
180             o.pack(it->first);
181             o.pack(it->second);
182         }
183         return o;
184     }
185 };
186 
187 template <typename K, typename V, typename Compare, typename Alloc>
188 struct object_with_zone<std::map<K, V, Compare, Alloc> > {
189     void operator()(msgpack::object::with_zone& o, const std::map<K, V, Compare, Alloc>& v) const {
190         o.type = msgpack::type::MAP;
191         if (v.empty()) {
192             o.via.map.ptr  = MSGPACK_NULLPTR;
193             o.via.map.size = 0;
194         }
195         else {
196             uint32_t size = checked_get_container_size(v.size());
197 
198             msgpack::object_kv* p = static_cast<msgpack::object_kv*>(o.zone.allocate_align(sizeof(msgpack::object_kv)*size, MSGPACK_ZONE_ALIGNOF(msgpack::object_kv)));
199             msgpack::object_kv* const pend = p + size;
200             o.via.map.ptr  = p;
201             o.via.map.size = size;
202             typename std::map<K, V, Compare, Alloc>::const_iterator it(v.begin());
203             do {
204 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__)
205 #pragma GCC diagnostic push
206 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
207 #endif // defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__)
208                 p->key = msgpack::object(it->first, o.zone);
209                 p->val = msgpack::object(it->second, o.zone);
210 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__)
211 #pragma GCC diagnostic pop
212 #endif // defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__)
213                 ++p;
214                 ++it;
215             } while(p < pend);
216         }
217     }
218 };
219 
220 #if !defined(MSGPACK_USE_CPP03)
221 
222 template <typename K, typename V, typename Compare, typename Alloc>
223 struct as<
224     std::multimap<K, V, Compare, Alloc>,
225     typename std::enable_if<msgpack::has_as<K>::value || msgpack::has_as<V>::value>::type> {
226     std::multimap<K, V, Compare, Alloc> operator()(msgpack::object const& o) const {
227         if (o.type != msgpack::type::MAP) { throw msgpack::type_error(); }
228         msgpack::object_kv* p(o.via.map.ptr);
229         msgpack::object_kv* const pend(o.via.map.ptr + o.via.map.size);
230         std::multimap<K, V, Compare, Alloc> v;
231         for (; p != pend; ++p) {
232             v.emplace(p->key.as<K>(), p->val.as<V>());
233         }
234         return v;
235     }
236 };
237 
238 #endif // !defined(MSGPACK_USE_CPP03)
239 
240 template <typename K, typename V, typename Compare, typename Alloc>
241 struct convert<std::multimap<K, V, Compare, Alloc> > {
242     msgpack::object const& operator()(msgpack::object const& o, std::multimap<K, V, Compare, Alloc>& v) const {
243         if (o.type != msgpack::type::MAP) { throw msgpack::type_error(); }
244         msgpack::object_kv* p(o.via.map.ptr);
245         msgpack::object_kv* const pend(o.via.map.ptr + o.via.map.size);
246         std::multimap<K, V, Compare, Alloc> tmp;
247         for (; p != pend; ++p) {
248             std::pair<K, V> value;
249             p->key.convert(value.first);
250             p->val.convert(value.second);
251 #if __cplusplus >= 201103L
252             tmp.insert(std::move(value));
253 #else
254             tmp.insert(value);
255 #endif
256         }
257 #if __cplusplus >= 201103L
258         v = std::move(tmp);
259 #else
260         tmp.swap(v);
261 #endif
262         return o;
263     }
264 };
265 
266 template <typename K, typename V, typename Compare, typename Alloc>
267 struct pack<std::multimap<K, V, Compare, Alloc> > {
268     template <typename Stream>
269     msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const std::multimap<K, V, Compare, Alloc>& v) const {
270         uint32_t size = checked_get_container_size(v.size());
271         o.pack_map(size);
272         for (typename std::multimap<K, V, Compare, Alloc>::const_iterator it(v.begin()), it_end(v.end());
273             it != it_end; ++it) {
274             o.pack(it->first);
275             o.pack(it->second);
276         }
277         return o;
278     }
279 };
280 
281 template <typename K, typename V, typename Compare, typename Alloc>
282 struct object_with_zone<std::multimap<K, V, Compare, Alloc> > {
283     void operator()(msgpack::object::with_zone& o, const std::multimap<K, V, Compare, Alloc>& v) const {
284         o.type = msgpack::type::MAP;
285         if (v.empty()) {
286             o.via.map.ptr  = MSGPACK_NULLPTR;
287             o.via.map.size = 0;
288         }
289         else {
290             uint32_t size = checked_get_container_size(v.size());
291             msgpack::object_kv* p = static_cast<msgpack::object_kv*>(o.zone.allocate_align(sizeof(msgpack::object_kv)*size, MSGPACK_ZONE_ALIGNOF(msgpack::object_kv)));
292             msgpack::object_kv* const pend = p + size;
293             o.via.map.ptr  = p;
294             o.via.map.size = size;
295             typename std::multimap<K, V, Compare, Alloc>::const_iterator it(v.begin());
296             do {
297                 p->key = msgpack::object(it->first, o.zone);
298                 p->val = msgpack::object(it->second, o.zone);
299                 ++p;
300                 ++it;
301             } while(p < pend);
302         }
303     }
304 };
305 
306 } // namespace adaptor
307 
308 /// @cond
309 }  // MSGPACK_API_VERSION_NAMESPACE(v1)
310 /// @endcond
311 
312 }  // namespace msgpack
313 
314 #endif // MSGPACK_V1_TYPE_MAP_HPP
315