Add support for workarounds for non-compliant C++11 compilers

This commit is contained in:
Ted Lyngmo 2018-06-14 12:24:00 +02:00
parent e830bc502f
commit 5e0c024b68
13 changed files with 75 additions and 79 deletions

View File

@ -256,7 +256,7 @@ fuzzing-stop:
########################################################################## ##########################################################################
# call cppcheck on the main header file # call cppcheck on the main header file
cppcheck: cppcheck: $(AMALGAMATED_FILE)
cppcheck --enable=warning --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1 cppcheck --enable=warning --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1
# compile and check with Clang Static Analyzer # compile and check with Clang Static Analyzer

View File

@ -4,7 +4,7 @@
"family": "clang", "family": "clang",
"version": "9.0.0 (clang-900.0.39.2)" "version": "9.0.0 (clang-900.0.39.2)"
}, },
"copyright": "(C) 2013-2017 Niels Lohmann", "copyright": "(C) 2013-2018 Niels Lohmann",
"name": "JSON for Modern C++", "name": "JSON for Modern C++",
"platform": "apple", "platform": "apple",
"url": "https://github.com/nlohmann/json", "url": "https://github.com/nlohmann/json",

View File

@ -93,7 +93,7 @@ class binary_reader
get(); get();
} }
if (JSON_UNLIKELY(current != std::char_traits<char>::eof())) if (JSON_UNLIKELY(current != end_of_file))
{ {
return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input")); return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input"));
} }
@ -126,8 +126,7 @@ class binary_reader
{ {
switch (get_char ? get() : current) switch (get_char ? get() : current)
{ {
// EOF case end_of_file:
case std::char_traits<char>::eof():
return unexpect_eof(); return unexpect_eof();
// Integer 0x00..0x17 (0..23) // Integer 0x00..0x17 (0..23)
@ -453,8 +452,7 @@ class binary_reader
{ {
switch (get()) switch (get())
{ {
// EOF case end_of_file:
case std::char_traits<char>::eof():
return unexpect_eof(); return unexpect_eof();
// positive fixint // positive fixint
@ -1420,7 +1418,7 @@ class binary_reader
{ {
switch (prefix) switch (prefix)
{ {
case std::char_traits<char>::eof(): // EOF case end_of_file:
return unexpect_eof(); return unexpect_eof();
case 'T': // true case 'T': // true
@ -1651,7 +1649,7 @@ class binary_reader
*/ */
bool unexpect_eof() const bool unexpect_eof() const
{ {
if (JSON_UNLIKELY(current == std::char_traits<char>::eof())) if (JSON_UNLIKELY(current == end_of_file))
{ {
return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input")); return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input"));
} }
@ -1673,7 +1671,7 @@ class binary_reader
input_adapter_t ia = nullptr; input_adapter_t ia = nullptr;
/// the current character /// the current character
int current = std::char_traits<char>::eof(); int current = end_of_file;
/// the number of characters read /// the number of characters read
std::size_t chars_read = 0; std::size_t chars_read = 0;

View File

@ -105,7 +105,7 @@ class input_buffer_adapter : public input_adapter_protocol
return std::char_traits<char>::to_int_type(*(cursor++)); return std::char_traits<char>::to_int_type(*(cursor++));
} }
return std::char_traits<char>::eof(); return end_of_file;
} }
private: private:
@ -152,7 +152,7 @@ class wide_string_input_adapter : public input_adapter_protocol
if (current_wchar == str.size()) if (current_wchar == str.size())
{ {
utf8_bytes[0] = std::char_traits<char>::eof(); utf8_bytes[0] = end_of_file;
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else else
@ -208,7 +208,7 @@ class wide_string_input_adapter : public input_adapter_protocol
if (current_wchar == str.size()) if (current_wchar == str.size())
{ {
utf8_bytes[0] = std::char_traits<char>::eof(); utf8_bytes[0] = end_of_file;
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else else

View File

@ -235,7 +235,7 @@ class lexer
switch (get()) switch (get())
{ {
// end of file while parsing string // end of file while parsing string
case std::char_traits<char>::eof(): case end_of_file:
{ {
error_message = "invalid string: missing closing quote"; error_message = "invalid string: missing closing quote";
return token_type::parse_error; return token_type::parse_error;
@ -1089,7 +1089,7 @@ scan_number_done:
current = ia->get_character(); current = ia->get_character();
} }
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != end_of_file))
{ {
token_string.push_back(std::char_traits<char>::to_char_type(current)); token_string.push_back(std::char_traits<char>::to_char_type(current));
} }
@ -1108,7 +1108,7 @@ scan_number_done:
{ {
next_unget = true; next_unget = true;
--chars_read; --chars_read;
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != end_of_file))
{ {
assert(token_string.size() != 0); assert(token_string.size() != 0);
token_string.pop_back(); token_string.pop_back();
@ -1285,7 +1285,7 @@ scan_number_done:
// end of input (the null byte is needed when parsing from // end of input (the null byte is needed when parsing from
// string literals) // string literals)
case '\0': case '\0':
case std::char_traits<char>::eof(): case end_of_file:
return token_type::end_of_input; return token_type::end_of_input;
// error // error
@ -1300,7 +1300,7 @@ scan_number_done:
detail::input_adapter_t ia = nullptr; detail::input_adapter_t ia = nullptr;
/// the current character /// the current character
std::char_traits<char>::int_type current = std::char_traits<char>::eof(); std::char_traits<char>::int_type current = end_of_file;
/// whether the next get() call should just return current /// whether the next get() call should just return current
bool next_unget = false; bool next_unget = false;

View File

@ -4,13 +4,15 @@
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
// exclude unsupported compilers // exclude unsupported compilers
#if defined(__clang__) #ifndef NLOHMANN_JSON_SKIP_COMPILER_CHECK
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 #if defined(__clang__)
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
#endif #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) #endif
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#endif #endif
#endif #endif

View File

@ -25,6 +25,8 @@ namespace detail
// helpers // // helpers //
///////////// /////////////
static constexpr std::char_traits<char>::int_type end_of_file = std::char_traits<char>::eof();
template<typename> struct is_basic_json : std::false_type {}; template<typename> struct is_basic_json : std::false_type {};
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION

View File

@ -414,7 +414,7 @@ class serializer
else else
{ {
// we finish reading, but do not accept: string was incomplete // we finish reading, but do not accept: string was incomplete
std::string sn(3,'\0'); std::string sn(3, '\0');
snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back())); snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
} }

View File

@ -316,7 +316,7 @@ class basic_json
{ {
basic_json result; basic_json result;
result["copyright"] = "(C) 2013-2017 Niels Lohmann"; result["copyright"] = "(C) 2013-2018 Niels Lohmann";
result["name"] = "JSON for Modern C++"; result["name"] = "JSON for Modern C++";
result["url"] = "https://github.com/nlohmann/json"; result["url"] = "https://github.com/nlohmann/json";
result["version"]["string"] = result["version"]["string"] =

View File

@ -119,13 +119,15 @@ using json = basic_json<>;
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
// exclude unsupported compilers // exclude unsupported compilers
#if defined(__clang__) #ifndef NLOHMANN_JSON_SKIP_COMPILER_CHECK
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 #if defined(__clang__)
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
#endif #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) #endif
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#endif #endif
#endif #endif
@ -259,6 +261,8 @@ namespace detail
// helpers // // helpers //
///////////// /////////////
static constexpr std::char_traits<char>::int_type end_of_file = std::char_traits<char>::eof();
template<typename> struct is_basic_json : std::false_type {}; template<typename> struct is_basic_json : std::false_type {};
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
@ -1699,7 +1703,7 @@ class input_buffer_adapter : public input_adapter_protocol
return std::char_traits<char>::to_int_type(*(cursor++)); return std::char_traits<char>::to_int_type(*(cursor++));
} }
return std::char_traits<char>::eof(); return end_of_file;
} }
private: private:
@ -1746,7 +1750,7 @@ class wide_string_input_adapter : public input_adapter_protocol
if (current_wchar == str.size()) if (current_wchar == str.size())
{ {
utf8_bytes[0] = std::char_traits<char>::eof(); utf8_bytes[0] = end_of_file;
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else else
@ -1802,7 +1806,7 @@ class wide_string_input_adapter : public input_adapter_protocol
if (current_wchar == str.size()) if (current_wchar == str.size())
{ {
utf8_bytes[0] = std::char_traits<char>::eof(); utf8_bytes[0] = end_of_file;
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else else
@ -1973,10 +1977,8 @@ class input_adapter
#include <clocale> // localeconv #include <clocale> // localeconv
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull #include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <cstdio> // snprintf
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <ios> // hex, uppercase
#include <iomanip> // setw, setfill
#include <sstream> // stringstream
#include <string> // char_traits, string #include <string> // char_traits, string
#include <vector> // vector #include <vector> // vector
@ -2209,7 +2211,7 @@ class lexer
switch (get()) switch (get())
{ {
// end of file while parsing string // end of file while parsing string
case std::char_traits<char>::eof(): case end_of_file:
{ {
error_message = "invalid string: missing closing quote"; error_message = "invalid string: missing closing quote";
return token_type::parse_error; return token_type::parse_error;
@ -3063,7 +3065,7 @@ scan_number_done:
current = ia->get_character(); current = ia->get_character();
} }
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != end_of_file))
{ {
token_string.push_back(std::char_traits<char>::to_char_type(current)); token_string.push_back(std::char_traits<char>::to_char_type(current));
} }
@ -3082,7 +3084,7 @@ scan_number_done:
{ {
next_unget = true; next_unget = true;
--chars_read; --chars_read;
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != end_of_file))
{ {
assert(token_string.size() != 0); assert(token_string.size() != 0);
token_string.pop_back(); token_string.pop_back();
@ -3146,10 +3148,9 @@ scan_number_done:
if ('\x00' <= c and c <= '\x1F') if ('\x00' <= c and c <= '\x1F')
{ {
// escape control characters // escape control characters
std::stringstream ss; char cs[9];
ss << "<U+" << std::setw(4) << std::uppercase << std::setfill('0') snprintf(cs, 9, "<U+%.4X>", c);
<< std::hex << static_cast<int>(c) << ">"; result += cs;
result += ss.str();
} }
else else
{ {
@ -3260,7 +3261,7 @@ scan_number_done:
// end of input (the null byte is needed when parsing from // end of input (the null byte is needed when parsing from
// string literals) // string literals)
case '\0': case '\0':
case std::char_traits<char>::eof(): case end_of_file:
return token_type::end_of_input; return token_type::end_of_input;
// error // error
@ -3275,7 +3276,7 @@ scan_number_done:
detail::input_adapter_t ia = nullptr; detail::input_adapter_t ia = nullptr;
/// the current character /// the current character
std::char_traits<char>::int_type current = std::char_traits<char>::eof(); std::char_traits<char>::int_type current = end_of_file;
/// whether the next get() call should just return current /// whether the next get() call should just return current
bool next_unget = false; bool next_unget = false;
@ -5619,12 +5620,10 @@ class output_adapter
#include <cmath> // ldexp #include <cmath> // ldexp
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <cstdio> // snprintf
#include <cstring> // memcpy #include <cstring> // memcpy
#include <iomanip> // setw, setfill
#include <ios> // hex
#include <iterator> // back_inserter #include <iterator> // back_inserter
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <sstream> // stringstream
#include <string> // char_traits, string #include <string> // char_traits, string
#include <utility> // make_pair, move #include <utility> // make_pair, move
@ -5713,7 +5712,7 @@ class binary_reader
get(); get();
} }
if (JSON_UNLIKELY(current != std::char_traits<char>::eof())) if (JSON_UNLIKELY(current != end_of_file))
{ {
return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input")); return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input"));
} }
@ -5746,8 +5745,7 @@ class binary_reader
{ {
switch (get_char ? get() : current) switch (get_char ? get() : current)
{ {
// EOF case end_of_file:
case std::char_traits<char>::eof():
return unexpect_eof(); return unexpect_eof();
// Integer 0x00..0x17 (0..23) // Integer 0x00..0x17 (0..23)
@ -6073,8 +6071,7 @@ class binary_reader
{ {
switch (get()) switch (get())
{ {
// EOF case end_of_file:
case std::char_traits<char>::eof():
return unexpect_eof(); return unexpect_eof();
// positive fixint // positive fixint
@ -7040,7 +7037,7 @@ class binary_reader
{ {
switch (prefix) switch (prefix)
{ {
case std::char_traits<char>::eof(): // EOF case end_of_file:
return unexpect_eof(); return unexpect_eof();
case 'T': // true case 'T': // true
@ -7271,7 +7268,7 @@ class binary_reader
*/ */
bool unexpect_eof() const bool unexpect_eof() const
{ {
if (JSON_UNLIKELY(current == std::char_traits<char>::eof())) if (JSON_UNLIKELY(current == end_of_file))
{ {
return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input")); return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input"));
} }
@ -7283,9 +7280,9 @@ class binary_reader
*/ */
std::string get_token_string() const std::string get_token_string() const
{ {
std::stringstream ss; char cr[3];
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; snprintf(cr, 3, "%.2X", current);
return ss.str(); return std::string{cr};
} }
private: private:
@ -7293,7 +7290,7 @@ class binary_reader
input_adapter_t ia = nullptr; input_adapter_t ia = nullptr;
/// the current character /// the current character
int current = std::char_traits<char>::eof(); int current = end_of_file;
/// the number of characters read /// the number of characters read
std::size_t chars_read = 0; std::size_t chars_read = 0;
@ -8272,11 +8269,8 @@ class binary_writer
#include <cstddef> // size_t, ptrdiff_t #include <cstddef> // size_t, ptrdiff_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <iomanip> // setfill
#include <iterator> // next
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string #include <string> // string
#include <sstream> // stringstream
#include <type_traits> // is_same #include <type_traits> // is_same
// #include <nlohmann/detail/exceptions.hpp> // #include <nlohmann/detail/exceptions.hpp>
@ -9753,9 +9747,9 @@ class serializer
case UTF8_REJECT: // decode found invalid UTF-8 byte case UTF8_REJECT: // decode found invalid UTF-8 byte
{ {
std::stringstream ss; std::string sn(3, '\0');
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(byte); snprintf(&sn[0], sn.size(), "%.2X", byte);
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
} }
default: // decode found yet incomplete multi-byte code point default: // decode found yet incomplete multi-byte code point
@ -9781,9 +9775,9 @@ class serializer
else else
{ {
// we finish reading, but do not accept: string was incomplete // we finish reading, but do not accept: string was incomplete
std::stringstream ss; std::string sn(3, '\0');
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(static_cast<uint8_t>(s.back())); snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
} }
} }
@ -11060,7 +11054,7 @@ class basic_json
{ {
basic_json result; basic_json result;
result["copyright"] = "(C) 2013-2017 Niels Lohmann"; result["copyright"] = "(C) 2013-2018 Niels Lohmann";
result["name"] = "JSON for Modern C++"; result["name"] = "JSON for Modern C++";
result["url"] = "https://github.com/nlohmann/json"; result["url"] = "https://github.com/nlohmann/json";
result["version"]["string"] = result["version"]["string"] =

View File

@ -1093,9 +1093,9 @@ TEST_CASE("value conversion")
SECTION("superfluous entries") SECTION("superfluous entries")
{ {
json j8 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; json j8 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}};
m2 = j8.get<std::map<int, int>>(); m2 = j8.get<std::map<int, int>>();
CHECK(m == m2); CHECK(m == m2);
} }
} }

View File

@ -317,8 +317,8 @@ TEST_CASE("object inspection")
SECTION("round trips") SECTION("round trips")
{ {
for (const auto& s : for (const auto& s :
{"3.141592653589793", "1000000000000000010E5" {"3.141592653589793", "1000000000000000010E5"
}) })
{ {
json j1 = json::parse(s); json j1 = json::parse(s);
std::string s1 = j1.dump(); std::string s1 = j1.dump();

View File

@ -39,7 +39,7 @@ TEST_CASE("version information")
json j = json::meta(); json j = json::meta();
CHECK(j["name"] == "JSON for Modern C++"); CHECK(j["name"] == "JSON for Modern C++");
CHECK(j["copyright"] == "(C) 2013-2017 Niels Lohmann"); CHECK(j["copyright"] == "(C) 2013-2018 Niels Lohmann");
CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["url"] == "https://github.com/nlohmann/json");
CHECK(j["version"] == json( CHECK(j["version"] == json(
{ {