Implement correct handling of std::streambuf int_type, eof()

o Make no assumptions about eof(), other than that it is somewhere
  outside of the valid range of char_type.
This commit is contained in:
Perry Kundert 2017-10-05 15:37:03 -07:00
parent 184dab60e6
commit 1b43a45bec

View file

@ -1397,7 +1397,7 @@ constexpr T static_const<T>::value;
/// abstract input adapter interface /// abstract input adapter interface
struct input_adapter_protocol struct input_adapter_protocol
{ {
virtual int get_character() = 0; // returns characters in range [0,255], or eof() (a -'ve value) virtual int get_character() = 0; // returns characters in range [0,255], or eof()
virtual void unget_character() = 0; // restore the last non-eof() character to input virtual void unget_character() = 0; // restore the last non-eof() character to input
virtual ~input_adapter_protocol() = default; virtual ~input_adapter_protocol() = default;
}; };
@ -1447,10 +1447,13 @@ class input_stream_adapter : public input_adapter_protocol
} }
} }
// delete because of pointer members
input_stream_adapter(const input_stream_adapter&) = delete;
input_stream_adapter& operator=(input_stream_adapter&) = delete;
int get_character() override int get_character() override
{ {
int c = sb->sbumpc(); // Avoided for performance: int c = is.get(); return reinterpret_cast<int>( sb->sbumpc() );
return c < 0 ? c : ( c & 0xFF ); // faster than == std::char_traits<char>::eof()
} }
void unget_character() override void unget_character() override
@ -1486,10 +1489,10 @@ class input_buffer_adapter : public input_adapter_protocol
{ {
if (JSON_LIKELY(cursor < limit)) if (JSON_LIKELY(cursor < limit))
{ {
return *(cursor++) & 0xFF; return reinterpret_cast<int>(std::char_traits<char>::to_int_type(*(cursor++)));
} }
return std::char_traits<char>::eof(); return reinterpret_cast<int>(std::char_traits<char>::eof());
} }
void unget_character() noexcept override void unget_character() noexcept override
@ -2668,9 +2671,9 @@ scan_number_done:
{ {
++chars_read; ++chars_read;
current = ia->get_character(); current = ia->get_character();
if (JSON_LIKELY(current >= 0)) // faster than: != std::char_traits<char>::eof())) if (JSON_LIKELY( current != std::char_traits<char>::eof()))
{ {
token_string.push_back(static_cast<char>(current)); token_string.push_back(std::char_traits<char>::to_char_type(current));
} }
return current; return current;
} }
@ -2679,7 +2682,7 @@ scan_number_done:
void unget() void unget()
{ {
--chars_read; --chars_read;
if (JSON_LIKELY(current >= 0)) // faster than: != std::char_traits<char>::eof())) if (JSON_LIKELY(current != std::char_traits<char>::eof()))
{ {
ia->unget_character(); ia->unget_character();
assert(token_string.size() != 0); assert(token_string.size() != 0);
@ -2690,7 +2693,7 @@ scan_number_done:
/// add a character to yytext /// add a character to yytext
void add(int c) void add(int c)
{ {
yytext.push_back(static_cast<char>(c)); yytext.push_back(std::char_traits<char>::to_char_type(c));
} }
public: public:
@ -5460,14 +5463,14 @@ class binary_reader
{ {
if (expect_eof) if (expect_eof)
{ {
if (JSON_UNLIKELY(current >= 0 )) // faster than: != std::char_traits<char>::eof())) if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))
{ {
JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); JSON_THROW(parse_error::create(110, chars_read, "expected end of input"));
} }
} }
else else
{ {
if (JSON_UNLIKELY(current < 0)) // faster than: == std::char_traits<char>::eof())) if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
{ {
JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
} }