Merge 876de47953 into 8215dbafbd
This commit is contained in:
commit
3dcebccc6a
@ -311,6 +311,9 @@ The number types can be changed with template parameters.
|
||||
in case of overflow.
|
||||
- The type for unsigned integers must be convertible from `#!c unsigned long long`. The type for floating-point
|
||||
numbers is used in case of overflow.
|
||||
- Custom `struct`s and `class`es are supported for signed and unsigned integers, providing they are trivially
|
||||
default-constructible, move-constructible, and destructible. This enables extended- but not dynamic-length
|
||||
integers.
|
||||
- The types for signed and unsigned integers must be distinct, see
|
||||
[#2573](https://github.com/nlohmann/json/issues/2573).
|
||||
- Only `#!c double`, `#!c float`, and `#!c long double` are supported for floating-point numbers.
|
||||
|
||||
@ -66,7 +66,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
|
||||
|
||||
// overloads for basic_json template parameters
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
||||
enable_if_t < std::numeric_limits<ArithmeticType>::is_specialized&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
int > = 0 >
|
||||
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
|
||||
@ -1261,7 +1261,7 @@ scan_number_done:
|
||||
if (errno != ERANGE)
|
||||
{
|
||||
value_unsigned = static_cast<number_unsigned_t>(x);
|
||||
if (value_unsigned == x)
|
||||
if (static_cast<decltype(x)>(value_unsigned) == x)
|
||||
{
|
||||
return token_type::value_unsigned;
|
||||
}
|
||||
@ -1277,7 +1277,7 @@ scan_number_done:
|
||||
if (errno != ERANGE)
|
||||
{
|
||||
value_integer = static_cast<number_integer_t>(x);
|
||||
if (value_integer == x)
|
||||
if (static_cast<decltype(x)>(value_integer) == x)
|
||||
{
|
||||
return token_type::value_integer;
|
||||
}
|
||||
|
||||
@ -497,8 +497,8 @@ struct is_compatible_integer_type_impl : std::false_type {};
|
||||
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||
struct is_compatible_integer_type_impl <
|
||||
RealIntegerType, CompatibleNumberIntegerType,
|
||||
enable_if_t < std::is_integral<RealIntegerType>::value&&
|
||||
std::is_integral<CompatibleNumberIntegerType>::value&&
|
||||
enable_if_t < std::numeric_limits<RealIntegerType>::is_integer&&
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_integer&&
|
||||
!std::is_same<bool, CompatibleNumberIntegerType>::value >>
|
||||
{
|
||||
// is there an assert somewhere on overflows?
|
||||
|
||||
@ -684,13 +684,13 @@ class serializer
|
||||
}
|
||||
|
||||
// templates to avoid warnings about useless casts
|
||||
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
||||
template <typename NumberType, enable_if_t<std::numeric_limits<NumberType>::is_signed, int> = 0>
|
||||
bool is_negative_number(NumberType x)
|
||||
{
|
||||
return x < 0;
|
||||
}
|
||||
|
||||
template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
|
||||
template < typename NumberType, enable_if_t < !std::numeric_limits<NumberType>::is_signed, int > = 0 >
|
||||
bool is_negative_number(NumberType /*unused*/)
|
||||
{
|
||||
return false;
|
||||
@ -706,7 +706,7 @@ class serializer
|
||||
@tparam NumberType either @a number_integer_t or @a number_unsigned_t
|
||||
*/
|
||||
template < typename NumberType, detail::enable_if_t <
|
||||
std::is_integral<NumberType>::value ||
|
||||
std::numeric_limits<NumberType>::is_integer ||
|
||||
std::is_same<NumberType, number_unsigned_t>::value ||
|
||||
std::is_same<NumberType, number_integer_t>::value ||
|
||||
std::is_same<NumberType, binary_char_t>::value,
|
||||
|
||||
@ -4032,8 +4032,8 @@ struct is_compatible_integer_type_impl : std::false_type {};
|
||||
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||
struct is_compatible_integer_type_impl <
|
||||
RealIntegerType, CompatibleNumberIntegerType,
|
||||
enable_if_t < std::is_integral<RealIntegerType>::value&&
|
||||
std::is_integral<CompatibleNumberIntegerType>::value&&
|
||||
enable_if_t < std::numeric_limits<RealIntegerType>::is_integer&&
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_integer&&
|
||||
!std::is_same<bool, CompatibleNumberIntegerType>::value >>
|
||||
{
|
||||
// is there an assert somewhere on overflows?
|
||||
@ -4846,7 +4846,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
|
||||
|
||||
// overloads for basic_json template parameters
|
||||
template < typename BasicJsonType, typename ArithmeticType,
|
||||
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
||||
enable_if_t < std::numeric_limits<ArithmeticType>::is_specialized&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
int > = 0 >
|
||||
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
@ -8268,7 +8268,7 @@ scan_number_done:
|
||||
if (errno != ERANGE)
|
||||
{
|
||||
value_unsigned = static_cast<number_unsigned_t>(x);
|
||||
if (value_unsigned == x)
|
||||
if (static_cast<typeof(x)>(value_unsigned) == x)
|
||||
{
|
||||
return token_type::value_unsigned;
|
||||
}
|
||||
@ -8284,7 +8284,7 @@ scan_number_done:
|
||||
if (errno != ERANGE)
|
||||
{
|
||||
value_integer = static_cast<number_integer_t>(x);
|
||||
if (value_integer == x)
|
||||
if (static_cast<typeof(x)>(value_integer) == x)
|
||||
{
|
||||
return token_type::value_integer;
|
||||
}
|
||||
@ -19390,13 +19390,13 @@ class serializer
|
||||
}
|
||||
|
||||
// templates to avoid warnings about useless casts
|
||||
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
||||
template <typename NumberType, enable_if_t<std::numeric_limits<NumberType>::is_signed, int> = 0>
|
||||
bool is_negative_number(NumberType x)
|
||||
{
|
||||
return x < 0;
|
||||
return x < NumberType(0);
|
||||
}
|
||||
|
||||
template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
|
||||
template < typename NumberType, enable_if_t < !std::numeric_limits<NumberType>::is_signed, int > = 0 >
|
||||
bool is_negative_number(NumberType /*unused*/)
|
||||
{
|
||||
return false;
|
||||
@ -19412,7 +19412,7 @@ class serializer
|
||||
@tparam NumberType either @a number_integer_t or @a number_unsigned_t
|
||||
*/
|
||||
template < typename NumberType, detail::enable_if_t <
|
||||
std::is_integral<NumberType>::value ||
|
||||
std::numeric_limits<NumberType>::is_integer ||
|
||||
std::is_same<NumberType, number_unsigned_t>::value ||
|
||||
std::is_same<NumberType, number_integer_t>::value ||
|
||||
std::is_same<NumberType, binary_char_t>::value,
|
||||
@ -19436,7 +19436,7 @@ class serializer
|
||||
};
|
||||
|
||||
// special case for "0"
|
||||
if (x == 0)
|
||||
if (x == NumberType(0))
|
||||
{
|
||||
o->write_character('0');
|
||||
return;
|
||||
@ -19472,15 +19472,16 @@ class serializer
|
||||
|
||||
// Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
|
||||
// See: https://www.youtube.com/watch?v=o4-CwDo2zpg
|
||||
while (abs_value >= 100)
|
||||
const NumberType hundred = 100;
|
||||
while (abs_value >= hundred)
|
||||
{
|
||||
const auto digits_index = static_cast<unsigned>((abs_value % 100));
|
||||
abs_value /= 100;
|
||||
const auto digits_index = static_cast<unsigned>((abs_value % hundred));
|
||||
abs_value /= hundred;
|
||||
*(--buffer_ptr) = digits_to_99[digits_index][1];
|
||||
*(--buffer_ptr) = digits_to_99[digits_index][0];
|
||||
}
|
||||
|
||||
if (abs_value >= 10)
|
||||
if (abs_value >= NumberType(10))
|
||||
{
|
||||
const auto digits_index = static_cast<unsigned>(abs_value);
|
||||
*(--buffer_ptr) = digits_to_99[digits_index][1];
|
||||
|
||||
103
tests/src/unit-custom-integer.cpp
Normal file
103
tests/src/unit-custom-integer.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
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>
|
||||
using nlohmann::json;
|
||||
|
||||
/// A wrapped integer
|
||||
template<typename T>
|
||||
class wrapped_int
|
||||
{
|
||||
T m_val;
|
||||
public:
|
||||
operator T() const
|
||||
{
|
||||
return m_val;
|
||||
}
|
||||
wrapped_int() = default;
|
||||
explicit wrapped_int(T val) : m_val(val) {}
|
||||
|
||||
// allow implicit conversions from any builtin types that `T` allows conversions from
|
||||
template<typename T2,
|
||||
typename = typename std::enable_if<std::is_convertible<T2, T>::value && std::is_arithmetic<T2>::value>::type>
|
||||
wrapped_int(T2 val) : m_val(static_cast<T>(val)) {}
|
||||
|
||||
bool operator==(const wrapped_int& other) const
|
||||
{
|
||||
return static_cast<T>(*this) == static_cast<T>(other);
|
||||
}
|
||||
bool operator<(const int& other) const
|
||||
{
|
||||
return static_cast<T>(*this) < other;
|
||||
}
|
||||
wrapped_int operator+(const wrapped_int& other) const
|
||||
{
|
||||
return static_cast<T>(*this) + static_cast<T>(other);
|
||||
}
|
||||
bool operator%(const wrapped_int& other) const
|
||||
{
|
||||
return static_cast<T>(*this) % static_cast<T>(other);
|
||||
}
|
||||
wrapped_int& operator/=(const wrapped_int& other)
|
||||
{
|
||||
m_val /= static_cast<T>(other);
|
||||
return *this;
|
||||
}
|
||||
bool operator<(const wrapped_int& other) const
|
||||
{
|
||||
return static_cast<T>(*this) < static_cast<T>(other);
|
||||
}
|
||||
bool operator<=(const wrapped_int& other) const
|
||||
{
|
||||
return static_cast<T>(*this) <= static_cast<T>(other);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> class std::numeric_limits<wrapped_int<T>>
|
||||
{
|
||||
public:
|
||||
static constexpr bool is_specialized = std::numeric_limits<T>::is_specialized;
|
||||
static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
|
||||
static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
|
||||
};
|
||||
|
||||
TEST_CASE("custom integer types")
|
||||
{
|
||||
using my_json = nlohmann::basic_json <
|
||||
std::map, std::vector, std::string, bool,
|
||||
wrapped_int<std::int64_t>, wrapped_int<std::uint64_t>, double, std::allocator >;
|
||||
std::string data = "[1,2,-3,-4]";
|
||||
my_json as_json = my_json::parse(data.begin(), data.end());
|
||||
wrapped_int<std::uint64_t> i1 = as_json[1];
|
||||
wrapped_int<std::int64_t> i2 = as_json[2];
|
||||
CHECK(i1 == wrapped_int<std::uint64_t>(2u));
|
||||
CHECK(i2 == wrapped_int<std::int64_t>(-3));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user