💄 moved changes to re2c file and ran make pretty

This commit is contained in:
Niels Lohmann 2016-12-18 20:32:09 +01:00 committed by Théo DELRIEU
parent aa2679a8ce
commit be1d3de49b
4 changed files with 6100 additions and 5602 deletions

View file

@ -142,7 +142,10 @@ using is_unscoped_enum =
namespace detail namespace detail
{ {
// Very useful construct against boilerplate (more boilerplate needed than in C++17: http://en.cppreference.com/w/cpp/types/void_t) // 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 { using type = void; }; template <typename...> struct make_void
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type; template <typename... Ts> using void_t = typename make_void<Ts...>::type;
// Implementation of 3 C++17 constructs: conjunction, disjunction, negation. // Implementation of 3 C++17 constructs: conjunction, disjunction, negation.
@ -1831,7 +1834,8 @@ class basic_json
int> = 0 > int> = 0 >
basic_json(const CompatibleNumberIntegerType val) noexcept basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer), : m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) { m_value(static_cast<number_integer_t>(val))
{
assert_invariant(); assert_invariant();
} }
@ -1888,7 +1892,8 @@ class basic_json
int> = 0 > int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned), : m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val)) { m_value(static_cast<number_unsigned_t>(val))
{
assert_invariant(); assert_invariant();
} }
@ -2544,32 +2549,38 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
~basic_json() { ~basic_json()
{
assert_invariant(); assert_invariant();
switch (m_type) { switch (m_type)
case value_t::object: { {
case value_t::object:
{
AllocatorType<object_t> alloc; AllocatorType<object_t> alloc;
alloc.destroy(m_value.object); alloc.destroy(m_value.object);
alloc.deallocate(m_value.object, 1); alloc.deallocate(m_value.object, 1);
break; break;
} }
case value_t::array: { case value_t::array:
{
AllocatorType<array_t> alloc; AllocatorType<array_t> alloc;
alloc.destroy(m_value.array); alloc.destroy(m_value.array);
alloc.deallocate(m_value.array, 1); alloc.deallocate(m_value.array, 1);
break; break;
} }
case value_t::string: { case value_t::string:
{
AllocatorType<string_t> alloc; AllocatorType<string_t> alloc;
alloc.destroy(m_value.string); alloc.destroy(m_value.string);
alloc.deallocate(m_value.string, 1); alloc.deallocate(m_value.string, 1);
break; break;
} }
default: { default:
{
// all other types need no specific destructor // all other types need no specific destructor
break; break;
} }

View file

@ -106,38 +106,356 @@ SOFTWARE.
*/ */
namespace nlohmann namespace nlohmann
{ {
// alias templates to reduce boilerplate
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <typename T>
using remove_cv_t = typename std::remove_cv<T>::type;
template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template <typename T>
using uncvref_t = remove_cv_t<remove_reference_t<T>>;
template <bool If, typename Then, typename Else>
using conditional_t = typename std::conditional<If, Then, Else>::type;
// Taken from http://stackoverflow.com/questions/26936640/how-to-implement-is-enum-class-type-trait
template <typename T>
using is_scoped_enum =
std::integral_constant<bool, not std::is_convertible<T, int>::value and
std::is_enum<T>::value>;
template <typename T>
using is_unscoped_enum =
std::integral_constant<bool, std::is_convertible<T, int>::value and
std::is_enum<T>::value>;
// TODO update this doc
/*! /*!
@brief unnamed namespace with internal helper functions @brief unnamed namespace with internal helper functions
@since version 1.0.0 @since version 1.0.0
*/ */
namespace
namespace detail
{ {
// 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
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type;
// Implementation of 3 C++17 constructs: conjunction, disjunction, negation.
// This is needed to avoid evaluating all the traits in a condition
//
// For example: not std::is_same<void, T>::value and has_value_type<T>::value
// will not compile when T = void (on MSVC at least)
// Whereas conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value
// will stop evaluating if negation<...>::value == false
//
// Please note that those constructs must be used with caution, since symbols can
// become very long quickly (which can slow down compilation and cause MSVC internal compiler errors)
// Only use it when you have too (see example ahead)
template <class...> struct conjunction : std::true_type {};
template <class B1> struct conjunction<B1> : B1 {};
template <class B1, class... Bn>
struct conjunction<B1, Bn...>
: conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
template <class B> struct negation : std::integral_constant < bool, !B::value > {};
template <class...> struct disjunction : std::false_type {};
template <class B1> struct disjunction<B1> : B1 {};
template <class B1, class... Bn>
struct disjunction<B1, Bn...>
: conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
/*! /*!
@brief Helper to determine whether there's a key_type for T. @brief Helper to determine whether there's a key_type for T.
Thus helper is used to tell associative containers apart from other containers Thus helper is used to tell associative containers apart from other containers
such as sequence containers. For instance, `std::map` passes the test as it such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test. contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378 @sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0, overworked in version 2.0.6 @since version 1.0.0, overworked in version 2.0.6
*/ */
template<typename T> #define NLOHMANN_JSON_HAS_HELPER(type) \
struct has_mapped_type template <typename T> struct has_##type { \
private: \
template <typename U, typename = typename U::type> \
static int detect(U &&); \
\
static void detect(...); \
\
public: \
static constexpr bool value = \
std::is_integral<decltype(detect(std::declval<T>()))>::value; \
};
NLOHMANN_JSON_HAS_HELPER(mapped_type)
NLOHMANN_JSON_HAS_HELPER(key_type)
NLOHMANN_JSON_HAS_HELPER(value_type)
NLOHMANN_JSON_HAS_HELPER(iterator)
#undef NLOHMANN_JSON_HAS_HELPER
template <bool B, class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl : std::false_type {};
template <class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
{
static constexpr auto value =
std::is_constructible<typename RealType::key_type,
typename CompatibleObjectType::key_type>::value and
std::is_constructible<typename RealType::mapped_type,
typename CompatibleObjectType::mapped_type>::value;
};
template<class RealType, class CompatibleObjectType>
struct is_compatible_object_type
{
// As noted ahead, we need to stop evaluating traits if CompatibleObjectType = void
// hence the conjunction
static auto constexpr value = is_compatible_object_type_impl <
conjunction<negation<std::is_same<void, CompatibleObjectType>>,
has_mapped_type<CompatibleObjectType>,
has_key_type<CompatibleObjectType>>::value,
RealType, CompatibleObjectType >::value;
};
template <bool B, class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type_impl : std::false_type {};
template <class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type_impl<true, BasicJson, CompatibleArrayType>
{
static constexpr auto value =
not std::is_same<CompatibleArrayType,
typename BasicJson::iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::const_iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::reverse_iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::const_reverse_iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::array_t::iterator>::value and
not std::is_same<CompatibleArrayType,
typename BasicJson::array_t::const_iterator>::value;
};
template <class BasicJson, class CompatibleArrayType>
struct is_compatible_array_type
{
// the check for CompatibleArrayType = void is done in is_compatible_object_type
// but we need the conjunction here as well
static auto constexpr value = is_compatible_array_type_impl <
conjunction<negation<is_compatible_object_type<
typename BasicJson::object_t, CompatibleArrayType>>,
has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value,
BasicJson, CompatibleArrayType >::value;
};
template <bool, typename, typename>
struct is_compatible_integer_type_impl : std::false_type {};
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
{
using RealLimits = std::numeric_limits<RealIntegerType>;
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
static constexpr auto value =
std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and
CompatibleLimits::is_integer and
RealLimits::is_signed == CompatibleLimits::is_signed;
};
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type
{
static constexpr auto value = is_compatible_integer_type_impl <
std::is_arithmetic<CompatibleNumberIntegerType>::value, RealIntegerType,
CompatibleNumberIntegerType >::value;
};
template <typename RealFloat, typename CompatibleFloat>
struct is_compatible_float_type
{
static constexpr auto value =
std::is_constructible<RealFloat, CompatibleFloat>::value and
std::is_floating_point<CompatibleFloat>::value;
};
template <typename T, typename BasicJson>
struct is_compatible_basic_json_type
{
static auto constexpr value =
is_unscoped_enum<T>::value or
std::is_same<T, BasicJson>::value or
std::is_constructible<typename BasicJson::string_t, T>::value or
std::is_same<typename BasicJson::boolean_t, T>::value or
is_compatible_array_type<BasicJson, T>::value or
is_compatible_object_type<typename BasicJson::object_t, T>::value or
is_compatible_float_type<typename BasicJson::number_float_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;
};
template <typename T, typename BasicJson, typename PrimitiveIterator>
struct is_basic_json_nested_class
{
static auto constexpr value = std::is_same<T, typename BasicJson::iterator>::value or
std::is_same<T, typename BasicJson::const_iterator>::value or
std::is_same<T, typename BasicJson::reverse_iterator>::value or
std::is_same<T, typename BasicJson::const_reverse_iterator>::value or
std::is_same<T, PrimitiveIterator>::value or
std::is_same<T, typename BasicJson::json_pointer>::value;
};
// This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists
template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_from_json
{ {
private: private:
template <typename U, typename = typename U::mapped_type> // also check the return type of from_json
template <typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
std::declval<Json>(), std::declval<T&>()))>::value>>
static int detect(U&&); static int detect(U&&);
static void detect(...); static void detect(...);
public: public:
static constexpr bool value = static constexpr bool value = std::is_integral<decltype(
std::is_integral<decltype(detect(std::declval<T>()))>::value; detect(std::declval<JSONSerializer<T, void>>()))>::value;
}; };
} // namespace // This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_non_default_from_json
{
private:
template <typename U, typename = enable_if_t<std::is_same<T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value>>
static int detect(U&&);
static void detect(...);
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
// This trait checks if JSONSerializer<T>::to_json exists
template <template <typename, typename> class JSONSerializer, typename Json,
typename T>
struct has_to_json
{
private:
template <typename U, typename = decltype(uncvref_t<U>::to_json(
std::declval<Json&>(), std::declval<T>()))>
static int detect(U&&);
static void detect(...);
public:
static constexpr bool value = std::is_integral<decltype(
detect(std::declval<JSONSerializer<T, void>>()))>::value;
};
// those declarations are needed to workaround a MSVC bug related to ADL
// (taken from MSVC-Ranges implementation)
void to_json();
void from_json();
struct to_json_fn
{
// is it really useful to mark those as constexpr?
template <typename Json, typename T>
constexpr auto operator()(Json&& j, T&& val) const
noexcept(noexcept(to_json(std::forward<Json>(j), std::forward<T>(val))))
-> decltype(to_json(std::forward<Json>(j), std::forward<T>(val)),
void())
{
return to_json(std::forward<Json>(j), std::forward<T>(val));
}
};
struct from_json_fn
{
template <typename Json, typename T>
constexpr auto operator()(Json&& j, T& val) const
noexcept(noexcept(from_json(std::forward<Json>(j), val)))
-> decltype(from_json(std::forward<Json>(j), val), void())
{
return from_json(std::forward<Json>(j), val);
}
};
/*!
@brief helper class to create locales with decimal point
This struct is used a default locale during the JSON serialization. JSON
requires the decimal point to be `.`, so this function overloads the
`do_decimal_point()` function to return `.`. This function is called by
float-to-string conversions to retrieve the decimal separator between integer
and fractional parts.
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
@since version 2.0.0
*/
struct DecimalSeparator : std::numpunct<char>
{
char do_decimal_point() const
{
return '.';
}
};
}
// taken from ranges-v3
// TODO add doc
template <typename T>
struct static_const
{
static constexpr T value{};
};
template <typename T>
constexpr T static_const<T>::value;
inline namespace
{
constexpr auto const& to_json = static_const<detail::to_json_fn>::value;
constexpr auto const& from_json = static_const<detail::from_json_fn>::value;
}
// default JSONSerializer template argument, doesn't care about template argument
// will use ADL for serialization
template <typename = void, typename = void>
struct adl_serializer
{
template <typename Json, typename T>
static void from_json(Json&& j, T& val)
{
::nlohmann::from_json(std::forward<Json>(j), val);
}
template <typename Json, typename T>
static void to_json(Json& j, T&& val)
{
::nlohmann::to_json(j, std::forward<T>(val));
}
};
/*! /*!
@brief a class to store JSON values @brief a class to store JSON values
@ -226,7 +544,8 @@ template <
class NumberIntegerType = std::int64_t, class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t, class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double, class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer
> >
class basic_json class basic_json
{ {
@ -234,7 +553,8 @@ class basic_json
/// workaround type for MSVC /// workaround type for MSVC
using basic_json_t = basic_json<ObjectType, ArrayType, StringType, using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>; AllocatorType, JSONSerializer>;
class primitive_iterator_t;
public: public:
// forward declarations // forward declarations
@ -1215,11 +1535,11 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<class CompatibleObjectType, typename std::enable_if< template <class CompatibleObjectType,
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and enable_if_t<detail::is_compatible_object_type<
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0> object_t, CompatibleObjectType>::value,
basic_json(const CompatibleObjectType& val) int> = 0>
: m_type(value_t::object) basic_json(const CompatibleObjectType& val) : m_type(value_t::object)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@ -1278,16 +1598,11 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<class CompatibleArrayType, typename std::enable_if< template <class CompatibleArrayType,
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and enable_if_t<detail::is_compatible_array_type<
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and basic_json_t, CompatibleArrayType>::value,
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and int> = 0>
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and basic_json(const CompatibleArrayType& val) : m_type(value_t::array)
not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
basic_json(const CompatibleArrayType& val)
: m_type(value_t::array)
{ {
using std::begin; using std::begin;
using std::end; using std::end;
@ -1295,6 +1610,28 @@ class basic_json
assert_invariant(); assert_invariant();
} }
// constructor chosen when:
// - JSONSerializer::to_json exists for type T
// - T is not a istream, nor convertible to basic_json (float, vectors, etc)
// is_compatible_basic_json_type == not is_user_defined_type
template <
typename T,
enable_if_t<not std::is_base_of<std::istream, uncvref_t<T>>::value and
not detail::is_basic_json_nested_class<uncvref_t<T>, basic_json_t, primitive_iterator_t>::value and
not std::is_same<uncvref_t<T>, typename basic_json_t::array_t::iterator>::value and
not std::is_same<uncvref_t<T>, typename basic_json_t::object_t::iterator>::value and
detail::conjunction<detail::negation<detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>>,
detail::has_to_json<JSONSerializer, basic_json,
uncvref_t<T>>>::value,
int> = 0 >
basic_json(T && val)
{
JSONSerializer<uncvref_t<T>>::to_json(*this, std::forward<T>(val));
}
/*! /*!
@brief create a string (explicit) @brief create a string (explicit)
@ -1456,7 +1793,10 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
basic_json(const int val) noexcept
// Constructor for unscoped enums (not enum classes)
template <typename T, enable_if_t<is_unscoped_enum<T>::value, int> = 0>
basic_json(T val) noexcept
: m_type(value_t::number_integer), : m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) m_value(static_cast<number_integer_t>(val))
{ {
@ -1488,11 +1828,11 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename CompatibleNumberIntegerType, typename std::enable_if< template <
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and typename CompatibleNumberIntegerType,
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and enable_if_t<detail::is_compatible_integer_type<
std::numeric_limits<CompatibleNumberIntegerType>::is_signed, number_integer_t, CompatibleNumberIntegerType>::value,
CompatibleNumberIntegerType>::type = 0> int> = 0 >
basic_json(const CompatibleNumberIntegerType val) noexcept basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer), : m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val)) m_value(static_cast<number_integer_t>(val))
@ -1546,11 +1886,11 @@ class basic_json
@since version 2.0.0 @since version 2.0.0
*/ */
template<typename CompatibleNumberUnsignedType, typename std::enable_if < template <
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and typename CompatibleNumberUnsignedType,
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and enable_if_t<detail::is_compatible_integer_type<
not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed, number_unsigned_t, CompatibleNumberUnsignedType>::value,
CompatibleNumberUnsignedType>::type = 0> int> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned), : m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val)) m_value(static_cast<number_unsigned_t>(val))
@ -1626,9 +1966,10 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename CompatibleNumberFloatType, typename = typename std::enable_if< template <typename CompatibleNumberFloatType,
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and enable_if_t<detail::is_compatible_float_type<
std::is_floating_point<CompatibleNumberFloatType>::value>::type> number_float_t, CompatibleNumberFloatType>::value,
int> = 0>
basic_json(const CompatibleNumberFloatType val) noexcept basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val)) : basic_json(number_float_t(val))
{ {
@ -2182,6 +2523,18 @@ class basic_json
return *this; return *this;
} }
// this overload is needed, since constructor for udt is explicit
template <typename T, enable_if_t<not detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>::value and
detail::has_to_json<JSONSerializer, basic_json_t, uncvref_t<T>>::value>>
reference& operator=(T&& val) noexcept(std::is_nothrow_constructible<basic_json_t, uncvref_t<T>>::value and
std::is_nothrow_move_assignable<uncvref_t<T>>::value)
{
static_assert(sizeof(T) == 0 , "");
// I'm not sure this a is good practice...
return *this = basic_json_t{std::forward<T>(val)};
}
/*! /*!
@brief destructor @brief destructor
@ -2655,7 +3008,6 @@ class basic_json
// value access // // value access //
////////////////// //////////////////
/// get an object (explicit)
template<class T, typename std::enable_if< template<class T, typename std::enable_if<
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0> std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
@ -2681,13 +3033,16 @@ class basic_json
} }
/// get an array (explicit) /// get an array (explicit)
template<class T, typename std::enable_if< template <
class T,
typename std::enable_if <
std::is_convertible<basic_json_t, typename T::value_type>::value and std::is_convertible<basic_json_t, typename T::value_type>::value and
not std::is_same<basic_json_t, typename T::value_type>::value and not std::is_same<basic_json_t,
typename T::value_type>::value and
not std::is_arithmetic<T>::value and not std::is_arithmetic<T>::value and
not std::is_convertible<std::string, T>::value and not std::is_convertible<std::string, T>::value and
not has_mapped_type<T>::value, int>::type = 0> not detail::has_mapped_type<T>::value,
T get_impl(T* /*unused*/) const int >::type = 0 >
{ {
if (is_array()) if (is_array())
{ {
@ -2727,7 +3082,7 @@ class basic_json
/// get an array (explicit) /// get an array (explicit)
template<class T, typename std::enable_if< template<class T, typename std::enable_if<
std::is_same<basic_json, typename T::value_type>::value and std::is_same<basic_json, typename T::value_type>::value and
not has_mapped_type<T>::value, int>::type = 0> not detail::has_mapped_type<T>::value, int>::type = 0>
T get_impl(T* /*unused*/) const T get_impl(T* /*unused*/) const
{ {
if (is_array()) if (is_array())
@ -2956,13 +3311,46 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename ValueType, typename std::enable_if< template <typename ValueType,
not std::is_pointer<ValueType>::value, int>::type = 0> enable_if_t<not std::is_pointer<ValueType>::value, int> = 0>
ValueType get() const auto get() const
-> decltype(this->get_impl(static_cast<ValueType*>(nullptr)))
{ {
return get_impl(static_cast<ValueType*>(nullptr)); return get_impl(static_cast<ValueType*>(nullptr));
} }
template <
typename T,
enable_if_t<detail::conjunction<detail::negation<detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>>,
detail::has_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value,
int> = 0 >
auto get() const -> uncvref_t<T>
{
using type = uncvref_t<T>;
static_assert(std::is_default_constructible<type>::value&&
std::is_copy_constructible<type>::value,
"user-defined types must be DefaultConstructible and "
"CopyConstructible when used with get");
type ret;
JSONSerializer<type>::from_json(*this, ret);
return ret;
}
// This overload is chosen for non-default constructible user-defined-types
template <
typename T,
enable_if_t<detail::conjunction<detail::negation<detail::is_compatible_basic_json_type<
uncvref_t<T>, basic_json_t>>,
detail::has_non_default_from_json<JSONSerializer, basic_json_t,
uncvref_t<T>>>::value,
short> = 0 >
T get() const
{
return JSONSerializer<T>::from_json(*this);
}
/*! /*!
@brief get a pointer value (explicit) @brief get a pointer value (explicit)
@ -8155,6 +8543,11 @@ class basic_json
class primitive_iterator_t class primitive_iterator_t
{ {
public: public:
difference_type get_value() const noexcept
{
return m_it;
}
/// set iterator to a defined beginning /// set iterator to a defined beginning
void set_begin() noexcept void set_begin() noexcept
{ {
@ -8179,16 +8572,87 @@ class basic_json
return (m_it == end_value); return (m_it == end_value);
} }
/// return reference to the value to change and compare friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
operator difference_type& () noexcept
{ {
return m_it; return lhs.m_it == rhs.m_it;
} }
/// return value to compare friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
constexpr operator difference_type () const noexcept
{ {
return m_it; return !(lhs == rhs);
}
friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it < rhs.m_it;
}
friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it <= rhs.m_it;
}
friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it > rhs.m_it;
}
friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it >= rhs.m_it;
}
primitive_iterator_t operator+(difference_type i)
{
auto result = *this;
result += i;
return result;
}
friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
{
return lhs.m_it - rhs.m_it;
}
friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
{
return os << it.m_it;
}
primitive_iterator_t& operator++()
{
++m_it;
return *this;
}
primitive_iterator_t& operator++(int)
{
m_it++;
return *this;
}
primitive_iterator_t& operator--()
{
--m_it;
return *this;
}
primitive_iterator_t& operator--(int)
{
m_it--;
return *this;
}
primitive_iterator_t& operator+=(difference_type n)
{
m_it += n;
return *this;
}
primitive_iterator_t& operator-=(difference_type n)
{
m_it -= n;
return *this;
} }
private: private:
@ -8893,7 +9357,7 @@ class basic_json
default: default:
{ {
if (m_it.primitive_iterator == -n) if (m_it.primitive_iterator.get_value() == -n)
{ {
return *m_object; return *m_object;
} }

View file

@ -187,10 +187,12 @@ namespace udt
void from_json(Json const& j, country& c) void from_json(Json const& j, country& c)
{ {
const auto str = j.template get<std::string>(); const auto str = j.template get<std::string>();
static const std::map<std::string, country> m = { static const std::map<std::string, country> m =
{
{u8"中华人民共和国", country::china}, {u8"中华人民共和国", country::china},
{"France", country::france}, {"France", country::france},
{"Российская Федерация", country::russia}}; {"Российская Федерация", country::russia}
};
const auto it = m.find(str); const auto it = m.find(str);
// TODO test exceptions // TODO test exceptions
@ -227,7 +229,10 @@ TEST_CASE("basic usage", "[udt]")
{ {
// a bit narcissic maybe :) ? // a bit narcissic maybe :) ?
const udt::age a{23}; const udt::age a
{
23
};
const udt::name n{"theo"}; const udt::name n{"theo"};
const udt::country c{udt::country::france}; const udt::country c{udt::country::france};
const udt::person sfinae_addict{a, n, c}; const udt::person sfinae_addict{a, n, c};
@ -295,18 +300,26 @@ struct adl_serializer<std::shared_ptr<T>>
static void to_json(json& j, std::shared_ptr<T> const& opt) static void to_json(json& j, std::shared_ptr<T> const& opt)
{ {
if (opt) if (opt)
{
j = *opt; j = *opt;
}
else else
{
j = nullptr; j = nullptr;
} }
}
static void from_json(json const& j, std::shared_ptr<T>& opt) static void from_json(json const& j, std::shared_ptr<T>& opt)
{ {
if (j.is_null()) if (j.is_null())
{
opt = nullptr; opt = nullptr;
}
else else
{
opt.reset(new T(j.get<T>())); opt.reset(new T(j.get<T>()));
} }
}
}; };
template <> template <>
@ -409,20 +422,28 @@ struct adl_serializer<std::unique_ptr<T>>
static void to_json(json& j, std::unique_ptr<T> const& opt) static void to_json(json& j, std::unique_ptr<T> const& opt)
{ {
if (opt) if (opt)
{
j = *opt; j = *opt;
}
else else
{
j = nullptr; j = nullptr;
} }
}
// this is the overload needed for non-copyable types, // this is the overload needed for non-copyable types,
// should we add a priority tag in the implementation to prefer this overload if it exists? // should we add a priority tag in the implementation to prefer this overload if it exists?
static std::unique_ptr<T> from_json(json const& j) static std::unique_ptr<T> from_json(json const& j)
{ {
if (j.is_null()) if (j.is_null())
{
return nullptr; return nullptr;
}
else else
{
return std::unique_ptr<T>(new T(j.get<T>())); return std::unique_ptr<T>(new T(j.get<T>()));
} }
}
}; };
} }
@ -477,7 +498,9 @@ struct pod_serializer
auto bytes = static_cast<char const*>(static_cast<void const*>(&t)); auto bytes = static_cast<char const*>(static_cast<void const*>(&t));
std::uint64_t value = bytes[0]; std::uint64_t value = bytes[0];
for (auto i = 1; i < 8; ++i) for (auto i = 1; i < 8; ++i)
{
value |= bytes[i] << 8 * i; value |= bytes[i] << 8 * i;
}
j = value; j = value;
} }