Compare commits

...

14 Commits

Author SHA1 Message Date
Niels Lohmann
c13ecd5344
💚 add trait for 128 bit integers 2020-07-13 14:03:04 +02:00
Niels Lohmann
0f1f5052bf
💚 add trait for 128 bit integers 2020-07-13 13:46:56 +02:00
Niels Lohmann
e3aace6dac
🔊 add test for type traits 2020-07-13 13:23:36 +02:00
Niels Lohmann
039c97694d
🔥 remove failing test 2020-07-13 12:51:39 +02:00
Niels Lohmann
23496a3abf
🔊 add test for type traits 2020-07-13 12:44:34 +02:00
Niels Lohmann
bffa18b46e
♻️ replace alternative operator 2020-07-12 17:44:39 +02:00
Niels Lohmann
de4933e093
🎨 fix format 2020-07-12 17:39:36 +02:00
Niels Lohmann
aba37d001e
Merge branch 'develop' of https://github.com/nlohmann/json into issue2228 2020-07-12 17:39:13 +02:00
Niels Lohmann
b6d0a4ab30
Merge branch 'develop' of https://github.com/nlohmann/json into issue2228 2020-07-10 12:46:43 +02:00
Niels Lohmann
2c231f9567
💚 remove failing test 2020-07-10 12:46:31 +02:00
Niels Lohmann
7fbcae2679
🚨 fix a warning 2020-07-09 22:17:59 +02:00
Niels Lohmann
3aa4c0b827
add tests for number types 2020-07-09 22:07:07 +02:00
Niels Lohmann
612f326052
♻️ add proper SFINAE for 64 bit check 2020-07-09 21:31:01 +02:00
Niels Lohmann
0c4e6aa2cd
♻️ move integer conversion out of scan_number 2020-07-09 14:21:39 +02:00
7 changed files with 304 additions and 9 deletions

View File

@ -468,7 +468,7 @@ cppcheck:
clang_analyze:
rm -fr clang_analyze_build
mkdir clang_analyze_build
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On -DJSON_MultipleHeaders=On
cd clang_analyze_build ; \
$(COMPILER_DIR)/scan-build \
-enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \
@ -490,7 +490,7 @@ clang_tidy:
pvs_studio:
rm -fr pvs_studio_build
mkdir pvs_studio_build
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DJSON_MultipleHeaders=On
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10
cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open pvs_studio_build/pvs/index.html
@ -499,7 +499,7 @@ pvs_studio:
infer:
rm -fr infer_build
mkdir infer_build
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4
cd infer_build ; infer compile -- cmake .. -DJSON_MultipleHeaders=On ; infer run -- make -j 4
# call OCLint <http://oclint.org> static analyzer
oclint:

View File

@ -34,7 +34,7 @@ void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
// overloads for basic_json template parameters
template < typename BasicJsonType, typename ArithmeticType,
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
enable_if_t < (std::is_arithmetic<ArithmeticType>::value || is_128_bit_integral<ArithmeticType>::value)&&
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 >
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)

View File

@ -13,6 +13,7 @@
#include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/position_t.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
namespace nlohmann
{
@ -918,6 +919,68 @@ class lexer : public lexer_base<BasicJsonType>
f = std::strtold(str, endptr);
}
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);
}
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' && * p <= '9')
{
val = (10U * val) + static_cast<number_unsigned_t>((*p - '0'));
p++;
}
if (str_end != nullptr)
{
*str_end = const_cast<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 = const_cast<char*>(p);
}
return val;
}
/*!
@brief scan a number literal
@ -1242,7 +1305,7 @@ scan_number_done:
// try to parse integers first and fall back to floats
if (number_type == token_type::value_unsigned)
{
const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
const auto x = strtoull(token_buffer.data(), &endptr, is_64_bit<number_unsigned_t>());
// we checked the number format before
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
@ -1258,7 +1321,7 @@ scan_number_done:
}
else if (number_type == token_type::value_integer)
{
const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
const auto x = strtoll(token_buffer.data(), &endptr, is_64_bit<number_integer_t>());
// we checked the number format before
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());

View File

@ -327,6 +327,16 @@ template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type
: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
// true for types with up to 64 bit
template<typename NumberType>
struct is_64_bit : std::integral_constant < bool, (sizeof(NumberType) <= 8) >
{};
// true for types with at least 64 bit that con be convert from 64 bit integers
template<typename NumberType>
struct is_128_bit_integral : std::integral_constant < bool, (((std::is_signed<NumberType>::value&& std::is_convertible<std::int64_t, NumberType>::value) || (std::is_unsigned<NumberType>::value&& std::is_convertible<std::uint64_t, NumberType>::value))&& !is_64_bit<NumberType>::value) >
{};
template<typename RealIntegerType, typename CompatibleNumberIntegerType,
typename = void>
struct is_compatible_integer_type_impl : std::false_type {};
@ -349,6 +359,16 @@ struct is_compatible_integer_type_impl <
RealLimits::is_signed == CompatibleLimits::is_signed;
};
// second version for 128 bit integers that fail std::is_integral test
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl < RealIntegerType, CompatibleNumberIntegerType,
enable_if_t < std::is_same<RealIntegerType, CompatibleNumberIntegerType>::value&&
!std::is_integral<CompatibleNumberIntegerType>::value&&
is_128_bit_integral<CompatibleNumberIntegerType>::value >>
{
static constexpr auto value = true;
};
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type
: is_compatible_integer_type_impl<RealIntegerType,

View File

@ -3142,6 +3142,14 @@ template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type
: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
template<typename NumberType>
struct is_64_bit : std::integral_constant < bool, (sizeof(NumberType) <= 8) >
{};
template<typename NumberType>
struct is_128_bit_integral : std::integral_constant < bool, (((std::is_signed<NumberType>::value&& std::is_convertible<std::int64_t, NumberType>::value) || (std::is_unsigned<NumberType>::value&& std::is_convertible<std::uint64_t, NumberType>::value))&& !is_64_bit<NumberType>::value) >
{};
template<typename RealIntegerType, typename CompatibleNumberIntegerType,
typename = void>
struct is_compatible_integer_type_impl : std::false_type {};
@ -3164,6 +3172,16 @@ struct is_compatible_integer_type_impl <
RealLimits::is_signed == CompatibleLimits::is_signed;
};
// second version for 128 bit integers that fail std::is_integral test
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl < RealIntegerType, CompatibleNumberIntegerType,
enable_if_t < std::is_same<RealIntegerType, CompatibleNumberIntegerType>::value&&
!std::is_integral<CompatibleNumberIntegerType>::value&&
is_128_bit_integral<CompatibleNumberIntegerType>::value >>
{
static constexpr auto value = true;
};
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type
: is_compatible_integer_type_impl<RealIntegerType,
@ -3300,7 +3318,7 @@ void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
// overloads for basic_json template parameters
template < typename BasicJsonType, typename ArithmeticType,
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
enable_if_t < (std::is_arithmetic<ArithmeticType>::value || is_128_bit_integral<ArithmeticType>::value)&&
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 >
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
@ -8118,6 +8136,8 @@ class binary_reader
// #include <nlohmann/detail/macro_scope.hpp>
// #include <nlohmann/detail/meta/type_traits.hpp>
namespace nlohmann
{
@ -9023,6 +9043,68 @@ class lexer : public lexer_base<BasicJsonType>
f = std::strtold(str, endptr);
}
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);
}
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' && * p <= '9')
{
val = (10U * val) + static_cast<number_unsigned_t>((*p - '0'));
p++;
}
if (str_end != nullptr)
{
*str_end = const_cast<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 = const_cast<char*>(p);
}
return val;
}
/*!
@brief scan a number literal
@ -9347,7 +9429,7 @@ scan_number_done:
// try to parse integers first and fall back to floats
if (number_type == token_type::value_unsigned)
{
const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
const auto x = strtoull(token_buffer.data(), &endptr, is_64_bit<number_unsigned_t>());
// we checked the number format before
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
@ -9363,7 +9445,7 @@ scan_number_done:
}
else if (number_type == token_type::value_integer)
{
const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
const auto x = strtoll(token_buffer.data(), &endptr, is_64_bit<number_integer_t>());
// we checked the number format before
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());

View File

@ -94,6 +94,7 @@ endif()
set(files
src/unit-algorithms.cpp
src/unit-allocator.cpp
src/unit-alt-number.cpp
src/unit-alt-string.cpp
src/unit-assert_macro.cpp
src/unit-bson.cpp

View File

@ -0,0 +1,129 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
TEST_CASE("Alternative number types")
{
SECTION("8 bit integers")
{
using json8 = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int8_t, std::uint8_t>;
SECTION("unsigned")
{
std::uint8_t unsigned_max = 255;
json8 j_unsigned_max = json8::parse("255");
CHECK(j_unsigned_max.is_number_unsigned());
CHECK(j_unsigned_max.dump() == "255");
CHECK((j_unsigned_max.get<std::uint8_t>() == unsigned_max));
CHECK(json8::parse(j_unsigned_max.dump()) == j_unsigned_max);
json8 j_overflow = json8::parse("256");
CHECK(j_overflow.is_number_float());
CHECK(j_overflow.dump() == "256.0");
}
SECTION("signed")
{
std::int8_t signed_min = -128;
json8 j_signed_min = json8::parse("-128");
CHECK(j_signed_min.is_number_integer());
CHECK(j_signed_min.dump() == "-128");
CHECK((j_signed_min.get<std::int8_t>() == signed_min));
CHECK(json8::parse(j_signed_min.dump()) == j_signed_min);
json8 j_underflow = json8::parse("-129");
CHECK(j_underflow.is_number_float());
CHECK(j_underflow.dump() == "-129.0");
}
}
SECTION("16 bit integers")
{
using json16 = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int16_t, std::uint16_t>;
SECTION("unsigned")
{
std::uint16_t unsigned_max = 65535;
json16 j_unsigned_max = json16::parse("65535");
CHECK(j_unsigned_max.is_number_unsigned());
CHECK(j_unsigned_max.dump() == "65535");
CHECK((j_unsigned_max.get<std::uint16_t>() == unsigned_max));
CHECK(json16::parse(j_unsigned_max.dump()) == j_unsigned_max);
json16 j_overflow = json16::parse("65536");
CHECK(j_overflow.is_number_float());
CHECK(j_overflow.dump() == "65536.0");
}
SECTION("signed")
{
std::int16_t signed_min = -32768;
json16 j_signed_min = json16::parse("-32768");
CHECK(j_signed_min.is_number_integer());
CHECK(j_signed_min.dump() == "-32768");
CHECK((j_signed_min.get<std::int16_t>() == signed_min));
CHECK(json16::parse(j_signed_min.dump()) == j_signed_min);
json16 j_underflow = json16::parse("-32769");
CHECK(j_underflow.is_number_float());
CHECK(j_underflow.dump() == "-32769.0");
}
}
// 128-bit arithmetic does not work with sanitizers
#if defined(__SIZEOF_INT128__) && !defined(__SANITIZE_ADDRESS__)
SECTION("128 bit integers")
{
using json128 = nlohmann::basic_json<std::map, std::vector, std::string, bool, __int128_t, __uint128_t>;
SECTION("unsigned")
{
__uint128_t unsigned_max = (340282366920938463463.374607431768211455) * std::pow(10, 18);
json128 j_unsigned_max = json128::parse("340282366920938463463374607431768211455");
CHECK(j_unsigned_max.is_number_unsigned());
CHECK(j_unsigned_max.dump() == "340282366920938463463374607431768211455");
//CHECK((j_unsigned_max.get<__uint128_t>() == unsigned_max));
CHECK(json128::parse(j_unsigned_max.dump()) == j_unsigned_max);
}
SECTION("signed")
{
__int128_t signed_min = (-170141183460469231731.687303715884105728) * std::pow(10, 18);
json128 j_signed_min = json128::parse("-170141183460469231731687303715884105728");
CHECK(j_signed_min.is_number_integer());
CHECK(j_signed_min.dump() == "-170141183460469231731687303715884105728");
CHECK((j_signed_min.get<__int128_t>() == signed_min));
CHECK(json128::parse(j_signed_min.dump()) == j_signed_min);
}
}
#endif
}