replace constructor by from/to_json: number_unsigned_t

This commit forces a design change in custom JSONSerializer, which might
be temporary
This commit is contained in:
Théo DELRIEU 2017-01-08 12:44:23 +01:00
parent d257149f36
commit a32de3b528
3 changed files with 73 additions and 128 deletions

View file

@ -248,6 +248,18 @@ struct external_constructor<value_t::number_float>
}
};
template <>
struct external_constructor<value_t::number_unsigned>
{
template <typename Json>
static void construct(Json &j, typename Json::number_unsigned_t val) noexcept
{
j.m_type = value_t::number_unsigned;
j.m_value = val;
j.assert_invariant();
}
};
// very useful construct against boilerplate (more boilerplate needed than in
// C++17: http://en.cppreference.com/w/cpp/types/void_t)
template <typename...> struct make_void
@ -411,9 +423,7 @@ struct is_compatible_basic_json_type
std::is_same<T, BasicJson>::value or
is_compatible_array_type<BasicJson, T>::value or
is_compatible_object_type<typename BasicJson::object_t, T>::value or
is_compatible_integer_type<typename BasicJson::number_integer_t, T>::value or
is_compatible_integer_type<typename BasicJson::number_unsigned_t,
T>::value;
is_compatible_integer_type<typename BasicJson::number_integer_t, T>::value;
};
template <typename T, typename BasicJson, typename PrimitiveIterator>
@ -526,6 +536,17 @@ void to_json(Json &j, CompatibleNumberFloatType val) noexcept
external_constructor<value_t::number_float>::construct(j, val);
}
template <
typename Json, typename CompatibleNumberUnsignedType,
enable_if_t<is_compatible_integer_type<typename Json::number_unsigned_t,
CompatibleNumberUnsignedType>::value,
int> = 0>
void to_json(Json &j, CompatibleNumberUnsignedType val) noexcept
{
external_constructor<value_t::number_unsigned>::construct(j, val);
}
template <typename Json>
void from_json(Json const& j, typename Json::boolean_t& b)
{
@ -548,6 +569,12 @@ void from_json(Json const& j, typename Json::number_float_t& val)
get_arithmetic_value(j, val);
}
template <typename Json>
void from_json(Json const& j, typename Json::number_unsigned_t& val)
{
get_arithmetic_value(j, val);
}
// overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..)
//
// note: Is it really necessary to provide explicit overloads for boolean_t etc..
@ -1897,64 +1924,6 @@ class basic_json
assert_invariant();
}
/*!
@brief create an unsigned integer number (explicit)
Create an unsigned integer number JSON value with a given content.
@tparam T helper type to compare number_unsigned_t and unsigned int (not
visible in) the interface.
@param[in] val an integer to create a JSON number from
@complexity Constant.
@sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
value (unsigned integer) from a compatible number type
@since version 2.0.0
*/
template<typename T, typename std::enable_if<
not (std::is_same<T, int>::value) and
std::is_same<T, number_unsigned_t>::value, int>::type = 0>
basic_json(const number_unsigned_t val) noexcept
: m_type(value_t::number_unsigned), m_value(val)
{
assert_invariant();
}
/*!
@brief create an unsigned number (implicit)
Create an unsigned number JSON value with a given content. This
constructor allows any type @a CompatibleNumberUnsignedType that can be
used to construct values of type @ref number_unsigned_t.
@tparam CompatibleNumberUnsignedType An integer type which is compatible
to @ref number_unsigned_t. Examples may include the types `unsigned int`,
`uint32_t`, or `unsigned short`.
@param[in] val an unsigned integer to create a JSON number from
@complexity Constant.
@sa @ref basic_json(const number_unsigned_t) -- create a number value
(unsigned)
@since version 2.0.0
*/
template <
typename CompatibleNumberUnsignedType,
enable_if_t<detail::is_compatible_integer_type<
number_unsigned_t, CompatibleNumberUnsignedType>::value,
int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val))
{
assert_invariant();
}
/*!
@brief create a container (array or object) from an initializer list

View file

@ -248,6 +248,18 @@ struct external_constructor<value_t::number_float>
}
};
template <>
struct external_constructor<value_t::number_unsigned>
{
template <typename Json>
static void construct(Json &j, typename Json::number_unsigned_t val) noexcept
{
j.m_type = value_t::number_unsigned;
j.m_value = val;
j.assert_invariant();
}
};
// very useful construct against boilerplate (more boilerplate needed than in
// C++17: http://en.cppreference.com/w/cpp/types/void_t)
template <typename...> struct make_void
@ -411,9 +423,7 @@ struct is_compatible_basic_json_type
std::is_same<T, BasicJson>::value or
is_compatible_array_type<BasicJson, T>::value or
is_compatible_object_type<typename BasicJson::object_t, T>::value or
is_compatible_integer_type<typename BasicJson::number_integer_t, T>::value or
is_compatible_integer_type<typename BasicJson::number_unsigned_t,
T>::value;
is_compatible_integer_type<typename BasicJson::number_integer_t, T>::value;
};
template <typename T, typename BasicJson, typename PrimitiveIterator>
@ -526,6 +536,17 @@ void to_json(Json &j, CompatibleNumberFloatType val) noexcept
external_constructor<value_t::number_float>::construct(j, val);
}
template <
typename Json, typename CompatibleNumberUnsignedType,
enable_if_t<is_compatible_integer_type<typename Json::number_unsigned_t,
CompatibleNumberUnsignedType>::value,
int> = 0>
void to_json(Json &j, CompatibleNumberUnsignedType val) noexcept
{
external_constructor<value_t::number_unsigned>::construct(j, val);
}
template <typename Json>
void from_json(Json const& j, typename Json::boolean_t& b)
{
@ -548,6 +569,12 @@ void from_json(Json const& j, typename Json::number_float_t& val)
get_arithmetic_value(j, val);
}
template <typename Json>
void from_json(Json const& j, typename Json::number_unsigned_t& val)
{
get_arithmetic_value(j, val);
}
// overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..)
//
// note: Is it really necessary to provide explicit overloads for boolean_t etc..
@ -1898,64 +1925,6 @@ class basic_json
assert_invariant();
}
/*!
@brief create an unsigned integer number (explicit)
Create an unsigned integer number JSON value with a given content.
@tparam T helper type to compare number_unsigned_t and unsigned int (not
visible in) the interface.
@param[in] val an integer to create a JSON number from
@complexity Constant.
@sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
value (unsigned integer) from a compatible number type
@since version 2.0.0
*/
template<typename T, typename std::enable_if<
not (std::is_same<T, int>::value) and
std::is_same<T, number_unsigned_t>::value, int>::type = 0>
basic_json(const number_unsigned_t val) noexcept
: m_type(value_t::number_unsigned), m_value(val)
{
assert_invariant();
}
/*!
@brief create an unsigned number (implicit)
Create an unsigned number JSON value with a given content. This
constructor allows any type @a CompatibleNumberUnsignedType that can be
used to construct values of type @ref number_unsigned_t.
@tparam CompatibleNumberUnsignedType An integer type which is compatible
to @ref number_unsigned_t. Examples may include the types `unsigned int`,
`uint32_t`, or `unsigned short`.
@param[in] val an unsigned integer to create a JSON number from
@complexity Constant.
@sa @ref basic_json(const number_unsigned_t) -- create a number value
(unsigned)
@since version 2.0.0
*/
template <
typename CompatibleNumberUnsignedType,
enable_if_t<detail::is_compatible_integer_type<
number_unsigned_t, CompatibleNumberUnsignedType>::value,
int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val))
{
assert_invariant();
}
/*!
@brief create a container (array or object) from an initializer list

View file

@ -483,13 +483,20 @@ TEST_CASE("Non-copyable types", "[udt]")
template <typename T, typename = typename std::enable_if<std::is_pod<T>::value>::type>
struct pod_serializer
{
// I could forward-declare this struct, and add a basic_json alias
template <typename Json>
static void from_json(Json const& j , T& t)
{
auto value = j.template get<std::uint64_t>();
auto bytes = static_cast<char*>(static_cast<void*>(&value));
std::memcpy(&t, bytes, sizeof(value));
std::uint64_t value;
// Why cannot we simply use: j.get<std::uint64_t>() ?
// Well, with the current experiment, the get method looks for a from_json function, which we are currently defining!
// This would end up in a stack overflow. Calling nlohmann::from_json is a workaround.
// I shall find a good way to avoid this once all constructors are converted to free methods
//
// In short, constructing a json by constructor calls to_json
// calling get calls from_json, for now, we cannot do this in custom serializers
nlohmann::from_json(j, value);
auto bytes = static_cast<char *>(static_cast<void *>(&value));
std::memcpy(&t, bytes, sizeof(value));
}
template <typename Json>
@ -501,8 +508,8 @@ struct pod_serializer
{
value |= bytes[i] << 8 * i;
}
j = value;
// same thing here
nlohmann::to_json(j, value);
}
};