Merge upstream commits and resolve conflicts
This commit is contained in:
commit
421affd06e
5 changed files with 276 additions and 81 deletions
|
@ -62,6 +62,7 @@ Please understand that I cannot accept pull requests changing only file `src/jso
|
||||||
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.
|
||||||
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
|
- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.
|
||||||
- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
|
- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.
|
||||||
|
- Please do not open pull requests that address **multiple issues**.
|
||||||
|
|
||||||
## Wanted
|
## Wanted
|
||||||
|
|
||||||
|
|
|
@ -388,6 +388,7 @@ I deeply appreciate the help of the following people.
|
||||||
- [406345](https://github.com/406345) fixed two small warnings.
|
- [406345](https://github.com/406345) fixed two small warnings.
|
||||||
- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
|
- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
|
||||||
- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
||||||
|
- [twelsby](https://github.com/twelsby) fixed the array subscript operator and an issue that failed the MSVC build.
|
||||||
|
|
||||||
Thanks a lot for helping out!
|
Thanks a lot for helping out!
|
||||||
|
|
||||||
|
@ -404,7 +405,7 @@ $ make
|
||||||
$ ./json_unit "*"
|
$ ./json_unit "*"
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
All tests passed (3343239 assertions in 28 test cases)
|
All tests passed (3343318 assertions in 29 test cases)
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
||||||
|
|
148
src/json.hpp
148
src/json.hpp
|
@ -43,7 +43,9 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
@ -53,6 +55,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -65,6 +68,12 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// disable float-equal warnings on GCC/clang
|
||||||
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
#endif
|
||||||
|
|
||||||
// enable ssize_t for MSVC
|
// enable ssize_t for MSVC
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <basetsd.h>
|
#include <basetsd.h>
|
||||||
|
@ -100,12 +109,6 @@ struct has_mapped_type
|
||||||
static constexpr bool value = sizeof(test<T>(0)) == 1;
|
static constexpr bool value = sizeof(test<T>(0)) == 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// "equality" comparison for floating point numbers
|
|
||||||
template<typename T>
|
|
||||||
static bool approx(const T a, const T b)
|
|
||||||
{
|
|
||||||
return not (a > b or a < b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -2671,14 +2674,14 @@ class basic_json
|
||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename ValueType, typename
|
template < typename ValueType, typename
|
||||||
std::enable_if<
|
std::enable_if <
|
||||||
not std::is_pointer<ValueType>::value
|
not std::is_pointer<ValueType>::value
|
||||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity 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
|
||||||
, int>::type = 0>
|
, int >::type = 0 >
|
||||||
operator ValueType() const
|
operator ValueType() const
|
||||||
{
|
{
|
||||||
// delegate the call to get<>() const
|
// delegate the call to get<>() const
|
||||||
|
@ -3062,8 +3065,6 @@ class basic_json
|
||||||
the object and filled with a `null` value to make `key` a valid reference.
|
the object and filled with a `null` value to make `key` a valid reference.
|
||||||
In case the value was `null` before, it is converted to an object.
|
In case the value was `null` before, it is converted to an object.
|
||||||
|
|
||||||
@note This function is required for compatibility reasons with Clang.
|
|
||||||
|
|
||||||
@param[in] key key of the element to access
|
@param[in] key key of the element to access
|
||||||
|
|
||||||
@return reference to the element at key @a key
|
@return reference to the element at key @a key
|
||||||
|
@ -3083,25 +3084,9 @@ class basic_json
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename T, std::size_t n>
|
template<typename T, std::size_t n>
|
||||||
reference operator[](const T (&key)[n])
|
reference operator[](T * (&key)[n])
|
||||||
{
|
{
|
||||||
// implicitly convert null to object
|
return operator[](static_cast<const T>(key));
|
||||||
if (is_null())
|
|
||||||
{
|
|
||||||
m_type = value_t::object;
|
|
||||||
m_value = value_t::object;
|
|
||||||
}
|
|
||||||
|
|
||||||
// at only works for objects
|
|
||||||
if (is_object())
|
|
||||||
{
|
|
||||||
assert(m_value.object != nullptr);
|
|
||||||
return m_value.object->operator[](key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3134,7 +3119,89 @@ class basic_json
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename T, std::size_t n>
|
template<typename T, std::size_t n>
|
||||||
const_reference operator[](const T (&key)[n]) const
|
const_reference operator[](T * (&key)[n]) const
|
||||||
|
{
|
||||||
|
return operator[](static_cast<const T>(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief access specified object element
|
||||||
|
|
||||||
|
Returns a reference to the element at with specified key @a key.
|
||||||
|
|
||||||
|
@note If @a key is not found in the object, then it is silently added to
|
||||||
|
the object and filled with a `null` value to make `key` a valid reference.
|
||||||
|
In case the value was `null` before, it is converted to an object.
|
||||||
|
|
||||||
|
@param[in] key key of the element to access
|
||||||
|
|
||||||
|
@return reference to the element at key @a key
|
||||||
|
|
||||||
|
@throw std::domain_error if JSON is not an object or null; example:
|
||||||
|
`"cannot use operator[] with null"`
|
||||||
|
|
||||||
|
@complexity Logarithmic in the size of the container.
|
||||||
|
|
||||||
|
@liveexample{The example below shows how object elements can be read and
|
||||||
|
written using the [] operator.,operatorarray__key_type}
|
||||||
|
|
||||||
|
@sa @ref at(const typename object_t::key_type&) for access by reference
|
||||||
|
with range checking
|
||||||
|
@sa @ref value() for access by value with a default value
|
||||||
|
|
||||||
|
@since version 1.0.1
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
reference operator[](T* key)
|
||||||
|
{
|
||||||
|
// implicitly convert null to object
|
||||||
|
if (is_null())
|
||||||
|
{
|
||||||
|
m_type = value_t::object;
|
||||||
|
m_value = value_t::object;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at only works for objects
|
||||||
|
if (is_object())
|
||||||
|
{
|
||||||
|
assert(m_value.object != nullptr);
|
||||||
|
return m_value.object->operator[](key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief read-only access specified object element
|
||||||
|
|
||||||
|
Returns a const reference to the element at with specified key @a key. No
|
||||||
|
bounds checking is performed.
|
||||||
|
|
||||||
|
@warning If the element with key @a key does not exist, the behavior is
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
@param[in] key key of the element to access
|
||||||
|
|
||||||
|
@return const reference to the element at key @a key
|
||||||
|
|
||||||
|
@throw std::domain_error if JSON is not an object; example: `"cannot use
|
||||||
|
operator[] with null"`
|
||||||
|
|
||||||
|
@complexity Logarithmic in the size of the container.
|
||||||
|
|
||||||
|
@liveexample{The example below shows how object elements can be read using
|
||||||
|
the [] operator.,operatorarray__key_type_const}
|
||||||
|
|
||||||
|
@sa @ref at(const typename object_t::key_type&) for access by reference
|
||||||
|
with range checking
|
||||||
|
@sa @ref value() for access by value with a default value
|
||||||
|
|
||||||
|
@since version 1.0.1
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
const_reference operator[](T* key) const
|
||||||
{
|
{
|
||||||
// at only works for objects
|
// at only works for objects
|
||||||
if (is_object())
|
if (is_object())
|
||||||
|
@ -4785,7 +4852,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
{
|
{
|
||||||
return approx(lhs.m_value.number_float, rhs.m_value.number_float);
|
return lhs.m_value.number_float == rhs.m_value.number_float;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
@ -4795,13 +4862,11 @@ class basic_json
|
||||||
}
|
}
|
||||||
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
|
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
|
||||||
{
|
{
|
||||||
return approx(static_cast<number_float_t>(lhs.m_value.number_integer),
|
return static_cast<number_float_t>(lhs.m_value.number_integer == rhs.m_value.number_float);
|
||||||
rhs.m_value.number_float);
|
|
||||||
}
|
}
|
||||||
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
|
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
|
||||||
{
|
{
|
||||||
return approx(lhs.m_value.number_float,
|
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
|
||||||
static_cast<number_float_t>(rhs.m_value.number_integer));
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -7622,7 +7687,7 @@ basic_json_parser_64:
|
||||||
|
|
||||||
// check if conversion loses precision (special case -0.0 always loses precision)
|
// check if conversion loses precision (special case -0.0 always loses precision)
|
||||||
const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
|
const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
|
||||||
if (approx(result.m_value.number_float, static_cast<number_float_t>(int_val)) &&
|
if (result.m_value.number_float == static_cast<number_float_t>(int_val) &&
|
||||||
result.m_value.number_integer != json_value(-0.0f).number_integer)
|
result.m_value.number_integer != json_value(-0.0f).number_integer)
|
||||||
{
|
{
|
||||||
// we would not lose precision -> return int
|
// we would not lose precision -> return int
|
||||||
|
@ -7767,4 +7832,9 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
|
||||||
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
|
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore GCC/clang diagnostic settings
|
||||||
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,7 +43,9 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
@ -53,6 +55,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -65,6 +68,12 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// disable float-equal warnings on GCC/clang
|
||||||
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
#endif
|
||||||
|
|
||||||
// enable ssize_t for MSVC
|
// enable ssize_t for MSVC
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <basetsd.h>
|
#include <basetsd.h>
|
||||||
|
@ -100,12 +109,6 @@ struct has_mapped_type
|
||||||
static constexpr bool value = sizeof(test<T>(0)) == 1;
|
static constexpr bool value = sizeof(test<T>(0)) == 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// "equality" comparison for floating point numbers
|
|
||||||
template<typename T>
|
|
||||||
static bool approx(const T a, const T b)
|
|
||||||
{
|
|
||||||
return not (a > b or a < b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -2671,14 +2674,14 @@ class basic_json
|
||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename ValueType, typename
|
template < typename ValueType, typename
|
||||||
std::enable_if<
|
std::enable_if <
|
||||||
not std::is_pointer<ValueType>::value
|
not std::is_pointer<ValueType>::value
|
||||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity 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
|
||||||
, int>::type = 0>
|
, int >::type = 0 >
|
||||||
operator ValueType() const
|
operator ValueType() const
|
||||||
{
|
{
|
||||||
// delegate the call to get<>() const
|
// delegate the call to get<>() const
|
||||||
|
@ -3062,8 +3065,6 @@ class basic_json
|
||||||
the object and filled with a `null` value to make `key` a valid reference.
|
the object and filled with a `null` value to make `key` a valid reference.
|
||||||
In case the value was `null` before, it is converted to an object.
|
In case the value was `null` before, it is converted to an object.
|
||||||
|
|
||||||
@note This function is required for compatibility reasons with Clang.
|
|
||||||
|
|
||||||
@param[in] key key of the element to access
|
@param[in] key key of the element to access
|
||||||
|
|
||||||
@return reference to the element at key @a key
|
@return reference to the element at key @a key
|
||||||
|
@ -3083,25 +3084,9 @@ class basic_json
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename T, std::size_t n>
|
template<typename T, std::size_t n>
|
||||||
reference operator[](const T (&key)[n])
|
reference operator[](T * (&key)[n])
|
||||||
{
|
{
|
||||||
// implicitly convert null to object
|
return operator[](static_cast<const T>(key));
|
||||||
if (is_null())
|
|
||||||
{
|
|
||||||
m_type = value_t::object;
|
|
||||||
m_value = value_t::object;
|
|
||||||
}
|
|
||||||
|
|
||||||
// at only works for objects
|
|
||||||
if (is_object())
|
|
||||||
{
|
|
||||||
assert(m_value.object != nullptr);
|
|
||||||
return m_value.object->operator[](key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3134,7 +3119,89 @@ class basic_json
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
template<typename T, std::size_t n>
|
template<typename T, std::size_t n>
|
||||||
const_reference operator[](const T (&key)[n]) const
|
const_reference operator[](T * (&key)[n]) const
|
||||||
|
{
|
||||||
|
return operator[](static_cast<const T>(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief access specified object element
|
||||||
|
|
||||||
|
Returns a reference to the element at with specified key @a key.
|
||||||
|
|
||||||
|
@note If @a key is not found in the object, then it is silently added to
|
||||||
|
the object and filled with a `null` value to make `key` a valid reference.
|
||||||
|
In case the value was `null` before, it is converted to an object.
|
||||||
|
|
||||||
|
@param[in] key key of the element to access
|
||||||
|
|
||||||
|
@return reference to the element at key @a key
|
||||||
|
|
||||||
|
@throw std::domain_error if JSON is not an object or null; example:
|
||||||
|
`"cannot use operator[] with null"`
|
||||||
|
|
||||||
|
@complexity Logarithmic in the size of the container.
|
||||||
|
|
||||||
|
@liveexample{The example below shows how object elements can be read and
|
||||||
|
written using the [] operator.,operatorarray__key_type}
|
||||||
|
|
||||||
|
@sa @ref at(const typename object_t::key_type&) for access by reference
|
||||||
|
with range checking
|
||||||
|
@sa @ref value() for access by value with a default value
|
||||||
|
|
||||||
|
@since version 1.0.1
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
reference operator[](T* key)
|
||||||
|
{
|
||||||
|
// implicitly convert null to object
|
||||||
|
if (is_null())
|
||||||
|
{
|
||||||
|
m_type = value_t::object;
|
||||||
|
m_value = value_t::object;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at only works for objects
|
||||||
|
if (is_object())
|
||||||
|
{
|
||||||
|
assert(m_value.object != nullptr);
|
||||||
|
return m_value.object->operator[](key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief read-only access specified object element
|
||||||
|
|
||||||
|
Returns a const reference to the element at with specified key @a key. No
|
||||||
|
bounds checking is performed.
|
||||||
|
|
||||||
|
@warning If the element with key @a key does not exist, the behavior is
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
@param[in] key key of the element to access
|
||||||
|
|
||||||
|
@return const reference to the element at key @a key
|
||||||
|
|
||||||
|
@throw std::domain_error if JSON is not an object; example: `"cannot use
|
||||||
|
operator[] with null"`
|
||||||
|
|
||||||
|
@complexity Logarithmic in the size of the container.
|
||||||
|
|
||||||
|
@liveexample{The example below shows how object elements can be read using
|
||||||
|
the [] operator.,operatorarray__key_type_const}
|
||||||
|
|
||||||
|
@sa @ref at(const typename object_t::key_type&) for access by reference
|
||||||
|
with range checking
|
||||||
|
@sa @ref value() for access by value with a default value
|
||||||
|
|
||||||
|
@since version 1.0.1
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
const_reference operator[](T* key) const
|
||||||
{
|
{
|
||||||
// at only works for objects
|
// at only works for objects
|
||||||
if (is_object())
|
if (is_object())
|
||||||
|
@ -4785,7 +4852,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
{
|
{
|
||||||
return approx(lhs.m_value.number_float, rhs.m_value.number_float);
|
return lhs.m_value.number_float == rhs.m_value.number_float;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
@ -4795,13 +4862,11 @@ class basic_json
|
||||||
}
|
}
|
||||||
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
|
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
|
||||||
{
|
{
|
||||||
return approx(static_cast<number_float_t>(lhs.m_value.number_integer),
|
return static_cast<number_float_t>(lhs.m_value.number_integer == rhs.m_value.number_float);
|
||||||
rhs.m_value.number_float);
|
|
||||||
}
|
}
|
||||||
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
|
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
|
||||||
{
|
{
|
||||||
return approx(lhs.m_value.number_float,
|
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
|
||||||
static_cast<number_float_t>(rhs.m_value.number_integer));
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -7304,7 +7369,7 @@ class basic_json
|
||||||
|
|
||||||
// check if conversion loses precision (special case -0.0 always loses precision)
|
// check if conversion loses precision (special case -0.0 always loses precision)
|
||||||
const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
|
const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
|
||||||
if (approx(result.m_value.number_float, static_cast<number_float_t>(int_val)) &&
|
if (result.m_value.number_float == static_cast<number_float_t>(int_val) &&
|
||||||
result.m_value.number_integer != json_value(-0.0f).number_integer)
|
result.m_value.number_integer != json_value(-0.0f).number_integer)
|
||||||
{
|
{
|
||||||
// we would not lose precision -> return int
|
// we would not lose precision -> return int
|
||||||
|
@ -7449,4 +7514,9 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
|
||||||
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
|
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore GCC/clang diagnostic settings
|
||||||
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
|
// disable float-equal warnings on GCC/clang
|
||||||
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST_CASE("constructors")
|
TEST_CASE("constructors")
|
||||||
{
|
{
|
||||||
SECTION("create an empty value with a given type")
|
SECTION("create an empty value with a given type")
|
||||||
|
@ -11501,11 +11506,59 @@ TEST_CASE("regression tests")
|
||||||
CHECK(s2 == "value");
|
CHECK(s2 == "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("character following a surrogate pair is skipped")
|
SECTION("issue #146 - character following a surrogate pair is skipped")
|
||||||
{
|
{
|
||||||
CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc");
|
CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("issue #171 - Cannot index by key of type static constexpr const char*")
|
||||||
|
{
|
||||||
|
json j;
|
||||||
|
|
||||||
|
// Non-const access with key as "char []"
|
||||||
|
char array_key[] = "Key1";
|
||||||
|
CHECK_NOTHROW(j[array_key] = 1);
|
||||||
|
CHECK(j[array_key] == json(1));
|
||||||
|
|
||||||
|
// Non-const access with key as "const char[]"
|
||||||
|
const char const_array_key[] = "Key2";
|
||||||
|
CHECK_NOTHROW(j[const_array_key] = 2);
|
||||||
|
CHECK(j[const_array_key] == json(2));
|
||||||
|
|
||||||
|
// Non-const access with key as "char *"
|
||||||
|
char _ptr_key[] = "Key3";
|
||||||
|
char* ptr_key = &_ptr_key[0];
|
||||||
|
CHECK_NOTHROW(j[ptr_key] = 3);
|
||||||
|
CHECK(j[ptr_key] == json(3));
|
||||||
|
|
||||||
|
// Non-const access with key as "const char *"
|
||||||
|
const char* const_ptr_key = "Key4";
|
||||||
|
CHECK_NOTHROW(j[const_ptr_key] = 4);
|
||||||
|
CHECK(j[const_ptr_key] == json(4));
|
||||||
|
|
||||||
|
// Non-const access with key as "static constexpr const char *"
|
||||||
|
static constexpr const char* constexpr_ptr_key = "Key5";
|
||||||
|
CHECK_NOTHROW(j[constexpr_ptr_key] = 5);
|
||||||
|
CHECK(j[constexpr_ptr_key] == json(5));
|
||||||
|
|
||||||
|
const json j_const = j;
|
||||||
|
|
||||||
|
// Const access with key as "char []"
|
||||||
|
CHECK(j_const[array_key] == json(1));
|
||||||
|
|
||||||
|
// Const access with key as "const char[]"
|
||||||
|
CHECK(j_const[const_array_key] == json(2));
|
||||||
|
|
||||||
|
//Const access with key as "char *"
|
||||||
|
CHECK(j_const[ptr_key] == json(3));
|
||||||
|
|
||||||
|
// Const access with key as "const char *"
|
||||||
|
CHECK(j_const[const_ptr_key] == json(4));
|
||||||
|
|
||||||
|
// Const access with key as "static constexpr const char *"
|
||||||
|
CHECK(j_const[constexpr_ptr_key] == json(5));
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing")
|
SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing")
|
||||||
{
|
{
|
||||||
json j;
|
json j;
|
||||||
|
@ -11520,7 +11573,7 @@ TEST_CASE("regression tests")
|
||||||
CHECK(j.get<double>() == 0.99999999999999989);
|
CHECK(j.get<double>() == 0.99999999999999989);
|
||||||
|
|
||||||
// Test fails under GCC/clang due to strtod() error (may originate in libstdc++
|
// Test fails under GCC/clang due to strtod() error (may originate in libstdc++
|
||||||
// but seems to have been fixed in the most current versions)
|
// but seems to have been fixed in the most current versions - just not on Travis)
|
||||||
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
j = json::parse("1.00000000000000011102230246251565404236316680908203126");
|
j = json::parse("1.00000000000000011102230246251565404236316680908203126");
|
||||||
CHECK(j.get<double>() == 1.00000000000000022);
|
CHECK(j.get<double>() == 1.00000000000000022);
|
||||||
|
|
Loading…
Reference in a new issue