diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index c6299aa0b..00a342dbc 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -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::value&& + enable_if_t < std::numeric_limits::is_specialized&& !std::is_same::value, int > = 0 > void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index b33d726b4..20cee3f7d 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -49,7 +49,7 @@ struct external_constructor { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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(); } diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 72e995108..84e7cd814 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -1258,7 +1258,7 @@ scan_number_done: if (errno == 0) { value_unsigned = static_cast(x); - if (value_unsigned == x) + if (static_cast(value_unsigned) == x) { return token_type::value_unsigned; } @@ -1274,7 +1274,7 @@ scan_number_done: if (errno == 0) { value_integer = static_cast(x); - if (value_integer == x) + if (static_cast(value_integer) == x) { return token_type::value_integer; } diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index cfc7e5ad3..7758e6aba 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -441,8 +441,8 @@ struct is_compatible_integer_type_impl : std::false_type {}; template struct is_compatible_integer_type_impl < RealIntegerType, CompatibleNumberIntegerType, - enable_if_t < std::is_integral::value&& - std::is_integral::value&& + enable_if_t < std::numeric_limits::is_integer&& + std::numeric_limits::is_integer&& !std::is_same::value >> { // is there an assert somewhere on overflows? diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 500fc55ec..758fbd5f0 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -684,13 +684,13 @@ class serializer } // templates to avoid warnings about useless casts - template ::value, int> = 0> + template ::is_signed, int> = 0> bool is_negative_number(NumberType x) { - return x < 0; + return x < NumberType(0); } - template < typename NumberType, enable_if_t ::value, int > = 0 > + template < typename NumberType, enable_if_t < !std::numeric_limits::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::value || + std::numeric_limits::is_integer || std::is_same::value || std::is_same::value || std::is_same::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((abs_value % 100)); - abs_value /= 100; + const auto digits_index = static_cast((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(abs_value); *(--buffer_ptr) = digits_to_99[digits_index][1]; diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 6a2a84606..a450f544e 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -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(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::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) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a7c12a3e1..745e0f2f6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3837,8 +3837,8 @@ struct is_compatible_integer_type_impl : std::false_type {}; template struct is_compatible_integer_type_impl < RealIntegerType, CompatibleNumberIntegerType, - enable_if_t < std::is_integral::value&& - std::is_integral::value&& + enable_if_t < std::numeric_limits::is_integer&& + std::numeric_limits::is_integer&& !std::is_same::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::value&& + enable_if_t < std::numeric_limits::is_specialized&& !std::is_same::value, int > = 0 > void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) @@ -5355,7 +5355,7 @@ struct external_constructor { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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(x); - if (value_unsigned == x) + if (static_cast(value_unsigned) == x) { return token_type::value_unsigned; } @@ -8575,7 +8575,7 @@ scan_number_done: if (errno == 0) { value_integer = static_cast(x); - if (value_integer == x) + if (static_cast(value_integer) == x) { return token_type::value_integer; } @@ -18568,13 +18568,13 @@ class serializer } // templates to avoid warnings about useless casts - template ::value, int> = 0> + template ::is_signed, int> = 0> bool is_negative_number(NumberType x) { - return x < 0; + return x < NumberType(0); } - template < typename NumberType, enable_if_t ::value, int > = 0 > + template < typename NumberType, enable_if_t < !std::numeric_limits::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::value || + std::numeric_limits::is_integer || std::is_same::value || std::is_same::value || std::is_same::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((abs_value % 100)); - abs_value /= 100; + const auto digits_index = static_cast((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(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(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::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) diff --git a/tests/src/unit-custom-integer.cpp b/tests/src/unit-custom-integer.cpp new file mode 100644 index 000000000..18184fc4c --- /dev/null +++ b/tests/src/unit-custom-integer.cpp @@ -0,0 +1,114 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.10.5 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2022 Niels Lohmann . + +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 +using nlohmann::json; + +/// A `int +template +class heap_int +{ + public: + std::unique_ptr val; + operator T() const + { + return val == nullptr ? 0 : *val; + } + // operator double() const { return static_cast(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(other))) {} + + heap_int& operator=(const heap_int& other) + { + val = std::unique_ptr(new T(static_cast(other))); + return *this; + } + + bool operator==(const heap_int& other) const + { + return static_cast(*this) == static_cast(other); + } + bool operator<(const int& other) const + { + return static_cast(*this) < other; + } + heap_int operator+(const heap_int& other) const + { + return static_cast(*this) + static_cast(other); + } + bool operator%(const heap_int& other) const + { + return static_cast(*this) % static_cast(other.val); + } + heap_int& operator/=(const heap_int& other) + { + if (val != nullptr) + { + *val /= static_cast(other.val); + } + return *this; + } + bool operator<(const heap_int& other) const + { + return static_cast(*this) < static_cast(other.val); + } + bool operator<=(const heap_int& other) const + { + return static_cast(*this) <= static_cast(other.val); + } + + friend void swap(heap_int& self, heap_int& other) + { + swap(self.val, other.val); + } +}; + +template class std::numeric_limits> +{ + public: + static constexpr bool is_signed = std::numeric_limits::is_signed; + static constexpr bool is_integer = std::numeric_limits::is_integer; + static constexpr bool is_specialized = std::numeric_limits::is_specialized; +}; + +TEST_CASE("custom integer type") +{ + using json = nlohmann::basic_json < + std::map, std::vector, std::string, bool, heap_int, 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 i = as_json[2]; + heap_int three = 3; + CHECK(i == three); +}