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