Skip to content

Commit 6c4cf7a

Browse files
committed
Provide fallback for missing char8_t support
Clang 11.0.x with libc++ fails to compile tests in C++20 mode due to incomplete char8_t support in std::filesystem::path. Signed-off-by: Sergiu Deitsch <sergiu.deitsch@gmail.com>
1 parent 7ddea26 commit 6c4cf7a

4 files changed

Lines changed: 34 additions & 16 deletions

File tree

include/nlohmann/detail/conversions/from_json.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
540540
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
541541
}
542542
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
543-
#ifdef JSON_HAS_CPP_20
543+
// Checking for C++20 standard or later can be insufficient in case the
544+
// library support for char8_t is either incomplete or was disabled
545+
// altogether. Use the __cpp_lib_char8_t feature test instead.
546+
#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L)
544547
p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));
545548
#else
546549
p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20

include/nlohmann/detail/conversions/to_json.hpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -440,15 +440,21 @@ inline void to_json(BasicJsonType& j, const T& t)
440440
}
441441

442442
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
443+
#if defined(__cpp_lib_char8_t)
444+
template<typename BasicJsonType, typename Tr, typename Allocator>
445+
inline void to_json(BasicJsonType& j, const std::basic_string<char8_t, Tr, Allocator>& s)
446+
{
447+
using OtherAllocator = std::allocator_traits<Allocator>::template rebind_alloc<char>;
448+
j = std::basic_string<char, std::char_traits<char>, OtherAllocator>(s.begin(), s.end(), s.get_allocator());
449+
}
450+
#endif
451+
443452
template<typename BasicJsonType>
444453
inline void to_json(BasicJsonType& j, const std_fs::path& p)
445454
{
446-
#ifdef JSON_HAS_CPP_20
447-
const std::u8string s = p.u8string();
448-
j = std::string(s.begin(), s.end());
449-
#else
450-
j = p.u8string(); // returns std::string in C++17
451-
#endif
455+
// Returns either a std::string or a std::u8string depending whether library
456+
// support for char8_t is enabled.
457+
j = p.u8string();
452458
}
453459
#endif
454460

single_include/nlohmann/json.hpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5325,7 +5325,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
53255325
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
53265326
}
53275327
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
5328-
#ifdef JSON_HAS_CPP_20
5328+
// Checking for C++20 standard or later can be insufficient in case the
5329+
// library support for char8_t is either incomplete or was disabled
5330+
// altogether. Use the __cpp_lib_char8_t feature test instead.
5331+
#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L)
53295332
p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));
53305333
#else
53315334
p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20
@@ -6087,15 +6090,20 @@ inline void to_json(BasicJsonType& j, const T& t)
60876090
}
60886091

60896092
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
6090-
template<typename BasicJsonType>
6091-
inline void to_json(BasicJsonType& j, const std_fs::path& p)
6093+
#if defined(__cpp_lib_char8_t)
6094+
template<typename BasicJsonType, typename Tr, typename Allocator>
6095+
inline void to_json(BasicJsonType& j, const std::basic_string<char8_t, Tr, Allocator>& s)
60926096
{
6093-
#ifdef JSON_HAS_CPP_20
6094-
const std::u8string s = p.u8string();
60956097
j = std::string(s.begin(), s.end());
6096-
#else
6097-
j = p.u8string(); // returns std::string in C++17
6098+
}
60986099
#endif
6100+
6101+
template<typename BasicJsonType>
6102+
inline void to_json(BasicJsonType& j, const std_fs::path& p)
6103+
{
6104+
// Returns either a std::string or a std::u8string depending whether library
6105+
// support for char8_t is enabled.
6106+
j = p.u8string();
60996107
}
61006108
#endif
61016109

tests/src/unit-deserialization.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,9 +1134,10 @@ TEST_CASE("deserialization")
11341134
}
11351135
}
11361136

1137-
// select the types to test - char8_t is only available in C++20
1137+
// select the types to test - char8_t is only available since C++20 if and only
1138+
// if __cpp_char8_t is defined.
11381139
#define TYPE_LIST(...) __VA_ARGS__
1139-
#ifdef JSON_HAS_CPP_20
1140+
#if defined(__cpp_char8_t) && (__cpp_char8_t >= 201811L)
11401141
#define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t, char8_t)
11411142
#else
11421143
#define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t)

0 commit comments

Comments
 (0)