Merge branch 'develop' into feature/sax2

This commit is contained in:
Niels Lohmann 2018-03-07 22:26:01 +01:00
commit 303a0c5843
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
11 changed files with 1187 additions and 183 deletions

View file

@ -233,7 +233,7 @@ struct is_compatible_complete_type
{
static constexpr bool value =
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
not std::is_same<BasicJsonType, CompatibleCompleteType>::value and
not is_basic_json<CompatibleCompleteType>::value and
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
};

View file

@ -704,116 +704,126 @@ class binary_writer
oa->write_characters(vec.data(), sizeof(NumberType));
}
template<typename NumberType>
// UBJSON: write number (floating point)
template<typename NumberType, typename std::enable_if<
std::is_floating_point<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
if (std::is_floating_point<NumberType>::value)
if (add_prefix)
{
oa->write_character(static_cast<CharType>('D')); // float64
}
write_number(n);
}
// UBJSON: write number (unsigned integer)
template<typename NumberType, typename std::enable_if<
std::is_unsigned<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('D')); // float64
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(n);
write_number(static_cast<uint8_t>(n));
}
else if (std::is_unsigned<NumberType>::value)
else if (n <= (std::numeric_limits<uint8_t>::max)())
{
if (n <= (std::numeric_limits<int8_t>::max)())
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(static_cast<uint8_t>(n));
oa->write_character(static_cast<CharType>('U')); // uint8
}
else if (n <= (std::numeric_limits<uint8_t>::max)())
write_number(static_cast<uint8_t>(n));
}
else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
{
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
oa->write_character(static_cast<CharType>('I')); // int16
}
else if (n <= (std::numeric_limits<int16_t>::max)())
write_number(static_cast<int16_t>(n));
}
else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
{
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
}
write_number(static_cast<int16_t>(n));
oa->write_character(static_cast<CharType>('l')); // int32
}
else if (n <= (std::numeric_limits<int32_t>::max)())
write_number(static_cast<int32_t>(n));
}
else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
{
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
else if (n <= (std::numeric_limits<int64_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
else
{
if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(static_cast<int8_t>(n));
}
else if ((std::numeric_limits<uint8_t>::min)() <= n and n <= (std::numeric_limits<uint8_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
// LCOV_EXCL_START
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
}
// LCOV_EXCL_STOP
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
}
}
// UBJSON: write number (signed integer)
template<typename NumberType, typename std::enable_if<
std::is_signed<NumberType>::value and
not std::is_floating_point<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(static_cast<int8_t>(n));
}
else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
// LCOV_EXCL_START
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
}
// LCOV_EXCL_STOP
}
/*!
@brief determine the type prefix of container values

View file

@ -1210,6 +1210,7 @@ class basic_json
- @a CompatibleType is not derived from `std::istream`,
- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
constructors),
- @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)
- @a CompatibleType is not a @ref basic_json nested type (e.g.,
@ref json_pointer, @ref iterator, etc ...)
- @ref @ref json_serializer<U> has a
@ -1245,6 +1246,78 @@ class basic_json
assert_invariant();
}
/*!
@brief create a JSON value from an existing one
This is a constructor for existing @ref basic_json types.
It does not hijack copy/move constructors, since the parameter has different
template arguments than the current ones.
The constructor tries to convert the internal @ref m_value of the parameter.
@tparam BasicJsonType a type such that:
- @a BasicJsonType is a @ref basic_json type.
- @a BasicJsonType has different template arguments than @ref basic_json_t.
@param[in] val the @ref basic_json value to be converted.
@complexity Usually linear in the size of the passed @a val, also
depending on the implementation of the called `to_json()`
method.
@exceptionsafety Depends on the called constructor. For types directly
supported by the library (i.e., all types for which no `to_json()` function
was provided), strong guarantee holds: if an exception is thrown, there are
no changes to any JSON value.
@since version 3.1.2
*/
template <typename BasicJsonType,
detail::enable_if_t<
detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>
basic_json(const BasicJsonType& val)
{
using other_boolean_t = typename BasicJsonType::boolean_t;
using other_number_float_t = typename BasicJsonType::number_float_t;
using other_number_integer_t = typename BasicJsonType::number_integer_t;
using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using other_string_t = typename BasicJsonType::string_t;
using other_object_t = typename BasicJsonType::object_t;
using other_array_t = typename BasicJsonType::array_t;
switch (val.type())
{
case value_t::boolean:
JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
break;
case value_t::number_float:
JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
break;
case value_t::number_integer:
JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
break;
case value_t::number_unsigned:
JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
break;
case value_t::string:
JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
break;
case value_t::object:
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
break;
case value_t::array:
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
break;
case value_t::null:
*this = nullptr;
break;
case value_t::discarded:
m_type = value_t::discarded;
break;
}
assert_invariant();
}
/*!
@brief create a container (array or object) from an initializer list
@ -2417,6 +2490,29 @@ class basic_json
return *this;
}
/*!
@brief get special-case overload
This overloads converts the current @ref basic_json in a different
@ref basic_json type
@tparam BasicJsonType == @ref basic_json
@return a copy of *this, converted into @tparam BasicJsonType
@complexity Depending on the implementation of the called `from_json()`
method.
@since version 3.1.2
*/
template<typename BasicJsonType, detail::enable_if_t<
not std::is_same<BasicJsonType, basic_json>::value and
detail::is_basic_json<BasicJsonType>::value, int> = 0>
BasicJsonType get() const
{
return *this;
}
/*!
@brief get a value (explicit)
@ -2458,7 +2554,7 @@ class basic_json
*/
template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
detail::enable_if_t <
not std::is_same<basic_json_t, ValueType>::value and
not detail::is_basic_json<ValueType>::value and
detail::has_from_json<basic_json_t, ValueType>::value and
not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
int> = 0>
@ -2724,7 +2820,8 @@ class basic_json
template < typename ValueType, typename std::enable_if <
not std::is_pointer<ValueType>::value and
not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
not std::is_same<ValueType, typename string_t::value_type>::value
not std::is_same<ValueType, typename string_t::value_type>::value and
not detail::is_basic_json<ValueType>::value
#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#endif

View file

@ -466,7 +466,7 @@ struct is_compatible_complete_type
{
static constexpr bool value =
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
not std::is_same<BasicJsonType, CompatibleCompleteType>::value and
not is_basic_json<CompatibleCompleteType>::value and
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
};
@ -7401,116 +7401,126 @@ class binary_writer
oa->write_characters(vec.data(), sizeof(NumberType));
}
template<typename NumberType>
// UBJSON: write number (floating point)
template<typename NumberType, typename std::enable_if<
std::is_floating_point<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
if (std::is_floating_point<NumberType>::value)
if (add_prefix)
{
oa->write_character(static_cast<CharType>('D')); // float64
}
write_number(n);
}
// UBJSON: write number (unsigned integer)
template<typename NumberType, typename std::enable_if<
std::is_unsigned<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('D')); // float64
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(n);
write_number(static_cast<uint8_t>(n));
}
else if (std::is_unsigned<NumberType>::value)
else if (n <= (std::numeric_limits<uint8_t>::max)())
{
if (n <= (std::numeric_limits<int8_t>::max)())
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(static_cast<uint8_t>(n));
oa->write_character(static_cast<CharType>('U')); // uint8
}
else if (n <= (std::numeric_limits<uint8_t>::max)())
write_number(static_cast<uint8_t>(n));
}
else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
{
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
oa->write_character(static_cast<CharType>('I')); // int16
}
else if (n <= (std::numeric_limits<int16_t>::max)())
write_number(static_cast<int16_t>(n));
}
else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
{
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
}
write_number(static_cast<int16_t>(n));
oa->write_character(static_cast<CharType>('l')); // int32
}
else if (n <= (std::numeric_limits<int32_t>::max)())
write_number(static_cast<int32_t>(n));
}
else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
{
if (add_prefix)
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
else if (n <= (std::numeric_limits<int64_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
else
{
if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(static_cast<int8_t>(n));
}
else if ((std::numeric_limits<uint8_t>::min)() <= n and n <= (std::numeric_limits<uint8_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
// LCOV_EXCL_START
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
}
// LCOV_EXCL_STOP
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
}
}
// UBJSON: write number (signed integer)
template<typename NumberType, typename std::enable_if<
std::is_signed<NumberType>::value and
not std::is_floating_point<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
}
write_number(static_cast<int8_t>(n));
}
else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
// LCOV_EXCL_START
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
}
// LCOV_EXCL_STOP
}
/*!
@brief determine the type prefix of container values
@ -11300,6 +11310,7 @@ class basic_json
- @a CompatibleType is not derived from `std::istream`,
- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
constructors),
- @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)
- @a CompatibleType is not a @ref basic_json nested type (e.g.,
@ref json_pointer, @ref iterator, etc ...)
- @ref @ref json_serializer<U> has a
@ -11335,6 +11346,78 @@ class basic_json
assert_invariant();
}
/*!
@brief create a JSON value from an existing one
This is a constructor for existing @ref basic_json types.
It does not hijack copy/move constructors, since the parameter has different
template arguments than the current ones.
The constructor tries to convert the internal @ref m_value of the parameter.
@tparam BasicJsonType a type such that:
- @a BasicJsonType is a @ref basic_json type.
- @a BasicJsonType has different template arguments than @ref basic_json_t.
@param[in] val the @ref basic_json value to be converted.
@complexity Usually linear in the size of the passed @a val, also
depending on the implementation of the called `to_json()`
method.
@exceptionsafety Depends on the called constructor. For types directly
supported by the library (i.e., all types for which no `to_json()` function
was provided), strong guarantee holds: if an exception is thrown, there are
no changes to any JSON value.
@since version 3.1.2
*/
template <typename BasicJsonType,
detail::enable_if_t<
detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>
basic_json(const BasicJsonType& val)
{
using other_boolean_t = typename BasicJsonType::boolean_t;
using other_number_float_t = typename BasicJsonType::number_float_t;
using other_number_integer_t = typename BasicJsonType::number_integer_t;
using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using other_string_t = typename BasicJsonType::string_t;
using other_object_t = typename BasicJsonType::object_t;
using other_array_t = typename BasicJsonType::array_t;
switch (val.type())
{
case value_t::boolean:
JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
break;
case value_t::number_float:
JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
break;
case value_t::number_integer:
JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
break;
case value_t::number_unsigned:
JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
break;
case value_t::string:
JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
break;
case value_t::object:
JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
break;
case value_t::array:
JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
break;
case value_t::null:
*this = nullptr;
break;
case value_t::discarded:
m_type = value_t::discarded;
break;
}
assert_invariant();
}
/*!
@brief create a container (array or object) from an initializer list
@ -12507,6 +12590,29 @@ class basic_json
return *this;
}
/*!
@brief get special-case overload
This overloads converts the current @ref basic_json in a different
@ref basic_json type
@tparam BasicJsonType == @ref basic_json
@return a copy of *this, converted into @tparam BasicJsonType
@complexity Depending on the implementation of the called `from_json()`
method.
@since version 3.1.2
*/
template<typename BasicJsonType, detail::enable_if_t<
not std::is_same<BasicJsonType, basic_json>::value and
detail::is_basic_json<BasicJsonType>::value, int> = 0>
BasicJsonType get() const
{
return *this;
}
/*!
@brief get a value (explicit)
@ -12548,7 +12654,7 @@ class basic_json
*/
template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
detail::enable_if_t <
not std::is_same<basic_json_t, ValueType>::value and
not detail::is_basic_json<ValueType>::value and
detail::has_from_json<basic_json_t, ValueType>::value and
not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
int> = 0>
@ -12814,7 +12920,8 @@ class basic_json
template < typename ValueType, typename std::enable_if <
not std::is_pointer<ValueType>::value and
not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
not std::is_same<ValueType, typename string_t::value_type>::value
not std::is_same<ValueType, typename string_t::value_type>::value and
not detail::is_basic_json<ValueType>::value
#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#endif

View file

@ -104,6 +104,7 @@ foreach(file ${files})
target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE)
target_include_directories(${testcase} PRIVATE "thirdparty/catch")
target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map")
target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR})
target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME})

View file

@ -4,7 +4,7 @@
# additional flags
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wcast-align -Wcast-qual -Wno-ctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wno-float-equal
CPPFLAGS += -I ../single_include -I . -I thirdparty/catch -DCATCH_CONFIG_FAST_COMPILE
CPPFLAGS += -I ../single_include -I . -I thirdparty/catch -I thirdparty/fifo_map -DCATCH_CONFIG_FAST_COMPILE
SOURCES = src/unit.cpp \
src/unit-algorithms.cpp \

View file

@ -1527,6 +1527,89 @@ TEST_CASE("parser class")
});
CHECK(j_empty_array == json());
}
SECTION("skip in GeoJSON")
{
auto geojsonExample = R"(
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
"properties": {"prop0": "value0"}
},
{ "type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
]
},
"properties": {
"prop0": "value0",
"prop1": 0.0
}
},
{ "type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
[100.0, 1.0], [100.0, 0.0] ]
]
},
"properties": {
"prop0": "value0",
"prop1": {"this": "that"}
}
}
]
})";
json::parser_callback_t cb = [&](int depth, json::parse_event_t event, json & parsed)
{
// skip uninteresting events
if (event == json::parse_event_t::value and !parsed.is_primitive())
{
return false;
}
switch (event)
{
case json::parse_event_t::key:
{
return true;
}
case json::parse_event_t::value:
{
return false;
}
case json::parse_event_t::object_start:
{
return true;
}
case json::parse_event_t::object_end:
{
return false;
}
case json::parse_event_t::array_start:
{
return true;
}
case json::parse_event_t::array_end:
{
return false;
}
default:
{
return true;
}
}
};
auto j = json::parse(geojsonExample, cb, true);
CHECK(j == json());
}
}
SECTION("constructing from contiguous containers")

View file

@ -32,10 +32,72 @@ SOFTWARE.
#include <nlohmann/json.hpp>
using nlohmann::json;
#include "fifo_map.hpp"
#include <fstream>
#include <list>
#include <cstdio>
/////////////////////////////////////////////////////////////////////
// for #972
/////////////////////////////////////////////////////////////////////
template<class K, class V, class dummy_compare, class A>
using my_workaround_fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
using my_json = nlohmann::basic_json<my_workaround_fifo_map>;
/////////////////////////////////////////////////////////////////////
// for #977
/////////////////////////////////////////////////////////////////////
namespace ns
{
struct foo
{
int x;
};
template <typename, typename SFINAE = void>
struct foo_serializer;
template<typename T>
struct foo_serializer<T, typename std::enable_if<std::is_same<foo, T>::value>::type>
{
template <typename BasicJsonType>
static void to_json(BasicJsonType& j, const T& value)
{
j = BasicJsonType{{"x", value.x}};
}
template <typename BasicJsonType>
static void from_json(const BasicJsonType& j, T& value) // !!!
{
nlohmann::from_json(j.at("x"), value.x);
}
};
template<typename T>
struct foo_serializer < T, typename std::enable_if < !std::is_same<foo, T>::value >::type >
{
template <typename BasicJsonType>
static void to_json(BasicJsonType& j, const T& value) noexcept
{
::nlohmann::to_json(j, value);
}
template <typename BasicJsonType>
static void from_json(const BasicJsonType& j, T& value) //!!!
{
::nlohmann::from_json(j, value);
}
};
}
using foo_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t,
std::uint64_t, double, std::allocator, ns::foo_serializer>;
/////////////////////////////////////////////////////////////////////
// for #805
/////////////////////////////////////////////////////////////////////
namespace
{
struct nocopy
@ -1436,4 +1498,20 @@ TEST_CASE("regression tests")
//CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
// "[json.exception.out_of_range.408] excessive object size: 8658170730974374167");
}
SECTION("issue #972 - Segmentation fault on G++ when trying to assign json string literal to custom json type")
{
my_json foo = R"([1, 2, 3])"_json;
}
SECTION("issue #977 - Assigning between different json types")
{
foo_json lj = ns::foo{3};
ns::foo ff = lj;
CHECK(lj.is_object());
CHECK(lj.size() == 1);
CHECK(lj["x"] == 3);
CHECK(ff.x == 3);
nlohmann::json nj = lj; // This line works as expected
}
}

View file

@ -693,6 +693,83 @@ TEST_CASE("custom serializer that does adl by default", "[udt]")
CHECK(me == cj.get<udt::person>());
}
TEST_CASE("different basic_json types conversions")
{
using json = nlohmann::json;
SECTION("null")
{
json j;
custom_json cj = j;
CHECK(cj == nullptr);
}
SECTION("boolean")
{
json j = true;
custom_json cj = j;
CHECK(cj == true);
}
SECTION("discarded")
{
json j(json::value_t::discarded);
custom_json cj;
CHECK_NOTHROW(cj = j);
CHECK(cj.type() == custom_json::value_t::discarded);
}
SECTION("array")
{
json j = {1, 2, 3};
custom_json cj = j;
CHECK((cj == std::vector<int> {1, 2, 3}));
}
SECTION("integer")
{
json j = 42;
custom_json cj = j;
CHECK(cj == 42);
}
SECTION("float")
{
json j = 42.0;
custom_json cj = j;
CHECK(cj == 42.0);
}
SECTION("unsigned")
{
json j = 42u;
custom_json cj = j;
CHECK(cj == 42u);
}
SECTION("string")
{
json j = "forty-two";
custom_json cj = j;
CHECK(cj == "forty-two");
}
SECTION("object")
{
json j = {{"forty", "two"}};
custom_json cj = j;
auto m = j.get<std::map<std::string, std::string>>();
CHECK(cj == m);
}
SECTION("get<custom_json>")
{
json j = 42;
custom_json cj = j.get<custom_json>();
CHECK(cj == 42);
}
}
namespace
{
struct incomplete;
@ -730,6 +807,6 @@ TEST_CASE("Issue #924")
// Prevent get<std::vector<Evil>>() to throw
auto j = json::array();
(void) j.get<Evil>();
(void) j.get<std::vector<Evil>>();
CHECK_NOTHROW(j.get<Evil>());
CHECK_NOTHROW(j.get<std::vector<Evil>>());
}

21
test/thirdparty/fifo_map/LICENSE.MIT vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2015-2017 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.

530
test/thirdparty/fifo_map/fifo_map.hpp vendored Normal file
View file

@ -0,0 +1,530 @@
/*
The code is licensed under the MIT License <http://opensource.org/licenses/MIT>:
Copyright (c) 2015-2017 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.
*/
#ifndef NLOHMANN_FIFO_MAP_HPP
#define NLOHMANN_FIFO_MAP_HPP
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <unordered_map>
#include <utility>
#include <vector>
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
*/
namespace nlohmann
{
template<class Key>
class fifo_map_compare
{
public:
/// constructor given a pointer to a key storage
fifo_map_compare(std::unordered_map<Key, std::size_t>* k) : keys(k) {}
/*!
This function compares two keys with respect to the order in which they
were added to the container. For this, the mapping keys is used.
*/
bool operator()(const Key& lhs, const Key& rhs) const
{
// look up timestamps for both keys
const auto timestamp_lhs = keys->find(lhs);
const auto timestamp_rhs = keys->find(rhs);
if (timestamp_lhs == keys->end())
{
// timestamp for lhs not found - cannot be smaller than for rhs
return false;
}
if (timestamp_rhs == keys->end())
{
// timestamp for rhs not found - timestamp for lhs is smaller
return true;
}
// compare timestamps
return timestamp_lhs->second < timestamp_rhs->second;
}
void add_key(const Key& key)
{
keys->insert({key, timestamp++});
}
void remove_key(const Key& key)
{
keys->erase(key);
}
private:
/// pointer to a mapping from keys to insertion timestamps
std::unordered_map<Key, std::size_t>* keys = nullptr;
/// the next valid insertion timestamp
size_t timestamp = 1;
};
template <
class Key,
class T,
class Compare = fifo_map_compare<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>
> class fifo_map
{
public:
using key_type = Key;
using mapped_type = T;
using value_type = std::pair<const Key, T>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using key_compare = Compare;
using allocator_type = Allocator;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = typename std::allocator_traits<Allocator>::pointer;
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
using internal_map_type = std::map<Key, T, Compare, Allocator>;
using iterator = typename internal_map_type::iterator;
using const_iterator = typename internal_map_type::const_iterator;
using reverse_iterator = typename internal_map_type::reverse_iterator;
using const_reverse_iterator = typename internal_map_type::const_reverse_iterator;
public:
/// default constructor
fifo_map() : m_keys(), m_compare(&m_keys), m_map(m_compare) {}
/// copy constructor
fifo_map(const fifo_map &f) : m_keys(f.m_keys), m_compare(&m_keys), m_map(f.m_map.begin(), f.m_map.end(), m_compare) {}
/// constructor for a range of elements
template<class InputIterator>
fifo_map(InputIterator first, InputIterator last)
: m_keys(), m_compare(&m_keys), m_map(m_compare)
{
for (auto it = first; it != last; ++it)
{
insert(*it);
}
}
/// constructor for a list of elements
fifo_map(std::initializer_list<value_type> init) : fifo_map()
{
for (auto x : init)
{
insert(x);
}
}
/*
* Element access
*/
/// access specified element with bounds checking
T& at(const Key& key)
{
return m_map.at(key);
}
/// access specified element with bounds checking
const T& at(const Key& key) const
{
return m_map.at(key);
}
/// access specified element
T& operator[](const Key& key)
{
m_compare.add_key(key);
return m_map[key];
}
/// access specified element
T& operator[](Key&& key)
{
m_compare.add_key(key);
return m_map[key];
}
/*
* Iterators
*/
/// returns an iterator to the beginning
iterator begin() noexcept
{
return m_map.begin();
}
/// returns an iterator to the end
iterator end() noexcept
{
return m_map.end();
}
/// returns an iterator to the beginning
const_iterator begin() const noexcept
{
return m_map.begin();
}
/// returns an iterator to the end
const_iterator end() const noexcept
{
return m_map.end();
}
/// returns an iterator to the beginning
const_iterator cbegin() const noexcept
{
return m_map.cbegin();
}
/// returns an iterator to the end
const_iterator cend() const noexcept
{
return m_map.cend();
}
/// returns a reverse iterator to the beginning
reverse_iterator rbegin() noexcept
{
return m_map.rbegin();
}
/// returns a reverse iterator to the end
reverse_iterator rend() noexcept
{
return m_map.rend();
}
/// returns a reverse iterator to the beginning
const_reverse_iterator rbegin() const noexcept
{
return m_map.rbegin();
}
/// returns a reverse iterator to the end
const_reverse_iterator rend() const noexcept
{
return m_map.rend();
}
/// returns a reverse iterator to the beginning
const_reverse_iterator crbegin() const noexcept
{
return m_map.crbegin();
}
/// returns a reverse iterator to the end
const_reverse_iterator crend() const noexcept
{
return m_map.crend();
}
/*
* Capacity
*/
/// checks whether the container is empty
bool empty() const noexcept
{
return m_map.empty();
}
/// returns the number of elements
size_type size() const noexcept
{
return m_map.size();
}
/// returns the maximum possible number of elements
size_type max_size() const noexcept
{
return m_map.max_size();
}
/*
* Modifiers
*/
/// clears the contents
void clear() noexcept
{
m_map.clear();
m_keys.clear();
}
/// insert value
std::pair<iterator, bool> insert(const value_type& value)
{
m_compare.add_key(value.first);
return m_map.insert(value);
}
/// insert value
template<class P>
std::pair<iterator, bool> insert( P&& value )
{
m_compare.add_key(value.first);
return m_map.insert(value);
}
/// insert value with hint
iterator insert(const_iterator hint, const value_type& value)
{
m_compare.add_key(value.first);
return m_map.insert(hint, value);
}
/// insert value with hint
iterator insert(const_iterator hint, value_type&& value)
{
m_compare.add_key(value.first);
return m_map.insert(hint, value);
}
/// insert value range
template<class InputIt>
void insert(InputIt first, InputIt last)
{
for (const_iterator it = first; it != last; ++it)
{
m_compare.add_key(it->first);
}
m_map.insert(first, last);
}
/// insert value list
void insert(std::initializer_list<value_type> ilist)
{
for (auto value : ilist)
{
m_compare.add_key(value.first);
}
m_map.insert(ilist);
}
/// constructs element in-place
template<class... Args>
std::pair<iterator, bool> emplace(Args&& ... args)
{
typename fifo_map::value_type value(std::forward<Args>(args)...);
m_compare.add_key(value.first);
return m_map.emplace(std::move(value));
}
/// constructs element in-place with hint
template<class... Args>
iterator emplace_hint(const_iterator hint, Args&& ... args)
{
typename fifo_map::value_type value(std::forward<Args>(args)...);
m_compare.add_key(value.first);
return m_map.emplace_hint(hint, std::move(value));
}
/// remove element at position
iterator erase(const_iterator pos)
{
m_compare.remove_key(pos->first);
return m_map.erase(pos);
}
/// remove elements in range
iterator erase(const_iterator first, const_iterator last)
{
for (const_iterator it = first; it != last; ++it)
{
m_compare.remove_key(it->first);
}
return m_map.erase(first, last);
}
/// remove elements with key
size_type erase(const key_type& key)
{
size_type res = m_map.erase(key);
if (res > 0)
{
m_compare.remove_key(key);
}
return res;
}
/// swaps the contents
void swap(fifo_map& other)
{
std::swap(m_map, other.m_map);
std::swap(m_compare, other.m_compare);
std::swap(m_keys, other.m_keys);
}
/*
* Lookup
*/
/// returns the number of elements matching specific key
size_type count(const Key& key) const
{
return m_map.count(key);
}
/// finds element with specific key
iterator find(const Key& key)
{
return m_map.find(key);
}
/// finds element with specific key
const_iterator find(const Key& key) const
{
return m_map.find(key);
}
/// returns range of elements matching a specific key
std::pair<iterator, iterator> equal_range(const Key& key)
{
return m_map.equal_range(key);
}
/// returns range of elements matching a specific key
std::pair<const_iterator, const_iterator> equal_range(const Key& key) const
{
return m_map.equal_range(key);
}
/// returns an iterator to the first element not less than the given key
iterator lower_bound(const Key& key)
{
return m_map.lower_bound(key);
}
/// returns an iterator to the first element not less than the given key
const_iterator lower_bound(const Key& key) const
{
return m_map.lower_bound(key);
}
/// returns an iterator to the first element greater than the given key
iterator upper_bound(const Key& key)
{
return m_map.upper_bound(key);
}
/// returns an iterator to the first element greater than the given key
const_iterator upper_bound(const Key& key) const
{
return m_map.upper_bound(key);
}
/*
* Observers
*/
/// returns the function that compares keys
key_compare key_comp() const
{
return m_compare;
}
/*
* Non-member functions
*/
friend bool operator==(const fifo_map& lhs, const fifo_map& rhs)
{
return lhs.m_map == rhs.m_map;
}
friend bool operator!=(const fifo_map& lhs, const fifo_map& rhs)
{
return lhs.m_map != rhs.m_map;
}
friend bool operator<(const fifo_map& lhs, const fifo_map& rhs)
{
return lhs.m_map < rhs.m_map;
}
friend bool operator<=(const fifo_map& lhs, const fifo_map& rhs)
{
return lhs.m_map <= rhs.m_map;
}
friend bool operator>(const fifo_map& lhs, const fifo_map& rhs)
{
return lhs.m_map > rhs.m_map;
}
friend bool operator>=(const fifo_map& lhs, const fifo_map& rhs)
{
return lhs.m_map >= rhs.m_map;
}
private:
/// the keys
std::unordered_map<Key, std::size_t> m_keys;
/// the comparison object
Compare m_compare;
/// the internal data structure
internal_map_type m_map;
};
}
// specialization of std::swap
namespace std
{
template <class Key, class T, class Compare, class Allocator>
inline void swap(nlohmann::fifo_map<Key, T, Compare, Allocator>& m1,
nlohmann::fifo_map<Key, T, Compare, Allocator>& m2)
{
m1.swap(m2);
}
}
#endif