Specify char type in JSON. (#8949)

char is defined as signed on x86 but unsigned on arm64

- Use `std::int8_t` instead of char.
- Fix include when clang is pretending to be gcc.
This commit is contained in:
Jiaming Yuan 2023-03-22 19:13:44 +08:00 committed by GitHub
parent 5891f752c8
commit a05799ed39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 50 deletions

View File

@ -1,5 +1,5 @@
/*! /**
* Copyright (c) by Contributors 2019-2022 * Copyright 2019-2023, XGBoost Contributors
*/ */
#ifndef XGBOOST_JSON_IO_H_ #ifndef XGBOOST_JSON_IO_H_
#define XGBOOST_JSON_IO_H_ #define XGBOOST_JSON_IO_H_
@ -17,44 +17,26 @@
#include <vector> #include <vector>
namespace xgboost { namespace xgboost {
namespace detail { /**
// Whether char is signed is undefined, as a result we might or might not need
// static_cast and std::to_string.
template <typename Char, std::enable_if_t<std::is_signed<Char>::value>* = nullptr>
std::string CharToStr(Char c) {
static_assert(std::is_same<Char, char>::value);
return std::string{c};
}
template <typename Char, std::enable_if_t<!std::is_signed<Char>::value>* = nullptr>
std::string CharToStr(Char c) {
static_assert(std::is_same<Char, char>::value);
return (c <= static_cast<char>(127) ? std::string{c} : std::to_string(c));
}
} // namespace detail
/*
* \brief A json reader, currently error checking and utf-8 is not fully supported. * \brief A json reader, currently error checking and utf-8 is not fully supported.
*/ */
class JsonReader { class JsonReader {
public:
using Char = std::int8_t;
protected: protected:
size_t constexpr static kMaxNumLength = size_t constexpr static kMaxNumLength = std::numeric_limits<double>::max_digits10 + 1;
std::numeric_limits<double>::max_digits10 + 1;
struct SourceLocation { struct SourceLocation {
private: private:
size_t pos_ { 0 }; // current position in raw_str_ std::size_t pos_{0}; // current position in raw_str_
public: public:
SourceLocation() = default; SourceLocation() = default;
size_t Pos() const { return pos_; } size_t Pos() const { return pos_; }
void Forward() { void Forward() { pos_++; }
pos_++; void Forward(uint32_t n) { pos_ += n; }
}
void Forward(uint32_t n) {
pos_ += n;
}
} cursor_; } cursor_;
StringView raw_str_; StringView raw_str_;
@ -62,7 +44,7 @@ class JsonReader {
protected: protected:
void SkipSpaces(); void SkipSpaces();
char GetNextChar() { Char GetNextChar() {
if (XGBOOST_EXPECT((cursor_.Pos() == raw_str_.size()), false)) { if (XGBOOST_EXPECT((cursor_.Pos() == raw_str_.size()), false)) {
return -1; return -1;
} }
@ -71,24 +53,24 @@ class JsonReader {
return ch; return ch;
} }
char PeekNextChar() { Char PeekNextChar() {
if (cursor_.Pos() == raw_str_.size()) { if (cursor_.Pos() == raw_str_.size()) {
return -1; return -1;
} }
char ch = raw_str_[cursor_.Pos()]; Char ch = raw_str_[cursor_.Pos()];
return ch; return ch;
} }
/* \brief Skip spaces and consume next character. */ /* \brief Skip spaces and consume next character. */
char GetNextNonSpaceChar() { Char GetNextNonSpaceChar() {
SkipSpaces(); SkipSpaces();
return GetNextChar(); return GetNextChar();
} }
/* \brief Consume next character without first skipping empty space, throw when the next /* \brief Consume next character without first skipping empty space, throw when the next
* character is not the expected one. * character is not the expected one.
*/ */
char GetConsecutiveChar(char expected_char) { Char GetConsecutiveChar(char expected_char) {
char result = GetNextChar(); Char result = GetNextChar();
if (XGBOOST_EXPECT(result != expected_char, false)) { Expect(expected_char, result); } if (XGBOOST_EXPECT(result != expected_char, false)) { Expect(expected_char, result); }
return result; return result;
} }
@ -96,7 +78,7 @@ class JsonReader {
void Error(std::string msg) const; void Error(std::string msg) const;
// Report expected character // Report expected character
void Expect(char c, char got) { void Expect(Char c, Char got) {
std::string msg = "Expecting: \""; std::string msg = "Expecting: \"";
msg += c; msg += c;
msg += "\", got: \""; msg += "\", got: \"";
@ -105,7 +87,7 @@ class JsonReader {
} else if (got == 0) { } else if (got == 0) {
msg += "\\0\""; msg += "\\0\"";
} else { } else {
msg += detail::CharToStr(got) + " \""; msg += std::to_string(got) + " \"";
} }
Error(msg); Error(msg);
} }

View File

@ -14,7 +14,7 @@
// clang with libstdc++ works as well // clang with libstdc++ works as well
#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__sun) && !defined(sun) && \ #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__sun) && !defined(sun) && \
!defined(__APPLE__) && __has_include(<omp.h>) !defined(__APPLE__) && __has_include(<omp.h>) && __has_include(<parallel/algorithm>)
#define GCC_HAS_PARALLEL 1 #define GCC_HAS_PARALLEL 1
#endif // GLIC_VERSION #endif // GLIC_VERSION

View File

@ -333,7 +333,7 @@ size_t constexpr JsonReader::kMaxNumLength;
Json JsonReader::Parse() { Json JsonReader::Parse() {
while (true) { while (true) {
SkipSpaces(); SkipSpaces();
char c = PeekNextChar(); auto c = PeekNextChar();
if (c == -1) { break; } if (c == -1) { break; }
if (c == '{') { if (c == '{') {
@ -408,13 +408,13 @@ void JsonReader::Error(std::string msg) const {
} }
namespace { namespace {
bool IsSpace(char c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t'; } bool IsSpace(JsonReader::Char c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t'; }
} // anonymous namespace } // anonymous namespace
// Json class // Json class
void JsonReader::SkipSpaces() { void JsonReader::SkipSpaces() {
while (cursor_.Pos() < raw_str_.size()) { while (cursor_.Pos() < raw_str_.size()) {
char c = raw_str_[cursor_.Pos()]; Char c = raw_str_[cursor_.Pos()];
if (IsSpace(c)) { if (IsSpace(c)) {
cursor_.Forward(); cursor_.Forward();
} else { } else {
@ -436,12 +436,12 @@ void ParseStr(std::string const& str) {
} }
Json JsonReader::ParseString() { Json JsonReader::ParseString() {
char ch { GetConsecutiveChar('\"') }; // NOLINT Char ch { GetConsecutiveChar('\"') }; // NOLINT
std::string str; std::string str;
while (true) { while (true) {
ch = GetNextChar(); ch = GetNextChar();
if (ch == '\\') { if (ch == '\\') {
char next = static_cast<char>(GetNextChar()); Char next{GetNextChar()};
switch (next) { switch (next) {
case 'r': str += u8"\r"; break; case 'r': str += u8"\r"; break;
case 'n': str += u8"\n"; break; case 'n': str += u8"\n"; break;
@ -466,8 +466,8 @@ Json JsonReader::ParseString() {
} }
Json JsonReader::ParseNull() { Json JsonReader::ParseNull() {
char ch = GetNextNonSpaceChar(); Char ch = GetNextNonSpaceChar();
std::string buffer{ch}; std::string buffer{static_cast<char>(ch)};
for (size_t i = 0; i < 3; ++i) { for (size_t i = 0; i < 3; ++i) {
buffer.push_back(GetNextChar()); buffer.push_back(GetNextChar());
} }
@ -480,7 +480,7 @@ Json JsonReader::ParseNull() {
Json JsonReader::ParseArray() { Json JsonReader::ParseArray() {
std::vector<Json> data; std::vector<Json> data;
char ch { GetConsecutiveChar('[') }; // NOLINT Char ch { GetConsecutiveChar('[') }; // NOLINT
while (true) { while (true) {
if (PeekNextChar() == ']') { if (PeekNextChar() == ']') {
GetConsecutiveChar(']'); GetConsecutiveChar(']');
@ -503,7 +503,7 @@ Json JsonReader::ParseObject() {
Object::Map data; Object::Map data;
SkipSpaces(); SkipSpaces();
char ch = PeekNextChar(); auto ch = PeekNextChar();
if (ch == '}') { if (ch == '}') {
GetConsecutiveChar('}'); GetConsecutiveChar('}');
@ -652,7 +652,7 @@ Json JsonReader::ParseNumber() {
Json JsonReader::ParseBoolean() { Json JsonReader::ParseBoolean() {
bool result = false; bool result = false;
char ch = GetNextNonSpaceChar(); Char ch = GetNextNonSpaceChar();
std::string const t_value = u8"true"; std::string const t_value = u8"true";
std::string const f_value = u8"false"; std::string const f_value = u8"false";
@ -737,7 +737,8 @@ Json UBJReader::ParseArray() {
case 'L': case 'L':
return ParseTypedArray<I64Array>(n); return ParseTypedArray<I64Array>(n);
default: default:
LOG(FATAL) << "`" + std::string{type} + "` is not supported for typed array."; // NOLINT LOG(FATAL) << "`" + std::string{static_cast<char>(type)} + // NOLINT
"` is not supported for typed array.";
} }
} }
std::vector<Json> results; std::vector<Json> results;
@ -794,7 +795,7 @@ Json UBJReader::Load() {
Json UBJReader::Parse() { Json UBJReader::Parse() {
while (true) { while (true) {
char c = PeekNextChar(); auto c = PeekNextChar();
if (c == -1) { if (c == -1) {
break; break;
} }