diff --git a/Files.cmake b/Files.cmake index d3a204fb..91b58ee2 100644 --- a/Files.cmake +++ b/Files.cmake @@ -231,6 +231,7 @@ IF (MSGPACK_ENABLE_CXX) include/msgpack/adaptor/vector_bool.hpp include/msgpack/adaptor/vector_char.hpp include/msgpack/adaptor/vector_unsigned_char.hpp + include/msgpack/adaptor/wstring.hpp include/msgpack/cpp_config.hpp include/msgpack/cpp_config_decl.hpp include/msgpack/create_object_visitor.hpp @@ -605,6 +606,7 @@ IF (MSGPACK_ENABLE_CXX) include/msgpack/v1/adaptor/vector_bool.hpp include/msgpack/v1/adaptor/vector_char.hpp include/msgpack/v1/adaptor/vector_unsigned_char.hpp + include/msgpack/v1/adaptor/wstring.hpp include/msgpack/v1/cpp_config.hpp include/msgpack/v1/cpp_config_decl.hpp include/msgpack/v1/detail/cpp03_zone.hpp diff --git a/include/msgpack/adaptor/wstring.hpp b/include/msgpack/adaptor/wstring.hpp new file mode 100644 index 00000000..52b59d52 --- /dev/null +++ b/include/msgpack/adaptor/wstring.hpp @@ -0,0 +1,15 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2018 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_TYPE_WSTRING_HPP +#define MSGPACK_TYPE_WSTRING_HPP + +#include "msgpack/v1/adaptor/wstring.hpp" + +#endif // MSGPACK_TYPE_WSTRING_HPP diff --git a/include/msgpack/type.hpp b/include/msgpack/type.hpp index 1a866c56..b98e7826 100644 --- a/include/msgpack/type.hpp +++ b/include/msgpack/type.hpp @@ -21,6 +21,7 @@ #include "adaptor/vector_bool.hpp" #include "adaptor/vector_char.hpp" #include "adaptor/vector_unsigned_char.hpp" +#include "adaptor/wstring.hpp" #include "adaptor/msgpack_tuple.hpp" #include "adaptor/define.hpp" diff --git a/include/msgpack/v1/adaptor/int.hpp b/include/msgpack/v1/adaptor/int.hpp index 962e66ff..4d6e83ae 100644 --- a/include/msgpack/v1/adaptor/int.hpp +++ b/include/msgpack/v1/adaptor/int.hpp @@ -64,10 +64,9 @@ inline T convert_integer(msgpack::object const& o) } template <> -struct object_char_sign { +struct object_sign { template - static typename msgpack::enable_if::value>::type - make(msgpack::object& o, T v) { + static void make(msgpack::object& o, T v) { if (v < 0) { o.type = msgpack::type::NEGATIVE_INTEGER; o.via.i64 = v; @@ -80,15 +79,17 @@ struct object_char_sign { }; template <> -struct object_char_sign { - static void make(msgpack::object& o, char v) { +struct object_sign { + template + static void make(msgpack::object& o, T v) { o.type = msgpack::type::POSITIVE_INTEGER; o.via.u64 = v; } }; -inline void object_char(msgpack::object& o, char v) { - return object_char_sign::value>::make(o, v); +template +inline void object_char(msgpack::object& o, T v) { + return object_sign::value>::make(o, v); } } // namespace detail @@ -102,6 +103,12 @@ struct convert { { v = type::detail::convert_integer(o); return o; } }; +template <> +struct convert { + msgpack::object const& operator()(msgpack::object const& o, wchar_t& v) const + { v = type::detail::convert_integer(o); return o; } +}; + template <> struct convert { msgpack::object const& operator()(msgpack::object const& o, signed char& v) const @@ -171,6 +178,13 @@ struct pack { { o.pack_char(v); return o; } }; +template <> +struct pack { + template + msgpack::packer& operator()(msgpack::packer& o, wchar_t v) const + { o.pack_wchar(v); return o; } +}; + template <> struct pack { template @@ -249,6 +263,12 @@ struct object { { type::detail::object_char(o, v); } }; +template <> +struct object { + void operator()(msgpack::object& o, wchar_t v) const + { type::detail::object_char(o, v); } +}; + template <> struct object { void operator()(msgpack::object& o, signed char v) const { @@ -367,6 +387,13 @@ struct object_with_zone { } }; +template <> +struct object_with_zone { + void operator()(msgpack::object::with_zone& o, wchar_t v) const { + static_cast(o) << v; + } +}; + template <> struct object_with_zone { void operator()(msgpack::object::with_zone& o, signed char v) const { diff --git a/include/msgpack/v1/adaptor/int_decl.hpp b/include/msgpack/v1/adaptor/int_decl.hpp index eb596c7a..75f1c7bf 100644 --- a/include/msgpack/v1/adaptor/int_decl.hpp +++ b/include/msgpack/v1/adaptor/int_decl.hpp @@ -33,9 +33,10 @@ template T convert_integer(msgpack::object const& o); template -struct object_char_sign; +struct object_sign; -void object_char(msgpack::object& o, char v); +template +void object_char(msgpack::object& o, T v); } // namespace detail } // namespace type diff --git a/include/msgpack/v1/adaptor/wstring.hpp b/include/msgpack/v1/adaptor/wstring.hpp new file mode 100644 index 00000000..66f7929e --- /dev/null +++ b/include/msgpack/v1/adaptor/wstring.hpp @@ -0,0 +1,121 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2018 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_WSTRING_HPP +#define MSGPACK_V1_TYPE_WSTRING_HPP + +#include "msgpack/versioning.hpp" +#include "msgpack/adaptor/adaptor_base.hpp" +#include "msgpack/adaptor/check_container_size.hpp" + +#include + +namespace msgpack { + +/// @cond +MSGPACK_API_VERSION_NAMESPACE(v1) { +/// @endcond + +namespace adaptor { + +#if !defined(MSGPACK_USE_CPP03) + +template <> +struct as { + std::wstring operator()(const msgpack::object& o) const { + if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); } + std::wstring v; + v.reserve(o.via.array.size); + if (o.via.array.size > 0) { + msgpack::object* p = o.via.array.ptr; + msgpack::object* const pend = o.via.array.ptr + o.via.array.size; + do { + v.push_back(p->as()); + ++p; + } while (p < pend); + } + return v; + } +}; + +#endif // !defined(MSGPACK_USE_CPP03) + +template <> +struct convert { + msgpack::object const& operator()(msgpack::object const& o, std::wstring& v) const { + if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); } + v.resize(o.via.array.size); + if (o.via.array.size > 0) { + msgpack::object* p = o.via.array.ptr; + msgpack::object* const pend = o.via.array.ptr + o.via.array.size; + std::wstring::iterator it = v.begin(); + do { + p->convert(*it); + ++p; + ++it; + } while(p < pend); + } + return o; + } +}; + +template <> +struct pack { + template + msgpack::packer& operator()(msgpack::packer& o, const std::wstring& v) const { + uint32_t size = checked_get_container_size(v.size()); + o.pack_array(size); + for (std::wstring::const_iterator it(v.begin()), it_end(v.end()); + it != it_end; ++it) { + o.pack(*it); + } + return o; + } +}; + +template <> +struct object_with_zone { + void operator()(msgpack::object::with_zone& o, const std::wstring& v) const { + o.type = msgpack::type::ARRAY; + if (v.empty()) { + o.via.array.ptr = MSGPACK_NULLPTR; + o.via.array.size = 0; + } + else { + uint32_t size = checked_get_container_size(v.size()); + msgpack::object* p = static_cast(o.zone.allocate_align(sizeof(msgpack::object)*size, MSGPACK_ZONE_ALIGNOF(msgpack::object))); + msgpack::object* const pend = p + size; + o.via.array.ptr = p; + o.via.array.size = size; + std::wstring::const_iterator it(v.begin()); + do { +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif // (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__) + *p = msgpack::object(*it, o.zone); +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif // (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && !defined(__clang__) + ++p; + ++it; + } while(p < pend); + } + } +}; + +} // namespace adaptor + +/// @cond +} // MSGPACK_API_VERSION_NAMESPACE(v1) +/// @endcond + +} // namespace msgpack + +#endif // MSGPACK_V1_TYPE_WSTRING_HPP diff --git a/include/msgpack/v1/pack.hpp b/include/msgpack/v1/pack.hpp index 109334cf..26e271ce 100644 --- a/include/msgpack/v1/pack.hpp +++ b/include/msgpack/v1/pack.hpp @@ -271,6 +271,20 @@ public: */ packer& pack_char(char d); + /// Packing wchar_t + /** + * The byte size of the packed data depends on `d`. + * If `d` is zero or positive, the packed type is positive fixnum, or uint*, + * else the packed type is negative fixnum, or int* + * The minimum byte size expression is used. + * See https://github.com/msgpack/msgpack/blob/master/spec.md#formats-int + * + * @param d a packing object. + * + * @return The reference of `*this`. + */ + packer& pack_wchar(wchar_t d); + /// Packing signed char /** * The byte size of the packed data depends on `d`. @@ -820,6 +834,18 @@ inline packer& packer::pack_char(char d) return *this; } +template +inline packer& packer::pack_wchar(wchar_t d) +{ + if (d < 0) { + pack_imp_int64(static_cast(d)); + } + else { + pack_imp_uint64(static_cast(d)); + } + return *this; +} + template inline packer& packer::pack_signed_char(signed char d) { diff --git a/include/msgpack/v2/adaptor/int_decl.hpp b/include/msgpack/v2/adaptor/int_decl.hpp index 8ad7206e..9b19f3b7 100644 --- a/include/msgpack/v2/adaptor/int_decl.hpp +++ b/include/msgpack/v2/adaptor/int_decl.hpp @@ -30,7 +30,7 @@ struct is_signed; template -struct object_char_sign; +struct object_sign; //using v1::type::detail::convert_integer_sign; diff --git a/include/msgpack/v3/adaptor/int_decl.hpp b/include/msgpack/v3/adaptor/int_decl.hpp index 3a3438ce..70600ec1 100644 --- a/include/msgpack/v3/adaptor/int_decl.hpp +++ b/include/msgpack/v3/adaptor/int_decl.hpp @@ -30,7 +30,7 @@ struct is_signed; template -struct object_char_sign; +struct object_sign; //using v2::type::detail::convert_integer_sign; diff --git a/test/msgpack_basic.cpp b/test/msgpack_basic.cpp index c191a03c..7271e2cd 100644 --- a/test/msgpack_basic.cpp +++ b/test/msgpack_basic.cpp @@ -614,3 +614,22 @@ TEST(MSGPACK_STL, simple_buffer_non_const_cstring) EXPECT_EQ(val1, val2); } } + +TEST(MSGPACK_STL, simple_buffer_wstring) +{ + for (unsigned int k = 0; k < kLoop; k++) { + wstring val1; + for (unsigned int i = 0; i < kElements; i++) + val1 += L'a' + rand() % 26; + msgpack::sbuffer sbuf; + msgpack::pack(sbuf, val1); + msgpack::object_handle oh = + msgpack::unpack(sbuf.data(), sbuf.size()); + EXPECT_EQ(oh.get().type, msgpack::type::ARRAY); + wstring val2 = oh.get().as(); + EXPECT_EQ(val1, val2); + wstring val3; + oh.get().convert(val3); + EXPECT_EQ(val1, val3); + } +} diff --git a/test/object_with_zone.cpp b/test/object_with_zone.cpp index 95c7845d..f23281c9 100644 --- a/test/object_with_zone.cpp +++ b/test/object_with_zone.cpp @@ -332,6 +332,17 @@ TEST(object_without_zone, string) #endif // MSGPACK_DEFAULT_API_VERSION == 1 +// wstring +TEST(object_with_zone, wstring) +{ + wstring v = L"abc"; + msgpack::zone z; + msgpack::object obj(v, z); + EXPECT_EQ(obj.as(), v); + v[0] = 'd'; + EXPECT_EQ(obj.as()[0], L'a'); +} + // char* TEST(object_with_zone, char_ptr) {