Merge pull request #193 from twelsby/issue178
Issue #178 - Extending support to full uint64_t/int64_t range and unsigned type (updated)
This commit is contained in:
		
						commit
						e46cc6327f
					
				
					 3 changed files with 2213 additions and 1251 deletions
				
			
		
							
								
								
									
										1656
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										1656
									
								
								src/json.hpp
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -124,6 +124,8 @@ default; will be used in @ref string_t)
 | 
			
		|||
in @ref boolean_t)
 | 
			
		||||
@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
 | 
			
		||||
default; will be used in @ref number_integer_t)
 | 
			
		||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by
 | 
			
		||||
default; will be used in @ref number_unsigned_t)
 | 
			
		||||
@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
 | 
			
		||||
default; will be used in @ref number_float_t)
 | 
			
		||||
@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
 | 
			
		||||
| 
						 | 
				
			
			@ -185,6 +187,7 @@ template <
 | 
			
		|||
    class StringType = std::string,
 | 
			
		||||
    class BooleanType = bool,
 | 
			
		||||
    class NumberIntegerType = int64_t,
 | 
			
		||||
    class NumberUnsignedType = uint64_t,
 | 
			
		||||
    class NumberFloatType = double,
 | 
			
		||||
    template<typename U> class AllocatorType = std::allocator
 | 
			
		||||
    >
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +200,7 @@ class basic_json
 | 
			
		|||
          StringType,
 | 
			
		||||
          BooleanType,
 | 
			
		||||
          NumberIntegerType,
 | 
			
		||||
          NumberUnsignedType,
 | 
			
		||||
          NumberFloatType,
 | 
			
		||||
          AllocatorType>;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -481,9 +485,10 @@ class basic_json
 | 
			
		|||
    > permitted.
 | 
			
		||||
 | 
			
		||||
    This description includes both integer and floating-point numbers. However,
 | 
			
		||||
    C++ allows more precise storage if it is known whether the number is an
 | 
			
		||||
    integer or a floating-point number. Therefore, two different types, @ref
 | 
			
		||||
    number_integer_t and @ref number_float_t are used.
 | 
			
		||||
    C++ allows more precise storage if it is known whether the number is a 
 | 
			
		||||
    signed integer, an unsigned integer or a floating-point number. Therefore,
 | 
			
		||||
    three different types, @ref number_integer_t,  @ref number_unsigned_t and 
 | 
			
		||||
    @ref number_float_t are used.
 | 
			
		||||
 | 
			
		||||
    To store integer numbers in C++, a type is defined by the template
 | 
			
		||||
    parameter @a NumberIntegerType which chooses the type to use.
 | 
			
		||||
| 
						 | 
				
			
			@ -516,7 +521,7 @@ class basic_json
 | 
			
		|||
    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
 | 
			
		||||
    that are out of range will yield over/underflow when used in a constructor.
 | 
			
		||||
    During deserialization, too large or small integer numbers will be
 | 
			
		||||
    automatically be stored as @ref number_float_t.
 | 
			
		||||
    automatically be stored as @ref number_unsigned_t or @ref number_float_t.
 | 
			
		||||
 | 
			
		||||
    [RFC 7159](http://rfc7159.net/rfc7159) further states:
 | 
			
		||||
    > Note that when such software is used, numbers that are integers and are
 | 
			
		||||
| 
						 | 
				
			
			@ -532,10 +537,84 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @sa @ref number_float_t -- type for number values (floating-point)
 | 
			
		||||
 | 
			
		||||
    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
 | 
			
		||||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
    using number_integer_t = NumberIntegerType;
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief a type for a number (unsigned)
 | 
			
		||||
 | 
			
		||||
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
 | 
			
		||||
    > The representation of numbers is similar to that used in most programming
 | 
			
		||||
    > languages. A number is represented in base 10 using decimal digits. It
 | 
			
		||||
    > contains an integer component that may be prefixed with an optional minus
 | 
			
		||||
    > sign, which may be followed by a fraction part and/or an exponent part.
 | 
			
		||||
    > Leading zeros are not allowed. (...) Numeric values that cannot be
 | 
			
		||||
    > represented in the grammar below (such as Infinity and NaN) are not
 | 
			
		||||
    > permitted.
 | 
			
		||||
 | 
			
		||||
    This description includes both integer and floating-point numbers. However,
 | 
			
		||||
    C++ allows more precise storage if it is known whether the number is a 
 | 
			
		||||
    signed integer, an unsigned integer or a floating-point number. Therefore,
 | 
			
		||||
    three different types, @ref number_integer_t,  @ref number_unsigned_t and 
 | 
			
		||||
    @ref number_float_t are used.
 | 
			
		||||
 | 
			
		||||
    To store unsigned integer numbers in C++, a type is defined by the template
 | 
			
		||||
    parameter @a NumberUnsignedType which chooses the type to use.
 | 
			
		||||
 | 
			
		||||
    #### Default type
 | 
			
		||||
 | 
			
		||||
    With the default values for @a NumberUnsignedType (`uint64_t`), the default
 | 
			
		||||
    value for @a number_unsigned_t is:
 | 
			
		||||
 | 
			
		||||
    @code {.cpp}
 | 
			
		||||
    uint64_t
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    #### Default behavior
 | 
			
		||||
 | 
			
		||||
    - The restrictions about leading zeros is not enforced in C++. Instead,
 | 
			
		||||
      leading zeros in integer literals lead to an interpretation as octal
 | 
			
		||||
      number. Internally, the value will be stored as decimal number. For
 | 
			
		||||
      instance, the C++ integer literal `010` will be serialized to `8`. During
 | 
			
		||||
      deserialization, leading zeros yield an error.
 | 
			
		||||
    - Not-a-number (NaN) values will be serialized to `null`.
 | 
			
		||||
 | 
			
		||||
    #### Limits
 | 
			
		||||
 | 
			
		||||
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
 | 
			
		||||
    > An implementation may set limits on the range and precision of numbers.
 | 
			
		||||
 | 
			
		||||
    When the default type is used, the maximal integer number that can be
 | 
			
		||||
    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number
 | 
			
		||||
    that can be stored is `0`. Integer numbers
 | 
			
		||||
    that are out of range will yield over/underflow when used in a constructor.
 | 
			
		||||
    During deserialization, too large or small integer numbers will be
 | 
			
		||||
    automatically be stored as @ref number_integer_t or @ref number_float_t.
 | 
			
		||||
 | 
			
		||||
    [RFC 7159](http://rfc7159.net/rfc7159) further states:
 | 
			
		||||
    > Note that when such software is used, numbers that are integers and are
 | 
			
		||||
    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
 | 
			
		||||
    > that implementations will agree exactly on their numeric values.
 | 
			
		||||
 | 
			
		||||
    As this range is a subrange (when considered in conjunction with the
 | 
			
		||||
    number_integer_t type) of the exactly supported range [0, UINT64_MAX], this 
 | 
			
		||||
    class's integer type is interoperable.
 | 
			
		||||
 | 
			
		||||
    #### Storage
 | 
			
		||||
 | 
			
		||||
    Integer number values are stored directly inside a @ref basic_json type.
 | 
			
		||||
 | 
			
		||||
    @sa @ref number_float_t -- type for number values (floating-point)
 | 
			
		||||
 | 
			
		||||
    @sa @ref number_integer_t -- type for number values (integer)
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    using number_unsigned_t = NumberUnsignedType;
 | 
			
		||||
    
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief a type for a number (floating-point)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -549,9 +628,10 @@ class basic_json
 | 
			
		|||
    > permitted.
 | 
			
		||||
 | 
			
		||||
    This description includes both integer and floating-point numbers. However,
 | 
			
		||||
    C++ allows more precise storage if it is known whether the number is an
 | 
			
		||||
    integer or a floating-point number. Therefore, two different types, @ref
 | 
			
		||||
    number_integer_t and @ref number_float_t are used.
 | 
			
		||||
    C++ allows more precise storage if it is known whether the number is a 
 | 
			
		||||
    signed integer, an unsigned integer or a floating-point number. Therefore,
 | 
			
		||||
    three different types, @ref number_integer_t,  @ref number_unsigned_t and 
 | 
			
		||||
    @ref number_float_t are used.
 | 
			
		||||
 | 
			
		||||
    To store floating-point numbers in C++, a type is defined by the template
 | 
			
		||||
    parameter @a NumberFloatType which chooses the type to use.
 | 
			
		||||
| 
						 | 
				
			
			@ -597,6 +677,8 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @sa @ref number_integer_t -- type for number values (integer)
 | 
			
		||||
 | 
			
		||||
    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
 | 
			
		||||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
    using number_float_t = NumberFloatType;
 | 
			
		||||
| 
						 | 
				
			
			@ -626,6 +708,7 @@ class basic_json
 | 
			
		|||
        string,         ///< string value
 | 
			
		||||
        boolean,        ///< boolean value
 | 
			
		||||
        number_integer, ///< number value (integer)
 | 
			
		||||
        number_unsigned,///< number value (unsigned integer)
 | 
			
		||||
        number_float,   ///< number value (floating-point)
 | 
			
		||||
        discarded       ///< discarded by the the parser callback function
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -669,6 +752,8 @@ class basic_json
 | 
			
		|||
        boolean_t boolean;
 | 
			
		||||
        /// number (integer)
 | 
			
		||||
        number_integer_t number_integer;
 | 
			
		||||
        /// number (unsigned integer)
 | 
			
		||||
        number_unsigned_t number_unsigned;
 | 
			
		||||
        /// number (floating-point)
 | 
			
		||||
        number_float_t number_float;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -678,6 +763,8 @@ class basic_json
 | 
			
		|||
        json_value(boolean_t v) noexcept : boolean(v) {}
 | 
			
		||||
        /// constructor for numbers (integer)
 | 
			
		||||
        json_value(number_integer_t v) noexcept : number_integer(v) {}
 | 
			
		||||
        /// constructor for numbers (unsigned)
 | 
			
		||||
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
 | 
			
		||||
        /// constructor for numbers (floating-point)
 | 
			
		||||
        json_value(number_float_t v) noexcept : number_float(v) {}
 | 
			
		||||
        /// constructor for empty values of a given type
 | 
			
		||||
| 
						 | 
				
			
			@ -714,6 +801,12 @@ class basic_json
 | 
			
		|||
                    number_integer = number_integer_t(0);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                case value_t::number_unsigned:
 | 
			
		||||
                {
 | 
			
		||||
                    number_unsigned = number_unsigned_t(0);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case value_t::number_float:
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -870,6 +963,8 @@ class basic_json
 | 
			
		|||
    (floating-point) value
 | 
			
		||||
    @sa @ref basic_json(const number_integer_t) -- create a number (integer)
 | 
			
		||||
    value
 | 
			
		||||
    @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
 | 
			
		||||
    value
 | 
			
		||||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
| 
						 | 
				
			
			@ -1171,7 +1266,8 @@ class basic_json
 | 
			
		|||
             typename std::enable_if<
 | 
			
		||||
                 not (std::is_same<T, int>::value)
 | 
			
		||||
                 and std::is_same<T, number_integer_t>::value
 | 
			
		||||
                 , int>::type = 0>
 | 
			
		||||
                 , int>::type
 | 
			
		||||
             = 0>
 | 
			
		||||
    basic_json(const number_integer_t val)
 | 
			
		||||
        : m_type(value_t::number_integer), m_value(val)
 | 
			
		||||
    {}
 | 
			
		||||
| 
						 | 
				
			
			@ -1234,13 +1330,74 @@ class basic_json
 | 
			
		|||
    template<typename CompatibleNumberIntegerType, typename
 | 
			
		||||
             std::enable_if<
 | 
			
		||||
                 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
 | 
			
		||||
                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
 | 
			
		||||
                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer and 
 | 
			
		||||
                 std::numeric_limits<CompatibleNumberIntegerType>::is_signed, 
 | 
			
		||||
                 CompatibleNumberIntegerType>::type
 | 
			
		||||
             = 0>
 | 
			
		||||
    basic_json(const CompatibleNumberIntegerType val) noexcept
 | 
			
		||||
        : m_type(value_t::number_integer),
 | 
			
		||||
          m_value(static_cast<number_integer_t>(val))
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief create an unsigned integer number (explicit)
 | 
			
		||||
 | 
			
		||||
    Create an unsigned integer number JSON value with a given content.
 | 
			
		||||
 | 
			
		||||
    @tparam T  helper type to compare number_unsigned_t and unsigned int 
 | 
			
		||||
    (not visible in) the interface.
 | 
			
		||||
 | 
			
		||||
    @param[in] val  an integer to create a JSON number from
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
 | 
			
		||||
    value (unsigned integer) from a compatible number type
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    template<typename T,
 | 
			
		||||
             typename std::enable_if<
 | 
			
		||||
                 not (std::is_same<T, int>::value)
 | 
			
		||||
                 and std::is_same<T, number_unsigned_t>::value
 | 
			
		||||
                 , int>::type
 | 
			
		||||
             = 0>
 | 
			
		||||
    basic_json(const number_unsigned_t val)
 | 
			
		||||
        : m_type(value_t::number_unsigned), m_value(val)
 | 
			
		||||
    {}
 | 
			
		||||
    
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief create an unsigned number (implicit)
 | 
			
		||||
 | 
			
		||||
    Create an unsigned number JSON value with a given content. This constructor
 | 
			
		||||
    allows any type that can be used to construct values of type @ref
 | 
			
		||||
    number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`,
 | 
			
		||||
    or `unsigned short`.
 | 
			
		||||
 | 
			
		||||
    @tparam CompatibleNumberUnsignedType an integer type which is compatible to
 | 
			
		||||
    @ref number_unsigned_t.
 | 
			
		||||
 | 
			
		||||
    @param[in] val  an unsigned integer to create a JSON number from
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @sa @ref basic_json(const number_unsigned_t) -- create a number value
 | 
			
		||||
    (unsigned)
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    template<typename CompatibleNumberUnsignedType, typename
 | 
			
		||||
             std::enable_if<
 | 
			
		||||
                 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
 | 
			
		||||
                 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and 
 | 
			
		||||
                 !std::numeric_limits<CompatibleNumberUnsignedType>::is_signed, 
 | 
			
		||||
                 CompatibleNumberUnsignedType>::type
 | 
			
		||||
             = 0>
 | 
			
		||||
    basic_json(const CompatibleNumberUnsignedType val) noexcept
 | 
			
		||||
        : m_type(value_t::number_unsigned),
 | 
			
		||||
          m_value(static_cast<number_unsigned_t>(val))
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief create a floating-point number (explicit)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1600,6 +1757,7 @@ class basic_json
 | 
			
		|||
            case value_t::boolean:
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            case value_t::number_integer:
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            case value_t::string:
 | 
			
		||||
            {
 | 
			
		||||
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
 | 
			
		||||
| 
						 | 
				
			
			@ -1623,6 +1781,13 @@ class basic_json
 | 
			
		|||
                m_value.number_integer = first.m_object->m_value.number_integer;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            {
 | 
			
		||||
                assert(first.m_object != nullptr);
 | 
			
		||||
                m_value.number_unsigned = first.m_object->m_value.number_unsigned;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -1726,6 +1891,12 @@ class basic_json
 | 
			
		|||
                m_value = other.m_value.number_integer;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            {
 | 
			
		||||
                m_value = other.m_value.number_unsigned;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -2004,15 +2175,17 @@ class basic_json
 | 
			
		|||
    This function returns true iff the JSON value is a number. This includes
 | 
			
		||||
    both integer and floating-point values.
 | 
			
		||||
 | 
			
		||||
    @return `true` if type is number (regardless whether integer or
 | 
			
		||||
    floating-type), `false` otherwise.
 | 
			
		||||
    @return `true` if type is number (regardless whether integer, unsigned
 | 
			
		||||
    integer or floating-type), `false` otherwise.
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @liveexample{The following code exemplifies @ref is_number for all JSON
 | 
			
		||||
    types.,is_number}
 | 
			
		||||
 | 
			
		||||
    @sa @ref is_number_integer() -- check if value is an integer number
 | 
			
		||||
    @sa @ref is_number_integer() -- check if value is an integer or unsigned 
 | 
			
		||||
    integer number
 | 
			
		||||
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer number
 | 
			
		||||
    @sa @ref is_number_float() -- check if value is a floating-point number
 | 
			
		||||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
| 
						 | 
				
			
			@ -2025,10 +2198,11 @@ class basic_json
 | 
			
		|||
    /*!
 | 
			
		||||
    @brief return whether value is an integer number
 | 
			
		||||
 | 
			
		||||
    This function returns true iff the JSON value is an integer number. This
 | 
			
		||||
    excludes floating-point values.
 | 
			
		||||
    This function returns true iff the JSON value is an integer or unsigned 
 | 
			
		||||
    integer number. This excludes floating-point values.
 | 
			
		||||
 | 
			
		||||
    @return `true` if type is an integer number, `false` otherwise.
 | 
			
		||||
    @return `true` if type is an integer or unsigned integer number, `false` 
 | 
			
		||||
    otherwise.
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2036,20 +2210,43 @@ class basic_json
 | 
			
		|||
    JSON types.,is_number_integer}
 | 
			
		||||
 | 
			
		||||
    @sa @ref is_number() -- check if value is a number
 | 
			
		||||
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer number
 | 
			
		||||
    @sa @ref is_number_float() -- check if value is a floating-point number
 | 
			
		||||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
    bool is_number_integer() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return m_type == value_t::number_integer;
 | 
			
		||||
        return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief return whether value is an unsigned integer number
 | 
			
		||||
 | 
			
		||||
    This function returns true iff the JSON value is an unsigned integer number. 
 | 
			
		||||
    This excludes floating-point and (signed) integer values.
 | 
			
		||||
 | 
			
		||||
    @return `true` if type is an unsigned integer number, `false` otherwise.
 | 
			
		||||
 | 
			
		||||
    @complexity Constant.
 | 
			
		||||
 | 
			
		||||
    @sa @ref is_number() -- check if value is a number
 | 
			
		||||
    @sa @ref is_number_integer() -- check if value is an integer or unsigned 
 | 
			
		||||
    integer number
 | 
			
		||||
    @sa @ref is_number_float() -- check if value is a floating-point number
 | 
			
		||||
 | 
			
		||||
    @since version 2.0.0
 | 
			
		||||
    */
 | 
			
		||||
    bool is_number_unsigned() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return m_type == value_t::number_unsigned;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief return whether value is a floating-point number
 | 
			
		||||
 | 
			
		||||
    This function returns true iff the JSON value is a floating-point number.
 | 
			
		||||
    This excludes integer values.
 | 
			
		||||
    This excludes integer and unsigned integer values.
 | 
			
		||||
 | 
			
		||||
    @return `true` if type is a floating-point number, `false` otherwise.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2060,6 +2257,7 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @sa @ref is_number() -- check if value is number
 | 
			
		||||
    @sa @ref is_number_integer() -- check if value is an integer number
 | 
			
		||||
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer number
 | 
			
		||||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
| 
						 | 
				
			
			@ -2327,6 +2525,11 @@ class basic_json
 | 
			
		|||
            {
 | 
			
		||||
                return static_cast<T>(m_value.number_integer);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            {
 | 
			
		||||
                return static_cast<T>(m_value.number_unsigned);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -2412,7 +2615,19 @@ class basic_json
 | 
			
		|||
    {
 | 
			
		||||
        return is_number_integer() ? &m_value.number_integer : nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// get a pointer to the value (unsigned number)
 | 
			
		||||
    number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// get a pointer to the value (unsigned number)
 | 
			
		||||
    const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// get a pointer to the value (floating-point number)
 | 
			
		||||
    number_float_t* get_impl_ptr(number_float_t*) noexcept
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -2510,8 +2725,8 @@ class basic_json
 | 
			
		|||
    @warning The pointer becomes invalid if the underlying JSON object changes.
 | 
			
		||||
 | 
			
		||||
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
 | 
			
		||||
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
 | 
			
		||||
    number_float_t.
 | 
			
		||||
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, 
 | 
			
		||||
    @ref number_unsigned_t, or @ref number_float_t.
 | 
			
		||||
 | 
			
		||||
    @return pointer to the internally stored JSON value if the requested
 | 
			
		||||
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
 | 
			
		||||
| 
						 | 
				
			
			@ -2561,8 +2776,8 @@ class basic_json
 | 
			
		|||
    state.
 | 
			
		||||
 | 
			
		||||
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
 | 
			
		||||
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
 | 
			
		||||
    number_float_t.
 | 
			
		||||
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, 
 | 
			
		||||
    @ref number_unsigned_t, or @ref number_float_t.
 | 
			
		||||
 | 
			
		||||
    @return pointer to the internally stored JSON value if the requested
 | 
			
		||||
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
 | 
			
		||||
| 
						 | 
				
			
			@ -2680,14 +2895,14 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
    @since version 1.0.0
 | 
			
		||||
    */
 | 
			
		||||
    template < typename ValueType, typename
 | 
			
		||||
               std::enable_if <
 | 
			
		||||
                   not std::is_pointer<ValueType>::value
 | 
			
		||||
                   and not std::is_same<ValueType, typename string_t::value_type>::value
 | 
			
		||||
    template<typename ValueType, typename
 | 
			
		||||
             std::enable_if<
 | 
			
		||||
                 not std::is_pointer<ValueType>::value
 | 
			
		||||
                 and not std::is_same<ValueType, typename string_t::value_type>::value
 | 
			
		||||
#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
 | 
			
		||||
                   , int >::type = 0 >
 | 
			
		||||
                 , int>::type = 0>
 | 
			
		||||
    operator ValueType() const
 | 
			
		||||
    {
 | 
			
		||||
        // delegate the call to get<>() const
 | 
			
		||||
| 
						 | 
				
			
			@ -3441,6 +3656,7 @@ class basic_json
 | 
			
		|||
            case value_t::boolean:
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            case value_t::number_integer:
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            case value_t::string:
 | 
			
		||||
            {
 | 
			
		||||
                if (not pos.m_it.primitive_iterator.is_begin())
 | 
			
		||||
| 
						 | 
				
			
			@ -3546,6 +3762,7 @@ class basic_json
 | 
			
		|||
            case value_t::boolean:
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            case value_t::number_integer:
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            case value_t::string:
 | 
			
		||||
            {
 | 
			
		||||
                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
 | 
			
		||||
| 
						 | 
				
			
			@ -4235,6 +4452,12 @@ class basic_json
 | 
			
		|||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            {
 | 
			
		||||
                m_value.number_unsigned = 0;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            {
 | 
			
		||||
                m_value.number_float = 0.0;
 | 
			
		||||
| 
						 | 
				
			
			@ -4773,14 +4996,15 @@ class basic_json
 | 
			
		|||
    */
 | 
			
		||||
    friend bool operator<(const value_t lhs, const value_t rhs)
 | 
			
		||||
    {
 | 
			
		||||
        static constexpr std::array<uint8_t, 7> order = {{
 | 
			
		||||
        static constexpr std::array<uint8_t, 8> order = {{
 | 
			
		||||
                0, // null
 | 
			
		||||
                3, // object
 | 
			
		||||
                4, // array
 | 
			
		||||
                5, // string
 | 
			
		||||
                1, // boolean
 | 
			
		||||
                2, // integer
 | 
			
		||||
                2  // float
 | 
			
		||||
                2, // unsigned
 | 
			
		||||
                2, // float
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4856,6 +5080,10 @@ class basic_json
 | 
			
		|||
                {
 | 
			
		||||
                    return lhs.m_value.number_integer == rhs.m_value.number_integer;
 | 
			
		||||
                }
 | 
			
		||||
                case value_t::number_unsigned:
 | 
			
		||||
                {
 | 
			
		||||
                    return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
 | 
			
		||||
                }
 | 
			
		||||
                case value_t::number_float:
 | 
			
		||||
                {
 | 
			
		||||
                    return lhs.m_value.number_float == rhs.m_value.number_float;
 | 
			
		||||
| 
						 | 
				
			
			@ -4874,6 +5102,23 @@ class basic_json
 | 
			
		|||
        {
 | 
			
		||||
            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
 | 
			
		||||
        {
 | 
			
		||||
            return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
 | 
			
		||||
        {
 | 
			
		||||
            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
 | 
			
		||||
        {
 | 
			
		||||
            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
 | 
			
		||||
        {
 | 
			
		||||
            return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5025,6 +5270,10 @@ class basic_json
 | 
			
		|||
                {
 | 
			
		||||
                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
 | 
			
		||||
                }
 | 
			
		||||
                case value_t::number_unsigned:
 | 
			
		||||
                {
 | 
			
		||||
                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
 | 
			
		||||
                }
 | 
			
		||||
                case value_t::number_float:
 | 
			
		||||
                {
 | 
			
		||||
                    return lhs.m_value.number_float < rhs.m_value.number_float;
 | 
			
		||||
| 
						 | 
				
			
			@ -5037,13 +5286,27 @@ class basic_json
 | 
			
		|||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
 | 
			
		||||
        {
 | 
			
		||||
            return static_cast<number_float_t>(lhs.m_value.number_integer) <
 | 
			
		||||
                   rhs.m_value.number_float;
 | 
			
		||||
            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
 | 
			
		||||
        {
 | 
			
		||||
            return lhs.m_value.number_float <
 | 
			
		||||
                   static_cast<number_float_t>(rhs.m_value.number_integer);
 | 
			
		||||
            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
 | 
			
		||||
        {
 | 
			
		||||
            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
 | 
			
		||||
        {
 | 
			
		||||
            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
 | 
			
		||||
        {
 | 
			
		||||
            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
 | 
			
		||||
        }
 | 
			
		||||
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
 | 
			
		||||
        {
 | 
			
		||||
            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We only reach this line if we cannot compare values. In that case,
 | 
			
		||||
| 
						 | 
				
			
			@ -5608,6 +5871,12 @@ class basic_json
 | 
			
		|||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_unsigned:
 | 
			
		||||
            {
 | 
			
		||||
                o << m_value.number_unsigned;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case value_t::number_float:
 | 
			
		||||
            {
 | 
			
		||||
                // If the number is an integer then output as a fixed with with
 | 
			
		||||
| 
						 | 
				
			
			@ -7059,9 +7328,9 @@ class basic_json
 | 
			
		|||
        @brief parse floating point number
 | 
			
		||||
 | 
			
		||||
        This function (and its overloads) serves to select the most approprate
 | 
			
		||||
        standard floating point number parsing function (i.e., `std::strtof`,
 | 
			
		||||
        `std::strtod`, or `std::strtold`) based on the type supplied via the
 | 
			
		||||
        first parameter. Set this to @a static_cast<number_float_t>(nullptr).
 | 
			
		||||
        standard floating point number parsing function based on the type
 | 
			
		||||
        supplied via the first parameter.  Set this to
 | 
			
		||||
        @a static_cast<number_float_t*>(nullptr).
 | 
			
		||||
 | 
			
		||||
        @param[in] type  the @ref number_float_t in use
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7080,45 +7349,135 @@ class basic_json
 | 
			
		|||
            return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// @copydoc str_to_float_t
 | 
			
		||||
        double str_to_float_t(double*, char** endptr) const
 | 
			
		||||
        /*!
 | 
			
		||||
        @brief parse floating point number
 | 
			
		||||
 | 
			
		||||
        This function (and its overloads) serves to select the most approprate
 | 
			
		||||
        standard floating point number parsing function based on the type
 | 
			
		||||
        supplied via the first parameter.  Set this to
 | 
			
		||||
        @a static_cast<number_float_t*>(nullptr).
 | 
			
		||||
 | 
			
		||||
        @param type  the @ref number_float_t in use
 | 
			
		||||
 | 
			
		||||
        @param endptr  recieves a pointer to the first character after the number
 | 
			
		||||
 | 
			
		||||
        @return the floating point number
 | 
			
		||||
        */
 | 
			
		||||
        double str_to_float_t(double* /* type */, char** endptr) const
 | 
			
		||||
        {
 | 
			
		||||
            return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// @copydoc str_to_float_t
 | 
			
		||||
        float str_to_float_t(float*, char** endptr) const
 | 
			
		||||
        /*!
 | 
			
		||||
        @brief parse floating point number
 | 
			
		||||
 | 
			
		||||
        This function (and its overloads) serves to select the most approprate
 | 
			
		||||
        standard floating point number parsing function based on the type
 | 
			
		||||
        supplied via the first parameter.  Set this to
 | 
			
		||||
        @a static_cast<number_float_t*>(nullptr).
 | 
			
		||||
 | 
			
		||||
        @param type  the @ref number_float_t in use
 | 
			
		||||
 | 
			
		||||
        @param endptr  recieves a pointer to the first character after the number
 | 
			
		||||
 | 
			
		||||
        @return the floating point number
 | 
			
		||||
        */
 | 
			
		||||
        float str_to_float_t(float* /* type */, char** endptr) const
 | 
			
		||||
        {
 | 
			
		||||
            return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*!
 | 
			
		||||
        @brief static_cast between two types and indicate if it results in error
 | 
			
		||||
 | 
			
		||||
        This function performs a static_cast between @a source and @a dest.  It 
 | 
			
		||||
        then checks if a static_cast back to @a dest produces an error.
 | 
			
		||||
 | 
			
		||||
        @param[in] source  the value to cast from 
 | 
			
		||||
 | 
			
		||||
        @param[out] dest  the value to cast to
 | 
			
		||||
 | 
			
		||||
        @return @a true if the cast was performed without error, @a false otherwise
 | 
			
		||||
        */
 | 
			
		||||
        template <typename T_A, typename T_B>
 | 
			
		||||
        bool attempt_cast(T_A source, T_B & dest) const
 | 
			
		||||
        {
 | 
			
		||||
            dest = static_cast<T_B>(source);
 | 
			
		||||
            return (source == static_cast<T_A>(dest));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*!
 | 
			
		||||
        @brief return number value for number tokens
 | 
			
		||||
 | 
			
		||||
        This function translates the last token into a floating point number.
 | 
			
		||||
        The pointer m_start points to the beginning of the parsed number. We
 | 
			
		||||
        pass this pointer to std::strtod which sets endptr to the first
 | 
			
		||||
        character past the converted number. If this pointer is not the same as
 | 
			
		||||
        m_cursor, then either more or less characters have been used during the
 | 
			
		||||
        comparison. This can happen for inputs like "01" which will be treated
 | 
			
		||||
        like number 0 followed by number 1.
 | 
			
		||||
        This function translates the last token into the most appropriate 
 | 
			
		||||
        number type (either integer, unsigned integer or floating point), 
 | 
			
		||||
        which is passed back to the caller via the result parameter. The pointer 
 | 
			
		||||
        @a m_start points to the beginning of the parsed number. We first examine
 | 
			
		||||
        the first character to determine the sign of the number and then pass
 | 
			
		||||
        this pointer to either @a std::strtoull (if positive) or @a std::strtoll
 | 
			
		||||
        (if negative), both of which set @a endptr to the first character past the 
 | 
			
		||||
        converted number. If this pointer is not the same as @a m_cursor, then 
 | 
			
		||||
        either more or less characters have been used during the comparison. 
 | 
			
		||||
        
 | 
			
		||||
        This can happen for inputs like "01" which will be treated like number 0 
 | 
			
		||||
        followed by number 1.  This will also occur for valid floating point 
 | 
			
		||||
        inputs like "12e3" will be incorrectly read as 12.  Numbers that are too
 | 
			
		||||
        large or too small for a signed/unsigned long long will cause a range
 | 
			
		||||
        error (@a errno set to ERANGE). The parsed number is cast to a @ref
 | 
			
		||||
        number_integer_t/@ref number_unsigned_t using the helper function @ref attempt_cast,
 | 
			
		||||
        which returns @a false if the cast could not be peformed without error.
 | 
			
		||||
 | 
			
		||||
        @return the result of the number conversion or NAN if the conversion
 | 
			
		||||
        read past the current token. The latter case needs to be treated by the
 | 
			
		||||
        caller function.
 | 
			
		||||
        In any of these cases (more/less characters read, range error or a cast
 | 
			
		||||
        error) the pointer is passed to @a std:strtod, which also sets @a endptr to the
 | 
			
		||||
        first character past the converted number. The resulting @ref number_float_t 
 | 
			
		||||
        is then cast to a @ref number_integer_t/@ref number_unsigned_t using
 | 
			
		||||
        @ref attempt_cast and if no error occurs is stored in that form, otherwise
 | 
			
		||||
        it is stored as a @ref number_float_t.
 | 
			
		||||
        
 | 
			
		||||
        A final comparison is made of @a endptr and if still not the same as 
 | 
			
		||||
        @ref m_cursor a bad input is assumed and @a result parameter is set to NAN.        
 | 
			
		||||
 | 
			
		||||
        @throw std::range_error if passed value is out of range
 | 
			
		||||
        @param[out] result  @ref basic_json object to receive the number, or NAN if the
 | 
			
		||||
        conversion read past the current token. The latter case needs to be 
 | 
			
		||||
        treated by the caller function.
 | 
			
		||||
        */
 | 
			
		||||
        number_float_t get_number() const
 | 
			
		||||
        void get_number(basic_json& result) const
 | 
			
		||||
        {
 | 
			
		||||
            // conversion
 | 
			
		||||
            typename string_t::value_type* endptr;
 | 
			
		||||
            assert(m_start != nullptr);
 | 
			
		||||
            number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
 | 
			
		||||
            errno = 0;
 | 
			
		||||
            
 | 
			
		||||
            // Attempt to parse it as an integer - first checking for a negative number
 | 
			
		||||
            if (*reinterpret_cast<typename string_t::const_pointer>(m_start) != '-')
 | 
			
		||||
            {
 | 
			
		||||
                // Positive, parse with strtoull and attempt cast to number_unsigned_t
 | 
			
		||||
                if (attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
 | 
			
		||||
                    result.m_type = value_t::number_unsigned;
 | 
			
		||||
                else result.m_type = value_t::number_float;  // Cast failed due to overflow - store as float
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Negative, parse with strtoll and attempt cast to number_integer_t
 | 
			
		||||
                if (attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
 | 
			
		||||
                    result.m_type = value_t::number_integer;
 | 
			
		||||
                else result.m_type = value_t::number_float;  // Cast failed due to overflow - store as float
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // return float_val if the whole number was translated and NAN
 | 
			
		||||
            // otherwise
 | 
			
		||||
            return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
 | 
			
		||||
            // Check the end of the number was reached and no range error occurred
 | 
			
		||||
            if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
 | 
			
		||||
 | 
			
		||||
            if (result.m_type  == value_t::number_float)
 | 
			
		||||
            {
 | 
			
		||||
                // Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was 
 | 
			
		||||
                // something else after the number, which could be an exponent
 | 
			
		||||
                
 | 
			
		||||
                // Parse with strtod
 | 
			
		||||
                result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
 | 
			
		||||
 | 
			
		||||
                // Anything after the number is an error
 | 
			
		||||
                if(reinterpret_cast<lexer_char_t*>(endptr) != m_cursor) 
 | 
			
		||||
                    throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      private:
 | 
			
		||||
| 
						 | 
				
			
			@ -7348,32 +7707,8 @@ class basic_json
 | 
			
		|||
 | 
			
		||||
                case lexer::token_type::value_number:
 | 
			
		||||
                {
 | 
			
		||||
                    result.m_value = m_lexer.get_number();
 | 
			
		||||
 | 
			
		||||
                    // NAN is returned if token could not be translated
 | 
			
		||||
                    // completely
 | 
			
		||||
                    if (std::isnan(result.m_value.number_float))
 | 
			
		||||
                    {
 | 
			
		||||
                        throw std::invalid_argument(std::string("parse error - ") +
 | 
			
		||||
                                                    m_lexer.get_token() + " is not a number");
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    m_lexer.get_number(result);
 | 
			
		||||
                    get_token();
 | 
			
		||||
 | 
			
		||||
                    // 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);
 | 
			
		||||
                    if (result.m_value.number_float == static_cast<number_float_t>(int_val) and
 | 
			
		||||
                            result.m_value.number_integer != json_value(-0.0f).number_integer)
 | 
			
		||||
                    {
 | 
			
		||||
                        // we would not lose precision -> return int
 | 
			
		||||
                        result.m_type = value_t::number_integer;
 | 
			
		||||
                        result.m_value = int_val;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // we would lose precision -> return float
 | 
			
		||||
                        result.m_type = value_t::number_float;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7513,3 +7848,5 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1307
									
								
								test/unit.cpp
									
										
									
									
									
								
							
							
						
						
									
										1307
									
								
								test/unit.cpp
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue