This commit is contained in:
Eric Wieser 2022-08-28 16:30:27 +09:00 committed by GitHub
commit f7d5ba33f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 604 additions and 118 deletions

View File

@ -45,7 +45,7 @@ inline 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::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)

View File

@ -49,7 +49,7 @@ struct external_constructor<value_t::boolean>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::boolean;
j.m_value = b;
new (&j.m_value) typename BasicJsonType::json_value(b);
j.assert_invariant();
}
};
@ -62,7 +62,7 @@ struct external_constructor<value_t::string>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::string;
j.m_value = s;
new (&j.m_value) typename BasicJsonType::json_value(s);
j.assert_invariant();
}
@ -71,7 +71,7 @@ struct external_constructor<value_t::string>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::string;
j.m_value = std::move(s);
new (&j.m_value) typename BasicJsonType::json_value(std::move(s));
j.assert_invariant();
}
@ -95,7 +95,7 @@ struct external_constructor<value_t::binary>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::binary;
j.m_value = typename BasicJsonType::binary_t(b);
new (&j.m_value) typename BasicJsonType::json_value(typename BasicJsonType::binary_t(b));
j.assert_invariant();
}
@ -104,7 +104,7 @@ struct external_constructor<value_t::binary>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::binary;
j.m_value = typename BasicJsonType::binary_t(std::move(b));
new (&j.m_value) typename BasicJsonType::json_value(typename BasicJsonType::binary_t(std::move(b)));
j.assert_invariant();
}
};
@ -117,7 +117,7 @@ struct external_constructor<value_t::number_float>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::number_float;
j.m_value = val;
new (&j.m_value) typename BasicJsonType::json_value(val);
j.assert_invariant();
}
};
@ -130,7 +130,7 @@ struct external_constructor<value_t::number_unsigned>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::number_unsigned;
j.m_value = val;
new (&j.m_value) typename BasicJsonType::json_value(val);
j.assert_invariant();
}
};
@ -143,7 +143,7 @@ struct external_constructor<value_t::number_integer>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::number_integer;
j.m_value = val;
new (&j.m_value) typename BasicJsonType::json_value(val);
j.assert_invariant();
}
};
@ -156,7 +156,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = arr;
new (&j.m_value) typename BasicJsonType::json_value(arr);
j.set_parents();
j.assert_invariant();
}
@ -166,7 +166,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = std::move(arr);
new (&j.m_value) typename BasicJsonType::json_value(std::move(arr));
j.set_parents();
j.assert_invariant();
}
@ -191,7 +191,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = value_t::array;
new (&j.m_value) typename BasicJsonType::json_value(value_t::array);
j.m_value.array->reserve(arr.size());
for (const bool x : arr)
{
@ -207,7 +207,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = value_t::array;
new (&j.m_value) typename BasicJsonType::json_value(value_t::array);
j.m_value.array->resize(arr.size());
if (arr.size() > 0)
{
@ -226,7 +226,7 @@ struct external_constructor<value_t::object>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::object;
j.m_value = obj;
new (&j.m_value) typename BasicJsonType::json_value(obj);
j.set_parents();
j.assert_invariant();
}
@ -236,7 +236,7 @@ struct external_constructor<value_t::object>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::object;
j.m_value = std::move(obj);
new (&j.m_value) typename BasicJsonType:: json_value(std::move(obj));
j.set_parents();
j.assert_invariant();
}

View File

@ -1258,7 +1258,7 @@ scan_number_done:
if (errno == 0)
{
value_unsigned = static_cast<number_unsigned_t>(x);
if (value_unsigned == x)
if (static_cast<long long>(value_unsigned) == x)
{
return token_type::value_unsigned;
}
@ -1274,7 +1274,7 @@ scan_number_done:
if (errno == 0)
{
value_integer = static_cast<number_integer_t>(x);
if (value_integer == x)
if (static_cast<long long>(value_integer) == x)
{
return token_type::value_integer;
}

View File

@ -441,8 +441,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?

View File

@ -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;
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;
@ -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,
@ -730,7 +730,7 @@ class serializer
};
// special case for "0"
if (x == 0)
if (x == NumberType(0))
{
o->write_character('0');
return;
@ -766,15 +766,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];

View File

@ -440,7 +440,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
number_float_t number_float;
/// default constructor (for null values)
json_value() = default;
json_value() {};
/// constructor for booleans
json_value(boolean_t v) noexcept : boolean(v) {}
/// constructor for numbers (integer)
@ -551,6 +551,179 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// constructor for rvalue binary arrays (internal type)
json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
/// User is responsible for calling `destroy` first to make this safe
~json_value() {}
json_value& operator=(json_value&) = delete;
/// Copy from an existing value of type t
json_value(value_t t, const json_value& v)
{
switch (t)
{
case value_t::object:
{
new (this) json_value(v.object);
break;
}
case value_t::array:
{
new (this) json_value(v.array);
break;
}
case value_t::string:
{
new (this) json_value(v.string);
break;
}
case value_t::binary:
{
new (this) json_value(v.binary);
break;
}
case value_t::boolean:
{
new (this) json_value(v.boolean);
break;
}
case value_t::number_integer:
{
new (this) json_value(v.number_integer);
break;
}
case value_t::number_unsigned:
{
new (this) json_value(v.number_unsigned);
break;
}
case value_t::number_float:
{
new (this) json_value(v.number_float);
break;
}
case value_t::discarded:
case value_t::null:
default:
break;
}
}
/// Move from an existing value of type t
json_value(value_t t, json_value&& v)
{
switch (t)
{
case value_t::object:
{
new (this) json_value(std::move(v.object));
break;
}
case value_t::array:
{
new (this) json_value(std::move(v.array));
break;
}
case value_t::string:
{
new (this) json_value(std::move(v.string));
break;
}
case value_t::binary:
{
new (this) json_value(std::move(v.binary));
break;
}
case value_t::boolean:
{
new (this) json_value(std::move(v.boolean));
break;
}
case value_t::number_integer:
{
new (this) json_value(std::move(v.number_integer));
break;
}
case value_t::number_unsigned:
{
new (this) json_value(std::move(v.number_unsigned));
break;
}
case value_t::number_float:
{
new (this) json_value(std::move(v.number_float));
break;
}
case value_t::discarded:
case value_t::null:
default:
break;
}
v.destroy(t);
}
static void swap (value_t& t1, json_value& v1, value_t& t2, json_value& v2)
{
using std::swap;
if (t1 == t2)
{
switch (t1)
{
case value_t::object:
{
swap(v1.object, v2.object);
break;
}
case value_t::array:
{
swap(v1.array, v2.array);
break;
}
case value_t::string:
{
swap(v1.string, v2.string);
break;
}
case value_t::binary:
{
swap(v1.binary, v2.binary);
break;
}
case value_t::boolean:
{
swap(v1.boolean, v2.boolean);
break;
}
case value_t::number_integer:
{
swap(v1.number_integer, v2.number_integer);
break;
}
case value_t::number_unsigned:
{
swap(v1.number_unsigned, v2.number_unsigned);
break;
}
case value_t::number_float:
{
swap(v1.number_float, v2.number_float);
break;
}
case value_t::discarded:
case value_t::null:
default:
break;
}
}
else
{
json_value tmp;
new (&tmp) json_value(t1, std::move(v1));
new (&v1) json_value(t2, std::move(v2));
new (&v2) json_value(t1, std::move(tmp));
swap(t1, t2);
}
}
void destroy(value_t t)
{
if (t == value_t::array || t == value_t::object)
@ -636,11 +809,27 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
break;
}
case value_t::null:
case value_t::boolean:
{
boolean.~boolean_t();
break;
}
case value_t::number_integer:
{
number_integer.~number_integer_t();
break;
}
case value_t::number_unsigned:
{
number_unsigned.~number_unsigned_t();
break;
}
case value_t::number_float:
{
number_float.~number_float_t();
break;
}
case value_t::null:
case value_t::discarded:
default:
{
@ -921,7 +1110,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
// the initializer list is a list of pairs -> create object
m_type = value_t::object;
m_value = value_t::object;
new (&m_value) json_value (value_t::object);
for (auto& element_ref : init)
{
@ -949,7 +1138,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = init;
new (&res.m_value) json_value(init);
return res;
}
@ -960,7 +1149,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = binary_t(init, subtype);
new (&res.m_value) json_value(binary_t(init, subtype));
return res;
}
@ -971,7 +1160,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = std::move(init);
new (&res.m_value) json_value(std::move(init));
return res;
}
@ -982,7 +1171,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = binary_t(std::move(init), subtype);
new (&res.m_value) json_value(binary_t(std::move(init), subtype));
return res;
}
@ -1085,7 +1274,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::string:
{
m_value = *first.m_object->m_value.string;
new (&m_value) json_value(*first.m_object->m_value.string);
break;
}
@ -1105,7 +1294,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::binary:
{
m_value = *first.m_object->m_value.binary;
new (&m_value) json_value(*first.m_object->m_value.binary);
break;
}
@ -1141,49 +1330,50 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
case value_t::object:
{
m_value = *other.m_value.object;
new (&m_value) json_value(*other.m_value.object);
break;
}
case value_t::array:
{
m_value = *other.m_value.array;
new (&m_value) json_value(*other.m_value.array);
break;
}
case value_t::string:
{
m_value = *other.m_value.string;
new (&m_value) json_value(*other.m_value.string);
break;
}
case value_t::boolean:
{
m_value = other.m_value.boolean;
new (&m_value) json_value(other.m_value.boolean);
break;
}
case value_t::number_integer:
{
m_value = other.m_value.number_integer;
new (&m_value) json_value(other.m_value.number_integer);
break;
}
case value_t::number_unsigned:
{
m_value = other.m_value.number_unsigned;
new (&m_value) json_value(other.m_value.number_unsigned);
break;
}
case value_t::number_float:
{
m_value = other.m_value.number_float;
new (&m_value) json_value(other.m_value.number_float);
break;
}
case value_t::binary:
{
m_value = *other.m_value.binary;
new (&m_value) json_value(*other.m_value.binary);
break;
}
@ -1201,14 +1391,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(basic_json&& other) noexcept
: m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
m_value(other.m_type, other.m_value)
{
// check that passed value is valid
other.assert_invariant(false);
// invalidate payload
other.m_type = value_t::null;
other.m_value = {};
set_parents();
assert_invariant();
@ -1226,10 +1415,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// check that passed value is valid
other.assert_invariant();
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
json_value::swap(m_type, m_value, other.m_type, other.m_value);
set_parents();
assert_invariant();
return *this;
@ -3089,7 +3275,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
new (&m_value) json_value(value_t::array);
assert_invariant();
}
@ -3122,7 +3308,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
new (&m_value) json_value(value_t::array);
assert_invariant();
}
@ -3154,7 +3340,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
new (&m_value) json_value(value_t::object);
assert_invariant();
}
@ -3210,7 +3396,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
new (&m_value) json_value(value_t::array);
assert_invariant();
}
@ -3235,7 +3421,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
new (&m_value) json_value(value_t::object);
assert_invariant();
}
@ -3458,8 +3644,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
std::is_nothrow_move_assignable<json_value>::value
)
{
std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value);
json_value::swap(m_type, m_value, other.m_type, other.m_value);
set_parents();
other.set_parents();
@ -4184,7 +4369,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
value_t m_type = value_t::null;
/// the value of the current element
json_value m_value = {};
json_value m_value;
#if JSON_DIAGNOSTICS
/// a pointer to a parent value (for debugging purposes)

View File

@ -3837,8 +3837,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?
@ -4601,7 +4601,7 @@ inline 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::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)
@ -5355,7 +5355,7 @@ struct external_constructor<value_t::boolean>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::boolean;
j.m_value = b;
new (&j.m_value) typename BasicJsonType::json_value(b);
j.assert_invariant();
}
};
@ -5368,7 +5368,7 @@ struct external_constructor<value_t::string>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::string;
j.m_value = s;
new (&j.m_value) typename BasicJsonType::json_value(s);
j.assert_invariant();
}
@ -5377,7 +5377,7 @@ struct external_constructor<value_t::string>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::string;
j.m_value = std::move(s);
new (&j.m_value) typename BasicJsonType::json_value(std::move(s));
j.assert_invariant();
}
@ -5401,7 +5401,7 @@ struct external_constructor<value_t::binary>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::binary;
j.m_value = typename BasicJsonType::binary_t(b);
new (&j.m_value) typename BasicJsonType::json_value(typename BasicJsonType::binary_t(b));
j.assert_invariant();
}
@ -5410,7 +5410,7 @@ struct external_constructor<value_t::binary>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::binary;
j.m_value = typename BasicJsonType::binary_t(std::move(b));
new (&j.m_value) typename BasicJsonType::json_value(typename BasicJsonType::binary_t(std::move(b)));
j.assert_invariant();
}
};
@ -5423,7 +5423,7 @@ struct external_constructor<value_t::number_float>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::number_float;
j.m_value = val;
new (&j.m_value) typename BasicJsonType::json_value(val);
j.assert_invariant();
}
};
@ -5436,7 +5436,7 @@ struct external_constructor<value_t::number_unsigned>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::number_unsigned;
j.m_value = val;
new (&j.m_value) typename BasicJsonType::json_value(val);
j.assert_invariant();
}
};
@ -5449,7 +5449,7 @@ struct external_constructor<value_t::number_integer>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::number_integer;
j.m_value = val;
new (&j.m_value) typename BasicJsonType::json_value(val);
j.assert_invariant();
}
};
@ -5462,7 +5462,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = arr;
new (&j.m_value) typename BasicJsonType::json_value(arr);
j.set_parents();
j.assert_invariant();
}
@ -5472,7 +5472,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = std::move(arr);
new (&j.m_value) typename BasicJsonType::json_value(std::move(arr));
j.set_parents();
j.assert_invariant();
}
@ -5497,7 +5497,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = value_t::array;
new (&j.m_value) typename BasicJsonType::json_value(value_t::array);
j.m_value.array->reserve(arr.size());
for (const bool x : arr)
{
@ -5513,7 +5513,7 @@ struct external_constructor<value_t::array>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::array;
j.m_value = value_t::array;
new (&j.m_value) typename BasicJsonType::json_value(value_t::array);
j.m_value.array->resize(arr.size());
if (arr.size() > 0)
{
@ -5532,7 +5532,7 @@ struct external_constructor<value_t::object>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::object;
j.m_value = obj;
new (&j.m_value) typename BasicJsonType::json_value(obj);
j.set_parents();
j.assert_invariant();
}
@ -5542,7 +5542,7 @@ struct external_constructor<value_t::object>
{
j.m_value.destroy(j.m_type);
j.m_type = value_t::object;
j.m_value = std::move(obj);
new (&j.m_value) typename BasicJsonType:: json_value(std::move(obj));
j.set_parents();
j.assert_invariant();
}
@ -8559,7 +8559,7 @@ scan_number_done:
if (errno == 0)
{
value_unsigned = static_cast<number_unsigned_t>(x);
if (value_unsigned == x)
if (static_cast<long long>(value_unsigned) == x)
{
return token_type::value_unsigned;
}
@ -8575,7 +8575,7 @@ scan_number_done:
if (errno == 0)
{
value_integer = static_cast<number_integer_t>(x);
if (value_integer == x)
if (static_cast<long long>(value_integer) == x)
{
return token_type::value_integer;
}
@ -18568,13 +18568,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;
@ -18590,7 +18590,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,
@ -18614,7 +18614,7 @@ class serializer
};
// special case for "0"
if (x == 0)
if (x == NumberType(0))
{
o->write_character('0');
return;
@ -18650,15 +18650,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];
@ -19618,7 +19619,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
number_float_t number_float;
/// default constructor (for null values)
json_value() = default;
json_value() {};
/// constructor for booleans
json_value(boolean_t v) noexcept : boolean(v) {}
/// constructor for numbers (integer)
@ -19729,6 +19730,179 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// constructor for rvalue binary arrays (internal type)
json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
/// User is responsible for calling `destroy` first to make this safe
~json_value() {}
json_value& operator=(json_value&) = delete;
/// Copy from an existing value of type t
json_value(value_t t, const json_value& v)
{
switch (t)
{
case value_t::object:
{
new (this) json_value(v.object);
break;
}
case value_t::array:
{
new (this) json_value(v.array);
break;
}
case value_t::string:
{
new (this) json_value(v.string);
break;
}
case value_t::binary:
{
new (this) json_value(v.binary);
break;
}
case value_t::boolean:
{
new (this) json_value(v.boolean);
break;
}
case value_t::number_integer:
{
new (this) json_value(v.number_integer);
break;
}
case value_t::number_unsigned:
{
new (this) json_value(v.number_unsigned);
break;
}
case value_t::number_float:
{
new (this) json_value(v.number_float);
break;
}
case value_t::discarded:
case value_t::null:
default:
break;
}
}
/// Move from an existing value of type t
json_value(value_t t, json_value&& v)
{
switch (t)
{
case value_t::object:
{
new (this) json_value(std::move(v.object));
break;
}
case value_t::array:
{
new (this) json_value(std::move(v.array));
break;
}
case value_t::string:
{
new (this) json_value(std::move(v.string));
break;
}
case value_t::binary:
{
new (this) json_value(std::move(v.binary));
break;
}
case value_t::boolean:
{
new (this) json_value(std::move(v.boolean));
break;
}
case value_t::number_integer:
{
new (this) json_value(std::move(v.number_integer));
break;
}
case value_t::number_unsigned:
{
new (this) json_value(std::move(v.number_unsigned));
break;
}
case value_t::number_float:
{
new (this) json_value(std::move(v.number_float));
break;
}
case value_t::discarded:
case value_t::null:
default:
break;
}
v.destroy(t);
}
static void swap (value_t& t1, json_value& v1, value_t& t2, json_value& v2)
{
using std::swap;
if (t1 == t2)
{
switch (t1)
{
case value_t::object:
{
swap(v1.object, v2.object);
break;
}
case value_t::array:
{
swap(v1.array, v2.array);
break;
}
case value_t::string:
{
swap(v1.string, v2.string);
break;
}
case value_t::binary:
{
swap(v1.binary, v2.binary);
break;
}
case value_t::boolean:
{
swap(v1.boolean, v2.boolean);
break;
}
case value_t::number_integer:
{
swap(v1.number_integer, v2.number_integer);
break;
}
case value_t::number_unsigned:
{
swap(v1.number_unsigned, v2.number_unsigned);
break;
}
case value_t::number_float:
{
swap(v1.number_float, v2.number_float);
break;
}
case value_t::discarded:
case value_t::null:
default:
break;
}
}
else
{
json_value tmp;
new (&tmp) json_value(t1, std::move(v1));
new (&v1) json_value(t2, std::move(v2));
new (&v2) json_value(t1, std::move(tmp));
swap(t1, t2);
}
}
void destroy(value_t t)
{
if (t == value_t::array || t == value_t::object)
@ -19814,11 +19988,27 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
break;
}
case value_t::null:
case value_t::boolean:
{
boolean.~boolean_t();
break;
}
case value_t::number_integer:
{
number_integer.~number_integer_t();
break;
}
case value_t::number_unsigned:
{
number_unsigned.~number_unsigned_t();
break;
}
case value_t::number_float:
{
number_float.~number_float_t();
break;
}
case value_t::null:
case value_t::discarded:
default:
{
@ -20099,7 +20289,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
// the initializer list is a list of pairs -> create object
m_type = value_t::object;
m_value = value_t::object;
new (&m_value) json_value (value_t::object);
for (auto& element_ref : init)
{
@ -20127,7 +20317,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = init;
new (&res.m_value) json_value(init);
return res;
}
@ -20138,7 +20328,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = binary_t(init, subtype);
new (&res.m_value) json_value(binary_t(init, subtype));
return res;
}
@ -20149,7 +20339,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = std::move(init);
new (&res.m_value) json_value(std::move(init));
return res;
}
@ -20160,7 +20350,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto res = basic_json();
res.m_type = value_t::binary;
res.m_value = binary_t(std::move(init), subtype);
new (&res.m_value) json_value(binary_t(std::move(init), subtype));
return res;
}
@ -20263,7 +20453,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::string:
{
m_value = *first.m_object->m_value.string;
new (&m_value) json_value(*first.m_object->m_value.string);
break;
}
@ -20283,7 +20473,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
case value_t::binary:
{
m_value = *first.m_object->m_value.binary;
new (&m_value) json_value(*first.m_object->m_value.binary);
break;
}
@ -20319,49 +20509,50 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
case value_t::object:
{
m_value = *other.m_value.object;
new (&m_value) json_value(*other.m_value.object);
break;
}
case value_t::array:
{
m_value = *other.m_value.array;
new (&m_value) json_value(*other.m_value.array);
break;
}
case value_t::string:
{
m_value = *other.m_value.string;
new (&m_value) json_value(*other.m_value.string);
break;
}
case value_t::boolean:
{
m_value = other.m_value.boolean;
new (&m_value) json_value(other.m_value.boolean);
break;
}
case value_t::number_integer:
{
m_value = other.m_value.number_integer;
new (&m_value) json_value(other.m_value.number_integer);
break;
}
case value_t::number_unsigned:
{
m_value = other.m_value.number_unsigned;
new (&m_value) json_value(other.m_value.number_unsigned);
break;
}
case value_t::number_float:
{
m_value = other.m_value.number_float;
new (&m_value) json_value(other.m_value.number_float);
break;
}
case value_t::binary:
{
m_value = *other.m_value.binary;
new (&m_value) json_value(*other.m_value.binary);
break;
}
@ -20379,14 +20570,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(basic_json&& other) noexcept
: m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
m_value(other.m_type, other.m_value)
{
// check that passed value is valid
other.assert_invariant(false);
// invalidate payload
other.m_type = value_t::null;
other.m_value = {};
set_parents();
assert_invariant();
@ -20404,10 +20594,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// check that passed value is valid
other.assert_invariant();
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
json_value::swap(m_type, m_value, other.m_type, other.m_value);
set_parents();
assert_invariant();
return *this;
@ -22267,7 +22454,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
new (&m_value) json_value(value_t::array);
assert_invariant();
}
@ -22300,7 +22487,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
new (&m_value) json_value(value_t::array);
assert_invariant();
}
@ -22332,7 +22519,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
new (&m_value) json_value(value_t::object);
assert_invariant();
}
@ -22388,7 +22575,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
new (&m_value) json_value(value_t::array);
assert_invariant();
}
@ -22413,7 +22600,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
new (&m_value) json_value(value_t::object);
assert_invariant();
}
@ -22636,8 +22823,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
std::is_nothrow_move_assignable<json_value>::value
)
{
std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value);
json_value::swap(m_type, m_value, other.m_type, other.m_value);
set_parents();
other.set_parents();
@ -23362,7 +23548,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
value_t m_type = value_t::null;
/// the value of the current element
json_value m_value = {};
json_value m_value;
#if JSON_DIAGNOSTICS
/// a pointer to a parent value (for debugging purposes)

View File

@ -0,0 +1,114 @@
/*
__ _____ _____ _____
__| | __| | | | 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 `int
template<typename T>
class heap_int
{
public:
std::unique_ptr<T> val;
operator T() const
{
return val == nullptr ? 0 : *val;
}
// operator double() const { return static_cast<T>(val); }
heap_int() : val() {}
heap_int(T val) : val(new T(val)) {}
heap_int(heap_int&&) = default;
heap_int(const heap_int& other) : val(new T(static_cast<T>(other))) {}
heap_int& operator=(const heap_int& other)
{
val = std::unique_ptr<T>(new T(static_cast<T>(other)));
return *this;
}
bool operator==(const heap_int& other) const
{
return static_cast<T>(*this) == static_cast<T>(other);
}
bool operator<(const int& other) const
{
return static_cast<T>(*this) < other;
}
heap_int operator+(const heap_int& other) const
{
return static_cast<T>(*this) + static_cast<T>(other);
}
bool operator%(const heap_int& other) const
{
return static_cast<T>(*this) % static_cast<T>(other.val);
}
heap_int& operator/=(const heap_int& other)
{
if (val != nullptr)
{
*val /= static_cast<T>(other.val);
}
return *this;
}
bool operator<(const heap_int& other) const
{
return static_cast<T>(*this) < static_cast<T>(other.val);
}
bool operator<=(const heap_int& other) const
{
return static_cast<T>(*this) <= static_cast<T>(other.val);
}
friend void swap(heap_int& self, heap_int& other)
{
swap(self.val, other.val);
}
};
template<typename T> class std::numeric_limits<heap_int<T>>
{
public:
static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
static constexpr bool is_specialized = std::numeric_limits<T>::is_specialized;
};
TEST_CASE("custom integer type")
{
using json = nlohmann::basic_json <
std::map, std::vector, std::string, bool, heap_int<std::int64_t>, std::uint64_t, double, std::allocator >;
// create a JSON value with different types
std::string data = "[1,2,3,4]";
json as_json = json::parse(data.begin(), data.end());
heap_int<std::int64_t> i = as_json[2];
heap_int<std::int64_t> three = 3;
CHECK(i == three);
}