diff --git a/CMakeLists.txt b/CMakeLists.txt index b3a9e120..2eb45129 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,15 @@ IF (MSGPACK_USE_X3_PARSE) ENDIF () ENDIF () ELSE () - IF (MSGPACK_CXX11) + IF (MSGPACK_CXX17) + IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + SET (CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_CXX_FLAGS}") + ELSEIF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + SET (CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_CXX_FLAGS}") + ELSEIF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + MESSAGE ( FATAL_ERROR "MSVC doesn't support C++17.") + ENDIF () + ELSEIF (MSGPACK_CXX11) IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") SET (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") ELSEIF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") diff --git a/include/msgpack/adaptor/cpp17/optional.hpp b/include/msgpack/adaptor/cpp17/optional.hpp new file mode 100644 index 00000000..5df17d9f --- /dev/null +++ b/include/msgpack/adaptor/cpp17/optional.hpp @@ -0,0 +1,16 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2017 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_CPP17_OPTIONAL_HPP +#define MSGPACK_TYPE_CPP17_OPTIONAL_HPP + +#include "msgpack/v1/adaptor/cpp17/optional.hpp" + +#endif // MSGPACK_TYPE_CPP17_OPTIONAL_HPP diff --git a/include/msgpack/adaptor/cpp17/string_view.hpp b/include/msgpack/adaptor/cpp17/string_view.hpp new file mode 100644 index 00000000..3f77e1bb --- /dev/null +++ b/include/msgpack/adaptor/cpp17/string_view.hpp @@ -0,0 +1,16 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2017 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_CPP17_STRING_VIEW_HPP +#define MSGPACK_TYPE_CPP17_STRING_VIEW_HPP + +#include "msgpack/v1/adaptor/cpp17/string_view.hpp" + +#endif // MSGPACK_TYPE_CPP17_STRING_VIEW_HPP diff --git a/include/msgpack/type.hpp b/include/msgpack/type.hpp index 7fd49e53..2ef6aa9e 100644 --- a/include/msgpack/type.hpp +++ b/include/msgpack/type.hpp @@ -42,6 +42,13 @@ #include "adaptor/cpp11/unordered_map.hpp" #include "adaptor/cpp11/unordered_set.hpp" +#if __cplusplus >= 201703 + +#include "adaptor/cpp17/optional.hpp" +#include "adaptor/cpp17/string_view.hpp" + +#endif // __cplusplus >= 201703 + #endif // defined(MSGPACK_USE_CPP03) #if defined(MSGPACK_USE_BOOST) diff --git a/include/msgpack/v1/adaptor/cpp17/optional.hpp b/include/msgpack/v1/adaptor/cpp17/optional.hpp new file mode 100644 index 00000000..2179ac08 --- /dev/null +++ b/include/msgpack/v1/adaptor/cpp17/optional.hpp @@ -0,0 +1,90 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2017 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_OPTIONAL_HPP +#define MSGPACK_V1_TYPE_OPTIONAL_HPP + +#if __cplusplus >= 201703 + +#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, typename std::enable_if::value>::type> { + std::optional operator()(msgpack::object const& o) const { + if(o.is_nil()) return std::nullopt; + return o.as(); + } +}; + +#endif // !defined (MSGPACK_USE_CPP03) + +template +struct convert > { + msgpack::object const& operator()(msgpack::object const& o, std::optional& v) const { + if(o.is_nil()) v = std::nullopt; + else { + T t; + msgpack::adaptor::convert()(o, t); + v = t; + } + return o; + } +}; + +template +struct pack > { + template + msgpack::packer& operator()(msgpack::packer& o, const std::optional& v) const { + if (v) o.pack(*v); + else o.pack_nil(); + return o; + } +}; + +template +struct object > { + void operator()(msgpack::object& o, const std::optional& v) const { + if (v) msgpack::adaptor::object()(o, *v); + else o.type = msgpack::type::NIL; + } +}; + +template +struct object_with_zone > { + void operator()(msgpack::object::with_zone& o, const std::optional& v) const { + if (v) msgpack::adaptor::object_with_zone()(o, *v); + else o.type = msgpack::type::NIL; + } +}; + +} // namespace adaptor + +/// @cond +} // MSGPACK_API_VERSION_NAMESPACE(v1) +/// @endcond + +} // namespace msgpack + +#endif // __cplusplus >= 201703 + +#endif // MSGPACK_V1_TYPE_OPTIONAL_HPP diff --git a/include/msgpack/v1/adaptor/cpp17/string_view.hpp b/include/msgpack/v1/adaptor/cpp17/string_view.hpp new file mode 100644 index 00000000..8ec56c26 --- /dev/null +++ b/include/msgpack/v1/adaptor/cpp17/string_view.hpp @@ -0,0 +1,86 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2017 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_STRING_VIEW_HPP +#define MSGPACK_V1_TYPE_STRING_VIEW_HPP + +#if __cplusplus >= 201703 + +#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 { + +template <> +struct convert { + msgpack::object const& operator()(msgpack::object const& o, std::string_view& v) const { + switch (o.type) { + case msgpack::type::BIN: + v = std::string_view(o.via.bin.ptr, o.via.bin.size); + break; + case msgpack::type::STR: + v = std::string_view(o.via.str.ptr, o.via.str.size); + break; + default: + throw msgpack::type_error(); + break; + } + return o; + } +}; + +template <> +struct pack { + template + msgpack::packer& operator()(msgpack::packer& o, const std::string_view& v) const { + uint32_t size = checked_get_container_size(v.size()); + o.pack_str(size); + o.pack_str_body(v.data(), size); + return o; + } +}; + +template <> +struct object { + void operator()(msgpack::object& o, const std::string_view& v) const { + uint32_t size = checked_get_container_size(v.size()); + o.type = msgpack::type::STR; + o.via.str.ptr = v.data(); + o.via.str.size = size; + } +}; + +template <> +struct object_with_zone { + void operator()(msgpack::object::with_zone& o, const std::string_view& v) const { + static_cast(o) << v; + } +}; + + +} // namespace adaptor + +/// @cond +} // MSGPACK_API_VERSION_NAMESPACE(v1) +/// @endcond + +} // namespace msgpack + +#endif // __cplusplus >= 201703 + +#endif // MSGPACK_V1_TYPE_STRING_VIEW_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 11935e07..7d86b7a9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -66,6 +66,12 @@ IF (MSGPACK_CXX11) ) ENDIF () +IF (MSGPACK_CXX17) + LIST (APPEND check_PROGRAMS + msgpack_cpp17.cpp + ) +ENDIF () + FOREACH (source_file ${check_PROGRAMS}) GET_FILENAME_COMPONENT (source_file_we ${source_file} NAME_WE) ADD_EXECUTABLE ( diff --git a/test/msgpack_cpp17.cpp b/test/msgpack_cpp17.cpp new file mode 100644 index 00000000..0da11344 --- /dev/null +++ b/test/msgpack_cpp17.cpp @@ -0,0 +1,207 @@ +#include + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if !defined(MSGPACK_USE_CPP03) && __cplusplus >= 201703 + +// C++17 + +TEST(MSGPACK_CPP17, optional_pack_convert_nil) +{ + std::stringstream ss; + std::optional val1; + msgpack::pack(ss, val1); + msgpack::object_handle oh = + msgpack::unpack(ss.str().data(), ss.str().size()); + std::optional val2 = oh.get().as >(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_pack_convert_int) +{ + std::stringstream ss; + std::optional val1 = 1; + msgpack::pack(ss, val1); + msgpack::object_handle oh = + msgpack::unpack(ss.str().data(), ss.str().size()); + std::optional val2 = oh.get().as >(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_pack_convert_vector) +{ + typedef std::optional > ovi_t; + std::stringstream ss; + ovi_t val1; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + val1 = v; + msgpack::pack(ss, val1); + msgpack::object_handle oh = + msgpack::unpack(ss.str().data(), ss.str().size()); + ovi_t val2 = oh.get().as(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_pack_convert_vector_optional) +{ + typedef std::vector > voi_t; + std::stringstream ss; + voi_t val1; + val1.resize(3); + val1[0] = 1; + val1[2] = 3; + msgpack::pack(ss, val1); + msgpack::object_handle oh = + msgpack::unpack(ss.str().data(), ss.str().size()); + voi_t val2 = oh.get().as(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_object_nil) +{ + std::optional val1; + msgpack::object obj(val1); + std::optional val2 = obj.as >(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_object_int) +{ + std::optional val1 = 1; + msgpack::object obj(val1); + std::optional val2 = obj.as >(); + EXPECT_TRUE(val1 == val2); +} + +// Compile error as expected +/* + TEST(MSGPACK_CPP17, optional_object_vector) + { + typedef std::optional > ovi_t; + ovi_t val1; + std::vector v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + val1 = v; + msgpack::object obj(val1); + ovi_t val2 = obj.as(); + EXPECT_TRUE(val1 == val2); + } +*/ + +TEST(MSGPACK_CPP17, optional_object_with_zone_nil) +{ + msgpack::zone z; + std::optional val1; + msgpack::object obj(val1, z); + std::optional val2 = obj.as >(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_object_with_zone_int) +{ + msgpack::zone z; + std::optional val1 = 1; + msgpack::object obj(val1, z); + std::optional val2 = obj.as >(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, optional_object_with_zone_vector_optional) +{ + typedef std::vector > voi_t; + msgpack::zone z; + voi_t val1; + val1.resize(3); + val1[0] = 1; + val1[2] = 3; + msgpack::object obj(val1, z); + voi_t val2 = obj.as(); + EXPECT_TRUE(val1 == val2); +} + +struct no_def_con { + no_def_con() = delete; + no_def_con(int i):i(i) {} + int i; + MSGPACK_DEFINE(i); +}; + +inline bool operator==(no_def_con const& lhs, no_def_con const& rhs) { + return lhs.i == rhs.i; +} + +inline bool operator!=(no_def_con const& lhs, no_def_con const& rhs) { + return !(lhs == rhs); +} + +namespace msgpack { +MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) { +namespace adaptor { + +template <> +struct as { + no_def_con operator()(msgpack::object const& o) const { + if (o.type != msgpack::type::ARRAY) throw msgpack::type_error(); + if (o.via.array.size != 1) throw msgpack::type_error(); + return no_def_con(o.via.array.ptr[0].as()); + } +}; + +} // adaptor +} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) +} // msgpack + +TEST(MSGPACK_CPP17, optional_pack_convert_no_def_con) +{ + std::stringstream ss; + std::optional val1 = no_def_con(1); + msgpack::pack(ss, val1); + msgpack::object_handle oh = + msgpack::unpack(ss.str().data(), ss.str().size()); + std::optional val2 = oh.get().as>(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, string_view_pack_convert_string_view) +{ + std::stringstream ss; + std::string s = "ABC"; + std::string_view val1(s); + + msgpack::pack(ss, val1); + + msgpack::object_handle oh; + msgpack::unpack(oh, ss.str().data(), ss.str().size()); + std::string_view val2 = oh.get().as(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, string_view_object_strinf_view) +{ + std::string s = "ABC"; + std::string_view val1(s); + msgpack::object obj(val1); + std::string_view val2 = obj.as(); + EXPECT_TRUE(val1 == val2); +} + +TEST(MSGPACK_CPP17, string_view_object_with_zone_string_view) +{ + msgpack::zone z; + std::string s = "ABC"; + std::string_view val1(s); + msgpack::object obj(val1, z); + std::string_view val2 = obj.as(); + EXPECT_TRUE(val1 == val2); +} + +#endif // !defined(MSGPACK_USE_CPP03) && __cplusplus >= 201703