From 612f326052a3817402a6ab330803535bbe27f77c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 9 Jul 2020 21:31:01 +0200 Subject: [PATCH] :recycle: add proper SFINAE for 64 bit check --- include/nlohmann/detail/input/lexer.hpp | 68 +++++++++++-- single_include/nlohmann/json.hpp | 128 +++++++++++++++++------- 2 files changed, 150 insertions(+), 46 deletions(-) diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index aad36708d..2f65d647a 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -918,20 +918,72 @@ class lexer : public lexer_base f = std::strtold(str, endptr); } - template < detail::enable_if_t = 0> - JSON_HEDLEY_NON_NULL(2) - auto strtoull(const char* str, char** str_end) -> decltype(std::strtoull(str, str_end, 10)) + template + struct is_64_bit : std::integral_constant < bool, (sizeof(NumberType) <= 8) > + {}; + + JSON_HEDLEY_NON_NULL(2) + unsigned long long strtoull(const char* str, char** str_end, std::true_type) { return std::strtoull(str, str_end, 10); } - template < detail::enable_if_t = 0> - JSON_HEDLEY_NON_NULL(2) - auto strtoll(const char* str, char** str_end) -> decltype(std::strtoll(str, str_end, 10)) + JSON_HEDLEY_NON_NULL(2) + number_unsigned_t strtoull(const char* str, char** str_end, std::false_type) + { + number_unsigned_t val = 0; + const char* p = str; + + while (*p >= '0' and * p <= '9') + { + val = (10 * val) + (*p - '0'); + p++; + } + + if (str_end != nullptr) + { + *str_end = (char*)p; + } + + return val; + } + + JSON_HEDLEY_NON_NULL(2) + long long strtoll(const char* str, char** str_end, std::true_type) { return std::strtoll(str, str_end, 10); } + JSON_HEDLEY_NON_NULL(2) + number_integer_t strtoll(const char* str, char** str_end, std::false_type) + { + number_integer_t val = 0; + const char* p = str; + + if (*p == '-') + { + p++; + } + + while (*p >= '0' and * p <= '9') + { + val = (10 * val) + (*p - '0'); + p++; + } + + if (*str == '-') + { + val = val * -1; + } + + if (str_end != nullptr) + { + *str_end = (char*)p; + } + + return val; + } + /*! @brief scan a number literal @@ -1256,7 +1308,7 @@ scan_number_done: // try to parse integers first and fall back to floats if (number_type == token_type::value_unsigned) { - const auto x = strtoull(token_buffer.data(), &endptr); + const auto x = strtoull(token_buffer.data(), &endptr, is_64_bit()); // we checked the number format before assert(endptr == token_buffer.data() + token_buffer.size()); @@ -1272,7 +1324,7 @@ scan_number_done: } else if (number_type == token_type::value_integer) { - const auto x = strtoll(token_buffer.data(), &endptr); + const auto x = strtoll(token_buffer.data(), &endptr, is_64_bit()); // we checked the number format before assert(endptr == token_buffer.data() + token_buffer.size()); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 01fc8bd5d..8020f4c94 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -9030,20 +9030,72 @@ class lexer : public lexer_base f = std::strtold(str, endptr); } - template < detail::enable_if_t = 0> - JSON_HEDLEY_NON_NULL(2) - auto strtoull(const char* str, char** str_end) -> decltype(std::strtoull(str, str_end, 10)) + template + struct is_64_bit : std::integral_constant < bool, (sizeof(NumberType) <= 8) > + {}; + + JSON_HEDLEY_NON_NULL(2) + unsigned long long strtoull(const char* str, char** str_end, std::true_type) { return std::strtoull(str, str_end, 10); } - template < detail::enable_if_t = 0> - JSON_HEDLEY_NON_NULL(2) - auto strtoll(const char* str, char** str_end) -> decltype(std::strtoll(str, str_end, 10)) + JSON_HEDLEY_NON_NULL(2) + number_unsigned_t strtoull(const char* str, char** str_end, std::false_type) + { + number_unsigned_t val = 0; + const char* p = str; + + while (*p >= '0' and * p <= '9') + { + val = (10 * val) + (*p - '0'); + p++; + } + + if (str_end != nullptr) + { + *str_end = (char*)p; + } + + return val; + } + + JSON_HEDLEY_NON_NULL(2) + long long strtoll(const char* str, char** str_end, std::true_type) { return std::strtoll(str, str_end, 10); } + JSON_HEDLEY_NON_NULL(2) + number_integer_t strtoll(const char* str, char** str_end, std::false_type) + { + number_integer_t val = 0; + const char* p = str; + + if (*p == '-') + { + p++; + } + + while (*p >= '0' and * p <= '9') + { + val = (10 * val) + (*p - '0'); + p++; + } + + if (*str == '-') + { + val = val * -1; + } + + if (str_end != nullptr) + { + *str_end = (char*)p; + } + + return val; + } + /*! @brief scan a number literal @@ -9368,7 +9420,7 @@ scan_number_done: // try to parse integers first and fall back to floats if (number_type == token_type::value_unsigned) { - const auto x = strtoull(token_buffer.data(), &endptr); + const auto x = strtoull(token_buffer.data(), &endptr, is_64_bit()); // we checked the number format before assert(endptr == token_buffer.data() + token_buffer.size()); @@ -9384,7 +9436,7 @@ scan_number_done: } else if (number_type == token_type::value_integer) { - const auto x = strtoll(token_buffer.data(), &endptr); + const auto x = strtoll(token_buffer.data(), &endptr, is_64_bit()); // we checked the number format before assert(endptr == token_buffer.data() + token_buffer.size()); @@ -9800,7 +9852,7 @@ enum class parse_event_t : uint8_t template using parser_callback_t = -std::function; + std::function; /*! @brief syntax analysis @@ -9817,7 +9869,7 @@ class parser using lexer_t = lexer; using token_type = typename lexer_t::token_type; -public: + public: /// a parser reading from an input adapter explicit parser(InputAdapterType&& adapter, const parser_callback_t cb = nullptr, @@ -9927,7 +9979,7 @@ public: return result; } -private: + private: template JSON_HEDLEY_NON_NULL(2) bool sax_parse_internal(SAX* sax) @@ -10246,7 +10298,7 @@ private: return error_msg; } -private: + private: /// callback function const parser_callback_t callback = nullptr; /// the type of the last read token @@ -10469,7 +10521,7 @@ class iter_impl static_assert(is_basic_json::type>::value, "iter_impl only accepts (const) basic_json"); -public: + public: /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. /// The C++ Standard has never required user-defined iterators to derive from std::iterator. @@ -10582,7 +10634,7 @@ public: return *this; } -private: + private: /*! @brief set the iterator to the first value @pre The iterator is initialized; i.e. `m_object != nullptr`. @@ -10650,7 +10702,7 @@ private: } } -public: + public: /*! @brief return a reference to the value pointed to by the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. @@ -11046,7 +11098,7 @@ public: return operator*(); } -private: + private: /// associated JSON instance pointer m_object = nullptr; /// the actual iterator of the associated instance @@ -11093,7 +11145,7 @@ create @ref const_reverse_iterator). template class json_reverse_iterator : public std::reverse_iterator { -public: + public: using difference_type = std::ptrdiff_t; /// shortcut to the reverse iterator adapter using base_iterator = std::reverse_iterator; @@ -11208,7 +11260,7 @@ class json_pointer NLOHMANN_BASIC_JSON_TPL_DECLARATION friend class basic_json; -public: + public: /*! @brief create JSON pointer @@ -11506,7 +11558,7 @@ public: return reference_tokens.empty(); } -private: + private: /*! @param[in] s reference token to be converted into an array index @@ -12177,7 +12229,7 @@ namespace detail template class json_ref { -public: + public: using value_type = BasicJsonType; json_ref(value_type&& value) @@ -12232,7 +12284,7 @@ public: return static_cast(value_ref); } -private: + private: mutable value_type owned_value = nullptr; value_type* value_ref = nullptr; const bool is_rvalue = true; @@ -12295,7 +12347,7 @@ using output_adapter_t = std::shared_ptr>; template class output_vector_adapter : public output_adapter_protocol { -public: + public: explicit output_vector_adapter(std::vector& vec) noexcept : v(vec) {} @@ -12311,7 +12363,7 @@ public: std::copy(s, s + length, std::back_inserter(v)); } -private: + private: std::vector& v; }; @@ -12319,7 +12371,7 @@ private: template class output_stream_adapter : public output_adapter_protocol { -public: + public: explicit output_stream_adapter(std::basic_ostream& s) noexcept : stream(s) {} @@ -12335,7 +12387,7 @@ public: stream.write(s, static_cast(length)); } -private: + private: std::basic_ostream& stream; }; @@ -12343,7 +12395,7 @@ private: template> class output_string_adapter : public output_adapter_protocol { -public: + public: explicit output_string_adapter(StringType& s) noexcept : str(s) {} @@ -12359,14 +12411,14 @@ public: str.append(s, length); } -private: + private: StringType& str; }; template> class output_adapter { -public: + public: output_adapter(std::vector& vec) : oa(std::make_shared>(vec)) {} @@ -12381,7 +12433,7 @@ public: return oa; } -private: + private: output_adapter_t oa = nullptr; }; } // namespace detail @@ -12406,7 +12458,7 @@ class binary_writer using binary_t = typename BasicJsonType::binary_t; using number_float_t = typename BasicJsonType::number_float_t; -public: + public: /*! @brief create a binary writer @@ -13262,7 +13314,7 @@ public: } } -private: + private: ////////// // BSON // ////////// @@ -13891,7 +13943,7 @@ private: } } -public: + public: // The following to_char_type functions are implement the conversion // between uint8_t and CharType. In case CharType is not unsigned, // such a conversion is required to allow values greater than 128. @@ -13932,7 +13984,7 @@ public: return x; } -private: + private: /// whether we can assume little endianess const bool is_little_endian = little_endianess(); @@ -15113,7 +15165,7 @@ class serializer static constexpr std::uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_REJECT = 1; -public: + public: /*! @param[in] s output stream to serialize to @param[in] ichar indentation character to use @@ -15428,7 +15480,7 @@ public: } } -private: + private: /*! @brief dump escaped string @@ -15984,7 +16036,7 @@ private: return static_cast(-(x + 1)) + 1; } -private: + private: /// the output of the serializer output_adapter_t o = nullptr; @@ -16142,7 +16194,7 @@ class basic_json detail::parser_callback_tcb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false - ) + ) { return ::nlohmann::detail::parser(std::move(adapter), std::move(cb), allow_exceptions, ignore_comments); @@ -24678,7 +24730,7 @@ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( is_nothrow_move_constructible::value and is_nothrow_move_assignable::value - ) +) { j1.swap(j2); }