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