// // MessagePack for C++ static resolution routine // // Copyright (C) 2015-2016 KONDO Takatoshi // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef MSGPACK_V1_TYPE_BOOST_MSGPACK_VARIANT_HPP #define MSGPACK_V1_TYPE_BOOST_MSGPACK_VARIANT_HPP #include "msgpack/v1/adaptor/boost/msgpack_variant_decl.hpp" #include "msgpack/adaptor/check_container_size.hpp" #include "msgpack/adaptor/boost/string_ref.hpp" #include "msgpack/adaptor/nil.hpp" #include "msgpack/adaptor/bool.hpp" #include "msgpack/adaptor/int.hpp" #include "msgpack/adaptor/float.hpp" #include "msgpack/adaptor/string.hpp" #include "msgpack/adaptor/vector_char.hpp" #include "msgpack/adaptor/raw.hpp" #include "msgpack/adaptor/ext.hpp" #include "msgpack/adaptor/vector.hpp" #include "msgpack/adaptor/map.hpp" #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif // defined(__GNUC__) #include #if defined(__GNUC__) #pragma GCC diagnostic pop #endif // defined(__GNUC__) #include namespace msgpack { /// @cond MSGPACK_API_VERSION_NAMESPACE(v1) { /// @endcond namespace type { template struct basic_variant : boost::variant< nil_t, // NIL bool, // BOOL int64_t, // NEGATIVE_INTEGER uint64_t, // POSITIVE_INTEGER double, // FLOAT32, FLOAT64 std::string, // STR #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 boost::string_ref, // STR #endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 std::vector, // BIN msgpack::type::raw_ref, // BIN msgpack::type::ext, // EXT msgpack::type::ext_ref, // EXT boost::recursive_wrapper > >, // ARRAY boost::recursive_wrapper, basic_variant > >, // MAP boost::recursive_wrapper, basic_variant > >// MAP >, private boost::totally_ordered > { typedef boost::variant< nil_t, // NIL bool, // BOOL int64_t, // NEGATIVE_INTEGER uint64_t, // POSITIVE_INTEGER double, // FLOAT32, FLOAT64 std::string, // STR #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 boost::string_ref, // STR #endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 std::vector, // BIN msgpack::type::raw_ref, // BIN msgpack::type::ext, // EXT msgpack::type::ext_ref, // EXT boost::recursive_wrapper > >, // ARRAY boost::recursive_wrapper, basic_variant > >, // MAP boost::recursive_wrapper, basic_variant > >// MAP > base; basic_variant() {} template basic_variant(T const& t):base(t) {} #if defined(_MSC_VER) && _MSC_VER < 1700 // The following redundant functions are required to avoid MSVC // See https://svn.boost.org/trac/boost/ticket/592 basic_variant(basic_variant const& other):base(static_cast(other)) {} basic_variant& operator=(basic_variant const& other) { *static_cast(this) = static_cast(other); return *this; } #endif // defined(_MSC_VER) && _MSC_VER < 1700 basic_variant(char const* p):base(std::string(p)) {} basic_variant(char v) { int_init(v); } basic_variant(signed char v) { int_init(v); } basic_variant(unsigned char v):base(uint64_t(v)) {} basic_variant(signed int v) { int_init(v); } basic_variant(unsigned int v):base(uint64_t(v)) {} basic_variant(signed long v) { int_init(v); } basic_variant(unsigned long v):base(uint64_t(v)) {} basic_variant(signed long long v) { int_init(v); } basic_variant(unsigned long long v):base(uint64_t(v)) {} basic_variant(float v) { double_init(v); } basic_variant(double v) { double_init(v); } bool is_nil() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_bool() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_int64_t() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_uint64_t() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_double() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_string() const { return boost::get(this) != MSGPACK_NULLPTR; } #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 bool is_boost_string_ref() const { return boost::get(this) != MSGPACK_NULLPTR; } #endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 bool is_vector_char() const { return boost::get >(this) != MSGPACK_NULLPTR; } bool is_vector_char() { return boost::get >(this) != MSGPACK_NULLPTR; } bool is_raw_ref() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_ext() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_ext_ref() const { return boost::get(this) != MSGPACK_NULLPTR; } bool is_vector() const { return boost::get > >(this) != MSGPACK_NULLPTR; } bool is_map() const { return boost::get, basic_variant > >(this) != MSGPACK_NULLPTR; } bool is_multimap() const { return boost::get, basic_variant > >(this) != MSGPACK_NULLPTR; } bool as_bool() const { return boost::get(*this); } int64_t as_int64_t() const { return boost::get(*this); } uint64_t as_uint64_t() const { return boost::get(*this); } double as_double() const { if (is_double()) { return boost::get(*this); } if (is_int64_t()) { return static_cast(boost::get(*this)); } if (is_uint64_t()) { return static_cast(boost::get(*this)); } throw msgpack::type_error(); } std::string const& as_string() const { return boost::get(*this); } #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 boost::string_ref const& as_boost_string_ref() const { return boost::get(*this); } #endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 std::vector const& as_vector_char() const { return boost::get >(*this); } raw_ref const& as_raw_ref() const { return boost::get(*this); } ext const& as_ext() const { return boost::get(*this); } ext_ref const& as_ext_ref() const { return boost::get(*this); } std::vector > const& as_vector() const { return boost::get > >(*this); } std::map, basic_variant > const& as_map() const { return boost::get, basic_variant > >(*this); } std::multimap, basic_variant > const& as_multimap() const { return boost::get, basic_variant > >(*this); } private: template void int_init(T v) { if (v < 0) { static_cast(*this) = int64_t(v); } else { static_cast(*this) = uint64_t(v); } } void double_init(double v) { if (v == v) { // check for nan if (v >= 0 && v <= double(std::numeric_limits::max()) && v == double(uint64_t(v))) { static_cast(*this) = uint64_t(v); return; } else if (v < 0 && v >= double(std::numeric_limits::min()) && v == double(int64_t(v))) { static_cast(*this) = int64_t(v); return; } } static_cast(*this) = v; } }; template inline bool operator<(basic_variant const& lhs, basic_variant const& rhs) { return static_cast::base const&>(lhs) < static_cast::base const&>(rhs); } template inline bool operator==(basic_variant const& lhs, basic_variant const& rhs) { return static_cast::base const&>(lhs) == static_cast::base const&>(rhs); } typedef basic_variant, ext> variant; typedef basic_variant< #if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 boost::string_ref, #else // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 std::string, #endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53 raw_ref, ext_ref> variant_ref; } // namespace type namespace adaptor { #if !defined (MSGPACK_USE_CPP03) template struct as > { type::basic_variant operator()(msgpack::object const& o) const { switch(o.type) { case type::NIL: return o.as(); case type::BOOLEAN: return o.as(); case type::POSITIVE_INTEGER: return o.as(); case type::NEGATIVE_INTEGER: return o.as(); case type::FLOAT32: case type::FLOAT64: return o.as(); case type::STR: return o.as(); case type::BIN: return o.as(); case type::EXT: return o.as(); case type::ARRAY: return o.as > >(); case type::MAP: return o.as, type::basic_variant > >(); default: break; } return type::basic_variant(); } }; #endif // !defined (MSGPACK_USE_CPP03) template struct convert > { msgpack::object const& operator()( msgpack::object const& o, type::basic_variant& v) const { switch(o.type) { case type::NIL: v = o.as(); break; case type::BOOLEAN: v = o.as(); break; case type::POSITIVE_INTEGER: v = o.as(); break; case type::NEGATIVE_INTEGER: v = o.as(); break; case type::FLOAT32: case type::FLOAT64: v = o.as(); break; case type::STR: v = o.as(); break; case type::BIN: v = o.as(); break; case type::EXT: v = o.as(); break; case type::ARRAY: v = o.as > >(); break; case type::MAP: v = o.as, type::basic_variant > >(); break; default: break; } return o; } }; namespace detail { template struct pack_imp : boost::static_visitor { template void operator()(T const& value) const { pack()(o_, value); } pack_imp(packer& o):o_(o) {} packer& o_; }; } // namespace detail template struct pack > { template msgpack::packer& operator()(msgpack::packer& o, const type::basic_variant& v) const { boost::apply_visitor(detail::pack_imp(o), v); return o; } }; namespace detail { struct object_imp : boost::static_visitor { void operator()(msgpack::type::nil_t const& v) const { object()(o_, v); } void operator()(bool const& v) const { object()(o_, v); } void operator()(uint64_t const& v) const { object()(o_, v); } void operator()(int64_t const& v) const { object()(o_, v); } void operator()(double const& v) const { object()(o_, v); } template void operator()(T const&) const { throw msgpack::type_error(); } object_imp(msgpack::object& o):o_(o) {} msgpack::object& o_; }; } // namespace detail template struct object > { void operator()(msgpack::object& o, const type::basic_variant& v) const { boost::apply_visitor(detail::object_imp(o), v); } }; namespace detail { struct object_with_zone_imp : boost::static_visitor { template void operator()(T const& v) const { object_with_zone()(o_, v); } object_with_zone_imp(msgpack::object::with_zone& o):o_(o) {} msgpack::object::with_zone& o_; }; } // namespace detail template struct object_with_zone > { void operator()(msgpack::object::with_zone& o, const type::basic_variant& v) const { boost::apply_visitor(detail::object_with_zone_imp(o), v); } }; } // namespace adaptor /// @cond } // MSGPACK_API_VERSION_NAMESPACE(v1) /// @endcond } // namespace msgpack #endif // MSGPACK_V1_TYPE_BOOST_MSGPACK_VARIANT_HPP