diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c3642f1..58c7e51c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,8 @@ LIST (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/") SET (GNUCXX_STD_SUPPORT_VERSION "4.3") OPTION (MSGPACK_CXX11 "Using c++11 compiler" OFF) +OPTION (MSGPACK_CXX17 "Using c++17 compiler" OFF) +OPTION (MSGPACK_CXX20 "Using c++20 compiler (experimental)" OFF) OPTION (MSGPACK_32BIT "32bit compile" OFF) IF (MSGPACK_USE_X3_PARSE) diff --git a/include/msgpack/v1/adaptor/ext.hpp b/include/msgpack/v1/adaptor/ext.hpp index 26a4b538..11fed72f 100644 --- a/include/msgpack/v1/adaptor/ext.hpp +++ b/include/msgpack/v1/adaptor/ext.hpp @@ -37,7 +37,7 @@ public: m_data.resize(static_cast(s) + 1); m_data[0] = static_cast(t); } - ext(ext_ref const&); + explicit ext(ext_ref const&); int8_t type() const { return static_cast(m_data[0]); } @@ -167,6 +167,7 @@ public: if (m_size < x.m_size) return false; return std::memcmp(m_ptr, x.m_ptr, m_size) > 0; } + private: const char* m_ptr; uint32_t m_size; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cc9c4d77..b77ce481 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,7 +46,7 @@ IF (MSGPACK_USE_X3_PARSE) ) ENDIF () -IF (MSGPACK_CXX11 OR MSGPACK_CXX17) +IF (MSGPACK_CXX11 OR MSGPACK_CXX17 OR MSGPACK_CXX20) LIST (APPEND check_PROGRAMS iterator_cpp11.cpp msgpack_cpp11.cpp @@ -60,12 +60,18 @@ IF (MSGPACK_CXX11 OR MSGPACK_CXX17) ) ENDIF () -IF (MSGPACK_CXX17) +IF (MSGPACK_CXX17 OR MSGPACK_CXX20) LIST (APPEND check_PROGRAMS msgpack_cpp17.cpp ) ENDIF () +IF (MSGPACK_CXX20) + LIST (APPEND check_PROGRAMS + msgpack_cpp20.cpp + ) +ENDIF () + FOREACH (source_file ${check_PROGRAMS}) GET_FILENAME_COMPONENT (source_file_we ${source_file} NAME_WE) ADD_EXECUTABLE ( diff --git a/test/boost_variant.cpp b/test/boost_variant.cpp index c2a28d8b..2ab1243e 100644 --- a/test/boost_variant.cpp +++ b/test/boost_variant.cpp @@ -488,7 +488,7 @@ TEST(MSGPACK_BOOST, object_with_zone_variant_ext_ref) msgpack::type::variant val2 = obj.as(); // Converted as msgpack::type::ext. EXPECT_TRUE(val2.is_ext()); - EXPECT_EQ(val2.as_ext(), e); + EXPECT_EQ(val2.as_ext(), msgpack::type::ext(e)); EXPECT_NO_THROW(boost::get(val2)); // msgpack::type::ext_ref and msgpack::type::ext are different. EXPECT_FALSE(val1 == val2); diff --git a/test/msgpack_cpp11.cpp b/test/msgpack_cpp11.cpp index f3569293..490384dd 100644 --- a/test/msgpack_cpp11.cpp +++ b/test/msgpack_cpp11.cpp @@ -262,11 +262,19 @@ struct set_allocator : std::allocator { using std::allocator::allocator; }; -template -struct map_allocator : std::allocator> { - using std::allocator>::allocator; +// C++ named requirement Allocator implies that the first template type +// parameter matches the value type of the allocator. There might be additional +// parameters, but the first one must match the type. +// That's why this helper with exactly one template parameter representing +// a whole key-value pair is required +template +struct map_allocator_impl : std::allocator { + using std::allocator::allocator; }; +template +using map_allocator = map_allocator_impl>; + template struct allocator : std::allocator { using std::allocator::allocator; diff --git a/test/msgpack_cpp20.cpp b/test/msgpack_cpp20.cpp new file mode 100644 index 00000000..339bc1ce --- /dev/null +++ b/test/msgpack_cpp20.cpp @@ -0,0 +1,138 @@ +#include + +#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__) + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// To avoid link error +TEST(MSGPACK_CPP20, dummy) +{ +} + +#if !defined(MSGPACK_USE_CPP03) && __cplusplus > 201703 + +#if MSGPACK_HAS_INCLUDE() + +template +bool operator==(const std::span& lhs, const std::span& rhs) +{ + if (lhs.size() != rhs.size()) + return false; + for (std::size_t i = 0; i < lhs.size(); ++i) + if (lhs[i] != rhs[i]) + return false; + return true; +} + +template +bool operator==(const std::span& lhs, const std::vector& rhs) +{ + return lhs == std::span{rhs.data(), rhs.size()}; +} + +template +bool operator==(const std::vector& lhs, const std::span& rhs) +{ + return std::span{lhs.data(), lhs.size()} == rhs; +} + +#define MSGPACK_TEST_SPAN_BYTE_PACK_CONVERT(byte_t, display_name) \ + TEST(MSGPACK_CPP20, span_##display_name##_pack_convert) \ + { \ + std::stringstream ss; \ + byte_t raw_data[] = { \ + (byte_t)(0x01), (byte_t)(0x02), (byte_t)(0x7f), (byte_t)(0x80), (byte_t)(0xff) \ + }; \ + std::span val1{raw_data, sizeof(raw_data)}; \ + \ + msgpack::pack(ss, val1); \ + std::string const& str = ss.str(); \ + \ + char packed[] = { char(0xc4), char(0x05), char(0x01), char(0x02), char(0x7f), char(0x80), char(0xff) }; \ + EXPECT_EQ(str.size(), sizeof(packed)); \ + for (size_t i = 0; i != sizeof(packed); ++i) { \ + EXPECT_EQ(str[i], packed[i]); \ + } \ + \ + msgpack::object_handle oh; \ + msgpack::unpack(oh, str.data(), str.size()); \ + { \ + auto val2 = oh.get().as>(); \ + EXPECT_TRUE(val1 == val2); \ + } \ + { \ + auto val2 = oh.get().as>(); \ + EXPECT_TRUE(val1 == val2); \ + } \ + } \ + +#define MSGPACK_TEST_SPAN_BYTE_OBJECT(byte_t, display_name) \ + TEST(MSGPACK_CPP20, span_##display_name##_object) \ + { \ + byte_t raw_data[] = { \ + (byte_t)(0x01), (byte_t)(0x02), (byte_t)(0x7f), (byte_t)(0x80), (byte_t)(0xff) \ + }; \ + std::span val1{raw_data, sizeof(raw_data)}; \ + \ + /* Caller needs to manage val1's lifetime. The Data is not copied. */ \ + msgpack::object obj(val1); \ + \ + { \ + auto val2 = obj.as>(); \ + EXPECT_TRUE(val1 == val2); \ + } \ + { \ + auto val2 = obj.as>(); \ + EXPECT_TRUE(val1 == val2); \ + } \ + } \ + +#define MSGPACK_TEST_SPAN_BYTE_OBJECT_WITH_ZONE(byte_t, display_name) \ + TEST(MSGPACK_CPP20, span_##display_name##_object_with_zone) \ + { \ + msgpack::zone z; \ + byte_t raw_data[] = { \ + (byte_t)(0x01), (byte_t)(0x02), (byte_t)(0x7f), (byte_t)(0x80), (byte_t)(0xff) \ + }; \ + std::span val1(raw_data, sizeof(raw_data)); \ + \ + msgpack::object obj(val1, z); \ + \ + { \ + auto val2 = obj.as>(); \ + EXPECT_TRUE(val1 == val2); \ + } \ + { \ + auto val2 = obj.as>(); \ + EXPECT_TRUE(val1 == val2); \ + } \ + } \ + +#define MSGPACK_TEST_SPAN_BYTE(byte_t, display_name) \ + MSGPACK_TEST_SPAN_BYTE_PACK_CONVERT(byte_t, display_name) \ + MSGPACK_TEST_SPAN_BYTE_OBJECT(byte_t, display_name) \ + MSGPACK_TEST_SPAN_BYTE_OBJECT_WITH_ZONE(byte_t, display_name) \ + +MSGPACK_TEST_SPAN_BYTE(std::byte, byte) +MSGPACK_TEST_SPAN_BYTE(char, char) +MSGPACK_TEST_SPAN_BYTE(unsigned char, unsigned_char) + +#undef MSGPACK_TEST_SPAN_BYTE +#undef MSGPACK_TEST_SPAN_BYTE_OBJECT_WITH_ZONE +#undef MSGPACK_TEST_SPAN_BYTE_OBJECT +#undef MSGPACK_TEST_SPAN_BYTE_PACK_CONVERT + +#endif // MSGPACK_HAS_INCLUDE() + +#endif // !defined(MSGPACK_USE_CPP03) && __cplusplus > 201703 diff --git a/test/test_allocator.hpp b/test/test_allocator.hpp index 48271032..6988a779 100644 --- a/test/test_allocator.hpp +++ b/test/test_allocator.hpp @@ -18,13 +18,20 @@ namespace test { template struct allocator { typedef typename std::allocator::value_type value_type; + typedef typename std::allocator::size_type size_type; + typedef typename std::allocator::difference_type difference_type; + template struct rebind { typedef allocator other; }; +#if __cplusplus <= 201703 typedef typename std::allocator::pointer pointer; typedef typename std::allocator::reference reference; typedef typename std::allocator::const_pointer const_pointer; typedef typename std::allocator::const_reference const_reference; - typedef typename std::allocator::size_type size_type; - typedef typename std::allocator::difference_type difference_type; - template struct rebind { typedef allocator other; }; +#else // __cplusplus <= 201703 + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type* const_pointer; + typedef const value_type& const_reference; +#endif // __cplusplus <= 201703 #if defined(MSGPACK_USE_CPP03) allocator() throw() {} allocator (const allocator& alloc) throw() @@ -45,11 +52,21 @@ struct allocator { template allocator (const allocator& alloc) noexcept :alloc_(alloc.alloc_) {} +#if __cplusplus <= 201703 template void construct (U* p, Args&&... args) { return alloc_.construct(p, std::forward(args)...); } size_type max_size() const noexcept { return alloc_.max_size(); } +#else // __cplusplus <= 201703 + template + void construct (U* p, Args&&... args) { + return std::allocator_traits::construct(alloc_, p, std::forward(args)...); + } + size_type max_size() const noexcept { + return std::allocator_traits::max_size(alloc_); + } +#endif // __cplusplus <= 201703 #endif // defined(MSGPACK_USE_CPP03) pointer allocate (size_type n) { return alloc_.allocate(n); @@ -57,9 +74,16 @@ struct allocator { void deallocate (pointer p, size_type n) { return alloc_.deallocate(p, n); } + +#if __cplusplus <= 201703 void destroy (pointer p) { alloc_.destroy(p); } +#else // __cplusplus <= 201703 + void destroy (pointer p) { + std::allocator_traits::destroy(alloc_, p); + } +#endif // __cplusplus <= 201703 std::allocator alloc_; };