Skip to content

Commit 4802b9f

Browse files
committed
Fix iterator_input_adapter for types not supported by char_traits
1 parent edffad0 commit 4802b9f

File tree

2 files changed

+122
-2
lines changed

2 files changed

+122
-2
lines changed

include/nlohmann/detail/input/input_adapters.hpp

+61-1
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,70 @@ class input_stream_adapter
132132
};
133133
#endif // JSON_NO_IO
134134

135+
template<typename T>
136+
struct has_char_traits : std::false_type {};
137+
138+
template<>
139+
struct has_char_traits<char> : std::true_type {};
140+
141+
template<>
142+
struct has_char_traits<wchar_t> : std::true_type {};
143+
144+
#ifdef JSON_HAS_CPP_20
145+
template<>
146+
struct has_char_traits<char8_t> : std::true_type {};
147+
148+
template<>
149+
struct has_char_traits<char16_t> : std::true_type {};
150+
151+
template<>
152+
struct has_char_traits<char32_t> : std::true_type {};
153+
#endif
154+
155+
template<typename T>
156+
struct is_iterator_of_char : has_char_traits<typename std::iterator_traits<T>::value_type> {};
157+
135158
// General-purpose iterator-based adapter. It might not be as fast as
136159
// theoretically possible for some containers, but it is extremely versatile.
137-
template<typename IteratorType>
160+
template<typename IteratorType, typename = void>
138161
class iterator_input_adapter
162+
{
163+
public:
164+
using char_type = char;
165+
using value_type = typename std::iterator_traits<IteratorType>::value_type;
166+
167+
iterator_input_adapter(IteratorType first, IteratorType last)
168+
: current(std::move(first)), end(std::move(last))
169+
{}
170+
171+
typename std::char_traits<char>::int_type get_character()
172+
{
173+
if (JSON_HEDLEY_LIKELY(current != end))
174+
{
175+
// Cast to unsigned to avoid EOF and 0xFF having same value
176+
auto result = static_cast<typename std::make_unsigned<value_type>::type>(*current);
177+
std::advance(current, 1);
178+
return result;
179+
}
180+
181+
return std::char_traits<char>::eof();
182+
}
183+
184+
private:
185+
IteratorType current;
186+
IteratorType end;
187+
188+
template<typename BaseInputAdapter, size_t T>
189+
friend struct wide_string_input_helper;
190+
191+
bool empty() const
192+
{
193+
return current == end;
194+
}
195+
};
196+
197+
template<typename IteratorType>
198+
class iterator_input_adapter<IteratorType, enable_if_t<is_iterator_of_char<IteratorType>::value>>
139199
{
140200
public:
141201
using char_type = typename std::iterator_traits<IteratorType>::value_type;

single_include/nlohmann/json.hpp

+61-1
Original file line numberDiff line numberDiff line change
@@ -6208,10 +6208,70 @@ class input_stream_adapter
62086208
};
62096209
#endif // JSON_NO_IO
62106210

6211+
template<typename T>
6212+
struct has_char_traits : std::false_type {};
6213+
6214+
template<>
6215+
struct has_char_traits<char> : std::true_type {};
6216+
6217+
template<>
6218+
struct has_char_traits<wchar_t> : std::true_type {};
6219+
6220+
#ifdef JSON_HAS_CPP_20
6221+
template<>
6222+
struct has_char_traits<char8_t> : std::true_type {};
6223+
6224+
template<>
6225+
struct has_char_traits<char16_t> : std::true_type {};
6226+
6227+
template<>
6228+
struct has_char_traits<char32_t> : std::true_type {};
6229+
#endif
6230+
6231+
template<typename T>
6232+
struct is_iterator_of_char : has_char_traits<typename std::iterator_traits<T>::value_type> {};
6233+
62116234
// General-purpose iterator-based adapter. It might not be as fast as
62126235
// theoretically possible for some containers, but it is extremely versatile.
6213-
template<typename IteratorType>
6236+
template<typename IteratorType, typename Enable = void>
62146237
class iterator_input_adapter
6238+
{
6239+
public:
6240+
using char_type = char;
6241+
using value_type = typename std::iterator_traits<IteratorType>::value_type;
6242+
6243+
iterator_input_adapter(IteratorType first, IteratorType last)
6244+
: current(std::move(first)), end(std::move(last))
6245+
{}
6246+
6247+
typename std::char_traits<char>::int_type get_character()
6248+
{
6249+
if (JSON_HEDLEY_LIKELY(current != end))
6250+
{
6251+
// Cast to unsigned to avoid EOF and 0xFF having same value
6252+
auto result = static_cast<typename std::make_unsigned<value_type>::type>(*current);
6253+
std::advance(current, 1);
6254+
return result;
6255+
}
6256+
6257+
return std::char_traits<char>::eof();
6258+
}
6259+
6260+
private:
6261+
IteratorType current;
6262+
IteratorType end;
6263+
6264+
template<typename BaseInputAdapter, size_t T>
6265+
friend struct wide_string_input_helper;
6266+
6267+
bool empty() const
6268+
{
6269+
return current == end;
6270+
}
6271+
};
6272+
6273+
template<typename IteratorType>
6274+
class iterator_input_adapter<IteratorType, enable_if_t<is_iterator_of_char<IteratorType>::value>>
62156275
{
62166276
public:
62176277
using char_type = typename std::iterator_traits<IteratorType>::value_type;

0 commit comments

Comments
 (0)