[nlohmann-json] Port upstream fix #4736 for char8_t detection (#49426)

This commit is contained in:
Aaron van Geffen
2026-01-14 23:45:37 +01:00
committed by GitHub
parent a3488f44d8
commit f55552d71c
5 changed files with 137 additions and 2 deletions

View File

@@ -0,0 +1,129 @@
diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp
index d647d74239..e161a4282f 100644
--- a/include/nlohmann/detail/conversions/from_json.hpp
+++ b/include/nlohmann/detail/conversions/from_json.hpp
@@ -540,7 +540,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
}
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
-#ifdef JSON_HAS_CPP_20
+ // Checking for C++20 standard or later can be insufficient in case the
+ // library support for char8_t is either incomplete or was disabled
+ // altogether. Use the __cpp_lib_char8_t feature test instead.
+#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L)
p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));
#else
p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20
diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp
index ead45665f1..b17e8af437 100644
--- a/include/nlohmann/detail/conversions/to_json.hpp
+++ b/include/nlohmann/detail/conversions/to_json.hpp
@@ -15,7 +15,8 @@
#include <algorithm> // copy
#include <iterator> // begin, end
-#include <string> // string
+#include <memory> // allocator_traits
+#include <string> // basic_string, char_traits
#include <tuple> // tuple, get
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
#include <utility> // move, forward, declval, pair
@@ -440,15 +441,21 @@ inline void to_json(BasicJsonType& j, const T& t)
}
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
+#if defined(__cpp_lib_char8_t)
+template<typename BasicJsonType, typename Tr, typename Allocator>
+inline void to_json(BasicJsonType& j, const std::basic_string<char8_t, Tr, Allocator>& s)
+{
+ using OtherAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
+ j = std::basic_string<char, std::char_traits<char>, OtherAllocator>(s.begin(), s.end(), s.get_allocator());
+}
+#endif
+
template<typename BasicJsonType>
inline void to_json(BasicJsonType& j, const std_fs::path& p)
{
-#ifdef JSON_HAS_CPP_20
- const std::u8string s = p.u8string();
- j = std::string(s.begin(), s.end());
-#else
- j = p.u8string(); // returns std::string in C++17
-#endif
+ // Returns either a std::string or a std::u8string depending whether library
+ // support for char8_t is enabled.
+ j = p.u8string();
}
#endif
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 82d69f7c5d..be3493efa8 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -5325,7 +5325,10 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
}
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
-#ifdef JSON_HAS_CPP_20
+ // Checking for C++20 standard or later can be insufficient in case the
+ // library support for char8_t is either incomplete or was disabled
+ // altogether. Use the __cpp_lib_char8_t feature test instead.
+#if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L)
p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));
#else
p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20
@@ -5380,7 +5383,8 @@ NLOHMANN_JSON_NAMESPACE_END
#include <algorithm> // copy
#include <iterator> // begin, end
-#include <string> // string
+#include <memory> // allocator_traits
+#include <string> // basic_string, char_traits
#include <tuple> // tuple, get
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
#include <utility> // move, forward, declval, pair
@@ -6087,15 +6091,21 @@ inline void to_json(BasicJsonType& j, const T& t)
}
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
+#if defined(__cpp_lib_char8_t)
+template<typename BasicJsonType, typename Tr, typename Allocator>
+inline void to_json(BasicJsonType& j, const std::basic_string<char8_t, Tr, Allocator>& s)
+{
+ using OtherAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
+ j = std::basic_string<char, std::char_traits<char>, OtherAllocator>(s.begin(), s.end(), s.get_allocator());
+}
+#endif
+
template<typename BasicJsonType>
inline void to_json(BasicJsonType& j, const std_fs::path& p)
{
-#ifdef JSON_HAS_CPP_20
- const std::u8string s = p.u8string();
- j = std::string(s.begin(), s.end());
-#else
- j = p.u8string(); // returns std::string in C++17
-#endif
+ // Returns either a std::string or a std::u8string depending whether library
+ // support for char8_t is enabled.
+ j = p.u8string();
}
#endif
diff --git a/tests/src/unit-deserialization.cpp b/tests/src/unit-deserialization.cpp
index 84a970a183..5c450c23d3 100644
--- a/tests/src/unit-deserialization.cpp
+++ b/tests/src/unit-deserialization.cpp
@@ -1134,9 +1134,10 @@ TEST_CASE("deserialization")
}
}
-// select the types to test - char8_t is only available in C++20
+// select the types to test - char8_t is only available since C++20 if and only
+// if __cpp_char8_t is defined.
#define TYPE_LIST(...) __VA_ARGS__
-#ifdef JSON_HAS_CPP_20
+#if defined(__cpp_char8_t) && (__cpp_char8_t >= 201811L)
#define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t, char8_t)
#else
#define ASCII_TYPES TYPE_LIST(char, wchar_t, char16_t, char32_t)

View File

@@ -5,6 +5,7 @@ vcpkg_from_github(
SHA512 6cc1e86261f8fac21cc17a33da3b6b3c3cd5c116755651642af3c9e99bb3538fd42c1bd50397a77c8fb6821bc62d90e6b91bcdde77a78f58f2416c62fc53b97d
HEAD_REF master
PATCHES
fix-4736_char8_t.patch
fix-4742_std_optional.patch
)

View File

@@ -1,7 +1,7 @@
{
"name": "nlohmann-json",
"version-semver": "3.12.0",
"port-version": 1,
"port-version": 2,
"description": "JSON for Modern C++",
"homepage": "https://github.com/nlohmann/json",
"license": "MIT",

View File

@@ -6886,7 +6886,7 @@
},
"nlohmann-json": {
"baseline": "3.12.0",
"port-version": 1
"port-version": 2
},
"nlopt": {
"baseline": "2.10.0",

View File

@@ -1,5 +1,10 @@
{
"versions": [
{
"git-tree": "ac3b8821cf486e45dd543bef2a4ba1d1ba230258",
"version-semver": "3.12.0",
"port-version": 2
},
{
"git-tree": "f89a58e6478ca1e39120e93e7ed535c4aaf8198c",
"version-semver": "3.12.0",