1 //
2 // MessagePack for C++ static resolution routine
3 //
4 // Copyright (C) 2008-2014 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_OBJECT_HPP
11 #define MSGPACK_V1_OBJECT_HPP
12 
13 #include "msgpack/object_decl.hpp"
14 #include "msgpack/adaptor/check_container_size.hpp"
15 
16 #include <cstring>
17 #include <stdexcept>
18 #include <typeinfo>
19 #include <limits>
20 #include <ostream>
21 #include <typeinfo>
22 #include <iomanip>
23 
24 namespace msgpack {
25 
26 /// @cond
MSGPACK_API_VERSION_NAMESPACE(v1)27 MSGPACK_API_VERSION_NAMESPACE(v1) {
28 /// @endcond
29 
30 struct object_kv {
31     msgpack::object key;
32     msgpack::object val;
33 };
34 
35 struct object::with_zone : msgpack::object {
36     with_zone(msgpack::zone& z) : zone(z) { }
37     msgpack::zone& zone;
38 private:
39     with_zone();
40 };
41 
42 
43 /// The class holds object and zone
44 class object_handle {
45 public:
46     /// Constructor that creates nil object and null zone.
47     object_handle() {}
48 
49     /// Constructor that creates an object_handle holding object `obj` and zone `z`.
50     /**
51      * @param obj object
52      * @param z zone
53      */
54     object_handle(
55         msgpack::object const& obj,
56 #if defined(MSGPACK_USE_CPP03)
57         msgpack::unique_ptr<msgpack::zone> z
58 #else  // defined(MSGPACK_USE_CPP03)
59         msgpack::unique_ptr<msgpack::zone>&& z
60 #endif // defined(MSGPACK_USE_CPP03)
61     ) :
62         m_obj(obj), m_zone(msgpack::move(z)) { }
63 
64     void set(msgpack::object const& obj)
65         { m_obj = obj; }
66 
67     /// Get object reference
68     /**
69      * @return object
70      */
71     const msgpack::object& get() const
72         { return m_obj; }
73 
74     /**
75      * @return object (to mimic smart pointers).
76      */
77     const msgpack::object& operator*() const
78         { return get(); }
79 
80     /**
81      * @return the address of the object (to mimic smart pointers).
82      */
83     const msgpack::object* operator->() const
84         { return &get(); }
85 
86     /// Get unique_ptr reference of zone.
87     /**
88      * @return unique_ptr reference of zone
89      */
90     msgpack::unique_ptr<msgpack::zone>& zone()
91         { return m_zone; }
92 
93     /// Get unique_ptr const reference of zone.
94     /**
95      * @return unique_ptr const reference of zone
96      */
97     const msgpack::unique_ptr<msgpack::zone>& zone() const
98         { return m_zone; }
99 
100 #if defined(MSGPACK_USE_CPP03)
101     struct object_handle_ref {
102         object_handle_ref(object_handle* oh):m_oh(oh) {}
103         object_handle* m_oh;
104     };
105 
106     object_handle(object_handle& other):
107         m_obj(other.m_obj),
108         m_zone(msgpack::move(other.m_zone)) {
109     }
110 
111     object_handle(object_handle_ref ref):
112         m_obj(ref.m_oh->m_obj),
113         m_zone(msgpack::move(ref.m_oh->m_zone)) {
114     }
115 
116     object_handle& operator=(object_handle& other) {
117         m_obj = other.m_obj;
118         m_zone = msgpack::move(other.m_zone);
119         return *this;
120     }
121 
122     object_handle& operator=(object_handle_ref ref) {
123         m_obj = ref.m_oh->m_obj;
124         m_zone = msgpack::move(ref.m_oh->m_zone);
125         return *this;
126     }
127 
128     operator object_handle_ref() {
129         return object_handle_ref(this);
130     }
131 #endif // defined(MSGPACK_USE_CPP03)
132 
133 private:
134     msgpack::object m_obj;
135     msgpack::unique_ptr<msgpack::zone> m_zone;
136 };
137 
138 namespace detail {
139 
140 template <std::size_t N>
141 inline std::size_t add_ext_type_size(std::size_t size) {
142     return size + 1;
143 }
144 
145 template <>
146 inline std::size_t add_ext_type_size<4>(std::size_t size) {
147     return size == 0xffffffff ? size : size + 1;
148 }
149 
150 } // namespace detail
151 class object_parser {
152 private:
153     enum next_ret {
154         cont,
155         finish,
156         abort
157     };
158     struct elem {
159         elem(msgpack::object const* p, std::size_t r)
160             : rest(r), is_map(false), is_key(false) {
161             as.obj_ptr = p;
162         }
163 
164         elem(msgpack::object_kv const* p, std::size_t r)
165             : rest(r), is_map(true), is_key(true) {
166             as.kv_ptr = p;
167         }
168 
169         msgpack::object const& get() const {
170             if (is_map) {
171                 if (is_key) {
172                     return as.kv_ptr->key;
173                 }
174                 else {
175                     return as.kv_ptr->val;
176                 }
177             }
178             else {
179                 return *as.obj_ptr;
180             }
181         }
182 
183         template <typename Visitor>
184         next_ret next(Visitor& v) {
185             if (rest == 0) {
186                 if (is_map) {
187                     if (!v.end_map()) return abort;
188                 }
189                 else {
190                     if (!v.end_array()) return abort;
191                 }
192                 return finish;
193             }
194             else {
195                 if (is_map) {
196                     if (is_key) {
197                         if (!v.end_map_key()) return abort;
198                         if (!v.start_map_value()) return abort;
199                         is_key = false;
200                     }
201                     else {
202                         if (!v.end_map_value()) return abort;
203                         --rest;
204                         if (rest == 0) {
205                             if (!v.end_map()) return abort;
206                             return finish;
207                         }
208                         if (!v.start_map_key()) return abort;
209                         ++as.kv_ptr;
210                         is_key = true;
211                     }
212                 }
213                 else {
214                     if (!v.end_array_item()) return abort;
215                     --rest;
216                     if (rest == 0) {
217                         if (!v.end_array()) return abort;
218                         return finish;
219                     }
220                     if (!v.start_array_item()) return abort;
221                     ++as.obj_ptr;
222                 }
223                 return cont;
224             }
225         }
226 
227         union {
228             msgpack::object const* obj_ptr;
229             msgpack::object_kv const* kv_ptr;
230         } as;
231         std::size_t rest;
232         bool is_map;
233         bool is_key;
234     };
235 public:
236     explicit object_parser(msgpack::object const& obj):m_current(&obj) {}
237     template <typename Visitor>
238     void parse(Visitor& v) {
239         while (true) {
240             bool start_collection = false;
241             switch(m_current->type) {
242             case msgpack::type::NIL:
243                 if (!v.visit_nil()) return;
244                 break;
245             case msgpack::type::BOOLEAN:
246                 if (!v.visit_boolean(m_current->via.boolean)) return;
247                 break;
248             case msgpack::type::POSITIVE_INTEGER:
249                 if (!v.visit_positive_integer(m_current->via.u64)) return;
250                 break;
251             case msgpack::type::NEGATIVE_INTEGER:
252                 if (!v.visit_negative_integer(m_current->via.i64)) return;
253                 break;
254             case msgpack::type::FLOAT32:
255                 if (!v.visit_float32(static_cast<float>(m_current->via.f64))) return;
256                 break;
257             case msgpack::type::FLOAT64:
258                 if (!v.visit_float64(m_current->via.f64)) return;
259                 break;
260             case msgpack::type::STR:
261                 if (!v.visit_str(m_current->via.str.ptr, m_current->via.str.size)) return;
262                 break;
263             case msgpack::type::BIN:
264                 if (!v.visit_bin(m_current->via.bin.ptr, m_current->via.bin.size)) return;
265                 break;
266             case msgpack::type::EXT:
267                 msgpack::detail::check_container_size<sizeof(std::size_t)>(m_current->via.ext.size);
268                 if (!v.visit_ext(m_current->via.ext.ptr, m_current->via.ext.size + 1)) return;
269                 break;
270             case msgpack::type::ARRAY:
271                 if (!v.start_array(m_current->via.array.size)) return;
272                 m_ctx.push_back(elem(m_current->via.array.ptr, m_current->via.array.size));
273                 start_collection = m_current->via.array.size != 0;
274                 if (start_collection) {
275                     if (!v.start_array_item()) return;
276                 }
277                 break;
278             case msgpack::type::MAP:
279                 if (!v.start_map(m_current->via.map.size)) return;
280                 m_ctx.push_back(elem(m_current->via.map.ptr, m_current->via.map.size));
281                 start_collection = m_current->via.map.size != 0;
282                 if (start_collection) {
283                     if (!v.start_map_key()) return;
284                 }
285                 break;
286             default:
287                 throw msgpack::type_error();
288                 break;
289             }
290             if (m_ctx.empty()) return;
291             if (!start_collection) {
292                 while (true) {
293                     next_ret r = m_ctx.back().next(v);
294                     if (r == finish) {
295                         m_ctx.pop_back();
296                         if (m_ctx.empty()) return;
297                     }
298                     else if (r == cont) {
299                         break;
300                     }
301                     else {
302                         // abort
303                         return;
304                     }
305                 }
306             }
307             m_current = &m_ctx.back().get();
308         }
309     }
310 private:
311     msgpack::object const* m_current;
312     std::vector<elem> m_ctx;
313 };
314 
315 template <typename Stream>
316 struct object_pack_visitor {
317     explicit object_pack_visitor(msgpack::packer<Stream>& pk)
318         :m_packer(pk) {}
319     bool visit_nil() {
320         m_packer.pack_nil();
321         return true;
322     }
323     bool visit_boolean(bool v) {
324         if (v) m_packer.pack_true();
325         else m_packer.pack_false();
326         return true;
327     }
328     bool visit_positive_integer(uint64_t v) {
329         m_packer.pack_uint64(v);
330         return true;
331     }
332     bool visit_negative_integer(int64_t v) {
333         m_packer.pack_int64(v);
334         return true;
335     }
336     bool visit_float32(float v) {
337         m_packer.pack_float(v);
338         return true;
339     }
340     bool visit_float64(double v) {
341         m_packer.pack_double(v);
342         return true;
343     }
344     bool visit_str(const char* v, uint32_t size) {
345         m_packer.pack_str(size);
346         m_packer.pack_str_body(v, size);
347         return true;
348     }
349     bool visit_bin(const char* v, uint32_t size) {
350         m_packer.pack_bin(size);
351         m_packer.pack_bin_body(v, size);
352         return true;
353     }
354     bool visit_ext(const char* v, uint32_t size) {
355         m_packer.pack_ext(size, *v);
356         m_packer.pack_ext_body(v, size);
357         return true;
358     }
359     bool start_array(uint32_t num_elements) {
360         m_packer.pack_array(num_elements);
361         return true;
362     }
363     bool start_array_item() {
364         return true;
365     }
366     bool end_array_item() {
367         return true;
368     }
369     bool end_array() {
370         return true;
371     }
372     bool start_map(uint32_t num_kv_pairs) {
373         m_packer.pack_map(num_kv_pairs);
374         return true;
375     }
376     bool start_map_key() {
377         return true;
378     }
379     bool end_map_key() {
380         return true;
381     }
382     bool start_map_value() {
383         return true;
384     }
385     bool end_map_value() {
386         return true;
387     }
388     bool end_map() {
389         return true;
390     }
391 private:
392     msgpack::packer<Stream>& m_packer;
393 };
394 
395 
396 struct object_stringize_visitor {
397     explicit object_stringize_visitor(std::ostream& os)
398         :m_os(os) {}
399     bool visit_nil() {
400         m_os << "null";
401         return true;
402     }
403     bool visit_boolean(bool v) {
404         if (v) m_os << "true";
405         else m_os << "false";
406         return true;
407     }
408     bool visit_positive_integer(uint64_t v) {
409         m_os << v;
410         return true;
411     }
412     bool visit_negative_integer(int64_t v) {
413         m_os << v;
414         return true;
415     }
416     bool visit_float32(float v) {
417         m_os << v;
418         return true;
419     }
420     bool visit_float64(double v) {
421         m_os << v;
422         return true;
423     }
424     bool visit_str(const char* v, uint32_t size) {
425         m_os << '"';
426         for (uint32_t i = 0; i < size; ++i) {
427             char c = v[i];
428             switch (c) {
429             case '\\':
430                 m_os << "\\\\";
431                 break;
432             case '"':
433                 m_os << "\\\"";
434                 break;
435             case '/':
436                 m_os << "\\/";
437                 break;
438             case '\b':
439                 m_os << "\\b";
440                 break;
441             case '\f':
442                 m_os << "\\f";
443                 break;
444             case '\n':
445                 m_os << "\\n";
446                 break;
447             case '\r':
448                 m_os << "\\r";
449                 break;
450             case '\t':
451                 m_os << "\\t";
452                 break;
453             default: {
454                 unsigned int code = static_cast<unsigned int>(c);
455                 if (code < 0x20 || code == 0x7f) {
456                     std::ios::fmtflags flags(m_os.flags());
457                     m_os << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (code & 0xff);
458                     m_os.flags(flags);
459                 }
460                 else {
461                     m_os << c;
462                 }
463             } break;
464             }
465         }
466         m_os << '"';
467         return true;
468     }
469     bool visit_bin(const char* v, uint32_t size) {
470         (m_os << '"').write(v, size) << '"';
471         return true;
472     }
473     bool visit_ext(const char* /*v*/, uint32_t /*size*/) {
474         m_os << "EXT";
475         return true;
476     }
477     bool start_array(uint32_t num_elements) {
478         m_current_size.push_back(num_elements);
479         m_os << "[";
480         return true;
481     }
482     bool start_array_item() {
483         return true;
484     }
485     bool end_array_item() {
486         --m_current_size.back();
487         if (m_current_size.back() != 0) {
488             m_os << ",";
489         }
490         return true;
491     }
492     bool end_array() {
493         m_current_size.pop_back();
494         m_os << "]";
495         return true;
496     }
497     bool start_map(uint32_t num_kv_pairs) {
498         m_current_size.push_back(num_kv_pairs);
499         m_os << "{";
500         return true;
501     }
502     bool start_map_key() {
503         return true;
504     }
505     bool end_map_key() {
506         m_os << ":";
507         return true;
508     }
509     bool start_map_value() {
510         return true;
511     }
512     bool end_map_value() {
513         --m_current_size.back();
514         if (m_current_size.back() != 0) {
515             m_os << ",";
516         }
517         return true;
518     }
519     bool end_map() {
520         m_current_size.pop_back();
521         m_os << "}";
522         return true;
523     }
524 private:
525     std::ostream& m_os;
526     std::vector<uint32_t> m_current_size;
527 };
528 
529 struct aligned_zone_size_visitor {
530     explicit aligned_zone_size_visitor(std::size_t s)
531         :m_size(s) {}
532     bool visit_nil() {
533         return true;
534     }
535     bool visit_boolean(bool) {
536         return true;
537     }
538     bool visit_positive_integer(uint64_t) {
539         return true;
540     }
541     bool visit_negative_integer(int64_t) {
542         return true;
543     }
544     bool visit_float32(float) {
545         return true;
546     }
547     bool visit_float64(double) {
548         return true;
549     }
550     bool visit_str(const char*, uint32_t size) {
551         m_size += msgpack::aligned_size(size, MSGPACK_ZONE_ALIGNOF(char));
552         return true;
553     }
554     bool visit_bin(const char*, uint32_t size) {
555         m_size += msgpack::aligned_size(size, MSGPACK_ZONE_ALIGNOF(char));
556         return true;
557     }
558     bool visit_ext(const char*, uint32_t size) {
559         m_size += msgpack::aligned_size(size, MSGPACK_ZONE_ALIGNOF(char));
560         return true;
561     }
562     bool start_array(uint32_t num_elements) {
563         m_size += msgpack::aligned_size(
564             sizeof(msgpack::object) * num_elements,
565             MSGPACK_ZONE_ALIGNOF(msgpack::object));
566         return true;
567     }
568     bool start_array_item() {
569         return true;
570     }
571     bool end_array_item() {
572         return true;
573     }
574     bool end_array() {
575         return true;
576     }
577     bool start_map(uint32_t num_kv_pairs) {
578         m_size += msgpack::aligned_size(
579             sizeof(msgpack::object_kv) * num_kv_pairs,
580             MSGPACK_ZONE_ALIGNOF(msgpack::object_kv));
581         return true;
582     }
583     bool start_map_key() {
584         return true;
585     }
586     bool end_map_key() {
587         return true;
588     }
589     bool start_map_value() {
590         return true;
591     }
592     bool end_map_value() {
593         return true;
594     }
595     bool end_map() {
596         return true;
597     }
598 private:
599     std::size_t m_size;
600 };
601 
602 inline std::size_t aligned_zone_size(msgpack::object const& obj) {
603     std::size_t s = 0;
604     aligned_zone_size_visitor vis(s);
605     msgpack::object_parser(obj).parse(vis);
606     return s;
607 }
608 
609 /// clone object
610 /**
611  * Clone (deep copy) object.
612  * The copied object is located on newly allocated zone.
613  * @param obj copy source object
614  *
615  * @return object_handle that holds deep copied object and zone.
616  */
617 inline object_handle clone(msgpack::object const& obj) {
618     std::size_t size = msgpack::aligned_zone_size(obj);
619     msgpack::unique_ptr<msgpack::zone> z(size == 0 ? MSGPACK_NULLPTR : new msgpack::zone(size));
620     msgpack::object newobj = z.get() ? msgpack::object(obj, *z) : obj;
621     return object_handle(newobj, msgpack::move(z));
622 }
623 
624 template <typename T>
625 inline object::implicit_type::operator T() { return obj.as<T>(); }
626 
627 namespace detail {
628 template <typename Stream, typename T>
629 struct packer_serializer {
630     static msgpack::packer<Stream>& pack(msgpack::packer<Stream>& o, const T& v) {
631         v.msgpack_pack(o);
632         return o;
633     }
634 };
635 } // namespace detail
636 
637 // Adaptor functors' member functions definitions.
638 template <typename T, typename Enabler>
639 inline
640 msgpack::object const&
641 adaptor::convert<T, Enabler>::operator()(msgpack::object const& o, T& v) const {
642     v.msgpack_unpack(o.convert());
643     return o;
644 }
645 
646 template <typename T, typename Enabler>
647 template <typename Stream>
648 inline
649 msgpack::packer<Stream>&
650 adaptor::pack<T, Enabler>::operator()(msgpack::packer<Stream>& o, T const& v) const {
651     return msgpack::detail::packer_serializer<Stream, T>::pack(o, v);
652 }
653 
654 template <typename T, typename Enabler>
655 inline
656 void
657 adaptor::object_with_zone<T, Enabler>::operator()(msgpack::object::with_zone& o, T const& v) const {
658     v.msgpack_object(static_cast<msgpack::object*>(&o), o.zone);
659 }
660 
661 // Adaptor functor specialization to object
662 namespace adaptor {
663 
664 template <>
665 struct convert<msgpack::object> {
666     msgpack::object const& operator()(msgpack::object const& o, msgpack::object& v) const {
667         v = o;
668         return o;
669     }
670 };
671 
672 template <>
673 struct pack<msgpack::object> {
674     template <typename Stream>
675     msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, msgpack::object const& v) const {
676         object_pack_visitor<Stream> vis(o);
677         msgpack::object_parser(v).parse(vis);
678         return o;
679     }
680 };
681 
682 template <>
683 struct object_with_zone<msgpack::object> {
684     void operator()(msgpack::object::with_zone& o, msgpack::object const& v) const {
685         object_with_zone_visitor vis(o);
686         msgpack::object_parser(v).parse(vis);
687     }
688 private:
689     struct object_with_zone_visitor {
690         explicit object_with_zone_visitor(msgpack::object::with_zone& owz)
691             :m_zone(owz.zone), m_ptr(&owz) {
692             m_objs.push_back(&owz);
693         }
694         bool visit_nil() {
695             m_ptr->type = msgpack::type::NIL;
696             return true;
697         }
698         bool visit_boolean(bool v) {
699             m_ptr->type = msgpack::type::BOOLEAN;
700             m_ptr->via.boolean = v;
701             return true;
702         }
703         bool visit_positive_integer(uint64_t v) {
704             m_ptr->type = msgpack::type::POSITIVE_INTEGER;
705             m_ptr->via.u64 = v;
706             return true;
707         }
708         bool visit_negative_integer(int64_t v) {
709             m_ptr->type = msgpack::type::NEGATIVE_INTEGER;
710             m_ptr->via.i64 = v;
711             return true;
712         }
713         bool visit_float32(float v) {
714             m_ptr->type = msgpack::type::FLOAT32;
715             m_ptr->via.f64 = v;
716             return true;
717         }
718         bool visit_float64(double v) {
719             m_ptr->type = msgpack::type::FLOAT64;
720             m_ptr->via.f64 = v;
721             return true;
722         }
723         bool visit_str(const char* v, uint32_t size) {
724             m_ptr->type = msgpack::type::STR;
725             m_ptr->via.str.size = size;
726             char* ptr = static_cast<char*>(m_zone.allocate_align(size, MSGPACK_ZONE_ALIGNOF(char)));
727             m_ptr->via.str.ptr = ptr;
728             std::memcpy(ptr, v, size);
729             return true;
730         }
731         bool visit_bin(const char* v, uint32_t size) {
732             m_ptr->type = msgpack::type::BIN;
733             m_ptr->via.bin.size = size;
734             char* ptr = static_cast<char*>(m_zone.allocate_align(size, MSGPACK_ZONE_ALIGNOF(char)));
735             m_ptr->via.bin.ptr = ptr;
736             std::memcpy(ptr, v, size);
737             return true;
738         }
739         bool visit_ext(const char* v, uint32_t size) {
740             m_ptr->type = msgpack::type::EXT;
741 
742             // v contains type but length(size) doesn't count the type byte.
743             // See https://github.com/msgpack/msgpack/blob/master/spec.md#ext-format-family
744             m_ptr->via.ext.size = size - 1;
745 
746             char* ptr = static_cast<char*>(m_zone.allocate_align(size, MSGPACK_ZONE_ALIGNOF(char)));
747             m_ptr->via.ext.ptr = ptr;
748             std::memcpy(ptr, v, size);
749             return true;
750         }
751         bool start_array(uint32_t num_elements) {
752             m_ptr->type = msgpack::type::ARRAY;
753             m_ptr->via.array.ptr = static_cast<msgpack::object*>(
754                 m_zone.allocate_align(
755                     sizeof(msgpack::object) * num_elements, MSGPACK_ZONE_ALIGNOF(msgpack::object)));
756             m_ptr->via.array.size = num_elements;
757             m_objs.push_back(elem(m_ptr->via.array.ptr));
758             return true;
759         }
760         bool start_array_item() {
761             m_ptr = m_objs.back().get_item();
762             return true;
763         }
764         bool end_array_item() {
765             ++m_objs.back().as.obj;
766             return true;
767         }
768         bool end_array() {
769             m_objs.pop_back();
770             return true;
771         }
772         bool start_map(uint32_t num_kv_pairs) {
773             m_ptr->type = msgpack::type::MAP;
774             m_ptr->via.map.ptr = (msgpack::object_kv*)m_zone.allocate_align(
775                 sizeof(msgpack::object_kv) * num_kv_pairs, MSGPACK_ZONE_ALIGNOF(msgpack::object_kv));
776             m_ptr->via.map.size = num_kv_pairs;
777             m_objs.push_back(elem(m_ptr->via.map.ptr));
778             return true;
779         }
780         bool start_map_key() {
781             m_ptr = m_objs.back().get_key();
782             return true;
783         }
784         bool end_map_key() {
785             return true;
786         }
787         bool start_map_value() {
788             m_ptr = m_objs.back().get_val();
789             return true;
790         }
791         bool end_map_value() {
792             ++m_objs.back().as.kv;
793             return true;
794         }
795         bool end_map() {
796             m_objs.pop_back();
797             return true;
798         }
799     private:
800         struct elem {
801             elem(msgpack::object* obj)
802                 :is_obj(true) {
803                 as.obj = obj;
804             }
805             elem(msgpack::object_kv* kv)
806                 :is_obj(false) {
807                 as.kv = kv;
808             }
809             msgpack::object* get_item() {
810                 return as.obj;
811             }
812             msgpack::object* get_key() {
813                 return &as.kv->key;
814             }
815             msgpack::object* get_val() {
816                 return &as.kv->val;
817             }
818             union {
819                 msgpack::object* obj;
820                 msgpack::object_kv* kv;
821             } as;
822             bool is_obj;
823         };
824         std::vector<elem> m_objs;
825         msgpack::zone& m_zone;
826         msgpack::object* m_ptr;
827     };
828 };
829 
830 // Adaptor functor specialization to object::with_zone
831 
832 template <>
833 struct object_with_zone<msgpack::object::with_zone> {
834     void operator()(
835         msgpack::object::with_zone& o,
836         msgpack::object::with_zone const& v) const {
837         o << static_cast<msgpack::object const&>(v);
838     }
839 };
840 
841 
842 } // namespace adaptor
843 
844 
845 // obsolete
846 template <typename Type>
847 class define : public Type {
848 public:
849     typedef Type msgpack_type;
850     typedef define<Type> define_type;
851     define() {}
852     define(const msgpack_type& v) : msgpack_type(v) {}
853 
854     template <typename Packer>
855     void msgpack_pack(Packer& o) const
856     {
857         msgpack::operator<<(o, static_cast<const msgpack_type&>(*this));
858     }
859 
860     void msgpack_unpack(object const& o)
861     {
862         msgpack::operator>>(o, static_cast<msgpack_type&>(*this));
863     }
864 };
865 
866 // deconvert operator
867 
868 template <typename Stream>
869 template <typename T>
870 inline msgpack::packer<Stream>& packer<Stream>::pack(const T& v)
871 {
872     msgpack::operator<<(*this, v);
873     return *this;
874 }
875 
876 struct object_equal_visitor {
877     object_equal_visitor(msgpack::object const& obj, bool& result)
878         :m_ptr(&obj), m_result(result) {}
879     bool visit_nil() {
880         if (m_ptr->type != msgpack::type::NIL) {
881             m_result = false;
882             return false;
883         }
884         return true;
885     }
886     bool visit_boolean(bool v) {
887         if (m_ptr->type != msgpack::type::BOOLEAN || m_ptr->via.boolean != v) {
888             m_result = false;
889             return false;
890         }
891         return true;
892     }
893     bool visit_positive_integer(uint64_t v) {
894         if (m_ptr->type != msgpack::type::POSITIVE_INTEGER || m_ptr->via.u64 != v) {
895             m_result = false;
896             return false;
897         }
898         return true;
899     }
900     bool visit_negative_integer(int64_t v) {
901         if (m_ptr->type != msgpack::type::NEGATIVE_INTEGER || m_ptr->via.i64 != v) {
902             m_result = false;
903             return false;
904         }
905         return true;
906     }
907     bool visit_float32(float v) {
908         if (m_ptr->type != msgpack::type::FLOAT32 || m_ptr->via.f64 != v) {
909             m_result = false;
910             return false;
911         }
912         return true;
913     }
914     bool visit_float64(double v) {
915         if (m_ptr->type != msgpack::type::FLOAT64 || m_ptr->via.f64 != v) {
916             m_result = false;
917             return false;
918         }
919         return true;
920     }
921     bool visit_str(const char* v, uint32_t size) {
922         if (m_ptr->type != msgpack::type::STR ||
923             m_ptr->via.str.size != size ||
924             std::memcmp(m_ptr->via.str.ptr, v, size) != 0) {
925             m_result = false;
926             return false;
927         }
928         return true;
929     }
930     bool visit_bin(const char* v, uint32_t size) {
931         if (m_ptr->type != msgpack::type::BIN ||
932             m_ptr->via.bin.size != size ||
933             std::memcmp(m_ptr->via.bin.ptr, v, size) != 0) {
934             m_result = false;
935             return false;
936         }
937         return true;
938     }
939     bool visit_ext(const char* v, uint32_t size) {
940         if (m_ptr->type != msgpack::type::EXT ||
941             m_ptr->via.ext.size != size ||
942             std::memcmp(m_ptr->via.ext.ptr, v, size) != 0) {
943             m_result = false;
944             return false;
945         }
946         return true;
947     }
948     bool start_array(uint32_t num_elements) {
949         if (m_ptr->type != msgpack::type::ARRAY ||
950             m_ptr->via.array.size != num_elements) {
951             m_result = false;
952             return false;
953         }
954         m_objs.push_back(elem(m_ptr->via.array.ptr));
955         return true;
956     }
957     bool start_array_item() {
958         m_ptr = m_objs.back().get_item();
959         return true;
960     }
961     bool end_array_item() {
962         ++m_objs.back().as.obj;
963         return true;
964     }
965     bool end_array() {
966         m_objs.pop_back();
967         return true;
968     }
969     bool start_map(uint32_t num_kv_pairs) {
970         if (m_ptr->type != msgpack::type::MAP ||
971             m_ptr->via.array.size != num_kv_pairs) {
972             m_result = false;
973             return false;
974         }
975         m_objs.push_back(elem(m_ptr->via.map.ptr));
976         return true;
977     }
978     bool start_map_key() {
979         m_ptr = m_objs.back().get_key();
980         return true;
981     }
982     bool end_map_key() {
983         return true;
984     }
985     bool start_map_value() {
986         m_ptr = m_objs.back().get_val();
987         return true;
988     }
989     bool end_map_value() {
990         ++m_objs.back().as.kv;
991         return true;
992     }
993     bool end_map() {
994         m_objs.pop_back();
995         return true;
996     }
997 private:
998     struct elem {
999         elem(msgpack::object const* obj)
1000             :is_obj(true) {
1001             as.obj = obj;
1002         }
1003         elem(msgpack::object_kv const* kv)
1004             :is_obj(false) {
1005             as.kv = kv;
1006         }
1007         msgpack::object const* get_item() {
1008             return as.obj;
1009         }
1010         msgpack::object const* get_key() {
1011             return &as.kv->key;
1012         }
1013         msgpack::object const* get_val() {
1014             return &as.kv->val;
1015         }
1016         union {
1017             msgpack::object const* obj;
1018             msgpack::object_kv const* kv;
1019         } as;
1020         bool is_obj;
1021     };
1022     std::vector<elem> m_objs;
1023     msgpack::object const* m_ptr;
1024     bool& m_result;
1025 };
1026 
1027 inline bool operator==(const msgpack::object& x, const msgpack::object& y)
1028 {
1029     if(x.type != y.type) { return false; }
1030     bool b = true;
1031     object_equal_visitor vis(y, b);
1032     msgpack::object_parser(x).parse(vis);
1033     return b;
1034 }
1035 
1036 template <typename T>
1037 inline bool operator==(const msgpack::object& x, const T& y)
1038 try {
1039     return x == msgpack::object(y);
1040 } catch (msgpack::type_error&) {
1041     return false;
1042 }
1043 
1044 inline bool operator!=(const msgpack::object& x, const msgpack::object& y)
1045 { return !(x == y); }
1046 
1047 template <typename T>
1048 inline bool operator==(const T& y, const msgpack::object& x)
1049 { return x == y; }
1050 
1051 template <typename T>
1052 inline bool operator!=(const msgpack::object& x, const T& y)
1053 { return !(x == y); }
1054 
1055 template <typename T>
1056 inline bool operator!=(const T& y, const msgpack::object& x)
1057 { return x != y; }
1058 
1059 
1060 inline object::implicit_type object::convert() const
1061 {
1062     return object::implicit_type(*this);
1063 }
1064 
1065 template <typename T>
1066 inline
1067 typename msgpack::enable_if<
1068     !msgpack::is_array<T>::value && !msgpack::is_pointer<T>::value,
1069     T&
1070 >::type
1071 object::convert(T& v) const
1072 {
1073     msgpack::operator>>(*this, v);
1074     return v;
1075 }
1076 
1077 template <typename T, std::size_t N>
1078 inline T(&object::convert(T(&v)[N]) const)[N]
1079 {
1080     msgpack::operator>>(*this, v);
1081     return v;
1082 }
1083 
1084 #if !defined(MSGPACK_DISABLE_LEGACY_CONVERT)
1085 template <typename T>
1086 inline
1087 typename msgpack::enable_if<
1088     msgpack::is_pointer<T>::value,
1089     T
1090 >::type
1091 object::convert(T v) const
1092 {
1093     convert(*v);
1094     return v;
1095 }
1096 #endif // !defined(MSGPACK_DISABLE_LEGACY_CONVERT)
1097 
1098 template <typename T>
1099 inline bool object::convert_if_not_nil(T& v) const
1100 {
1101     if (is_nil()) {
1102         return false;
1103     }
1104     convert(v);
1105     return true;
1106 }
1107 
1108 #if defined(MSGPACK_USE_CPP03)
1109 
1110 template <typename T>
1111 inline T object::as() const
1112 {
1113     T v;
1114     convert(v);
1115     return v;
1116 }
1117 
1118 #else  // defined(MSGPACK_USE_CPP03)
1119 
1120 template <typename T>
1121 inline typename std::enable_if<msgpack::has_as<T>::value, T>::type object::as() const {
1122     return msgpack::adaptor::as<T>()(*this);
1123 }
1124 
1125 template <typename T>
1126 inline typename std::enable_if<!msgpack::has_as<T>::value, T>::type object::as() const {
1127     T v;
1128     convert(v);
1129     return v;
1130 }
1131 
1132 #endif // defined(MSGPACK_USE_CPP03)
1133 
1134 inline object::object()
1135 {
1136     type = msgpack::type::NIL;
1137 }
1138 
1139 template <typename T>
1140 inline object::object(const T& v)
1141 {
1142     *this << v;
1143 }
1144 
1145 template <typename T>
1146 inline object& object::operator=(const T& v)
1147 {
1148     *this = object(v);
1149     return *this;
1150 }
1151 
1152 template <typename T>
1153 inline object::object(const T& v, msgpack::zone& z)
1154 {
1155     with_zone oz(z);
1156     msgpack::operator<<(oz, v);
1157     type = oz.type;
1158     via = oz.via;
1159 }
1160 
1161 template <typename T>
1162 inline object::object(const T& v, msgpack::zone* z)
1163 {
1164     with_zone oz(*z);
1165     msgpack::operator<<(oz, v);
1166     type = oz.type;
1167     via = oz.via;
1168 }
1169 
1170 
1171 inline object::object(const msgpack_object& o)
1172 {
1173     // FIXME beter way?
1174     std::memcpy(this, &o, sizeof(o));
1175 }
1176 
1177 inline void operator<< (msgpack::object& o, const msgpack_object& v)
1178 {
1179     // FIXME beter way?
1180     std::memcpy(static_cast<void*>(&o), &v, sizeof(v));
1181 }
1182 
1183 inline object::operator msgpack_object() const
1184 {
1185     // FIXME beter way?
1186     msgpack_object obj;
1187     std::memcpy(&obj, this, sizeof(obj));
1188     return obj;
1189 }
1190 
1191 
1192 // obsolete
1193 template <typename T>
1194 inline void convert(T& v, msgpack::object const& o)
1195 {
1196     o.convert(v);
1197 }
1198 
1199 // obsolete
1200 template <typename Stream, typename T>
1201 inline void pack(msgpack::packer<Stream>& o, const T& v)
1202 {
1203     o.pack(v);
1204 }
1205 
1206 // obsolete
1207 template <typename Stream, typename T>
1208 inline void pack_copy(msgpack::packer<Stream>& o, T v)
1209 {
1210     pack(o, v);
1211 }
1212 
1213 template <typename Stream>
1214 inline msgpack::packer<Stream>& operator<< (msgpack::packer<Stream>& o, const msgpack::object& v)
1215 {
1216     object_pack_visitor<Stream> vis(o);
1217     msgpack::object_parser(v).parse(vis);
1218     return o;
1219 }
1220 
1221 template <typename Stream>
1222 inline msgpack::packer<Stream>& operator<< (msgpack::packer<Stream>& o, const msgpack::object::with_zone& v)
1223 {
1224     return o << static_cast<msgpack::object>(v);
1225 }
1226 
1227 inline std::ostream& operator<< (std::ostream& s, const msgpack::object& v)
1228 {
1229     object_stringize_visitor vis(s);
1230     msgpack::object_parser(v).parse(vis);
1231     return s;
1232 }
1233 
1234 /// @cond
1235 }  // MSGPACK_API_VERSION_NAMESPACE(v1)
1236 /// @endcond
1237 
1238 }  // namespace msgpack
1239 
1240 #endif // MSGPACK_V1_OBJECT_HPP
1241