Merge branch 'develop' into feature/sax2
This commit is contained in:
commit
303a0c5843
11 changed files with 1187 additions and 183 deletions
|
@ -233,7 +233,7 @@ struct is_compatible_complete_type
|
||||||
{
|
{
|
||||||
static constexpr bool value =
|
static constexpr bool value =
|
||||||
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
|
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
|
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
|
||||||
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
|
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
|
||||||
};
|
};
|
||||||
|
|
|
@ -704,11 +704,11 @@ class binary_writer
|
||||||
oa->write_characters(vec.data(), sizeof(NumberType));
|
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,
|
void write_number_with_ubjson_prefix(const NumberType n,
|
||||||
const bool add_prefix)
|
const bool add_prefix)
|
||||||
{
|
|
||||||
if (std::is_floating_point<NumberType>::value)
|
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -716,9 +716,14 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(n);
|
write_number(n);
|
||||||
}
|
}
|
||||||
else if (std::is_unsigned<NumberType>::value)
|
|
||||||
|
// 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 <= (std::numeric_limits<int8_t>::max)())
|
if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -734,7 +739,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<uint8_t>(n));
|
write_number(static_cast<uint8_t>(n));
|
||||||
}
|
}
|
||||||
else if (n <= (std::numeric_limits<int16_t>::max)())
|
else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -742,7 +747,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<int16_t>(n));
|
write_number(static_cast<int16_t>(n));
|
||||||
}
|
}
|
||||||
else if (n <= (std::numeric_limits<int32_t>::max)())
|
else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -750,7 +755,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<int32_t>(n));
|
write_number(static_cast<int32_t>(n));
|
||||||
}
|
}
|
||||||
else if (n <= (std::numeric_limits<int64_t>::max)())
|
else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -763,7 +768,13 @@ class binary_writer
|
||||||
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
|
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// 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 ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
|
||||||
{
|
{
|
||||||
|
@ -773,7 +784,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<int8_t>(n));
|
write_number(static_cast<int8_t>(n));
|
||||||
}
|
}
|
||||||
else if ((std::numeric_limits<uint8_t>::min)() <= n and n <= (std::numeric_limits<uint8_t>::max)())
|
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)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -812,7 +823,6 @@ class binary_writer
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief determine the type prefix of container values
|
@brief determine the type prefix of container values
|
||||||
|
|
|
@ -1210,6 +1210,7 @@ class basic_json
|
||||||
- @a CompatibleType is not derived from `std::istream`,
|
- @a CompatibleType is not derived from `std::istream`,
|
||||||
- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
|
- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
|
||||||
constructors),
|
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.,
|
- @a CompatibleType is not a @ref basic_json nested type (e.g.,
|
||||||
@ref json_pointer, @ref iterator, etc ...)
|
@ref json_pointer, @ref iterator, etc ...)
|
||||||
- @ref @ref json_serializer<U> has a
|
- @ref @ref json_serializer<U> has a
|
||||||
|
@ -1245,6 +1246,78 @@ class basic_json
|
||||||
assert_invariant();
|
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
|
@brief create a container (array or object) from an initializer list
|
||||||
|
|
||||||
|
@ -2417,6 +2490,29 @@ class basic_json
|
||||||
return *this;
|
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)
|
@brief get a value (explicit)
|
||||||
|
|
||||||
|
@ -2458,7 +2554,7 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
|
template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
|
||||||
detail::enable_if_t <
|
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
|
detail::has_from_json<basic_json_t, ValueType>::value and
|
||||||
not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
|
not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
|
||||||
int> = 0>
|
int> = 0>
|
||||||
|
@ -2724,7 +2820,8 @@ class basic_json
|
||||||
template < typename ValueType, typename std::enable_if <
|
template < typename ValueType, typename std::enable_if <
|
||||||
not std::is_pointer<ValueType>::value and
|
not std::is_pointer<ValueType>::value and
|
||||||
not std::is_same<ValueType, detail::json_ref<basic_json>>::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
|
#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
|
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -466,7 +466,7 @@ struct is_compatible_complete_type
|
||||||
{
|
{
|
||||||
static constexpr bool value =
|
static constexpr bool value =
|
||||||
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
|
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
|
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
|
||||||
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
|
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
|
||||||
};
|
};
|
||||||
|
@ -7401,11 +7401,11 @@ class binary_writer
|
||||||
oa->write_characters(vec.data(), sizeof(NumberType));
|
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,
|
void write_number_with_ubjson_prefix(const NumberType n,
|
||||||
const bool add_prefix)
|
const bool add_prefix)
|
||||||
{
|
|
||||||
if (std::is_floating_point<NumberType>::value)
|
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -7413,9 +7413,14 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(n);
|
write_number(n);
|
||||||
}
|
}
|
||||||
else if (std::is_unsigned<NumberType>::value)
|
|
||||||
|
// 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 <= (std::numeric_limits<int8_t>::max)())
|
if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -7431,7 +7436,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<uint8_t>(n));
|
write_number(static_cast<uint8_t>(n));
|
||||||
}
|
}
|
||||||
else if (n <= (std::numeric_limits<int16_t>::max)())
|
else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -7439,7 +7444,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<int16_t>(n));
|
write_number(static_cast<int16_t>(n));
|
||||||
}
|
}
|
||||||
else if (n <= (std::numeric_limits<int32_t>::max)())
|
else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -7447,7 +7452,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<int32_t>(n));
|
write_number(static_cast<int32_t>(n));
|
||||||
}
|
}
|
||||||
else if (n <= (std::numeric_limits<int64_t>::max)())
|
else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
|
||||||
{
|
{
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -7460,7 +7465,13 @@ class binary_writer
|
||||||
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
|
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// 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 ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
|
||||||
{
|
{
|
||||||
|
@ -7470,7 +7481,7 @@ class binary_writer
|
||||||
}
|
}
|
||||||
write_number(static_cast<int8_t>(n));
|
write_number(static_cast<int8_t>(n));
|
||||||
}
|
}
|
||||||
else if ((std::numeric_limits<uint8_t>::min)() <= n and n <= (std::numeric_limits<uint8_t>::max)())
|
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)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
|
@ -7509,7 +7520,6 @@ class binary_writer
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief determine the type prefix of container values
|
@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 derived from `std::istream`,
|
||||||
- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
|
- @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
|
||||||
constructors),
|
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.,
|
- @a CompatibleType is not a @ref basic_json nested type (e.g.,
|
||||||
@ref json_pointer, @ref iterator, etc ...)
|
@ref json_pointer, @ref iterator, etc ...)
|
||||||
- @ref @ref json_serializer<U> has a
|
- @ref @ref json_serializer<U> has a
|
||||||
|
@ -11335,6 +11346,78 @@ class basic_json
|
||||||
assert_invariant();
|
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
|
@brief create a container (array or object) from an initializer list
|
||||||
|
|
||||||
|
@ -12507,6 +12590,29 @@ class basic_json
|
||||||
return *this;
|
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)
|
@brief get a value (explicit)
|
||||||
|
|
||||||
|
@ -12548,7 +12654,7 @@ class basic_json
|
||||||
*/
|
*/
|
||||||
template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
|
template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
|
||||||
detail::enable_if_t <
|
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
|
detail::has_from_json<basic_json_t, ValueType>::value and
|
||||||
not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
|
not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
|
||||||
int> = 0>
|
int> = 0>
|
||||||
|
@ -12814,7 +12920,8 @@ class basic_json
|
||||||
template < typename ValueType, typename std::enable_if <
|
template < typename ValueType, typename std::enable_if <
|
||||||
not std::is_pointer<ValueType>::value and
|
not std::is_pointer<ValueType>::value and
|
||||||
not std::is_same<ValueType, detail::json_ref<basic_json>>::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
|
#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
|
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,6 +104,7 @@ foreach(file ${files})
|
||||||
|
|
||||||
target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE)
|
target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE)
|
||||||
target_include_directories(${testcase} PRIVATE "thirdparty/catch")
|
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_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR})
|
||||||
target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME})
|
target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME})
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
# additional flags
|
# 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
|
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 \
|
SOURCES = src/unit.cpp \
|
||||||
src/unit-algorithms.cpp \
|
src/unit-algorithms.cpp \
|
||||||
|
|
|
@ -1527,6 +1527,89 @@ TEST_CASE("parser class")
|
||||||
});
|
});
|
||||||
CHECK(j_empty_array == json());
|
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")
|
SECTION("constructing from contiguous containers")
|
||||||
|
|
|
@ -32,10 +32,72 @@ SOFTWARE.
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
|
#include "fifo_map.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <cstdio>
|
#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
|
namespace
|
||||||
{
|
{
|
||||||
struct nocopy
|
struct nocopy
|
||||||
|
@ -1436,4 +1498,20 @@ TEST_CASE("regression tests")
|
||||||
//CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
|
//CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
|
||||||
// "[json.exception.out_of_range.408] excessive object size: 8658170730974374167");
|
// "[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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -693,6 +693,83 @@ TEST_CASE("custom serializer that does adl by default", "[udt]")
|
||||||
CHECK(me == cj.get<udt::person>());
|
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
|
namespace
|
||||||
{
|
{
|
||||||
struct incomplete;
|
struct incomplete;
|
||||||
|
@ -730,6 +807,6 @@ TEST_CASE("Issue #924")
|
||||||
// Prevent get<std::vector<Evil>>() to throw
|
// Prevent get<std::vector<Evil>>() to throw
|
||||||
auto j = json::array();
|
auto j = json::array();
|
||||||
|
|
||||||
(void) j.get<Evil>();
|
CHECK_NOTHROW(j.get<Evil>());
|
||||||
(void) j.get<std::vector<Evil>>();
|
CHECK_NOTHROW(j.get<std::vector<Evil>>());
|
||||||
}
|
}
|
||||||
|
|
21
test/thirdparty/fifo_map/LICENSE.MIT
vendored
Normal file
21
test/thirdparty/fifo_map/LICENSE.MIT
vendored
Normal 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
530
test/thirdparty/fifo_map/fifo_map.hpp
vendored
Normal 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
|
Loading…
Reference in a new issue