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_OBJECT_HPP
11#define MSGPACK_OBJECT_HPP
12
13#include "msgpack/versioning.hpp"
14#include "msgpack/pack.hpp"
15#include "msgpack/zone.hpp"
16#include "msgpack/adaptor/adaptor_base.hpp"
17
18#include <cstring>
19#include <stdexcept>
20#include <typeinfo>
21#include <limits>
22#include <ostream>
23#include <typeinfo>
24#include <iomanip>
25
26namespace msgpack {
27
28/// @cond
29MSGPACK_API_VERSION_NAMESPACE(v1) {
30/// @endcond
31
32/// The class holds object and zone
33class object_handle {
34public:
35    /// Constructor that creates nil object and null zone.
36    object_handle() {}
37
38    /// Constructor that creates an object_handle holding object `obj` and zone `z`.
39    /**
40     * @param obj object
41     * @param z zone
42     */
43    object_handle(msgpack::object const& obj, msgpack::unique_ptr<msgpack::zone> z) :
44        m_obj(obj), m_zone(msgpack::move(z)) { }
45
46    // obsolete
47    void set(msgpack::object const& obj)
48        { m_obj = obj; }
49
50    /// Get object reference
51    /**
52     * @return object
53     */
54    const msgpack::object& get() const
55        { return m_obj; }
56
57    /// Get unique_ptr reference of zone.
58    /**
59     * @return unique_ptr reference of zone
60     */
61    msgpack::unique_ptr<msgpack::zone>& zone()
62        { return m_zone; }
63
64    /// Get unique_ptr const reference of zone.
65    /**
66     * @return unique_ptr const reference of zone
67     */
68    const msgpack::unique_ptr<msgpack::zone>& zone() const
69        { return m_zone; }
70
71#if defined(MSGPACK_USE_CPP03)
72    struct object_handle_ref {
73        object_handle_ref(object_handle* oh):m_oh(oh) {}
74        object_handle* m_oh;
75    };
76
77    object_handle(object_handle& other):
78        m_obj(other.m_obj),
79        m_zone(msgpack::move(other.m_zone)) {
80    }
81
82    object_handle(object_handle_ref ref):
83        m_obj(ref.m_oh->m_obj),
84        m_zone(msgpack::move(ref.m_oh->m_zone)) {
85    }
86
87    object_handle& operator=(object_handle& other) {
88        m_obj = other.m_obj;
89        m_zone = msgpack::move(other.m_zone);
90        return *this;
91    }
92
93    object_handle& operator=(object_handle_ref ref) {
94        m_obj = ref.m_oh->m_obj;
95        m_zone = msgpack::move(ref.m_oh->m_zone);
96        return *this;
97    }
98
99    operator object_handle_ref() {
100        return object_handle_ref(this);
101    }
102#endif // defined(MSGPACK_USE_CPP03)
103
104private:
105    msgpack::object m_obj;
106    msgpack::unique_ptr<msgpack::zone> m_zone;
107};
108
109namespace detail {
110
111template <std::size_t N>
112inline std::size_t add_ext_type_size(std::size_t size) {
113    return size + 1;
114}
115
116template <>
117inline std::size_t add_ext_type_size<4>(std::size_t size) {
118    return size == 0xffffffff ? size : size + 1;
119}
120
121} // namespace detail
122
123inline std::size_t aligned_zone_size(msgpack::object const& obj) {
124    std::size_t s = 0;
125    switch (obj.type) {
126    case msgpack::type::ARRAY:
127        s += sizeof(msgpack::object) * obj.via.array.size;
128        for (uint32_t i = 0; i < obj.via.array.size; ++i) {
129            s += msgpack::aligned_zone_size(obj.via.array.ptr[i]);
130        }
131        break;
132    case msgpack::type::MAP:
133        s += sizeof(msgpack::object_kv) * obj.via.map.size;
134        for (uint32_t i = 0; i < obj.via.map.size; ++i) {
135            s += msgpack::aligned_zone_size(obj.via.map.ptr[i].key);
136            s += msgpack::aligned_zone_size(obj.via.map.ptr[i].val);
137        }
138        break;
139    case msgpack::type::EXT:
140        s += msgpack::aligned_size(
141            detail::add_ext_type_size<sizeof(std::size_t)>(obj.via.ext.size));
142        break;
143    case msgpack::type::STR:
144        s += msgpack::aligned_size(obj.via.str.size);
145        break;
146    case msgpack::type::BIN:
147        s += msgpack::aligned_size(obj.via.bin.size);
148        break;
149    default:
150        break;
151    }
152    return s;
153}
154
155/// clone object
156/**
157 * Clone (deep copy) object.
158 * The copied object is located on newly allocated zone.
159 * @param obj copy source object
160 *
161 * @return object_handle that holds deep copied object and zone.
162 */
163inline object_handle clone(msgpack::object const& obj) {
164    std::size_t size = msgpack::aligned_zone_size(obj);
165    msgpack::unique_ptr<msgpack::zone> z(size == 0 ? nullptr : new msgpack::zone(size));
166    msgpack::object newobj = z.get() ? msgpack::object(obj, *z) : obj;
167    return object_handle(newobj, msgpack::move(z));
168}
169
170struct object::implicit_type {
171    implicit_type(object const& o) : obj(o) { }
172    ~implicit_type() { }
173
174    template <typename T>
175    operator T() { return obj.as<T>(); }
176
177private:
178    msgpack::object const& obj;
179};
180
181namespace detail {
182template <typename Stream, typename T>
183struct packer_serializer {
184    static msgpack::packer<Stream>& pack(msgpack::packer<Stream>& o, const T& v) {
185        v.msgpack_pack(o);
186        return o;
187    }
188};
189} // namespace detail
190
191// Adaptor functors' member functions definitions.
192template <typename T, typename Enabler>
193inline
194msgpack::object const&
195msgpack::adaptor::convert<T, Enabler>::operator()(msgpack::object const& o, T& v) const {
196    v.msgpack_unpack(o.convert());
197    return o;
198}
199
200template <typename T, typename Enabler>
201template <typename Stream>
202inline
203msgpack::packer<Stream>&
204msgpack::adaptor::pack<T, Enabler>::operator()(msgpack::packer<Stream>& o, T const& v) const {
205    return msgpack::detail::packer_serializer<Stream, T>::pack(o, v);
206}
207
208template <typename T, typename Enabler>
209inline
210void
211msgpack::adaptor::object_with_zone<T, Enabler>::operator()(msgpack::object::with_zone& o, T const& v) const {
212    v.msgpack_object(static_cast<msgpack::object*>(&o), o.zone);
213}
214
215// Adaptor functor specialization to object
216namespace adaptor {
217
218template <>
219struct convert<msgpack::object> {
220    msgpack::object const& operator()(msgpack::object const& o, msgpack::object& v) const {
221        v = o;
222        return o;
223    }
224};
225
226template <>
227struct pack<msgpack::object> {
228    template <typename Stream>
229    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, msgpack::object const& v) const {
230        switch(v.type) {
231        case msgpack::type::NIL:
232            o.pack_nil();
233            return o;
234
235        case msgpack::type::BOOLEAN:
236            if(v.via.boolean) {
237                o.pack_true();
238            } else {
239                o.pack_false();
240            }
241            return o;
242
243        case msgpack::type::POSITIVE_INTEGER:
244            o.pack_uint64(v.via.u64);
245            return o;
246
247        case msgpack::type::NEGATIVE_INTEGER:
248            o.pack_int64(v.via.i64);
249            return o;
250
251        case msgpack::type::FLOAT:
252            o.pack_double(v.via.f64);
253            return o;
254
255        case msgpack::type::STR:
256            o.pack_str(v.via.str.size);
257            o.pack_str_body(v.via.str.ptr, v.via.str.size);
258            return o;
259
260        case msgpack::type::BIN:
261            o.pack_bin(v.via.bin.size);
262            o.pack_bin_body(v.via.bin.ptr, v.via.bin.size);
263            return o;
264
265        case msgpack::type::EXT:
266            o.pack_ext(v.via.ext.size, v.via.ext.type());
267            o.pack_ext_body(v.via.ext.data(), v.via.ext.size);
268            return o;
269
270        case msgpack::type::ARRAY:
271            o.pack_array(v.via.array.size);
272            for(msgpack::object* p(v.via.array.ptr),
273                    * const pend(v.via.array.ptr + v.via.array.size);
274                p < pend; ++p) {
275                msgpack::operator<<(o, *p);
276            }
277            return o;
278
279        case msgpack::type::MAP:
280            o.pack_map(v.via.map.size);
281            for(msgpack::object_kv* p(v.via.map.ptr),
282                    * const pend(v.via.map.ptr + v.via.map.size);
283                p < pend; ++p) {
284                msgpack::operator<<(o, p->key);
285                msgpack::operator<<(o, p->val);
286            }
287            return o;
288
289        default:
290            throw msgpack::type_error();
291        }
292    }
293};
294
295template <>
296struct object_with_zone<msgpack::object> {
297    void operator()(msgpack::object::with_zone& o, msgpack::object const& v) const {
298        o.type = v.type;
299
300        switch(v.type) {
301        case msgpack::type::NIL:
302        case msgpack::type::BOOLEAN:
303        case msgpack::type::POSITIVE_INTEGER:
304        case msgpack::type::NEGATIVE_INTEGER:
305        case msgpack::type::FLOAT:
306            std::memcpy(&o.via, &v.via, sizeof(v.via));
307            return;
308
309        case msgpack::type::STR: {
310            char* ptr = static_cast<char*>(o.zone.allocate_align(v.via.str.size));
311            o.via.str.ptr = ptr;
312            o.via.str.size = v.via.str.size;
313            std::memcpy(ptr, v.via.str.ptr, v.via.str.size);
314            return;
315        }
316
317        case msgpack::type::BIN: {
318            char* ptr = static_cast<char*>(o.zone.allocate_align(v.via.bin.size));
319            o.via.bin.ptr = ptr;
320            o.via.bin.size = v.via.bin.size;
321            std::memcpy(ptr, v.via.bin.ptr, v.via.bin.size);
322            return;
323        }
324
325        case msgpack::type::EXT: {
326            char* ptr = static_cast<char*>(o.zone.allocate_align(v.via.ext.size + 1));
327            o.via.ext.ptr = ptr;
328            o.via.ext.size = v.via.ext.size;
329            std::memcpy(ptr, v.via.ext.ptr, v.via.ext.size + 1);
330            return;
331        }
332
333        case msgpack::type::ARRAY:
334            o.via.array.ptr = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object) * v.via.array.size));
335            o.via.array.size = v.via.array.size;
336            for (msgpack::object
337                     * po(o.via.array.ptr),
338                     * pv(v.via.array.ptr),
339                     * const pvend(v.via.array.ptr + v.via.array.size);
340                 pv < pvend;
341                 ++po, ++pv) {
342                new (po) msgpack::object(*pv, o.zone);
343            }
344            return;
345
346        case msgpack::type::MAP:
347            o.via.map.ptr = (msgpack::object_kv*)o.zone.allocate_align(sizeof(msgpack::object_kv) * v.via.map.size);
348            o.via.map.size = v.via.map.size;
349            for(msgpack::object_kv
350                    * po(o.via.map.ptr),
351                    * pv(v.via.map.ptr),
352                    * const pvend(v.via.map.ptr + v.via.map.size);
353                pv < pvend;
354                ++po, ++pv) {
355                msgpack::object_kv* kv = new (po) msgpack::object_kv;
356                new (&kv->key) msgpack::object(pv->key, o.zone);
357                new (&kv->val) msgpack::object(pv->val, o.zone);
358            }
359            return;
360
361        default:
362            throw msgpack::type_error();
363        }
364
365    }
366};
367
368// Adaptor functor specialization to object::with_zone
369
370template <>
371struct object_with_zone<msgpack::object::with_zone> {
372    void operator()(
373        msgpack::object::with_zone& o,
374        msgpack::object::with_zone const& v) const {
375        o << static_cast<msgpack::object const&>(v);
376    }
377};
378
379
380} // namespace adaptor
381
382
383// obsolete
384template <typename Type>
385class define : public Type {
386public:
387    typedef Type msgpack_type;
388    typedef define<Type> define_type;
389
390    define() {}
391    define(const msgpack_type& v) : msgpack_type(v) {}
392
393    template <typename Packer>
394    void msgpack_pack(Packer& o) const
395    {
396        msgpack::operator<<(o, static_cast<const msgpack_type&>(*this));
397    }
398
399    void msgpack_unpack(object const& o)
400    {
401        msgpack::operator>>(o, static_cast<msgpack_type&>(*this));
402    }
403};
404
405// deconvert operator
406
407template <typename Stream>
408template <typename T>
409inline msgpack::packer<Stream>& packer<Stream>::pack(const T& v)
410{
411    msgpack::operator<<(*this, v);
412    return *this;
413}
414
415inline bool operator==(const msgpack::object& x, const msgpack::object& y)
416{
417    if(x.type != y.type) { return false; }
418
419    switch(x.type) {
420    case msgpack::type::NIL:
421        return true;
422
423    case msgpack::type::BOOLEAN:
424        return x.via.boolean == y.via.boolean;
425
426    case msgpack::type::POSITIVE_INTEGER:
427        return x.via.u64 == y.via.u64;
428
429    case msgpack::type::NEGATIVE_INTEGER:
430        return x.via.i64 == y.via.i64;
431
432    case msgpack::type::FLOAT:
433        return x.via.f64 == y.via.f64;
434
435    case msgpack::type::STR:
436        return x.via.str.size == y.via.str.size &&
437            std::memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0;
438
439    case msgpack::type::BIN:
440        return x.via.bin.size == y.via.bin.size &&
441            std::memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0;
442
443    case msgpack::type::EXT:
444        return x.via.ext.size == y.via.ext.size &&
445            std::memcmp(x.via.ext.ptr, y.via.ext.ptr, x.via.ext.size) == 0;
446
447    case msgpack::type::ARRAY:
448        if(x.via.array.size != y.via.array.size) {
449            return false;
450        } else if(x.via.array.size == 0) {
451            return true;
452        } else {
453            msgpack::object* px = x.via.array.ptr;
454            msgpack::object* const pxend = x.via.array.ptr + x.via.array.size;
455            msgpack::object* py = y.via.array.ptr;
456            do {
457                if(!(*px == *py)) {
458                    return false;
459                }
460                ++px;
461                ++py;
462            } while(px < pxend);
463            return true;
464        }
465
466    case msgpack::type::MAP:
467        if(x.via.map.size != y.via.map.size) {
468            return false;
469        } else if(x.via.map.size == 0) {
470            return true;
471        } else {
472            msgpack::object_kv* px = x.via.map.ptr;
473            msgpack::object_kv* const pxend = x.via.map.ptr + x.via.map.size;
474            msgpack::object_kv* py = y.via.map.ptr;
475            do {
476                if(!(px->key == py->key) || !(px->val == py->val)) {
477                    return false;
478                }
479                ++px;
480                ++py;
481            } while(px < pxend);
482            return true;
483        }
484
485    default:
486        return false;
487    }
488}
489
490template <typename T>
491inline bool operator==(const msgpack::object& x, const T& y)
492try {
493    return x == msgpack::object(y);
494} catch (msgpack::type_error&) {
495    return false;
496}
497
498inline bool operator!=(const msgpack::object& x, const msgpack::object& y)
499{ return !(x == y); }
500
501template <typename T>
502inline bool operator==(const T& y, const msgpack::object& x)
503{ return x == y; }
504
505template <typename T>
506inline bool operator!=(const msgpack::object& x, const T& y)
507{ return !(x == y); }
508
509template <typename T>
510inline bool operator!=(const T& y, const msgpack::object& x)
511{ return x != y; }
512
513
514inline msgpack::object::implicit_type object::convert() const
515{
516    return msgpack::object::implicit_type(*this);
517}
518
519template <typename T>
520inline T& object::convert(T& v) const
521{
522    msgpack::operator>>(*this, v);
523    return v;
524}
525
526#if !defined(MSGPACK_DISABLE_LEGACY_CONVERT)
527template <typename T>
528inline T* object::convert(T* v) const
529{
530    convert(*v);
531    return v;
532}
533#endif // !defined(MSGPACK_DISABLE_LEGACY_CONVERT)
534
535template <typename T>
536inline bool object::convert_if_not_nil(T& v) const
537{
538    if (is_nil()) {
539        return false;
540    }
541    convert(v);
542    return true;
543}
544
545#if defined(MSGPACK_USE_CPP03)
546
547template <typename T>
548inline T object::as() const
549{
550    T v;
551    convert(v);
552    return v;
553}
554
555#else  // defined(MSGPACK_USE_CPP03)
556
557template <typename T>
558inline typename std::enable_if<msgpack::has_as<T>::value, T>::type object::as() const {
559    return msgpack::adaptor::as<T>()(*this);
560}
561
562template <typename T>
563inline typename std::enable_if<!msgpack::has_as<T>::value, T>::type object::as() const {
564    T v;
565    convert(v);
566    return v;
567}
568
569#endif // defined(MSGPACK_USE_CPP03)
570
571inline object::object()
572{
573    type = msgpack::type::NIL;
574}
575
576template <typename T>
577inline object::object(const T& v)
578{
579    msgpack::operator<<(*this, v);
580}
581
582template <typename T>
583inline object& object::operator=(const T& v)
584{
585    *this = object(v);
586    return *this;
587}
588
589template <typename T>
590object::object(const T& v, msgpack::zone& z)
591{
592    with_zone oz(z);
593    msgpack::operator<<(oz, v);
594    type = oz.type;
595    via = oz.via;
596}
597
598template <typename T>
599object::object(const T& v, msgpack::zone* z)
600{
601    with_zone oz(*z);
602    msgpack::operator<<(oz, v);
603    type = oz.type;
604    via = oz.via;
605}
606
607
608inline object::object(const msgpack_object& o)
609{
610    // FIXME beter way?
611    std::memcpy(this, &o, sizeof(o));
612}
613
614inline void operator<< (msgpack::object& o, const msgpack_object& v)
615{
616    // FIXME beter way?
617    std::memcpy(&o, &v, sizeof(v));
618}
619
620inline object::operator msgpack_object() const
621{
622    // FIXME beter way?
623    msgpack_object obj;
624    std::memcpy(&obj, this, sizeof(obj));
625    return obj;
626}
627
628
629// obsolete
630template <typename T>
631inline void convert(T& v, msgpack::object const& o)
632{
633    o.convert(v);
634}
635
636// obsolete
637template <typename Stream, typename T>
638inline void pack(msgpack::packer<Stream>& o, const T& v)
639{
640    o.pack(v);
641}
642
643// obsolete
644template <typename Stream, typename T>
645inline void pack_copy(msgpack::packer<Stream>& o, T v)
646{
647    pack(o, v);
648}
649
650
651template <typename Stream>
652inline msgpack::packer<Stream>& operator<< (msgpack::packer<Stream>& o, const msgpack::object& v)
653{
654    switch(v.type) {
655    case msgpack::type::NIL:
656        o.pack_nil();
657        return o;
658
659    case msgpack::type::BOOLEAN:
660        if(v.via.boolean) {
661            o.pack_true();
662        } else {
663            o.pack_false();
664        }
665        return o;
666
667    case msgpack::type::POSITIVE_INTEGER:
668        o.pack_uint64(v.via.u64);
669        return o;
670
671    case msgpack::type::NEGATIVE_INTEGER:
672        o.pack_int64(v.via.i64);
673        return o;
674
675    case msgpack::type::FLOAT:
676        o.pack_double(v.via.f64);
677        return o;
678
679    case msgpack::type::STR:
680        o.pack_str(v.via.str.size);
681        o.pack_str_body(v.via.str.ptr, v.via.str.size);
682        return o;
683
684    case msgpack::type::BIN:
685        o.pack_bin(v.via.bin.size);
686        o.pack_bin_body(v.via.bin.ptr, v.via.bin.size);
687        return o;
688
689    case msgpack::type::EXT:
690        o.pack_ext(v.via.ext.size, v.via.ext.type());
691        o.pack_ext_body(v.via.ext.data(), v.via.ext.size);
692        return o;
693
694    case msgpack::type::ARRAY:
695        o.pack_array(v.via.array.size);
696        for(msgpack::object* p(v.via.array.ptr),
697                * const pend(v.via.array.ptr + v.via.array.size);
698                p < pend; ++p) {
699            msgpack::operator<<(o, *p);
700        }
701        return o;
702
703    case msgpack::type::MAP:
704        o.pack_map(v.via.map.size);
705        for(msgpack::object_kv* p(v.via.map.ptr),
706                * const pend(v.via.map.ptr + v.via.map.size);
707                p < pend; ++p) {
708            msgpack::operator<<(o, p->key);
709            msgpack::operator<<(o, p->val);
710        }
711        return o;
712
713    default:
714        throw msgpack::type_error();
715    }
716}
717
718template <typename Stream>
719msgpack::packer<Stream>& operator<< (msgpack::packer<Stream>& o, const msgpack::object::with_zone& v)
720{
721    return o << static_cast<msgpack::object>(v);
722}
723
724inline std::ostream& operator<< (std::ostream& s, const msgpack::object& o)
725{
726    switch(o.type) {
727    case msgpack::type::NIL:
728        s << "nil";
729        break;
730
731    case msgpack::type::BOOLEAN:
732        s << (o.via.boolean ? "true" : "false");
733        break;
734
735    case msgpack::type::POSITIVE_INTEGER:
736        s << o.via.u64;
737        break;
738
739    case msgpack::type::NEGATIVE_INTEGER:
740        s << o.via.i64;
741        break;
742
743    case msgpack::type::FLOAT:
744        s << o.via.f64;
745        break;
746
747    case msgpack::type::STR:
748        s << '"';
749        for (uint32_t i = 0; i < o.via.str.size; ++i) {
750            char c = o.via.str.ptr[i];
751            switch (c) {
752            case '\\':
753                s << "\\\\";
754                break;
755            case '"':
756                s << "\\\"";
757                break;
758            case '/':
759                s << "\\/";
760                break;
761            case '\b':
762                s << "\\b";
763                break;
764            case '\f':
765                s << "\\f";
766                break;
767            case '\n':
768                s << "\\n";
769                break;
770            case '\r':
771                s << "\\r";
772                break;
773            case '\t':
774                s << "\\t";
775                break;
776            default: {
777                unsigned int code = static_cast<unsigned int>(c);
778                if (code < 0x20 || code == 0x7f) {
779                    s << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (code & 0xff);
780                }
781                else {
782                    s << c;
783                }
784            } break;
785            }
786        }
787        s << '"';
788        break;
789
790    case msgpack::type::BIN:
791        (s << '"').write(o.via.bin.ptr, o.via.bin.size) << '"';
792        break;
793
794    case msgpack::type::EXT:
795        s << "EXT";
796        break;
797
798    case msgpack::type::ARRAY:
799        s << "[";
800        if(o.via.array.size != 0) {
801            msgpack::object* p(o.via.array.ptr);
802            s << *p;
803            ++p;
804            for(msgpack::object* const pend(o.via.array.ptr + o.via.array.size);
805                    p < pend; ++p) {
806                s << ", " << *p;
807            }
808        }
809        s << "]";
810        break;
811
812    case msgpack::type::MAP:
813        s << "{";
814        if(o.via.map.size != 0) {
815            msgpack::object_kv* p(o.via.map.ptr);
816            s << p->key << ':' << p->val;
817            ++p;
818            for(msgpack::object_kv* const pend(o.via.map.ptr + o.via.map.size);
819                    p < pend; ++p) {
820                s << ", " << p->key << ':' << p->val;
821            }
822        }
823        s << "}";
824        break;
825
826    default:
827        // FIXME
828        s << "#<UNKNOWN " << static_cast<uint16_t>(o.type) << ">";
829    }
830    return s;
831}
832
833/// @cond
834}  // MSGPACK_API_VERSION_NAMESPACE(v1)
835/// @endcond
836
837}  // namespace msgpack
838
839#include "msgpack/type.hpp"
840
841#endif /* msgpack/object.hpp */
842