Skip to content

Commit bf348ca

Browse files
authored
Merge pull request #1028 from gracicot/develop
Added support for string_view in C++17
2 parents ed6a068 + 14e6278 commit bf348ca

6 files changed

Lines changed: 152 additions & 4 deletions

File tree

include/nlohmann/detail/conversions/from_json.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
7272
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
7373
}
7474

75+
template <
76+
typename BasicJsonType, typename CompatibleStringType,
77+
enable_if_t <
78+
is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
79+
not std::is_same<typename BasicJsonType::string_t,
80+
CompatibleStringType>::value,
81+
int > = 0 >
82+
void from_json(const BasicJsonType& j, CompatibleStringType& s)
83+
{
84+
if (JSON_UNLIKELY(not j.is_string()))
85+
{
86+
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
87+
}
88+
89+
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
90+
}
91+
7592
template<typename BasicJsonType>
7693
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
7794
{

include/nlohmann/detail/conversions/to_json.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ struct external_constructor<value_t::string>
5151
j.m_value = std::move(s);
5252
j.assert_invariant();
5353
}
54+
55+
template<typename BasicJsonType, typename CompatibleStringType,
56+
enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
57+
int> = 0>
58+
static void construct(BasicJsonType& j, const CompatibleStringType& str)
59+
{
60+
j.m_type = value_t::string;
61+
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
62+
j.assert_invariant();
63+
}
5464
};
5565

5666
template<>

include/nlohmann/detail/meta.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
120120
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
121121
};
122122

123+
template<bool B, class RealType, class CompatibleStringType>
124+
struct is_compatible_string_type_impl : std::false_type {};
125+
126+
template<class RealType, class CompatibleStringType>
127+
struct is_compatible_string_type_impl<true, RealType, CompatibleStringType>
128+
{
129+
static constexpr auto value =
130+
std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and
131+
std::is_constructible<RealType, CompatibleStringType>::value;
132+
};
133+
123134
template<class BasicJsonType, class CompatibleObjectType>
124135
struct is_compatible_object_type
125136
{
@@ -130,6 +141,15 @@ struct is_compatible_object_type
130141
typename BasicJsonType::object_t, CompatibleObjectType >::value;
131142
};
132143

144+
template<class BasicJsonType, class CompatibleStringType>
145+
struct is_compatible_string_type
146+
{
147+
static auto constexpr value = is_compatible_string_type_impl <
148+
conjunction<negation<std::is_same<void, CompatibleStringType>>,
149+
has_value_type<CompatibleStringType>>::value,
150+
typename BasicJsonType::string_t, CompatibleStringType >::value;
151+
};
152+
133153
template<typename BasicJsonType, typename T>
134154
struct is_basic_json_nested_type
135155
{

include/nlohmann/json.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2829,9 +2829,9 @@ class basic_json
28292829
not detail::is_basic_json<ValueType>::value
28302830
#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
28312831
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
2832-
#endif
2833-
#if defined(JSON_HAS_CPP_17)
2832+
#if defined(JSON_HAS_CPP_17) && _MSC_VER <= 1914
28342833
and not std::is_same<ValueType, typename std::string_view>::value
2834+
#endif
28352835
#endif
28362836
, int >::type = 0 >
28372837
operator ValueType() const

single_include/nlohmann/json.hpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,17 @@ struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
354354
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
355355
};
356356

357+
template<bool B, class RealType, class CompatibleStringType>
358+
struct is_compatible_string_type_impl : std::false_type {};
359+
360+
template<class RealType, class CompatibleStringType>
361+
struct is_compatible_string_type_impl<true, RealType, CompatibleStringType>
362+
{
363+
static constexpr auto value =
364+
std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and
365+
std::is_constructible<RealType, CompatibleStringType>::value;
366+
};
367+
357368
template<class BasicJsonType, class CompatibleObjectType>
358369
struct is_compatible_object_type
359370
{
@@ -364,6 +375,15 @@ struct is_compatible_object_type
364375
typename BasicJsonType::object_t, CompatibleObjectType >::value;
365376
};
366377

378+
template<class BasicJsonType, class CompatibleStringType>
379+
struct is_compatible_string_type
380+
{
381+
static auto constexpr value = is_compatible_string_type_impl <
382+
conjunction<negation<std::is_same<void, CompatibleStringType>>,
383+
has_value_type<CompatibleStringType>>::value,
384+
typename BasicJsonType::string_t, CompatibleStringType >::value;
385+
};
386+
367387
template<typename BasicJsonType, typename T>
368388
struct is_basic_json_nested_type
369389
{
@@ -980,6 +1000,23 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
9801000
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
9811001
}
9821002

1003+
template <
1004+
typename BasicJsonType, typename CompatibleStringType,
1005+
enable_if_t <
1006+
is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
1007+
not std::is_same<typename BasicJsonType::string_t,
1008+
CompatibleStringType>::value,
1009+
int > = 0 >
1010+
void from_json(const BasicJsonType& j, CompatibleStringType& s)
1011+
{
1012+
if (JSON_UNLIKELY(not j.is_string()))
1013+
{
1014+
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
1015+
}
1016+
1017+
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
1018+
}
1019+
9831020
template<typename BasicJsonType>
9841021
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
9851022
{
@@ -1324,6 +1361,16 @@ struct external_constructor<value_t::string>
13241361
j.m_value = std::move(s);
13251362
j.assert_invariant();
13261363
}
1364+
1365+
template<typename BasicJsonType, typename CompatibleStringType,
1366+
enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
1367+
int> = 0>
1368+
static void construct(BasicJsonType& j, const CompatibleStringType& str)
1369+
{
1370+
j.m_type = value_t::string;
1371+
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
1372+
j.assert_invariant();
1373+
}
13271374
};
13281375

13291376
template<>
@@ -13588,9 +13635,9 @@ class basic_json
1358813635
not detail::is_basic_json<ValueType>::value
1358913636
#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
1359013637
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
13591-
#endif
13592-
#if defined(JSON_HAS_CPP_17)
13638+
#if defined(JSON_HAS_CPP_17) && _MSC_VER <= 1914
1359313639
and not std::is_same<ValueType, typename std::string_view>::value
13640+
#endif
1359413641
#endif
1359513642
, int >::type = 0 >
1359613643
operator ValueType() const

test/src/unit-conversions.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ using nlohmann::json;
4040
#include <unordered_set>
4141
#include <valarray>
4242

43+
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
44+
#define JSON_HAS_CPP_17
45+
#define JSON_HAS_CPP_14
46+
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
47+
#define JSON_HAS_CPP_14
48+
#endif
49+
50+
#if defined(JSON_HAS_CPP_17)
51+
#include <string_view>
52+
#endif
53+
4354
TEST_CASE("value conversion")
4455
{
4556
SECTION("get an object (explicit)")
@@ -344,6 +355,13 @@ TEST_CASE("value conversion")
344355
std::string s = j.get<std::string>();
345356
CHECK(json(s) == j);
346357
}
358+
#if defined(JSON_HAS_CPP_17)
359+
SECTION("std::string_view")
360+
{
361+
std::string_view s = j.get<std::string_view>();
362+
CHECK(json(s) == j);
363+
}
364+
#endif
347365

348366
SECTION("exception in case of a non-string type")
349367
{
@@ -385,6 +403,34 @@ TEST_CASE("value conversion")
385403
json(json::value_t::number_float).get<json::string_t>(),
386404
"[json.exception.type_error.302] type must be string, but is number");
387405
}
406+
407+
#if defined(JSON_HAS_CPP_17)
408+
SECTION("exception in case of a non-string type using string_view")
409+
{
410+
CHECK_THROWS_AS(json(json::value_t::null).get<std::string_view>(), json::type_error&);
411+
CHECK_THROWS_AS(json(json::value_t::object).get<std::string_view>(), json::type_error&);
412+
CHECK_THROWS_AS(json(json::value_t::array).get<std::string_view>(), json::type_error&);
413+
CHECK_THROWS_AS(json(json::value_t::boolean).get<std::string_view>(), json::type_error&);
414+
CHECK_THROWS_AS(json(json::value_t::number_integer).get<std::string_view>(), json::type_error&);
415+
CHECK_THROWS_AS(json(json::value_t::number_unsigned).get<std::string_view>(), json::type_error&);
416+
CHECK_THROWS_AS(json(json::value_t::number_float).get<std::string_view>(), json::type_error&);
417+
418+
CHECK_THROWS_WITH(json(json::value_t::null).get<std::string_view>(),
419+
"[json.exception.type_error.302] type must be string, but is null");
420+
CHECK_THROWS_WITH(json(json::value_t::object).get<std::string_view>(),
421+
"[json.exception.type_error.302] type must be string, but is object");
422+
CHECK_THROWS_WITH(json(json::value_t::array).get<std::string_view>(),
423+
"[json.exception.type_error.302] type must be string, but is array");
424+
CHECK_THROWS_WITH(json(json::value_t::boolean).get<std::string_view>(),
425+
"[json.exception.type_error.302] type must be string, but is boolean");
426+
CHECK_THROWS_WITH(json(json::value_t::number_integer).get<std::string_view>(),
427+
"[json.exception.type_error.302] type must be string, but is number");
428+
CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get<std::string_view>(),
429+
"[json.exception.type_error.302] type must be string, but is number");
430+
CHECK_THROWS_WITH(json(json::value_t::number_float).get<std::string_view>(),
431+
"[json.exception.type_error.302] type must be string, but is number");
432+
}
433+
#endif
388434
}
389435

390436
SECTION("get a string (implicit)")
@@ -398,6 +444,14 @@ TEST_CASE("value conversion")
398444
CHECK(json(s) == j);
399445
}
400446

447+
#if defined(JSON_HAS_CPP_17)
448+
SECTION("std::string_view")
449+
{
450+
std::string_view s = j;
451+
CHECK(json(s) == j);
452+
}
453+
#endif
454+
401455
SECTION("std::string")
402456
{
403457
std::string s = j;

0 commit comments

Comments
 (0)