Skip to content

Commit

Permalink
Fix iterator_input_adapter for types not supported by char_traits
Browse files Browse the repository at this point in the history
  • Loading branch information
colbychaskell committed Oct 7, 2023
1 parent edffad0 commit 92372b5
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 2 deletions.
62 changes: 61 additions & 1 deletion include/nlohmann/detail/input/input_adapters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,70 @@ class input_stream_adapter
};
#endif // JSON_NO_IO

template<typename T>
struct has_char_traits : std::false_type {};

template<>
struct has_char_traits<char> : std::true_type {};

template<>
struct has_char_traits<wchar_t> : std::true_type {};

#ifdef JSON_HAS_CPP_20
template<>
struct has_char_traits<char8_t> : std::true_type {};

template<>
struct has_char_traits<char16_t> : std::true_type {};

template<>
struct has_char_traits<char32_t> : std::true_type {};
#endif

template<typename T>
struct is_iterator_of_char : has_char_traits<typename std::iterator_traits<T>::value_type> {};

// General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile.
template<typename IteratorType>
template<typename IteratorType, typename Enable = void>
class iterator_input_adapter
{
public:
using char_type = char;
using value_type = typename std::iterator_traits<IteratorType>::value_type;

iterator_input_adapter(IteratorType first, IteratorType last)
: current(std::move(first)), end(std::move(last))
{}

typename std::char_traits<char>::int_type get_character()
{
if (JSON_HEDLEY_LIKELY(current != end))
{
// Cast to unsigned to avoid EOF and 0xFF having same value
auto result = static_cast<typename std::make_unsigned<value_type>::type>(*current);
std::advance(current, 1);
return static_cast<std::char_traits<char>::int_type>(result);
}

return std::char_traits<char>::eof();
}

private:
IteratorType current;
IteratorType end;

template<typename BaseInputAdapter, size_t T>
friend struct wide_string_input_helper;

bool empty() const
{
return current == end;
}
};

template<typename IteratorType>
class iterator_input_adapter<IteratorType, enable_if_t<is_iterator_of_char<IteratorType>::value>>
{
public:
using char_type = typename std::iterator_traits<IteratorType>::value_type;
Expand Down
62 changes: 61 additions & 1 deletion single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6208,10 +6208,70 @@ class input_stream_adapter
};
#endif // JSON_NO_IO

template<typename T>
struct has_char_traits : std::false_type {};

template<>
struct has_char_traits<char> : std::true_type {};

template<>
struct has_char_traits<wchar_t> : std::true_type {};

#ifdef JSON_HAS_CPP_20
template<>
struct has_char_traits<char8_t> : std::true_type {};

template<>
struct has_char_traits<char16_t> : std::true_type {};

template<>
struct has_char_traits<char32_t> : std::true_type {};
#endif

template<typename T>
struct is_iterator_of_char : has_char_traits<typename std::iterator_traits<T>::value_type> {};

// General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile.
template<typename IteratorType>
template<typename IteratorType, typename Enable = void>
class iterator_input_adapter
{
public:
using char_type = char;
using value_type = typename std::iterator_traits<IteratorType>::value_type;

iterator_input_adapter(IteratorType first, IteratorType last)
: current(std::move(first)), end(std::move(last))
{}

typename std::char_traits<char>::int_type get_character()
{
if (JSON_HEDLEY_LIKELY(current != end))
{
// Cast to unsigned to avoid EOF and 0xFF having same value
auto result = static_cast<typename std::make_unsigned<value_type>::type>(*current);
std::advance(current, 1);
return static_cast<std::char_traits<char>::int_type>(result);
}

return std::char_traits<char>::eof();
}

private:
IteratorType current;
IteratorType end;

template<typename BaseInputAdapter, size_t T>
friend struct wide_string_input_helper;

bool empty() const
{
return current == end;
}
};

template<typename IteratorType>
class iterator_input_adapter<IteratorType, enable_if_t<is_iterator_of_char<IteratorType>::value>>
{
public:
using char_type = typename std::iterator_traits<IteratorType>::value_type;
Expand Down

0 comments on commit 92372b5

Please sign in to comment.