2017-07-18 05:37:27 +02:00
/*
__ _____ _____ _____
__ | | __ | | | | JSON for Modern C + +
2018-05-19 21:59:03 +02:00
| | | __ | | | | | | version 3.1 .2
2017-07-18 05:37:27 +02:00
| _____ | _____ | _____ | _ | ___ | https : //github.com/nlohmann/json
Licensed under the MIT License < http : //opensource.org/licenses/MIT>.
2018-05-19 21:59:03 +02:00
Copyright ( c ) 2013 - 2018 Niels Lohmann < http : //nlohmann.me>.
2017-07-18 05:37:27 +02:00
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_JSON_HPP
# define NLOHMANN_JSON_HPP
2018-05-19 21:59:03 +02:00
# define NLOHMANN_JSON_VERSION_MAJOR 3
# define NLOHMANN_JSON_VERSION_MINOR 1
# define NLOHMANN_JSON_VERSION_PATCH 2
# include <algorithm> // all_of, find, for_each
2017-07-18 05:37:27 +02:00
# include <cassert> // assert
# include <ciso646> // and, not, or
# include <cstddef> // nullptr_t, ptrdiff_t, size_t
2018-05-19 21:59:03 +02:00
# include <functional> // hash, less
2017-07-18 05:37:27 +02:00
# include <initializer_list> // initializer_list
2018-05-19 21:59:03 +02:00
# include <iosfwd> // istream, ostream
# include <iterator> // iterator_traits, random_access_iterator_tag
2017-07-18 05:37:27 +02:00
# include <numeric> // accumulate
2018-05-19 21:59:03 +02:00
# include <string> // string, stoi, to_string
# include <utility> // declval, forward, move, pair, swap
// #include <nlohmann/json_fwd.hpp>
# ifndef NLOHMANN_JSON_FWD_HPP
# define NLOHMANN_JSON_FWD_HPP
# include <cstdint> // int64_t, uint64_t
# include <map> // map
# include <memory> // allocator
# include <string> // string
2017-07-18 05:37:27 +02:00
# include <vector> // vector
2018-05-19 21:59:03 +02:00
/*!
@ brief namespace for Niels Lohmann
@ see https : //github.com/nlohmann
@ since version 1.0 .0
*/
namespace nlohmann
{
/*!
@ brief default JSONSerializer template argument
This serializer ignores the template arguments and uses ADL
( [ argument - dependent lookup ] ( http : //en.cppreference.com/w/cpp/language/adl))
for serialization .
*/
template < typename = void , typename = void >
struct adl_serializer ;
template < template < typename U , typename V , typename . . . Args > class ObjectType =
std : : map ,
template < typename U , typename . . . Args > class ArrayType = std : : vector ,
class StringType = std : : string , class BooleanType = bool ,
class NumberIntegerType = std : : int64_t ,
class NumberUnsignedType = std : : uint64_t ,
class NumberFloatType = double ,
template < typename U > class AllocatorType = std : : allocator ,
template < typename T , typename SFINAE = void > class JSONSerializer =
adl_serializer >
class basic_json ;
/*!
@ brief JSON Pointer
A JSON pointer defines a string syntax for identifying a specific value
within a JSON document . It can be used with functions ` at ` and
` operator [ ] ` . Furthermore , JSON pointers are the base for JSON patches .
@ sa [ RFC 6901 ] ( https : //tools.ietf.org/html/rfc6901)
@ since version 2.0 .0
*/
template < typename BasicJsonType >
class json_pointer ;
/*!
@ brief default JSON class
This type is the default specialization of the @ ref basic_json class which
uses the standard template types .
@ since version 1.0 .0
*/
using json = basic_json < > ;
}
# endif
// #include <nlohmann/detail/macro_scope.hpp>
// This file contains all internal macro definitions
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
2017-07-18 05:37:27 +02:00
// exclude unsupported compilers
# if defined(__clang__)
# if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
# error "unsupported Clang version - see https: //github.com/nlohmann/json#supported-compilers"
# endif
2018-05-19 21:59:03 +02:00
# elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
2017-07-18 05:37:27 +02:00
# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
# error "unsupported GCC version - see https: //github.com/nlohmann/json#supported-compilers"
# 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
// disable documentation warnings on clang
# if defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdocumentation"
# endif
// allow for portable deprecation warnings
# if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
# define JSON_DEPRECATED __attribute__((deprecated))
# elif defined(_MSC_VER)
# define JSON_DEPRECATED __declspec(deprecated)
# else
# define JSON_DEPRECATED
# endif
// allow to disable exceptions
2018-05-19 21:59:03 +02:00
# if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
2017-07-18 05:37:27 +02:00
# define JSON_THROW(exception) throw exception
# define JSON_TRY try
# define JSON_CATCH(exception) catch(exception)
# else
# define JSON_THROW(exception) std::abort()
# define JSON_TRY if(true)
# define JSON_CATCH(exception) if(false)
# endif
2018-05-19 21:59:03 +02:00
// override exception macros
# if defined(JSON_THROW_USER)
# undef JSON_THROW
# define JSON_THROW JSON_THROW_USER
# endif
# if defined(JSON_TRY_USER)
# undef JSON_TRY
# define JSON_TRY JSON_TRY_USER
# endif
# if defined(JSON_CATCH_USER)
# undef JSON_CATCH
# define JSON_CATCH JSON_CATCH_USER
# endif
2017-07-18 05:37:27 +02:00
// manual branch prediction
# if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
# define JSON_LIKELY(x) __builtin_expect(!!(x), 1)
# define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
# else
# define JSON_LIKELY(x) x
# define JSON_UNLIKELY(x) x
# endif
2018-05-19 21:59:03 +02:00
// C++ language standard detection
# if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
# define JSON_HAS_CPP_17
# define JSON_HAS_CPP_14
# elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
# define JSON_HAS_CPP_14
# endif
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
// may be removed in the future once the class is split.
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
template < template < typename , typename , typename . . . > class ObjectType , \
template < typename , typename . . . > class ArrayType , \
class StringType , class BooleanType , class NumberIntegerType , \
class NumberUnsignedType , class NumberFloatType , \
template < typename > class AllocatorType , \
template < typename , typename = void > class JSONSerializer >
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# define NLOHMANN_BASIC_JSON_TPL \
basic_json < ObjectType , ArrayType , StringType , BooleanType , \
NumberIntegerType , NumberUnsignedType , NumberFloatType , \
AllocatorType , JSONSerializer >
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief Helper to determine whether there ' s a key_type for T .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This helper is used to tell associative containers apart from other containers
such as sequence containers . For instance , ` std : : map ` passes the test as it
contains a ` mapped_type ` , whereas ` std : : vector ` fails the test .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa http : //stackoverflow.com/a/7728728/266378
@ since version 1.0 .0 , overworked in version 2.0 .6
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
# define NLOHMANN_JSON_HAS_HELPER(type) \
template < typename T > struct has_ # # type { \
private : \
template < typename U , typename = typename U : : type > \
static int detect ( U & & ) ; \
static void detect ( . . . ) ; \
public : \
static constexpr bool value = \
std : : is_integral < decltype ( detect ( std : : declval < T > ( ) ) ) > : : value ; \
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/meta.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <ciso646> // not
# include <cstddef> // size_t
# include <limits> // numeric_limits
# include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
# include <utility> // declval
// #include <nlohmann/json_fwd.hpp>
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief detail namespace with internal helper functions
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This namespace collects functions that should not be exposed ,
implementations of some @ ref basic_json methods , and meta - programming helpers .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.1 .0
*/
namespace detail
{
/////////////
// helpers //
/////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename > struct is_basic_json : std : : false_type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct is_basic_json < NLOHMANN_BASIC_JSON_TPL > : std : : true_type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// alias templates to reduce boilerplate
template < bool B , typename T = void >
using enable_if_t = typename std : : enable_if < B , T > : : type ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename T >
using uncvref_t = typename std : : remove_cv < typename std : : remove_reference < T > : : type > : : type ;
// implementation of C++14 index_sequence and affiliates
// source: https://stackoverflow.com/a/32223343
template < std : : size_t . . . Ints >
struct index_sequence
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
using type = index_sequence ;
using value_type = std : : size_t ;
static constexpr std : : size_t size ( ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return sizeof . . . ( Ints ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < class Sequence1 , class Sequence2 >
struct merge_and_renumber ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < std : : size_t . . . I1 , std : : size_t . . . I2 >
struct merge_and_renumber < index_sequence < I1 . . . > , index_sequence < I2 . . . > >
: index_sequence < I1 . . . , ( sizeof . . . ( I1 ) + I2 ) . . . > { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < std : : size_t N >
struct make_index_sequence
: merge_and_renumber < typename make_index_sequence < N / 2 > : : type ,
typename make_index_sequence < N - N / 2 > : : type > { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < > struct make_index_sequence < 0 > : index_sequence < > { } ;
template < > struct make_index_sequence < 1 > : index_sequence < 0 > { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename . . . Ts >
using index_sequence_for = make_index_sequence < sizeof . . . ( Ts ) > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*
Implementation of two C + + 17 constructs : conjunction , negation . This is needed
to avoid evaluating all the traits in a condition
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
For example : not std : : is_same < void , T > : : value and has_value_type < T > : : value
will not compile when T = void ( on MSVC at least ) . Whereas
conjunction < negation < std : : is_same < void , T > > , has_value_type < T > > : : value will
stop evaluating if negation < . . . > : : value = = false
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Please note that those constructs must be used with caution , since symbols can
become very long quickly ( which can slow down compilation and cause MSVC
internal compiler errors ) . Only use it when you have to ( see example ahead ) .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < class . . . > struct conjunction : std : : true_type { } ;
template < class B1 > struct conjunction < B1 > : B1 { } ;
template < class B1 , class . . . Bn >
struct conjunction < B1 , Bn . . . > : std : : conditional < bool ( B1 : : value ) , conjunction < Bn . . . > , B1 > : : type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < class B > struct negation : std : : integral_constant < bool , not B : : value > { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// dispatch utility (taken from ranges-v3)
template < unsigned N > struct priority_tag : priority_tag < N - 1 > { } ;
template < > struct priority_tag < 0 > { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
////////////////////////
// has_/is_ functions //
////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// source: https://stackoverflow.com/a/37193089/4116453
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename T , typename = void >
struct is_complete_type : std : : false_type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename T >
struct is_complete_type < T , decltype ( void ( sizeof ( T ) ) ) > : std : : true_type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
NLOHMANN_JSON_HAS_HELPER ( mapped_type ) ;
NLOHMANN_JSON_HAS_HELPER ( key_type ) ;
NLOHMANN_JSON_HAS_HELPER ( value_type ) ;
NLOHMANN_JSON_HAS_HELPER ( iterator ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < bool B , class RealType , class CompatibleObjectType >
struct is_compatible_object_type_impl : std : : false_type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < class RealType , class CompatibleObjectType >
struct is_compatible_object_type_impl < true , RealType , CompatibleObjectType >
{
static constexpr auto value =
std : : is_constructible < typename RealType : : key_type , typename CompatibleObjectType : : key_type > : : value and
std : : is_constructible < typename RealType : : mapped_type , typename CompatibleObjectType : : mapped_type > : : value ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < class BasicJsonType , class CompatibleObjectType >
struct is_compatible_object_type
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
static auto constexpr value = is_compatible_object_type_impl <
conjunction < negation < std : : is_same < void , CompatibleObjectType > > ,
has_mapped_type < CompatibleObjectType > ,
has_key_type < CompatibleObjectType > > : : value ,
typename BasicJsonType : : object_t , CompatibleObjectType > : : value ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T >
struct is_basic_json_nested_type
{
static auto constexpr value = std : : is_same < T , typename BasicJsonType : : iterator > : : value or
std : : is_same < T , typename BasicJsonType : : const_iterator > : : value or
std : : is_same < T , typename BasicJsonType : : reverse_iterator > : : value or
std : : is_same < T , typename BasicJsonType : : const_reverse_iterator > : : value ;
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
template < class BasicJsonType , class CompatibleArrayType >
struct is_compatible_array_type
{
static auto constexpr value =
conjunction < negation < std : : is_same < void , CompatibleArrayType > > ,
negation < is_compatible_object_type <
BasicJsonType , CompatibleArrayType > > ,
negation < std : : is_constructible < typename BasicJsonType : : string_t ,
CompatibleArrayType > > ,
negation < is_basic_json_nested_type < BasicJsonType , CompatibleArrayType > > ,
has_value_type < CompatibleArrayType > ,
has_iterator < CompatibleArrayType > > : : value ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < bool , typename , typename >
struct is_compatible_integer_type_impl : std : : false_type { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename RealIntegerType , typename CompatibleNumberIntegerType >
struct is_compatible_integer_type_impl < true , RealIntegerType , CompatibleNumberIntegerType >
{
// is there an assert somewhere on overflows?
using RealLimits = std : : numeric_limits < RealIntegerType > ;
using CompatibleLimits = std : : numeric_limits < CompatibleNumberIntegerType > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static constexpr auto value =
std : : is_constructible < RealIntegerType , CompatibleNumberIntegerType > : : value and
CompatibleLimits : : is_integer and
RealLimits : : is_signed = = CompatibleLimits : : is_signed ;
} ;
template < typename RealIntegerType , typename CompatibleNumberIntegerType >
struct is_compatible_integer_type
{
static constexpr auto value =
is_compatible_integer_type_impl <
std : : is_integral < CompatibleNumberIntegerType > : : value and
not std : : is_same < bool , CompatibleNumberIntegerType > : : value ,
RealIntegerType , CompatibleNumberIntegerType > : : value ;
} ;
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template < typename BasicJsonType , typename T >
struct has_from_json
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
private :
// also check the return type of from_json
template < typename U , typename = enable_if_t < std : : is_same < void , decltype ( uncvref_t < U > : : from_json (
std : : declval < BasicJsonType > ( ) , std : : declval < T & > ( ) ) ) > : : value > >
static int detect ( U & & ) ;
static void detect ( . . . ) ;
2017-07-18 05:37:27 +02:00
public :
2018-05-19 21:59:03 +02:00
static constexpr bool value = std : : is_integral < decltype (
detect ( std : : declval < typename BasicJsonType : : template json_serializer < T , void > > ( ) ) ) > : : value ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
template < typename BasicJsonType , typename T >
struct has_non_default_from_json
{
2017-07-18 05:37:27 +02:00
private :
2018-05-19 21:59:03 +02:00
template <
typename U ,
typename = enable_if_t < std : : is_same <
T , decltype ( uncvref_t < U > : : from_json ( std : : declval < BasicJsonType > ( ) ) ) > : : value > >
static int detect ( U & & ) ;
static void detect ( . . . ) ;
public :
static constexpr bool value = std : : is_integral < decltype ( detect (
std : : declval < typename BasicJsonType : : template json_serializer < T , void > > ( ) ) ) > : : value ;
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template < typename BasicJsonType , typename T >
struct has_to_json
{
private :
template < typename U , typename = decltype ( uncvref_t < U > : : to_json (
std : : declval < BasicJsonType & > ( ) , std : : declval < T > ( ) ) ) >
static int detect ( U & & ) ;
static void detect ( . . . ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
static constexpr bool value = std : : is_integral < decltype ( detect (
std : : declval < typename BasicJsonType : : template json_serializer < T , void > > ( ) ) ) > : : value ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleCompleteType >
struct is_compatible_complete_type
{
static constexpr bool value =
not std : : is_base_of < std : : istream , CompatibleCompleteType > : : value and
not is_basic_json < CompatibleCompleteType > : : value and
not is_basic_json_nested_type < BasicJsonType , CompatibleCompleteType > : : value and
has_to_json < BasicJsonType , CompatibleCompleteType > : : value ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleType >
struct is_compatible_type
: conjunction < is_complete_type < CompatibleType > ,
is_compatible_complete_type < BasicJsonType , CompatibleType > >
{
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// taken from ranges-v3
template < typename T >
struct static_const
{
static constexpr T value { } ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename T >
constexpr T static_const < T > : : value ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/exceptions.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <exception> // exception
# include <stdexcept> // runtime_error
# include <string> // to_string
namespace nlohmann
{
namespace detail
{
////////////////
// exceptions //
////////////////
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief general exception of the @ ref basic_json class
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This class is an extension of ` std : : exception ` objects with a member @ a id for
exception ids . It is used as the base class for all exceptions thrown by the
@ ref basic_json class . This class can hence be used as " wildcard " to catch
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Subclasses :
- @ ref parse_error for exceptions indicating a parse error
- @ ref invalid_iterator for exceptions indicating errors with iterators
- @ ref type_error for exceptions indicating executing a member function with
a wrong type
- @ ref out_of_range for exceptions indicating access out of the defined range
- @ ref other_error for exceptions indicating other library errors
@ internal
@ note To have nothrow - copy - constructible exceptions , we internally use
` std : : runtime_error ` which can cope with arbitrary - length error messages .
Intermediate strings are built with static functions and then passed to
the actual constructor .
@ endinternal
@ liveexample { The following code shows how arbitrary library exceptions can be
caught . , exception }
@ since version 3.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
class exception : public std : : exception
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
public :
/// returns the explanatory string
const char * what ( ) const noexcept override
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m . what ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// the id of the exception
const int id ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
protected :
exception ( int id_ , const char * what_arg ) : id ( id_ ) , m ( what_arg ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static std : : string name ( const std : : string & ename , int id_ )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return " [json.exception. " + ename + " . " + std : : to_string ( id_ ) + " ] " ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
/// an exception object as storage for error messages
std : : runtime_error m ;
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
/*!
@ brief exception indicating a parse error
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This exception is thrown by the library when a parse error occurs . Parse errors
can occur during the deserialization of JSON text , CBOR , MessagePack , as well
as when using JSON Patch .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Member @ a byte holds the byte index of the last read character in the input
file .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exceptions have ids 1 xx .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
name / id | example message | description
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
json . exception . parse_error .101 | parse error at 2 : unexpected end of input ; expected string literal | This error indicates a syntax error while deserializing a JSON text . The error message describes that an unexpected token ( character ) was encountered , and the member @ a byte indicates the error position .
json . exception . parse_error .102 | parse error at 14 : missing or wrong low surrogate | JSON uses the ` \ uxxxx ` format to describe Unicode characters . Code points above above 0xFFFF are split into two ` \ uxxxx ` entries ( " surrogate pairs " ) . This error indicates that the surrogate pair is incomplete or contains an invalid code point .
json . exception . parse_error .103 | parse error : code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF . Code points above 0x10FFFF are invalid .
json . exception . parse_error .104 | parse error : JSON patch must be an array of objects | [ RFC 6902 ] ( https : //tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.
json . exception . parse_error .105 | parse error : operation must have string member ' op ' | An operation of a JSON Patch document must contain exactly one " op " member , whose value indicates the operation to perform . Its value must be one of " add " , " remove " , " replace " , " move " , " copy " , or " test " ; other values are errors .
json . exception . parse_error .106 | parse error : array index ' 01 ' must not begin with ' 0 ' | An array index in a JSON Pointer ( [ RFC 6901 ] ( https : //tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.
json . exception . parse_error .107 | parse error : JSON pointer must be empty or begin with ' / ' - was : ' foo ' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens , each prefixed by a ` / ` character .
json . exception . parse_error .108 | parse error : escape character ' ~ ' must be followed with ' 0 ' or ' 1 ' | In a JSON Pointer , only ` ~ 0 ` and ` ~ 1 ` are valid escape sequences .
json . exception . parse_error .109 | parse error : array index ' one ' is not a number | A JSON Pointer array index must be a number .
json . exception . parse_error .110 | parse error at 1 : cannot read 2 bytes from vector | When parsing CBOR or MessagePack , the byte vector ends before the complete value has been read .
json . exception . parse_error .112 | parse error at 1 : error reading CBOR ; last byte : 0xF8 | Not all types of CBOR or MessagePack are supported . This exception occurs if an unsupported byte was read .
json . exception . parse_error .113 | parse error at 2 : expected a CBOR string ; last byte : 0x98 | While parsing a map key , a value that is not a string has been read .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note For an input with n bytes , 1 is the index of the first character and n + 1
is the index of the terminating null byte or the end of file . This also
holds true when reading a byte vector ( CBOR or MessagePack ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows how a ` parse_error ` exception can be
caught . , parse_error }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref exception for the base class of the library exceptions
@ sa @ ref invalid_iterator for exceptions indicating errors with iterators
@ sa @ ref type_error for exceptions indicating executing a member function with
a wrong type
@ sa @ ref out_of_range for exceptions indicating access out of the defined range
@ sa @ ref other_error for exceptions indicating other library errors
@ since version 3.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
class parse_error : public exception
{
public :
/*!
@ brief create a parse error exception
@ param [ in ] id_ the id of the exception
@ param [ in ] byte_ the byte index where the error occurred ( or 0 if the
position cannot be determined )
@ param [ in ] what_arg the explanatory string
@ return parse_error object
*/
static parse_error create ( int id_ , std : : size_t byte_ , const std : : string & what_arg )
{
std : : string w = exception : : name ( " parse_error " , id_ ) + " parse error " +
( byte_ ! = 0 ? ( " at " + std : : to_string ( byte_ ) ) : " " ) +
" : " + what_arg ;
return parse_error ( id_ , byte_ , w . c_str ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief byte index of the parse error
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The byte index of the last read character in the input file .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note For an input with n bytes , 1 is the index of the first character and
n + 1 is the index of the terminating null byte or the end of file .
This also holds true when reading a byte vector ( CBOR or MessagePack ) .
*/
const std : : size_t byte ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
parse_error ( int id_ , std : : size_t byte_ , const char * what_arg )
: exception ( id_ , what_arg ) , byte ( byte_ ) { }
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief exception indicating errors with iterators
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This exception is thrown if iterators passed to a library function do not match
the expected semantics .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exceptions have ids 2 xx .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
name / id | example message | description
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
json . exception . invalid_iterator .201 | iterators are not compatible | The iterators passed to constructor @ ref basic_json ( InputIT first , InputIT last ) are not compatible , meaning they do not belong to the same container . Therefore , the range ( @ a first , @ a last ) is invalid .
json . exception . invalid_iterator .202 | iterator does not fit current value | In an erase or insert function , the passed iterator @ a pos does not belong to the JSON value for which the function was called . It hence does not define a valid position for the deletion / insertion .
json . exception . invalid_iterator .203 | iterators do not fit current value | Either iterator passed to function @ ref erase ( IteratorType first , IteratorType last ) does not belong to the JSON value from which values shall be erased . It hence does not define a valid range to delete values from .
json . exception . invalid_iterator .204 | iterators out of range | When an iterator range for a primitive type ( number , boolean , or string ) is passed to a constructor or an erase function , this range has to be exactly ( @ ref begin ( ) , @ ref end ( ) ) , because this is the only way the single stored value is expressed . All other ranges are invalid .
json . exception . invalid_iterator .205 | iterator out of range | When an iterator for a primitive type ( number , boolean , or string ) is passed to an erase function , the iterator has to be the @ ref begin ( ) iterator , because it is the only way to address the stored value . All other iterators are invalid .
json . exception . invalid_iterator .206 | cannot construct with iterators from null | The iterators passed to constructor @ ref basic_json ( InputIT first , InputIT last ) belong to a JSON null value and hence to not define a valid range .
json . exception . invalid_iterator .207 | cannot use key ( ) for non - object iterators | The key ( ) member function can only be used on iterators belonging to a JSON object , because other types do not have a concept of a key .
json . exception . invalid_iterator .208 | cannot use operator [ ] for object iterators | The operator [ ] to specify a concrete offset cannot be used on iterators belonging to a JSON object , because JSON objects are unordered .
json . exception . invalid_iterator .209 | cannot use offsets with object iterators | The offset operators ( + , - , + = , - = ) cannot be used on iterators belonging to a JSON object , because JSON objects are unordered .
json . exception . invalid_iterator .210 | iterators do not fit | The iterator range passed to the insert function are not compatible , meaning they do not belong to the same container . Therefore , the range ( @ a first , @ a last ) is invalid .
json . exception . invalid_iterator .211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to .
json . exception . invalid_iterator .212 | cannot compare iterators of different containers | When two iterators are compared , they must belong to the same container .
json . exception . invalid_iterator .213 | cannot compare order of object iterators | The order of object iterators cannot be compared , because JSON objects are unordered .
json . exception . invalid_iterator .214 | cannot get value | Cannot get value for iterator : Either the iterator belongs to a null value or it is an iterator to a primitive type ( number , boolean , or string ) , but the iterator is different to @ ref begin ( ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows how an ` invalid_iterator ` exception can be
caught . , invalid_iterator }
@ sa @ ref exception for the base class of the library exceptions
@ sa @ ref parse_error for exceptions indicating a parse error
@ sa @ ref type_error for exceptions indicating executing a member function with
a wrong type
@ sa @ ref out_of_range for exceptions indicating access out of the defined range
@ sa @ ref other_error for exceptions indicating other library errors
@ since version 3.0 .0
*/
class invalid_iterator : public exception
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
public :
static invalid_iterator create ( int id_ , const std : : string & what_arg )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : string w = exception : : name ( " invalid_iterator " , id_ ) + what_arg ;
return invalid_iterator ( id_ , w . c_str ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
invalid_iterator ( int id_ , const char * what_arg )
: exception ( id_ , what_arg ) { }
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
/*!
@ brief exception indicating executing a member function with a wrong type
This exception is thrown in case of a type error ; that is , a library function is
executed on a JSON value whose type does not match the expected semantics .
Exceptions have ids 3 xx .
name / id | example message | description
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
json . exception . type_error .301 | cannot create object from initializer list | To create an object from an initializer list , the initializer list must consist only of a list of pairs whose first element is a string . When this constraint is violated , an array is created instead .
json . exception . type_error .302 | type must be object , but is array | During implicit or explicit value conversion , the JSON type must be compatible to the target type . For instance , a JSON string can only be converted into string types , but not into numbers or boolean types .
json . exception . type_error .303 | incompatible ReferenceType for get_ref , actual type is object | To retrieve a reference to a value stored in a @ ref basic_json object with @ ref get_ref , the type of the reference must match the value type . For instance , for a JSON array , the @ a ReferenceType must be @ ref array_t & .
json . exception . type_error .304 | cannot use at ( ) with string | The @ ref at ( ) member functions can only be executed for certain JSON types .
json . exception . type_error .305 | cannot use operator [ ] with string | The @ ref operator [ ] member functions can only be executed for certain JSON types .
json . exception . type_error .306 | cannot use value ( ) with string | The @ ref value ( ) member functions can only be executed for certain JSON types .
json . exception . type_error .307 | cannot use erase ( ) with string | The @ ref erase ( ) member functions can only be executed for certain JSON types .
json . exception . type_error .308 | cannot use push_back ( ) with string | The @ ref push_back ( ) and @ ref operator + = member functions can only be executed for certain JSON types .
json . exception . type_error .309 | cannot use insert ( ) with | The @ ref insert ( ) member functions can only be executed for certain JSON types .
json . exception . type_error .310 | cannot use swap ( ) with number | The @ ref swap ( ) member functions can only be executed for certain JSON types .
json . exception . type_error .311 | cannot use emplace_back ( ) with string | The @ ref emplace_back ( ) member function can only be executed for certain JSON types .
json . exception . type_error .312 | cannot use update ( ) with string | The @ ref update ( ) member functions can only be executed for certain JSON types .
json . exception . type_error .313 | invalid value to unflatten | The @ ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value . The JSON Pointers must not overlap , because then the resulting value would not be well defined .
json . exception . type_error .314 | only objects can be unflattened | The @ ref unflatten function only works for an object whose keys are JSON Pointers .
json . exception . type_error .315 | values in object must be primitive | The @ ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive .
json . exception . type_error .316 | invalid UTF - 8 byte at index 10 : 0x7E | The @ ref dump function only works with UTF - 8 encoded strings ; that is , if you assign a ` std : : string ` to a JSON value , make sure it is UTF - 8 encoded . |
@ liveexample { The following code shows how a ` type_error ` exception can be
caught . , type_error }
@ sa @ ref exception for the base class of the library exceptions
@ sa @ ref parse_error for exceptions indicating a parse error
@ sa @ ref invalid_iterator for exceptions indicating errors with iterators
@ sa @ ref out_of_range for exceptions indicating access out of the defined range
@ sa @ ref other_error for exceptions indicating other library errors
@ since version 3.0 .0
*/
class type_error : public exception
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
public :
static type_error create ( int id_ , const std : : string & what_arg )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : string w = exception : : name ( " type_error " , id_ ) + what_arg ;
return type_error ( id_ , w . c_str ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
type_error ( int id_ , const char * what_arg ) : exception ( id_ , what_arg ) { }
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
/*!
@ brief exception indicating access out of the defined range
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This exception is thrown in case a library function is called on an input
parameter that exceeds the expected range , for instance in case of array
indices or nonexisting object keys .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exceptions have ids 4 xx .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
name / id | example message | description
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
json . exception . out_of_range .401 | array index 3 is out of range | The provided array index @ a i is larger than @ a size - 1.
json . exception . out_of_range .402 | array index ' - ' ( 3 ) is out of range | The special array index ` - ` in a JSON Pointer never describes a valid element of the array , but the index past the end . That is , it can only be used to add elements at this position , but not to read it .
json . exception . out_of_range .403 | key ' foo ' not found | The provided key was not found in the JSON object .
json . exception . out_of_range .404 | unresolved reference token ' foo ' | A reference token in a JSON Pointer could not be resolved .
json . exception . out_of_range .405 | JSON pointer has no parent | The JSON Patch operations ' remove ' and ' add ' can not be applied to the root element of the JSON value .
json . exception . out_of_range .406 | number overflow parsing ' 10E1000 ' | A parsed number could not be stored as without changing it to NaN or INF .
json . exception . out_of_range .407 | number overflow serializing ' 9223372036854775808 ' | UBJSON only supports integers numbers up to 9223372036854775807. |
json . exception . out_of_range .408 | excessive array size : 8658170730974374167 | The size ( following ` # ` ) of an UBJSON array or object exceeds the maximal capacity . |
@ liveexample { The following code shows how an ` out_of_range ` exception can be
caught . , out_of_range }
@ sa @ ref exception for the base class of the library exceptions
@ sa @ ref parse_error for exceptions indicating a parse error
@ sa @ ref invalid_iterator for exceptions indicating errors with iterators
@ sa @ ref type_error for exceptions indicating executing a member function with
a wrong type
@ sa @ ref other_error for exceptions indicating other library errors
@ since version 3.0 .0
*/
class out_of_range : public exception
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
public :
static out_of_range create ( int id_ , const std : : string & what_arg )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : string w = exception : : name ( " out_of_range " , id_ ) + what_arg ;
return out_of_range ( id_ , w . c_str ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
out_of_range ( int id_ , const char * what_arg ) : exception ( id_ , what_arg ) { }
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
/*!
@ brief exception indicating other library errors
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This exception is thrown in case of errors that cannot be classified with the
other exception types .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exceptions have ids 5 xx .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
name / id | example message | description
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
json . exception . other_error .501 | unsuccessful : { " op " : " test " , " path " : " /baz " , " value " : " bar " } | A JSON Patch operation ' test ' failed . The unsuccessful operation is also printed .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref exception for the base class of the library exceptions
@ sa @ ref parse_error for exceptions indicating a parse error
@ sa @ ref invalid_iterator for exceptions indicating errors with iterators
@ sa @ ref type_error for exceptions indicating executing a member function with
a wrong type
@ sa @ ref out_of_range for exceptions indicating access out of the defined range
@ liveexample { The following code shows how an ` other_error ` exception can be
caught . , other_error }
@ since version 3.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
class other_error : public exception
{
public :
static other_error create ( int id_ , const std : : string & what_arg )
{
std : : string w = exception : : name ( " other_error " , id_ ) + what_arg ;
return other_error ( id_ , w . c_str ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
other_error ( int id_ , const char * what_arg ) : exception ( id_ , what_arg ) { }
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <array> // array
# include <ciso646> // and
# include <cstddef> // size_t
# include <cstdint> // uint8_t
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
namespace detail
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
///////////////////////////
// JSON type enumeration //
///////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief the JSON type enumeration
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This enumeration collects the different JSON types . It is internally used to
distinguish the stored values , and the functions @ ref basic_json : : is_null ( ) ,
@ ref basic_json : : is_object ( ) , @ ref basic_json : : is_array ( ) ,
@ ref basic_json : : is_string ( ) , @ ref basic_json : : is_boolean ( ) ,
@ ref basic_json : : is_number ( ) ( with @ ref basic_json : : is_number_integer ( ) ,
@ ref basic_json : : is_number_unsigned ( ) , and @ ref basic_json : : is_number_float ( ) ) ,
@ ref basic_json : : is_discarded ( ) , @ ref basic_json : : is_primitive ( ) , and
@ ref basic_json : : is_structured ( ) rely on it .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note There are three enumeration entries ( number_integer , number_unsigned , and
number_float ) , because the library distinguishes these three types for numbers :
@ ref basic_json : : number_unsigned_t is used for unsigned integers ,
@ ref basic_json : : number_integer_t is used for signed integers , and
@ ref basic_json : : number_float_t is used for floating - point numbers or to
approximate integers which do not fit in the limits of their respective type .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref basic_json : : basic_json ( const value_t value_type ) - - create a JSON
value with the default value for a given type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
enum class value_t : std : : uint8_t
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
null , ///< null value
object , ///< object (unordered set of name/value pairs)
array , ///< array (ordered collection of values)
string , ///< string value
boolean , ///< boolean value
number_integer , ///< number value (signed integer)
number_unsigned , ///< number value (unsigned integer)
number_float , ///< number value (floating-point)
discarded ///< discarded by the the parser callback function
2017-07-18 05:37:27 +02:00
} ;
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison operator for JSON types
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns an ordering that is similar to Python :
- order : null < boolean < number < object < array < string
- furthermore , each type is not smaller than itself
- discarded values are not comparable
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
inline bool operator < ( const value_t lhs , const value_t rhs ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
static constexpr std : : array < std : : uint8_t , 8 > order = { {
0 /* null */ , 3 /* object */ , 4 /* array */ , 5 /* string */ ,
1 /* boolean */ , 2 /* integer */ , 2 /* unsigned */ , 2 /* float */
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const auto l_index = static_cast < std : : size_t > ( lhs ) ;
const auto r_index = static_cast < std : : size_t > ( rhs ) ;
return l_index < order . size ( ) and r_index < order . size ( ) and order [ l_index ] < order [ r_index ] ;
2017-07-18 05:37:27 +02:00
}
}
}
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/conversions/from_json.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <algorithm> // transform
# include <array> // array
# include <ciso646> // and, not
# include <forward_list> // forward_list
# include <iterator> // inserter, front_inserter, end
# include <string> // string
# include <tuple> // tuple, make_tuple
# include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
# include <utility> // pair, declval
# include <valarray> // valarray
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/exceptions.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/meta.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
namespace detail
2017-07-18 05:37:27 +02:00
{
// overloads for basic_json template parameters
template < typename BasicJsonType , typename ArithmeticType ,
enable_if_t < std : : is_arithmetic < ArithmeticType > : : value and
2018-05-19 21:59:03 +02:00
not std : : is_same < ArithmeticType , typename BasicJsonType : : boolean_t > : : value ,
2017-07-18 05:37:27 +02:00
int > = 0 >
void get_arithmetic_value ( const BasicJsonType & j , ArithmeticType & val )
{
switch ( static_cast < value_t > ( j ) )
{
case value_t : : number_unsigned :
{
2018-05-19 21:59:03 +02:00
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : number_unsigned_t * > ( ) ) ;
2017-07-18 05:37:27 +02:00
break ;
}
case value_t : : number_integer :
{
2018-05-19 21:59:03 +02:00
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : number_integer_t * > ( ) ) ;
2017-07-18 05:37:27 +02:00
break ;
}
case value_t : : number_float :
{
2018-05-19 21:59:03 +02:00
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : number_float_t * > ( ) ) ;
2017-07-18 05:37:27 +02:00
break ;
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
default :
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be number, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
}
template < typename BasicJsonType >
void from_json ( const BasicJsonType & j , typename BasicJsonType : : boolean_t & b )
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not j . is_boolean ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be boolean, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
b = * j . template get_ptr < const typename BasicJsonType : : boolean_t * > ( ) ;
}
template < typename BasicJsonType >
void from_json ( const BasicJsonType & j , typename BasicJsonType : : string_t & s )
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not j . is_string ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be string, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
s = * j . template get_ptr < const typename BasicJsonType : : string_t * > ( ) ;
}
template < typename BasicJsonType >
void from_json ( const BasicJsonType & j , typename BasicJsonType : : number_float_t & val )
{
get_arithmetic_value ( j , val ) ;
}
template < typename BasicJsonType >
void from_json ( const BasicJsonType & j , typename BasicJsonType : : number_unsigned_t & val )
{
get_arithmetic_value ( j , val ) ;
}
template < typename BasicJsonType >
void from_json ( const BasicJsonType & j , typename BasicJsonType : : number_integer_t & val )
{
get_arithmetic_value ( j , val ) ;
}
template < typename BasicJsonType , typename EnumType ,
enable_if_t < std : : is_enum < EnumType > : : value , int > = 0 >
void from_json ( const BasicJsonType & j , EnumType & e )
{
typename std : : underlying_type < EnumType > : : type val ;
get_arithmetic_value ( j , val ) ;
e = static_cast < EnumType > ( val ) ;
}
template < typename BasicJsonType >
void from_json ( const BasicJsonType & j , typename BasicJsonType : : array_t & arr )
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not j . is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be array, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
arr = * j . template get_ptr < const typename BasicJsonType : : array_t * > ( ) ;
}
// forward_list doesn't have an insert method
template < typename BasicJsonType , typename T , typename Allocator ,
enable_if_t < std : : is_convertible < BasicJsonType , T > : : value , int > = 0 >
void from_json ( const BasicJsonType & j , std : : forward_list < T , Allocator > & l )
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not j . is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be array, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
std : : transform ( j . rbegin ( ) , j . rend ( ) ,
std : : front_inserter ( l ) , [ ] ( const BasicJsonType & i )
{
return i . template get < T > ( ) ;
} ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// valarray doesn't have an insert method
template < typename BasicJsonType , typename T ,
enable_if_t < std : : is_convertible < BasicJsonType , T > : : value , int > = 0 >
void from_json ( const BasicJsonType & j , std : : valarray < T > & l )
{
if ( JSON_UNLIKELY ( not j . is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be array, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
l . resize ( j . size ( ) ) ;
std : : copy ( j . m_value . array - > begin ( ) , j . m_value . array - > end ( ) , std : : begin ( l ) ) ;
2017-07-18 05:37:27 +02:00
}
template < typename BasicJsonType , typename CompatibleArrayType >
2018-05-19 21:59:03 +02:00
void from_json_array_impl ( const BasicJsonType & j , CompatibleArrayType & arr , priority_tag < 0 > /*unused*/ )
2017-07-18 05:37:27 +02:00
{
using std : : end ;
std : : transform ( j . begin ( ) , j . end ( ) ,
std : : inserter ( arr , end ( arr ) ) , [ ] ( const BasicJsonType & i )
{
// get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType
return i . template get < typename CompatibleArrayType : : value_type > ( ) ;
} ) ;
}
template < typename BasicJsonType , typename CompatibleArrayType >
2018-05-19 21:59:03 +02:00
auto from_json_array_impl ( const BasicJsonType & j , CompatibleArrayType & arr , priority_tag < 1 > /*unused*/ )
2017-07-18 05:37:27 +02:00
- > decltype (
arr . reserve ( std : : declval < typename CompatibleArrayType : : size_type > ( ) ) ,
void ( ) )
{
using std : : end ;
arr . reserve ( j . size ( ) ) ;
std : : transform ( j . begin ( ) , j . end ( ) ,
std : : inserter ( arr , end ( arr ) ) , [ ] ( const BasicJsonType & i )
{
// get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType
return i . template get < typename CompatibleArrayType : : value_type > ( ) ;
} ) ;
}
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T , std : : size_t N >
void from_json_array_impl ( const BasicJsonType & j , std : : array < T , N > & arr , priority_tag < 2 > /*unused*/ )
2017-07-18 05:37:27 +02:00
{
for ( std : : size_t i = 0 ; i < N ; + + i )
{
arr [ i ] = j . at ( i ) . template get < T > ( ) ;
}
}
2018-05-19 21:59:03 +02:00
template <
typename BasicJsonType , typename CompatibleArrayType ,
enable_if_t <
is_compatible_array_type < BasicJsonType , CompatibleArrayType > : : value and
not std : : is_same < typename BasicJsonType : : array_t ,
CompatibleArrayType > : : value and
std : : is_constructible <
BasicJsonType , typename CompatibleArrayType : : value_type > : : value ,
int > = 0 >
2017-07-18 05:37:27 +02:00
void from_json ( const BasicJsonType & j , CompatibleArrayType & arr )
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not j . is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be array, but is " +
std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
from_json_array_impl ( j , arr , priority_tag < 2 > { } ) ;
}
template < typename BasicJsonType , typename CompatibleObjectType ,
enable_if_t < is_compatible_object_type < BasicJsonType , CompatibleObjectType > : : value , int > = 0 >
void from_json ( const BasicJsonType & j , CompatibleObjectType & obj )
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not j . is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be object, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
auto inner_object = j . template get_ptr < const typename BasicJsonType : : object_t * > ( ) ;
using value_type = typename CompatibleObjectType : : value_type ;
std : : transform (
inner_object - > begin ( ) , inner_object - > end ( ) ,
std : : inserter ( obj , obj . begin ( ) ) ,
[ ] ( typename BasicJsonType : : object_t : : value_type const & p )
{
2018-05-19 21:59:03 +02:00
return value_type ( p . first , p . second . template get < typename CompatibleObjectType : : mapped_type > ( ) ) ;
2017-07-18 05:37:27 +02:00
} ) ;
}
// overload for arithmetic types, not chosen for basic_json template arguments
// (BooleanType, etc..); note: Is it really necessary to provide explicit
// overloads for boolean_t etc. in case of a custom BooleanType which is not
// an arithmetic type?
template < typename BasicJsonType , typename ArithmeticType ,
enable_if_t <
std : : is_arithmetic < ArithmeticType > : : value and
not std : : is_same < ArithmeticType , typename BasicJsonType : : number_unsigned_t > : : value and
not std : : is_same < ArithmeticType , typename BasicJsonType : : number_integer_t > : : value and
not std : : is_same < ArithmeticType , typename BasicJsonType : : number_float_t > : : value and
not std : : is_same < ArithmeticType , typename BasicJsonType : : boolean_t > : : value ,
int > = 0 >
void from_json ( const BasicJsonType & j , ArithmeticType & val )
{
switch ( static_cast < value_t > ( j ) )
{
case value_t : : number_unsigned :
{
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : number_unsigned_t * > ( ) ) ;
break ;
}
case value_t : : number_integer :
{
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : number_integer_t * > ( ) ) ;
break ;
}
case value_t : : number_float :
{
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : number_float_t * > ( ) ) ;
break ;
}
case value_t : : boolean :
{
val = static_cast < ArithmeticType > ( * j . template get_ptr < const typename BasicJsonType : : boolean_t * > ( ) ) ;
break ;
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
default :
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be number, but is " + std : : string ( j . type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename A1 , typename A2 >
void from_json ( const BasicJsonType & j , std : : pair < A1 , A2 > & p )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
p = { j . at ( 0 ) . template get < A1 > ( ) , j . at ( 1 ) . template get < A2 > ( ) } ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename Tuple , std : : size_t . . . Idx >
2017-07-18 05:37:27 +02:00
void from_json_tuple_impl ( const BasicJsonType & j , Tuple & t , index_sequence < Idx . . . > )
{
2018-05-19 21:59:03 +02:00
t = std : : make_tuple ( j . at ( Idx ) . template get < typename std : : tuple_element < Idx , Tuple > : : type > ( ) . . . ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename . . . Args >
2017-07-18 05:37:27 +02:00
void from_json ( const BasicJsonType & j , std : : tuple < Args . . . > & t )
{
from_json_tuple_impl ( j , t , index_sequence_for < Args . . . > { } ) ;
}
struct from_json_fn
{
private :
template < typename BasicJsonType , typename T >
2018-05-19 21:59:03 +02:00
auto call ( const BasicJsonType & j , T & val , priority_tag < 1 > /*unused*/ ) const
2017-07-18 05:37:27 +02:00
noexcept ( noexcept ( from_json ( j , val ) ) )
- > decltype ( from_json ( j , val ) , void ( ) )
{
return from_json ( j , val ) ;
}
template < typename BasicJsonType , typename T >
2018-05-19 21:59:03 +02:00
void call ( const BasicJsonType & /*unused*/ , T & /*unused*/ , priority_tag < 0 > /*unused*/ ) const noexcept
2017-07-18 05:37:27 +02:00
{
static_assert ( sizeof ( BasicJsonType ) = = 0 ,
" could not find from_json() method in T's namespace " ) ;
2018-05-19 21:59:03 +02:00
# ifdef _MSC_VER
// MSVC does not show a stacktrace for the above assert
using decayed = uncvref_t < T > ;
static_assert ( sizeof ( typename decayed : : force_msvc_stacktrace ) = = 0 ,
" forcing MSVC stacktrace to show which T we're talking about. " ) ;
# endif
2017-07-18 05:37:27 +02:00
}
public :
template < typename BasicJsonType , typename T >
void operator ( ) ( const BasicJsonType & j , T & val ) const
noexcept ( noexcept ( std : : declval < from_json_fn > ( ) . call ( j , val , priority_tag < 1 > { } ) ) )
{
return call ( j , val , priority_tag < 1 > { } ) ;
}
} ;
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// namespace to hold default `from_json` function
/// to see why this is required:
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
namespace
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
constexpr const auto & from_json = detail : : static_const < detail : : from_json_fn > : : value ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/conversions/to_json.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <ciso646> // or, and, not
# include <iterator> // begin, end
# include <tuple> // tuple, get
# include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
# include <utility> // move, forward, declval, pair
# include <valarray> // valarray
# include <vector> // vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/meta.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
namespace detail
{
//////////////////
// constructors //
//////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < value_t > struct external_constructor ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : boolean >
{
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : boolean_t b ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
j . m_type = value_t : : boolean ;
j . m_value = b ;
j . assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : string >
{
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , const typename BasicJsonType : : string_t & s )
{
j . m_type = value_t : : string ;
j . m_value = s ;
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : string_t & & s )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
j . m_type = value_t : : string ;
j . m_value = std : : move ( s ) ;
j . assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
} ;
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : number_float >
{
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : number_float_t val ) noexcept
{
j . m_type = value_t : : number_float ;
j . m_value = val ;
j . assert_invariant ( ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : number_unsigned >
{
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : number_unsigned_t val ) noexcept
{
j . m_type = value_t : : number_unsigned ;
j . m_value = val ;
j . assert_invariant ( ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : number_integer >
{
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : number_integer_t val ) noexcept
{
j . m_type = value_t : : number_integer ;
j . m_value = val ;
j . assert_invariant ( ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : array >
{
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , const typename BasicJsonType : : array_t & arr )
{
j . m_type = value_t : : array ;
j . m_value = arr ;
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : array_t & & arr )
{
j . m_type = value_t : : array ;
j . m_value = std : : move ( arr ) ;
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleArrayType ,
enable_if_t < not std : : is_same < CompatibleArrayType , typename BasicJsonType : : array_t > : : value ,
int > = 0 >
static void construct ( BasicJsonType & j , const CompatibleArrayType & arr )
{
using std : : begin ;
using std : : end ;
j . m_type = value_t : : array ;
j . m_value . array = j . template create < typename BasicJsonType : : array_t > ( begin ( arr ) , end ( arr ) ) ;
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , const std : : vector < bool > & arr )
{
j . m_type = value_t : : array ;
j . m_value = value_t : : array ;
j . m_value . array - > reserve ( arr . size ( ) ) ;
for ( const bool x : arr )
{
j . m_value . array - > push_back ( x ) ;
}
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T ,
enable_if_t < std : : is_convertible < T , BasicJsonType > : : value , int > = 0 >
static void construct ( BasicJsonType & j , const std : : valarray < T > & arr )
{
j . m_type = value_t : : array ;
j . m_value = value_t : : array ;
j . m_value . array - > resize ( arr . size ( ) ) ;
std : : copy ( std : : begin ( arr ) , std : : end ( arr ) , j . m_value . array - > begin ( ) ) ;
j . assert_invariant ( ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < >
struct external_constructor < value_t : : object >
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , const typename BasicJsonType : : object_t & obj )
{
j . m_type = value_t : : object ;
j . m_value = obj ;
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
static void construct ( BasicJsonType & j , typename BasicJsonType : : object_t & & obj )
{
j . m_type = value_t : : object ;
j . m_value = std : : move ( obj ) ;
j . assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleObjectType ,
enable_if_t < not std : : is_same < CompatibleObjectType , typename BasicJsonType : : object_t > : : value , int > = 0 >
static void construct ( BasicJsonType & j , const CompatibleObjectType & obj )
{
using std : : begin ;
using std : : end ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
j . m_type = value_t : : object ;
j . m_value . object = j . template create < typename BasicJsonType : : object_t > ( begin ( obj ) , end ( obj ) ) ;
j . assert_invariant ( ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/////////////
// to_json //
/////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T ,
enable_if_t < std : : is_same < T , typename BasicJsonType : : boolean_t > : : value , int > = 0 >
void to_json ( BasicJsonType & j , T b ) noexcept
{
external_constructor < value_t : : boolean > : : construct ( j , b ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleString ,
enable_if_t < std : : is_constructible < typename BasicJsonType : : string_t , CompatibleString > : : value , int > = 0 >
void to_json ( BasicJsonType & j , const CompatibleString & s )
{
external_constructor < value_t : : string > : : construct ( j , s ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
void to_json ( BasicJsonType & j , typename BasicJsonType : : string_t & & s )
{
external_constructor < value_t : : string > : : construct ( j , std : : move ( s ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename FloatType ,
enable_if_t < std : : is_floating_point < FloatType > : : value , int > = 0 >
void to_json ( BasicJsonType & j , FloatType val ) noexcept
{
external_constructor < value_t : : number_float > : : construct ( j , static_cast < typename BasicJsonType : : number_float_t > ( val ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleNumberUnsignedType ,
enable_if_t < is_compatible_integer_type < typename BasicJsonType : : number_unsigned_t , CompatibleNumberUnsignedType > : : value , int > = 0 >
void to_json ( BasicJsonType & j , CompatibleNumberUnsignedType val ) noexcept
{
external_constructor < value_t : : number_unsigned > : : construct ( j , static_cast < typename BasicJsonType : : number_unsigned_t > ( val ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleNumberIntegerType ,
enable_if_t < is_compatible_integer_type < typename BasicJsonType : : number_integer_t , CompatibleNumberIntegerType > : : value , int > = 0 >
void to_json ( BasicJsonType & j , CompatibleNumberIntegerType val ) noexcept
{
external_constructor < value_t : : number_integer > : : construct ( j , static_cast < typename BasicJsonType : : number_integer_t > ( val ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename EnumType ,
enable_if_t < std : : is_enum < EnumType > : : value , int > = 0 >
void to_json ( BasicJsonType & j , EnumType e ) noexcept
{
using underlying_type = typename std : : underlying_type < EnumType > : : type ;
external_constructor < value_t : : number_integer > : : construct ( j , static_cast < underlying_type > ( e ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
void to_json ( BasicJsonType & j , const std : : vector < bool > & e )
{
external_constructor < value_t : : array > : : construct ( j , e ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleArrayType ,
enable_if_t < is_compatible_array_type < BasicJsonType , CompatibleArrayType > : : value or
std : : is_same < typename BasicJsonType : : array_t , CompatibleArrayType > : : value ,
int > = 0 >
void to_json ( BasicJsonType & j , const CompatibleArrayType & arr )
{
external_constructor < value_t : : array > : : construct ( j , arr ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T ,
enable_if_t < std : : is_convertible < T , BasicJsonType > : : value , int > = 0 >
void to_json ( BasicJsonType & j , std : : valarray < T > arr )
{
external_constructor < value_t : : array > : : construct ( j , std : : move ( arr ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
void to_json ( BasicJsonType & j , typename BasicJsonType : : array_t & & arr )
{
external_constructor < value_t : : array > : : construct ( j , std : : move ( arr ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename CompatibleObjectType ,
enable_if_t < is_compatible_object_type < BasicJsonType , CompatibleObjectType > : : value , int > = 0 >
void to_json ( BasicJsonType & j , const CompatibleObjectType & obj )
{
external_constructor < value_t : : object > : : construct ( j , obj ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
void to_json ( BasicJsonType & j , typename BasicJsonType : : object_t & & obj )
{
external_constructor < value_t : : object > : : construct ( j , std : : move ( obj ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T , std : : size_t N ,
enable_if_t < not std : : is_constructible < typename BasicJsonType : : string_t , T ( & ) [ N ] > : : value , int > = 0 >
void to_json ( BasicJsonType & j , T ( & arr ) [ N ] )
{
external_constructor < value_t : : array > : : construct ( j , arr ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename . . . Args >
void to_json ( BasicJsonType & j , const std : : pair < Args . . . > & p )
{
j = { p . first , p . second } ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename Tuple , std : : size_t . . . Idx >
void to_json_tuple_impl ( BasicJsonType & j , const Tuple & t , index_sequence < Idx . . . > )
{
j = { std : : get < Idx > ( t ) . . . } ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename . . . Args >
void to_json ( BasicJsonType & j , const std : : tuple < Args . . . > & t )
{
to_json_tuple_impl ( j , t , index_sequence_for < Args . . . > { } ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
struct to_json_fn
{
private :
template < typename BasicJsonType , typename T >
auto call ( BasicJsonType & j , T & & val , priority_tag < 1 > /*unused*/ ) const noexcept ( noexcept ( to_json ( j , std : : forward < T > ( val ) ) ) )
- > decltype ( to_json ( j , std : : forward < T > ( val ) ) , void ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return to_json ( j , std : : forward < T > ( val ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename T >
void call ( BasicJsonType & /*unused*/ , T & & /*unused*/ , priority_tag < 0 > /*unused*/ ) const noexcept
{
static_assert ( sizeof ( BasicJsonType ) = = 0 ,
" could not find to_json() method in T's namespace " ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ifdef _MSC_VER
// MSVC does not show a stacktrace for the above assert
using decayed = uncvref_t < T > ;
static_assert ( sizeof ( typename decayed : : force_msvc_stacktrace ) = = 0 ,
" forcing MSVC stacktrace to show which T we're talking about. " ) ;
2017-07-18 05:37:27 +02:00
# endif
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
template < typename BasicJsonType , typename T >
void operator ( ) ( BasicJsonType & j , T & & val ) const
noexcept ( noexcept ( std : : declval < to_json_fn > ( ) . call ( j , std : : forward < T > ( val ) , priority_tag < 1 > { } ) ) )
{
return call ( j , std : : forward < T > ( val ) , priority_tag < 1 > { } ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
} ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// namespace to hold default `to_json` function
namespace
{
constexpr const auto & to_json = detail : : static_const < detail : : to_json_fn > : : value ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/input/input_adapters.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <algorithm> // min
# include <array> // array
# include <cassert> // assert
# include <cstddef> // size_t
# include <cstring> // strlen
# include <ios> // streamsize, streamoff, streampos
# include <istream> // istream
# include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
# include <memory> // shared_ptr, make_shared, addressof
# include <numeric> // accumulate
# include <string> // string, char_traits
# include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
# include <utility> // pair, declval
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
////////////////////
// input adapters //
////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief abstract input adapter interface
Produces a stream of std : : char_traits < char > : : int_type characters from a
std : : istream , a buffer , or some other input type . Accepts the return of exactly
one non - EOF character for future input . The int_type characters returned
consist of all valid char values as positive values ( typically unsigned char ) ,
plus an EOF value outside that range , specified by the value of the function
std : : char_traits < char > : : eof ( ) . This value is typically - 1 , but could be any
arbitrary value which is not a valid char value .
*/
struct input_adapter_protocol
{
/// get a character [0,255] or std::char_traits<char>::eof().
virtual std : : char_traits < char > : : int_type get_character ( ) = 0 ;
/// restore the last non-eof() character to input
virtual void unget_character ( ) = 0 ;
virtual ~ input_adapter_protocol ( ) = default ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// a type to simplify interfaces
using input_adapter_t = std : : shared_ptr < input_adapter_protocol > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
Input adapter for a ( caching ) istream . Ignores a UFT Byte Order Mark at
beginning of input . Does not support changing the underlying std : : streambuf
in mid - input . Maintains underlying std : : istream and std : : streambuf to support
subsequent use of standard std : : istream operations to process any input
characters following those used in parsing the JSON input . Clears the
std : : istream flags ; any input errors ( e . g . , EOF ) will be detected by the first
subsequent call for input from the std : : istream .
*/
class input_stream_adapter : public input_adapter_protocol
{
public :
~ input_stream_adapter ( ) override
{
// clear stream flags; we use underlying streambuf I/O, do not
// maintain ifstream flags
is . clear ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
explicit input_stream_adapter ( std : : istream & i )
: is ( i ) , sb ( * i . rdbuf ( ) )
{
// skip byte order mark
std : : char_traits < char > : : int_type c ;
if ( ( c = get_character ( ) ) = = 0xEF )
{
if ( ( c = get_character ( ) ) = = 0xBB )
{
if ( ( c = get_character ( ) ) = = 0xBF )
{
return ; // Ignore BOM
}
else if ( c ! = std : : char_traits < char > : : eof ( ) )
{
is . unget ( ) ;
}
is . putback ( ' \xBB ' ) ;
}
else if ( c ! = std : : char_traits < char > : : eof ( ) )
{
is . unget ( ) ;
}
is . putback ( ' \xEF ' ) ;
}
else if ( c ! = std : : char_traits < char > : : eof ( ) )
{
is . unget ( ) ; // no byte order mark; process as usual
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// delete because of pointer members
input_stream_adapter ( const input_stream_adapter & ) = delete ;
input_stream_adapter & operator = ( input_stream_adapter & ) = delete ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
// ensure that std::char_traits<char>::eof() and the character 0xFF do not
// end up as the same value, eg. 0xFFFFFFFF.
std : : char_traits < char > : : int_type get_character ( ) override
{
return sb . sbumpc ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
void unget_character ( ) override
{
sb . sungetc ( ) ; // is.unget() avoided for performance
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/// the associated input stream
std : : istream & is ;
std : : streambuf & sb ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// input adapter for buffer input
class input_buffer_adapter : public input_adapter_protocol
{
public :
input_buffer_adapter ( const char * b , const std : : size_t l )
: cursor ( b ) , limit ( b + l ) , start ( b )
{
// skip byte order mark
if ( l > = 3 and b [ 0 ] = = ' \xEF ' and b [ 1 ] = = ' \xBB ' and b [ 2 ] = = ' \xBF ' )
{
cursor + = 3 ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// delete because of pointer members
input_buffer_adapter ( const input_buffer_adapter & ) = delete ;
input_buffer_adapter & operator = ( input_buffer_adapter & ) = delete ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
std : : char_traits < char > : : int_type get_character ( ) noexcept override
{
if ( JSON_LIKELY ( cursor < limit ) )
{
return std : : char_traits < char > : : to_int_type ( * ( cursor + + ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return std : : char_traits < char > : : eof ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
void unget_character ( ) noexcept override
{
if ( JSON_LIKELY ( cursor > start ) )
{
- - cursor ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/// pointer to the current character
const char * cursor ;
/// pointer past the last character
const char * limit ;
/// pointer to the first character
const char * start ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
class input_adapter
{
public :
// native support
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// input adapter for input stream
input_adapter ( std : : istream & i )
: ia ( std : : make_shared < input_stream_adapter > ( i ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// input adapter for input stream
input_adapter ( std : : istream & & i )
: ia ( std : : make_shared < input_stream_adapter > ( i ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// input adapter for buffer
template < typename CharT ,
typename std : : enable_if <
std : : is_pointer < CharT > : : value and
std : : is_integral < typename std : : remove_pointer < CharT > : : type > : : value and
sizeof ( typename std : : remove_pointer < CharT > : : type ) = = 1 ,
int > : : type = 0 >
input_adapter ( CharT b , std : : size_t l )
: ia ( std : : make_shared < input_buffer_adapter > ( reinterpret_cast < const char * > ( b ) , l ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// derived support
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// input adapter for string literal
template < typename CharT ,
typename std : : enable_if <
std : : is_pointer < CharT > : : value and
std : : is_integral < typename std : : remove_pointer < CharT > : : type > : : value and
sizeof ( typename std : : remove_pointer < CharT > : : type ) = = 1 ,
int > : : type = 0 >
input_adapter ( CharT b )
: input_adapter ( reinterpret_cast < const char * > ( b ) ,
std : : strlen ( reinterpret_cast < const char * > ( b ) ) ) { }
/// input adapter for iterator range with contiguous storage
template < class IteratorType ,
typename std : : enable_if <
std : : is_same < typename std : : iterator_traits < IteratorType > : : iterator_category , std : : random_access_iterator_tag > : : value ,
int > : : type = 0 >
input_adapter ( IteratorType first , IteratorType last )
{
// assertion to check that the iterator range is indeed contiguous,
// see http://stackoverflow.com/a/35008842/266378 for more discussion
assert ( std : : accumulate (
first , last , std : : pair < bool , int > ( true , 0 ) ,
[ & first ] ( std : : pair < bool , int > res , decltype ( * first ) val )
{
res . first & = ( val = = * ( std : : next ( std : : addressof ( * first ) , res . second + + ) ) ) ;
return res ;
} ) . first ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// assertion to check that each element is 1 byte long
static_assert (
sizeof ( typename std : : iterator_traits < IteratorType > : : value_type ) = = 1 ,
" each element in the iterator range must have the size of 1 byte " ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const auto len = static_cast < size_t > ( std : : distance ( first , last ) ) ;
if ( JSON_LIKELY ( len > 0 ) )
{
// there is at least one element: use the address of first
ia = std : : make_shared < input_buffer_adapter > ( reinterpret_cast < const char * > ( & ( * first ) ) , len ) ;
}
else
{
// the address of first cannot be used: use nullptr
ia = std : : make_shared < input_buffer_adapter > ( nullptr , len ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// input adapter for array
template < class T , std : : size_t N >
input_adapter ( T ( & array ) [ N ] )
: input_adapter ( std : : begin ( array ) , std : : end ( array ) ) { }
/// input adapter for contiguous container
template < class ContiguousContainer , typename
std : : enable_if < not std : : is_pointer < ContiguousContainer > : : value and
std : : is_base_of < std : : random_access_iterator_tag , typename std : : iterator_traits < decltype ( std : : begin ( std : : declval < ContiguousContainer const > ( ) ) ) > : : iterator_category > : : value ,
int > : : type = 0 >
input_adapter ( const ContiguousContainer & c )
: input_adapter ( std : : begin ( c ) , std : : end ( c ) ) { }
operator input_adapter_t ( )
{
return ia ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/// the actual adapter
input_adapter_t ia = nullptr ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/input/lexer.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <clocale> // localeconv
# include <cstddef> // size_t
# include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
# include <initializer_list> // initializer_list
# include <ios> // hex, uppercase
# include <iomanip> // setw, setfill
# include <sstream> // stringstream
# include <string> // char_traits, string
# include <vector> // vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/input/input_adapters.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
///////////
// lexer //
///////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief lexical analysis
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This class organizes the lexical analysis during JSON deserialization .
*/
template < typename BasicJsonType >
class lexer
{
using number_integer_t = typename BasicJsonType : : number_integer_t ;
using number_unsigned_t = typename BasicJsonType : : number_unsigned_t ;
using number_float_t = typename BasicJsonType : : number_float_t ;
using string_t = typename BasicJsonType : : string_t ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
/// token types for the parser
enum class token_type
{
uninitialized , ///< indicating the scanner is uninitialized
literal_true , ///< the `true` literal
literal_false , ///< the `false` literal
literal_null , ///< the `null` literal
value_string , ///< a string -- use get_string() for actual value
value_unsigned , ///< an unsigned integer -- use get_number_unsigned() for actual value
value_integer , ///< a signed integer -- use get_number_integer() for actual value
value_float , ///< an floating point number -- use get_number_float() for actual value
begin_array , ///< the character for array begin `[`
begin_object , ///< the character for object begin `{`
end_array , ///< the character for array end `]`
end_object , ///< the character for object end `}`
name_separator , ///< the name separator `:`
value_separator , ///< the value separator `,`
parse_error , ///< indicating a parse error
end_of_input , ///< indicating the end of the input buffer
literal_or_value ///< a literal or the begin of a value (only for diagnostics)
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return name of values of type token_type (only used for errors)
static const char * token_type_name ( const token_type t ) noexcept
{
switch ( t )
{
case token_type : : uninitialized :
return " <uninitialized> " ;
case token_type : : literal_true :
return " true literal " ;
case token_type : : literal_false :
return " false literal " ;
case token_type : : literal_null :
return " null literal " ;
case token_type : : value_string :
return " string literal " ;
case lexer : : token_type : : value_unsigned :
case lexer : : token_type : : value_integer :
case lexer : : token_type : : value_float :
return " number literal " ;
case token_type : : begin_array :
return " '[' " ;
case token_type : : begin_object :
return " '{' " ;
case token_type : : end_array :
return " ']' " ;
case token_type : : end_object :
return " '}' " ;
case token_type : : name_separator :
return " ':' " ;
case token_type : : value_separator :
return " ',' " ;
case token_type : : parse_error :
return " <parse error> " ;
case token_type : : end_of_input :
return " end of input " ;
case token_type : : literal_or_value :
return " '[', '{', or a literal " ;
default : // catch non-enum values
return " unknown token " ; // LCOV_EXCL_LINE
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
explicit lexer ( detail : : input_adapter_t adapter )
: ia ( std : : move ( adapter ) ) , decimal_point_char ( get_decimal_point ( ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// delete because of pointer members
lexer ( const lexer & ) = delete ;
lexer & operator = ( lexer & ) = delete ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/////////////////////
// locales
/////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return the locale-dependent decimal point
static char get_decimal_point ( ) noexcept
{
const auto loc = localeconv ( ) ;
assert ( loc ! = nullptr ) ;
return ( loc - > decimal_point = = nullptr ) ? ' . ' : * ( loc - > decimal_point ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/////////////////////
// scan functions
/////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get codepoint from 4 hex characters following ` \ u `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
For input " \ u c1 c2 c3 c4 " the codepoint is :
( c1 * 0x1000 ) + ( c2 * 0x0100 ) + ( c3 * 0x0010 ) + c4
= ( c1 < < 12 ) + ( c2 < < 8 ) + ( c3 < < 4 ) + ( c4 < < 0 )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Furthermore , the possible characters ' 0 ' . . ' 9 ' , ' A ' . . ' F ' , and ' a ' . . ' f '
must be converted to the integers 0x0 . .0 x9 , 0xA . .0 xF , 0xA . .0 xF , resp . The
conversion is done by subtracting the offset ( 0x30 , 0x37 , and 0x57 )
between the ASCII value of the character and the desired integer value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return codepoint ( 0x0000 . .0 xFFFF ) or - 1 in case of an error ( e . g . EOF or
non - hex character )
*/
int get_codepoint ( )
{
// this function only makes sense after reading `\u`
assert ( current = = ' u ' ) ;
int codepoint = 0 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const auto factors = { 12 , 8 , 4 , 0 } ;
for ( const auto factor : factors )
{
get ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( current > = ' 0 ' and current < = ' 9 ' )
{
codepoint + = ( ( current - 0x30 ) < < factor ) ;
}
else if ( current > = ' A ' and current < = ' F ' )
{
codepoint + = ( ( current - 0x37 ) < < factor ) ;
}
else if ( current > = ' a ' and current < = ' f ' )
{
codepoint + = ( ( current - 0x57 ) < < factor ) ;
}
else
{
return - 1 ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert ( 0x0000 < = codepoint and codepoint < = 0xFFFF ) ;
return codepoint ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief check if the next byte ( s ) are inside a given range
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Adds the current byte and , for each passed range , reads a new byte and
checks if it is inside the range . If a violation was detected , set up an
error message and return false . Otherwise , return true .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] ranges list of integers ; interpreted as list of pairs of
inclusive lower and upper bound , respectively
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The passed list @ a ranges must have 2 , 4 , or 6 elements ; that is ,
1 , 2 , or 3 pairs . This precondition is enforced by an assertion .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return true if and only if no range violation was detected
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
bool next_byte_in_range ( std : : initializer_list < int > ranges )
{
assert ( ranges . size ( ) = = 2 or ranges . size ( ) = = 4 or ranges . size ( ) = = 6 ) ;
add ( current ) ;
for ( auto range = ranges . begin ( ) ; range ! = ranges . end ( ) ; + + range )
{
get ( ) ;
if ( JSON_LIKELY ( * range < = current and current < = * ( + + range ) ) )
{
add ( current ) ;
}
else
{
error_message = " invalid string: ill-formed UTF-8 byte " ;
return false ;
}
}
return true ;
}
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief scan a string literal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function scans a string according to Sect . 7 of RFC 7159. While
scanning , bytes are escaped and copied into buffer token_buffer . Then the
function returns successfully , token_buffer is * not * null - terminated ( as it
may contain \ 0 bytes ) , and token_buffer . size ( ) is the number of bytes in the
string .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return token_type : : value_string if string could be successfully scanned ,
token_type : : parse_error otherwise
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note In case of errors , variable error_message contains a textual
description .
*/
token_type scan_string ( )
{
// reset token_buffer (ignore opening quote)
reset ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// we entered the function by reading an open quote
assert ( current = = ' \" ' ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
while ( true )
{
// get next character
switch ( get ( ) )
{
// end of file while parsing string
case std : : char_traits < char > : : eof ( ) :
{
error_message = " invalid string: missing closing quote " ;
return token_type : : parse_error ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing quote
case ' \" ' :
{
return token_type : : value_string ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// escapes
case ' \\ ' :
{
switch ( get ( ) )
{
// quotation mark
case ' \" ' :
add ( ' \" ' ) ;
break ;
// reverse solidus
case ' \\ ' :
add ( ' \\ ' ) ;
break ;
// solidus
case ' / ' :
add ( ' / ' ) ;
break ;
// backspace
case ' b ' :
add ( ' \b ' ) ;
break ;
// form feed
case ' f ' :
add ( ' \f ' ) ;
break ;
// line feed
case ' n ' :
add ( ' \n ' ) ;
break ;
// carriage return
case ' r ' :
add ( ' \r ' ) ;
break ;
// tab
case ' t ' :
add ( ' \t ' ) ;
break ;
// unicode escapes
case ' u ' :
{
const int codepoint1 = get_codepoint ( ) ;
int codepoint = codepoint1 ; // start with codepoint1
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( codepoint1 = = - 1 ) )
{
error_message = " invalid string: ' \\ u' must be followed by 4 hex digits " ;
return token_type : : parse_error ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if code point is a high surrogate
if ( 0xD800 < = codepoint1 and codepoint1 < = 0xDBFF )
{
// expect next \uxxxx entry
if ( JSON_LIKELY ( get ( ) = = ' \\ ' and get ( ) = = ' u ' ) )
{
const int codepoint2 = get_codepoint ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( codepoint2 = = - 1 ) )
{
error_message = " invalid string: ' \\ u' must be followed by 4 hex digits " ;
return token_type : : parse_error ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if codepoint2 is a low surrogate
if ( JSON_LIKELY ( 0xDC00 < = codepoint2 and codepoint2 < = 0xDFFF ) )
{
// overwrite codepoint
codepoint =
// high surrogate occupies the most significant 22 bits
( codepoint1 < < 10 )
// low surrogate occupies the least significant 15 bits
+ codepoint2
// there is still the 0xD800, 0xDC00 and 0x10000 noise
// in the result so we have to subtract with:
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
- 0x35FDC00 ;
}
else
{
error_message = " invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF " ;
return token_type : : parse_error ;
}
}
else
{
error_message = " invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF " ;
return token_type : : parse_error ;
}
}
else
{
if ( JSON_UNLIKELY ( 0xDC00 < = codepoint1 and codepoint1 < = 0xDFFF ) )
{
error_message = " invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF " ;
return token_type : : parse_error ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// result of the above calculation yields a proper codepoint
assert ( 0x00 < = codepoint and codepoint < = 0x10FFFF ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// translate codepoint into bytes
if ( codepoint < 0x80 )
{
// 1-byte characters: 0xxxxxxx (ASCII)
add ( codepoint ) ;
}
else if ( codepoint < = 0x7FF )
{
// 2-byte characters: 110xxxxx 10xxxxxx
add ( 0xC0 | ( codepoint > > 6 ) ) ;
add ( 0x80 | ( codepoint & 0x3F ) ) ;
}
else if ( codepoint < = 0xFFFF )
{
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
add ( 0xE0 | ( codepoint > > 12 ) ) ;
add ( 0x80 | ( ( codepoint > > 6 ) & 0x3F ) ) ;
add ( 0x80 | ( codepoint & 0x3F ) ) ;
}
else
{
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
add ( 0xF0 | ( codepoint > > 18 ) ) ;
add ( 0x80 | ( ( codepoint > > 12 ) & 0x3F ) ) ;
add ( 0x80 | ( ( codepoint > > 6 ) & 0x3F ) ) ;
add ( 0x80 | ( codepoint & 0x3F ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// other characters after escape
default :
error_message = " invalid string: forbidden character after backslash " ;
return token_type : : parse_error ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// invalid control characters
case 0x00 :
case 0x01 :
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
case 0x07 :
case 0x08 :
case 0x09 :
case 0x0A :
case 0x0B :
case 0x0C :
case 0x0D :
case 0x0E :
case 0x0F :
case 0x10 :
case 0x11 :
case 0x12 :
case 0x13 :
case 0x14 :
case 0x15 :
case 0x16 :
case 0x17 :
case 0x18 :
case 0x19 :
case 0x1A :
case 0x1B :
case 0x1C :
case 0x1D :
case 0x1E :
case 0x1F :
{
error_message = " invalid string: control character must be escaped " ;
return token_type : : parse_error ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
case 0x20 :
case 0x21 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2A :
case 0x2B :
case 0x2C :
case 0x2D :
case 0x2E :
case 0x2F :
case 0x30 :
case 0x31 :
case 0x32 :
case 0x33 :
case 0x34 :
case 0x35 :
case 0x36 :
case 0x37 :
case 0x38 :
case 0x39 :
case 0x3A :
case 0x3B :
case 0x3C :
case 0x3D :
case 0x3E :
case 0x3F :
case 0x40 :
case 0x41 :
case 0x42 :
case 0x43 :
case 0x44 :
case 0x45 :
case 0x46 :
case 0x47 :
case 0x48 :
case 0x49 :
case 0x4A :
case 0x4B :
case 0x4C :
case 0x4D :
case 0x4E :
case 0x4F :
case 0x50 :
case 0x51 :
case 0x52 :
case 0x53 :
case 0x54 :
case 0x55 :
case 0x56 :
case 0x57 :
case 0x58 :
case 0x59 :
case 0x5A :
case 0x5B :
case 0x5D :
case 0x5E :
case 0x5F :
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
case 0x78 :
case 0x79 :
case 0x7A :
case 0x7B :
case 0x7C :
case 0x7D :
case 0x7E :
case 0x7F :
{
add ( current ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+0080..U+07FF: bytes C2..DF 80..BF
case 0xC2 :
case 0xC3 :
case 0xC4 :
case 0xC5 :
case 0xC6 :
case 0xC7 :
case 0xC8 :
case 0xC9 :
case 0xCA :
case 0xCB :
case 0xCC :
case 0xCD :
case 0xCE :
case 0xCF :
case 0xD0 :
case 0xD1 :
case 0xD2 :
case 0xD3 :
case 0xD4 :
case 0xD5 :
case 0xD6 :
case 0xD7 :
case 0xD8 :
case 0xD9 :
case 0xDA :
case 0xDB :
case 0xDC :
case 0xDD :
case 0xDE :
case 0xDF :
{
if ( JSON_UNLIKELY ( not next_byte_in_range ( { 0x80 , 0xBF } ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case 0xE0 :
{
if ( JSON_UNLIKELY ( not ( next_byte_in_range ( { 0xA0 , 0xBF , 0x80 , 0xBF } ) ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
// U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
case 0xE1 :
case 0xE2 :
case 0xE3 :
case 0xE4 :
case 0xE5 :
case 0xE6 :
case 0xE7 :
case 0xE8 :
case 0xE9 :
case 0xEA :
case 0xEB :
case 0xEC :
case 0xEE :
case 0xEF :
{
if ( JSON_UNLIKELY ( not ( next_byte_in_range ( { 0x80 , 0xBF , 0x80 , 0xBF } ) ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+D000..U+D7FF: bytes ED 80..9F 80..BF
case 0xED :
{
if ( JSON_UNLIKELY ( not ( next_byte_in_range ( { 0x80 , 0x9F , 0x80 , 0xBF } ) ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case 0xF0 :
{
if ( JSON_UNLIKELY ( not ( next_byte_in_range ( { 0x90 , 0xBF , 0x80 , 0xBF , 0x80 , 0xBF } ) ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
case 0xF1 :
case 0xF2 :
case 0xF3 :
{
if ( JSON_UNLIKELY ( not ( next_byte_in_range ( { 0x80 , 0xBF , 0x80 , 0xBF , 0x80 , 0xBF } ) ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case 0xF4 :
{
if ( JSON_UNLIKELY ( not ( next_byte_in_range ( { 0x80 , 0x8F , 0x80 , 0xBF , 0x80 , 0xBF } ) ) ) )
{
return token_type : : parse_error ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// remaining bytes (80..C1 and F5..FF) are ill-formed
default :
{
error_message = " invalid string: ill-formed UTF-8 byte " ;
return token_type : : parse_error ;
}
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void strtof ( float & f , const char * str , char * * endptr ) noexcept
{
f = std : : strtof ( str , endptr ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void strtof ( double & f , const char * str , char * * endptr ) noexcept
{
f = std : : strtod ( str , endptr ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void strtof ( long double & f , const char * str , char * * endptr ) noexcept
{
f = std : : strtold ( str , endptr ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief scan a number literal
This function scans a string according to Sect . 6 of RFC 7159.
The function is realized with a deterministic finite state machine derived
from the grammar described in RFC 7159. Starting in state " init " , the
input is read and used to determined the next state . Only state " done "
accepts the number . State " error " is a trap state to model errors . In the
table below , " anything " means any character but the ones listed before .
state | 0 | 1 - 9 | e E | + | - | . | anything
- - - - - - - - - | - - - - - - - - - - | - - - - - - - - - - | - - - - - - - - - - | - - - - - - - - - | - - - - - - - - - | - - - - - - - - - - | - - - - - - - - - - -
init | zero | any1 | [ error ] | [ error ] | minus | [ error ] | [ error ]
minus | zero | any1 | [ error ] | [ error ] | [ error ] | [ error ] | [ error ]
zero | done | done | exponent | done | done | decimal1 | done
any1 | any1 | any1 | exponent | done | done | decimal1 | done
decimal1 | decimal2 | [ error ] | [ error ] | [ error ] | [ error ] | [ error ] | [ error ]
decimal2 | decimal2 | decimal2 | exponent | done | done | done | done
exponent | any2 | any2 | [ error ] | sign | sign | [ error ] | [ error ]
sign | any2 | any2 | [ error ] | [ error ] | [ error ] | [ error ] | [ error ]
any2 | any2 | any2 | done | done | done | done | done
The state machine is realized with one label per state ( prefixed with
" scan_number_ " ) and ` goto ` statements between them . The state machine
contains cycles , but any cycle can be left when EOF is read . Therefore ,
the function is guaranteed to terminate .
During scanning , the read bytes are stored in token_buffer . This string is
then converted to a signed integer , an unsigned integer , or a
floating - point number .
@ return token_type : : value_unsigned , token_type : : value_integer , or
token_type : : value_float if number could be successfully scanned ,
token_type : : parse_error otherwise
@ note The scanner is independent of the current locale . Internally , the
locale ' s decimal point is used instead of ` . ` to work with the
locale - dependent converters .
*/
token_type scan_number ( )
{
// reset token_buffer to store the number's bytes
reset ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// the type of the parsed number; initially set to unsigned; will be
// changed if minus sign, decimal point or exponent is read
token_type number_type = token_type : : value_unsigned ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// state (init): we just found out we need to scan a number
switch ( current )
{
case ' - ' :
{
add ( current ) ;
goto scan_number_minus ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' 0 ' :
{
add ( current ) ;
goto scan_number_zero ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_any1 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
// all other characters are rejected outside scan_number()
assert ( false ) ; // LCOV_EXCL_LINE
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_minus :
// state: we just parsed a leading minus sign
number_type = token_type : : value_integer ;
switch ( get ( ) )
{
case ' 0 ' :
{
add ( current ) ;
goto scan_number_zero ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_any1 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
error_message = " invalid number; expected digit after '-' " ;
return token_type : : parse_error ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_zero :
// state: we just parse a zero (maybe with a leading minus sign)
switch ( get ( ) )
{
case ' . ' :
{
add ( decimal_point_char ) ;
goto scan_number_decimal1 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' e ' :
case ' E ' :
{
add ( current ) ;
goto scan_number_exponent ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
goto scan_number_done ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_any1 :
// state: we just parsed a number 0-9 (maybe with a leading minus sign)
switch ( get ( ) )
{
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_any1 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' . ' :
{
add ( decimal_point_char ) ;
goto scan_number_decimal1 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' e ' :
case ' E ' :
{
add ( current ) ;
goto scan_number_exponent ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
goto scan_number_done ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_decimal1 :
// state: we just parsed a decimal point
number_type = token_type : : value_float ;
switch ( get ( ) )
{
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_decimal2 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
error_message = " invalid number; expected digit after '.' " ;
return token_type : : parse_error ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_decimal2 :
// we just parsed at least one number after a decimal point
switch ( get ( ) )
{
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_decimal2 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' e ' :
case ' E ' :
{
add ( current ) ;
goto scan_number_exponent ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
goto scan_number_done ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_exponent :
// we just parsed an exponent
number_type = token_type : : value_float ;
switch ( get ( ) )
{
case ' + ' :
case ' - ' :
{
add ( current ) ;
goto scan_number_sign ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_any2 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
error_message =
" invalid number; expected '+', '-', or digit after exponent " ;
return token_type : : parse_error ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_sign :
// we just parsed an exponent sign
switch ( get ( ) )
{
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_any2 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
error_message = " invalid number; expected digit after exponent sign " ;
return token_type : : parse_error ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_any2 :
// we just parsed a number after the exponent or exponent sign
switch ( get ( ) )
{
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
{
add ( current ) ;
goto scan_number_any2 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
goto scan_number_done ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
scan_number_done :
// unget the character after the number (we only read it to know that
// we are done scanning a number)
unget ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
char * endptr = nullptr ;
errno = 0 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// try to parse integers first and fall back to floats
if ( number_type = = token_type : : value_unsigned )
{
const auto x = std : : strtoull ( token_buffer . data ( ) , & endptr , 10 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// we checked the number format before
assert ( endptr = = token_buffer . data ( ) + token_buffer . size ( ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( errno = = 0 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
value_unsigned = static_cast < number_unsigned_t > ( x ) ;
if ( value_unsigned = = x )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return token_type : : value_unsigned ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
}
else if ( number_type = = token_type : : value_integer )
{
const auto x = std : : strtoll ( token_buffer . data ( ) , & endptr , 10 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// we checked the number format before
assert ( endptr = = token_buffer . data ( ) + token_buffer . size ( ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( errno = = 0 )
{
value_integer = static_cast < number_integer_t > ( x ) ;
if ( value_integer = = x )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return token_type : : value_integer ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// this code is reached if we parse a floating-point number or if an
// integer conversion above failed
strtof ( value_float , token_buffer . data ( ) , & endptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// we checked the number format before
assert ( endptr = = token_buffer . data ( ) + token_buffer . size ( ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return token_type : : value_float ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ param [ in ] literal_text the literal text to expect
@ param [ in ] length the length of the passed literal text
@ param [ in ] return_type the token type to return on success
*/
token_type scan_literal ( const char * literal_text , const std : : size_t length ,
token_type return_type )
{
assert ( current = = literal_text [ 0 ] ) ;
for ( std : : size_t i = 1 ; i < length ; + + i )
{
if ( JSON_UNLIKELY ( get ( ) ! = literal_text [ i ] ) )
{
error_message = " invalid literal " ;
return token_type : : parse_error ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
return return_type ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/////////////////////
// input management
/////////////////////
/// reset token_buffer; current character is beginning of token
void reset ( ) noexcept
{
token_buffer . clear ( ) ;
token_string . clear ( ) ;
token_string . push_back ( std : : char_traits < char > : : to_char_type ( current ) ) ;
}
/*
@ brief get next character from the input
This function provides the interface to the used input adapter . It does
not throw in case the input reached EOF , but returns a
` std : : char_traits < char > : : eof ( ) ` in that case . Stores the scanned characters
for use in error messages .
@ return character read from the input
*/
std : : char_traits < char > : : int_type get ( )
{
+ + chars_read ;
current = ia - > get_character ( ) ;
if ( JSON_LIKELY ( current ! = std : : char_traits < char > : : eof ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
token_string . push_back ( std : : char_traits < char > : : to_char_type ( current ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return current ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// unget current character (return it again on next get)
void unget ( )
{
- - chars_read ;
if ( JSON_LIKELY ( current ! = std : : char_traits < char > : : eof ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
ia - > unget_character ( ) ;
assert ( token_string . size ( ) ! = 0 ) ;
token_string . pop_back ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// add a character to token_buffer
void add ( int c )
{
token_buffer . push_back ( std : : char_traits < char > : : to_char_type ( c ) ) ;
}
public :
/////////////////////
// value getters
/////////////////////
/// return integer value
constexpr number_integer_t get_number_integer ( ) const noexcept
{
return value_integer ;
}
/// return unsigned integer value
constexpr number_unsigned_t get_number_unsigned ( ) const noexcept
{
return value_unsigned ;
}
/// return floating-point value
constexpr number_float_t get_number_float ( ) const noexcept
{
return value_float ;
}
/// return current string value (implicitly resets the token; useful only once)
string_t & & move_string ( )
{
return std : : move ( token_buffer ) ;
}
/////////////////////
// diagnostics
/////////////////////
/// return position of last read token
constexpr std : : size_t get_position ( ) const noexcept
{
return chars_read ;
}
/// return the last read token (for errors only). Will never contain EOF
/// (an arbitrary value that is not a valid char value, often -1), because
/// 255 may legitimately occur. May contain NUL, which should be escaped.
std : : string get_token_string ( ) const
{
// escape control characters
std : : string result ;
for ( const auto c : token_string )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( ' \x00 ' < = c and c < = ' \x1F ' )
{
// escape control characters
std : : stringstream ss ;
ss < < " <U+ " < < std : : setw ( 4 ) < < std : : uppercase < < std : : setfill ( ' 0 ' )
< < std : : hex < < static_cast < int > ( c ) < < " > " ;
result + = ss . str ( ) ;
}
else
{
// add character as is
result . push_back ( c ) ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return syntax error message
constexpr const char * get_error_message ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return error_message ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/////////////////////
// actual scanner
/////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
token_type scan ( )
{
// read next character and ignore whitespace
do
{
get ( ) ;
}
while ( current = = ' ' or current = = ' \t ' or current = = ' \n ' or current = = ' \r ' ) ;
switch ( current )
{
// structural characters
case ' [ ' :
return token_type : : begin_array ;
case ' ] ' :
return token_type : : end_array ;
case ' { ' :
return token_type : : begin_object ;
case ' } ' :
return token_type : : end_object ;
case ' : ' :
return token_type : : name_separator ;
case ' , ' :
return token_type : : value_separator ;
// literals
case ' t ' :
return scan_literal ( " true " , 4 , token_type : : literal_true ) ;
case ' f ' :
return scan_literal ( " false " , 5 , token_type : : literal_false ) ;
case ' n ' :
return scan_literal ( " null " , 4 , token_type : : literal_null ) ;
// string
case ' \" ' :
return scan_string ( ) ;
// number
case ' - ' :
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
return scan_number ( ) ;
// end of input (the null byte is needed when parsing from
// string literals)
case ' \0 ' :
case std : : char_traits < char > : : eof ( ) :
return token_type : : end_of_input ;
// error
default :
error_message = " invalid literal " ;
return token_type : : parse_error ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/// input adapter
detail : : input_adapter_t ia = nullptr ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the current character
std : : char_traits < char > : : int_type current = std : : char_traits < char > : : eof ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the number of characters read
std : : size_t chars_read = 0 ;
/// raw input token string (for error messages)
std : : vector < char > token_string { } ;
/// buffer for variable-length tokens (numbers, strings)
string_t token_buffer { } ;
/// a description of occurred lexer errors
const char * error_message = " " ;
// number values
number_integer_t value_integer = 0 ;
number_unsigned_t value_unsigned = 0 ;
number_float_t value_float = 0 ;
/// the decimal point
const char decimal_point_char = ' . ' ;
} ;
}
}
// #include <nlohmann/detail/input/parser.hpp>
# include <cassert> // assert
# include <cmath> // isfinite
# include <cstdint> // uint8_t
# include <functional> // function
# include <string> // string
# include <utility> // move
// #include <nlohmann/detail/exceptions.hpp>
// #include <nlohmann/detail/macro_scope.hpp>
// #include <nlohmann/detail/input/input_adapters.hpp>
// #include <nlohmann/detail/input/lexer.hpp>
// #include <nlohmann/detail/value_t.hpp>
namespace nlohmann
{
namespace detail
{
////////////
// parser //
////////////
/*!
@ brief syntax analysis
This class implements a recursive decent parser .
*/
template < typename BasicJsonType >
class parser
{
using number_integer_t = typename BasicJsonType : : number_integer_t ;
using number_unsigned_t = typename BasicJsonType : : number_unsigned_t ;
using number_float_t = typename BasicJsonType : : number_float_t ;
using string_t = typename BasicJsonType : : string_t ;
using lexer_t = lexer < BasicJsonType > ;
using token_type = typename lexer_t : : token_type ;
public :
2017-07-18 05:37:27 +02:00
enum class parse_event_t : uint8_t
{
/// the parser read `{` and started to process a JSON object
object_start ,
/// the parser read `}` and finished processing a JSON object
object_end ,
/// the parser read `[` and started to process a JSON array
array_start ,
/// the parser read `]` and finished processing a JSON array
array_end ,
/// the parser read a key of a value in an object
key ,
/// the parser finished reading a JSON value
value
} ;
2018-05-19 21:59:03 +02:00
using parser_callback_t =
std : : function < bool ( int depth , parse_event_t event , BasicJsonType & parsed ) > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// a parser reading from an input adapter
explicit parser ( detail : : input_adapter_t adapter ,
const parser_callback_t cb = nullptr ,
const bool allow_exceptions_ = true )
: callback ( cb ) , m_lexer ( adapter ) , allow_exceptions ( allow_exceptions_ )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief public parser interface
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] strict whether to expect the last token to be EOF
@ param [ in , out ] result parsed JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .101 in case of an unexpected token
@ throw parse_error .102 if to_unicode fails or surrogate error
@ throw parse_error .103 if to_unicode fails
*/
void parse ( const bool strict , BasicJsonType & result )
{
// read first token
get_token ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
parse_internal ( true , result ) ;
result . assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// in strict mode, input must be completely read
if ( strict )
{
get_token ( ) ;
expect ( token_type : : end_of_input ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// in case of an error, return discarded value
if ( errored )
{
result = value_t : : discarded ;
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// set top-level value to null if it was discarded by the callback
// function
if ( result . is_discarded ( ) )
{
result = nullptr ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief public accept interface
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] strict whether to expect the last token to be EOF
@ return whether the input is a proper JSON text
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
bool accept ( const bool strict = true )
{
// read first token
get_token ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( not accept_internal ( ) )
{
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// strict => last token must be EOF
return not strict or ( get_token ( ) = = token_type : : end_of_input ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief the actual parser
@ throw parse_error .101 in case of an unexpected token
@ throw parse_error .102 if to_unicode fails or surrogate error
@ throw parse_error .103 if to_unicode fails
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void parse_internal ( bool keep , BasicJsonType & result )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// never parse after a parse error was detected
assert ( not errored ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// start with a discarded value
if ( not result . is_discarded ( ) )
{
result . m_value . destroy ( result . m_type ) ;
result . m_type = value_t : : discarded ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( last_token )
{
case token_type : : begin_object :
{
if ( keep )
{
if ( callback )
{
keep = callback ( depth + + , parse_event_t : : object_start , result ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( not callback or keep )
{
// explicitly set result to object to cope with {}
result . m_type = value_t : : object ;
result . m_value = value_t : : object ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// read next token
get_token ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing } -> we are done
if ( last_token = = token_type : : end_object )
{
if ( keep and callback and not callback ( - - depth , parse_event_t : : object_end , result ) )
{
result . m_value . destroy ( result . m_type ) ;
result . m_type = value_t : : discarded ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse values
string_t key ;
BasicJsonType value ;
while ( true )
{
// store key
if ( not expect ( token_type : : value_string ) )
{
return ;
}
key = m_lexer . move_string ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
bool keep_tag = false ;
if ( keep )
{
if ( callback )
{
BasicJsonType k ( key ) ;
keep_tag = callback ( depth , parse_event_t : : key , k ) ;
}
else
{
keep_tag = true ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse separator (:)
get_token ( ) ;
if ( not expect ( token_type : : name_separator ) )
{
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse and add value
get_token ( ) ;
value . m_value . destroy ( value . m_type ) ;
value . m_type = value_t : : discarded ;
parse_internal ( keep , value ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( errored ) )
{
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( keep and keep_tag and not value . is_discarded ( ) )
{
result . m_value . object - > emplace ( std : : move ( key ) , std : : move ( value ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// comma -> next value
get_token ( ) ;
if ( last_token = = token_type : : value_separator )
{
get_token ( ) ;
continue ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing }
if ( not expect ( token_type : : end_object ) )
{
return ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( keep and callback and not callback ( - - depth , parse_event_t : : object_end , result ) )
{
result . m_value . destroy ( result . m_type ) ;
result . m_type = value_t : : discarded ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : begin_array :
{
if ( keep )
{
if ( callback )
{
keep = callback ( depth + + , parse_event_t : : array_start , result ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( not callback or keep )
{
// explicitly set result to array to cope with []
result . m_type = value_t : : array ;
result . m_value = value_t : : array ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// read next token
get_token ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing ] -> we are done
if ( last_token = = token_type : : end_array )
{
if ( callback and not callback ( - - depth , parse_event_t : : array_end , result ) )
{
result . m_value . destroy ( result . m_type ) ;
result . m_type = value_t : : discarded ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse values
BasicJsonType value ;
while ( true )
{
// parse value
value . m_value . destroy ( value . m_type ) ;
value . m_type = value_t : : discarded ;
parse_internal ( keep , value ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( errored ) )
{
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( keep and not value . is_discarded ( ) )
{
result . m_value . array - > push_back ( std : : move ( value ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// comma -> next value
get_token ( ) ;
if ( last_token = = token_type : : value_separator )
{
get_token ( ) ;
continue ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing ]
if ( not expect ( token_type : : end_array ) )
{
return ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( keep and callback and not callback ( - - depth , parse_event_t : : array_end , result ) )
{
result . m_value . destroy ( result . m_type ) ;
result . m_type = value_t : : discarded ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : literal_null :
{
result . m_type = value_t : : null ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : value_string :
{
result . m_type = value_t : : string ;
result . m_value = m_lexer . move_string ( ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : literal_true :
{
result . m_type = value_t : : boolean ;
result . m_value = true ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : literal_false :
{
result . m_type = value_t : : boolean ;
result . m_value = false ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : value_unsigned :
{
result . m_type = value_t : : number_unsigned ;
result . m_value = m_lexer . get_number_unsigned ( ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : value_integer :
{
result . m_type = value_t : : number_integer ;
result . m_value = m_lexer . get_number_integer ( ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : value_float :
{
result . m_type = value_t : : number_float ;
result . m_value = m_lexer . get_number_float ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// throw in case of infinity or NAN
if ( JSON_UNLIKELY ( not std : : isfinite ( result . m_value . number_float ) ) )
{
if ( allow_exceptions )
{
JSON_THROW ( out_of_range : : create ( 406 , " number overflow parsing ' " +
m_lexer . get_token_string ( ) + " ' " ) ) ;
}
expect ( token_type : : uninitialized ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : parse_error :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// using "uninitialized" to avoid "expected" message
if ( not expect ( token_type : : uninitialized ) )
{
return ;
}
break ; // LCOV_EXCL_LINE
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
default :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// the last token was unexpected; we expected a value
if ( not expect ( token_type : : literal_or_value ) )
{
return ;
}
break ; // LCOV_EXCL_LINE
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
if ( keep and callback and not callback ( depth , parse_event_t : : value , result ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
result . m_value . destroy ( result . m_type ) ;
result . m_type = value_t : : discarded ;
2017-07-18 05:37:27 +02:00
}
}
/*!
2018-05-19 21:59:03 +02:00
@ brief the actual acceptor
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ invariant 1. The last token is not yet processed . Therefore , the caller
of this function must make sure a token has been read .
2. When this function returns , the last token is processed .
That is , the last read character was already considered .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This invariant makes sure that no token needs to be " unput " .
*/
bool accept_internal ( )
{
switch ( last_token )
{
case token_type : : begin_object :
{
// read next token
get_token ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing } -> we are done
if ( last_token = = token_type : : end_object )
{
return true ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse values
while ( true )
{
// parse key
if ( last_token ! = token_type : : value_string )
{
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse separator (:)
get_token ( ) ;
if ( last_token ! = token_type : : name_separator )
{
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse value
get_token ( ) ;
if ( not accept_internal ( ) )
{
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// comma -> next value
get_token ( ) ;
if ( last_token = = token_type : : value_separator )
{
get_token ( ) ;
continue ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing }
return ( last_token = = token_type : : end_object ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : begin_array :
{
// read next token
get_token ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing ] -> we are done
if ( last_token = = token_type : : end_array )
{
return true ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// parse values
while ( true )
{
// parse value
if ( not accept_internal ( ) )
{
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// comma -> next value
get_token ( ) ;
if ( last_token = = token_type : : value_separator )
{
get_token ( ) ;
continue ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// closing ]
return ( last_token = = token_type : : end_array ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : value_float :
{
// reject infinity or NAN
return std : : isfinite ( m_lexer . get_number_float ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case token_type : : literal_false :
case token_type : : literal_null :
case token_type : : literal_true :
case token_type : : value_integer :
case token_type : : value_string :
case token_type : : value_unsigned :
return true ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default : // the last token was unexpected
return false ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get next token from lexer
token_type get_token ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( last_token = m_lexer . scan ( ) ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ throw parse_error .101 if expected token did not occur
*/
bool expect ( token_type t )
{
if ( JSON_UNLIKELY ( t ! = last_token ) )
{
errored = true ;
expected = t ;
if ( allow_exceptions )
{
throw_exception ( ) ;
}
else
{
return false ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return true ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[[noreturn]] void throw_exception ( ) const
{
std : : string error_msg = " syntax error - " ;
if ( last_token = = token_type : : parse_error )
{
error_msg + = std : : string ( m_lexer . get_error_message ( ) ) + " ; last read: ' " +
m_lexer . get_token_string ( ) + " ' " ;
}
else
{
error_msg + = " unexpected " + std : : string ( lexer_t : : token_type_name ( last_token ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( expected ! = token_type : : uninitialized )
{
error_msg + = " ; expected " + std : : string ( lexer_t : : token_type_name ( expected ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( parse_error : : create ( 101 , m_lexer . get_position ( ) , error_msg ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
/// current level of recursion
int depth = 0 ;
/// callback function
const parser_callback_t callback = nullptr ;
/// the type of the last read token
token_type last_token = token_type : : uninitialized ;
/// the lexer
lexer_t m_lexer ;
/// whether a syntax error occurred
bool errored = false ;
/// possible reason for the syntax error
token_type expected = token_type : : uninitialized ;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <cstddef> // ptrdiff_t
# include <limits> // numeric_limits
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
/*
@ brief an iterator for primitive JSON types
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This class models an iterator for primitive JSON types ( boolean , number ,
string ) . It ' s only purpose is to allow the iterator / const_iterator classes
to " iterate " over primitive values . Internally , the iterator is modeled by
a ` difference_type ` variable . Value begin_value ( ` 0 ` ) models the begin ,
end_value ( ` 1 ` ) models past the end .
*/
class primitive_iterator_t
{
private :
using difference_type = std : : ptrdiff_t ;
static constexpr difference_type begin_value = 0 ;
static constexpr difference_type end_value = begin_value + 1 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// iterator as signed integer type
difference_type m_it = ( std : : numeric_limits < std : : ptrdiff_t > : : min ) ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
constexpr difference_type get_value ( ) const noexcept
{
return m_it ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// set iterator to a defined beginning
void set_begin ( ) noexcept
{
m_it = begin_value ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// set iterator to a defined past the end
void set_end ( ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_it = end_value ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return whether the iterator can be dereferenced
constexpr bool is_begin ( ) const noexcept
{
return m_it = = begin_value ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return whether the iterator is at end
constexpr bool is_end ( ) const noexcept
{
return m_it = = end_value ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
friend constexpr bool operator = = ( primitive_iterator_t lhs , primitive_iterator_t rhs ) noexcept
{
return lhs . m_it = = rhs . m_it ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
friend constexpr bool operator < ( primitive_iterator_t lhs , primitive_iterator_t rhs ) noexcept
{
return lhs . m_it < rhs . m_it ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t operator + ( difference_type n ) noexcept
{
auto result = * this ;
result + = n ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
friend constexpr difference_type operator - ( primitive_iterator_t lhs , primitive_iterator_t rhs ) noexcept
{
return lhs . m_it - rhs . m_it ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t & operator + + ( ) noexcept
{
+ + m_it ;
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t const operator + + ( int ) noexcept
{
auto result = * this ;
m_it + + ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t & operator - - ( ) noexcept
{
- - m_it ;
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t const operator - - ( int ) noexcept
{
auto result = * this ;
m_it - - ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t & operator + = ( difference_type n ) noexcept
{
m_it + = n ;
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
primitive_iterator_t & operator - = ( difference_type n ) noexcept
{
m_it - = n ;
return * this ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
/*!
@ brief an iterator value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This structure could easily be a union , but MSVC currently does not allow
unions members with complex constructors , see https : //github.com/nlohmann/json/pull/105.
*/
template < typename BasicJsonType > struct internal_iterator
{
/// iterator for JSON objects
typename BasicJsonType : : object_t : : iterator object_iterator { } ;
/// iterator for JSON arrays
typename BasicJsonType : : array_t : : iterator array_iterator { } ;
/// generic iterator for all other types
primitive_iterator_t primitive_iterator { } ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/iterators/iter_impl.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <ciso646> // not
# include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
# include <type_traits> // conditional, is_const, remove_const
// #include <nlohmann/detail/exceptions.hpp>
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
// #include <nlohmann/detail/macro_scope.hpp>
// #include <nlohmann/detail/meta.hpp>
// #include <nlohmann/detail/value_t.hpp>
namespace nlohmann
{
namespace detail
{
// forward declare, to be able to friend it later on
template < typename IteratorType > class iteration_proxy ;
/*!
@ brief a template for a bidirectional iterator for the @ ref basic_json class
This class implements a both iterators ( iterator and const_iterator ) for the
@ ref basic_json class .
@ note An iterator is called * initialized * when a pointer to a JSON value has
been set ( e . g . , by a constructor or a copy assignment ) . If the iterator is
default - constructed , it is * uninitialized * and most methods are undefined .
* * The library uses assertions to detect calls on uninitialized iterators . * *
@ requirement The class satisfies the following concept requirements :
-
[ BidirectionalIterator ] ( http : //en.cppreference.com/w/cpp/concept/BidirectionalIterator):
The iterator that can be moved can be moved in both directions ( i . e .
incremented and decremented ) .
@ since version 1.0 .0 , simplified in version 2.0 .9 , change to bidirectional
iterators in version 3.0 .0 ( see https : //github.com/nlohmann/json/issues/593)
*/
template < typename BasicJsonType >
class iter_impl
{
/// allow basic_json to access private members
friend iter_impl < typename std : : conditional < std : : is_const < BasicJsonType > : : value , typename std : : remove_const < BasicJsonType > : : type , const BasicJsonType > : : type > ;
friend BasicJsonType ;
friend iteration_proxy < iter_impl > ;
using object_t = typename BasicJsonType : : object_t ;
using array_t = typename BasicJsonType : : array_t ;
// make sure BasicJsonType is basic_json or const basic_json
static_assert ( is_basic_json < typename std : : remove_const < BasicJsonType > : : type > : : value ,
" iter_impl only accepts (const) basic_json " ) ;
public :
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
/// The C++ Standard has never required user-defined iterators to derive from std::iterator.
/// A user-defined iterator should provide publicly accessible typedefs named
/// iterator_category, value_type, difference_type, pointer, and reference.
/// Note that value_type is required to be non-const, even for constant iterators.
using iterator_category = std : : bidirectional_iterator_tag ;
/// the type of the values when the iterator is dereferenced
using value_type = typename BasicJsonType : : value_type ;
/// a type to represent differences between iterators
using difference_type = typename BasicJsonType : : difference_type ;
/// defines a pointer to the type iterated over (value_type)
using pointer = typename std : : conditional < std : : is_const < BasicJsonType > : : value ,
typename BasicJsonType : : const_pointer ,
typename BasicJsonType : : pointer > : : type ;
/// defines a reference to the type iterated over (value_type)
using reference =
typename std : : conditional < std : : is_const < BasicJsonType > : : value ,
typename BasicJsonType : : const_reference ,
typename BasicJsonType : : reference > : : type ;
/// default constructor
iter_impl ( ) = default ;
/*!
@ brief constructor for a given JSON instance
@ param [ in ] object pointer to a JSON object for this iterator
@ pre object ! = nullptr
@ post The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
explicit iter_impl ( pointer object ) noexcept : m_object ( object )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
2017-07-18 05:37:27 +02:00
{
case value_t : : object :
{
2018-05-19 21:59:03 +02:00
m_it . object_iterator = typename object_t : : iterator ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
case value_t : : array :
{
2018-05-19 21:59:03 +02:00
m_it . array_iterator = typename array_t : : iterator ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
2018-05-19 21:59:03 +02:00
default :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_it . primitive_iterator = primitive_iterator_t ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
2018-05-19 21:59:03 +02:00
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ note The conventional copy constructor and copy assignment are implicitly
defined . Combined with the following converting constructor and
assignment , they support : ( 1 ) copy from iterator to iterator , ( 2 )
copy from const iterator to const iterator , and ( 3 ) conversion from
iterator to const iterator . However conversion from const iterator
to iterator is not defined .
*/
/*!
@ brief converting constructor
@ param [ in ] other non - const iterator to copy from
@ note It is not checked whether @ a other is initialized .
*/
iter_impl ( const iter_impl < typename std : : remove_const < BasicJsonType > : : type > & other ) noexcept
: m_object ( other . m_object ) , m_it ( other . m_it ) { }
/*!
@ brief converting assignment
@ param [ in , out ] other non - const iterator to copy from
@ return const / non - const iterator
@ note It is not checked whether @ a other is initialized .
*/
iter_impl & operator = ( const iter_impl < typename std : : remove_const < BasicJsonType > : : type > & other ) noexcept
{
m_object = other . m_object ;
m_it = other . m_it ;
return * this ;
}
private :
/*!
@ brief set the iterator to the first value
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
void set_begin ( ) noexcept
{
assert ( m_object ! = nullptr ) ;
switch ( m_object - > m_type )
{
case value_t : : object :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_it . object_iterator = m_object - > m_value . object - > begin ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
2018-05-19 21:59:03 +02:00
case value_t : : array :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_it . array_iterator = m_object - > m_value . array - > begin ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
2018-05-19 21:59:03 +02:00
case value_t : : null :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// set to end so begin()==end() is true: null is empty
m_it . primitive_iterator . set_end ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
2018-05-19 21:59:03 +02:00
default :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_it . primitive_iterator . set_begin ( ) ;
break ;
}
}
}
/*!
@ brief set the iterator past the last value
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
void set_end ( ) noexcept
{
assert ( m_object ! = nullptr ) ;
switch ( m_object - > m_type )
{
case value_t : : object :
{
m_it . object_iterator = m_object - > m_value . object - > end ( ) ;
break ;
}
case value_t : : array :
{
m_it . array_iterator = m_object - > m_value . array - > end ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
default :
{
2018-05-19 21:59:03 +02:00
m_it . primitive_iterator . set_end ( ) ;
2017-07-18 05:37:27 +02:00
break ;
}
}
}
2018-05-19 21:59:03 +02:00
public :
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief return a reference to the value pointed to by the iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
reference operator * ( ) const
{
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
{
assert ( m_it . object_iterator ! = m_object - > m_value . object - > end ( ) ) ;
return m_it . object_iterator - > second ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
assert ( m_it . array_iterator ! = m_object - > m_value . array - > end ( ) ) ;
return * m_it . array_iterator ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : null :
JSON_THROW ( invalid_iterator : : create ( 214 , " cannot get value " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
if ( JSON_LIKELY ( m_it . primitive_iterator . is_begin ( ) ) )
{
return * m_object ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 214 , " cannot get value " ) ) ;
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief dereference the iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
pointer operator - > ( ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
{
assert ( m_it . object_iterator ! = m_object - > m_value . object - > end ( ) ) ;
return & ( m_it . object_iterator - > second ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
assert ( m_it . array_iterator ! = m_object - > m_value . array - > end ( ) ) ;
return & * m_it . array_iterator ;
}
default :
{
if ( JSON_LIKELY ( m_it . primitive_iterator . is_begin ( ) ) )
{
return m_object ;
}
JSON_THROW ( invalid_iterator : : create ( 214 , " cannot get value " ) ) ;
}
}
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief post - increment ( it + + )
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
iter_impl const operator + + ( int )
{
auto result = * this ;
+ + ( * this ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief pre - increment ( + + it )
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
iter_impl & operator + + ( )
{
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
{
std : : advance ( m_it . object_iterator , 1 ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
std : : advance ( m_it . array_iterator , 1 ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
+ + m_it . primitive_iterator ;
break ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief post - decrement ( it - - )
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
iter_impl const operator - - ( int )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
auto result = * this ;
- - ( * this ) ;
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief pre - decrement ( - - it )
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
iter_impl & operator - - ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
2017-07-18 05:37:27 +02:00
{
case value_t : : object :
{
2018-05-19 21:59:03 +02:00
std : : advance ( m_it . object_iterator , - 1 ) ;
2017-07-18 05:37:27 +02:00
break ;
}
case value_t : : array :
{
2018-05-19 21:59:03 +02:00
std : : advance ( m_it . array_iterator , - 1 ) ;
2017-07-18 05:37:27 +02:00
break ;
}
default :
{
2018-05-19 21:59:03 +02:00
- - m_it . primitive_iterator ;
2017-07-18 05:37:27 +02:00
break ;
}
}
2018-05-19 21:59:03 +02:00
return * this ;
}
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief comparison : equal
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
bool operator = = ( const iter_impl & other ) const
{
// if objects are not the same, the comparison is undefined
if ( JSON_UNLIKELY ( m_object ! = other . m_object ) )
{
JSON_THROW ( invalid_iterator : : create ( 212 , " cannot compare iterators of different containers " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
return ( m_it . object_iterator = = other . m_it . object_iterator ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
return ( m_it . array_iterator = = other . m_it . array_iterator ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
return ( m_it . primitive_iterator = = other . m_it . primitive_iterator ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : not equal
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
bool operator ! = ( const iter_impl & other ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return not operator = = ( other ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : smaller
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
bool operator < ( const iter_impl & other ) const
{
// if objects are not the same, the comparison is undefined
if ( JSON_UNLIKELY ( m_object ! = other . m_object ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 212 , " cannot compare iterators of different containers " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
assert ( m_object ! = nullptr ) ;
switch ( m_object - > m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : object :
JSON_THROW ( invalid_iterator : : create ( 213 , " cannot compare order of object iterators " ) ) ;
case value_t : : array :
return ( m_it . array_iterator < other . m_it . array_iterator ) ;
default :
return ( m_it . primitive_iterator < other . m_it . primitive_iterator ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than or equal
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
bool operator < = ( const iter_impl & other ) const
{
return not other . operator < ( * this ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief comparison : greater than
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
bool operator > ( const iter_impl & other ) const
{
return not operator < = ( other ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than or equal
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
bool operator > = ( const iter_impl & other ) const
{
return not operator < ( other ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief add to iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
iter_impl & operator + = ( difference_type i )
{
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
JSON_THROW ( invalid_iterator : : create ( 209 , " cannot use offsets with object iterators " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
std : : advance ( m_it . array_iterator , i ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
m_it . primitive_iterator + = i ;
break ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return * this ;
}
/*!
@ brief subtract from iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
iter_impl & operator - = ( difference_type i )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return operator + = ( - i ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief add to iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
iter_impl operator + ( difference_type i ) const
{
auto result = * this ;
result + = i ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief addition of distance and iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
friend iter_impl operator + ( difference_type i , const iter_impl & it )
{
auto result = it ;
result + = i ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief subtract from iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
iter_impl operator - ( difference_type i ) const
{
auto result = * this ;
result - = i ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return difference
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
difference_type operator - ( const iter_impl & other ) const
{
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
JSON_THROW ( invalid_iterator : : create ( 209 , " cannot use offsets with object iterators " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
return m_it . array_iterator - other . m_it . array_iterator ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
return m_it . primitive_iterator - other . m_it . primitive_iterator ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access to successor
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
reference operator [ ] ( difference_type n ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_object - > m_type )
{
case value_t : : object :
JSON_THROW ( invalid_iterator : : create ( 208 , " cannot use operator[] for object iterators " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
return * std : : next ( m_it . array_iterator , n ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : null :
JSON_THROW ( invalid_iterator : : create ( 214 , " cannot get value " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
if ( JSON_LIKELY ( m_it . primitive_iterator . get_value ( ) = = - n ) )
{
return * m_object ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 214 , " cannot get value " ) ) ;
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return the key of an object iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
*/
typename object_t : : key_type key ( ) const
{
assert ( m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_LIKELY ( m_object - > is_object ( ) ) )
{
return m_it . object_iterator - > first ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 207 , " cannot use key() for non-object iterators " ) ) ;
}
/*!
@ brief return the value of an iterator
@ pre The iterator is initialized ; i . e . ` m_object ! = nullptr ` .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
reference value ( ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return operator * ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
/// associated JSON instance
pointer m_object = nullptr ;
/// the actual iterator of the associated instance
internal_iterator < typename std : : remove_const < BasicJsonType > : : type > m_it ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <cstddef> // size_t
# include <string> // string, to_string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
/// proxy class for the items() function
template < typename IteratorType > class iteration_proxy
{
private :
/// helper class for iteration
class iteration_proxy_internal
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
private :
/// the iterator
IteratorType anchor ;
/// an index for arrays (used to create key names)
std : : size_t array_index = 0 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
explicit iteration_proxy_internal ( IteratorType it ) noexcept : anchor ( it ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// dereference operator (needed for range-based for)
iteration_proxy_internal & operator * ( )
{
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// increment operator (needed for range-based for)
iteration_proxy_internal & operator + + ( )
{
+ + anchor ;
+ + array_index ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// inequality operator (needed for range-based for)
bool operator ! = ( const iteration_proxy_internal & o ) const noexcept
{
return anchor ! = o . anchor ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return key of the iterator
std : : string key ( ) const
{
assert ( anchor . m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( anchor . m_object - > type ( ) )
{
// use integer array index as key
case value_t : : array :
return std : : to_string ( array_index ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// use key from the object
case value_t : : object :
return anchor . key ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// use an empty key for all primitive types
default :
return " " ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return value of the iterator
typename IteratorType : : reference value ( ) const
{
return anchor . value ( ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the container to iterate
typename IteratorType : : reference container ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
/// construct iteration proxy from a container
explicit iteration_proxy ( typename IteratorType : : reference cont ) noexcept
: container ( cont ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return iterator begin (needed for range-based for)
iteration_proxy_internal begin ( ) noexcept
{
return iteration_proxy_internal ( container . begin ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return iterator end (needed for range-based for)
iteration_proxy_internal end ( ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return iteration_proxy_internal ( container . end ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <cstddef> // ptrdiff_t
# include <iterator> // reverse_iterator
# include <utility> // declval
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
//////////////////////
// reverse_iterator //
//////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief a template for a reverse iterator class
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam Base the base iterator type to reverse . Valid types are @ ref
iterator ( to create @ ref reverse_iterator ) and @ ref const_iterator ( to
create @ ref const_reverse_iterator ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ requirement The class satisfies the following concept requirements :
-
[ BidirectionalIterator ] ( http : //en.cppreference.com/w/cpp/concept/BidirectionalIterator):
The iterator that can be moved can be moved in both directions ( i . e .
incremented and decremented ) .
- [ OutputIterator ] ( http : //en.cppreference.com/w/cpp/concept/OutputIterator):
It is possible to write to the pointed - to element ( only if @ a Base is
@ ref iterator ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < typename Base >
class json_reverse_iterator : public std : : reverse_iterator < Base >
{
public :
using difference_type = std : : ptrdiff_t ;
/// shortcut to the reverse iterator adapter
using base_iterator = std : : reverse_iterator < Base > ;
/// the reference type for the pointed-to element
using reference = typename Base : : reference ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// create reverse iterator from iterator
json_reverse_iterator ( const typename base_iterator : : iterator_type & it ) noexcept
: base_iterator ( it ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// create reverse iterator from base class
json_reverse_iterator ( const base_iterator & it ) noexcept : base_iterator ( it ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// post-increment (it++)
json_reverse_iterator const operator + + ( int )
{
return static_cast < json_reverse_iterator > ( base_iterator : : operator + + ( 1 ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// pre-increment (++it)
json_reverse_iterator & operator + + ( )
{
return static_cast < json_reverse_iterator & > ( base_iterator : : operator + + ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// post-decrement (it--)
json_reverse_iterator const operator - - ( int )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return static_cast < json_reverse_iterator > ( base_iterator : : operator - - ( 1 ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// pre-decrement (--it)
json_reverse_iterator & operator - - ( )
{
return static_cast < json_reverse_iterator & > ( base_iterator : : operator - - ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// add to iterator
json_reverse_iterator & operator + = ( difference_type i )
{
return static_cast < json_reverse_iterator & > ( base_iterator : : operator + = ( i ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// add to iterator
json_reverse_iterator operator + ( difference_type i ) const
{
return static_cast < json_reverse_iterator > ( base_iterator : : operator + ( i ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// subtract from iterator
json_reverse_iterator operator - ( difference_type i ) const
{
return static_cast < json_reverse_iterator > ( base_iterator : : operator - ( i ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return difference
difference_type operator - ( const json_reverse_iterator & other ) const
{
return base_iterator ( * this ) - base_iterator ( other ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// access to successor
reference operator [ ] ( difference_type n ) const
{
return * ( this - > operator + ( n ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return the key of an object iterator
auto key ( ) const - > decltype ( std : : declval < Base > ( ) . key ( ) )
{
auto it = - - this - > base ( ) ;
return it . key ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return the value of an iterator
reference value ( ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
auto it = - - this - > base ( ) ;
return it . operator * ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/output/output_adapters.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <algorithm> // copy
# include <cstddef> // size_t
# include <ios> // streamsize
# include <iterator> // back_inserter
# include <memory> // shared_ptr, make_shared
# include <ostream> // basic_ostream
# include <string> // basic_string
# include <vector> // vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
/// abstract output adapter interface
template < typename CharType > struct output_adapter_protocol
{
virtual void write_character ( CharType c ) = 0 ;
virtual void write_characters ( const CharType * s , std : : size_t length ) = 0 ;
virtual ~ output_adapter_protocol ( ) = default ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// a type to simplify interfaces
template < typename CharType >
using output_adapter_t = std : : shared_ptr < output_adapter_protocol < CharType > > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// output adapter for byte vectors
template < typename CharType >
class output_vector_adapter : public output_adapter_protocol < CharType >
{
public :
explicit output_vector_adapter ( std : : vector < CharType > & vec ) : v ( vec ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
void write_character ( CharType c ) override
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
v . push_back ( c ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
void write_characters ( const CharType * s , std : : size_t length ) override
{
std : : copy ( s , s + length , std : : back_inserter ( v ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
std : : vector < CharType > & v ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// output adapter for output streams
template < typename CharType >
class output_stream_adapter : public output_adapter_protocol < CharType >
{
public :
explicit output_stream_adapter ( std : : basic_ostream < CharType > & s ) : stream ( s ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
void write_character ( CharType c ) override
{
stream . put ( c ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
void write_characters ( const CharType * s , std : : size_t length ) override
{
stream . write ( s , static_cast < std : : streamsize > ( length ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
std : : basic_ostream < CharType > & stream ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// output adapter for basic_string
template < typename CharType , typename StringType = std : : basic_string < CharType > >
class output_string_adapter : public output_adapter_protocol < CharType >
{
public :
explicit output_string_adapter ( StringType & s ) : str ( s ) { }
void write_character ( CharType c ) override
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
str . push_back ( c ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
void write_characters ( const CharType * s , std : : size_t length ) override
{
str . append ( s , length ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
StringType & str ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename CharType , typename StringType = std : : basic_string < CharType > >
class output_adapter
{
public :
output_adapter ( std : : vector < CharType > & vec )
: oa ( std : : make_shared < output_vector_adapter < CharType > > ( vec ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
output_adapter ( std : : basic_ostream < CharType > & s )
: oa ( std : : make_shared < output_stream_adapter < CharType > > ( s ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
output_adapter ( StringType & s )
: oa ( std : : make_shared < output_string_adapter < CharType , StringType > > ( s ) ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
operator output_adapter_t < CharType > ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return oa ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
output_adapter_t < CharType > oa = nullptr ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/input/binary_reader.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <algorithm> // generate_n
# include <array> // array
# include <cassert> // assert
# include <cmath> // ldexp
# include <cstddef> // size_t
# include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
# include <cstring> // memcpy
# include <iomanip> // setw, setfill
# include <ios> // hex
# include <iterator> // back_inserter
# include <limits> // numeric_limits
# include <sstream> // stringstream
# include <string> // char_traits, string
# include <utility> // make_pair, move
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/input/input_adapters.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/exceptions.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
///////////////////
// binary reader //
///////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief deserialization of CBOR and MessagePack values
*/
template < typename BasicJsonType >
class binary_reader
{
using number_integer_t = typename BasicJsonType : : number_integer_t ;
using number_unsigned_t = typename BasicJsonType : : number_unsigned_t ;
using string_t = typename BasicJsonType : : string_t ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
/*!
@ brief create a binary reader
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] adapter input adapter to read from
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
explicit binary_reader ( input_adapter_t adapter ) : ia ( std : : move ( adapter ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( ia ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief create a JSON value from CBOR input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] strict whether to expect the input to be consumed completed
@ return JSON value created from CBOR input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input ended unexpectedly or the end of file was
not reached when @ a strict was set to true
@ throw parse_error .112 if unsupported byte was read
*/
BasicJsonType parse_cbor ( const bool strict )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
const auto res = parse_cbor_internal ( ) ;
if ( strict )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
get ( ) ;
expect_eof ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return res ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief create a JSON value from MessagePack input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] strict whether to expect the input to be consumed completed
@ return JSON value created from MessagePack input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input ended unexpectedly or the end of file was
not reached when @ a strict was set to true
@ throw parse_error .112 if unsupported byte was read
*/
BasicJsonType parse_msgpack ( const bool strict )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
const auto res = parse_msgpack_internal ( ) ;
if ( strict )
{
get ( ) ;
expect_eof ( ) ;
}
return res ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief create a JSON value from UBJSON input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] strict whether to expect the input to be consumed completed
@ return JSON value created from UBJSON input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input ended unexpectedly or the end of file was
not reached when @ a strict was set to true
@ throw parse_error .112 if unsupported byte was read
*/
BasicJsonType parse_ubjson ( const bool strict )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
const auto res = parse_ubjson_internal ( ) ;
if ( strict )
{
get_ignore_noop ( ) ;
expect_eof ( ) ;
}
return res ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief determine system byte order
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return true if and only if system ' s byte order is little endian
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note from http : //stackoverflow.com/a/1001328/266378
*/
static constexpr bool little_endianess ( int num = 1 ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( * reinterpret_cast < char * > ( & num ) = = 1 ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
/*!
@ param [ in ] get_char whether a new character should be retrieved from the
input ( true , default ) or whether the last read
character should be considered instead
*/
BasicJsonType parse_cbor_internal ( const bool get_char = true )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( get_char ? get ( ) : current )
{
// EOF
case std : : char_traits < char > : : eof ( ) :
JSON_THROW ( parse_error : : create ( 110 , chars_read , " unexpected end of input " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// Integer 0x00..0x17 (0..23)
case 0x00 :
case 0x01 :
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
case 0x07 :
case 0x08 :
case 0x09 :
case 0x0A :
case 0x0B :
case 0x0C :
case 0x0D :
case 0x0E :
case 0x0F :
case 0x10 :
case 0x11 :
case 0x12 :
case 0x13 :
case 0x14 :
case 0x15 :
case 0x16 :
case 0x17 :
return static_cast < number_unsigned_t > ( current ) ;
case 0x18 : // Unsigned integer (one-byte uint8_t follows)
return get_number < uint8_t > ( ) ;
case 0x19 : // Unsigned integer (two-byte uint16_t follows)
return get_number < uint16_t > ( ) ;
case 0x1A : // Unsigned integer (four-byte uint32_t follows)
return get_number < uint32_t > ( ) ;
case 0x1B : // Unsigned integer (eight-byte uint64_t follows)
return get_number < uint64_t > ( ) ;
// Negative integer -1-0x00..-1-0x17 (-1..-24)
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2A :
case 0x2B :
case 0x2C :
case 0x2D :
case 0x2E :
case 0x2F :
case 0x30 :
case 0x31 :
case 0x32 :
case 0x33 :
case 0x34 :
case 0x35 :
case 0x36 :
case 0x37 :
return static_cast < int8_t > ( 0x20 - 1 - current ) ;
case 0x38 : // Negative integer (one-byte uint8_t follows)
{
return static_cast < number_integer_t > ( - 1 ) - get_number < uint8_t > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x39 : // Negative integer -1-n (two-byte uint16_t follows)
{
return static_cast < number_integer_t > ( - 1 ) - get_number < uint16_t > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x3A : // Negative integer -1-n (four-byte uint32_t follows)
{
return static_cast < number_integer_t > ( - 1 ) - get_number < uint32_t > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x3B : // Negative integer -1-n (eight-byte uint64_t follows)
{
return static_cast < number_integer_t > ( - 1 ) -
static_cast < number_integer_t > ( get_number < uint64_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// UTF-8 string (0x00..0x17 bytes follow)
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
case 0x78 : // UTF-8 string (one-byte uint8_t for n follows)
case 0x79 : // UTF-8 string (two-byte uint16_t for n follow)
case 0x7A : // UTF-8 string (four-byte uint32_t for n follow)
case 0x7B : // UTF-8 string (eight-byte uint64_t for n follow)
case 0x7F : // UTF-8 string (indefinite length)
{
return get_cbor_string ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// array (0x00..0x17 data items follow)
case 0x80 :
case 0x81 :
case 0x82 :
case 0x83 :
case 0x84 :
case 0x85 :
case 0x86 :
case 0x87 :
case 0x88 :
case 0x89 :
case 0x8A :
case 0x8B :
case 0x8C :
case 0x8D :
case 0x8E :
case 0x8F :
case 0x90 :
case 0x91 :
case 0x92 :
case 0x93 :
case 0x94 :
case 0x95 :
case 0x96 :
case 0x97 :
{
return get_cbor_array ( current & 0x1F ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x98 : // array (one-byte uint8_t for n follows)
{
return get_cbor_array ( get_number < uint8_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x99 : // array (two-byte uint16_t for n follow)
{
return get_cbor_array ( get_number < uint16_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x9A : // array (four-byte uint32_t for n follow)
{
return get_cbor_array ( get_number < uint32_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x9B : // array (eight-byte uint64_t for n follow)
{
return get_cbor_array ( get_number < uint64_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x9F : // array (indefinite length)
{
BasicJsonType result = value_t : : array ;
while ( get ( ) ! = 0xFF )
{
result . push_back ( parse_cbor_internal ( false ) ) ;
}
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// map (0x00..0x17 pairs of data items follow)
case 0xA0 :
case 0xA1 :
case 0xA2 :
case 0xA3 :
case 0xA4 :
case 0xA5 :
case 0xA6 :
case 0xA7 :
case 0xA8 :
case 0xA9 :
case 0xAA :
case 0xAB :
case 0xAC :
case 0xAD :
case 0xAE :
case 0xAF :
case 0xB0 :
case 0xB1 :
case 0xB2 :
case 0xB3 :
case 0xB4 :
case 0xB5 :
case 0xB6 :
case 0xB7 :
{
return get_cbor_object ( current & 0x1F ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xB8 : // map (one-byte uint8_t for n follows)
{
return get_cbor_object ( get_number < uint8_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xB9 : // map (two-byte uint16_t for n follow)
{
return get_cbor_object ( get_number < uint16_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xBA : // map (four-byte uint32_t for n follow)
{
return get_cbor_object ( get_number < uint32_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xBB : // map (eight-byte uint64_t for n follow)
{
return get_cbor_object ( get_number < uint64_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xBF : // map (indefinite length)
{
BasicJsonType result = value_t : : object ;
while ( get ( ) ! = 0xFF )
{
auto key = get_cbor_string ( ) ;
result [ key ] = parse_cbor_internal ( ) ;
}
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xF4 : // false
{
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xF5 : // true
{
return true ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xF6 : // null
{
return value_t : : null ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xF9 : // Half-Precision Float (two-byte IEEE 754)
{
const int byte1 = get ( ) ;
unexpect_eof ( ) ;
const int byte2 = get ( ) ;
unexpect_eof ( ) ;
// code from RFC 7049, Appendix D, Figure 3:
// As half-precision floating-point numbers were only added
// to IEEE 754 in 2008, today's programming platforms often
// still only have limited support for them. It is very
// easy to include at least decoding support for them even
// without such support. An example of a small decoder for
// half-precision floating-point numbers in the C language
// is shown in Fig. 3.
const int half = ( byte1 < < 8 ) + byte2 ;
const int exp = ( half > > 10 ) & 0x1F ;
const int mant = half & 0x3FF ;
double val ;
if ( exp = = 0 )
{
val = std : : ldexp ( mant , - 24 ) ;
}
else if ( exp ! = 31 )
{
val = std : : ldexp ( mant + 1024 , exp - 25 ) ;
}
else
{
val = ( mant = = 0 ) ? std : : numeric_limits < double > : : infinity ( )
: std : : numeric_limits < double > : : quiet_NaN ( ) ;
}
return ( half & 0x8000 ) ! = 0 ? - val : val ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xFA : // Single-Precision Float (four-byte IEEE 754)
{
return get_number < float > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xFB : // Double-Precision Float (eight-byte IEEE 754)
{
return get_number < double > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default : // anything else (0xFF is handled inside the other types)
{
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 112 , chars_read , " error reading CBOR; last byte: 0x " + ss . str ( ) ) ) ;
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
BasicJsonType parse_msgpack_internal ( )
{
switch ( get ( ) )
{
// EOF
case std : : char_traits < char > : : eof ( ) :
JSON_THROW ( parse_error : : create ( 110 , chars_read , " unexpected end of input " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// positive fixint
case 0x00 :
case 0x01 :
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
case 0x07 :
case 0x08 :
case 0x09 :
case 0x0A :
case 0x0B :
case 0x0C :
case 0x0D :
case 0x0E :
case 0x0F :
case 0x10 :
case 0x11 :
case 0x12 :
case 0x13 :
case 0x14 :
case 0x15 :
case 0x16 :
case 0x17 :
case 0x18 :
case 0x19 :
case 0x1A :
case 0x1B :
case 0x1C :
case 0x1D :
case 0x1E :
case 0x1F :
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2A :
case 0x2B :
case 0x2C :
case 0x2D :
case 0x2E :
case 0x2F :
case 0x30 :
case 0x31 :
case 0x32 :
case 0x33 :
case 0x34 :
case 0x35 :
case 0x36 :
case 0x37 :
case 0x38 :
case 0x39 :
case 0x3A :
case 0x3B :
case 0x3C :
case 0x3D :
case 0x3E :
case 0x3F :
case 0x40 :
case 0x41 :
case 0x42 :
case 0x43 :
case 0x44 :
case 0x45 :
case 0x46 :
case 0x47 :
case 0x48 :
case 0x49 :
case 0x4A :
case 0x4B :
case 0x4C :
case 0x4D :
case 0x4E :
case 0x4F :
case 0x50 :
case 0x51 :
case 0x52 :
case 0x53 :
case 0x54 :
case 0x55 :
case 0x56 :
case 0x57 :
case 0x58 :
case 0x59 :
case 0x5A :
case 0x5B :
case 0x5C :
case 0x5D :
case 0x5E :
case 0x5F :
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
case 0x78 :
case 0x79 :
case 0x7A :
case 0x7B :
case 0x7C :
case 0x7D :
case 0x7E :
case 0x7F :
return static_cast < number_unsigned_t > ( current ) ;
// fixmap
case 0x80 :
case 0x81 :
case 0x82 :
case 0x83 :
case 0x84 :
case 0x85 :
case 0x86 :
case 0x87 :
case 0x88 :
case 0x89 :
case 0x8A :
case 0x8B :
case 0x8C :
case 0x8D :
case 0x8E :
case 0x8F :
{
return get_msgpack_object ( current & 0x0F ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// fixarray
case 0x90 :
case 0x91 :
case 0x92 :
case 0x93 :
case 0x94 :
case 0x95 :
case 0x96 :
case 0x97 :
case 0x98 :
case 0x99 :
case 0x9A :
case 0x9B :
case 0x9C :
case 0x9D :
case 0x9E :
case 0x9F :
{
return get_msgpack_array ( current & 0x0F ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// fixstr
case 0xA0 :
case 0xA1 :
case 0xA2 :
case 0xA3 :
case 0xA4 :
case 0xA5 :
case 0xA6 :
case 0xA7 :
case 0xA8 :
case 0xA9 :
case 0xAA :
case 0xAB :
case 0xAC :
case 0xAD :
case 0xAE :
case 0xAF :
case 0xB0 :
case 0xB1 :
case 0xB2 :
case 0xB3 :
case 0xB4 :
case 0xB5 :
case 0xB6 :
case 0xB7 :
case 0xB8 :
case 0xB9 :
case 0xBA :
case 0xBB :
case 0xBC :
case 0xBD :
case 0xBE :
case 0xBF :
return get_msgpack_string ( ) ;
case 0xC0 : // nil
return value_t : : null ;
case 0xC2 : // false
return false ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xC3 : // true
return true ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xCA : // float 32
return get_number < float > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xCB : // float 64
return get_number < double > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xCC : // uint 8
return get_number < uint8_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xCD : // uint 16
return get_number < uint16_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xCE : // uint 32
return get_number < uint32_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xCF : // uint 64
return get_number < uint64_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xD0 : // int 8
return get_number < int8_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xD1 : // int 16
return get_number < int16_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xD2 : // int 32
return get_number < int32_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xD3 : // int 64
return get_number < int64_t > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xD9 : // str 8
case 0xDA : // str 16
case 0xDB : // str 32
return get_msgpack_string ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xDC : // array 16
{
return get_msgpack_array ( get_number < uint16_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xDD : // array 32
{
return get_msgpack_array ( get_number < uint32_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xDE : // map 16
{
return get_msgpack_object ( get_number < uint16_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xDF : // map 32
{
return get_msgpack_object ( get_number < uint32_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// positive fixint
case 0xE0 :
case 0xE1 :
case 0xE2 :
case 0xE3 :
case 0xE4 :
case 0xE5 :
case 0xE6 :
case 0xE7 :
case 0xE8 :
case 0xE9 :
case 0xEA :
case 0xEB :
case 0xEC :
case 0xED :
case 0xEE :
case 0xEF :
case 0xF0 :
case 0xF1 :
case 0xF2 :
case 0xF3 :
case 0xF4 :
case 0xF5 :
case 0xF6 :
case 0xF7 :
case 0xF8 :
case 0xF9 :
case 0xFA :
case 0xFB :
case 0xFC :
case 0xFD :
case 0xFE :
case 0xFF :
return static_cast < int8_t > ( current ) ;
default : // anything else
{
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 112 , chars_read ,
" error reading MessagePack; last byte: 0x " + ss . str ( ) ) ) ;
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ param [ in ] get_char whether a new character should be retrieved from the
input ( true , default ) or whether the last read
character should be considered instead
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
BasicJsonType parse_ubjson_internal ( const bool get_char = true )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return get_ubjson_value ( get_char ? get_ignore_noop ( ) : current ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief get next character from the input
This function provides the interface to the used input adapter . It does
not throw in case the input reached EOF , but returns a - ' ve valued
` std : : char_traits < char > : : eof ( ) ` in that case .
@ return character read from the input
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
int get ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
+ + chars_read ;
return ( current = ia - > get_character ( ) ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ return character read from the input after ignoring all ' N ' entries
*/
int get_ignore_noop ( )
{
do
{
get ( ) ;
}
while ( current = = ' N ' ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return current ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*
@ brief read a number from the input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam NumberType the type of the number
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return number of type @ a NumberType
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This function needs to respect the system ' s endianess , because
bytes in CBOR and MessagePack are stored in network order ( big
endian ) and therefore need reordering on little endian systems .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input has less than ` sizeof ( NumberType ) ` bytes
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename NumberType > NumberType get_number ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// step 1: read input into array with system's byte order
std : : array < uint8_t , sizeof ( NumberType ) > vec ;
for ( std : : size_t i = 0 ; i < sizeof ( NumberType ) ; + + i )
{
get ( ) ;
unexpect_eof ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// reverse byte order prior to conversion if necessary
if ( is_little_endian )
{
vec [ sizeof ( NumberType ) - i - 1 ] = static_cast < uint8_t > ( current ) ;
}
else
{
vec [ i ] = static_cast < uint8_t > ( current ) ; // LCOV_EXCL_LINE
}
}
// step 2: convert array into number of type T and return
NumberType result ;
std : : memcpy ( & result , vec . data ( ) , sizeof ( NumberType ) ) ;
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief create a string by reading characters from the input
@ param [ in ] len number of bytes to read
@ note We can not reserve @ a len bytes for the result , because @ a len
may be too large . Usually , @ ref unexpect_eof ( ) detects the end of
the input before we run out of string memory .
@ return string created by reading @ a len bytes
@ throw parse_error .110 if input has less than @ a len bytes
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename NumberType >
string_t get_string ( const NumberType len )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
string_t result ;
std : : generate_n ( std : : back_inserter ( result ) , len , [ this ] ( )
{
get ( ) ;
unexpect_eof ( ) ;
return static_cast < char > ( current ) ;
} ) ;
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief reads a CBOR string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function first reads starting bytes to determine the expected
string length and then copies this number of bytes into a string .
Additionally , CBOR ' s strings with indefinite lengths are supported .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input ended
@ throw parse_error .113 if an unexpected byte is read
*/
string_t get_cbor_string ( )
{
unexpect_eof ( ) ;
switch ( current )
{
// UTF-8 string (0x00..0x17 bytes follow)
case 0x60 :
case 0x61 :
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
case 0x6B :
case 0x6C :
case 0x6D :
case 0x6E :
case 0x6F :
case 0x70 :
case 0x71 :
case 0x72 :
case 0x73 :
case 0x74 :
case 0x75 :
case 0x76 :
case 0x77 :
{
return get_string ( current & 0x1F ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x78 : // UTF-8 string (one-byte uint8_t for n follows)
{
return get_string ( get_number < uint8_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x79 : // UTF-8 string (two-byte uint16_t for n follow)
{
return get_string ( get_number < uint16_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x7A : // UTF-8 string (four-byte uint32_t for n follow)
{
return get_string ( get_number < uint32_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x7B : // UTF-8 string (eight-byte uint64_t for n follow)
{
return get_string ( get_number < uint64_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x7F : // UTF-8 string (indefinite length)
{
string_t result ;
while ( get ( ) ! = 0xFF )
{
result . append ( get_cbor_string ( ) ) ;
}
return result ;
}
default :
{
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 113 , chars_read , " expected a CBOR string; last byte: 0x " + ss . str ( ) ) ) ;
}
}
}
template < typename NumberType >
BasicJsonType get_cbor_array ( const NumberType len )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
BasicJsonType result = value_t : : array ;
std : : generate_n ( std : : back_inserter ( * result . m_value . array ) , len , [ this ] ( )
{
return parse_cbor_internal ( ) ;
} ) ;
return result ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
template < typename NumberType >
BasicJsonType get_cbor_object ( const NumberType len )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
BasicJsonType result = value_t : : object ;
std : : generate_n ( std : : inserter ( * result . m_value . object ,
result . m_value . object - > end ( ) ) ,
len , [ this ] ( )
{
get ( ) ;
auto key = get_cbor_string ( ) ;
auto val = parse_cbor_internal ( ) ;
return std : : make_pair ( std : : move ( key ) , std : : move ( val ) ) ;
} ) ;
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief reads a MessagePack string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function first reads starting bytes to determine the expected
string length and then copies this number of bytes into a string .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input ended
@ throw parse_error .113 if an unexpected byte is read
*/
string_t get_msgpack_string ( )
{
unexpect_eof ( ) ;
switch ( current )
{
// fixstr
case 0xA0 :
case 0xA1 :
case 0xA2 :
case 0xA3 :
case 0xA4 :
case 0xA5 :
case 0xA6 :
case 0xA7 :
case 0xA8 :
case 0xA9 :
case 0xAA :
case 0xAB :
case 0xAC :
case 0xAD :
case 0xAE :
case 0xAF :
case 0xB0 :
case 0xB1 :
case 0xB2 :
case 0xB3 :
case 0xB4 :
case 0xB5 :
case 0xB6 :
case 0xB7 :
case 0xB8 :
case 0xB9 :
case 0xBA :
case 0xBB :
case 0xBC :
case 0xBD :
case 0xBE :
case 0xBF :
{
return get_string ( current & 0x1F ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xD9 : // str 8
{
return get_string ( get_number < uint8_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xDA : // str 16
{
return get_string ( get_number < uint16_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0xDB : // str 32
{
return get_string ( get_number < uint32_t > ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 113 , chars_read ,
" expected a MessagePack string; last byte: 0x " + ss . str ( ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
template < typename NumberType >
BasicJsonType get_msgpack_array ( const NumberType len )
{
BasicJsonType result = value_t : : array ;
std : : generate_n ( std : : back_inserter ( * result . m_value . array ) , len , [ this ] ( )
{
return parse_msgpack_internal ( ) ;
} ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename NumberType >
BasicJsonType get_msgpack_object ( const NumberType len )
{
BasicJsonType result = value_t : : object ;
std : : generate_n ( std : : inserter ( * result . m_value . object ,
result . m_value . object - > end ( ) ) ,
len , [ this ] ( )
{
get ( ) ;
auto key = get_msgpack_string ( ) ;
auto val = parse_msgpack_internal ( ) ;
return std : : make_pair ( std : : move ( key ) , std : : move ( val ) ) ;
} ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief reads a UBJSON string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function is either called after reading the ' S ' byte explicitly
indicating a string , or in case of an object key where the ' S ' byte can be
left out .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] get_char whether a new character should be retrieved from the
input ( true , default ) or whether the last read
character should be considered instead
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if input ended
@ throw parse_error .113 if an unexpected byte is read
*/
string_t get_ubjson_string ( const bool get_char = true )
{
if ( get_char )
{
get ( ) ; // TODO: may we ignore N here?
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
unexpect_eof ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( current )
{
case ' U ' :
return get_string ( get_number < uint8_t > ( ) ) ;
case ' i ' :
return get_string ( get_number < int8_t > ( ) ) ;
case ' I ' :
return get_string ( get_number < int16_t > ( ) ) ;
case ' l ' :
return get_string ( get_number < int32_t > ( ) ) ;
case ' L ' :
return get_string ( get_number < int64_t > ( ) ) ;
default :
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 113 , chars_read ,
" expected a UBJSON string; last byte: 0x " + ss . str ( ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief determine the type and size for a container
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
In the optimized UBJSON format , a type and a size can be provided to allow
for a more compact representation .
@ return pair of the size and the type
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
std : : pair < std : : size_t , int > get_ubjson_size_type ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : size_t sz = string_t : : npos ;
int tc = 0 ;
get_ignore_noop ( ) ;
if ( current = = ' $ ' )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
tc = get ( ) ; // must not ignore 'N', because 'N' maybe the type
unexpect_eof ( ) ;
get_ignore_noop ( ) ;
if ( current ! = ' # ' )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 112 , chars_read ,
" expected '#' after UBJSON type information; last byte: 0x " + ss . str ( ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
sz = parse_ubjson_internal ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( current = = ' # ' )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
sz = parse_ubjson_internal ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return std : : make_pair ( sz , tc ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
BasicJsonType get_ubjson_value ( const int prefix )
{
switch ( prefix )
{
case std : : char_traits < char > : : eof ( ) : // EOF
JSON_THROW ( parse_error : : create ( 110 , chars_read , " unexpected end of input " ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' T ' : // true
return true ;
case ' F ' : // false
return false ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' Z ' : // null
return nullptr ;
case ' U ' :
return get_number < uint8_t > ( ) ;
case ' i ' :
return get_number < int8_t > ( ) ;
case ' I ' :
return get_number < int16_t > ( ) ;
case ' l ' :
return get_number < int32_t > ( ) ;
case ' L ' :
return get_number < int64_t > ( ) ;
case ' d ' :
return get_number < float > ( ) ;
case ' D ' :
return get_number < double > ( ) ;
case ' C ' : // char
{
get ( ) ;
unexpect_eof ( ) ;
if ( JSON_UNLIKELY ( current > 127 ) )
{
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 113 , chars_read ,
" byte after 'C' must be in range 0x00..0x7F; last byte: 0x " + ss . str ( ) ) ) ;
}
return string_t ( 1 , static_cast < char > ( current ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' S ' : // string
return get_ubjson_string ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' [ ' : // array
return get_ubjson_array ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case ' { ' : // object
return get_ubjson_object ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default : // anything else
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < current ;
JSON_THROW ( parse_error : : create ( 112 , chars_read ,
" error reading UBJSON; last byte: 0x " + ss . str ( ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
BasicJsonType get_ubjson_array ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
BasicJsonType result = value_t : : array ;
const auto size_and_type = get_ubjson_size_type ( ) ;
if ( size_and_type . first ! = string_t : : npos )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( size_and_type . first > result . max_size ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( out_of_range : : create ( 408 ,
" excessive array size: " + std : : to_string ( size_and_type . first ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( size_and_type . second ! = 0 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( size_and_type . second ! = ' N ' )
{
std : : generate_n ( std : : back_inserter ( * result . m_value . array ) ,
size_and_type . first , [ this , size_and_type ] ( )
{
return get_ubjson_value ( size_and_type . second ) ;
} ) ;
}
}
else
{
std : : generate_n ( std : : back_inserter ( * result . m_value . array ) ,
size_and_type . first , [ this ] ( )
{
return parse_ubjson_internal ( ) ;
} ) ;
2017-07-18 05:37:27 +02:00
}
}
else
{
2018-05-19 21:59:03 +02:00
while ( current ! = ' ] ' )
{
result . push_back ( parse_ubjson_internal ( false ) ) ;
get_ignore_noop ( ) ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
BasicJsonType get_ubjson_object ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
BasicJsonType result = value_t : : object ;
const auto size_and_type = get_ubjson_size_type ( ) ;
if ( size_and_type . first ! = string_t : : npos )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( size_and_type . first > result . max_size ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( out_of_range : : create ( 408 ,
" excessive object size: " + std : : to_string ( size_and_type . first ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( size_and_type . second ! = 0 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : generate_n ( std : : inserter ( * result . m_value . object ,
result . m_value . object - > end ( ) ) ,
size_and_type . first , [ this , size_and_type ] ( )
{
auto key = get_ubjson_string ( ) ;
auto val = get_ubjson_value ( size_and_type . second ) ;
return std : : make_pair ( std : : move ( key ) , std : : move ( val ) ) ;
} ) ;
}
else
{
std : : generate_n ( std : : inserter ( * result . m_value . object ,
result . m_value . object - > end ( ) ) ,
size_and_type . first , [ this ] ( )
{
auto key = get_ubjson_string ( ) ;
auto val = parse_ubjson_internal ( ) ;
return std : : make_pair ( std : : move ( key ) , std : : move ( val ) ) ;
} ) ;
2017-07-18 05:37:27 +02:00
}
}
else
{
2018-05-19 21:59:03 +02:00
while ( current ! = ' } ' )
{
auto key = get_ubjson_string ( false ) ;
result [ std : : move ( key ) ] = parse_ubjson_internal ( ) ;
get_ignore_noop ( ) ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief throw if end of input is not reached
@ throw parse_error .110 if input not ended
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void expect_eof ( ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( current ! = std : : char_traits < char > : : eof ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( parse_error : : create ( 110 , chars_read , " expected end of input " ) ) ;
2017-07-18 05:37:27 +02:00
}
}
/*!
2018-05-19 21:59:03 +02:00
@ briefthrow if end of input is reached
@ throw parse_error .110 if input ended
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void unexpect_eof ( ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( current = = std : : char_traits < char > : : eof ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( parse_error : : create ( 110 , chars_read , " unexpected end of input " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/// input adapter
input_adapter_t ia = nullptr ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the current character
int current = std : : char_traits < char > : : eof ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the number of characters read
std : : size_t chars_read = 0 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// whether we can assume little endianess
const bool is_little_endian = little_endianess ( ) ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/output/binary_writer.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <algorithm> // reverse
# include <array> // array
# include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
# include <cstring> // memcpy
# include <limits> // numeric_limits
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/input/binary_reader.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/output/output_adapters.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
///////////////////
// binary writer //
///////////////////
/*!
@ brief serialization to CBOR and MessagePack values
*/
template < typename BasicJsonType , typename CharType >
class binary_writer
{
public :
/*!
@ brief create a binary writer
@ param [ in ] adapter output adapter to write to
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
explicit binary_writer ( output_adapter_t < CharType > adapter ) : oa ( adapter )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( oa ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief [ in ] j JSON value to serialize
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void write_cbor ( const BasicJsonType & j )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( j . type ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : null :
{
oa - > write_character ( static_cast < CharType > ( 0xF6 ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
{
oa - > write_character ( j . m_value . boolean
? static_cast < CharType > ( 0xF5 )
: static_cast < CharType > ( 0xF4 ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
{
if ( j . m_value . number_integer > = 0 )
{
// CBOR does not differentiate between positive signed
// integers and unsigned integers. Therefore, we used the
// code from the value_t::number_unsigned case here.
if ( j . m_value . number_integer < = 0x17 )
{
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x18 ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x19 ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x1A ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_integer ) ) ;
}
else
{
oa - > write_character ( static_cast < CharType > ( 0x1B ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_integer ) ) ;
}
}
else
{
// The conversions below encode the sign in the first
// byte, and the value is converted to a positive number.
const auto positive_number = - 1 - j . m_value . number_integer ;
if ( j . m_value . number_integer > = - 24 )
{
write_number ( static_cast < uint8_t > ( 0x20 + positive_number ) ) ;
}
else if ( positive_number < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x38 ) ) ;
write_number ( static_cast < uint8_t > ( positive_number ) ) ;
}
else if ( positive_number < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x39 ) ) ;
write_number ( static_cast < uint16_t > ( positive_number ) ) ;
}
else if ( positive_number < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x3A ) ) ;
write_number ( static_cast < uint32_t > ( positive_number ) ) ;
}
else
{
oa - > write_character ( static_cast < CharType > ( 0x3B ) ) ;
write_number ( static_cast < uint64_t > ( positive_number ) ) ;
}
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
{
if ( j . m_value . number_unsigned < = 0x17 )
{
write_number ( static_cast < uint8_t > ( j . m_value . number_unsigned ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x18 ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_unsigned ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x19 ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_unsigned ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x1A ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_unsigned ) ) ;
}
else
{
oa - > write_character ( static_cast < CharType > ( 0x1B ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_unsigned ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_float : // Double-Precision Float
{
oa - > write_character ( static_cast < CharType > ( 0xFB ) ) ;
write_number ( j . m_value . number_float ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
{
// step 1: write control byte and the string length
const auto N = j . m_value . string - > size ( ) ;
if ( N < = 0x17 )
{
write_number ( static_cast < uint8_t > ( 0x60 + N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x78 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x79 ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x7A ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// LCOV_EXCL_START
else if ( N < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x7B ) ) ;
write_number ( static_cast < uint64_t > ( N ) ) ;
}
// LCOV_EXCL_STOP
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write the string
oa - > write_characters (
reinterpret_cast < const CharType * > ( j . m_value . string - > c_str ( ) ) ,
j . m_value . string - > size ( ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
// step 1: write control byte and the array size
const auto N = j . m_value . array - > size ( ) ;
if ( N < = 0x17 )
{
write_number ( static_cast < uint8_t > ( 0x80 + N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x98 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x99 ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x9A ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// LCOV_EXCL_START
else if ( N < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x9B ) ) ;
write_number ( static_cast < uint64_t > ( N ) ) ;
}
// LCOV_EXCL_STOP
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write each element
for ( const auto & el : * j . m_value . array )
{
write_cbor ( el ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
{
// step 1: write control byte and the object size
const auto N = j . m_value . object - > size ( ) ;
if ( N < = 0x17 )
{
write_number ( static_cast < uint8_t > ( 0xA0 + N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0xB8 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0xB9 ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0xBA ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// LCOV_EXCL_START
else if ( N < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0xBB ) ) ;
write_number ( static_cast < uint64_t > ( N ) ) ;
}
// LCOV_EXCL_STOP
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write each element
for ( const auto & el : * j . m_value . object )
{
write_cbor ( el . first ) ;
write_cbor ( el . second ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
break ;
}
}
/*!
@ brief [ in ] j JSON value to serialize
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void write_msgpack ( const BasicJsonType & j )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( j . type ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : null : // nil
{
oa - > write_character ( static_cast < CharType > ( 0xC0 ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean : // true and false
{
oa - > write_character ( j . m_value . boolean
? static_cast < CharType > ( 0xC3 )
: static_cast < CharType > ( 0xC2 ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
{
if ( j . m_value . number_integer > = 0 )
{
// MessagePack does not differentiate between positive
// signed integers and unsigned integers. Therefore, we used
// the code from the value_t::number_unsigned case here.
if ( j . m_value . number_unsigned < 128 )
{
// positive fixnum
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
// uint 8
oa - > write_character ( static_cast < CharType > ( 0xCC ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// uint 16
oa - > write_character ( static_cast < CharType > ( 0xCD ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// uint 32
oa - > write_character ( static_cast < CharType > ( 0xCE ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
// uint 64
oa - > write_character ( static_cast < CharType > ( 0xCF ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_integer ) ) ;
}
}
else
{
if ( j . m_value . number_integer > = - 32 )
{
// negative fixnum
write_number ( static_cast < int8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int8_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
// int 8
oa - > write_character ( static_cast < CharType > ( 0xD0 ) ) ;
write_number ( static_cast < int8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int16_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
{
// int 16
oa - > write_character ( static_cast < CharType > ( 0xD1 ) ) ;
write_number ( static_cast < int16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int32_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
{
// int 32
oa - > write_character ( static_cast < CharType > ( 0xD2 ) ) ;
write_number ( static_cast < int32_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int64_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int64_t > : : max ) ( ) )
{
// int 64
oa - > write_character ( static_cast < CharType > ( 0xD3 ) ) ;
write_number ( static_cast < int64_t > ( j . m_value . number_integer ) ) ;
}
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
{
if ( j . m_value . number_unsigned < 128 )
{
// positive fixnum
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
// uint 8
oa - > write_character ( static_cast < CharType > ( 0xCC ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// uint 16
oa - > write_character ( static_cast < CharType > ( 0xCD ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// uint 32
oa - > write_character ( static_cast < CharType > ( 0xCE ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
// uint 64
oa - > write_character ( static_cast < CharType > ( 0xCF ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_integer ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_float : // float 64
{
oa - > write_character ( static_cast < CharType > ( 0xCB ) ) ;
write_number ( j . m_value . number_float ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
{
// step 1: write control byte and the string length
const auto N = j . m_value . string - > size ( ) ;
if ( N < = 31 )
{
// fixstr
write_number ( static_cast < uint8_t > ( 0xA0 | N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
// str 8
oa - > write_character ( static_cast < CharType > ( 0xD9 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// str 16
oa - > write_character ( static_cast < CharType > ( 0xDA ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// str 32
oa - > write_character ( static_cast < CharType > ( 0xDB ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write the string
oa - > write_characters (
reinterpret_cast < const CharType * > ( j . m_value . string - > c_str ( ) ) ,
j . m_value . string - > size ( ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
// step 1: write control byte and the array size
const auto N = j . m_value . array - > size ( ) ;
if ( N < = 15 )
{
// fixarray
write_number ( static_cast < uint8_t > ( 0x90 | N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// array 16
oa - > write_character ( static_cast < CharType > ( 0xDC ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// array 32
oa - > write_character ( static_cast < CharType > ( 0xDD ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write each element
for ( const auto & el : * j . m_value . array )
{
write_msgpack ( el ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
{
// step 1: write control byte and the object size
const auto N = j . m_value . object - > size ( ) ;
if ( N < = 15 )
{
// fixmap
write_number ( static_cast < uint8_t > ( 0x80 | ( N & 0xF ) ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// map 16
oa - > write_character ( static_cast < CharType > ( 0xDE ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// map 32
oa - > write_character ( static_cast < CharType > ( 0xDF ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write each element
for ( const auto & el : * j . m_value . object )
{
write_msgpack ( el . first ) ;
write_msgpack ( el . second ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
break ;
}
}
/*!
@ param [ in ] j JSON value to serialize
@ param [ in ] use_count whether to use ' # ' prefixes ( optimized format )
@ param [ in ] use_type whether to use ' $ ' prefixes ( optimized format )
@ param [ in ] add_prefix whether prefixes need to be used for this value
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void write_ubjson ( const BasicJsonType & j , const bool use_count ,
const bool use_type , const bool add_prefix = true )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( j . type ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : null :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' Z ' ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
{
if ( add_prefix )
oa - > write_character ( j . m_value . boolean
? static_cast < CharType > ( ' T ' )
: static_cast < CharType > ( ' F ' ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
{
write_number_with_ubjson_prefix ( j . m_value . number_integer , add_prefix ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
{
write_number_with_ubjson_prefix ( j . m_value . number_unsigned , add_prefix ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_float :
{
write_number_with_ubjson_prefix ( j . m_value . number_float , add_prefix ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' S ' ) ) ;
}
write_number_with_ubjson_prefix ( j . m_value . string - > size ( ) , true ) ;
oa - > write_characters (
reinterpret_cast < const CharType * > ( j . m_value . string - > c_str ( ) ) ,
j . m_value . string - > size ( ) ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' [ ' ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
bool prefix_required = true ;
if ( use_type and not j . m_value . array - > empty ( ) )
{
assert ( use_count ) ;
const char first_prefix = ubjson_prefix ( j . front ( ) ) ;
const bool same_prefix = std : : all_of ( j . begin ( ) + 1 , j . end ( ) ,
[ this , first_prefix ] ( const BasicJsonType & v )
{
return ubjson_prefix ( v ) = = first_prefix ;
} ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( same_prefix )
{
prefix_required = false ;
oa - > write_character ( static_cast < CharType > ( ' $ ' ) ) ;
oa - > write_character ( static_cast < CharType > ( first_prefix ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( use_count )
{
oa - > write_character ( static_cast < CharType > ( ' # ' ) ) ;
write_number_with_ubjson_prefix ( j . m_value . array - > size ( ) , true ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
for ( const auto & el : * j . m_value . array )
{
write_ubjson ( el , use_count , use_type , prefix_required ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( not use_count )
{
oa - > write_character ( static_cast < CharType > ( ' ] ' ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' { ' ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
bool prefix_required = true ;
if ( use_type and not j . m_value . object - > empty ( ) )
{
assert ( use_count ) ;
const char first_prefix = ubjson_prefix ( j . front ( ) ) ;
const bool same_prefix = std : : all_of ( j . begin ( ) , j . end ( ) ,
[ this , first_prefix ] ( const BasicJsonType & v )
{
return ubjson_prefix ( v ) = = first_prefix ;
} ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( same_prefix )
{
prefix_required = false ;
oa - > write_character ( static_cast < CharType > ( ' $ ' ) ) ;
oa - > write_character ( static_cast < CharType > ( first_prefix ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( use_count )
{
oa - > write_character ( static_cast < CharType > ( ' # ' ) ) ;
write_number_with_ubjson_prefix ( j . m_value . object - > size ( ) , true ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
for ( const auto & el : * j . m_value . object )
{
write_number_with_ubjson_prefix ( el . first . size ( ) , true ) ;
oa - > write_characters (
reinterpret_cast < const CharType * > ( el . first . c_str ( ) ) ,
el . first . size ( ) ) ;
write_ubjson ( el . second , use_count , use_type , prefix_required ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( not use_count )
{
oa - > write_character ( static_cast < CharType > ( ' } ' ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
break ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/*
@ brief write a number to output input
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] n number of type @ a NumberType
@ tparam NumberType the type of the number
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This function needs to respect the system ' s endianess , because bytes
in CBOR , MessagePack , and UBJSON are stored in network order ( big
endian ) and therefore need reordering on little endian systems .
*/
template < typename NumberType >
void write_number ( const NumberType n )
{
// step 1: write number to array of length NumberType
std : : array < CharType , sizeof ( NumberType ) > vec ;
std : : memcpy ( vec . data ( ) , & n , sizeof ( NumberType ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// step 2: write array to output (with possible reordering)
if ( is_little_endian )
{
// reverse byte order prior to conversion if necessary
std : : reverse ( vec . begin ( ) , vec . end ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
oa - > write_characters ( vec . data ( ) , sizeof ( NumberType ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// UBJSON: write number (floating point)
template < typename NumberType , typename std : : enable_if <
std : : is_floating_point < NumberType > : : value , int > : : type = 0 >
void write_number_with_ubjson_prefix ( const NumberType n ,
const bool add_prefix )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' D ' ) ) ; // float64
}
write_number ( n ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// 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 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int8_t > : : max ) ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( add_prefix )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
oa - > write_character ( static_cast < CharType > ( ' i ' ) ) ; // int8
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
write_number ( static_cast < uint8_t > ( n ) ) ;
}
else if ( n < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' U ' ) ) ; // uint8
}
write_number ( static_cast < uint8_t > ( n ) ) ;
}
else if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int16_t > : : max ) ( ) ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' I ' ) ) ; // int16
}
write_number ( static_cast < int16_t > ( n ) ) ;
}
else if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int32_t > : : max ) ( ) ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' l ' ) ) ; // int32
}
write_number ( static_cast < int32_t > ( n ) ) ;
}
else if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int64_t > : : max ) ( ) ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' L ' ) ) ; // int64
}
write_number ( static_cast < int64_t > ( n ) ) ;
2017-07-18 05:37:27 +02:00
}
else
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( out_of_range : : create ( 407 , " number overflow serializing " + std : : to_string ( n ) ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
// 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 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( ( std : : numeric_limits < int8_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( add_prefix )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
oa - > write_character ( static_cast < CharType > ( ' i ' ) ) ; // int8
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
write_number ( static_cast < int8_t > ( n ) ) ;
}
else if ( static_cast < int64_t > ( ( std : : numeric_limits < uint8_t > : : min ) ( ) ) < = n and n < = static_cast < int64_t > ( ( std : : numeric_limits < uint8_t > : : max ) ( ) ) )
{
if ( add_prefix )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
oa - > write_character ( static_cast < CharType > ( ' U ' ) ) ; // uint8
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
write_number ( static_cast < uint8_t > ( n ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( ( std : : numeric_limits < int16_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' I ' ) ) ; // int16
}
write_number ( static_cast < int16_t > ( n ) ) ;
}
else if ( ( std : : numeric_limits < int32_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' l ' ) ) ; // int32
}
write_number ( static_cast < int32_t > ( n ) ) ;
}
else if ( ( std : : numeric_limits < int64_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int64_t > : : max ) ( ) )
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' L ' ) ) ; // int64
}
write_number ( static_cast < int64_t > ( n ) ) ;
}
// LCOV_EXCL_START
else
{
JSON_THROW ( out_of_range : : create ( 407 , " number overflow serializing " + std : : to_string ( n ) ) ) ;
}
// LCOV_EXCL_STOP
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief determine the type prefix of container values
@ note This function does not need to be 100 % accurate when it comes to
integer limits . In case a number exceeds the limits of int64_t ,
this will be detected by a later call to function
write_number_with_ubjson_prefix . Therefore , we return ' L ' for any
value that does not fit the previous limits .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
char ubjson_prefix ( const BasicJsonType & j ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( j . type ( ) )
{
case value_t : : null :
return ' Z ' ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
return j . m_value . boolean ? ' T ' : ' F ' ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
{
if ( ( std : : numeric_limits < int8_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
return ' i ' ;
}
else if ( ( std : : numeric_limits < uint8_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
return ' U ' ;
}
else if ( ( std : : numeric_limits < int16_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
{
return ' I ' ;
}
else if ( ( std : : numeric_limits < int32_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
{
return ' l ' ;
}
else // no check and assume int64_t (see note above)
{
return ' L ' ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
{
if ( j . m_value . number_unsigned < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
return ' i ' ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
return ' U ' ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
{
return ' I ' ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
{
return ' l ' ;
}
else // no check and assume int64_t (see note above)
{
return ' L ' ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_float :
return ' D ' ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
return ' S ' ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
return ' [ ' ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
return ' { ' ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default : // discarded values
return ' N ' ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
/// whether we can assume little endianess
const bool is_little_endian = binary_reader < BasicJsonType > : : little_endianess ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the output
output_adapter_t < CharType > oa = nullptr ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/output/serializer.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <algorithm> // reverse, remove, fill, find, none_of
# include <array> // array
# include <cassert> // assert
# include <ciso646> // and, or
# include <clocale> // localeconv, lconv
# include <cmath> // labs, isfinite, isnan, signbit
# include <cstddef> // size_t, ptrdiff_t
# include <cstdint> // uint8_t
# include <cstdio> // snprintf
# include <iomanip> // setfill
# include <iterator> // next
# include <limits> // numeric_limits
# include <string> // string
# include <sstream> // stringstream
# include <type_traits> // is_same
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/exceptions.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/conversions/to_chars.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <cassert> // assert
# include <ciso646> // or, and, not
# include <cmath> // signbit, isfinite
# include <cstdint> // intN_t, uintN_t
# include <cstring> // memcpy, memmove
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief implements the Grisu2 algorithm for binary to decimal floating - point
conversion .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This implementation is a slightly modified version of the reference
implementation which may be obtained from
http : //florian.loitsch.com/publications (bench.tar.gz).
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The code is distributed under the MIT license , Copyright ( c ) 2009 Florian Loitsch .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
For a detailed description of the algorithm see :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ 1 ] Loitsch , " Printing Floating-Point Numbers Quickly and Accurately with
Integers " , Proceedings of the ACM SIGPLAN 2010 Conference on Programming
Language Design and Implementation , PLDI 2010
[ 2 ] Burger , Dybvig , " Printing Floating-Point Numbers Quickly and Accurately " ,
Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
Design and Implementation , PLDI 1996
*/
namespace dtoa_impl
{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename Target , typename Source >
Target reinterpret_bits ( const Source source )
{
static_assert ( sizeof ( Target ) = = sizeof ( Source ) , " size mismatch " ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Target target ;
std : : memcpy ( & target , & source , sizeof ( Source ) ) ;
return target ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
struct diyfp // f * 2^e
{
static constexpr int kPrecision = 64 ; // = q
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
uint64_t f ;
int e ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
constexpr diyfp ( ) noexcept : f ( 0 ) , e ( 0 ) { }
constexpr diyfp ( uint64_t f_ , int e_ ) noexcept : f ( f_ ) , e ( e_ ) { }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief returns x - y
@ pre x . e = = y . e and x . f > = y . f
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static diyfp sub ( const diyfp & x , const diyfp & y ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( x . e = = y . e ) ;
assert ( x . f > = y . f ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return diyfp ( x . f - y . f , x . e ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief returns x * y
@ note The result is rounded . ( Only the upper q bits are returned . )
*/
static diyfp mul ( const diyfp & x , const diyfp & y ) noexcept
{
static_assert ( kPrecision = = 64 , " internal error " ) ;
// Computes:
// f = round((x.f * y.f) / 2^q)
// e = x.e + y.e + q
// Emulate the 64-bit * 64-bit multiplication:
//
// p = u * v
// = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
// = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi )
// = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 )
// = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 )
// = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3)
// = (p0_lo ) + 2^32 (Q ) + 2^64 (H )
// = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H )
//
// (Since Q might be larger than 2^32 - 1)
//
// = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
//
// (Q_hi + H does not overflow a 64-bit int)
//
// = p_lo + 2^64 p_hi
const uint64_t u_lo = x . f & 0xFFFFFFFF ;
const uint64_t u_hi = x . f > > 32 ;
const uint64_t v_lo = y . f & 0xFFFFFFFF ;
const uint64_t v_hi = y . f > > 32 ;
const uint64_t p0 = u_lo * v_lo ;
const uint64_t p1 = u_lo * v_hi ;
const uint64_t p2 = u_hi * v_lo ;
const uint64_t p3 = u_hi * v_hi ;
const uint64_t p0_hi = p0 > > 32 ;
const uint64_t p1_lo = p1 & 0xFFFFFFFF ;
const uint64_t p1_hi = p1 > > 32 ;
const uint64_t p2_lo = p2 & 0xFFFFFFFF ;
const uint64_t p2_hi = p2 > > 32 ;
uint64_t Q = p0_hi + p1_lo + p2_lo ;
// The full product might now be computed as
//
// p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
// p_lo = p0_lo + (Q << 32)
//
// But in this particular case here, the full p_lo is not required.
// Effectively we only need to add the highest bit in p_lo to p_hi (and
// Q_hi + 1 does not overflow).
Q + = uint64_t { 1 } < < ( 64 - 32 - 1 ) ; // round, ties up
const uint64_t h = p3 + p2_hi + p1_hi + ( Q > > 32 ) ;
return diyfp ( h , x . e + y . e + 64 ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief normalize x such that the significand is > = 2 ^ ( q - 1 )
@ pre x . f ! = 0
*/
static diyfp normalize ( diyfp x ) noexcept
{
assert ( x . f ! = 0 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
while ( ( x . f > > 63 ) = = 0 )
{
x . f < < = 1 ;
x . e - - ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return x ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief normalize x such that the result has the exponent E
@ pre e > = x . e and the upper e - x . e bits of x . f must be zero .
*/
static diyfp normalize_to ( const diyfp & x , const int target_exponent ) noexcept
{
const int delta = x . e - target_exponent ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert ( delta > = 0 ) ;
assert ( ( ( x . f < < delta ) > > delta ) = = x . f ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return diyfp ( x . f < < delta , target_exponent ) ;
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
struct boundaries
{
diyfp w ;
diyfp minus ;
diyfp plus ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
Compute the ( normalized ) diyfp representing the input number ' value ' and its
boundaries .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre value must be finite and positive
*/
template < typename FloatType >
boundaries compute_boundaries ( FloatType value )
{
assert ( std : : isfinite ( value ) ) ;
assert ( value > 0 ) ;
// Convert the IEEE representation into a diyfp.
//
// If v is denormal:
// value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1))
// If v is normalized:
// value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
static_assert ( std : : numeric_limits < FloatType > : : is_iec559 ,
" internal error: dtoa_short requires an IEEE-754 floating-point implementation " ) ;
constexpr int kPrecision = std : : numeric_limits < FloatType > : : digits ; // = p (includes the hidden bit)
constexpr int kBias = std : : numeric_limits < FloatType > : : max_exponent - 1 + ( kPrecision - 1 ) ;
constexpr int kMinExp = 1 - kBias ;
constexpr uint64_t kHiddenBit = uint64_t { 1 } < < ( kPrecision - 1 ) ; // = 2^(p-1)
using bits_type = typename std : : conditional < kPrecision = = 24 , uint32_t , uint64_t > : : type ;
const uint64_t bits = reinterpret_bits < bits_type > ( value ) ;
const uint64_t E = bits > > ( kPrecision - 1 ) ;
const uint64_t F = bits & ( kHiddenBit - 1 ) ;
const bool is_denormal = ( E = = 0 ) ;
const diyfp v = is_denormal
? diyfp ( F , kMinExp )
: diyfp ( F + kHiddenBit , static_cast < int > ( E ) - kBias ) ;
// Compute the boundaries m- and m+ of the floating-point value
// v = f * 2^e.
//
// Determine v- and v+, the floating-point predecessor and successor if v,
// respectively.
//
// v- = v - 2^e if f != 2^(p-1) or e == e_min (A)
// = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B)
//
// v+ = v + 2^e
//
// Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
// between m- and m+ round to v, regardless of how the input rounding
// algorithm breaks ties.
//
// ---+-------------+-------------+-------------+-------------+--- (A)
// v- m- v m+ v+
//
// -----------------+------+------+-------------+-------------+--- (B)
// v- m- v m+ v+
const bool lower_boundary_is_closer = ( F = = 0 and E > 1 ) ;
const diyfp m_plus = diyfp ( 2 * v . f + 1 , v . e - 1 ) ;
const diyfp m_minus = lower_boundary_is_closer
? diyfp ( 4 * v . f - 1 , v . e - 2 ) // (B)
: diyfp ( 2 * v . f - 1 , v . e - 1 ) ; // (A)
// Determine the normalized w+ = m+.
const diyfp w_plus = diyfp : : normalize ( m_plus ) ;
// Determine w- = m- such that e_(w-) = e_(w+).
const diyfp w_minus = diyfp : : normalize_to ( m_minus , w_plus . e ) ;
return { diyfp : : normalize ( v ) , w_minus , w_plus } ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// Given normalized diyfp w, Grisu needs to find a (normalized) cached
// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
// within a certain range [alpha, gamma] (Definition 3.2 from [1])
//
// alpha <= e = e_c + e_w + q <= gamma
//
// or
//
// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
// <= f_c * f_w * 2^gamma
//
// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
//
// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
//
// or
//
// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
//
// The choice of (alpha,gamma) determines the size of the table and the form of
// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
// in practice:
//
// The idea is to cut the number c * w = f * 2^e into two parts, which can be
// processed independently: An integral part p1, and a fractional part p2:
//
// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
// = (f div 2^-e) + (f mod 2^-e) * 2^e
// = p1 + p2 * 2^e
//
// The conversion of p1 into decimal form requires a series of divisions and
// modulos by (a power of) 10. These operations are faster for 32-bit than for
// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
// achieved by choosing
//
// -e >= 32 or e <= -32 := gamma
//
// In order to convert the fractional part
//
// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
//
// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
// d[-i] are extracted in order:
//
// (10 * p2) div 2^-e = d[-1]
// (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
//
// The multiplication by 10 must not overflow. It is sufficient to choose
//
// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
//
// Since p2 = f mod 2^-e < 2^-e,
//
// -e <= 60 or e >= -60 := alpha
constexpr int kAlpha = - 60 ;
constexpr int kGamma = - 32 ;
struct cached_power // c = f * 2^e ~= 10^k
{
uint64_t f ;
int e ;
int k ;
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
For a normalized diyfp w = f * 2 ^ e , this function returns a ( normalized ) cached
power - of - ten c = f_c * 2 ^ e_c , such that the exponent of the product w * c
satisfies ( Definition 3.2 from [ 1 ] )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
alpha < = e_c + e + q < = gamma .
*/
inline cached_power get_cached_power_for_binary_exponent ( int e )
{
// Now
//
// alpha <= e_c + e + q <= gamma (1)
// ==> f_c * 2^alpha <= c * 2^e * 2^q
//
// and since the c's are normalized, 2^(q-1) <= f_c,
//
// ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
// ==> 2^(alpha - e - 1) <= c
//
// If c were an exakt power of ten, i.e. c = 10^k, one may determine k as
//
// k = ceil( log_10( 2^(alpha - e - 1) ) )
// = ceil( (alpha - e - 1) * log_10(2) )
//
// From the paper:
// "In theory the result of the procedure could be wrong since c is rounded,
// and the computation itself is approximated [...]. In practice, however,
// this simple function is sufficient."
//
// For IEEE double precision floating-point numbers converted into
// normalized diyfp's w = f * 2^e, with q = 64,
//
// e >= -1022 (min IEEE exponent)
// -52 (p - 1)
// -52 (p - 1, possibly normalize denormal IEEE numbers)
// -11 (normalize the diyfp)
// = -1137
//
// and
//
// e <= +1023 (max IEEE exponent)
// -52 (p - 1)
// -11 (normalize the diyfp)
// = 960
//
// This binary exponent range [-1137,960] results in a decimal exponent
// range [-307,324]. One does not need to store a cached power for each
// k in this range. For each such k it suffices to find a cached power
// such that the exponent of the product lies in [alpha,gamma].
// This implies that the difference of the decimal exponents of adjacent
// table entries must be less than or equal to
//
// floor( (gamma - alpha) * log_10(2) ) = 8.
//
// (A smaller distance gamma-alpha would require a larger table.)
// NB:
// Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
constexpr int kCachedPowersSize = 79 ;
constexpr int kCachedPowersMinDecExp = - 300 ;
constexpr int kCachedPowersDecStep = 8 ;
static constexpr cached_power kCachedPowers [ ] =
{
{ 0xAB70FE17C79AC6CA , - 1060 , - 300 } ,
{ 0xFF77B1FCBEBCDC4F , - 1034 , - 292 } ,
{ 0xBE5691EF416BD60C , - 1007 , - 284 } ,
{ 0x8DD01FAD907FFC3C , - 980 , - 276 } ,
{ 0xD3515C2831559A83 , - 954 , - 268 } ,
{ 0x9D71AC8FADA6C9B5 , - 927 , - 260 } ,
{ 0xEA9C227723EE8BCB , - 901 , - 252 } ,
{ 0xAECC49914078536D , - 874 , - 244 } ,
{ 0x823C12795DB6CE57 , - 847 , - 236 } ,
{ 0xC21094364DFB5637 , - 821 , - 228 } ,
{ 0x9096EA6F3848984F , - 794 , - 220 } ,
{ 0xD77485CB25823AC7 , - 768 , - 212 } ,
{ 0xA086CFCD97BF97F4 , - 741 , - 204 } ,
{ 0xEF340A98172AACE5 , - 715 , - 196 } ,
{ 0xB23867FB2A35B28E , - 688 , - 188 } ,
{ 0x84C8D4DFD2C63F3B , - 661 , - 180 } ,
{ 0xC5DD44271AD3CDBA , - 635 , - 172 } ,
{ 0x936B9FCEBB25C996 , - 608 , - 164 } ,
{ 0xDBAC6C247D62A584 , - 582 , - 156 } ,
{ 0xA3AB66580D5FDAF6 , - 555 , - 148 } ,
{ 0xF3E2F893DEC3F126 , - 529 , - 140 } ,
{ 0xB5B5ADA8AAFF80B8 , - 502 , - 132 } ,
{ 0x87625F056C7C4A8B , - 475 , - 124 } ,
{ 0xC9BCFF6034C13053 , - 449 , - 116 } ,
{ 0x964E858C91BA2655 , - 422 , - 108 } ,
{ 0xDFF9772470297EBD , - 396 , - 100 } ,
{ 0xA6DFBD9FB8E5B88F , - 369 , - 92 } ,
{ 0xF8A95FCF88747D94 , - 343 , - 84 } ,
{ 0xB94470938FA89BCF , - 316 , - 76 } ,
{ 0x8A08F0F8BF0F156B , - 289 , - 68 } ,
{ 0xCDB02555653131B6 , - 263 , - 60 } ,
{ 0x993FE2C6D07B7FAC , - 236 , - 52 } ,
{ 0xE45C10C42A2B3B06 , - 210 , - 44 } ,
{ 0xAA242499697392D3 , - 183 , - 36 } ,
{ 0xFD87B5F28300CA0E , - 157 , - 28 } ,
{ 0xBCE5086492111AEB , - 130 , - 20 } ,
{ 0x8CBCCC096F5088CC , - 103 , - 12 } ,
{ 0xD1B71758E219652C , - 77 , - 4 } ,
{ 0x9C40000000000000 , - 50 , 4 } ,
{ 0xE8D4A51000000000 , - 24 , 12 } ,
{ 0xAD78EBC5AC620000 , 3 , 20 } ,
{ 0x813F3978F8940984 , 30 , 28 } ,
{ 0xC097CE7BC90715B3 , 56 , 36 } ,
{ 0x8F7E32CE7BEA5C70 , 83 , 44 } ,
{ 0xD5D238A4ABE98068 , 109 , 52 } ,
{ 0x9F4F2726179A2245 , 136 , 60 } ,
{ 0xED63A231D4C4FB27 , 162 , 68 } ,
{ 0xB0DE65388CC8ADA8 , 189 , 76 } ,
{ 0x83C7088E1AAB65DB , 216 , 84 } ,
{ 0xC45D1DF942711D9A , 242 , 92 } ,
{ 0x924D692CA61BE758 , 269 , 100 } ,
{ 0xDA01EE641A708DEA , 295 , 108 } ,
{ 0xA26DA3999AEF774A , 322 , 116 } ,
{ 0xF209787BB47D6B85 , 348 , 124 } ,
{ 0xB454E4A179DD1877 , 375 , 132 } ,
{ 0x865B86925B9BC5C2 , 402 , 140 } ,
{ 0xC83553C5C8965D3D , 428 , 148 } ,
{ 0x952AB45CFA97A0B3 , 455 , 156 } ,
{ 0xDE469FBD99A05FE3 , 481 , 164 } ,
{ 0xA59BC234DB398C25 , 508 , 172 } ,
{ 0xF6C69A72A3989F5C , 534 , 180 } ,
{ 0xB7DCBF5354E9BECE , 561 , 188 } ,
{ 0x88FCF317F22241E2 , 588 , 196 } ,
{ 0xCC20CE9BD35C78A5 , 614 , 204 } ,
{ 0x98165AF37B2153DF , 641 , 212 } ,
{ 0xE2A0B5DC971F303A , 667 , 220 } ,
{ 0xA8D9D1535CE3B396 , 694 , 228 } ,
{ 0xFB9B7CD9A4A7443C , 720 , 236 } ,
{ 0xBB764C4CA7A44410 , 747 , 244 } ,
{ 0x8BAB8EEFB6409C1A , 774 , 252 } ,
{ 0xD01FEF10A657842C , 800 , 260 } ,
{ 0x9B10A4E5E9913129 , 827 , 268 } ,
{ 0xE7109BFBA19C0C9D , 853 , 276 } ,
{ 0xAC2820D9623BF429 , 880 , 284 } ,
{ 0x80444B5E7AA7CF85 , 907 , 292 } ,
{ 0xBF21E44003ACDD2D , 933 , 300 } ,
{ 0x8E679C2F5E44FF8F , 960 , 308 } ,
{ 0xD433179D9C8CB841 , 986 , 316 } ,
{ 0x9E19DB92B4E31BA9 , 1013 , 324 } ,
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// This computation gives exactly the same results for k as
// k = ceil((kAlpha - e - 1) * 0.30102999566398114)
// for |e| <= 1500, but doesn't require floating-point operations.
// NB: log_10(2) ~= 78913 / 2^18
assert ( e > = - 1500 ) ;
assert ( e < = 1500 ) ;
const int f = kAlpha - e - 1 ;
const int k = ( f * 78913 ) / ( 1 < < 18 ) + ( f > 0 ) ;
const int index = ( - kCachedPowersMinDecExp + k + ( kCachedPowersDecStep - 1 ) ) / kCachedPowersDecStep ;
assert ( index > = 0 ) ;
assert ( index < kCachedPowersSize ) ;
static_cast < void > ( kCachedPowersSize ) ; // Fix warning.
const cached_power cached = kCachedPowers [ index ] ;
assert ( kAlpha < = cached . e + e + 64 ) ;
assert ( kGamma > = cached . e + e + 64 ) ;
return cached ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
For n ! = 0 , returns k , such that pow10 : = 10 ^ ( k - 1 ) < = n < 10 ^ k .
For n = = 0 , returns 1 and sets pow10 : = 1.
*/
inline int find_largest_pow10 ( const uint32_t n , uint32_t & pow10 )
{
// LCOV_EXCL_START
if ( n > = 1000000000 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
pow10 = 1000000000 ;
return 10 ;
}
// LCOV_EXCL_STOP
else if ( n > = 100000000 )
{
pow10 = 100000000 ;
return 9 ;
}
else if ( n > = 10000000 )
{
pow10 = 10000000 ;
return 8 ;
}
else if ( n > = 1000000 )
{
pow10 = 1000000 ;
return 7 ;
}
else if ( n > = 100000 )
{
pow10 = 100000 ;
return 6 ;
}
else if ( n > = 10000 )
{
pow10 = 10000 ;
return 5 ;
}
else if ( n > = 1000 )
{
pow10 = 1000 ;
return 4 ;
}
else if ( n > = 100 )
{
pow10 = 100 ;
return 3 ;
}
else if ( n > = 10 )
{
pow10 = 10 ;
return 2 ;
}
else
{
pow10 = 1 ;
return 1 ;
}
}
inline void grisu2_round ( char * buf , int len , uint64_t dist , uint64_t delta ,
uint64_t rest , uint64_t ten_k )
{
assert ( len > = 1 ) ;
assert ( dist < = delta ) ;
assert ( rest < = delta ) ;
assert ( ten_k > 0 ) ;
// <--------------------------- delta ---->
// <---- dist --------->
// --------------[------------------+-------------------]--------------
// M- w M+
//
// ten_k
// <------>
// <---- rest ---->
// --------------[------------------+----+--------------]--------------
// w V
// = buf * 10^k
//
// ten_k represents a unit-in-the-last-place in the decimal representation
// stored in buf.
// Decrement buf by ten_k while this takes buf closer to w.
// The tests are written in this order to avoid overflow in unsigned
// integer arithmetic.
while ( rest < dist
and delta - rest > = ten_k
and ( rest + ten_k < dist or dist - rest > rest + ten_k - dist ) )
{
assert ( buf [ len - 1 ] ! = ' 0 ' ) ;
buf [ len - 1 ] - - ;
rest + = ten_k ;
}
}
/*!
Generates V = buffer * 10 ^ decimal_exponent , such that M - < = V < = M + .
M - and M + must be normalized and share the same exponent - 60 < = e < = - 32.
*/
inline void grisu2_digit_gen ( char * buffer , int & length , int & decimal_exponent ,
diyfp M_minus , diyfp w , diyfp M_plus )
{
static_assert ( kAlpha > = - 60 , " internal error " ) ;
static_assert ( kGamma < = - 32 , " internal error " ) ;
// Generates the digits (and the exponent) of a decimal floating-point
// number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
// w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
//
// <--------------------------- delta ---->
// <---- dist --------->
// --------------[------------------+-------------------]--------------
// M- w M+
//
// Grisu2 generates the digits of M+ from left to right and stops as soon as
// V is in [M-,M+].
assert ( M_plus . e > = kAlpha ) ;
assert ( M_plus . e < = kGamma ) ;
uint64_t delta = diyfp : : sub ( M_plus , M_minus ) . f ; // (significand of (M+ - M-), implicit exponent is e)
uint64_t dist = diyfp : : sub ( M_plus , w ) . f ; // (significand of (M+ - w ), implicit exponent is e)
// Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
//
// M+ = f * 2^e
// = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
// = ((p1 ) * 2^-e + (p2 )) * 2^e
// = p1 + p2 * 2^e
const diyfp one ( uint64_t { 1 } < < - M_plus . e , M_plus . e ) ;
uint32_t p1 = static_cast < uint32_t > ( M_plus . f > > - one . e ) ; // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
uint64_t p2 = M_plus . f & ( one . f - 1 ) ; // p2 = f mod 2^-e
// 1)
//
// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
assert ( p1 > 0 ) ;
uint32_t pow10 ;
const int k = find_largest_pow10 ( p1 , pow10 ) ;
// 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
//
// p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
// = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1))
//
// M+ = p1 + p2 * 2^e
// = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e
// = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
// = d[k-1] * 10^(k-1) + ( rest) * 2^e
//
// Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
//
// p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
//
// but stop as soon as
//
// rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
int n = k ;
while ( n > 0 )
{
// Invariants:
// M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k)
// pow10 = 10^(n-1) <= p1 < 10^n
//
const uint32_t d = p1 / pow10 ; // d = p1 div 10^(n-1)
const uint32_t r = p1 % pow10 ; // r = p1 mod 10^(n-1)
//
// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
//
assert ( d < = 9 ) ;
buffer [ length + + ] = static_cast < char > ( ' 0 ' + d ) ; // buffer := buffer * 10 + d
//
// M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
//
p1 = r ;
n - - ;
//
// M+ = buffer * 10^n + (p1 + p2 * 2^e)
// pow10 = 10^n
//
// Now check if enough digits have been generated.
// Compute
//
// p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
//
// Note:
// Since rest and delta share the same exponent e, it suffices to
// compare the significands.
const uint64_t rest = ( uint64_t { p1 } < < - one . e ) + p2 ;
if ( rest < = delta )
{
// V = buffer * 10^n, with M- <= V <= M+.
decimal_exponent + = n ;
// We may now just stop. But instead look if the buffer could be
// decremented to bring V closer to w.
//
// pow10 = 10^n is now 1 ulp in the decimal representation V.
// The rounding procedure works with diyfp's with an implicit
// exponent of e.
//
// 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
//
const uint64_t ten_n = uint64_t { pow10 } < < - one . e ;
grisu2_round ( buffer , length , dist , delta , rest , ten_n ) ;
return ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
pow10 / = 10 ;
//
// pow10 = 10^(n-1) <= p1 < 10^n
// Invariants restored.
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// 2)
//
// The digits of the integral part have been generated:
//
// M+ = d[k-1]...d[1]d[0] + p2 * 2^e
// = buffer + p2 * 2^e
//
// Now generate the digits of the fractional part p2 * 2^e.
//
// Note:
// No decimal point is generated: the exponent is adjusted instead.
//
// p2 actually represents the fraction
//
// p2 * 2^e
// = p2 / 2^-e
// = d[-1] / 10^1 + d[-2] / 10^2 + ...
//
// Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
//
// p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
// + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
//
// using
//
// 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
// = ( d) * 2^-e + ( r)
//
// or
// 10^m * p2 * 2^e = d + r * 2^e
//
// i.e.
//
// M+ = buffer + p2 * 2^e
// = buffer + 10^-m * (d + r * 2^e)
// = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
//
// and stop as soon as 10^-m * r * 2^e <= delta * 2^e
assert ( p2 > delta ) ;
int m = 0 ;
for ( ; ; )
{
// Invariant:
// M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
// = buffer * 10^-m + 10^-m * (p2 ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
//
assert ( p2 < = UINT64_MAX / 10 ) ;
p2 * = 10 ;
const uint64_t d = p2 > > - one . e ; // d = (10 * p2) div 2^-e
const uint64_t r = p2 & ( one . f - 1 ) ; // r = (10 * p2) mod 2^-e
//
// M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
//
assert ( d < = 9 ) ;
buffer [ length + + ] = static_cast < char > ( ' 0 ' + d ) ; // buffer := buffer * 10 + d
//
// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
//
p2 = r ;
m + + ;
//
// M+ = buffer * 10^-m + 10^-m * p2 * 2^e
// Invariant restored.
// Check if enough digits have been generated.
//
// 10^-m * p2 * 2^e <= delta * 2^e
// p2 * 2^e <= 10^m * delta * 2^e
// p2 <= 10^m * delta
delta * = 10 ;
dist * = 10 ;
if ( p2 < = delta )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
break ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// V = buffer * 10^-m, with M- <= V <= M+.
decimal_exponent - = m ;
// 1 ulp in the decimal representation is now 10^-m.
// Since delta and dist are now scaled by 10^m, we need to do the
// same with ulp in order to keep the units in sync.
//
// 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
//
const uint64_t ten_m = one . f ;
grisu2_round ( buffer , length , dist , delta , p2 , ten_m ) ;
// By construction this algorithm generates the shortest possible decimal
// number (Loitsch, Theorem 6.2) which rounds back to w.
// For an input number of precision p, at least
//
// N = 1 + ceil(p * log_10(2))
//
// decimal digits are sufficient to identify all binary floating-point
// numbers (Matula, "In-and-Out conversions").
// This implies that the algorithm does not produce more than N decimal
// digits.
//
// N = 17 for p = 53 (IEEE double precision)
// N = 9 for p = 24 (IEEE single precision)
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
v = buf * 10 ^ decimal_exponent
len is the length of the buffer ( number of decimal digits )
The buffer must be large enough , i . e . > = max_digits10 .
*/
inline void grisu2 ( char * buf , int & len , int & decimal_exponent ,
diyfp m_minus , diyfp v , diyfp m_plus )
{
assert ( m_plus . e = = m_minus . e ) ;
assert ( m_plus . e = = v . e ) ;
// --------(-----------------------+-----------------------)-------- (A)
// m- v m+
//
// --------------------(-----------+-----------------------)-------- (B)
// m- v m+
//
// First scale v (and m- and m+) such that the exponent is in the range
// [alpha, gamma].
const cached_power cached = get_cached_power_for_binary_exponent ( m_plus . e ) ;
const diyfp c_minus_k ( cached . f , cached . e ) ; // = c ~= 10^-k
// The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
const diyfp w = diyfp : : mul ( v , c_minus_k ) ;
const diyfp w_minus = diyfp : : mul ( m_minus , c_minus_k ) ;
const diyfp w_plus = diyfp : : mul ( m_plus , c_minus_k ) ;
// ----(---+---)---------------(---+---)---------------(---+---)----
// w- w w+
// = c*m- = c*v = c*m+
//
// diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
// w+ are now off by a small amount.
// In fact:
//
// w - v * 10^k < 1 ulp
//
// To account for this inaccuracy, add resp. subtract 1 ulp.
//
// --------+---[---------------(---+---)---------------]---+--------
// w- M- w M+ w+
//
// Now any number in [M-, M+] (bounds included) will round to w when input,
// regardless of how the input rounding algorithm breaks ties.
//
// And digit_gen generates the shortest possible such number in [M-, M+].
// Note that this does not mean that Grisu2 always generates the shortest
// possible number in the interval (m-, m+).
const diyfp M_minus ( w_minus . f + 1 , w_minus . e ) ;
const diyfp M_plus ( w_plus . f - 1 , w_plus . e ) ;
decimal_exponent = - cached . k ; // = -(-k) = k
grisu2_digit_gen ( buf , len , decimal_exponent , M_minus , w , M_plus ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
v = buf * 10 ^ decimal_exponent
len is the length of the buffer ( number of decimal digits )
The buffer must be large enough , i . e . > = max_digits10 .
*/
template < typename FloatType >
void grisu2 ( char * buf , int & len , int & decimal_exponent , FloatType value )
{
static_assert ( diyfp : : kPrecision > = std : : numeric_limits < FloatType > : : digits + 3 ,
" internal error: not enough precision " ) ;
assert ( std : : isfinite ( value ) ) ;
assert ( value > 0 ) ;
// If the neighbors (and boundaries) of 'value' are always computed for double-precision
// numbers, all float's can be recovered using strtod (and strtof). However, the resulting
// decimal representations are not exactly "short".
//
// The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars)
// says "value is converted to a string as if by std::sprintf in the default ("C") locale"
// and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
// does.
// On the other hand, the documentation for 'std::to_chars' requires that "parsing the
// representation using the corresponding std::from_chars function recovers value exactly". That
// indicates that single precision floating-point numbers should be recovered using
// 'std::strtof'.
//
// NB: If the neighbors are computed for single-precision numbers, there is a single float
// (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
// value is off by 1 ulp.
#if 0
const boundaries w = compute_boundaries ( static_cast < double > ( value ) ) ;
# else
const boundaries w = compute_boundaries ( value ) ;
# endif
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
grisu2 ( buf , len , decimal_exponent , w . minus , w . w , w . plus ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief appends a decimal representation of e to buf
@ return a pointer to the element following the exponent .
@ pre - 1000 < e < 1000
*/
inline char * append_exponent ( char * buf , int e )
{
assert ( e > - 1000 ) ;
assert ( e < 1000 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( e < 0 )
{
e = - e ;
* buf + + = ' - ' ;
}
else
{
* buf + + = ' + ' ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
uint32_t k = static_cast < uint32_t > ( e ) ;
if ( k < 10 )
{
// Always print at least two digits in the exponent.
// This is for compatibility with printf("%g").
* buf + + = ' 0 ' ;
* buf + + = static_cast < char > ( ' 0 ' + k ) ;
}
else if ( k < 100 )
{
* buf + + = static_cast < char > ( ' 0 ' + k / 10 ) ;
k % = 10 ;
* buf + + = static_cast < char > ( ' 0 ' + k ) ;
}
else
{
* buf + + = static_cast < char > ( ' 0 ' + k / 100 ) ;
k % = 100 ;
* buf + + = static_cast < char > ( ' 0 ' + k / 10 ) ;
k % = 10 ;
* buf + + = static_cast < char > ( ' 0 ' + k ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return buf ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief prettify v = buf * 10 ^ decimal_exponent
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
If v is in the range [ 10 ^ min_exp , 10 ^ max_exp ) it will be printed in fixed - point
notation . Otherwise it will be printed in exponential notation .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre min_exp < 0
@ pre max_exp > 0
*/
inline char * format_buffer ( char * buf , int len , int decimal_exponent ,
int min_exp , int max_exp )
{
assert ( min_exp < 0 ) ;
assert ( max_exp > 0 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const int k = len ;
const int n = len + decimal_exponent ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// v = buf * 10^(n-k)
// k is the length of the buffer (number of decimal digits)
// n is the position of the decimal point relative to the start of the buffer.
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( k < = n and n < = max_exp )
{
// digits[000]
// len <= max_exp + 2
std : : memset ( buf + k , ' 0 ' , static_cast < size_t > ( n - k ) ) ;
// Make it look like a floating-point number (#362, #378)
buf [ n + 0 ] = ' . ' ;
buf [ n + 1 ] = ' 0 ' ;
return buf + ( n + 2 ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( 0 < n and n < = max_exp )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// dig.its
// len <= max_digits10 + 1
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert ( k > n ) ;
std : : memmove ( buf + ( n + 1 ) , buf + n , static_cast < size_t > ( k - n ) ) ;
buf [ n ] = ' . ' ;
return buf + ( k + 1 ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( min_exp < n and n < = 0 )
{
// 0.[000]digits
// len <= 2 + (-min_exp - 1) + max_digits10
std : : memmove ( buf + ( 2 + - n ) , buf , static_cast < size_t > ( k ) ) ;
buf [ 0 ] = ' 0 ' ;
buf [ 1 ] = ' . ' ;
std : : memset ( buf + 2 , ' 0 ' , static_cast < size_t > ( - n ) ) ;
return buf + ( 2 + ( - n ) + k ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( k = = 1 )
{
// dE+123
// len <= 1 + 5
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
buf + = 1 ;
}
else
{
// d.igitsE+123
// len <= max_digits10 + 1 + 5
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
std : : memmove ( buf + 2 , buf + 1 , static_cast < size_t > ( k - 1 ) ) ;
buf [ 1 ] = ' . ' ;
buf + = 1 + k ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
* buf + + = ' e ' ;
return append_exponent ( buf , n - 1 ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
} // namespace dtoa_impl
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief generates a decimal representation of the floating - point number value in [ first , last ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The format of the resulting decimal representation is similar to printf ' s % g
format . Returns an iterator pointing past - the - end of the decimal representation .
@ note The input number must be finite , i . e . NaN ' s and Inf ' s are not supported .
@ note The buffer must be large enough .
@ note The result is NOT null - terminated .
*/
template < typename FloatType >
char * to_chars ( char * first , char * last , FloatType value )
{
static_cast < void > ( last ) ; // maybe unused - fix warning
assert ( std : : isfinite ( value ) ) ;
// Use signbit(value) instead of (value < 0) since signbit works for -0.
if ( std : : signbit ( value ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
value = - value ;
* first + + = ' - ' ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( value = = 0 ) // +-0
{
* first + + = ' 0 ' ;
// Make it look like a floating-point number (#362, #378)
* first + + = ' . ' ;
* first + + = ' 0 ' ;
return first ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
assert ( last - first > = std : : numeric_limits < FloatType > : : max_digits10 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// Compute v = buffer * 10^decimal_exponent.
// The decimal digits are stored in the buffer, which needs to be interpreted
// as an unsigned decimal integer.
// len is the length of the buffer, i.e. the number of decimal digits.
int len = 0 ;
int decimal_exponent = 0 ;
dtoa_impl : : grisu2 ( first , len , decimal_exponent , value ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert ( len < = std : : numeric_limits < FloatType > : : max_digits10 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// Format the buffer like printf("%.*g", prec, value)
constexpr int kMinExp = - 4 ;
// Use digits10 here to increase compatibility with version 2.
constexpr int kMaxExp = std : : numeric_limits < FloatType > : : digits10 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert ( last - first > = kMaxExp + 2 ) ;
assert ( last - first > = 2 + ( - kMinExp - 1 ) + std : : numeric_limits < FloatType > : : max_digits10 ) ;
assert ( last - first > = std : : numeric_limits < FloatType > : : max_digits10 + 6 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return dtoa_impl : : format_buffer ( first , len , decimal_exponent , kMinExp , kMaxExp ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
} // namespace detail
} // namespace nlohmann
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/meta.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/output/output_adapters.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
///////////////////
// serialization //
///////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType >
class serializer
{
using string_t = typename BasicJsonType : : string_t ;
using number_float_t = typename BasicJsonType : : number_float_t ;
using number_integer_t = typename BasicJsonType : : number_integer_t ;
using number_unsigned_t = typename BasicJsonType : : number_unsigned_t ;
static constexpr uint8_t UTF8_ACCEPT = 0 ;
static constexpr uint8_t UTF8_REJECT = 1 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ param [ in ] s output stream to serialize to
@ param [ in ] ichar indentation character to use
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
serializer ( output_adapter_t < char > s , const char ichar )
: o ( std : : move ( s ) ) , loc ( std : : localeconv ( ) ) ,
thousands_sep ( loc - > thousands_sep = = nullptr ? ' \0 ' : * ( loc - > thousands_sep ) ) ,
decimal_point ( loc - > decimal_point = = nullptr ? ' \0 ' : * ( loc - > decimal_point ) ) ,
indent_char ( ichar ) , indent_string ( 512 , indent_char )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// delete because of pointer members
serializer ( const serializer & ) = delete ;
serializer & operator = ( const serializer & ) = delete ;
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief internal implementation of the serialization function
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function is called by the public member function dump and organizes
the serialization internally . The indentation level is propagated as
additional parameter . In case of arrays and objects , the function is
called recursively .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
- strings and object keys are escaped using ` escape_string ( ) `
- integer numbers are converted implicitly via ` operator < < `
- floating - point numbers are converted to a string using ` " %g " ` format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] val value to serialize
@ param [ in ] pretty_print whether the output shall be pretty - printed
@ param [ in ] indent_step the indent level
@ param [ in ] current_indent the current indent level ( only used internally )
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void dump ( const BasicJsonType & val , const bool pretty_print ,
const bool ensure_ascii ,
const unsigned int indent_step ,
const unsigned int current_indent = 0 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( val . m_type )
{
case value_t : : object :
{
if ( val . m_value . object - > empty ( ) )
{
o - > write_characters ( " {} " , 2 ) ;
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( pretty_print )
{
o - > write_characters ( " { \n " , 2 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step ;
if ( JSON_UNLIKELY ( indent_string . size ( ) < new_indent ) )
{
indent_string . resize ( indent_string . size ( ) * 2 , ' ' ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// first n-1 elements
auto i = val . m_value . object - > cbegin ( ) ;
for ( std : : size_t cnt = 0 ; cnt < val . m_value . object - > size ( ) - 1 ; + + cnt , + + i )
{
o - > write_characters ( indent_string . c_str ( ) , new_indent ) ;
o - > write_character ( ' \" ' ) ;
dump_escaped ( i - > first , ensure_ascii ) ;
o - > write_characters ( " \" : " , 3 ) ;
dump ( i - > second , true , ensure_ascii , indent_step , new_indent ) ;
o - > write_characters ( " , \n " , 2 ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// last element
assert ( i ! = val . m_value . object - > cend ( ) ) ;
assert ( std : : next ( i ) = = val . m_value . object - > cend ( ) ) ;
o - > write_characters ( indent_string . c_str ( ) , new_indent ) ;
o - > write_character ( ' \" ' ) ;
dump_escaped ( i - > first , ensure_ascii ) ;
o - > write_characters ( " \" : " , 3 ) ;
dump ( i - > second , true , ensure_ascii , indent_step , new_indent ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
o - > write_character ( ' \n ' ) ;
o - > write_characters ( indent_string . c_str ( ) , current_indent ) ;
o - > write_character ( ' } ' ) ;
}
else
{
o - > write_character ( ' { ' ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// first n-1 elements
auto i = val . m_value . object - > cbegin ( ) ;
for ( std : : size_t cnt = 0 ; cnt < val . m_value . object - > size ( ) - 1 ; + + cnt , + + i )
{
o - > write_character ( ' \" ' ) ;
dump_escaped ( i - > first , ensure_ascii ) ;
o - > write_characters ( " \" : " , 2 ) ;
dump ( i - > second , false , ensure_ascii , indent_step , current_indent ) ;
o - > write_character ( ' , ' ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// last element
assert ( i ! = val . m_value . object - > cend ( ) ) ;
assert ( std : : next ( i ) = = val . m_value . object - > cend ( ) ) ;
o - > write_character ( ' \" ' ) ;
dump_escaped ( i - > first , ensure_ascii ) ;
o - > write_characters ( " \" : " , 2 ) ;
dump ( i - > second , false , ensure_ascii , indent_step , current_indent ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
o - > write_character ( ' } ' ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
if ( val . m_value . array - > empty ( ) )
{
o - > write_characters ( " [] " , 2 ) ;
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( pretty_print )
{
o - > write_characters ( " [ \n " , 2 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step ;
if ( JSON_UNLIKELY ( indent_string . size ( ) < new_indent ) )
{
indent_string . resize ( indent_string . size ( ) * 2 , ' ' ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// first n-1 elements
for ( auto i = val . m_value . array - > cbegin ( ) ;
i ! = val . m_value . array - > cend ( ) - 1 ; + + i )
{
o - > write_characters ( indent_string . c_str ( ) , new_indent ) ;
dump ( * i , true , ensure_ascii , indent_step , new_indent ) ;
o - > write_characters ( " , \n " , 2 ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// last element
assert ( not val . m_value . array - > empty ( ) ) ;
o - > write_characters ( indent_string . c_str ( ) , new_indent ) ;
dump ( val . m_value . array - > back ( ) , true , ensure_ascii , indent_step , new_indent ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
o - > write_character ( ' \n ' ) ;
o - > write_characters ( indent_string . c_str ( ) , current_indent ) ;
o - > write_character ( ' ] ' ) ;
}
else
{
o - > write_character ( ' [ ' ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// first n-1 elements
for ( auto i = val . m_value . array - > cbegin ( ) ;
i ! = val . m_value . array - > cend ( ) - 1 ; + + i )
{
dump ( * i , false , ensure_ascii , indent_step , current_indent ) ;
o - > write_character ( ' , ' ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// last element
assert ( not val . m_value . array - > empty ( ) ) ;
dump ( val . m_value . array - > back ( ) , false , ensure_ascii , indent_step , current_indent ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
o - > write_character ( ' ] ' ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
{
o - > write_character ( ' \" ' ) ;
dump_escaped ( * val . m_value . string , ensure_ascii ) ;
o - > write_character ( ' \" ' ) ;
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
{
if ( val . m_value . boolean )
{
o - > write_characters ( " true " , 4 ) ;
}
else
{
o - > write_characters ( " false " , 5 ) ;
}
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
{
dump_integer ( val . m_value . number_integer ) ;
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
{
dump_integer ( val . m_value . number_unsigned ) ;
return ;
}
case value_t : : number_float :
{
dump_float ( val . m_value . number_float ) ;
return ;
}
case value_t : : discarded :
{
o - > write_characters ( " <discarded> " , 11 ) ;
return ;
}
case value_t : : null :
{
o - > write_characters ( " null " , 4 ) ;
return ;
}
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief dump escaped string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Escape a string by replacing certain special characters by a sequence of an
escape character ( backslash ) and another character and other control
characters by a sequence of " \ u " followed by a four - digit hex
representation . The escaped string is written to output stream @ a o .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] s the string to escape
@ param [ in ] ensure_ascii whether to escape non - ASCII characters with
\ uXXXX sequences
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the length of string @ a s .
*/
void dump_escaped ( const string_t & s , const bool ensure_ascii )
{
uint32_t codepoint ;
uint8_t state = UTF8_ACCEPT ;
std : : size_t bytes = 0 ; // number of bytes written to string_buffer
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
for ( std : : size_t i = 0 ; i < s . size ( ) ; + + i )
{
const auto byte = static_cast < uint8_t > ( s [ i ] ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( decode ( state , codepoint , byte ) )
{
case UTF8_ACCEPT : // decode found a new code point
{
switch ( codepoint )
{
case 0x08 : // backspace
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' b ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x09 : // horizontal tab
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' t ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x0A : // newline
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' n ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x0C : // formfeed
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' f ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x0D : // carriage return
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' r ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x22 : // quotation mark
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' \" ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case 0x5C : // reverse solidus
{
string_buffer [ bytes + + ] = ' \\ ' ;
string_buffer [ bytes + + ] = ' \\ ' ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
// escape control characters (0x00..0x1F) or, if
// ensure_ascii parameter is used, non-ASCII characters
if ( ( codepoint < = 0x1F ) or ( ensure_ascii and ( codepoint > = 0x7F ) ) )
{
if ( codepoint < = 0xFFFF )
{
std : : snprintf ( string_buffer . data ( ) + bytes , 7 , " \\ u%04x " ,
static_cast < uint16_t > ( codepoint ) ) ;
bytes + = 6 ;
}
else
{
std : : snprintf ( string_buffer . data ( ) + bytes , 13 , " \\ u%04x \\ u%04x " ,
static_cast < uint16_t > ( 0xD7C0 + ( codepoint > > 10 ) ) ,
static_cast < uint16_t > ( 0xDC00 + ( codepoint & 0x3FF ) ) ) ;
bytes + = 12 ;
}
}
else
{
// copy byte to buffer (all previous bytes
// been copied have in default case above)
string_buffer [ bytes + + ] = s [ i ] ;
}
break ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// write buffer and reset index; there must be 13 bytes
// left, as this is the maximal number of bytes to be
// written ("\uxxxx\uxxxx\0") for one code point
if ( string_buffer . size ( ) - bytes < 13 )
{
o - > write_characters ( string_buffer . data ( ) , bytes ) ;
bytes = 0 ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case UTF8_REJECT : // decode found invalid UTF-8 byte
{
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < static_cast < int > ( byte ) ;
JSON_THROW ( type_error : : create ( 316 , " invalid UTF-8 byte at index " + std : : to_string ( i ) + " : 0x " + ss . str ( ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default : // decode found yet incomplete multi-byte code point
{
if ( not ensure_ascii )
{
// code point will not be escaped - copy byte to buffer
string_buffer [ bytes + + ] = s [ i ] ;
}
break ;
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_LIKELY ( state = = UTF8_ACCEPT ) )
{
// write buffer
if ( bytes > 0 )
{
o - > write_characters ( string_buffer . data ( ) , bytes ) ;
}
}
else
{
// we finish reading, but do not accept: string was incomplete
std : : stringstream ss ;
ss < < std : : setw ( 2 ) < < std : : uppercase < < std : : setfill ( ' 0 ' ) < < std : : hex < < static_cast < int > ( static_cast < uint8_t > ( s . back ( ) ) ) ;
JSON_THROW ( type_error : : create ( 316 , " incomplete UTF-8 string; last byte: 0x " + ss . str ( ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief dump an integer
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Dump a given integer to output stream @ a o . Works internally with
@ a number_buffer .
@ param [ in ] x integer number ( signed or unsigned ) to dump
@ tparam NumberType either @ a number_integer_t or @ a number_unsigned_t
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename NumberType , detail : : enable_if_t <
std : : is_same < NumberType , number_unsigned_t > : : value or
std : : is_same < NumberType , number_integer_t > : : value ,
int > = 0 >
void dump_integer ( NumberType x )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// special case for "0"
if ( x = = 0 )
{
o - > write_character ( ' 0 ' ) ;
return ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const bool is_negative = ( x < = 0 ) and ( x ! = 0 ) ; // see issue #755
std : : size_t i = 0 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
while ( x ! = 0 )
{
// spare 1 byte for '\0'
assert ( i < number_buffer . size ( ) - 1 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const auto digit = std : : labs ( static_cast < long > ( x % 10 ) ) ;
number_buffer [ i + + ] = static_cast < char > ( ' 0 ' + digit ) ;
x / = 10 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( is_negative )
{
// make sure there is capacity for the '-'
assert ( i < number_buffer . size ( ) - 2 ) ;
number_buffer [ i + + ] = ' - ' ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
std : : reverse ( number_buffer . begin ( ) , number_buffer . begin ( ) + i ) ;
o - > write_characters ( number_buffer . data ( ) , i ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief dump a floating - point number
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Dump a given floating - point number to output stream @ a o . Works internally
with @ a number_buffer .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] x floating - point number to dump
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void dump_float ( number_float_t x )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// NaN / inf
if ( not std : : isfinite ( x ) )
{
o - > write_characters ( " null " , 4 ) ;
return ;
}
// If number_float_t is an IEEE-754 single or double precision number,
// use the Grisu2 algorithm to produce short numbers which are
// guaranteed to round-trip, using strtof and strtod, resp.
//
// NB: The test below works if <long double> == <double>.
static constexpr bool is_ieee_single_or_double
= ( std : : numeric_limits < number_float_t > : : is_iec559 and std : : numeric_limits < number_float_t > : : digits = = 24 and std : : numeric_limits < number_float_t > : : max_exponent = = 128 ) or
( std : : numeric_limits < number_float_t > : : is_iec559 and std : : numeric_limits < number_float_t > : : digits = = 53 and std : : numeric_limits < number_float_t > : : max_exponent = = 1024 ) ;
dump_float ( x , std : : integral_constant < bool , is_ieee_single_or_double > ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
void dump_float ( number_float_t x , std : : true_type /*is_ieee_single_or_double*/ )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
char * begin = number_buffer . data ( ) ;
char * end = : : nlohmann : : detail : : to_chars ( begin , begin + number_buffer . size ( ) , x ) ;
o - > write_characters ( begin , static_cast < size_t > ( end - begin ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
void dump_float ( number_float_t x , std : : false_type /*is_ieee_single_or_double*/ )
{
// get number of digits for a float -> text -> float round-trip
static constexpr auto d = std : : numeric_limits < number_float_t > : : max_digits10 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// the actual conversion
std : : ptrdiff_t len = snprintf ( number_buffer . data ( ) , number_buffer . size ( ) , " %.*g " , d , x ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// negative value indicates an error
assert ( len > 0 ) ;
// check if buffer was large enough
assert ( static_cast < std : : size_t > ( len ) < number_buffer . size ( ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// erase thousands separator
if ( thousands_sep ! = ' \0 ' )
{
const auto end = std : : remove ( number_buffer . begin ( ) ,
number_buffer . begin ( ) + len , thousands_sep ) ;
std : : fill ( end , number_buffer . end ( ) , ' \0 ' ) ;
assert ( ( end - number_buffer . begin ( ) ) < = len ) ;
len = ( end - number_buffer . begin ( ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// convert decimal point to '.'
if ( decimal_point ! = ' \0 ' and decimal_point ! = ' . ' )
{
const auto dec_pos = std : : find ( number_buffer . begin ( ) , number_buffer . end ( ) , decimal_point ) ;
if ( dec_pos ! = number_buffer . end ( ) )
{
* dec_pos = ' . ' ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
o - > write_characters ( number_buffer . data ( ) , static_cast < std : : size_t > ( len ) ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// determine if need to append ".0"
const bool value_is_int_like =
std : : none_of ( number_buffer . begin ( ) , number_buffer . begin ( ) + len + 1 ,
[ ] ( char c )
{
return ( c = = ' . ' or c = = ' e ' ) ;
} ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( value_is_int_like )
{
o - > write_characters ( " .0 " , 2 ) ;
}
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief check whether a string is UTF - 8 encoded
The function checks each byte of a string whether it is UTF - 8 encoded . The
result of the check is stored in the @ a state parameter . The function must
be called initially with state 0 ( accept ) . State 1 means the string must
be rejected , because the current byte is not allowed . If the string is
completely processed , but the state is non - zero , the string ended
prematurely ; that is , the last byte indicated more bytes should have
followed .
@ param [ in , out ] state the state of the decoding
@ param [ in , out ] codep codepoint ( valid only if resulting state is UTF8_ACCEPT )
@ param [ in ] byte next byte to decode
@ return new state
@ note The function has been edited : a std : : array is used .
@ copyright Copyright ( c ) 2008 - 2009 Bjoern Hoehrmann < bjoern @ hoehrmann . de >
@ sa http : //bjoern.hoehrmann.de/utf-8/decoder/dfa/
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static uint8_t decode ( uint8_t & state , uint32_t & codep , const uint8_t byte ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
static const std : : array < uint8_t , 400 > utf8d =
{
{
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 00..1F
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 20..3F
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 40..5F
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 60..7F
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , // 80..9F
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , // A0..BF
8 , 8 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , // C0..DF
0xA , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x4 , 0x3 , 0x3 , // E0..EF
0xB , 0x6 , 0x6 , 0x6 , 0x5 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , 0x8 , // F0..FF
0x0 , 0x1 , 0x2 , 0x3 , 0x5 , 0x8 , 0x7 , 0x1 , 0x1 , 0x1 , 0x4 , 0x6 , 0x1 , 0x1 , 0x1 , 0x1 , // s0..s0
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , // s1..s2
1 , 2 , 1 , 1 , 1 , 1 , 1 , 2 , 1 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , // s3..s4
1 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 3 , 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , // s5..s6
1 , 3 , 1 , 1 , 1 , 1 , 1 , 3 , 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 // s7..s8
}
} ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
const uint8_t type = utf8d [ byte ] ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
codep = ( state ! = UTF8_ACCEPT )
? ( byte & 0x3fu ) | ( codep < < 6 )
: static_cast < uint32_t > ( 0xff > > type ) & ( byte ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
state = utf8d [ 256u + state * 16u + type ] ;
return state ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
/// the output of the serializer
output_adapter_t < char > o = nullptr ;
/// a (hopefully) large enough character buffer
std : : array < char , 64 > number_buffer { { } } ;
/// the locale
const std : : lconv * loc = nullptr ;
/// the locale's thousand separator character
const char thousands_sep = ' \0 ' ;
/// the locale's decimal point character
const char decimal_point = ' \0 ' ;
/// string buffer
std : : array < char , 512 > string_buffer { { } } ;
/// the indentation character
const char indent_char ;
/// the indentation string
string_t indent_string ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/json_ref.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <initializer_list>
# include <utility>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
namespace detail
{
template < typename BasicJsonType >
class json_ref
{
public :
using value_type = BasicJsonType ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
json_ref ( value_type & & value )
: owned_value ( std : : move ( value ) ) , value_ref ( & owned_value ) , is_rvalue ( true )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
json_ref ( const value_type & value )
: value_ref ( const_cast < value_type * > ( & value ) ) , is_rvalue ( false )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
json_ref ( std : : initializer_list < json_ref > init )
: owned_value ( init ) , value_ref ( & owned_value ) , is_rvalue ( true )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < class . . . Args >
json_ref ( Args & & . . . args )
: owned_value ( std : : forward < Args > ( args ) . . . ) , value_ref ( & owned_value ) , is_rvalue ( true )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// class should be movable only
json_ref ( json_ref & & ) = default ;
json_ref ( const json_ref & ) = delete ;
json_ref & operator = ( const json_ref & ) = delete ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
value_type moved_or_copied ( ) const
{
if ( is_rvalue )
{
return std : : move ( * value_ref ) ;
}
return * value_ref ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
value_type const & operator * ( ) const
{
return * static_cast < value_type const * > ( value_ref ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
value_type const * operator - > ( ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return static_cast < value_type const * > ( value_ref ) ;
2017-07-18 05:37:27 +02:00
}
private :
2018-05-19 21:59:03 +02:00
mutable value_type owned_value = nullptr ;
value_type * value_ref = nullptr ;
const bool is_rvalue ;
} ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/json_pointer.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <cassert> // assert
# include <numeric> // accumulate
# include <string> // string
# include <vector> // vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_scope.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/exceptions.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/value_t.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
template < typename BasicJsonType >
class json_pointer
{
// allow basic_json to access private members
NLOHMANN_BASIC_JSON_TPL_DECLARATION
friend class basic_json ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief create JSON pointer
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Create a JSON pointer according to the syntax described in
[ Section 3 of RFC6901 ] ( https : //tools.ietf.org/html/rfc6901#section-3).
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] s string representing the JSON pointer ; if omitted , the empty
string is assumed which references the whole JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .107 if the given JSON pointer @ a s is nonempty and does
not begin with a slash ( ` / ` ) ; see example below
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .108 if a tilde ( ` ~ ` ) in the given JSON pointer @ a s is
not followed by ` 0 ` ( representing ` ~ ` ) or ` 1 ` ( representing ` / ` ) ; see
example below
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the construction several valid JSON pointers
as well as the exceptional behavior . , json_pointer }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .0
*/
explicit json_pointer ( const std : : string & s = " " )
: reference_tokens ( split ( s ) )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return a string representation of the JSON pointer
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ invariant For each JSON pointer ` ptr ` , it holds :
@ code { . cpp }
ptr = = json_pointer ( ptr . to_string ( ) ) ;
@ endcode
@ return a string representation of the JSON pointer
@ liveexample { The example shows the result of ` to_string ` . ,
json_pointer__to_string }
@ since version 2.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
std : : string to_string ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return std : : accumulate ( reference_tokens . begin ( ) , reference_tokens . end ( ) ,
std : : string { } ,
[ ] ( const std : : string & a , const std : : string & b )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return a + " / " + escape ( b ) ;
} ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @copydoc to_string()
operator std : : string ( ) const
{
return to_string ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ param [ in ] s reference token to be converted into an array index
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return integer representation of @ a s
@ throw out_of_range .404 if string @ a s could not be converted to an integer
*/
static int array_index ( const std : : string & s )
{
std : : size_t processed_chars = 0 ;
const int res = std : : stoi ( s , & processed_chars ) ;
// check if the string was completely read
if ( JSON_UNLIKELY ( processed_chars ! = s . size ( ) ) )
{
JSON_THROW ( detail : : out_of_range : : create ( 404 , " unresolved reference token ' " + s + " ' " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return res ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
private :
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief remove and return last reference pointer
@ throw out_of_range .405 if JSON pointer has no parent
*/
std : : string pop_back ( )
{
if ( JSON_UNLIKELY ( is_root ( ) ) )
{
JSON_THROW ( detail : : out_of_range : : create ( 405 , " JSON pointer has no parent " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
auto last = reference_tokens . back ( ) ;
reference_tokens . pop_back ( ) ;
return last ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// return whether pointer points to the root document
bool is_root ( ) const
{
return reference_tokens . empty ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
json_pointer top ( ) const
{
if ( JSON_UNLIKELY ( is_root ( ) ) )
{
JSON_THROW ( detail : : out_of_range : : create ( 405 , " JSON pointer has no parent " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
json_pointer result = * this ;
result . reference_tokens = { reference_tokens [ 0 ] } ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief create and return a reference to the pointed to value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the number of reference tokens .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .109 if array index is not a number
@ throw type_error .313 if value cannot be unflattened
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
BasicJsonType & get_and_create ( BasicJsonType & j ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
using size_type = typename BasicJsonType : : size_type ;
auto result = & j ;
// in case no reference tokens exist, return a reference to the JSON value
// j which will be overwritten by a primitive value
for ( const auto & reference_token : reference_tokens )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( result - > m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case detail : : value_t : : null :
{
if ( reference_token = = " 0 " )
{
// start a new array if reference token is 0
result = & result - > operator [ ] ( 0 ) ;
}
else
{
// start a new object otherwise
result = & result - > operator [ ] ( reference_token ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case detail : : value_t : : object :
{
// create an entry in the object
result = & result - > operator [ ] ( reference_token ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case detail : : value_t : : array :
{
// create an entry in the array
JSON_TRY
{
result = & result - > operator [ ] ( static_cast < size_type > ( array_index ( reference_token ) ) ) ;
}
JSON_CATCH ( std : : invalid_argument & )
{
JSON_THROW ( detail : : parse_error : : create ( 109 , 0 , " array index ' " + reference_token + " ' is not a number " ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*
The following code is only reached if there exists a reference
token _and_ the current value is primitive . In this case , we have
an error situation , because primitive values may only occur as
single value ; that is , with an empty list of reference tokens .
*/
default :
JSON_THROW ( detail : : type_error : : create ( 313 , " invalid value to unflatten " ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
return * result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return a reference to the pointed to value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This version does not throw if a value is not present , but tries to
create nested values instead . For instance , calling this function
with pointer ` " /this/that " ` on a null value is equivalent to calling
` operator [ ] ( " this " ) . operator [ ] ( " that " ) ` on that value , effectively
changing the null value to an object .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] ptr a JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the JSON value pointed to by the JSON pointer
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the length of the JSON pointer .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .106 if an array index begins with ' 0 '
@ throw parse_error .109 if an array index was not a number
@ throw out_of_range .404 if the JSON pointer can not be resolved
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
BasicJsonType & get_unchecked ( BasicJsonType * ptr ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
using size_type = typename BasicJsonType : : size_type ;
for ( const auto & reference_token : reference_tokens )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// convert null values to arrays or objects before continuing
if ( ptr - > m_type = = detail : : value_t : : null )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// check if reference token is a number
const bool nums =
std : : all_of ( reference_token . begin ( ) , reference_token . end ( ) ,
[ ] ( const char x )
{
return ( x > = ' 0 ' and x < = ' 9 ' ) ;
} ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// change value to array for numbers or "-" or to object otherwise
* ptr = ( nums or reference_token = = " - " )
? detail : : value_t : : array
: detail : : value_t : : object ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
switch ( ptr - > m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case detail : : value_t : : object :
{
// use unchecked object access
ptr = & ptr - > operator [ ] ( reference_token ) ;
break ;
}
case detail : : value_t : : array :
{
// error condition (cf. RFC 6901, Sect. 4)
if ( JSON_UNLIKELY ( reference_token . size ( ) > 1 and reference_token [ 0 ] = = ' 0 ' ) )
{
JSON_THROW ( detail : : parse_error : : create ( 106 , 0 ,
" array index ' " + reference_token +
" ' must not begin with '0' " ) ) ;
}
if ( reference_token = = " - " )
{
// explicitly treat "-" as index beyond the end
ptr = & ptr - > operator [ ] ( ptr - > m_value . array - > size ( ) ) ;
}
else
{
// convert array index to number; unchecked access
JSON_TRY
{
ptr = & ptr - > operator [ ] (
static_cast < size_type > ( array_index ( reference_token ) ) ) ;
}
JSON_CATCH ( std : : invalid_argument & )
{
JSON_THROW ( detail : : parse_error : : create ( 109 , 0 , " array index ' " + reference_token + " ' is not a number " ) ) ;
}
}
break ;
}
default :
JSON_THROW ( detail : : out_of_range : : create ( 404 , " unresolved reference token ' " + reference_token + " ' " ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
return * ptr ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ throw parse_error .106 if an array index begins with ' 0 '
@ throw parse_error .109 if an array index was not a number
@ throw out_of_range .402 if the array index ' - ' is used
@ throw out_of_range .404 if the JSON pointer can not be resolved
*/
BasicJsonType & get_checked ( BasicJsonType * ptr ) const
{
using size_type = typename BasicJsonType : : size_type ;
for ( const auto & reference_token : reference_tokens )
{
switch ( ptr - > m_type )
{
case detail : : value_t : : object :
{
// note: at performs range check
ptr = & ptr - > at ( reference_token ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case detail : : value_t : : array :
{
if ( JSON_UNLIKELY ( reference_token = = " - " ) )
{
// "-" always fails the range check
JSON_THROW ( detail : : out_of_range : : create ( 402 ,
" array index '-' ( " + std : : to_string ( ptr - > m_value . array - > size ( ) ) +
" ) is out of range " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// error condition (cf. RFC 6901, Sect. 4)
if ( JSON_UNLIKELY ( reference_token . size ( ) > 1 and reference_token [ 0 ] = = ' 0 ' ) )
{
JSON_THROW ( detail : : parse_error : : create ( 106 , 0 ,
" array index ' " + reference_token +
" ' must not begin with '0' " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// note: at performs range check
JSON_TRY
{
ptr = & ptr - > at ( static_cast < size_type > ( array_index ( reference_token ) ) ) ;
}
JSON_CATCH ( std : : invalid_argument & )
{
JSON_THROW ( detail : : parse_error : : create ( 109 , 0 , " array index ' " + reference_token + " ' is not a number " ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
JSON_THROW ( detail : : out_of_range : : create ( 404 , " unresolved reference token ' " + reference_token + " ' " ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return * ptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return a const reference to the pointed to value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] ptr a JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return const reference to the JSON value pointed to by the JSON
pointer
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .106 if an array index begins with ' 0 '
@ throw parse_error .109 if an array index was not a number
@ throw out_of_range .402 if the array index ' - ' is used
@ throw out_of_range .404 if the JSON pointer can not be resolved
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
const BasicJsonType & get_unchecked ( const BasicJsonType * ptr ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
using size_type = typename BasicJsonType : : size_type ;
for ( const auto & reference_token : reference_tokens )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( ptr - > m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case detail : : value_t : : object :
{
// use unchecked object access
ptr = & ptr - > operator [ ] ( reference_token ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case detail : : value_t : : array :
{
if ( JSON_UNLIKELY ( reference_token = = " - " ) )
{
// "-" cannot be used for const access
JSON_THROW ( detail : : out_of_range : : create ( 402 ,
" array index '-' ( " + std : : to_string ( ptr - > m_value . array - > size ( ) ) +
" ) is out of range " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// error condition (cf. RFC 6901, Sect. 4)
if ( JSON_UNLIKELY ( reference_token . size ( ) > 1 and reference_token [ 0 ] = = ' 0 ' ) )
{
JSON_THROW ( detail : : parse_error : : create ( 106 , 0 ,
" array index ' " + reference_token +
" ' must not begin with '0' " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// use unchecked array access
JSON_TRY
{
ptr = & ptr - > operator [ ] (
static_cast < size_type > ( array_index ( reference_token ) ) ) ;
}
JSON_CATCH ( std : : invalid_argument & )
{
JSON_THROW ( detail : : parse_error : : create ( 109 , 0 , " array index ' " + reference_token + " ' is not a number " ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
JSON_THROW ( detail : : out_of_range : : create ( 404 , " unresolved reference token ' " + reference_token + " ' " ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
return * ptr ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ throw parse_error .106 if an array index begins with ' 0 '
@ throw parse_error .109 if an array index was not a number
@ throw out_of_range .402 if the array index ' - ' is used
@ throw out_of_range .404 if the JSON pointer can not be resolved
*/
const BasicJsonType & get_checked ( const BasicJsonType * ptr ) const
{
using size_type = typename BasicJsonType : : size_type ;
for ( const auto & reference_token : reference_tokens )
{
switch ( ptr - > m_type )
{
case detail : : value_t : : object :
{
// note: at performs range check
ptr = & ptr - > at ( reference_token ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case detail : : value_t : : array :
{
if ( JSON_UNLIKELY ( reference_token = = " - " ) )
{
// "-" always fails the range check
JSON_THROW ( detail : : out_of_range : : create ( 402 ,
" array index '-' ( " + std : : to_string ( ptr - > m_value . array - > size ( ) ) +
" ) is out of range " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// error condition (cf. RFC 6901, Sect. 4)
if ( JSON_UNLIKELY ( reference_token . size ( ) > 1 and reference_token [ 0 ] = = ' 0 ' ) )
{
JSON_THROW ( detail : : parse_error : : create ( 106 , 0 ,
" array index ' " + reference_token +
" ' must not begin with '0' " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// note: at performs range check
JSON_TRY
{
ptr = & ptr - > at ( static_cast < size_type > ( array_index ( reference_token ) ) ) ;
}
JSON_CATCH ( std : : invalid_argument & )
{
JSON_THROW ( detail : : parse_error : : create ( 109 , 0 , " array index ' " + reference_token + " ' is not a number " ) ) ;
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
JSON_THROW ( detail : : out_of_range : : create ( 404 , " unresolved reference token ' " + reference_token + " ' " ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return * ptr ;
}
/*!
@ brief split the string input to reference tokens
@ note This function is only called by the json_pointer constructor .
All exceptions below are documented there .
@ throw parse_error .107 if the pointer is not empty or begins with ' / '
@ throw parse_error .108 if character ' ~ ' is not followed by ' 0 ' or ' 1 '
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static std : : vector < std : : string > split ( const std : : string & reference_string )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : vector < std : : string > result ;
// special case: empty reference string -> no reference tokens
if ( reference_string . empty ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return result ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// check if nonempty reference string begins with slash
if ( JSON_UNLIKELY ( reference_string [ 0 ] ! = ' / ' ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( detail : : parse_error : : create ( 107 , 1 ,
" JSON pointer must be empty or begin with '/' - was: ' " +
reference_string + " ' " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// extract the reference tokens:
// - slash: position of the last read slash (or end of string)
// - start: position after the previous slash
for (
// search for the first slash after the first character
std : : size_t slash = reference_string . find_first_of ( ' / ' , 1 ) ,
// set the beginning of the first reference token
start = 1 ;
// we can stop if start == string::npos+1 = 0
start ! = 0 ;
// set the beginning of the next reference token
// (will eventually be 0 if slash == std::string::npos)
start = slash + 1 ,
// find next slash
slash = reference_string . find_first_of ( ' / ' , start ) )
{
// use the text between the beginning of the reference token
// (start) and the last slash (slash).
auto reference_token = reference_string . substr ( start , slash - start ) ;
// check reference tokens are properly escaped
for ( std : : size_t pos = reference_token . find_first_of ( ' ~ ' ) ;
pos ! = std : : string : : npos ;
pos = reference_token . find_first_of ( ' ~ ' , pos + 1 ) )
{
assert ( reference_token [ pos ] = = ' ~ ' ) ;
// ~ must be followed by 0 or 1
if ( JSON_UNLIKELY ( pos = = reference_token . size ( ) - 1 or
( reference_token [ pos + 1 ] ! = ' 0 ' and
reference_token [ pos + 1 ] ! = ' 1 ' ) ) )
{
JSON_THROW ( detail : : parse_error : : create ( 108 , 0 , " escape character '~' must be followed with '0' or '1' " ) ) ;
}
}
// finally, store the reference token
unescape ( reference_token ) ;
result . push_back ( reference_token ) ;
}
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief replace all occurrences of a substring by another string
@ param [ in , out ] s the string to manipulate ; changed so that all
occurrences of @ a f are replaced with @ a t
@ param [ in ] f the substring to replace with @ a t
@ param [ in ] t the string to replace @ a f
@ pre The search string @ a f must not be empty . * * This precondition is
enforced with an assertion . * *
@ since version 2.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static void replace_substring ( std : : string & s , const std : : string & f ,
const std : : string & t )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( not f . empty ( ) ) ;
for ( auto pos = s . find ( f ) ; // find first occurrence of f
pos ! = std : : string : : npos ; // make sure f was found
s . replace ( pos , f . size ( ) , t ) , // replace with t, and
pos = s . find ( f , pos + t . size ( ) ) ) // find next occurrence of f
{ }
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// escape "~"" to "~0" and "/" to "~1"
static std : : string escape ( std : : string s )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
replace_substring ( s , " ~ " , " ~0 " ) ;
replace_substring ( s , " / " , " ~1 " ) ;
return s ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// unescape "~1" to tilde and "~0" to slash (order is important!)
static void unescape ( std : : string & s )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
replace_substring ( s , " ~1 " , " / " ) ;
replace_substring ( s , " ~0 " , " ~ " ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ param [ in ] reference_string the reference string to the current value
@ param [ in ] value the value to consider
@ param [ in , out ] result the result object to insert values to
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Empty objects or arrays are flattened to ` null ` .
*/
static void flatten ( const std : : string & reference_string ,
const BasicJsonType & value ,
BasicJsonType & result )
{
switch ( value . m_type )
{
case detail : : value_t : : array :
{
if ( value . m_value . array - > empty ( ) )
{
// flatten empty array as null
result [ reference_string ] = nullptr ;
}
else
{
// iterate array and use index as reference string
for ( std : : size_t i = 0 ; i < value . m_value . array - > size ( ) ; + + i )
{
flatten ( reference_string + " / " + std : : to_string ( i ) ,
value . m_value . array - > operator [ ] ( i ) , result ) ;
}
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case detail : : value_t : : object :
{
if ( value . m_value . object - > empty ( ) )
{
// flatten empty object as null
result [ reference_string ] = nullptr ;
}
else
{
// iterate object and use keys as reference string
for ( const auto & element : * value . m_value . object )
{
flatten ( reference_string + " / " + escape ( element . first ) , element . second , result ) ;
}
}
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
{
// add primitive value with its reference string
result [ reference_string ] = value ;
break ;
}
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ param [ in ] value flattened JSON
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return unflattened JSON
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .109 if array index is not a number
@ throw type_error .314 if value is not an object
@ throw type_error .315 if object values are not primitive
@ throw type_error .313 if value cannot be unflattened
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static BasicJsonType
unflatten ( const BasicJsonType & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not value . is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( detail : : type_error : : create ( 314 , " only objects can be unflattened " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
BasicJsonType result ;
// iterate the JSON object values
for ( const auto & element : * value . m_value . object )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not element . second . is_primitive ( ) ) )
{
JSON_THROW ( detail : : type_error : : create ( 315 , " values in object must be primitive " ) ) ;
}
// assign value to reference pointed to by JSON pointer; Note that if
// the JSON pointer is "" (i.e., points to the whole value), function
// get_and_create returns a reference to result itself. An assignment
// will then create a primitive value.
json_pointer ( element . first ) . get_and_create ( result ) = element . second ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return result ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
friend bool operator = = ( json_pointer const & lhs ,
json_pointer const & rhs ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( lhs . reference_tokens = = rhs . reference_tokens ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
friend bool operator ! = ( json_pointer const & lhs ,
json_pointer const & rhs ) noexcept
{
return not ( lhs = = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the reference tokens
std : : vector < std : : string > reference_tokens ;
} ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/adl_serializer.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# include <utility>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/conversions/from_json.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/conversions/to_json.hpp>
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
namespace nlohmann
{
template < typename , typename >
struct adl_serializer
{
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief convert a JSON value to any value type
This function is usually called by the ` get ( ) ` function of the
@ ref basic_json class ( either explicit or via conversion operators ) .
@ param [ in ] j JSON value to read from
@ param [ in , out ] val value to write to
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename ValueType >
static void from_json ( BasicJsonType & & j , ValueType & val ) noexcept (
noexcept ( : : nlohmann : : from_json ( std : : forward < BasicJsonType > ( j ) , val ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
: : nlohmann : : from_json ( std : : forward < BasicJsonType > ( j ) , val ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief convert any value type to a JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function is usually called by the constructors of the @ ref basic_json
class .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] j JSON value to write to
@ param [ in ] val value to read from
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename BasicJsonType , typename ValueType >
static void to_json ( BasicJsonType & j , ValueType & & val ) noexcept (
noexcept ( : : nlohmann : : to_json ( j , std : : forward < ValueType > ( val ) ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
: : nlohmann : : to_json ( j , std : : forward < ValueType > ( val ) ) ;
}
} ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief namespace for Niels Lohmann
@ see https : //github.com/nlohmann
@ since version 1.0 .0
*/
namespace nlohmann
{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief a class to store JSON values
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ObjectType type for JSON objects ( ` std : : map ` by default ; will be used
in @ ref object_t )
@ tparam ArrayType type for JSON arrays ( ` std : : vector ` by default ; will be used
in @ ref array_t )
@ tparam StringType type for JSON strings and object keys ( ` std : : string ` by
default ; will be used in @ ref string_t )
@ tparam BooleanType type for JSON booleans ( ` bool ` by default ; will be used
in @ ref boolean_t )
@ tparam NumberIntegerType type for JSON integer numbers ( ` 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 ( ` double ` by
default ; will be used in @ ref number_float_t )
@ tparam AllocatorType type of the allocator to use ( ` std : : allocator ` by
default )
@ tparam JSONSerializer the serializer to resolve internal calls to ` to_json ( ) `
and ` from_json ( ) ` ( @ ref adl_serializer by default )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ requirement The class satisfies the following concept requirements :
- Basic
- [ DefaultConstructible ] ( http : //en.cppreference.com/w/cpp/concept/DefaultConstructible):
JSON values can be default constructed . The result will be a JSON null
value .
- [ MoveConstructible ] ( http : //en.cppreference.com/w/cpp/concept/MoveConstructible):
A JSON value can be constructed from an rvalue argument .
- [ CopyConstructible ] ( http : //en.cppreference.com/w/cpp/concept/CopyConstructible):
A JSON value can be copy - constructed from an lvalue expression .
- [ MoveAssignable ] ( http : //en.cppreference.com/w/cpp/concept/MoveAssignable):
A JSON value van be assigned from an rvalue argument .
- [ CopyAssignable ] ( http : //en.cppreference.com/w/cpp/concept/CopyAssignable):
A JSON value can be copy - assigned from an lvalue expression .
- [ Destructible ] ( http : //en.cppreference.com/w/cpp/concept/Destructible):
JSON values can be destructed .
- Layout
- [ StandardLayoutType ] ( http : //en.cppreference.com/w/cpp/concept/StandardLayoutType):
JSON values have
[ standard layout ] ( http : //en.cppreference.com/w/cpp/language/data_members#Standard_layout):
All non - static data members are private and standard layout types , the
class has no virtual functions or ( virtual ) base classes .
- Library - wide
- [ EqualityComparable ] ( http : //en.cppreference.com/w/cpp/concept/EqualityComparable):
JSON values can be compared with ` = = ` , see @ ref
operator = = ( const_reference , const_reference ) .
- [ LessThanComparable ] ( http : //en.cppreference.com/w/cpp/concept/LessThanComparable):
JSON values can be compared with ` < ` , see @ ref
operator < ( const_reference , const_reference ) .
- [ Swappable ] ( http : //en.cppreference.com/w/cpp/concept/Swappable):
Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
other compatible types , using unqualified function call @ ref swap ( ) .
- [ NullablePointer ] ( http : //en.cppreference.com/w/cpp/concept/NullablePointer):
JSON values can be compared against ` std : : nullptr_t ` objects which are used
to model the ` null ` value .
- Container
- [ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container):
JSON values can be used like STL containers and provide iterator access .
- [ ReversibleContainer ] ( http : //en.cppreference.com/w/cpp/concept/ReversibleContainer);
JSON values can be used like STL containers and provide reverse iterator
access .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ invariant The member variables @ a m_value and @ a m_type have the following
relationship :
- If ` m_type = = value_t : : object ` , then ` m_value . object ! = nullptr ` .
- If ` m_type = = value_t : : array ` , then ` m_value . array ! = nullptr ` .
- If ` m_type = = value_t : : string ` , then ` m_value . string ! = nullptr ` .
The invariants are checked by member function assert_invariant ( ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ internal
@ note ObjectType trick from http : //stackoverflow.com/a/9860911
@ endinternal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ see [ RFC 7159 : The JavaScript Object Notation ( JSON ) Data Interchange
Format ] ( http : //rfc7159.net/rfc7159)
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ nosubgrouping
*/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
class basic_json
{
private :
template < detail : : value_t > friend struct detail : : external_constructor ;
friend : : nlohmann : : json_pointer < basic_json > ;
friend : : nlohmann : : detail : : parser < basic_json > ;
friend : : nlohmann : : detail : : serializer < basic_json > ;
template < typename BasicJsonType >
friend class : : nlohmann : : detail : : iter_impl ;
template < typename BasicJsonType , typename CharType >
friend class : : nlohmann : : detail : : binary_writer ;
template < typename BasicJsonType >
friend class : : nlohmann : : detail : : binary_reader ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// workaround type for MSVC
using basic_json_t = NLOHMANN_BASIC_JSON_TPL ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// convenience aliases for types residing in namespace detail;
using lexer = : : nlohmann : : detail : : lexer < basic_json > ;
using parser = : : nlohmann : : detail : : parser < basic_json > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
using primitive_iterator_t = : : nlohmann : : detail : : primitive_iterator_t ;
template < typename BasicJsonType >
using internal_iterator = : : nlohmann : : detail : : internal_iterator < BasicJsonType > ;
template < typename BasicJsonType >
using iter_impl = : : nlohmann : : detail : : iter_impl < BasicJsonType > ;
template < typename Iterator >
using iteration_proxy = : : nlohmann : : detail : : iteration_proxy < Iterator > ;
template < typename Base > using json_reverse_iterator = : : nlohmann : : detail : : json_reverse_iterator < Base > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename CharType >
using output_adapter_t = : : nlohmann : : detail : : output_adapter_t < CharType > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
using binary_reader = : : nlohmann : : detail : : binary_reader < basic_json > ;
template < typename CharType > using binary_writer = : : nlohmann : : detail : : binary_writer < basic_json , CharType > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
using serializer = : : nlohmann : : detail : : serializer < basic_json > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
using value_t = detail : : value_t ;
/// @copydoc nlohmann::json_pointer
using json_pointer = : : nlohmann : : json_pointer < basic_json > ;
template < typename T , typename SFINAE >
using json_serializer = JSONSerializer < T , SFINAE > ;
/// helper type for initializer lists of basic_json values
using initializer_list_t = std : : initializer_list < detail : : json_ref < basic_json > > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
////////////////
// exceptions //
////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name exceptions
/// Classes to implement user-defined exceptions.
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @copydoc detail::exception
using exception = detail : : exception ;
/// @copydoc detail::parse_error
using parse_error = detail : : parse_error ;
/// @copydoc detail::invalid_iterator
using invalid_iterator = detail : : invalid_iterator ;
/// @copydoc detail::type_error
using type_error = detail : : type_error ;
/// @copydoc detail::out_of_range
using out_of_range = detail : : out_of_range ;
/// @copydoc detail::other_error
using other_error = detail : : other_error ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/////////////////////
// container types //
/////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name container types
/// The canonic container types to use @ref basic_json like any other STL
/// container.
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the type of elements in a basic_json container
using value_type = basic_json ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the type of an element reference
using reference = value_type & ;
/// the type of an element const reference
using const_reference = const value_type & ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// a type to represent differences between iterators
using difference_type = std : : ptrdiff_t ;
/// a type to represent container sizes
using size_type = std : : size_t ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the allocator type
using allocator_type = AllocatorType < basic_json > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the type of an element pointer
using pointer = typename std : : allocator_traits < allocator_type > : : pointer ;
/// the type of an element const pointer
using const_pointer = typename std : : allocator_traits < allocator_type > : : const_pointer ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// an iterator for a basic_json container
using iterator = iter_impl < basic_json > ;
/// a const iterator for a basic_json container
using const_iterator = iter_impl < const basic_json > ;
/// a reverse iterator for a basic_json container
using reverse_iterator = json_reverse_iterator < typename basic_json : : iterator > ;
/// a const reverse iterator for a basic_json container
using const_reverse_iterator = json_reverse_iterator < typename basic_json : : const_iterator > ;
/// @}
/*!
@ brief returns the allocator associated with the container
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static allocator_type get_allocator ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return allocator_type ( ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief returns version information on the library
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns a JSON object with information about the library ,
including the version number and information on the platform and compiler .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return JSON object holding version information
key | description
- - - - - - - - - - - | - - - - - - - - - - - - - - -
` compiler ` | Information on the used compiler . It is an object with the following keys : ` c + + ` ( the used C + + standard ) , ` family ` ( the compiler family ; possible values are ` clang ` , ` icc ` , ` gcc ` , ` ilecpp ` , ` msvc ` , ` pgcpp ` , ` sunpro ` , and ` unknown ` ) , and ` version ` ( the compiler version ) .
` copyright ` | The copyright line for the library as string .
` name ` | The name of the library as string .
` platform ` | The used platform as string . Possible values are ` win32 ` , ` linux ` , ` apple ` , ` unix ` , and ` unknown ` .
` url ` | The URL of the project as string .
` version ` | The version of the library . It is an object with the following keys : ` major ` , ` minor ` , and ` patch ` as defined by [ Semantic Versioning ] ( http : //semver.org), and `string` (the version string).
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows an example output of the ` meta ( ) `
function . , meta }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since 2.1 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static basic_json meta ( )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
basic_json result ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
result [ " copyright " ] = " (C) 2013-2017 Niels Lohmann " ;
result [ " name " ] = " JSON for Modern C++ " ;
result [ " url " ] = " https://github.com/nlohmann/json " ;
result [ " version " ] [ " string " ] =
std : : to_string ( NLOHMANN_JSON_VERSION_MAJOR ) + " . " +
std : : to_string ( NLOHMANN_JSON_VERSION_MINOR ) + " . " +
std : : to_string ( NLOHMANN_JSON_VERSION_PATCH ) ;
result [ " version " ] [ " major " ] = NLOHMANN_JSON_VERSION_MAJOR ;
result [ " version " ] [ " minor " ] = NLOHMANN_JSON_VERSION_MINOR ;
result [ " version " ] [ " patch " ] = NLOHMANN_JSON_VERSION_PATCH ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ifdef _WIN32
result [ " platform " ] = " win32 " ;
# elif defined __linux__
result [ " platform " ] = " linux " ;
# elif defined __APPLE__
result [ " platform " ] = " apple " ;
# elif defined __unix__
result [ " platform " ] = " unix " ;
# else
result [ " platform " ] = " unknown " ;
# endif
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# if defined(__ICC) || defined(__INTEL_COMPILER)
result [ " compiler " ] = { { " family " , " icc " } , { " version " , __INTEL_COMPILER } } ;
# elif defined(__clang__)
result [ " compiler " ] = { { " family " , " clang " } , { " version " , __clang_version__ } } ;
# elif defined(__GNUC__) || defined(__GNUG__)
result [ " compiler " ] = { { " family " , " gcc " } , { " version " , std : : to_string ( __GNUC__ ) + " . " + std : : to_string ( __GNUC_MINOR__ ) + " . " + std : : to_string ( __GNUC_PATCHLEVEL__ ) } } ;
# elif defined(__HP_cc) || defined(__HP_aCC)
result [ " compiler " ] = " hp "
# elif defined(__IBMCPP__)
result [ " compiler " ] = { { " family " , " ilecpp " } , { " version " , __IBMCPP__ } } ;
# elif defined(_MSC_VER)
result [ " compiler " ] = { { " family " , " msvc " } , { " version " , _MSC_VER } } ;
# elif defined(__PGI)
result [ " compiler " ] = { { " family " , " pgcpp " } , { " version " , __PGI } } ;
# elif defined(__SUNPRO_CC)
result [ " compiler " ] = { { " family " , " sunpro " } , { " version " , __SUNPRO_CC } } ;
# else
result [ " compiler " ] = { { " family " , " unknown " } , { " version " , " unknown " } } ;
# endif
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ifdef __cplusplus
result [ " compiler " ] [ " c++ " ] = std : : to_string ( __cplusplus ) ;
# else
result [ " compiler " ] [ " c++ " ] = " unknown " ;
# endif
2017-07-18 05:37:27 +02:00
return result ;
}
2018-05-19 21:59:03 +02:00
///////////////////////////
// JSON value data types //
///////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name JSON value data types
/// The data types to store a JSON value. These types are derived from
/// the template arguments passed to class @ref basic_json.
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# if defined(JSON_HAS_CPP_14)
// Use transparent comparator if possible, combined with perfect forwarding
// on find() and count() calls prevents unnecessary string construction.
using object_comparator_t = std : : less < > ;
# else
using object_comparator_t = std : : less < StringType > ;
# endif
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief a type for an object
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) describes JSON objects as follows:
> An object is an unordered collection of zero or more name / value pairs ,
> where a name is a string and a value is a string , number , boolean , null ,
> object , or array .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
To store objects in C + + , a type is defined by the template parameters
described below .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ObjectType the container to store objects ( e . g . , ` std : : map ` or
` std : : unordered_map ` )
@ tparam StringType the type of the keys or names ( e . g . , ` std : : string ` ) .
The comparison function ` std : : less < StringType > ` is used to order elements
inside the container .
@ tparam AllocatorType the allocator to use for objects ( e . g . ,
` std : : allocator ` )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Default type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
With the default values for @ a ObjectType ( ` std : : map ` ) , @ a StringType
( ` std : : string ` ) , and @ a AllocatorType ( ` std : : allocator ` ) , the default
value for @ a object_t is :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ code { . cpp }
std : : map <
std : : string , // key_type
basic_json , // value_type
std : : less < std : : string > , // key_compare
std : : allocator < std : : pair < const std : : string , basic_json > > // allocator_type
>
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Behavior
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The choice of @ a object_t influences the behavior of the JSON class . With
the default type , objects have the following behavior :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
- When all names are unique , objects will be interoperable in the sense
that all software implementations receiving that object will agree on
the name - value mappings .
- When the names within an object are not unique , it is unspecified which
one of the values for a given key will be chosen . For instance ,
` { " key " : 2 , " key " : 1 } ` could be equal to either ` { " key " : 1 } ` or
` { " key " : 2 } ` .
- Internally , name / value pairs are stored in lexicographical order of the
names . Objects will also be serialized ( see @ ref dump ) in this order .
For instance , ` { " b " : 1 , " a " : 2 } ` and ` { " a " : 2 , " b " : 1 } ` will be stored
and serialized as ` { " a " : 2 , " b " : 1 } ` .
- When comparing objects , the order of the name / value pairs is irrelevant .
This makes objects interoperable in the sense that they will not be
affected by these differences . For instance , ` { " b " : 1 , " a " : 2 } ` and
` { " a " : 2 , " b " : 1 } ` will be treated as equal .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Limits
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the maximum depth of nesting .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
In this class , the object ' s limit of nesting is not explicitly constrained .
However , a maximum depth of nesting may be introduced by the compiler or
runtime environment . A theoretical limit can be queried by calling the
@ ref max_size function of a JSON object .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Storage
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Objects are stored as pointers in a @ ref basic_json type . That is , for any
access to object values , a pointer of type ` object_t * ` must be
dereferenced .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref array_t - - type for an array value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The order name / value pairs are added to the object is * not *
preserved by the library . Therefore , iterating an object may return
name / value pairs in a different order than they were originally stored . In
fact , keys will be traversed in alphabetical order as ` std : : map ` with
` std : : less ` is used by default . Please note this behavior conforms to [ RFC
7159 ] ( http : //rfc7159.net/rfc7159), because any order implements the
specified " unordered " nature of JSON objects .
*/
using object_t = ObjectType < StringType ,
basic_json ,
object_comparator_t ,
AllocatorType < std : : pair < const StringType ,
basic_json > > > ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief a type for an array
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) describes JSON arrays as follows:
> An array is an ordered sequence of zero or more values .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
To store objects in C + + , a type is defined by the template parameters
explained below .
@ tparam ArrayType container type to store arrays ( e . g . , ` std : : vector ` or
` std : : list ` )
@ tparam AllocatorType allocator to use for arrays ( e . g . , ` std : : allocator ` )
# ### Default type
With the default values for @ a ArrayType ( ` std : : vector ` ) and @ a
AllocatorType ( ` std : : allocator ` ) , the default value for @ a array_t is :
@ code { . cpp }
std : : vector <
basic_json , // value_type
std : : allocator < basic_json > // allocator_type
>
@ endcode
# ### Limits
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the maximum depth of nesting .
In this class , the array ' s limit of nesting is not explicitly constrained .
However , a maximum depth of nesting may be introduced by the compiler or
runtime environment . A theoretical limit can be queried by calling the
@ ref max_size function of a JSON array .
# ### Storage
Arrays are stored as pointers in a @ ref basic_json type . That is , for any
access to array values , a pointer of type ` array_t * ` must be dereferenced .
@ sa @ ref object_t - - type for an object value
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
using array_t = ArrayType < basic_json , AllocatorType < basic_json > > ;
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief a type for a string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) describes JSON strings as follows:
> A string is a sequence of zero or more Unicode characters .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
To store objects in C + + , a type is defined by the template parameter
described below . Unicode values are split by the JSON class into
byte - sized characters during deserialization .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam StringType the container to store strings ( e . g . , ` std : : string ` ) .
Note this container is used for keys / names in objects , see @ ref object_t .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Default type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
With the default values for @ a StringType ( ` std : : string ` ) , the default
value for @ a string_t is :
@ code { . cpp }
std : : string
@ endcode
# ### Encoding
Strings are stored in UTF - 8 encoding . Therefore , functions like
` std : : string : : size ( ) ` or ` std : : string : : length ( ) ` return the number of
bytes in the string rather than the number of characters or glyphs .
# ### String comparison
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) states:
> Software implementations are typically required to test names of object
> members for equality . Implementations that transform the textual
> representation into sequences of Unicode code units and then perform the
> comparison numerically , code unit by code unit , are interoperable in the
> sense that implementations will agree in all cases on equality or
> inequality of two strings . For example , implementations that compare
> strings with escaped characters unconverted may incorrectly find that
> ` " a \\ b " ` and ` " a \u005C b " ` are not equal .
This implementation is interoperable as it does compare strings code unit
by code unit .
# ### Storage
String values are stored as pointers in a @ ref basic_json type . That is ,
for any access to string values , a pointer of type ` string_t * ` must be
dereferenced .
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
using string_t = StringType ;
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief a type for a boolean
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) implicitly describes a boolean as a
type which differentiates the two literals ` true ` and ` false ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
To store objects in C + + , a type is defined by the template parameter @ a
BooleanType which chooses the type to use .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Default type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
With the default values for @ a BooleanType ( ` bool ` ) , the default value for
@ a boolean_t is :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ code { . cpp }
bool
@ endcode
# ### Storage
Boolean values are stored directly inside a @ ref basic_json type .
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
using boolean_t = BooleanType ;
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief a type for a number ( integer )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ 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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
To store integer numbers in C + + , a type is defined by the template
parameter @ a NumberIntegerType which chooses the type to use .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Default type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
With the default values for @ a NumberIntegerType ( ` int64_t ` ) , the default
value for @ a number_integer_t is :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ code { . cpp }
int64_t
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Default behavior
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
- 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 ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Limits
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) specifies:
> An implementation may set limits on the range and precision of numbers .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
When the default type is used , the maximal integer number that can be
stored is ` 9223372036854775807 ` ( INT64_MAX ) and the minimal integer number
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_unsigned_t or @ ref
number_float_t .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
[ 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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
As this range is a subrange of the exactly supported range [ INT64_MIN ,
INT64_MAX ] , this class ' s integer type is interoperable .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
# ### Storage
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
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_unsigned_t - - type for number values ( unsigned integer )
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
using number_integer_t = NumberIntegerType ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ 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 )
[ 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 floating - point numbers in C + + , a type is defined by the template
parameter @ a NumberFloatType which chooses the type to use .
# ### Default type
With the default values for @ a NumberFloatType ( ` double ` ) , the default
value for @ a number_float_t is :
@ code { . cpp }
double
@ endcode
# ### Default behavior
- The restrictions about leading zeros is not enforced in C + + . Instead ,
leading zeros in floating - point literals will be ignored . Internally ,
the value will be stored as decimal number . For instance , the C + +
floating - point literal ` 01.2 ` will be serialized to ` 1.2 ` . During
deserialization , leading zeros yield an error .
- Not - a - number ( NaN ) values will be serialized to ` null ` .
# ### Limits
[ RFC 7159 ] ( http : //rfc7159.net/rfc7159) states:
> This specification allows implementations to set limits on the range and
> precision of numbers accepted . Since software that implements IEEE
> 754 - 2008 binary64 ( double precision ) numbers is generally available and
> widely used , good interoperability can be achieved by implementations
> that expect no more precision or range than these provide , in the sense
> that implementations will approximate JSON numbers within the expected
> precision .
This implementation does exactly follow this approach , as it uses double
precision floating - point numbers . Note values smaller than
` - 1.79769313486232e+308 ` and values greater than ` 1.79769313486232e+308 `
will be stored as NaN internally and be serialized to ` null ` .
# ### Storage
Floating - point number values are stored directly inside a @ ref basic_json
type .
@ 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 ;
/// @}
private :
/// helper for exception-safe object creation
template < typename T , typename . . . Args >
static T * create ( Args & & . . . args )
{
AllocatorType < T > alloc ;
using AllocatorTraits = std : : allocator_traits < AllocatorType < T > > ;
auto deleter = [ & ] ( T * object )
{
AllocatorTraits : : deallocate ( alloc , object , 1 ) ;
} ;
std : : unique_ptr < T , decltype ( deleter ) > object ( AllocatorTraits : : allocate ( alloc , 1 ) , deleter ) ;
AllocatorTraits : : construct ( alloc , object . get ( ) , std : : forward < Args > ( args ) . . . ) ;
assert ( object ! = nullptr ) ;
return object . release ( ) ;
}
////////////////////////
// JSON value storage //
////////////////////////
/*!
@ brief a JSON value
The actual storage for a JSON value of the @ ref basic_json class . This
union combines the different storage types for the JSON value types
defined in @ ref value_t .
JSON type | value_t type | used type
- - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - -
object | object | pointer to @ ref object_t
array | array | pointer to @ ref array_t
string | string | pointer to @ ref string_t
boolean | boolean | @ ref boolean_t
number | number_integer | @ ref number_integer_t
number | number_unsigned | @ ref number_unsigned_t
number | number_float | @ ref number_float_t
null | null | * no value is stored *
@ note Variable - length types ( objects , arrays , and strings ) are stored as
pointers . The size of the union should not exceed 64 bits if the default
value types are used .
@ since version 1.0 .0
*/
union json_value
{
/// object (stored with pointer to save storage)
object_t * object ;
/// array (stored with pointer to save storage)
array_t * array ;
/// string (stored with pointer to save storage)
string_t * string ;
/// boolean
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 ;
/// default constructor (for null values)
json_value ( ) = default ;
/// constructor for booleans
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
json_value ( value_t t )
{
switch ( t )
{
2017-07-18 05:37:27 +02:00
case value_t : : object :
{
2018-05-19 21:59:03 +02:00
object = create < object_t > ( ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : array :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
array = create < array_t > ( ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
case value_t : : string :
{
2018-05-19 21:59:03 +02:00
string = create < string_t > ( " " ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
case value_t : : boolean :
{
2018-05-19 21:59:03 +02:00
boolean = boolean_t ( false ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
case value_t : : number_integer :
{
2018-05-19 21:59:03 +02:00
number_integer = number_integer_t ( 0 ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
case value_t : : number_unsigned :
{
2018-05-19 21:59:03 +02:00
number_unsigned = number_unsigned_t ( 0 ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
case value_t : : number_float :
{
2018-05-19 21:59:03 +02:00
number_float = number_float_t ( 0.0 ) ;
break ;
}
case value_t : : null :
{
object = nullptr ; // silence warning, see #821
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
2017-07-18 05:37:27 +02:00
default :
{
2018-05-19 21:59:03 +02:00
object = nullptr ; // silence warning, see #821
if ( JSON_UNLIKELY ( t = = value_t : : null ) )
{
JSON_THROW ( other_error : : create ( 500 , " 961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2 " ) ) ; // LCOV_EXCL_LINE
}
break ;
2017-07-18 05:37:27 +02:00
}
}
}
2018-05-19 21:59:03 +02:00
/// constructor for strings
json_value ( const string_t & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
string = create < string_t > ( value ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// constructor for rvalue strings
json_value ( string_t & & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
string = create < string_t > ( std : : move ( value ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// constructor for objects
json_value ( const object_t & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
object = create < object_t > ( value ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// constructor for rvalue objects
json_value ( object_t & & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
object = create < object_t > ( std : : move ( value ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// constructor for arrays
json_value ( const array_t & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
array = create < array_t > ( value ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/// constructor for rvalue arrays
json_value ( array_t & & value )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
array = create < array_t > ( std : : move ( value ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
void destroy ( value_t t ) noexcept
{
switch ( t )
{
case value_t : : object :
{
AllocatorType < object_t > alloc ;
std : : allocator_traits < decltype ( alloc ) > : : destroy ( alloc , object ) ;
std : : allocator_traits < decltype ( alloc ) > : : deallocate ( alloc , object , 1 ) ;
break ;
}
case value_t : : array :
{
AllocatorType < array_t > alloc ;
std : : allocator_traits < decltype ( alloc ) > : : destroy ( alloc , array ) ;
std : : allocator_traits < decltype ( alloc ) > : : deallocate ( alloc , array , 1 ) ;
break ;
}
case value_t : : string :
{
AllocatorType < string_t > alloc ;
std : : allocator_traits < decltype ( alloc ) > : : destroy ( alloc , string ) ;
std : : allocator_traits < decltype ( alloc ) > : : deallocate ( alloc , string , 1 ) ;
break ;
}
default :
{
break ;
}
}
}
} ;
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief checks the class invariants
This function asserts the class invariants . It needs to be called at the
end of every constructor to make sure that created objects respect the
invariant . Furthermore , it has to be called each time the type of a JSON
value is changed , because the invariant expresses a relationship between
@ a m_type and @ a m_value .
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void assert_invariant ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert ( m_type ! = value_t : : object or m_value . object ! = nullptr ) ;
assert ( m_type ! = value_t : : array or m_value . array ! = nullptr ) ;
assert ( m_type ! = value_t : : string or m_value . string ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
public :
//////////////////////////
// JSON parser callback //
//////////////////////////
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief parser event types
The parser callback distinguishes the following events :
- ` object_start ` : the parser read ` { ` and started to process a JSON object
- ` key ` : the parser read a key of a value in an object
- ` object_end ` : the parser read ` } ` and finished processing a JSON object
- ` array_start ` : the parser read ` [ ` and started to process a JSON array
- ` array_end ` : the parser read ` ] ` and finished processing a JSON array
- ` value ` : the parser finished reading a JSON value
@ image html callback_events . png " Example when certain parse events are triggered "
@ sa @ ref parser_callback_t for more information and examples
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
using parse_event_t = typename parser : : parse_event_t ;
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief per - element parser callback type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
With a parser callback function , the result of parsing a JSON text can be
influenced . When passed to @ ref parse , it is called on certain events
( passed as @ ref parse_event_t via parameter @ a event ) with a set recursion
depth @ a depth and context JSON value @ a parsed . The return value of the
callback function is a boolean indicating whether the element that emitted
the callback shall be kept or not .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
We distinguish six scenarios ( determined by the event type ) in which the
callback function can be called . The following table describes the values
of the parameters @ a depth , @ a event , and @ a parsed .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
parameter @ a event | description | parameter @ a depth | parameter @ a parsed
- - - - - - - - - - - - - - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - -
parse_event_t : : object_start | the parser read ` { ` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
parse_event_t : : key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
parse_event_t : : object_end | the parser read ` } ` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
parse_event_t : : array_start | the parser read ` [ ` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
parse_event_t : : array_end | the parser read ` ] ` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
parse_event_t : : value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ image html callback_events . png " Example when certain parse events are triggered "
Discarding a value ( i . e . , returning ` false ` ) has different effects
depending on the context in which function was called :
- Discarded values in structured types are skipped . That is , the parser
will behave as if the discarded value was never read .
- In case a value outside a structured type is skipped , it is replaced
with ` null ` . This case happens if the top - level element is skipped .
@ param [ in ] depth the depth of the recursion during parsing
@ param [ in ] event an event of type parse_event_t indicating the context in
the callback function has been called
@ param [ in , out ] parsed the current intermediate parse result ; note that
writing to this value has no effect for parse_event_t : : key events
@ return Whether the JSON value which called the function during parsing
should be kept ( ` true ` ) or not ( ` false ` ) . In the latter case , it is either
skipped completely or replaced by an empty discarded object .
@ sa @ ref parse for examples
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
using parser_callback_t = typename parser : : parser_callback_t ;
//////////////////
// constructors //
//////////////////
/// @name constructors and destructors
/// Constructors of class @ref basic_json, copy/move constructor, copy
/// assignment, static functions creating objects, and the destructor.
/// @{
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief create an empty value with a given type
Create an empty JSON value with a given type . The value will be default
initialized with an empty value which depends on the type :
Value type | initial value
- - - - - - - - - - - | - - - - - - - - - - - - -
null | ` null `
boolean | ` false `
string | ` " " `
number | ` 0 `
object | ` { } `
array | ` [ ] `
@ param [ in ] v the type of the value to create
@ complexity Constant .
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
@ liveexample { The following code shows the constructor for different @ ref
value_t values , basic_json__value_t }
@ sa @ ref clear ( ) - - restores the postcondition of this constructor
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
basic_json ( const value_t v )
: m_type ( v ) , m_value ( v )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief create a null object
Create a ` null ` JSON value . It either takes a null pointer as parameter
( explicitly creating ` null ` ) or no parameter ( implicitly creating ` null ` ) .
The passed null pointer itself is not read - - it is only used to choose
the right constructor .
@ complexity Constant .
@ exceptionsafety No - throw guarantee : this constructor never throws
exceptions .
@ liveexample { The following code shows the constructor with and without a
null pointer parameter . , basic_json__nullptr_t }
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
basic_json ( std : : nullptr_t = nullptr ) noexcept
: basic_json ( value_t : : null )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief create a JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This is a " catch all " constructor for all compatible JSON types ; that is ,
types for which a ` to_json ( ) ` method exists . The constructor forwards the
parameter @ a val to that method ( to ` json_serializer < U > : : to_json ` method
with ` U = uncvref_t < CompatibleType > ` , to be exact ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Template type @ a CompatibleType includes , but is not limited to , the
following types :
- * * arrays * * : @ ref array_t and all kinds of compatible containers such as
` std : : vector ` , ` std : : deque ` , ` std : : list ` , ` std : : forward_list ` ,
` std : : array ` , ` std : : valarray ` , ` std : : set ` , ` std : : unordered_set ` ,
` std : : multiset ` , and ` std : : unordered_multiset ` with a ` value_type ` from
which a @ ref basic_json value can be constructed .
- * * objects * * : @ ref object_t and all kinds of compatible associative
containers such as ` std : : map ` , ` std : : unordered_map ` , ` std : : multimap ` ,
and ` std : : unordered_multimap ` with a ` key_type ` compatible to
@ ref string_t and a ` value_type ` from which a @ ref basic_json value can
be constructed .
- * * strings * * : @ ref string_t , string literals , and all compatible string
containers can be used .
- * * numbers * * : @ ref number_integer_t , @ ref number_unsigned_t ,
@ ref number_float_t , and all convertible number types such as ` int ` ,
` size_t ` , ` int64_t ` , ` float ` or ` double ` can be used .
- * * boolean * * : @ ref boolean_t / ` bool ` can be used .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
See the examples below .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam CompatibleType a type such that :
- @ a CompatibleType is not derived from ` std : : istream ` ,
- @ a CompatibleType is not @ ref basic_json ( to avoid hijacking copy / move
constructors ) ,
- @ a CompatibleType is not a different @ ref basic_json type ( i . e . with different template arguments )
- @ a CompatibleType is not a @ ref basic_json nested type ( e . g . ,
@ ref json_pointer , @ ref iterator , etc . . . )
- @ ref @ ref json_serializer < U > has a
` to_json ( basic_json_t & , CompatibleType & & ) ` method
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam U = ` uncvref_t < CompatibleType > `
@ param [ in ] val the value to be forwarded to the respective constructor
@ 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 .
@ liveexample { The following code shows the constructor with several
compatible types . , basic_json__CompatibleType }
@ since version 2.1 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename CompatibleType ,
typename U = detail : : uncvref_t < CompatibleType > ,
detail : : enable_if_t <
detail : : is_compatible_type < basic_json_t , U > : : value , int > = 0 >
basic_json ( CompatibleType & & val ) noexcept ( noexcept (
JSONSerializer < U > : : to_json ( std : : declval < basic_json_t & > ( ) ,
std : : forward < CompatibleType > ( val ) ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSONSerializer < U > : : to_json ( * this , std : : forward < CompatibleType > ( val ) ) ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief create a JSON value from an existing one
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The constructor tries to convert the internal @ ref m_value of the parameter .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] val the @ ref basic_json value to be converted .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Usually linear in the size of the passed @ a val , also
depending on the implementation of the called ` to_json ( ) `
method .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 3.1 .2
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
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 )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
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 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
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 ( ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief create a container ( array or object ) from an initializer list
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Creates a JSON value of type array or object from the passed initializer
list @ a init . In case @ a type_deduction is ` true ` ( default ) , the type of
the JSON value to be created is deducted from the initializer list @ a init
according to the following rules :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
1. If the list is empty , an empty JSON object value ` { } ` is created .
2. If the list consists of pairs whose first element is a string , a JSON
object value is created where the first elements of the pairs are
treated as keys and the second elements are as values .
3. In all other cases , an array is created .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The rules aim to create the best fit between a C + + initializer list and
JSON values . The rationale is as follows :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
1. The empty initializer list is written as ` { } ` which is exactly an empty
JSON object .
2. C + + has no way of describing mapped types other than to list a list of
pairs . As JSON requires that keys must be of type string , rule 2 is the
weakest constraint one can pose on initializer lists to interpret them
as an object .
3. In all other cases , the initializer list could not be interpreted as
JSON object type , so interpreting it as JSON array type is safe .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
With the rules described above , the following JSON values cannot be
expressed by an initializer list :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
- the empty array ( ` [ ] ` ) : use @ ref array ( initializer_list_t )
with an empty initializer list in this case
- arrays whose elements satisfy rule 2 : use @ ref
array ( initializer_list_t ) with the same initializer list
in this case
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note When used without parentheses around an empty initializer list , @ ref
basic_json ( ) is called instead of this function , yielding the JSON null
value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] init initializer list with JSON values
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] type_deduction internal parameter ; when set to ` true ` , the type
of the JSON value is deducted from the initializer list @ a init ; when set
to ` false ` , the type provided via @ a manual_type is forced . This mode is
used by the functions @ ref array ( initializer_list_t ) and
@ ref object ( initializer_list_t ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] manual_type internal parameter ; when @ a type_deduction is set
to ` false ` , the created JSON value will use the provided type ( only @ ref
value_t : : array and @ ref value_t : : object are valid ) ; when @ a type_deduction
is set to ` true ` , this parameter has no effect
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .301 if @ a type_deduction is ` false ` , @ a manual_type is
` value_t : : object ` , but @ a init contains an element which is not a pair
whose first element is a string . In this case , the constructor could not
create an object . If @ a type_deduction would have be ` true ` , an array
would have been created . See @ ref object ( initializer_list_t )
for an example .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the initializer list @ a init .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
@ liveexample { The example below shows how JSON values are created from
initializer lists . , basic_json__list_init_t }
@ sa @ ref array ( initializer_list_t ) - - create a JSON array
value from an initializer list
@ sa @ ref object ( initializer_list_t ) - - create a JSON object
value from an initializer list
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
basic_json ( initializer_list_t init ,
bool type_deduction = true ,
value_t manual_type = value_t : : array )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// check if each element is an array with two elements whose first
// element is a string
bool is_an_object = std : : all_of ( init . begin ( ) , init . end ( ) ,
[ ] ( const detail : : json_ref < basic_json > & element_ref )
{
return ( element_ref - > is_array ( ) and element_ref - > size ( ) = = 2 and ( * element_ref ) [ 0 ] . is_string ( ) ) ;
} ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// adjust type if type deduction is not wanted
if ( not type_deduction )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// if array is wanted, do not create an object though possible
if ( manual_type = = value_t : : array )
{
is_an_object = false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// if object is wanted but impossible, throw an exception
if ( JSON_UNLIKELY ( manual_type = = value_t : : object and not is_an_object ) )
{
JSON_THROW ( type_error : : create ( 301 , " cannot create object from initializer list " ) ) ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( is_an_object )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// the initializer list is a list of pairs -> create object
m_type = value_t : : object ;
m_value = value_t : : object ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
std : : for_each ( init . begin ( ) , init . end ( ) , [ this ] ( const detail : : json_ref < basic_json > & element_ref )
{
auto element = element_ref . moved_or_copied ( ) ;
m_value . object - > emplace (
std : : move ( * ( ( * element . m_value . array ) [ 0 ] . m_value . string ) ) ,
std : : move ( ( * element . m_value . array ) [ 1 ] ) ) ;
} ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// the initializer list describes an array -> create array
m_type = value_t : : array ;
m_value . array = create < array_t > ( init . begin ( ) , init . end ( ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief explicitly create an array from an initializer list
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Creates a JSON array value from a given initializer list . That is , given a
list of values ` a , b , c ` , creates the JSON value ` [ a , b , c ] ` . If the
initializer list is empty , the empty array ` [ ] ` is created .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This function is only needed to express two edge cases that cannot
be realized with the initializer list constructor ( @ ref
basic_json ( initializer_list_t , bool , value_t ) ) . These cases
are :
1. creating an array whose elements are all pairs whose first element is a
string - - in this case , the initializer list constructor would create an
object , taking the first elements as keys
2. creating an empty array - - passing the empty initializer list to the
initializer list constructor yields an empty object
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] init initializer list with JSON values to create an array from
( optional )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return JSON array value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of @ a init .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows an example for the ` array `
function . , array }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref basic_json ( initializer_list_t , bool , value_t ) - -
create a JSON value from an initializer list
@ sa @ ref object ( initializer_list_t ) - - create a JSON object
value from an initializer list
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
static basic_json array ( initializer_list_t init = { } )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return basic_json ( init , false , value_t : : array ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief explicitly create an object from an initializer list
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Creates a JSON object value from a given initializer list . The initializer
lists elements must be pairs , and their first elements must be strings . If
the initializer list is empty , the empty object ` { } ` is created .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This function is only added for symmetry reasons . In contrast to the
related function @ ref array ( initializer_list_t ) , there are
no cases which can only be expressed by this function . That is , any
initializer list @ a init can also be passed to the initializer list
constructor @ ref basic_json ( initializer_list_t , bool , value_t ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] init initializer list to create an object from ( optional )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return JSON object value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .301 if @ a init is not a list of pairs whose first
elements are strings . In this case , no object can be created . When such a
value is passed to @ ref basic_json ( initializer_list_t , bool , value_t ) ,
an array would have been created from the passed initializer list @ a init .
See example below .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of @ a init .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows an example for the ` object `
function . , object }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref basic_json ( initializer_list_t , bool , value_t ) - -
create a JSON value from an initializer list
@ sa @ ref array ( initializer_list_t ) - - create a JSON array
value from an initializer list
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
static basic_json object ( initializer_list_t init = { } )
{
return basic_json ( init , false , value_t : : object ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief construct an array with count copies of given value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Constructs a JSON array value by creating @ a cnt copies of a passed value .
In case @ a cnt is ` 0 ` , an empty array is created .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] cnt the number of JSON copies of @ a val to create
@ param [ in ] val the JSON value to copy
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ post ` std : : distance ( begin ( ) , end ( ) ) = = cnt ` holds .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in @ a cnt .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows examples for the @ ref
basic_json ( size_type \ , const basic_json & )
constructor . , basic_json__size_type_basic_json }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
basic_json ( size_type cnt , const basic_json & val )
: m_type ( value_t : : array )
{
m_value . array = create < array_t > ( cnt , val ) ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief construct a JSON container given an iterator range
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Constructs the JSON value with the contents of the range ` [ first , last ) ` .
The semantics depends on the different types a JSON value can have :
- In case of a null type , invalid_iterator .206 is thrown .
- In case of other primitive types ( number , boolean , or string ) , @ a first
must be ` begin ( ) ` and @ a last must be ` end ( ) ` . In this case , the value is
copied . Otherwise , invalid_iterator .204 is thrown .
- In case of structured types ( array , object ) , the constructor behaves as
similar versions for ` std : : vector ` or ` std : : map ` ; that is , a JSON array
or object is constructed from the values in the range .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam InputIT an input iterator type ( @ ref iterator or @ ref
const_iterator )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] first begin of the range to copy from ( included )
@ param [ in ] last end of the range to copy from ( excluded )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre Iterators @ a first and @ a last must be initialized . * * This
precondition is enforced with an assertion ( see warning ) . * * If
assertions are switched off , a violation of this precondition yields
undefined behavior .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre Range ` [ first , last ) ` is valid . Usually , this precondition cannot be
checked efficiently . Only certain edge cases are detected ; see the
description of the exceptions below . A violation of this precondition
yields undefined behavior .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning A precondition is enforced with a runtime assertion that will
result in calling ` std : : abort ` if this precondition is not met .
Assertions can be disabled by defining ` NDEBUG ` at compile time .
See http : //en.cppreference.com/w/cpp/error/assert for more
information .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw invalid_iterator .201 if iterators @ a first and @ a last are not
compatible ( i . e . , do not belong to the same JSON value ) . In this case ,
the range ` [ first , last ) ` is undefined .
@ throw invalid_iterator .204 if iterators @ a first and @ a last belong to a
primitive type ( number , boolean , or string ) , but @ a first does not point
to the first element any more . In this case , the range ` [ first , last ) ` is
undefined . See example code below .
@ throw invalid_iterator .206 if iterators @ a first and @ a last belong to a
null value . In this case , the range ` [ first , last ) ` is undefined .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in distance between @ a first and @ a last .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows several ways to create JSON values by
specifying a subrange with iterators . , basic_json__InputIt_InputIt }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < class InputIT , typename std : : enable_if <
std : : is_same < InputIT , typename basic_json_t : : iterator > : : value or
std : : is_same < InputIT , typename basic_json_t : : const_iterator > : : value , int > : : type = 0 >
basic_json ( InputIT first , InputIT last )
{
assert ( first . m_object ! = nullptr ) ;
assert ( last . m_object ! = nullptr ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// make sure iterator fits the current value
if ( JSON_UNLIKELY ( first . m_object ! = last . m_object ) )
{
JSON_THROW ( invalid_iterator : : create ( 201 , " iterators are not compatible " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// copy type from first iterator
m_type = first . m_object - > m_type ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if iterator range is complete for primitive values
switch ( m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
case value_t : : number_float :
case value_t : : number_integer :
case value_t : : number_unsigned :
case value_t : : string :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not first . m_it . primitive_iterator . is_begin ( )
or not last . m_it . primitive_iterator . is_end ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 204 , " iterators out of range " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value . number_integer = first . m_object - > m_value . number_integer ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value . number_unsigned = first . m_object - > m_value . number_unsigned ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_float :
{
m_value . number_float = first . m_object - > m_value . number_float ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
{
m_value . boolean = first . m_object - > m_value . boolean ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
{
m_value = * first . m_object - > m_value . string ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
{
m_value . object = create < object_t > ( first . m_it . object_iterator ,
last . m_it . object_iterator ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
m_value . array = create < array_t > ( first . m_it . array_iterator ,
last . m_it . array_iterator ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
JSON_THROW ( invalid_iterator : : create ( 206 , " cannot construct with iterators from " +
std : : string ( first . m_object - > type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
///////////////////////////////////////
// other constructors and destructor //
///////////////////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @private
basic_json ( const detail : : json_ref < basic_json > & ref )
: basic_json ( ref . moved_or_copied ( ) )
{ }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief copy constructor
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Creates a copy of a given JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] other the JSON value to copy
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ post ` * this = = other `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of @ a other .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes to any JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is linear .
- As postcondition , it holds : ` other = = basic_json ( other ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows an example for the copy
constructor . , basic_json__basic_json }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
basic_json ( const basic_json & other )
: m_type ( other . m_type )
{
// check of passed value is valid
other . assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : object :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value = * other . m_value . object ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : array :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value = * other . m_value . array ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : string :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value = * other . m_value . string ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value = other . m_value . boolean ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value = other . m_value . number_integer ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
m_value = other . m_value . number_unsigned ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : number_float :
{
m_value = other . m_value . number_float ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief move constructor
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Move constructor . Constructs a JSON value with the contents of the given
value @ a other using move semantics . It " steals " the resources from @ a
other and leaves it as JSON null value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] other value to move to this object
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ post ` * this ` has the same value as @ a other before the call .
@ post @ a other is a JSON null value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this constructor never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ requirement This function helps ` basic_json ` satisfying the
[ MoveConstructible ] ( http : //en.cppreference.com/w/cpp/concept/MoveConstructible)
requirements .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The code below shows the move constructor explicitly called
via std : : move . , basic_json__moveconstructor }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
basic_json ( basic_json & & other ) noexcept
: m_type ( std : : move ( other . m_type ) ) ,
m_value ( std : : move ( other . m_value ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// check that passed value is valid
other . assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// invalidate payload
other . m_type = value_t : : null ;
other . m_value = { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief copy assignment
Copy assignment operator . Copies a JSON value via the " copy and swap "
strategy : It is expressed in terms of the copy constructor , destructor ,
and the ` swap ( ) ` member function .
@ param [ in ] other value to copy from
@ complexity Linear .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is linear .
@ liveexample { The code below shows and example for the copy assignment . It
creates a copy of value ` a ` which is then swapped with ` b ` . Finally \ , the
copy of ` a ` ( which is the null value after the swap ) is
destroyed . , basic_json__copyassignment }
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
reference & operator = ( basic_json other ) noexcept (
std : : is_nothrow_move_constructible < value_t > : : value and
std : : is_nothrow_move_assignable < value_t > : : value and
std : : is_nothrow_move_constructible < json_value > : : value and
std : : is_nothrow_move_assignable < json_value > : : value
)
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// check that passed value is valid
other . assert_invariant ( ) ;
using std : : swap ;
swap ( m_type , other . m_type ) ;
swap ( m_value , other . m_value ) ;
assert_invariant ( ) ;
return * this ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief destructor
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Destroys the JSON value and frees all allocated memory .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is linear .
- All stored elements are destroyed and all memory is freed .
@ since version 1.0 .0
*/
~ basic_json ( ) noexcept
{
assert_invariant ( ) ;
m_value . destroy ( m_type ) ;
}
/// @}
public :
///////////////////////
// object inspection //
///////////////////////
/// @name object inspection
/// Functions to inspect the type of a JSON value.
2017-07-18 05:37:27 +02:00
/// @{
/*!
2018-05-19 21:59:03 +02:00
@ brief serialization
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Serialization function for JSON values . The function tries to mimic
Python ' s ` json . dumps ( ) ` function , and currently supports its @ a indent
and @ a ensure_ascii parameters .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] indent If indent is nonnegative , then array elements and object
members will be pretty - printed with that indent level . An indent level of
` 0 ` will only insert newlines . ` - 1 ` ( the default ) selects the most compact
representation .
@ param [ in ] indent_char The character to use for indentation if @ a indent is
greater than ` 0 ` . The default is ` ` ( space ) .
@ param [ in ] ensure_ascii If @ a ensure_ascii is true , all non - ASCII characters
in the output are escaped with ` \ uXXXX ` sequences , and the result consists
of ASCII characters only .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return string containing the serialization of the JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .316 if a string stored inside the JSON value is not
UTF - 8 encoded
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following example shows the effect of different @ a indent \ ,
@ a indent_char \ , and @ a ensure_ascii parameters to the result of the
serialization . , dump }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ see https : //docs.python.org/2/library/json.html#json.dump
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0 ; indentation character @ a indent_char , option
@ a ensure_ascii and exceptions added in version 3.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
string_t dump ( const int indent = - 1 , const char indent_char = ' ' ,
const bool ensure_ascii = false ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
string_t result ;
serializer s ( detail : : output_adapter < char , string_t > ( result ) , indent_char ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( indent > = 0 )
{
s . dump ( * this , true , ensure_ascii , static_cast < unsigned int > ( indent ) ) ;
}
else
{
s . dump ( * this , false , ensure_ascii , 0 ) ;
}
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return the type of the JSON value ( explicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Return the type of the JSON value as a value from the @ ref value_t
enumeration .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return the type of the JSON value
Value type | return value
- - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - -
null | value_t : : null
boolean | value_t : : boolean
string | value_t : : string
number ( integer ) | value_t : : number_integer
number ( unsigned integer ) | value_t : : number_unsigned
number ( floating - point ) | value_t : : number_float
object | value_t : : object
array | value_t : : array
discarded | value_t : : discarded
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` type ( ) ` for all JSON
types . , type }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref operator value_t ( ) - - return the type of the JSON value ( implicit )
@ sa @ ref type_name ( ) - - return the type as string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr value_t type ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m_type ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return whether type is primitive
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON type is primitive
( string , number , boolean , or null ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is primitive ( string , number , boolean , or null ) ,
` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_primitive ( ) ` for all JSON
types . , is_primitive }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref is_structured ( ) - - returns whether JSON value is structured
@ sa @ ref is_null ( ) - - returns whether JSON value is ` null `
@ sa @ ref is_string ( ) - - returns whether JSON value is a string
@ sa @ ref is_boolean ( ) - - returns whether JSON value is a boolean
@ sa @ ref is_number ( ) - - returns whether JSON value is a number
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_primitive ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return is_null ( ) or is_string ( ) or is_boolean ( ) or is_number ( ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return whether type is structured
This function returns true if and only if the JSON type is structured
( array or object ) .
@ return ` true ` if type is structured ( array or object ) , ` false ` otherwise .
@ complexity Constant .
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
@ liveexample { The following code exemplifies ` is_structured ( ) ` for all JSON
types . , is_structured }
@ sa @ ref is_primitive ( ) - - returns whether value is primitive
@ sa @ ref is_array ( ) - - returns whether value is an array
@ sa @ ref is_object ( ) - - returns whether value is an object
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_structured ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return is_array ( ) or is_object ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief return whether value is null
This function returns true if and only if the JSON value is null .
@ return ` true ` if type is null , ` false ` otherwise .
@ complexity Constant .
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
@ liveexample { The following code exemplifies ` is_null ( ) ` for all JSON
types . , is_null }
@ since version 1.0 .0
*/
constexpr bool is_null ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( m_type = = value_t : : null ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return whether value is a boolean
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is a boolean .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is boolean , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_boolean ( ) ` for all JSON
types . , is_boolean }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
constexpr bool is_boolean ( ) const noexcept
{
return ( m_type = = value_t : : boolean ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return whether value is a number
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is a number . This
includes both integer ( signed and unsigned ) and floating - point values .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is number ( regardless whether integer , unsigned
integer or floating - type ) , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_number ( ) ` for all JSON
types . , is_number }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
constexpr bool is_number ( ) const noexcept
{
return is_number_integer ( ) or is_number_float ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return whether value is an integer number
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is a signed or
unsigned integer number . This excludes floating - point values .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is an integer or unsigned integer number , ` false `
otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_number_integer ( ) ` for all
JSON types . , is_number_integer }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_number_integer ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( m_type = = value_t : : number_integer or m_type = = value_t : : number_unsigned ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return whether value is an unsigned integer number
This function returns true if and only if 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 .
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
@ liveexample { The following code exemplifies ` is_number_unsigned ( ) ` for all
JSON types . , is_number_unsigned }
@ 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
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_number_unsigned ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( m_type = = value_t : : number_unsigned ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return whether value is a floating - point number
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is a
floating - point number . This excludes signed and unsigned integer values .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is a floating - point number , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_number_float ( ) ` for all
JSON types . , is_number_float }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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
2017-07-18 05:37:27 +02:00
@ since version 1.0 .0
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_number_float ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( m_type = = value_t : : number_float ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief return whether value is an object
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is an object .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is object , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
@ complexity Constant .
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_object ( ) ` for all JSON
types . , is_object }
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_object ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( m_type = = value_t : : object ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
/*!
@ brief return whether value is an array
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is an array .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is array , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_array ( ) ` for all JSON
types . , is_array }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr bool is_array ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return ( m_type = = value_t : : array ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return whether value is a string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value is a string .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is string , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_string ( ) ` for all JSON
types . , is_string }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
constexpr bool is_string ( ) const noexcept
{
return ( m_type = = value_t : : string ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return whether value is discarded
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function returns true if and only if the JSON value was discarded
during parsing with a callback function ( see @ ref parser_callback_t ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This function will always be ` false ` for JSON values after parsing .
That is , discarded values can only occur during parsing , but will be
removed when inside a structured value or replaced by null in other cases .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return ` true ` if type is discarded , ` false ` otherwise .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` is_discarded ( ) ` for all JSON
types . , is_discarded }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
constexpr bool is_discarded ( ) const noexcept
{
return ( m_type = = value_t : : discarded ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return the type of the JSON value ( implicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Implicitly return the type of the JSON value as a value from the @ ref
value_t enumeration .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return the type of the JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this member function never throws
exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies the @ ref value_t operator for
all JSON types . , operator__value_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref type ( ) - - return the type of the JSON value ( explicit )
@ sa @ ref type_name ( ) - - return the type as string
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
constexpr operator value_t ( ) const noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m_type ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
private :
//////////////////
// value access //
//////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a boolean (explicit)
boolean_t get_impl ( boolean_t * /*unused*/ ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_LIKELY ( is_boolean ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m_value . boolean ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 302 , " type must be boolean, but is " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (object)
object_t * get_impl_ptr ( object_t * /*unused*/ ) noexcept
{
return is_object ( ) ? m_value . object : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (object)
constexpr const object_t * get_impl_ptr ( const object_t * /*unused*/ ) const noexcept
{
return is_object ( ) ? m_value . object : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (array)
array_t * get_impl_ptr ( array_t * /*unused*/ ) noexcept
{
return is_array ( ) ? m_value . array : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (array)
constexpr const array_t * get_impl_ptr ( const array_t * /*unused*/ ) const noexcept
{
return is_array ( ) ? m_value . array : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (string)
string_t * get_impl_ptr ( string_t * /*unused*/ ) noexcept
{
return is_string ( ) ? m_value . string : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (string)
constexpr const string_t * get_impl_ptr ( const string_t * /*unused*/ ) const noexcept
{
return is_string ( ) ? m_value . string : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (boolean)
boolean_t * get_impl_ptr ( boolean_t * /*unused*/ ) noexcept
{
return is_boolean ( ) ? & m_value . boolean : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (boolean)
constexpr const boolean_t * get_impl_ptr ( const boolean_t * /*unused*/ ) const noexcept
{
return is_boolean ( ) ? & m_value . boolean : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (integer number)
number_integer_t * get_impl_ptr ( number_integer_t * /*unused*/ ) noexcept
{
return is_number_integer ( ) ? & m_value . number_integer : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (integer number)
constexpr const number_integer_t * get_impl_ptr ( const number_integer_t * /*unused*/ ) const noexcept
{
return is_number_integer ( ) ? & m_value . number_integer : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (unsigned number)
number_unsigned_t * get_impl_ptr ( number_unsigned_t * /*unused*/ ) noexcept
{
return is_number_unsigned ( ) ? & m_value . number_unsigned : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (unsigned number)
constexpr const number_unsigned_t * get_impl_ptr ( const number_unsigned_t * /*unused*/ ) const noexcept
{
return is_number_unsigned ( ) ? & m_value . number_unsigned : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (floating-point number)
number_float_t * get_impl_ptr ( number_float_t * /*unused*/ ) noexcept
{
return is_number_float ( ) ? & m_value . number_float : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// get a pointer to the value (floating-point number)
constexpr const number_float_t * get_impl_ptr ( const number_float_t * /*unused*/ ) const noexcept
{
return is_number_float ( ) ? & m_value . number_float : nullptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief helper function to implement get_ref ( )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function helps to implement get_ref ( ) without code duplication for
const and non - const overloads
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ThisType will be deduced as ` basic_json ` or ` const basic_json `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .303 if ReferenceType does not match underlying value
type of the current JSON
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < typename ReferenceType , typename ThisType >
static ReferenceType get_ref_impl ( ThisType & obj )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// delegate the call to get_ptr<>()
auto ptr = obj . template get_ptr < typename std : : add_pointer < ReferenceType > : : type > ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_LIKELY ( ptr ! = nullptr ) )
{
return * ptr ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 303 , " incompatible ReferenceType for get_ref, actual type is " + std : : string ( obj . type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
/// @name value access
/// Direct access to the stored value of a JSON value.
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get special - case overload
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This overloads avoids a lot of template boilerplate , it can be seen as the
identity method
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam BasicJsonType = = @ ref basic_json
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return a copy of * this
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.1 .0
*/
template < typename BasicJsonType , detail : : enable_if_t <
std : : is_same < typename std : : remove_const < BasicJsonType > : : type , basic_json_t > : : value ,
int > = 0 >
basic_json get ( ) const
{
return * this ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get special - case overload
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This overloads converts the current @ ref basic_json in a different
@ ref basic_json type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam BasicJsonType = = @ ref basic_json
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return a copy of * this , converted into @ tparam BasicJsonType
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Depending on the implementation of the called ` from_json ( ) `
method .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a value ( explicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Explicit type conversion between the JSON value and a compatible value
which is [ CopyConstructible ] ( http : //en.cppreference.com/w/cpp/concept/CopyConstructible)
and [ DefaultConstructible ] ( http : //en.cppreference.com/w/cpp/concept/DefaultConstructible).
The value is converted by calling the @ ref json_serializer < ValueType >
` from_json ( ) ` method .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The function is equivalent to executing
@ code { . cpp }
ValueType ret ;
JSONSerializer < ValueType > : : from_json ( * this , ret ) ;
return ret ;
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This overloads is chosen if :
- @ a ValueType is not @ ref basic_json ,
- @ ref json_serializer < ValueType > has a ` from_json ( ) ` method of the form
` void from_json ( const basic_json & , ValueType & ) ` , and
- @ ref json_serializer < ValueType > does not have a ` from_json ( ) ` method of
the form ` ValueType from_json ( const basic_json & ) `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ValueTypeCV the provided value type
@ tparam ValueType the returned value type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return copy of the JSON value , converted to @ a ValueType
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw what @ ref json_serializer < ValueType > ` from_json ( ) ` method throws
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows several conversions from JSON values
to other types . There a few things to note : ( 1 ) Floating - point numbers can
be converted to integers \ , ( 2 ) A JSON array can be converted to a standard
` std : : vector < short > ` \ , ( 3 ) A JSON object can be converted to C + +
associative containers such as ` std : : unordered_map < std : : string \ ,
json > ` . , get__ValueType_const }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.1 .0
*/
template < typename ValueTypeCV , typename ValueType = detail : : uncvref_t < ValueTypeCV > ,
detail : : enable_if_t <
not detail : : is_basic_json < ValueType > : : value and
detail : : has_from_json < basic_json_t , ValueType > : : value and
not detail : : has_non_default_from_json < basic_json_t , ValueType > : : value ,
int > = 0 >
ValueType get ( ) const noexcept ( noexcept (
JSONSerializer < ValueType > : : from_json ( std : : declval < const basic_json_t & > ( ) , std : : declval < ValueType & > ( ) ) ) )
{
// we cannot static_assert on ValueTypeCV being non-const, because
// there is support for get<const basic_json_t>(), which is why we
// still need the uncvref
static_assert ( not std : : is_reference < ValueTypeCV > : : value ,
" get() cannot be used with reference types, you might want to use get_ref() " ) ;
static_assert ( std : : is_default_constructible < ValueType > : : value ,
" types must be DefaultConstructible when used with get() " ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
ValueType ret ;
JSONSerializer < ValueType > : : from_json ( * this , ret ) ;
return ret ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a value ( explicit ) ; special case
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Explicit type conversion between the JSON value and a compatible value
which is * * not * * [ CopyConstructible ] ( http : //en.cppreference.com/w/cpp/concept/CopyConstructible)
and * * not * * [ DefaultConstructible ] ( http : //en.cppreference.com/w/cpp/concept/DefaultConstructible).
The value is converted by calling the @ ref json_serializer < ValueType >
` from_json ( ) ` method .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The function is equivalent to executing
@ code { . cpp }
return JSONSerializer < ValueTypeCV > : : from_json ( * this ) ;
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This overloads is chosen if :
- @ a ValueType is not @ ref basic_json and
- @ ref json_serializer < ValueType > has a ` from_json ( ) ` method of the form
` ValueType from_json ( const basic_json & ) `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note If @ ref json_serializer < ValueType > has both overloads of
` from_json ( ) ` , this one is chosen .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ValueTypeCV the provided value type
@ tparam ValueType the returned value type
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return copy of the JSON value , converted to @ a ValueType
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw what @ ref json_serializer < ValueType > ` from_json ( ) ` method throws
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.1 .0
*/
template < typename ValueTypeCV , typename ValueType = detail : : uncvref_t < ValueTypeCV > ,
detail : : enable_if_t < not std : : is_same < basic_json_t , ValueType > : : value and
detail : : has_non_default_from_json < basic_json_t , ValueType > : : value ,
int > = 0 >
ValueType get ( ) const noexcept ( noexcept (
JSONSerializer < ValueTypeCV > : : from_json ( std : : declval < const basic_json_t & > ( ) ) ) )
{
static_assert ( not std : : is_reference < ValueTypeCV > : : value ,
" get() cannot be used with reference types, you might want to use get_ref() " ) ;
return JSONSerializer < ValueTypeCV > : : from_json ( * this ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a pointer value ( explicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Explicit pointer access to the internally stored JSON value . No copies are
made .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning The pointer becomes invalid if the underlying JSON object
changes .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 ,
@ ref number_unsigned_t , or @ ref number_float_t .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return pointer to the internally stored JSON value if the requested
pointer type @ a PointerType fits to the JSON value ; ` nullptr ` otherwise
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how pointers to internal values of a
JSON value can be requested . Note that no type conversions are made and a
` nullptr ` is returned if the value and the requested pointer type does not
match . , get__PointerType }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref get_ptr ( ) for explicit pointer - member access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < typename PointerType , typename std : : enable_if <
std : : is_pointer < PointerType > : : value , int > : : type = 0 >
PointerType get ( ) noexcept
{
// delegate the call to get_ptr
return get_ptr < PointerType > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a pointer value ( explicit )
@ copydoc get ( )
*/
template < typename PointerType , typename std : : enable_if <
std : : is_pointer < PointerType > : : value , int > : : type = 0 >
constexpr const PointerType get ( ) const noexcept
{
// delegate the call to get_ptr
return get_ptr < PointerType > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a pointer value ( implicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Implicit pointer access to the internally stored JSON value . No copies are
made .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning Writing data to the pointee of the result yields an undefined
state .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 ,
@ ref number_unsigned_t , or @ ref number_float_t . Enforced by a static
assertion .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return pointer to the internally stored JSON value if the requested
pointer type @ a PointerType fits to the JSON value ; ` nullptr ` otherwise
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how pointers to internal values of a
JSON value can be requested . Note that no type conversions are made and a
` nullptr ` is returned if the value and the requested pointer type does not
match . , get_ptr }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < typename PointerType , typename std : : enable_if <
std : : is_pointer < PointerType > : : value , int > : : type = 0 >
PointerType get_ptr ( ) noexcept
{
// get the type of the PointerType (remove pointer and const)
using pointee_t = typename std : : remove_const < typename
std : : remove_pointer < typename
std : : remove_const < PointerType > : : type > : : type > : : type ;
// make sure the type matches the allowed types
static_assert (
std : : is_same < object_t , pointee_t > : : value
or std : : is_same < array_t , pointee_t > : : value
or std : : is_same < string_t , pointee_t > : : value
or std : : is_same < boolean_t , pointee_t > : : value
or std : : is_same < number_integer_t , pointee_t > : : value
or std : : is_same < number_unsigned_t , pointee_t > : : value
or std : : is_same < number_float_t , pointee_t > : : value
, " incompatible pointer type " ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// delegate the call to get_impl_ptr<>()
return get_impl_ptr ( static_cast < PointerType > ( nullptr ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a pointer value ( implicit )
@ copydoc get_ptr ( )
*/
template < typename PointerType , typename std : : enable_if <
std : : is_pointer < PointerType > : : value and
std : : is_const < typename std : : remove_pointer < PointerType > : : type > : : value , int > : : type = 0 >
constexpr const PointerType get_ptr ( ) const noexcept
{
// get the type of the PointerType (remove pointer and const)
using pointee_t = typename std : : remove_const < typename
std : : remove_pointer < typename
std : : remove_const < PointerType > : : type > : : type > : : type ;
// make sure the type matches the allowed types
static_assert (
std : : is_same < object_t , pointee_t > : : value
or std : : is_same < array_t , pointee_t > : : value
or std : : is_same < string_t , pointee_t > : : value
or std : : is_same < boolean_t , pointee_t > : : value
or std : : is_same < number_integer_t , pointee_t > : : value
or std : : is_same < number_unsigned_t , pointee_t > : : value
or std : : is_same < number_float_t , pointee_t > : : value
, " incompatible pointer type " ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// delegate the call to get_impl_ptr<>() const
return get_impl_ptr ( static_cast < PointerType > ( nullptr ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a reference value ( implicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Implicit reference access to the internally stored JSON value . No copies
are made .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning Writing data to the referee of the result yields an undefined
state .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ReferenceType reference type ; must be a reference to @ ref array_t ,
@ ref object_t , @ ref string_t , @ ref boolean_t , @ ref number_integer_t , or
@ ref number_float_t . Enforced by static assertion .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the internally stored JSON value if the requested
reference type @ a ReferenceType fits to the JSON value ; throws
type_error .303 otherwise
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .303 in case passed type @ a ReferenceType is incompatible
with the stored JSON value ; see example below
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows several calls to ` get_ref ( ) ` . , get_ref }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.1 .0
*/
template < typename ReferenceType , typename std : : enable_if <
std : : is_reference < ReferenceType > : : value , int > : : type = 0 >
ReferenceType get_ref ( )
{
// delegate call to get_ref_impl
return get_ref_impl < ReferenceType > ( * this ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a reference value ( implicit )
@ copydoc get_ref ( )
*/
template < typename ReferenceType , typename std : : enable_if <
std : : is_reference < ReferenceType > : : value and
std : : is_const < typename std : : remove_reference < ReferenceType > : : type > : : value , int > : : type = 0 >
ReferenceType get_ref ( ) const
{
// delegate call to get_ref_impl
return get_ref_impl < ReferenceType > ( * this ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief get a value ( implicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Implicit type conversion between the JSON value and a compatible value .
The call is realized by calling @ ref get ( ) const .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ValueType non - pointer type compatible to the JSON value , for
instance ` int ` for JSON integer numbers , ` bool ` for JSON booleans , or
` std : : vector ` types for JSON arrays . The character type of @ ref string_t
as well as an initializer list of this type is excluded to avoid
ambiguities as these types implicitly convert to ` std : : string ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return copy of the JSON value , converted to type @ a ValueType
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .302 in case passed type @ a ValueType is incompatible
to the JSON value type ( e . g . , the JSON value is of type boolean , but a
string is requested ) ; see example below
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows several conversions from JSON values
to other types . There a few things to note : ( 1 ) Floating - point numbers can
be converted to integers \ , ( 2 ) A JSON array can be converted to a standard
` std : : vector < short > ` \ , ( 3 ) A JSON object can be converted to C + +
associative containers such as ` std : : unordered_map < std : : string \ ,
json > ` . , operator__ValueType }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < typename ValueType , typename std : : enable_if <
not std : : is_pointer < ValueType > : : value and
not std : : is_same < ValueType , detail : : json_ref < basic_json > > : : value and
not std : : is_same < ValueType , typename string_t : : value_type > : : value and
not detail : : is_basic_json < ValueType > : : value
# ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
and not std : : is_same < ValueType , std : : initializer_list < typename string_t : : value_type > > : : value
# endif
# if defined(JSON_HAS_CPP_17)
and not std : : is_same < ValueType , typename std : : string_view > : : value
# endif
, int > : : type = 0 >
operator ValueType ( ) const
{
// delegate the call to get<>() const
return get < ValueType > ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
////////////////////
// element access //
////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name element access
/// Access to the JSON value.
/// @{
2017-07-18 05:37:27 +02:00
/*!
2018-05-19 21:59:03 +02:00
@ brief access specified array element with bounds checking
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a reference to the element at specified location @ a idx , with
bounds checking .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] idx index of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the element at index @ a idx
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .304 if the JSON value is not an array ; in this case ,
calling ` at ` with an index makes no sense . See example below .
@ throw out_of_range .401 if the index @ a idx is out of range of the array ;
that is , ` idx > = size ( ) ` . See example below .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how array elements can be read and
written using ` at ( ) ` . It also demonstrates the different exceptions that
can be thrown . , at__size_type }
*/
reference at ( size_type idx )
{
// at only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_TRY
{
return m_value . array - > at ( idx ) ;
}
JSON_CATCH ( std : : out_of_range & )
{
// create better exception explanation
JSON_THROW ( out_of_range : : create ( 401 , " array index " + std : : to_string ( idx ) + " is out of range " ) ) ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 304 , " cannot use at() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified array element with bounds checking
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a const reference to the element at specified location @ a idx ,
with bounds checking .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] idx index of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return const reference to the element at index @ a idx
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .304 if the JSON value is not an array ; in this case ,
calling ` at ` with an index makes no sense . See example below .
@ throw out_of_range .401 if the index @ a idx is out of range of the array ;
that is , ` idx > = size ( ) ` . See example below .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how array elements can be read using
` at ( ) ` . It also demonstrates the different exceptions that can be thrown . ,
at__size_type_const }
*/
const_reference at ( size_type idx ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// at only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_TRY
{
return m_value . array - > at ( idx ) ;
}
JSON_CATCH ( std : : out_of_range & )
{
// create better exception explanation
JSON_THROW ( out_of_range : : create ( 401 , " array index " + std : : to_string ( idx ) + " is out of range " ) ) ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 304 , " cannot use at() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified object element with bounds checking
Returns a reference to the element at with specified key @ a key , with
bounds checking .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key key of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the element at key @ a key
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .304 if the JSON value is not an object ; in this case ,
calling ` at ` with a key makes no sense . See example below .
@ throw out_of_range .403 if the key @ a key is is not stored in the object ;
that is , ` find ( key ) = = end ( ) ` . See example below .
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
@ complexity Logarithmic in the size of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref operator [ ] ( const typename object_t : : key_type & ) for unchecked
access by reference
@ sa @ ref value ( ) for access by value with a default value
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how object elements can be read and
written using ` at ( ) ` . It also demonstrates the different exceptions that
can be thrown . , at__object_t_key_type }
*/
reference at ( const typename object_t : : key_type & key )
{
// at only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
{
JSON_TRY
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m_value . object - > at ( key ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
JSON_CATCH ( std : : out_of_range & )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// create better exception explanation
JSON_THROW ( out_of_range : : create ( 403 , " key ' " + key + " ' not found " ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
else
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 304 , " cannot use at() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified object element with bounds checking
Returns a const reference to the element at with specified key @ a key ,
with bounds checking .
@ param [ in ] key key of the element to access
@ return const reference to the element at key @ a key
@ throw type_error .304 if the JSON value is not an object ; in this case ,
calling ` at ` with a key makes no sense . See example below .
@ throw out_of_range .403 if the key @ a key is is not stored in the object ;
that is , ` find ( key ) = = end ( ) ` . See example below .
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
@ complexity Logarithmic in the size of the container .
@ sa @ ref operator [ ] ( const typename object_t : : key_type & ) for unchecked
access by reference
@ sa @ ref value ( ) for access by value with a default value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how object elements can be read using
` at ( ) ` . It also demonstrates the different exceptions that can be thrown . ,
at__object_t_key_type_const }
*/
const_reference at ( const typename object_t : : key_type & key ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// at only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_TRY
{
return m_value . object - > at ( key ) ;
}
JSON_CATCH ( std : : out_of_range & )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// create better exception explanation
JSON_THROW ( out_of_range : : create ( 403 , " key ' " + key + " ' not found " ) ) ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
else
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 304 , " cannot use at() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified array element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a reference to the element at specified location @ a idx .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note If @ a idx is beyond the range of the array ( i . e . , ` idx > = size ( ) ` ) ,
then the array is silently filled up with ` null ` values to make ` idx ` a
valid reference to the last stored element .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] idx index of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the element at index @ a idx
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .305 if the JSON value is not an array or null ; in that
cases , using the [ ] operator with an index makes no sense .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant if @ a idx is in the range of the array . Otherwise
linear in ` idx - size ( ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how array elements can be read and
written using ` [ ] ` operator . Note the addition of ` null `
values . , operatorarray__size_type }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
reference operator [ ] ( size_type idx )
{
// implicitly convert null value to an empty array
if ( is_null ( ) )
{
m_type = value_t : : array ;
m_value . array = create < array_t > ( ) ;
assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// operator[] only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// fill up array with null values if given idx is outside range
if ( idx > = m_value . array - > size ( ) )
{
m_value . array - > insert ( m_value . array - > end ( ) ,
idx - m_value . array - > size ( ) + 1 ,
basic_json ( ) ) ;
}
return m_value . array - > operator [ ] ( idx ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 305 , " cannot use operator[] with " + std : : string ( type_name ( ) ) ) ) ;
}
/*!
@ brief access specified array element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a const reference to the element at specified location @ a idx .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] idx index of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return const reference to the element at index @ a idx
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .305 if the JSON value is not an array ; in that case ,
using the [ ] operator with an index makes no sense .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
@ liveexample { The example below shows how array elements can be read using
the ` [ ] ` operator . , operatorarray__size_type_const }
@ since version 1.0 .0
*/
const_reference operator [ ] ( size_type idx ) const
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// const operator[] only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m_value . array - > operator [ ] ( idx ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 305 , " cannot use operator[] with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified object element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a reference to the element at with specified key @ a key .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key key of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the element at key @ a key
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .305 if the JSON value is not an object or null ; in that
cases , using the [ ] operator with a key makes no sense .
@ 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 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
reference operator [ ] ( const typename object_t : : key_type & key )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// implicitly convert null value to an empty object
if ( is_null ( ) )
{
m_type = value_t : : object ;
m_value . object = create < object_t > ( ) ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// operator[] only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return m_value . object - > operator [ ] ( key ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 305 , " cannot use operator[] with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief read - only access specified object element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a const reference to the element at with specified key @ a key . No
bounds checking is performed .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning If the element with key @ a key does not exist , the behavior is
undefined .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key key of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return const reference to the element at key @ a key
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The element with key @ a key must exist . * * This precondition is
enforced with an assertion . * *
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .305 if the JSON value is not an object ; in that case ,
using the [ ] operator with a key makes no sense .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Logarithmic in the size of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how object elements can be read using
the ` [ ] ` operator . , operatorarray__key_type_const }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
const_reference operator [ ] ( const typename object_t : : key_type & key ) const
{
// const operator[] only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
{
assert ( m_value . object - > find ( key ) ! = m_value . object - > end ( ) ) ;
return m_value . object - > find ( key ) - > second ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 305 , " cannot use operator[] with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified object element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a reference to the element at with specified key @ a key .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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 .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key key of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return reference to the element at key @ a key
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .305 if the JSON value is not an object or null ; in that
cases , using the [ ] operator with a key makes no sense .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Logarithmic in the size of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how object elements can be read and
written using the ` [ ] ` operator . , operatorarray__key_type }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.1 .0
*/
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 ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// at only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
{
return m_value . object - > operator [ ] ( key ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 305 , " cannot use operator[] with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief read - only access specified object element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a const reference to the element at with specified key @ a key . No
bounds checking is performed .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning If the element with key @ a key does not exist , the behavior is
undefined .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key key of the element to access
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return const reference to the element at key @ a key
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The element with key @ a key must exist . * * This precondition is
enforced with an assertion . * *
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .305 if the JSON value is not an object ; in that case ,
using the [ ] operator with a key makes no sense .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ 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.1 .0
*/
template < typename T >
const_reference operator [ ] ( T * key ) const
{
// at only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
{
assert ( m_value . object - > find ( key ) ! = m_value . object - > end ( ) ) ;
return m_value . object - > find ( key ) - > second ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 305 , " cannot use operator[] with " + std : : string ( type_name ( ) ) ) ) ;
}
/*!
@ brief access specified object element with default value
Returns either a copy of an object ' s element at the specified key @ a key
or a given default value if no element with key @ a key exists .
The function is basically equivalent to executing
@ code { . cpp }
try {
return at ( key ) ;
} catch ( out_of_range ) {
return default_value ;
}
@ endcode
@ note Unlike @ ref at ( const typename object_t : : key_type & ) , this function
does not throw if the given key @ a key was not found .
@ note Unlike @ ref operator [ ] ( const typename object_t : : key_type & key ) , this
function does not implicitly add an element to the position defined by @ a
key . This function is furthermore also applicable to const objects .
@ param [ in ] key key of the element to access
@ param [ in ] default_value the value to return if @ a key is not found
@ tparam ValueType type compatible to JSON values , for instance ` int ` for
JSON integer numbers , ` bool ` for JSON booleans , or ` std : : vector ` types for
JSON arrays . Note the type of the expected value at @ a key and the default
value @ a default_value must be compatible .
@ return copy of the element at key @ a key or @ a default_value if @ a key
is not found
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .306 if the JSON value is not an object ; in that case ,
using ` value ( ) ` with a key makes no sense .
@ complexity Logarithmic in the size of the container .
@ liveexample { The example below shows how object elements can be queried
with a default value . , basic_json__value }
@ sa @ ref at ( const typename object_t : : key_type & ) for access by reference
with range checking
@ sa @ ref operator [ ] ( const typename object_t : : key_type & ) for unchecked
access by reference
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < class ValueType , typename std : : enable_if <
std : : is_convertible < basic_json_t , ValueType > : : value , int > : : type = 0 >
ValueType value ( const typename object_t : : key_type & key , const ValueType & default_value ) const
{
// at only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// if key is found, return value and given default value otherwise
const auto it = find ( key ) ;
if ( it ! = end ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return * it ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return default_value ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 306 , " cannot use value() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief overload for a default value of type const char *
@ copydoc basic_json : : value ( const typename object_t : : key_type & , ValueType ) const
*/
string_t value ( const typename object_t : : key_type & key , const char * default_value ) const
{
return value ( key , string_t ( default_value ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access specified object element via JSON Pointer with default value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns either a copy of an object ' s element at the specified key @ a key
or a given default value if no element with key @ a key exists .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The function is basically equivalent to executing
@ code { . cpp }
try {
return at ( ptr ) ;
} catch ( out_of_range ) {
return default_value ;
}
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Unlike @ ref at ( const json_pointer & ) , this function does not throw
if the given key @ a key was not found .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] ptr a JSON pointer to the element to access
@ param [ in ] default_value the value to return if @ a ptr found no value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam ValueType type compatible to JSON values , for instance ` int ` for
JSON integer numbers , ` bool ` for JSON booleans , or ` std : : vector ` types for
JSON arrays . Note the type of the expected value at @ a key and the default
value @ a default_value must be compatible .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return copy of the element at key @ a key or @ a default_value if @ a key
is not found
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .306 if the JSON value is not an objec ; in that case ,
using ` value ( ) ` with a key makes no sense .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Logarithmic in the size of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how object elements can be queried
with a default value . , basic_json__value_ptr }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref operator [ ] ( const json_pointer & ) for unchecked access by reference
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .2
*/
template < class ValueType , typename std : : enable_if <
std : : is_convertible < basic_json_t , ValueType > : : value , int > : : type = 0 >
ValueType value ( const json_pointer & ptr , const ValueType & default_value ) const
{
// at only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
{
// if pointer resolves a value, return it or use default value
JSON_TRY
{
return ptr . get_checked ( this ) ;
}
JSON_CATCH ( out_of_range & )
{
return default_value ;
2017-07-18 05:37:27 +02:00
}
}
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 306 , " cannot use value() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief overload for a default value of type const char *
@ copydoc basic_json : : value ( const json_pointer & , ValueType ) const
*/
string_t value ( const json_pointer & ptr , const char * default_value ) const
{
return value ( ptr , string_t ( default_value ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access the first element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a reference to the first element in the container . For a JSON
container ` c ` , the expression ` c . front ( ) ` is equivalent to ` * c . begin ( ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return In case of a structured type ( array or object ) , a reference to the
first element is returned . In case of number , string , or boolean values , a
reference to the value is returned .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The JSON value must not be ` null ` ( would throw ` std : : out_of_range ` )
or an empty array or object ( undefined behavior , * * guarded by
assertions * * ) .
@ post The JSON value remains unchanged .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw invalid_iterator .214 when called on ` null ` value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows an example for ` front ( ) ` . , front }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref back ( ) - - access the last element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
reference front ( )
{
return * begin ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ copydoc basic_json : : front ( )
*/
const_reference front ( ) const
{
return * cbegin ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief access the last element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns a reference to the last element in the container . For a JSON
container ` c ` , the expression ` c . back ( ) ` is equivalent to
@ code { . cpp }
auto tmp = c . end ( ) ;
- - tmp ;
return * tmp ;
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return In case of a structured type ( array or object ) , a reference to the
last element is returned . In case of number , string , or boolean values , a
reference to the value is returned .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The JSON value must not be ` null ` ( would throw ` std : : out_of_range ` )
or an empty array or object ( undefined behavior , * * guarded by
assertions * * ) .
@ post The JSON value remains unchanged .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw invalid_iterator .214 when called on a ` null ` value . See example
below .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code shows an example for ` back ( ) ` . , back }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref front ( ) - - access the first element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
reference back ( )
{
auto tmp = end ( ) ;
- - tmp ;
return * tmp ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ copydoc basic_json : : back ( )
*/
const_reference back ( ) const
{
auto tmp = cend ( ) ;
- - tmp ;
return * tmp ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief remove element given an iterator
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Removes the element specified by iterator @ a pos . The iterator @ a pos must
be valid and dereferenceable . Thus the ` end ( ) ` iterator ( which is valid ,
but is not dereferenceable ) cannot be used as a value for @ a pos .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
If called on a primitive type other than ` null ` , the resulting JSON value
will be ` null ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] pos iterator to the element to remove
@ return Iterator following the last removed element . If the iterator @ a
pos refers to the last element , the ` end ( ) ` iterator is returned .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam IteratorType an @ ref iterator or @ ref const_iterator
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ post Invalidates iterators and references at or after the point of the
erase , including the ` end ( ) ` iterator .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .307 if called on a ` null ` value ; example : ` " cannot use
erase ( ) with null " `
@ throw invalid_iterator .202 if called on an iterator which does not belong
to the current JSON value ; example : ` " iterator does not fit current
value " `
@ throw invalid_iterator .205 if called on a primitive type with invalid
iterator ( i . e . , any iterator which is not ` begin ( ) ` ) ; example : ` " iterator
out of range " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity The complexity depends on the type :
- objects : amortized constant
- arrays : linear in distance between @ a pos and the end of the container
- strings : linear in the length of the string
- other types : constant
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the result of ` erase ( ) ` for different JSON
types . , erase__IteratorType }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref erase ( IteratorType , IteratorType ) - - removes the elements in
the given range
@ sa @ ref erase ( const typename object_t : : key_type & ) - - removes the element
from an object at the given key
@ sa @ ref erase ( const size_type ) - - removes the element from an array at
the given index
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
template < class IteratorType , typename std : : enable_if <
std : : is_same < IteratorType , typename basic_json_t : : iterator > : : value or
std : : is_same < IteratorType , typename basic_json_t : : const_iterator > : : value , int > : : type
= 0 >
IteratorType erase ( IteratorType pos )
{
// make sure iterator fits the current value
if ( JSON_UNLIKELY ( this ! = pos . m_object ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 202 , " iterator does not fit current value " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
IteratorType result = end ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
switch ( m_type )
{
case value_t : : boolean :
case value_t : : number_float :
case value_t : : number_integer :
case value_t : : number_unsigned :
case value_t : : string :
{
if ( JSON_UNLIKELY ( not pos . m_it . primitive_iterator . is_begin ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 205 , " iterator out of range " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( is_string ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
AllocatorType < string_t > alloc ;
std : : allocator_traits < decltype ( alloc ) > : : destroy ( alloc , m_value . string ) ;
std : : allocator_traits < decltype ( alloc ) > : : deallocate ( alloc , m_value . string , 1 ) ;
m_value . string = nullptr ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
m_type = value_t : : null ;
assert_invariant ( ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
{
result . m_it . object_iterator = m_value . object - > erase ( pos . m_it . object_iterator ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
case value_t : : array :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
result . m_it . array_iterator = m_value . array - > erase ( pos . m_it . array_iterator ) ;
break ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
default :
JSON_THROW ( type_error : : create ( 307 , " cannot use erase() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief remove elements given an iterator range
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Removes the element specified by the range ` [ first ; last ) ` . The iterator
@ a first does not need to be dereferenceable if ` first = = last ` : erasing
an empty range is a no - op .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
If called on a primitive type other than ` null ` , the resulting JSON value
will be ` null ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] first iterator to the beginning of the range to remove
@ param [ in ] last iterator past the end of the range to remove
@ return Iterator following the last removed element . If the iterator @ a
second refers to the last element , the ` end ( ) ` iterator is returned .
@ tparam IteratorType an @ ref iterator or @ ref const_iterator
@ post Invalidates iterators and references at or after the point of the
erase , including the ` end ( ) ` iterator .
@ throw type_error .307 if called on a ` null ` value ; example : ` " cannot use
erase ( ) with null " `
@ throw invalid_iterator .203 if called on iterators which does not belong
to the current JSON value ; example : ` " iterators do not fit current value " `
@ throw invalid_iterator .204 if called on a primitive type with invalid
iterators ( i . e . , if ` first ! = begin ( ) ` and ` last ! = end ( ) ` ) ; example :
` " iterators out of range " `
@ complexity The complexity depends on the type :
- objects : ` log ( size ( ) ) + std : : distance ( first , last ) `
- arrays : linear in the distance between @ a first and @ a last , plus linear
in the distance between @ a last and end of the container
- strings : linear in the length of the string
- other types : constant
@ liveexample { The example shows the result of ` erase ( ) ` for different JSON
types . , erase__IteratorType_IteratorType }
@ sa @ ref erase ( IteratorType ) - - removes the element at a given position
@ sa @ ref erase ( const typename object_t : : key_type & ) - - removes the element
from an object at the given key
@ sa @ ref erase ( const size_type ) - - removes the element from an array at
the given index
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
template < class IteratorType , typename std : : enable_if <
std : : is_same < IteratorType , typename basic_json_t : : iterator > : : value or
std : : is_same < IteratorType , typename basic_json_t : : const_iterator > : : value , int > : : type
= 0 >
IteratorType erase ( IteratorType first , IteratorType last )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// make sure iterator fits the current value
if ( JSON_UNLIKELY ( this ! = first . m_object or this ! = last . m_object ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 203 , " iterators do not fit current value " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
IteratorType result = end ( ) ;
switch ( m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
case value_t : : number_float :
case value_t : : number_integer :
case value_t : : number_unsigned :
case value_t : : string :
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_LIKELY ( not first . m_it . primitive_iterator . is_begin ( )
or not last . m_it . primitive_iterator . is_end ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 204 , " iterators out of range " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( is_string ( ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
AllocatorType < string_t > alloc ;
std : : allocator_traits < decltype ( alloc ) > : : destroy ( alloc , m_value . string ) ;
std : : allocator_traits < decltype ( alloc ) > : : deallocate ( alloc , m_value . string , 1 ) ;
m_value . string = nullptr ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
m_type = value_t : : null ;
assert_invariant ( ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
{
result . m_it . object_iterator = m_value . object - > erase ( first . m_it . object_iterator ,
last . m_it . object_iterator ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : array :
{
result . m_it . array_iterator = m_value . array - > erase ( first . m_it . array_iterator ,
last . m_it . array_iterator ) ;
break ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
JSON_THROW ( type_error : : create ( 307 , " cannot use erase() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief remove element from a JSON object given a key
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Removes elements from a JSON object with the key value @ a key .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key value of the elements to remove
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return Number of elements removed . If @ a ObjectType is the default
` std : : map ` type , the return value will always be ` 0 ` ( @ a key was not
found ) or ` 1 ` ( @ a key was found ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ post References and iterators to the erased elements are invalidated .
Other references and iterators are not affected .
@ throw type_error .307 when called on a type other than JSON object ;
example : ` " cannot use erase() with null " `
@ complexity ` log ( size ( ) ) + count ( key ) `
@ liveexample { The example shows the effect of ` erase ( ) ` . , erase__key_type }
@ sa @ ref erase ( IteratorType ) - - removes the element at a given position
@ sa @ ref erase ( IteratorType , IteratorType ) - - removes the elements in
the given range
@ sa @ ref erase ( const size_type ) - - removes the element from an array at
the given index
@ since version 1.0 .0
*/
size_type erase ( const typename object_t : : key_type & key )
{
// this erase only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
{
return m_value . object - > erase ( key ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 307 , " cannot use erase() with " + std : : string ( type_name ( ) ) ) ) ;
}
/*!
@ brief remove element from a JSON array given an index
Removes element from a JSON array at the index @ a idx .
@ param [ in ] idx index of the element to remove
@ throw type_error .307 when called on a type other than JSON object ;
example : ` " cannot use erase() with null " `
@ throw out_of_range .401 when ` idx > = size ( ) ` ; example : ` " array index 17
is out of range " `
@ complexity Linear in distance between @ a idx and the end of the container .
@ liveexample { The example shows the effect of ` erase ( ) ` . , erase__size_type }
@ sa @ ref erase ( IteratorType ) - - removes the element at a given position
@ sa @ ref erase ( IteratorType , IteratorType ) - - removes the elements in
the given range
@ sa @ ref erase ( const typename object_t : : key_type & ) - - removes the element
from an object at the given key
@ since version 1.0 .0
*/
void erase ( const size_type idx )
{
// this erase only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( idx > = size ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( out_of_range : : create ( 401 , " array index " + std : : to_string ( idx ) + " is out of range " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
m_value . array - > erase ( m_value . array - > begin ( ) + static_cast < difference_type > ( idx ) ) ;
}
else
{
JSON_THROW ( type_error : : create ( 307 , " cannot use erase() with " + std : : string ( type_name ( ) ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
////////////
// lookup //
////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name lookup
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief find an element in a JSON object
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Finds an element in a JSON object with key equivalent to @ a key . If the
element is not found or the JSON value is not an object , end ( ) is
returned .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note This method always returns @ ref end ( ) when executed on a JSON type
that is not an object .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] key key value of the element to search for .
@ return Iterator to an element with key equivalent to @ a key . If no such
element is found or the JSON value is not an object , past - the - end ( see
@ ref end ( ) ) iterator is returned .
@ complexity Logarithmic in the size of the JSON object .
@ liveexample { The example shows how ` find ( ) ` is used . , find__key_type }
@ since version 1.0 .0
*/
template < typename KeyT >
iterator find ( KeyT & & key )
{
auto result = end ( ) ;
if ( is_object ( ) )
{
result . m_it . object_iterator = m_value . object - > find ( std : : forward < KeyT > ( key ) ) ;
}
return result ;
}
/*!
@ brief find an element in a JSON object
@ copydoc find ( KeyT & & )
*/
template < typename KeyT >
const_iterator find ( KeyT & & key ) const
{
auto result = cend ( ) ;
if ( is_object ( ) )
{
result . m_it . object_iterator = m_value . object - > find ( std : : forward < KeyT > ( key ) ) ;
}
return result ;
}
/*!
@ brief returns the number of occurrences of a key in a JSON object
Returns the number of elements with key @ a key . If ObjectType is the
default ` std : : map ` type , the return value will always be ` 0 ` ( @ a key was
not found ) or ` 1 ` ( @ a key was found ) .
@ note This method always returns ` 0 ` when executed on a JSON type that is
not an object .
@ param [ in ] key key value of the element to count
@ return Number of elements with key @ a key . If the JSON value is not an
object , the return value will be ` 0 ` .
@ complexity Logarithmic in the size of the JSON object .
@ liveexample { The example shows how ` count ( ) ` is used . , count }
@ since version 1.0 .0
*/
template < typename KeyT >
size_type count ( KeyT & & key ) const
{
// return 0 for all nonobject types
return is_object ( ) ? m_value . object - > count ( std : : forward < KeyT > ( key ) ) : 0 ;
}
/// @}
///////////////
// iterators //
///////////////
/// @name iterators
/// @{
/*!
@ brief returns an iterator to the first element
Returns an iterator to the first element .
@ image html range - begin - end . svg " Illustration from cppreference.com "
@ return iterator to the first element
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
@ liveexample { The following code shows an example for ` begin ( ) ` . , begin }
@ sa @ ref cbegin ( ) - - returns a const iterator to the beginning
@ sa @ ref end ( ) - - returns an iterator to the end
@ sa @ ref cend ( ) - - returns a const iterator to the end
@ since version 1.0 .0
*/
iterator begin ( ) noexcept
{
iterator result ( this ) ;
result . set_begin ( ) ;
return result ;
}
/*!
@ copydoc basic_json : : cbegin ( )
*/
const_iterator begin ( ) const noexcept
{
return cbegin ( ) ;
}
/*!
@ brief returns a const iterator to the first element
Returns a const iterator to the first element .
@ image html range - begin - end . svg " Illustration from cppreference.com "
@ return const iterator to the first element
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
- Has the semantics of ` const_cast < const basic_json & > ( * this ) . begin ( ) ` .
@ liveexample { The following code shows an example for ` cbegin ( ) ` . , cbegin }
@ sa @ ref begin ( ) - - returns an iterator to the beginning
@ sa @ ref end ( ) - - returns an iterator to the end
@ sa @ ref cend ( ) - - returns a const iterator to the end
@ since version 1.0 .0
*/
const_iterator cbegin ( ) const noexcept
{
const_iterator result ( this ) ;
result . set_begin ( ) ;
return result ;
}
/*!
@ brief returns an iterator to one past the last element
Returns an iterator to one past the last element .
@ image html range - begin - end . svg " Illustration from cppreference.com "
@ return iterator one past the last element
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
@ liveexample { The following code shows an example for ` end ( ) ` . , end }
@ sa @ ref cend ( ) - - returns a const iterator to the end
@ sa @ ref begin ( ) - - returns an iterator to the beginning
@ sa @ ref cbegin ( ) - - returns a const iterator to the beginning
@ since version 1.0 .0
*/
iterator end ( ) noexcept
{
iterator result ( this ) ;
result . set_end ( ) ;
return result ;
}
/*!
@ copydoc basic_json : : cend ( )
*/
const_iterator end ( ) const noexcept
{
return cend ( ) ;
}
/*!
@ brief returns a const iterator to one past the last element
Returns a const iterator to one past the last element .
@ image html range - begin - end . svg " Illustration from cppreference.com "
@ return const iterator one past the last element
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
- Has the semantics of ` const_cast < const basic_json & > ( * this ) . end ( ) ` .
@ liveexample { The following code shows an example for ` cend ( ) ` . , cend }
@ sa @ ref end ( ) - - returns an iterator to the end
@ sa @ ref begin ( ) - - returns an iterator to the beginning
@ sa @ ref cbegin ( ) - - returns a const iterator to the beginning
@ since version 1.0 .0
*/
const_iterator cend ( ) const noexcept
{
const_iterator result ( this ) ;
result . set_end ( ) ;
return result ;
}
/*!
@ brief returns an iterator to the reverse - beginning
Returns an iterator to the reverse - beginning ; that is , the last element .
@ image html range - rbegin - rend . svg " Illustration from cppreference.com "
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ ReversibleContainer ] ( http : //en.cppreference.com/w/cpp/concept/ReversibleContainer)
requirements :
- The complexity is constant .
- Has the semantics of ` reverse_iterator ( end ( ) ) ` .
@ liveexample { The following code shows an example for ` rbegin ( ) ` . , rbegin }
@ sa @ ref crbegin ( ) - - returns a const reverse iterator to the beginning
@ sa @ ref rend ( ) - - returns a reverse iterator to the end
@ sa @ ref crend ( ) - - returns a const reverse iterator to the end
@ since version 1.0 .0
*/
reverse_iterator rbegin ( ) noexcept
{
return reverse_iterator ( end ( ) ) ;
}
/*!
@ copydoc basic_json : : crbegin ( )
*/
const_reverse_iterator rbegin ( ) const noexcept
{
return crbegin ( ) ;
}
/*!
@ brief returns an iterator to the reverse - end
Returns an iterator to the reverse - end ; that is , one before the first
element .
@ image html range - rbegin - rend . svg " Illustration from cppreference.com "
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ ReversibleContainer ] ( http : //en.cppreference.com/w/cpp/concept/ReversibleContainer)
requirements :
- The complexity is constant .
- Has the semantics of ` reverse_iterator ( begin ( ) ) ` .
@ liveexample { The following code shows an example for ` rend ( ) ` . , rend }
@ sa @ ref crend ( ) - - returns a const reverse iterator to the end
@ sa @ ref rbegin ( ) - - returns a reverse iterator to the beginning
@ sa @ ref crbegin ( ) - - returns a const reverse iterator to the beginning
@ since version 1.0 .0
*/
reverse_iterator rend ( ) noexcept
{
return reverse_iterator ( begin ( ) ) ;
}
/*!
@ copydoc basic_json : : crend ( )
*/
const_reverse_iterator rend ( ) const noexcept
{
return crend ( ) ;
}
/*!
@ brief returns a const reverse iterator to the last element
Returns a const iterator to the reverse - beginning ; that is , the last
element .
@ image html range - rbegin - rend . svg " Illustration from cppreference.com "
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ ReversibleContainer ] ( http : //en.cppreference.com/w/cpp/concept/ReversibleContainer)
requirements :
- The complexity is constant .
- Has the semantics of ` const_cast < const basic_json & > ( * this ) . rbegin ( ) ` .
@ liveexample { The following code shows an example for ` crbegin ( ) ` . , crbegin }
@ sa @ ref rbegin ( ) - - returns a reverse iterator to the beginning
@ sa @ ref rend ( ) - - returns a reverse iterator to the end
@ sa @ ref crend ( ) - - returns a const reverse iterator to the end
@ since version 1.0 .0
*/
const_reverse_iterator crbegin ( ) const noexcept
{
return const_reverse_iterator ( cend ( ) ) ;
}
/*!
@ brief returns a const reverse iterator to one before the first
Returns a const reverse iterator to the reverse - end ; that is , one before
the first element .
@ image html range - rbegin - rend . svg " Illustration from cppreference.com "
@ complexity Constant .
@ requirement This function helps ` basic_json ` satisfying the
[ ReversibleContainer ] ( http : //en.cppreference.com/w/cpp/concept/ReversibleContainer)
requirements :
- The complexity is constant .
- Has the semantics of ` const_cast < const basic_json & > ( * this ) . rend ( ) ` .
@ liveexample { The following code shows an example for ` crend ( ) ` . , crend }
@ sa @ ref rend ( ) - - returns a reverse iterator to the end
@ sa @ ref rbegin ( ) - - returns a reverse iterator to the beginning
@ sa @ ref crbegin ( ) - - returns a const reverse iterator to the beginning
@ since version 1.0 .0
*/
const_reverse_iterator crend ( ) const noexcept
{
return const_reverse_iterator ( cbegin ( ) ) ;
}
public :
/*!
@ brief wrapper to access iterator member functions in range - based for
This function allows to access @ ref iterator : : key ( ) and @ ref
iterator : : value ( ) during range - based for loops . In these loops , a
reference to the JSON values is returned , so there is no access to the
underlying iterator .
For loop without iterator_wrapper :
@ code { cpp }
for ( auto it = j_object . begin ( ) ; it ! = j_object . end ( ) ; + + it )
{
std : : cout < < " key: " < < it . key ( ) < < " , value: " < < it . value ( ) < < ' \n ' ;
}
@ endcode
Range - based for loop without iterator proxy :
@ code { cpp }
for ( auto it : j_object )
{
// "it" is of type json::reference and has no key() member
std : : cout < < " value: " < < it < < ' \n ' ;
}
@ endcode
Range - based for loop with iterator proxy :
@ code { cpp }
for ( auto it : json : : iterator_wrapper ( j_object ) )
{
std : : cout < < " key: " < < it . key ( ) < < " , value: " < < it . value ( ) < < ' \n ' ;
}
@ endcode
@ note When iterating over an array , ` key ( ) ` will return the index of the
element as string ( see example ) .
@ param [ in ] ref reference to a JSON value
@ return iteration proxy object wrapping @ a ref with an interface to use in
range - based for loops
@ liveexample { The following code shows how the wrapper is used , iterator_wrapper }
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
@ complexity Constant .
@ note The name of this function is not yet final and may change in the
future .
@ deprecated This stream operator is deprecated and will be removed in
future 4.0 .0 of the library . Please use @ ref items ( ) instead ;
that is , replace ` json : : iterator_wrapper ( j ) ` with ` j . items ( ) ` .
*/
JSON_DEPRECATED
static iteration_proxy < iterator > iterator_wrapper ( reference ref ) noexcept
{
return ref . items ( ) ;
}
/*!
@ copydoc iterator_wrapper ( reference )
*/
JSON_DEPRECATED
static iteration_proxy < const_iterator > iterator_wrapper ( const_reference ref ) noexcept
{
return ref . items ( ) ;
}
/*!
@ brief helper to access iterator member functions in range - based for
This function allows to access @ ref iterator : : key ( ) and @ ref
iterator : : value ( ) during range - based for loops . In these loops , a
reference to the JSON values is returned , so there is no access to the
underlying iterator .
For loop without ` items ( ) ` function :
@ code { cpp }
for ( auto it = j_object . begin ( ) ; it ! = j_object . end ( ) ; + + it )
{
std : : cout < < " key: " < < it . key ( ) < < " , value: " < < it . value ( ) < < ' \n ' ;
}
@ endcode
Range - based for loop without ` items ( ) ` function :
@ code { cpp }
for ( auto it : j_object )
{
// "it" is of type json::reference and has no key() member
std : : cout < < " value: " < < it < < ' \n ' ;
}
@ endcode
Range - based for loop with ` items ( ) ` function :
@ code { cpp }
for ( auto it : j_object . items ( ) )
{
std : : cout < < " key: " < < it . key ( ) < < " , value: " < < it . value ( ) < < ' \n ' ;
}
@ endcode
@ note When iterating over an array , ` key ( ) ` will return the index of the
element as string ( see example ) . For primitive types ( e . g . , numbers ) ,
` key ( ) ` returns an empty string .
@ return iteration proxy object wrapping @ a ref with an interface to use in
range - based for loops
@ liveexample { The following code shows how the function is used . , items }
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
@ complexity Constant .
@ since version 3. x . x .
*/
iteration_proxy < iterator > items ( ) noexcept
{
return iteration_proxy < iterator > ( * this ) ;
}
/*!
@ copydoc items ( )
*/
iteration_proxy < const_iterator > items ( ) const noexcept
{
return iteration_proxy < const_iterator > ( * this ) ;
}
/// @}
//////////////
// capacity //
//////////////
/// @name capacity
/// @{
/*!
@ brief checks whether the container is empty .
Checks if a JSON value has no elements ( i . e . whether its @ ref size is ` 0 ` ) .
@ return The return value depends on the different types and is
defined as follows :
Value type | return value
- - - - - - - - - - - | - - - - - - - - - - - - -
null | ` true `
boolean | ` false `
string | ` false `
number | ` false `
object | result of function ` object_t : : empty ( ) `
array | result of function ` array_t : : empty ( ) `
@ liveexample { The following code uses ` empty ( ) ` to check if a JSON
object contains any elements . , empty }
@ complexity Constant , as long as @ ref array_t and @ ref object_t satisfy
the Container concept ; that is , their ` empty ( ) ` functions have constant
complexity .
@ iterators No changes .
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
@ note This function does not return whether a string stored as JSON value
is empty - it returns whether the JSON container itself is empty which is
false in the case of a string .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
- Has the semantics of ` begin ( ) = = end ( ) ` .
@ sa @ ref size ( ) - - returns the number of elements
@ since version 1.0 .0
*/
bool empty ( ) const noexcept
{
switch ( m_type )
{
case value_t : : null :
{
// null values are empty
return true ;
}
case value_t : : array :
{
// delegate call to array_t::empty()
return m_value . array - > empty ( ) ;
}
case value_t : : object :
{
// delegate call to object_t::empty()
return m_value . object - > empty ( ) ;
}
default :
{
// all other types are nonempty
return false ;
}
}
}
/*!
@ brief returns the number of elements
Returns the number of elements in a JSON value .
@ return The return value depends on the different types and is
defined as follows :
Value type | return value
- - - - - - - - - - - | - - - - - - - - - - - - -
null | ` 0 `
boolean | ` 1 `
string | ` 1 `
number | ` 1 `
object | result of function object_t : : size ( )
array | result of function array_t : : size ( )
@ liveexample { The following code calls ` size ( ) ` on the different value
types . , size }
@ complexity Constant , as long as @ ref array_t and @ ref object_t satisfy
the Container concept ; that is , their size ( ) functions have constant
complexity .
@ iterators No changes .
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
@ note This function does not return the length of a string stored as JSON
value - it returns the number of elements in the JSON value which is 1 in
the case of a string .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
- Has the semantics of ` std : : distance ( begin ( ) , end ( ) ) ` .
@ sa @ ref empty ( ) - - checks whether the container is empty
@ sa @ ref max_size ( ) - - returns the maximal number of elements
@ since version 1.0 .0
*/
size_type size ( ) const noexcept
{
switch ( m_type )
{
case value_t : : null :
{
// null values are empty
return 0 ;
}
case value_t : : array :
{
// delegate call to array_t::size()
return m_value . array - > size ( ) ;
}
case value_t : : object :
{
// delegate call to object_t::size()
return m_value . object - > size ( ) ;
}
default :
{
// all other types have size 1
return 1 ;
}
}
}
/*!
@ brief returns the maximum possible number of elements
Returns the maximum number of elements a JSON value is able to hold due to
system or library implementation limitations , i . e . ` std : : distance ( begin ( ) ,
end ( ) ) ` for the JSON value .
@ return The return value depends on the different types and is
defined as follows :
Value type | return value
- - - - - - - - - - - | - - - - - - - - - - - - -
null | ` 0 ` ( same as ` size ( ) ` )
boolean | ` 1 ` ( same as ` size ( ) ` )
string | ` 1 ` ( same as ` size ( ) ` )
number | ` 1 ` ( same as ` size ( ) ` )
object | result of function ` object_t : : max_size ( ) `
array | result of function ` array_t : : max_size ( ) `
@ liveexample { The following code calls ` max_size ( ) ` on the different value
types . Note the output is implementation specific . , max_size }
@ complexity Constant , as long as @ ref array_t and @ ref object_t satisfy
the Container concept ; that is , their ` max_size ( ) ` functions have constant
complexity .
@ iterators No changes .
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
@ requirement This function helps ` basic_json ` satisfying the
[ Container ] ( http : //en.cppreference.com/w/cpp/concept/Container)
requirements :
- The complexity is constant .
- Has the semantics of returning ` b . size ( ) ` where ` b ` is the largest
possible JSON value .
@ sa @ ref size ( ) - - returns the number of elements
@ since version 1.0 .0
*/
size_type max_size ( ) const noexcept
{
switch ( m_type )
{
case value_t : : array :
{
// delegate call to array_t::max_size()
return m_value . array - > max_size ( ) ;
}
case value_t : : object :
{
// delegate call to object_t::max_size()
return m_value . object - > max_size ( ) ;
}
default :
{
// all other types have max_size() == size()
return size ( ) ;
}
}
}
/// @}
///////////////
// modifiers //
///////////////
/// @name modifiers
/// @{
/*!
@ brief clears the contents
Clears the content of a JSON value and resets it to the default value as
if @ ref basic_json ( value_t ) would have been called with the current value
type from @ ref type ( ) :
Value type | initial value
- - - - - - - - - - - | - - - - - - - - - - - - -
null | ` null `
boolean | ` false `
string | ` " " `
number | ` 0 `
object | ` { } `
array | ` [ ] `
@ post Has the same effect as calling
@ code { . cpp }
* this = basic_json ( type ( ) ) ;
@ endcode
@ liveexample { The example below shows the effect of ` clear ( ) ` to different
JSON types . , clear }
@ complexity Linear in the size of the JSON value .
@ iterators All iterators , pointers and references related to this container
are invalidated .
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
@ sa @ ref basic_json ( value_t ) - - constructor that creates an object with the
same value than calling ` clear ( ) `
@ since version 1.0 .0
*/
void clear ( ) noexcept
{
switch ( m_type )
{
case value_t : : number_integer :
{
m_value . number_integer = 0 ;
break ;
}
case value_t : : number_unsigned :
{
m_value . number_unsigned = 0 ;
break ;
}
case value_t : : number_float :
{
m_value . number_float = 0.0 ;
break ;
}
case value_t : : boolean :
{
m_value . boolean = false ;
break ;
}
case value_t : : string :
{
m_value . string - > clear ( ) ;
break ;
}
case value_t : : array :
{
m_value . array - > clear ( ) ;
break ;
}
case value_t : : object :
{
m_value . object - > clear ( ) ;
break ;
}
default :
break ;
}
}
/*!
@ brief add an object to an array
Appends the given element @ a val to the end of the JSON value . If the
function is called on a JSON null value , an empty array is created before
appending @ a val .
@ param [ in ] val the value to add to the JSON array
@ throw type_error .308 when called on a type other than JSON array or
null ; example : ` " cannot use push_back() with number " `
@ complexity Amortized constant .
@ liveexample { The example shows how ` push_back ( ) ` and ` + = ` can be used to
add elements to a JSON array . Note how the ` null ` value was silently
converted to a JSON array . , push_back }
@ since version 1.0 .0
*/
void push_back ( basic_json & & val )
{
// push_back only works for null objects or arrays
if ( JSON_UNLIKELY ( not ( is_null ( ) or is_array ( ) ) ) )
{
JSON_THROW ( type_error : : create ( 308 , " cannot use push_back() with " + std : : string ( type_name ( ) ) ) ) ;
}
// transform null object into an array
if ( is_null ( ) )
{
m_type = value_t : : array ;
m_value = value_t : : array ;
assert_invariant ( ) ;
}
// add element to array (move semantics)
m_value . array - > push_back ( std : : move ( val ) ) ;
// invalidate object
val . m_type = value_t : : null ;
}
/*!
@ brief add an object to an array
@ copydoc push_back ( basic_json & & )
*/
reference operator + = ( basic_json & & val )
{
push_back ( std : : move ( val ) ) ;
return * this ;
}
/*!
@ brief add an object to an array
@ copydoc push_back ( basic_json & & )
*/
void push_back ( const basic_json & val )
{
// push_back only works for null objects or arrays
if ( JSON_UNLIKELY ( not ( is_null ( ) or is_array ( ) ) ) )
{
JSON_THROW ( type_error : : create ( 308 , " cannot use push_back() with " + std : : string ( type_name ( ) ) ) ) ;
}
// transform null object into an array
if ( is_null ( ) )
{
m_type = value_t : : array ;
m_value = value_t : : array ;
assert_invariant ( ) ;
}
// add element to array
m_value . array - > push_back ( val ) ;
}
/*!
@ brief add an object to an array
@ copydoc push_back ( basic_json & & )
*/
reference operator + = ( const basic_json & val )
{
push_back ( val ) ;
return * this ;
}
/*!
@ brief add an object to an object
Inserts the given element @ a val to the JSON object . If the function is
called on a JSON null value , an empty object is created before inserting
@ a val .
@ param [ in ] val the value to add to the JSON object
@ throw type_error .308 when called on a type other than JSON object or
null ; example : ` " cannot use push_back() with number " `
@ complexity Logarithmic in the size of the container , O ( log ( ` size ( ) ` ) ) .
@ liveexample { The example shows how ` push_back ( ) ` and ` + = ` can be used to
add elements to a JSON object . Note how the ` null ` value was silently
converted to a JSON object . , push_back__object_t__value }
@ since version 1.0 .0
*/
void push_back ( const typename object_t : : value_type & val )
{
// push_back only works for null objects or objects
if ( JSON_UNLIKELY ( not ( is_null ( ) or is_object ( ) ) ) )
{
JSON_THROW ( type_error : : create ( 308 , " cannot use push_back() with " + std : : string ( type_name ( ) ) ) ) ;
}
// transform null object into an object
if ( is_null ( ) )
{
m_type = value_t : : object ;
m_value = value_t : : object ;
assert_invariant ( ) ;
}
// add element to array
m_value . object - > insert ( val ) ;
}
/*!
@ brief add an object to an object
@ copydoc push_back ( const typename object_t : : value_type & )
*/
reference operator + = ( const typename object_t : : value_type & val )
{
push_back ( val ) ;
return * this ;
}
/*!
@ brief add an object to an object
This function allows to use ` push_back ` with an initializer list . In case
1. the current value is an object ,
2. the initializer list @ a init contains only two elements , and
3. the first element of @ a init is a string ,
@ a init is converted into an object element and added using
@ ref push_back ( const typename object_t : : value_type & ) . Otherwise , @ a init
is converted to a JSON value and added using @ ref push_back ( basic_json & & ) .
@ param [ in ] init an initializer list
@ complexity Linear in the size of the initializer list @ a init .
@ note This function is required to resolve an ambiguous overload error ,
because pairs like ` { " key " , " value " } ` can be both interpreted as
` object_t : : value_type ` or ` std : : initializer_list < basic_json > ` , see
https : //github.com/nlohmann/json/issues/235 for more information.
@ liveexample { The example shows how initializer lists are treated as
objects when possible . , push_back__initializer_list }
*/
void push_back ( initializer_list_t init )
{
if ( is_object ( ) and init . size ( ) = = 2 and ( * init . begin ( ) ) - > is_string ( ) )
{
basic_json & & key = init . begin ( ) - > moved_or_copied ( ) ;
push_back ( typename object_t : : value_type (
std : : move ( key . get_ref < string_t & > ( ) ) , ( init . begin ( ) + 1 ) - > moved_or_copied ( ) ) ) ;
}
else
{
push_back ( basic_json ( init ) ) ;
}
}
/*!
@ brief add an object to an object
@ copydoc push_back ( initializer_list_t )
*/
reference operator + = ( initializer_list_t init )
{
push_back ( init ) ;
return * this ;
}
/*!
@ brief add an object to an array
Creates a JSON value from the passed parameters @ a args to the end of the
JSON value . If the function is called on a JSON null value , an empty array
is created before appending the value created from @ a args .
@ param [ in ] args arguments to forward to a constructor of @ ref basic_json
@ tparam Args compatible types to create a @ ref basic_json object
@ throw type_error .311 when called on a type other than JSON array or
null ; example : ` " cannot use emplace_back() with number " `
@ complexity Amortized constant .
@ liveexample { The example shows how ` push_back ( ) ` can be used to add
elements to a JSON array . Note how the ` null ` value was silently converted
to a JSON array . , emplace_back }
@ since version 2.0 .8
*/
template < class . . . Args >
void emplace_back ( Args & & . . . args )
{
// emplace_back only works for null objects or arrays
if ( JSON_UNLIKELY ( not ( is_null ( ) or is_array ( ) ) ) )
{
JSON_THROW ( type_error : : create ( 311 , " cannot use emplace_back() with " + std : : string ( type_name ( ) ) ) ) ;
}
// transform null object into an array
if ( is_null ( ) )
{
m_type = value_t : : array ;
m_value = value_t : : array ;
assert_invariant ( ) ;
}
// add element to array (perfect forwarding)
m_value . array - > emplace_back ( std : : forward < Args > ( args ) . . . ) ;
}
/*!
@ brief add an object to an object if key does not exist
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts a new element into a JSON object constructed in - place with the
given @ a args if there is no element with the key in the container . If the
function is called on a JSON null value , an empty object is created before
appending the value created from @ a args .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] args arguments to forward to a constructor of @ ref basic_json
@ tparam Args compatible types to create a @ ref basic_json object
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return a pair consisting of an iterator to the inserted element , or the
already - existing element if no insertion happened , and a bool
denoting whether the insertion took place .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .311 when called on a type other than JSON object or
null ; example : ` " cannot use emplace() with number " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Logarithmic in the size of the container , O ( log ( ` size ( ) ` ) ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` emplace ( ) ` can be used to add elements
to a JSON object . Note how the ` null ` value was silently converted to a
JSON object . Further note how no value is added if there was already one
value stored with the same key . , emplace }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .8
*/
template < class . . . Args >
std : : pair < iterator , bool > emplace ( Args & & . . . args )
{
// emplace only works for null objects or arrays
if ( JSON_UNLIKELY ( not ( is_null ( ) or is_object ( ) ) ) )
{
JSON_THROW ( type_error : : create ( 311 , " cannot use emplace() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// transform null object into an object
if ( is_null ( ) )
{
m_type = value_t : : object ;
m_value = value_t : : object ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// add element to array (perfect forwarding)
auto res = m_value . object - > emplace ( std : : forward < Args > ( args ) . . . ) ;
// create result iterator and set iterator to the result of emplace
auto it = begin ( ) ;
it . m_it . object_iterator = res . first ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// return pair of iterator and boolean
return { it , res . second } ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief inserts element
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts element @ a val before iterator @ a pos .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] pos iterator before which the content will be inserted ; may be
the end ( ) iterator
@ param [ in ] val element to insert
@ return iterator pointing to the inserted @ a val .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .309 if called on JSON values other than arrays ;
example : ` " cannot use insert() with string " `
@ throw invalid_iterator .202 if @ a pos is not an iterator of * this ;
example : ` " iterator does not fit current value " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant plus linear in the distance between @ a pos and end of
the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` insert ( ) ` is used . , insert }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
iterator insert ( const_iterator pos , const basic_json & val )
{
// insert only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
{
// check if iterator pos fits to this JSON value
if ( JSON_UNLIKELY ( pos . m_object ! = this ) )
{
JSON_THROW ( invalid_iterator : : create ( 202 , " iterator does not fit current value " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// insert to array and return iterator
iterator result ( this ) ;
result . m_it . array_iterator = m_value . array - > insert ( pos . m_it . array_iterator , val ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 309 , " cannot use insert() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief inserts element
@ copydoc insert ( const_iterator , const basic_json & )
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
iterator insert ( const_iterator pos , basic_json & & val )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return insert ( pos , val ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief inserts elements
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts @ a cnt copies of @ a val before iterator @ a pos .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] pos iterator before which the content will be inserted ; may be
the end ( ) iterator
@ param [ in ] cnt number of copies of @ a val to insert
@ param [ in ] val element to insert
@ return iterator pointing to the first element inserted , or @ a pos if
` cnt = = 0 `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .309 if called on JSON values other than arrays ; example :
` " cannot use insert() with string " `
@ throw invalid_iterator .202 if @ a pos is not an iterator of * this ;
example : ` " iterator does not fit current value " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in @ a cnt plus linear in the distance between @ a pos
and end of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` insert ( ) ` is used . , insert__count }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
iterator insert ( const_iterator pos , size_type cnt , const basic_json & val )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// insert only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
{
// check if iterator pos fits to this JSON value
if ( JSON_UNLIKELY ( pos . m_object ! = this ) )
{
JSON_THROW ( invalid_iterator : : create ( 202 , " iterator does not fit current value " ) ) ;
}
// insert to array and return iterator
iterator result ( this ) ;
result . m_it . array_iterator = m_value . array - > insert ( pos . m_it . array_iterator , cnt , val ) ;
return result ;
}
JSON_THROW ( type_error : : create ( 309 , " cannot use insert() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief inserts elements
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts elements from range ` [ first , last ) ` before iterator @ a pos .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] pos iterator before which the content will be inserted ; may be
the end ( ) iterator
@ param [ in ] first begin of the range of elements to insert
@ param [ in ] last end of the range of elements to insert
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .309 if called on JSON values other than arrays ; example :
` " cannot use insert() with string " `
@ throw invalid_iterator .202 if @ a pos is not an iterator of * this ;
example : ` " iterator does not fit current value " `
@ throw invalid_iterator .210 if @ a first and @ a last do not belong to the
same JSON value ; example : ` " iterators do not fit " `
@ throw invalid_iterator .211 if @ a first or @ a last are iterators into
container for which insert is called ; example : ` " passed iterators may not
belong to container " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return iterator pointing to the first element inserted , or @ a pos if
` first = = last `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in ` std : : distance ( first , last ) ` plus linear in the
distance between @ a pos and end of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` insert ( ) ` is used . , insert__range }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
iterator insert ( const_iterator pos , const_iterator first , const_iterator last )
{
// insert only works for arrays
if ( JSON_UNLIKELY ( not is_array ( ) ) )
{
JSON_THROW ( type_error : : create ( 309 , " cannot use insert() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if iterator pos fits to this JSON value
if ( JSON_UNLIKELY ( pos . m_object ! = this ) )
{
JSON_THROW ( invalid_iterator : : create ( 202 , " iterator does not fit current value " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if range iterators belong to the same JSON object
if ( JSON_UNLIKELY ( first . m_object ! = last . m_object ) )
{
JSON_THROW ( invalid_iterator : : create ( 210 , " iterators do not fit " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( first . m_object = = this ) )
{
JSON_THROW ( invalid_iterator : : create ( 211 , " passed iterators may not belong to container " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// insert to array and return iterator
iterator result ( this ) ;
result . m_it . array_iterator = m_value . array - > insert (
pos . m_it . array_iterator ,
first . m_it . array_iterator ,
last . m_it . array_iterator ) ;
return result ;
2017-07-18 05:37:27 +02:00
}
/*!
2018-05-19 21:59:03 +02:00
@ brief inserts elements
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts elements from initializer list @ a ilist before iterator @ a pos .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] pos iterator before which the content will be inserted ; may be
the end ( ) iterator
@ param [ in ] ilist initializer list to insert the values from
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .309 if called on JSON values other than arrays ; example :
` " cannot use insert() with string " `
@ throw invalid_iterator .202 if @ a pos is not an iterator of * this ;
example : ` " iterator does not fit current value " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return iterator pointing to the first element inserted , or @ a pos if
` ilist ` is empty
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in ` ilist . size ( ) ` plus linear in the distance between
@ a pos and end of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` insert ( ) ` is used . , insert__ilist }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
iterator insert ( const_iterator pos , initializer_list_t ilist )
{
// insert only works for arrays
if ( JSON_UNLIKELY ( not is_array ( ) ) )
{
JSON_THROW ( type_error : : create ( 309 , " cannot use insert() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if iterator pos fits to this JSON value
if ( JSON_UNLIKELY ( pos . m_object ! = this ) )
{
JSON_THROW ( invalid_iterator : : create ( 202 , " iterator does not fit current value " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// insert to array and return iterator
iterator result ( this ) ;
result . m_it . array_iterator = m_value . array - > insert ( pos . m_it . array_iterator , ilist . begin ( ) , ilist . end ( ) ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief inserts elements
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts elements from range ` [ first , last ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] first begin of the range of elements to insert
@ param [ in ] last end of the range of elements to insert
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .309 if called on JSON values other than objects ; example :
` " cannot use insert() with string " `
@ throw invalid_iterator .202 if iterator @ a first or @ a last does does not
point to an object ; example : ` " iterators first and last must point to
objects " `
@ throw invalid_iterator .210 if @ a first and @ a last do not belong to the
same JSON value ; example : ` " iterators do not fit " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Logarithmic : ` O ( N * log ( size ( ) + N ) ) ` , where ` N ` is the number
of elements to insert .
@ liveexample { The example shows how ` insert ( ) ` is used . , insert__range_object }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 3.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
void insert ( const_iterator first , const_iterator last )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
// insert only works for objects
if ( JSON_UNLIKELY ( not is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 309 , " cannot use insert() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// check if range iterators belong to the same JSON object
if ( JSON_UNLIKELY ( first . m_object ! = last . m_object ) )
{
JSON_THROW ( invalid_iterator : : create ( 210 , " iterators do not fit " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// passed iterators must belong to objects
if ( JSON_UNLIKELY ( not first . m_object - > is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( invalid_iterator : : create ( 202 , " iterators first and last must point to objects " ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
m_value . object - > insert ( first . m_it . object_iterator , last . m_it . object_iterator ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief updates a JSON object from another object , overwriting existing keys
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts all values from JSON object @ a j and overwrites existing keys .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] j JSON object to read values from
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .312 if called on JSON values other than objects ; example :
` " cannot use update() with string " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity O ( N * log ( size ( ) + N ) ) , where N is the number of elements to
insert .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` update ( ) ` is used . , update }
@ sa https : //docs.python.org/3.6/library/stdtypes.html#dict.update
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 3.0 .0
*/
void update ( const_reference j )
{
// implicitly convert null value to an empty object
if ( is_null ( ) )
{
m_type = value_t : : object ;
m_value . object = create < object_t > ( ) ;
assert_invariant ( ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not is_object ( ) ) )
{
JSON_THROW ( type_error : : create ( 312 , " cannot use update() with " + std : : string ( type_name ( ) ) ) ) ;
}
if ( JSON_UNLIKELY ( not j . is_object ( ) ) )
{
JSON_THROW ( type_error : : create ( 312 , " cannot use update() with " + std : : string ( j . type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
for ( auto it = j . cbegin ( ) ; it ! = j . cend ( ) ; + + it )
{
m_value . object - > operator [ ] ( it . key ( ) ) = it . value ( ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief updates a JSON object from another object , overwriting existing keys
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Inserts all values from from range ` [ first , last ) ` and overwrites existing
keys .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] first begin of the range of elements to insert
@ param [ in ] last end of the range of elements to insert
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .312 if called on JSON values other than objects ; example :
` " cannot use update() with string " `
@ throw invalid_iterator .202 if iterator @ a first or @ a last does does not
point to an object ; example : ` " iterators first and last must point to
objects " `
@ throw invalid_iterator .210 if @ a first and @ a last do not belong to the
same JSON value ; example : ` " iterators do not fit " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity O ( N * log ( size ( ) + N ) ) , where N is the number of elements to
insert .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows how ` update ( ) ` is used__range . , update }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa https : //docs.python.org/3.6/library/stdtypes.html#dict.update
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 3.0 .0
*/
void update ( const_iterator first , const_iterator last )
{
// implicitly convert null value to an empty object
if ( is_null ( ) )
{
m_type = value_t : : object ;
m_value . object = create < object_t > ( ) ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not is_object ( ) ) )
{
JSON_THROW ( type_error : : create ( 312 , " cannot use update() with " + std : : string ( type_name ( ) ) ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// check if range iterators belong to the same JSON object
if ( JSON_UNLIKELY ( first . m_object ! = last . m_object ) )
{
JSON_THROW ( invalid_iterator : : create ( 210 , " iterators do not fit " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// passed iterators must belong to objects
if ( JSON_UNLIKELY ( not first . m_object - > is_object ( )
or not last . m_object - > is_object ( ) ) )
{
JSON_THROW ( invalid_iterator : : create ( 202 , " iterators first and last must point to objects " ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
for ( auto it = first ; it ! = last ; + + it )
{
m_value . object - > operator [ ] ( it . key ( ) ) = it . value ( ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief exchanges the values
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exchanges the contents of the JSON value with those of @ a other . Does not
invoke any move , copy , or swap operations on individual elements . All
iterators and references remain valid . The past - the - end iterator is
invalidated .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] other JSON value to exchange the contents with
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how JSON values can be swapped with
` swap ( ) ` . , swap__reference }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
void swap ( reference other ) noexcept (
std : : is_nothrow_move_constructible < value_t > : : value and
std : : is_nothrow_move_assignable < value_t > : : value and
std : : is_nothrow_move_constructible < json_value > : : value and
std : : is_nothrow_move_assignable < json_value > : : value
)
{
std : : swap ( m_type , other . m_type ) ;
std : : swap ( m_value , other . m_value ) ;
assert_invariant ( ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief exchanges the values
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exchanges the contents of a JSON array with those of @ a other . Does not
invoke any move , copy , or swap operations on individual elements . All
iterators and references remain valid . The past - the - end iterator is
invalidated .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] other array to exchange the contents with
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .310 when JSON value is not an array ; example : ` " cannot
use swap ( ) with string " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how arrays can be swapped with
` swap ( ) ` . , swap__array_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
void swap ( array_t & other )
{
// swap only works for arrays
if ( JSON_LIKELY ( is_array ( ) ) )
{
std : : swap ( * ( m_value . array ) , other ) ;
}
else
{
JSON_THROW ( type_error : : create ( 310 , " cannot use swap() with " + std : : string ( type_name ( ) ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief exchanges the values
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Exchanges the contents of a JSON object with those of @ a other . Does not
invoke any move , copy , or swap operations on individual elements . All
iterators and references remain valid . The past - the - end iterator is
invalidated .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] other object to exchange the contents with
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .310 when JSON value is not an object ; example :
` " cannot use swap() with string " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how objects can be swapped with
` swap ( ) ` . , swap__object_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
void swap ( object_t & other )
{
// swap only works for objects
if ( JSON_LIKELY ( is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
std : : swap ( * ( m_value . object ) , other ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
JSON_THROW ( type_error : : create ( 310 , " cannot use swap() with " + std : : string ( type_name ( ) ) ) ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief exchanges the values
Exchanges the contents of a JSON string with those of @ a other . Does not
invoke any move , copy , or swap operations on individual elements . All
iterators and references remain valid . The past - the - end iterator is
invalidated .
@ param [ in , out ] other string to exchange the contents with
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .310 when JSON value is not a string ; example : ` " cannot
use swap ( ) with boolean " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how strings can be swapped with
` swap ( ) ` . , swap__string_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
void swap ( string_t & other )
{
// swap only works for strings
if ( JSON_LIKELY ( is_string ( ) ) )
{
std : : swap ( * ( m_value . string ) , other ) ;
}
else
{
JSON_THROW ( type_error : : create ( 310 , " cannot use swap() with " + std : : string ( type_name ( ) ) ) ) ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
//////////////////////////////////////////
// lexicographical comparison operators //
//////////////////////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name lexicographical comparison operators
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : equal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Compares two JSON values for equality according to the following rules :
- Two JSON values are equal if ( 1 ) they are from the same type and ( 2 )
their stored values are the same according to their respective
` operator = = ` .
- Integer and floating - point numbers are automatically converted before
comparison . Note than two NaN values are always treated as unequal .
- Two JSON null values are equal .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Floating - point inside JSON values numbers are compared with
` json : : number_float_t : : operator = = ` which is ` double : : operator = = ` by
default . To compare floating - point while respecting an epsilon , an alternative
[ comparison function ] ( https : //github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)
could be used , for instance
@ code { . cpp }
template < typename T , typename = typename std : : enable_if < std : : is_floating_point < T > : : value , T > : : type >
inline bool is_same ( T a , T b , T epsilon = std : : numeric_limits < T > : : epsilon ( ) ) noexcept
{
return std : : abs ( a - b ) < = epsilon ;
}
@ endcode
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note NaN values never compare equal to themselves or to other NaN values .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] lhs first JSON value to consider
@ param [ in ] rhs second JSON value to consider
@ return whether the values @ a lhs and @ a rhs are equal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example demonstrates comparing several JSON
types . , operator__equal }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
friend bool operator = = ( const_reference lhs , const_reference rhs ) noexcept
{
const auto lhs_type = lhs . type ( ) ;
const auto rhs_type = rhs . type ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( lhs_type = = rhs_type )
{
switch ( lhs_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : array :
return ( * lhs . m_value . array = = * rhs . m_value . array ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
return ( * lhs . m_value . object = = * rhs . m_value . object ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : null :
return true ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : string :
return ( * lhs . m_value . string = = * rhs . m_value . string ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : boolean :
return ( lhs . m_value . boolean = = rhs . m_value . boolean ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_integer :
return ( lhs . m_value . number_integer = = rhs . m_value . number_integer ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_unsigned :
return ( lhs . m_value . number_unsigned = = rhs . m_value . number_unsigned ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : number_float :
return ( lhs . m_value . number_float = = rhs . m_value . number_float ) ;
2017-07-18 05:37:27 +02:00
default :
2018-05-19 21:59:03 +02:00
return false ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
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 ) ;
}
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 ) ) ;
}
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 ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
return false ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : equal
@ copydoc operator = = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator = = ( const_reference lhs , const ScalarType rhs ) noexcept
{
return ( lhs = = basic_json ( rhs ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : equal
@ copydoc operator = = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator = = ( const ScalarType lhs , const_reference rhs ) noexcept
{
return ( basic_json ( lhs ) = = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : not equal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Compares two JSON values for inequality by calculating ` not ( lhs = = rhs ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] lhs first JSON value to consider
@ param [ in ] rhs second JSON value to consider
@ return whether the values @ a lhs and @ a rhs are not equal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example demonstrates comparing several JSON
types . , operator__notequal }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
friend bool operator ! = ( const_reference lhs , const_reference rhs ) noexcept
{
return not ( lhs = = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : not equal
@ copydoc operator ! = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator ! = ( const_reference lhs , const ScalarType rhs ) noexcept
{
return ( lhs ! = basic_json ( rhs ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : not equal
@ copydoc operator ! = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator ! = ( const ScalarType lhs , const_reference rhs ) noexcept
{
return ( basic_json ( lhs ) ! = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Compares whether one JSON value @ a lhs is less than another JSON value @ a
rhs according to the following rules :
- If @ a lhs and @ a rhs have the same type , the values are compared using
the default ` < ` operator .
- Integer and floating - point numbers are automatically converted before
comparison
- In case @ a lhs and @ a rhs have different types , the values are ignored
and the order of the types is considered , see
@ ref operator < ( const value_t , const value_t ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] lhs first JSON value to consider
@ param [ in ] rhs second JSON value to consider
@ return whether @ a lhs is less than @ a rhs
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example demonstrates comparing several JSON
types . , operator__less }
@ since version 1.0 .0
*/
friend bool operator < ( const_reference lhs , const_reference rhs ) noexcept
{
const auto lhs_type = lhs . type ( ) ;
const auto rhs_type = rhs . type ( ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
if ( lhs_type = = rhs_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( lhs_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : array :
return ( * lhs . m_value . array ) < ( * rhs . m_value . array ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : object :
return * lhs . m_value . object < * rhs . m_value . object ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
case value_t : : null :
return false ;
case value_t : : string :
return * lhs . m_value . string < * rhs . m_value . string ;
case value_t : : boolean :
return lhs . m_value . boolean < rhs . m_value . boolean ;
case value_t : : number_integer :
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 ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
default :
return false ;
}
}
else if ( lhs_type = = value_t : : number_integer and rhs_type = = value_t : : number_float )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return static_cast < number_float_t > ( lhs . m_value . number_integer ) < rhs . m_value . number_float ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( lhs_type = = value_t : : number_float and rhs_type = = value_t : : number_integer )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return lhs . m_value . number_float < static_cast < number_float_t > ( rhs . m_value . number_integer ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( lhs_type = = value_t : : number_unsigned and rhs_type = = value_t : : number_float )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return static_cast < number_float_t > ( lhs . m_value . number_unsigned ) < rhs . m_value . number_float ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( lhs_type = = value_t : : number_float and rhs_type = = value_t : : number_unsigned )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return lhs . m_value . number_float < static_cast < number_float_t > ( rhs . m_value . number_unsigned ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( lhs_type = = value_t : : number_integer and rhs_type = = value_t : : number_unsigned )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return lhs . m_value . number_integer < static_cast < number_integer_t > ( rhs . m_value . number_unsigned ) ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
else if ( lhs_type = = value_t : : number_unsigned and rhs_type = = value_t : : number_integer )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return static_cast < number_integer_t > ( lhs . m_value . number_unsigned ) < rhs . m_value . number_integer ;
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
// We only reach this line if we cannot compare values. In that case,
// we compare types. Note we have to call the operator explicitly,
// because MSVC has problems otherwise.
return operator < ( lhs_type , rhs_type ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than
@ copydoc operator < ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator < ( const_reference lhs , const ScalarType rhs ) noexcept
{
return ( lhs < basic_json ( rhs ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than
@ copydoc operator < ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator < ( const ScalarType lhs , const_reference rhs ) noexcept
{
return ( basic_json ( lhs ) < rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than or equal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Compares whether one JSON value @ a lhs is less than or equal to another
JSON value by calculating ` not ( rhs < lhs ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] lhs first JSON value to consider
@ param [ in ] rhs second JSON value to consider
@ return whether @ a lhs is less than or equal to @ a rhs
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example demonstrates comparing several JSON
types . , operator__greater }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
friend bool operator < = ( const_reference lhs , const_reference rhs ) noexcept
{
return not ( rhs < lhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than or equal
@ copydoc operator < = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator < = ( const_reference lhs , const ScalarType rhs ) noexcept
{
return ( lhs < = basic_json ( rhs ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : less than or equal
@ copydoc operator < = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator < = ( const ScalarType lhs , const_reference rhs ) noexcept
{
return ( basic_json ( lhs ) < = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Compares whether one JSON value @ a lhs is greater than another
JSON value by calculating ` not ( lhs < = rhs ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] lhs first JSON value to consider
@ param [ in ] rhs second JSON value to consider
@ return whether @ a lhs is greater than to @ a rhs
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example demonstrates comparing several JSON
types . , operator__lessequal }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
friend bool operator > ( const_reference lhs , const_reference rhs ) noexcept
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
return not ( lhs < = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than
@ copydoc operator > ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator > ( const_reference lhs , const ScalarType rhs ) noexcept
{
return ( lhs > basic_json ( rhs ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than
@ copydoc operator > ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator > ( const ScalarType lhs , const_reference rhs ) noexcept
{
return ( basic_json ( lhs ) > rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than or equal
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Compares whether one JSON value @ a lhs is greater than or equal to another
JSON value by calculating ` not ( lhs < rhs ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] lhs first JSON value to consider
@ param [ in ] rhs second JSON value to consider
@ return whether @ a lhs is greater than or equal to @ a rhs
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example demonstrates comparing several JSON
types . , operator__greaterequal }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
*/
friend bool operator > = ( const_reference lhs , const_reference rhs ) noexcept
{
return not ( lhs < rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than or equal
@ copydoc operator > = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator > = ( const_reference lhs , const ScalarType rhs ) noexcept
{
return ( lhs > = basic_json ( rhs ) ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief comparison : greater than or equal
@ copydoc operator > = ( const_reference , const_reference )
*/
template < typename ScalarType , typename std : : enable_if <
std : : is_scalar < ScalarType > : : value , int > : : type = 0 >
friend bool operator > = ( const ScalarType lhs , const_reference rhs ) noexcept
{
return ( basic_json ( lhs ) > = rhs ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
///////////////////
// serialization //
///////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name serialization
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief serialize to stream
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Serialize the given JSON value @ a j to the output stream @ a o . The JSON
value will be serialized using the @ ref dump member function .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
- The indentation of the output can be controlled with the member variable
` width ` of the output stream @ a o . For instance , using the manipulator
` std : : setw ( 4 ) ` on @ a o sets the indentation level to ` 4 ` and the
serialization result is the same as calling ` dump ( 4 ) ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
- The indentation character can be controlled with the member variable
` fill ` of the output stream @ a o . For instance , the manipulator
` std : : setfill ( ' \ \ t ' ) ` sets indentation to use a tab character rather than
the default space character .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] o stream to serialize to
@ param [ in ] j JSON value to serialize
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return the stream @ a o
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw type_error .316 if a string stored inside the JSON value is not
UTF - 8 encoded
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows the serialization with different
parameters to ` width ` to adjust the indentation level . , operator_serialize }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0 ; indentation character added in version 3.0 .0
*/
friend std : : ostream & operator < < ( std : : ostream & o , const basic_json & j )
{
// read width member and use it as indentation parameter if nonzero
const bool pretty_print = ( o . width ( ) > 0 ) ;
const auto indentation = ( pretty_print ? o . width ( ) : 0 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// reset width to 0 for subsequent calls to this stream
o . width ( 0 ) ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
// do the actual serialization
serializer s ( detail : : output_adapter < char > ( o ) , o . fill ( ) ) ;
s . dump ( j , pretty_print , false , static_cast < unsigned int > ( indentation ) ) ;
return o ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief serialize to stream
@ deprecated This stream operator is deprecated and will be removed in
future 4.0 .0 of the library . Please use
@ ref operator < < ( std : : ostream & , const basic_json & )
instead ; that is , replace calls like ` j > > o ; ` with ` o < < j ; ` .
@ since version 1.0 .0 ; deprecated since version 3.0 .0
*/
JSON_DEPRECATED
friend std : : ostream & operator > > ( const basic_json & j , std : : ostream & o )
{
return o < < j ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/////////////////////
// deserialization //
/////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name deserialization
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief deserialize from a compatible input
This function reads from a compatible input . Examples are :
- an array of 1 - byte values
- strings with character / literal type with size of 1 byte
- input streams
- container with contiguous storage of 1 - byte values . Compatible container
types include ` std : : vector ` , ` std : : string ` , ` std : : array ` ,
` std : : valarray ` , and ` std : : initializer_list ` . Furthermore , C - style
arrays can be used with ` std : : begin ( ) ` / ` std : : end ( ) ` . User - defined
containers can be used as long as they implement random - access iterators
and a contiguous storage .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre Each element of the container has a size of 1 byte . Violating this
precondition yields undefined behavior . * * This precondition is enforced
with a static assertion . * *
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The container storage is contiguous . Violating this precondition
yields undefined behavior . * * This precondition is enforced with an
assertion . * *
@ pre Each element of the container has a size of 1 byte . Violating this
precondition yields undefined behavior . * * This precondition is enforced
with a static assertion . * *
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning There is no way to enforce all preconditions at compile - time . If
the function is called with a noncompliant container and with
assertions switched off , the behavior is undefined and will most
likely yield segmentation violation .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] i input to read from
@ param [ in ] cb a parser callback function of type @ ref parser_callback_t
which is used to control the deserialization by filtering unwanted values
( optional )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return result of the deserialization
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .101 if a parse error occurs ; example : ` " " unexpected end
of input ; expected string literal " " `
@ throw parse_error .102 if to_unicode fails or surrogate error
@ throw parse_error .103 if to_unicode fails
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the length of the input . The parser is a predictive
LL ( 1 ) parser . The complexity can be higher if the parser callback function
@ a cb has a super - linear complexity .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note A UTF - 8 byte order mark is silently ignored .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below demonstrates the ` parse ( ) ` function reading
from an array . , parse__array__parser_callback_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below demonstrates the ` parse ( ) ` function with
and without callback function . , parse__string__parser_callback_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below demonstrates the ` parse ( ) ` function with
and without callback function . , parse__istream__parser_callback_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below demonstrates the ` parse ( ) ` function reading
from a contiguous container . , parse__contiguouscontainer__parser_callback_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .3 ( contiguous containers )
*/
static basic_json parse ( detail : : input_adapter i ,
const parser_callback_t cb = nullptr ,
const bool allow_exceptions = true )
{
basic_json result ;
parser ( i , cb , allow_exceptions ) . parse ( true , result ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ copydoc basic_json parse ( detail : : input_adapter , const parser_callback_t )
*/
static basic_json parse ( detail : : input_adapter & i ,
const parser_callback_t cb = nullptr ,
const bool allow_exceptions = true )
{
basic_json result ;
parser ( i , cb , allow_exceptions ) . parse ( true , result ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static bool accept ( detail : : input_adapter i )
{
return parser ( i ) . accept ( true ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static bool accept ( detail : : input_adapter & i )
{
return parser ( i ) . accept ( true ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief deserialize from an iterator range with contiguous storage
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
This function reads from an iterator range of a container with contiguous
storage of 1 - byte values . Compatible container types include
` std : : vector ` , ` std : : string ` , ` std : : array ` , ` std : : valarray ` , and
` std : : initializer_list ` . Furthermore , C - style arrays can be used with
` std : : begin ( ) ` / ` std : : end ( ) ` . User - defined containers can be used as long
as they implement random - access iterators and a contiguous storage .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ pre The iterator range is contiguous . Violating this precondition yields
undefined behavior . * * This precondition is enforced with an assertion . * *
@ pre Each element in the range has a size of 1 byte . Violating this
precondition yields undefined behavior . * * This precondition is enforced
with a static assertion . * *
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning There is no way to enforce all preconditions at compile - time . If
the function is called with noncompliant iterators and with
assertions switched off , the behavior is undefined and will most
likely yield segmentation violation .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ tparam IteratorType iterator of container with contiguous storage
@ param [ in ] first begin of the range to parse ( included )
@ param [ in ] last end of the range to parse ( excluded )
@ param [ in ] cb a parser callback function of type @ ref parser_callback_t
which is used to control the deserialization by filtering unwanted values
( optional )
@ param [ in ] allow_exceptions whether to throw exceptions in case of a
parse error ( optional , true by default )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return result of the deserialization
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .101 in case of an unexpected token
@ throw parse_error .102 if to_unicode fails or surrogate error
@ throw parse_error .103 if to_unicode fails
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the length of the input . The parser is a predictive
LL ( 1 ) parser . The complexity can be higher if the parser callback function
@ a cb has a super - linear complexity .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note A UTF - 8 byte order mark is silently ignored .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below demonstrates the ` parse ( ) ` function reading
from an iterator range . , parse__iteratortype__parser_callback_t }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .3
*/
template < class IteratorType , typename std : : enable_if <
std : : is_base_of <
std : : random_access_iterator_tag ,
typename std : : iterator_traits < IteratorType > : : iterator_category > : : value , int > : : type = 0 >
static basic_json parse ( IteratorType first , IteratorType last ,
const parser_callback_t cb = nullptr ,
const bool allow_exceptions = true )
{
basic_json result ;
parser ( detail : : input_adapter ( first , last ) , cb , allow_exceptions ) . parse ( true , result ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < class IteratorType , typename std : : enable_if <
std : : is_base_of <
std : : random_access_iterator_tag ,
typename std : : iterator_traits < IteratorType > : : iterator_category > : : value , int > : : type = 0 >
static bool accept ( IteratorType first , IteratorType last )
{
return parser ( detail : : input_adapter ( first , last ) ) . accept ( true ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief deserialize from stream
@ deprecated This stream operator is deprecated and will be removed in
version 4.0 .0 of the library . Please use
@ ref operator > > ( std : : istream & , basic_json & )
instead ; that is , replace calls like ` j < < i ; ` with ` i > > j ; ` .
@ since version 1.0 .0 ; deprecated since version 3.0 .0
*/
JSON_DEPRECATED
friend std : : istream & operator < < ( basic_json & j , std : : istream & i )
{
return operator > > ( i , j ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief deserialize from stream
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Deserializes an input stream to a JSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in , out ] i input stream to read a serialized JSON value from
@ param [ in , out ] j JSON value to write the deserialized input to
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .101 in case of an unexpected token
@ throw parse_error .102 if to_unicode fails or surrogate error
@ throw parse_error .103 if to_unicode fails
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the length of the input . The parser is a predictive
LL ( 1 ) parser .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note A UTF - 8 byte order mark is silently ignored .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example below shows how a JSON value is constructed by
reading a serialization from a stream . , operator_deserialize }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa parse ( std : : istream & , const parser_callback_t ) for a variant with a
parser callback function to filter values while parsing
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0
2017-07-18 05:37:27 +02:00
*/
2018-05-19 21:59:03 +02:00
friend std : : istream & operator > > ( std : : istream & i , basic_json & j )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
parser ( detail : : input_adapter ( i ) ) . parse ( false , j ) ;
return i ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
///////////////////////////
// convenience functions //
///////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief return the type as string
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Returns the type name as string to be used in error messages - usually to
indicate that a function was called on a wrong JSON type .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ return a string representation of a the @ a m_type member :
Value type | return value
- - - - - - - - - - - | - - - - - - - - - - - - -
null | ` " null " `
boolean | ` " boolean " `
string | ` " string " `
number | ` " number " ` ( for all number types )
object | ` " object " `
array | ` " array " `
discarded | ` " discarded " `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ exceptionsafety No - throw guarantee : this function never throws exceptions .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Constant .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The following code exemplifies ` type_name ( ) ` for all JSON
types . , type_name }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref type ( ) - - return the type of the JSON value
@ sa @ ref operator value_t ( ) - - return the type of the JSON value ( implicit )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 1.0 .0 , public since 2.1 .0 , ` const char * ` and ` noexcept `
since 3.0 .0
*/
const char * type_name ( ) const noexcept
{
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
switch ( m_type )
2017-07-18 05:37:27 +02:00
{
2018-05-19 21:59:03 +02:00
case value_t : : null :
return " null " ;
case value_t : : object :
return " object " ;
case value_t : : array :
return " array " ;
case value_t : : string :
return " string " ;
case value_t : : boolean :
return " boolean " ;
case value_t : : discarded :
return " discarded " ;
default :
return " number " ;
}
2017-07-18 05:37:27 +02:00
}
2018-05-19 21:59:03 +02:00
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
private :
//////////////////////
// member variables //
//////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the type of the current element
value_t m_type = value_t : : null ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// the value of the current element
json_value m_value = { } ;
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
//////////////////////////////////////////
// binary serialization/deserialization //
//////////////////////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name binary serialization/deserialization support
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
public :
/*!
@ brief create a CBOR serialization of a given JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Serializes a given JSON value @ a j to a byte vector using the CBOR ( Concise
Binary Object Representation ) serialization format . CBOR is a binary
serialization format which aims to be more compact than JSON itself , yet
more efficient to parse .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The library uses the following mapping from JSON values types to
CBOR types according to the CBOR specification ( RFC 7049 ) :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON value type | value / range | CBOR type | first byte
- - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - -
null | ` null ` | Null | 0xF6
boolean | ` true ` | True | 0xF5
boolean | ` false ` | False | 0xF4
number_integer | - 9223372036854775808. . - 2147483649 | Negative integer ( 8 bytes follow ) | 0x3B
number_integer | - 2147483648. . - 32769 | Negative integer ( 4 bytes follow ) | 0x3A
number_integer | - 32768. . - 129 | Negative integer ( 2 bytes follow ) | 0x39
number_integer | - 128. . - 25 | Negative integer ( 1 byte follow ) | 0x38
number_integer | - 24. . - 1 | Negative integer | 0x20 . .0 x37
number_integer | 0. .23 | Integer | 0x00 . .0 x17
number_integer | 24. .255 | Unsigned integer ( 1 byte follow ) | 0x18
number_integer | 256. .65535 | Unsigned integer ( 2 bytes follow ) | 0x19
number_integer | 65536. .4294967295 | Unsigned integer ( 4 bytes follow ) | 0x1A
number_integer | 4294967296. .18446744073709551615 | Unsigned integer ( 8 bytes follow ) | 0x1B
number_unsigned | 0. .23 | Integer | 0x00 . .0 x17
number_unsigned | 24. .255 | Unsigned integer ( 1 byte follow ) | 0x18
number_unsigned | 256. .65535 | Unsigned integer ( 2 bytes follow ) | 0x19
number_unsigned | 65536. .4294967295 | Unsigned integer ( 4 bytes follow ) | 0x1A
number_unsigned | 4294967296. .18446744073709551615 | Unsigned integer ( 8 bytes follow ) | 0x1B
number_float | * any value * | Double - Precision Float | 0xFB
string | * length * : 0. .23 | UTF - 8 string | 0x60 . .0 x77
string | * length * : 23. .255 | UTF - 8 string ( 1 byte follow ) | 0x78
string | * length * : 256. .65535 | UTF - 8 string ( 2 bytes follow ) | 0x79
string | * length * : 65536. .4294967295 | UTF - 8 string ( 4 bytes follow ) | 0x7A
string | * length * : 4294967296. .18446744073709551615 | UTF - 8 string ( 8 bytes follow ) | 0x7B
array | * size * : 0. .23 | array | 0x80 . .0 x97
array | * size * : 23. .255 | array ( 1 byte follow ) | 0x98
array | * size * : 256. .65535 | array ( 2 bytes follow ) | 0x99
array | * size * : 65536. .4294967295 | array ( 4 bytes follow ) | 0x9A
array | * size * : 4294967296. .18446744073709551615 | array ( 8 bytes follow ) | 0x9B
object | * size * : 0. .23 | map | 0xA0 . .0 xB7
object | * size * : 23. .255 | map ( 1 byte follow ) | 0xB8
object | * size * : 256. .65535 | map ( 2 bytes follow ) | 0xB9
object | * size * : 65536. .4294967295 | map ( 4 bytes follow ) | 0xBA
object | * size * : 4294967296. .18446744073709551615 | map ( 8 bytes follow ) | 0xBB
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The mapping is * * complete * * in the sense that any JSON value type
can be converted to a CBOR value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note If NaN or Infinity are stored inside a JSON number , they are
serialized properly . This behavior differs from the @ ref dump ( )
function which serializes NaN or Infinity to ` null ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The following CBOR types are not used in the conversion :
- byte strings ( 0x40 . .0 x5F )
- UTF - 8 strings terminated by " break " ( 0x7F )
- arrays terminated by " break " ( 0x9F )
- maps terminated by " break " ( 0xBF )
- date / time ( 0xC0 . .0 xC1 )
- bignum ( 0xC2 . .0 xC3 )
- decimal fraction ( 0xC4 )
- bigfloat ( 0xC5 )
- tagged items ( 0xC6 . .0 xD4 , 0xD8 . .0 xDB )
- expected conversions ( 0xD5 . .0 xD7 )
- simple values ( 0xE0 . .0 xF3 , 0xF8 )
- undefined ( 0xF7 )
- half and single - precision floats ( 0xF9 - 0xFA )
- break ( 0xFF )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] j JSON value to serialize
@ return MessagePack serialization as byte vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the JSON value @ a j .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the serialization of a JSON value to a byte
vector in CBOR format . , to_cbor }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa http : //cbor.io
@ sa @ ref from_cbor ( detail : : input_adapter , const bool strict ) for the
analogous deserialization
@ sa @ ref to_msgpack ( const basic_json & ) for the related MessagePack format
@ sa @ ref to_ubjson ( const basic_json & , const bool , const bool ) for the
related UBJSON format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .9
*/
static std : : vector < uint8_t > to_cbor ( const basic_json & j )
{
std : : vector < uint8_t > result ;
to_cbor ( j , result ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void to_cbor ( const basic_json & j , detail : : output_adapter < uint8_t > o )
{
binary_writer < uint8_t > ( o ) . write_cbor ( j ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void to_cbor ( const basic_json & j , detail : : output_adapter < char > o )
{
binary_writer < char > ( o ) . write_cbor ( j ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief create a MessagePack serialization of a given JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Serializes a given JSON value @ a j to a byte vector using the MessagePack
serialization format . MessagePack is a binary serialization format which
aims to be more compact than JSON itself , yet more efficient to parse .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The library uses the following mapping from JSON values types to
MessagePack types according to the MessagePack specification :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
JSON value type | value / range | MessagePack type | first byte
- - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - | - - - - - - - - - -
null | ` null ` | nil | 0xC0
boolean | ` true ` | true | 0xC3
boolean | ` false ` | false | 0xC2
number_integer | - 9223372036854775808. . - 2147483649 | int64 | 0xD3
number_integer | - 2147483648. . - 32769 | int32 | 0xD2
number_integer | - 32768. . - 129 | int16 | 0xD1
number_integer | - 128. . - 33 | int8 | 0xD0
number_integer | - 32. . - 1 | negative fixint | 0xE0 . .0 xFF
number_integer | 0. .127 | positive fixint | 0x00 . .0 x7F
number_integer | 128. .255 | uint 8 | 0xCC
number_integer | 256. .65535 | uint 16 | 0xCD
number_integer | 65536. .4294967295 | uint 32 | 0xCE
number_integer | 4294967296. .18446744073709551615 | uint 64 | 0xCF
number_unsigned | 0. .127 | positive fixint | 0x00 . .0 x7F
number_unsigned | 128. .255 | uint 8 | 0xCC
number_unsigned | 256. .65535 | uint 16 | 0xCD
number_unsigned | 65536. .4294967295 | uint 32 | 0xCE
number_unsigned | 4294967296. .18446744073709551615 | uint 64 | 0xCF
number_float | * any value * | float 64 | 0xCB
string | * length * : 0. .31 | fixstr | 0xA0 . .0 xBF
string | * length * : 32. .255 | str 8 | 0xD9
string | * length * : 256. .65535 | str 16 | 0xDA
string | * length * : 65536. .4294967295 | str 32 | 0xDB
array | * size * : 0. .15 | fixarray | 0x90 . .0 x9F
array | * size * : 16. .65535 | array 16 | 0xDC
array | * size * : 65536. .4294967295 | array 32 | 0xDD
object | * size * : 0. .15 | fix map | 0x80 . .0 x8F
object | * size * : 16. .65535 | map 16 | 0xDE
object | * size * : 65536. .4294967295 | map 32 | 0xDF
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The mapping is * * complete * * in the sense that any JSON value type
can be converted to a MessagePack value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The following values can * * not * * be converted to a MessagePack value :
- strings with more than 4294967295 bytes
- arrays with more than 4294967295 elements
- objects with more than 4294967295 elements
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The following MessagePack types are not used in the conversion :
- bin 8 - bin 32 ( 0xC4 . .0 xC6 )
- ext 8 - ext 32 ( 0xC7 . .0 xC9 )
- float 32 ( 0xCA )
- fixext 1 - fixext 16 ( 0xD4 . .0 xD8 )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Any MessagePack output created @ ref to_msgpack can be successfully
parsed by @ ref from_msgpack .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note If NaN or Infinity are stored inside a JSON number , they are
serialized properly . This behavior differs from the @ ref dump ( )
function which serializes NaN or Infinity to ` null ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] j JSON value to serialize
@ return MessagePack serialization as byte vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the JSON value @ a j .
@ liveexample { The example shows the serialization of a JSON value to a byte
vector in MessagePack format . , to_msgpack }
@ sa http : //msgpack.org
@ sa @ ref from_msgpack ( const std : : vector < uint8_t > & , const size_t ) for the
analogous deserialization
@ sa @ ref to_cbor ( const basic_json & for the related CBOR format
@ sa @ ref to_ubjson ( const basic_json & , const bool , const bool ) for the
related UBJSON format
@ since version 2.0 .9
*/
static std : : vector < uint8_t > to_msgpack ( const basic_json & j )
{
std : : vector < uint8_t > result ;
to_msgpack ( j , result ) ;
return result ;
}
static void to_msgpack ( const basic_json & j , detail : : output_adapter < uint8_t > o )
{
binary_writer < uint8_t > ( o ) . write_msgpack ( j ) ;
}
static void to_msgpack ( const basic_json & j , detail : : output_adapter < char > o )
{
binary_writer < char > ( o ) . write_msgpack ( j ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief create a UBJSON serialization of a given JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Serializes a given JSON value @ a j to a byte vector using the UBJSON
( Universal Binary JSON ) serialization format . UBJSON aims to be more compact
than JSON itself , yet more efficient to parse .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The library uses the following mapping from JSON values types to
UBJSON types according to the UBJSON specification :
JSON value type | value / range | UBJSON type | marker
- - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - | - - - - - -
null | ` null ` | null | ` Z `
boolean | ` true ` | true | ` T `
boolean | ` false ` | false | ` F `
number_integer | - 9223372036854775808. . - 2147483649 | int64 | ` L `
number_integer | - 2147483648. . - 32769 | int32 | ` l `
number_integer | - 32768. . - 129 | int16 | ` I `
number_integer | - 128. .127 | int8 | ` i `
number_integer | 128. .255 | uint8 | ` U `
number_integer | 256. .32767 | int16 | ` I `
number_integer | 32768. .2147483647 | int32 | ` l `
number_integer | 2147483648. .9223372036854775807 | int64 | ` L `
number_unsigned | 0. .127 | int8 | ` i `
number_unsigned | 128. .255 | uint8 | ` U `
number_unsigned | 256. .32767 | int16 | ` I `
number_unsigned | 32768. .2147483647 | int32 | ` l `
number_unsigned | 2147483648. .9223372036854775807 | int64 | ` L `
number_float | * any value * | float64 | ` D `
string | * with shortest length indicator * | string | ` S `
array | * see notes on optimized format * | array | ` [ `
object | * see notes on optimized format * | map | ` { `
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The mapping is * * complete * * in the sense that any JSON value type
can be converted to a UBJSON value .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The following values can * * not * * be converted to a UBJSON value :
- strings with more than 9223372036854775807 bytes ( theoretical )
- unsigned integer numbers above 9223372036854775807
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The following markers are not used in the conversion :
- ` Z ` : no - op values are not created .
- ` C ` : single - byte strings are serialized with ` S ` markers .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Any UBJSON output created @ ref to_ubjson can be successfully parsed
by @ ref from_ubjson .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note If NaN or Infinity are stored inside a JSON number , they are
serialized properly . This behavior differs from the @ ref dump ( )
function which serializes NaN or Infinity to ` null ` .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note The optimized formats for containers are supported : Parameter
@ a use_size adds size information to the beginning of a container and
removes the closing marker . Parameter @ a use_type further checks
whether all elements of a container have the same type and adds the
type marker to the beginning of the container . The @ a use_type
parameter must only be used together with @ a use_size = true . Note
that @ a use_size = true alone may result in larger representations -
the benefit of this parameter is that the receiving side is
immediately informed on the number of elements of the container .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] j JSON value to serialize
@ param [ in ] use_size whether to add size annotations to container types
@ param [ in ] use_type whether to add type annotations to container types
( must be combined with @ a use_size = true )
@ return UBJSON serialization as byte vector
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the JSON value @ a j .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the serialization of a JSON value to a byte
vector in UBJSON format . , to_ubjson }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa http : //ubjson.org
@ sa @ ref from_ubjson ( detail : : input_adapter , const bool strict ) for the
analogous deserialization
@ sa @ ref to_cbor ( const basic_json & for the related CBOR format
@ sa @ ref to_msgpack ( const basic_json & ) for the related MessagePack format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 3.1 .0
*/
static std : : vector < uint8_t > to_ubjson ( const basic_json & j ,
const bool use_size = false ,
const bool use_type = false )
{
std : : vector < uint8_t > result ;
to_ubjson ( j , result , use_size , use_type ) ;
return result ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void to_ubjson ( const basic_json & j , detail : : output_adapter < uint8_t > o ,
const bool use_size = false , const bool use_type = false )
{
binary_writer < uint8_t > ( o ) . write_ubjson ( j , use_size , use_type ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
static void to_ubjson ( const basic_json & j , detail : : output_adapter < char > o ,
const bool use_size = false , const bool use_type = false )
{
binary_writer < char > ( o ) . write_ubjson ( j , use_size , use_type ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief create a JSON value from an input in CBOR format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Deserializes a given input @ a i to a JSON value using the CBOR ( Concise
Binary Object Representation ) serialization format .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The library maps CBOR types to JSON value types as follows :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
CBOR type | JSON value type | first byte
- - - - - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - -
Integer | number_unsigned | 0x00 . .0 x17
Unsigned integer | number_unsigned | 0x18
Unsigned integer | number_unsigned | 0x19
Unsigned integer | number_unsigned | 0x1A
Unsigned integer | number_unsigned | 0x1B
Negative integer | number_integer | 0x20 . .0 x37
Negative integer | number_integer | 0x38
Negative integer | number_integer | 0x39
Negative integer | number_integer | 0x3A
Negative integer | number_integer | 0x3B
Negative integer | number_integer | 0x40 . .0 x57
UTF - 8 string | string | 0x60 . .0 x77
UTF - 8 string | string | 0x78
UTF - 8 string | string | 0x79
UTF - 8 string | string | 0x7A
UTF - 8 string | string | 0x7B
UTF - 8 string | string | 0x7F
array | array | 0x80 . .0 x97
array | array | 0x98
array | array | 0x99
array | array | 0x9A
array | array | 0x9B
array | array | 0x9F
map | object | 0xA0 . .0 xB7
map | object | 0xB8
map | object | 0xB9
map | object | 0xBA
map | object | 0xBB
map | object | 0xBF
False | ` false ` | 0xF4
True | ` true ` | 0xF5
Nill | ` null ` | 0xF6
Half - Precision Float | number_float | 0xF9
Single - Precision Float | number_float | 0xFA
Double - Precision Float | number_float | 0xFB
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning The mapping is * * incomplete * * in the sense that not all CBOR
types can be converted to a JSON value . The following CBOR types
are not supported and will yield parse errors ( parse_error .112 ) :
- byte strings ( 0x40 . .0 x5F )
- date / time ( 0xC0 . .0 xC1 )
- bignum ( 0xC2 . .0 xC3 )
- decimal fraction ( 0xC4 )
- bigfloat ( 0xC5 )
- tagged items ( 0xC6 . .0 xD4 , 0xD8 . .0 xDB )
- expected conversions ( 0xD5 . .0 xD7 )
- simple values ( 0xE0 . .0 xF3 , 0xF8 )
- undefined ( 0xF7 )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning CBOR allows map keys of any type , whereas JSON only allows
strings as keys in object values . Therefore , CBOR maps with keys
other than UTF - 8 strings are rejected ( parse_error .113 ) .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Any CBOR output created @ ref to_cbor can be successfully parsed by
@ ref from_cbor .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] i an input in CBOR format convertible to an input adapter
@ param [ in ] strict whether to expect the input to be consumed until EOF
( true by default )
@ return deserialized JSON value
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if the given input ends prematurely or the end of
file was not reached when @ a strict was set to true
@ throw parse_error .112 if unsupported features from CBOR were
used in the given input @ a v or if the input is not valid CBOR
@ throw parse_error .113 if a string was expected as map key , but not found
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the input @ a i .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the deserialization of a byte vector in CBOR
format to a JSON value . , from_cbor }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa http : //cbor.io
@ sa @ ref to_cbor ( const basic_json & ) for the analogous serialization
@ sa @ ref from_msgpack ( detail : : input_adapter , const bool ) for the
related MessagePack format
@ sa @ ref from_ubjson ( detail : : input_adapter , const bool ) for the related
UBJSON format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 2.0 .9 ; parameter @ a start_index since 2.1 .1 ; changed to
consume input adapters , removed start_index parameter , and added
@ a strict parameter since 3.0 .0
*/
static basic_json from_cbor ( detail : : input_adapter i ,
const bool strict = true )
{
return binary_reader ( i ) . parse_cbor ( strict ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ copydoc from_cbor ( detail : : input_adapter , const bool )
*/
template < typename A1 , typename A2 ,
detail : : enable_if_t < std : : is_constructible < detail : : input_adapter , A1 , A2 > : : value , int > = 0 >
static basic_json from_cbor ( A1 & & a1 , A2 & & a2 , const bool strict = true )
{
return binary_reader ( detail : : input_adapter ( std : : forward < A1 > ( a1 ) , std : : forward < A2 > ( a2 ) ) ) . parse_cbor ( strict ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief create a JSON value from an input in MessagePack format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
Deserializes a given input @ a i to a JSON value using the MessagePack
serialization format .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
The library maps MessagePack types to JSON value types as follows :
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
MessagePack type | JSON value type | first byte
- - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - | - - - - - - - - - -
positive fixint | number_unsigned | 0x00 . .0 x7F
fixmap | object | 0x80 . .0 x8F
fixarray | array | 0x90 . .0 x9F
fixstr | string | 0xA0 . .0 xBF
nil | ` null ` | 0xC0
false | ` false ` | 0xC2
true | ` true ` | 0xC3
float 32 | number_float | 0xCA
float 64 | number_float | 0xCB
uint 8 | number_unsigned | 0xCC
uint 16 | number_unsigned | 0xCD
uint 32 | number_unsigned | 0xCE
uint 64 | number_unsigned | 0xCF
int 8 | number_integer | 0xD0
int 16 | number_integer | 0xD1
int 32 | number_integer | 0xD2
int 64 | number_integer | 0xD3
str 8 | string | 0xD9
str 16 | string | 0xDA
str 32 | string | 0xDB
array 16 | array | 0xDC
array 32 | array | 0xDD
map 16 | object | 0xDE
map 32 | object | 0xDF
negative fixint | number_integer | 0xE0 - 0xFF
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ warning The mapping is * * incomplete * * in the sense that not all
MessagePack types can be converted to a JSON value . The following
MessagePack types are not supported and will yield parse errors :
- bin 8 - bin 32 ( 0xC4 . .0 xC6 )
- ext 8 - ext 32 ( 0xC7 . .0 xC9 )
- fixext 1 - fixext 16 ( 0xD4 . .0 xD8 )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ note Any MessagePack output created @ ref to_msgpack can be successfully
parsed by @ ref from_msgpack .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ param [ in ] i an input in MessagePack format convertible to an input
adapter
@ param [ in ] strict whether to expect the input to be consumed until EOF
( true by default )
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ throw parse_error .110 if the given input ends prematurely or the end of
file was not reached when @ a strict was set to true
@ throw parse_error .112 if unsupported features from MessagePack were
used in the given input @ a i or if the input is not valid MessagePack
@ throw parse_error .113 if a string was expected as map key , but not found
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ complexity Linear in the size of the input @ a i .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the deserialization of a byte vector in
MessagePack format to a JSON value . , from_msgpack }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa http : //msgpack.org
@ sa @ ref to_msgpack ( const basic_json & ) for the analogous serialization
@ sa @ ref from_cbor ( detail : : input_adapter , const bool ) for the related CBOR
format
@ sa @ ref from_ubjson ( detail : : input_adapter , const bool ) for the related
UBJSON format
@ since version 2.0 .9 ; parameter @ a start_index since 2.1 .1 ; changed to
consume input adapters , removed start_index parameter , and added
@ a strict parameter since 3.0 .0
*/
static basic_json from_msgpack ( detail : : input_adapter i ,
const bool strict = true )
{
return binary_reader ( i ) . parse_msgpack ( strict ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ copydoc from_msgpack ( detail : : input_adapter , const bool )
*/
template < typename A1 , typename A2 ,
detail : : enable_if_t < std : : is_constructible < detail : : input_adapter , A1 , A2 > : : value , int > = 0 >
static basic_json from_msgpack ( A1 & & a1 , A2 & & a2 , const bool strict = true )
{
return binary_reader ( detail : : input_adapter ( std : : forward < A1 > ( a1 ) , std : : forward < A2 > ( a2 ) ) ) . parse_msgpack ( strict ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief create a JSON value from an input in UBJSON format
Deserializes a given input @ a i to a JSON value using the UBJSON ( Universal
Binary JSON ) serialization format .
The library maps UBJSON types to JSON value types as follows :
UBJSON type | JSON value type | marker
- - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | - - - - - -
no - op | * no value , next value is read * | ` N `
null | ` null ` | ` Z `
false | ` false ` | ` F `
true | ` true ` | ` T `
float32 | number_float | ` d `
float64 | number_float | ` D `
uint8 | number_unsigned | ` U `
int8 | number_integer | ` i `
int16 | number_integer | ` I `
int32 | number_integer | ` l `
int64 | number_integer | ` L `
string | string | ` S `
char | string | ` C `
array | array ( optimized values are supported ) | ` [ `
object | object ( optimized values are supported ) | ` { `
@ note The mapping is * * complete * * in the sense that any UBJSON value can
be converted to a JSON value .
@ param [ in ] i an input in UBJSON format convertible to an input adapter
@ param [ in ] strict whether to expect the input to be consumed until EOF
( true by default )
@ throw parse_error .110 if the given input ends prematurely or the end of
file was not reached when @ a strict was set to true
@ throw parse_error .112 if a parse error occurs
@ throw parse_error .113 if a string could not be parsed successfully
@ complexity Linear in the size of the input @ a i .
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ liveexample { The example shows the deserialization of a byte vector in
UBJSON format to a JSON value . , from_ubjson }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa http : //ubjson.org
@ sa @ ref to_ubjson ( const basic_json & , const bool , const bool ) for the
analogous serialization
@ sa @ ref from_cbor ( detail : : input_adapter , const bool ) for the related CBOR
format
@ sa @ ref from_msgpack ( detail : : input_adapter , const bool ) for the related
MessagePack format
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ since version 3.1 .0
*/
static basic_json from_ubjson ( detail : : input_adapter i ,
const bool strict = true )
{
return binary_reader ( i ) . parse_ubjson ( strict ) ;
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
template < typename A1 , typename A2 ,
detail : : enable_if_t < std : : is_constructible < detail : : input_adapter , A1 , A2 > : : value , int > = 0 >
static basic_json from_ubjson ( A1 & & a1 , A2 & & a2 , const bool strict = true )
{
return binary_reader ( detail : : input_adapter ( std : : forward < A1 > ( a1 ) , std : : forward < A2 > ( a2 ) ) ) . parse_ubjson ( strict ) ;
}
/// @}
2017-07-18 05:37:27 +02:00
//////////////////////////
// JSON Pointer support //
//////////////////////////
/// @name JSON Pointer functions
/// @{
/*!
@ brief access specified element via JSON Pointer
Uses a JSON pointer to retrieve a reference to the respective JSON value .
No bound checking is performed . Similar to @ ref operator [ ] ( const typename
object_t : : key_type & ) , ` null ` values are created in arrays and objects if
necessary .
In particular :
- If the JSON pointer points to an object key that does not exist , it
is created an filled with a ` null ` value before a reference to it
is returned .
- If the JSON pointer points to an array index that does not exist , it
is created an filled with a ` null ` value before a reference to it
is returned . All indices between the current maximum and the given
index are also filled with ` null ` .
- The special value ` - ` is treated as a synonym for the index past the
end .
@ param [ in ] ptr a JSON pointer
@ return reference to the element pointed to by @ a ptr
@ complexity Constant .
@ throw parse_error .106 if an array index begins with ' 0 '
@ throw parse_error .109 if an array index was not a number
@ throw out_of_range .404 if the JSON pointer can not be resolved
@ liveexample { The behavior is shown in the example . , operatorjson_pointer }
@ since version 2.0 .0
*/
reference operator [ ] ( const json_pointer & ptr )
{
return ptr . get_unchecked ( this ) ;
}
/*!
@ brief access specified element via JSON Pointer
Uses a JSON pointer to retrieve a reference to the respective JSON value .
No bound checking is performed . The function does not change the JSON
value ; no ` null ` values are created . In particular , the the special value
` - ` yields an exception .
@ param [ in ] ptr JSON pointer to the desired element
@ return const reference to the element pointed to by @ a ptr
@ complexity Constant .
@ throw parse_error .106 if an array index begins with ' 0 '
@ throw parse_error .109 if an array index was not a number
@ throw out_of_range .402 if the array index ' - ' is used
@ throw out_of_range .404 if the JSON pointer can not be resolved
@ liveexample { The behavior is shown in the example . , operatorjson_pointer_const }
@ since version 2.0 .0
*/
const_reference operator [ ] ( const json_pointer & ptr ) const
{
return ptr . get_unchecked ( this ) ;
}
/*!
@ brief access specified element via JSON Pointer
Returns a reference to the element at with specified JSON pointer @ a ptr ,
with bounds checking .
@ param [ in ] ptr JSON pointer to the desired element
@ return reference to the element pointed to by @ a ptr
@ throw parse_error .106 if an array index in the passed JSON pointer @ a ptr
begins with ' 0 ' . See example below .
@ throw parse_error .109 if an array index in the passed JSON pointer @ a ptr
is not a number . See example below .
@ throw out_of_range .401 if an array index in the passed JSON pointer @ a ptr
is out of range . See example below .
@ throw out_of_range .402 if the array index ' - ' is used in the passed JSON
pointer @ a ptr . As ` at ` provides checked access ( and no elements are
implicitly inserted ) , the index ' - ' is always invalid . See example below .
2018-05-19 21:59:03 +02:00
@ throw out_of_range .403 if the JSON pointer describes a key of an object
which cannot be found . See example below .
2017-07-18 05:37:27 +02:00
@ throw out_of_range .404 if the JSON pointer @ a ptr can not be resolved .
See example below .
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
@ complexity Constant .
@ since version 2.0 .0
@ liveexample { The behavior is shown in the example . , at_json_pointer }
*/
reference at ( const json_pointer & ptr )
{
return ptr . get_checked ( this ) ;
}
/*!
@ brief access specified element via JSON Pointer
Returns a const reference to the element at with specified JSON pointer @ a
ptr , with bounds checking .
@ param [ in ] ptr JSON pointer to the desired element
@ return reference to the element pointed to by @ a ptr
@ throw parse_error .106 if an array index in the passed JSON pointer @ a ptr
begins with ' 0 ' . See example below .
@ throw parse_error .109 if an array index in the passed JSON pointer @ a ptr
is not a number . See example below .
@ throw out_of_range .401 if an array index in the passed JSON pointer @ a ptr
is out of range . See example below .
@ throw out_of_range .402 if the array index ' - ' is used in the passed JSON
pointer @ a ptr . As ` at ` provides checked access ( and no elements are
implicitly inserted ) , the index ' - ' is always invalid . See example below .
2018-05-19 21:59:03 +02:00
@ throw out_of_range .403 if the JSON pointer describes a key of an object
which cannot be found . See example below .
2017-07-18 05:37:27 +02:00
@ throw out_of_range .404 if the JSON pointer @ a ptr can not be resolved .
See example below .
@ exceptionsafety Strong guarantee : if an exception is thrown , there are no
changes in the JSON value .
@ complexity Constant .
@ since version 2.0 .0
@ liveexample { The behavior is shown in the example . , at_json_pointer_const }
*/
const_reference at ( const json_pointer & ptr ) const
{
return ptr . get_checked ( this ) ;
}
/*!
@ brief return flattened JSON value
The function creates a JSON object whose keys are JSON pointers ( see [ RFC
6901 ] ( https : //tools.ietf.org/html/rfc6901)) and whose values are all
primitive . The original JSON value can be restored using the @ ref
unflatten ( ) function .
@ return an object that maps JSON pointers to primitive values
@ note Empty objects and arrays are flattened to ` null ` and will not be
reconstructed correctly by the @ ref unflatten ( ) function .
@ complexity Linear in the size the JSON value .
@ liveexample { The following code shows how a JSON object is flattened to an
object whose keys consist of JSON pointers . , flatten }
@ sa @ ref unflatten ( ) for the reverse function
@ since version 2.0 .0
*/
basic_json flatten ( ) const
{
basic_json result ( value_t : : object ) ;
json_pointer : : flatten ( " " , * this , result ) ;
return result ;
}
/*!
@ brief unflatten a previously flattened JSON value
The function restores the arbitrary nesting of a JSON value that has been
flattened before using the @ ref flatten ( ) function . The JSON value must
meet certain constraints :
1. The value must be an object .
2. The keys must be JSON pointers ( see
[ RFC 6901 ] ( https : //tools.ietf.org/html/rfc6901))
3. The mapped values must be primitive JSON types .
@ return the original JSON from a flattened version
@ note Empty objects and arrays are flattened by @ ref flatten ( ) to ` null `
values and can not unflattened to their original type . Apart from
this example , for a JSON value ` j ` , the following is always true :
` j = = j . flatten ( ) . unflatten ( ) ` .
@ complexity Linear in the size the JSON value .
@ throw type_error .314 if value is not an object
@ throw type_error .315 if object values are not primitive
@ liveexample { The following code shows how a flattened JSON object is
unflattened into the original nested JSON object . , unflatten }
@ sa @ ref flatten ( ) for the reverse function
@ since version 2.0 .0
*/
basic_json unflatten ( ) const
{
return json_pointer : : unflatten ( * this ) ;
}
/// @}
//////////////////////////
// JSON Patch functions //
//////////////////////////
/// @name JSON Patch functions
/// @{
/*!
@ brief applies a JSON patch
[ JSON Patch ] ( http : //jsonpatch.com) defines a JSON document structure for
expressing a sequence of operations to apply to a JSON ) document . With
this function , a JSON Patch is applied to the current JSON value by
executing all operations from the patch .
@ param [ in ] json_patch JSON patch document
@ return patched document
@ note The application of a patch is atomic : Either all operations succeed
and the patched document is returned or an exception is thrown . In
any case , the original value is not changed : the patch is applied
to a copy of the value .
@ throw parse_error .104 if the JSON patch does not consist of an array of
objects
@ throw parse_error .105 if the JSON patch is malformed ( e . g . , mandatory
attributes are missing ) ; example : ` " operation add must have member path " `
@ throw out_of_range .401 if an array index is out of range .
@ throw out_of_range .403 if a JSON pointer inside the patch could not be
resolved successfully in the current JSON value ; example : ` " key baz not
found " `
@ throw out_of_range .405 if JSON pointer has no parent ( " add " , " remove " ,
" move " )
@ throw other_error .501 if " test " operation was unsuccessful
@ complexity Linear in the size of the JSON value and the length of the
JSON patch . As usually only a fraction of the JSON value is affected by
the patch , the complexity can usually be neglected .
@ liveexample { The following code shows how a JSON patch is applied to a
value . , patch }
@ sa @ ref diff - - create a JSON patch by comparing two JSON values
@ sa [ RFC 6902 ( JSON Patch ) ] ( https : //tools.ietf.org/html/rfc6902)
@ sa [ RFC 6901 ( JSON Pointer ) ] ( https : //tools.ietf.org/html/rfc6901)
@ since version 2.0 .0
*/
basic_json patch ( const basic_json & json_patch ) const
{
// make a working copy to apply the patch to
basic_json result = * this ;
// the valid JSON Patch operations
enum class patch_operations { add , remove , replace , move , copy , test , invalid } ;
const auto get_op = [ ] ( const std : : string & op )
{
if ( op = = " add " )
{
return patch_operations : : add ;
}
if ( op = = " remove " )
{
return patch_operations : : remove ;
}
if ( op = = " replace " )
{
return patch_operations : : replace ;
}
if ( op = = " move " )
{
return patch_operations : : move ;
}
if ( op = = " copy " )
{
return patch_operations : : copy ;
}
if ( op = = " test " )
{
return patch_operations : : test ;
}
return patch_operations : : invalid ;
} ;
// wrapper for "add" operation; add value at ptr
const auto operation_add = [ & result ] ( json_pointer & ptr , basic_json val )
{
// adding to the root of the target document means replacing it
if ( ptr . is_root ( ) )
{
result = val ;
}
else
{
// make sure the top element of the pointer exists
json_pointer top_pointer = ptr . top ( ) ;
if ( top_pointer ! = ptr )
{
result . at ( top_pointer ) ;
}
// get reference to parent of JSON pointer ptr
const auto last_path = ptr . pop_back ( ) ;
basic_json & parent = result [ ptr ] ;
switch ( parent . m_type )
{
case value_t : : null :
case value_t : : object :
{
// use operator[] to add value
parent [ last_path ] = val ;
break ;
}
case value_t : : array :
{
if ( last_path = = " - " )
{
// special case: append to back
parent . push_back ( val ) ;
}
else
{
2018-05-19 21:59:03 +02:00
const auto idx = json_pointer : : array_index ( last_path ) ;
if ( JSON_UNLIKELY ( static_cast < size_type > ( idx ) > parent . size ( ) ) )
2017-07-18 05:37:27 +02:00
{
// avoid undefined behavior
JSON_THROW ( out_of_range : : create ( 401 , " array index " + std : : to_string ( idx ) + " is out of range " ) ) ;
}
else
{
// default case: insert add offset
parent . insert ( parent . begin ( ) + static_cast < difference_type > ( idx ) , val ) ;
}
}
break ;
}
default :
{
// if there exists a parent it cannot be primitive
assert ( false ) ; // LCOV_EXCL_LINE
}
}
}
} ;
// wrapper for "remove" operation; remove value at ptr
const auto operation_remove = [ & result ] ( json_pointer & ptr )
{
// get reference to parent of JSON pointer ptr
const auto last_path = ptr . pop_back ( ) ;
basic_json & parent = result . at ( ptr ) ;
// remove child
if ( parent . is_object ( ) )
{
// perform range check
auto it = parent . find ( last_path ) ;
2018-05-19 21:59:03 +02:00
if ( JSON_LIKELY ( it ! = parent . end ( ) ) )
2017-07-18 05:37:27 +02:00
{
parent . erase ( it ) ;
}
else
{
JSON_THROW ( out_of_range : : create ( 403 , " key ' " + last_path + " ' not found " ) ) ;
}
}
else if ( parent . is_array ( ) )
{
// note erase performs range check
2018-05-19 21:59:03 +02:00
parent . erase ( static_cast < size_type > ( json_pointer : : array_index ( last_path ) ) ) ;
2017-07-18 05:37:27 +02:00
}
} ;
// type check: top level value must be an array
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not json_patch . is_array ( ) ) )
2017-07-18 05:37:27 +02:00
{
JSON_THROW ( parse_error : : create ( 104 , 0 , " JSON patch must be an array of objects " ) ) ;
}
// iterate and apply the operations
for ( const auto & val : json_patch )
{
// wrapper to get a value for an operation
const auto get_value = [ & val ] ( const std : : string & op ,
const std : : string & member ,
2018-05-19 21:59:03 +02:00
bool string_type ) - > basic_json &
2017-07-18 05:37:27 +02:00
{
// find value
auto it = val . m_value . object - > find ( member ) ;
// context-sensitive error message
const auto error_msg = ( op = = " op " ) ? " operation " : " operation ' " + op + " ' " ;
// check if desired value is present
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( it = = val . m_value . object - > end ( ) ) )
2017-07-18 05:37:27 +02:00
{
JSON_THROW ( parse_error : : create ( 105 , 0 , error_msg + " must have member ' " + member + " ' " ) ) ;
}
// check if result is of type string
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( string_type and not it - > second . is_string ( ) ) )
2017-07-18 05:37:27 +02:00
{
JSON_THROW ( parse_error : : create ( 105 , 0 , error_msg + " must have string member ' " + member + " ' " ) ) ;
}
// no error: return value
return it - > second ;
} ;
// type check: every element of the array must be an object
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not val . is_object ( ) ) )
2017-07-18 05:37:27 +02:00
{
JSON_THROW ( parse_error : : create ( 104 , 0 , " JSON patch must be an array of objects " ) ) ;
}
// collect mandatory members
const std : : string op = get_value ( " op " , " op " , true ) ;
const std : : string path = get_value ( op , " path " , true ) ;
json_pointer ptr ( path ) ;
switch ( get_op ( op ) )
{
case patch_operations : : add :
{
operation_add ( ptr , get_value ( " add " , " value " , false ) ) ;
break ;
}
case patch_operations : : remove :
{
operation_remove ( ptr ) ;
break ;
}
case patch_operations : : replace :
{
// the "path" location must exist - use at()
result . at ( ptr ) = get_value ( " replace " , " value " , false ) ;
break ;
}
case patch_operations : : move :
{
const std : : string from_path = get_value ( " move " , " from " , true ) ;
json_pointer from_ptr ( from_path ) ;
// the "from" location must exist - use at()
basic_json v = result . at ( from_ptr ) ;
// The move operation is functionally identical to a
// "remove" operation on the "from" location, followed
// immediately by an "add" operation at the target
// location with the value that was just removed.
operation_remove ( from_ptr ) ;
operation_add ( ptr , v ) ;
break ;
}
case patch_operations : : copy :
{
const std : : string from_path = get_value ( " copy " , " from " , true ) ;
const json_pointer from_ptr ( from_path ) ;
// the "from" location must exist - use at()
2018-05-19 21:59:03 +02:00
basic_json v = result . at ( from_ptr ) ;
// The copy is functionally identical to an "add"
// operation at the target location using the value
// specified in the "from" member.
operation_add ( ptr , v ) ;
2017-07-18 05:37:27 +02:00
break ;
}
case patch_operations : : test :
{
bool success = false ;
JSON_TRY
{
// check if "value" matches the one at "path"
// the "path" location must exist - use at()
success = ( result . at ( ptr ) = = get_value ( " test " , " value " , false ) ) ;
}
JSON_CATCH ( out_of_range & )
{
// ignore out of range errors: success remains false
}
// throw an exception if test fails
2018-05-19 21:59:03 +02:00
if ( JSON_UNLIKELY ( not success ) )
2017-07-18 05:37:27 +02:00
{
JSON_THROW ( other_error : : create ( 501 , " unsuccessful: " + val . dump ( ) ) ) ;
}
break ;
}
case patch_operations : : invalid :
{
// op must be "add", "remove", "replace", "move", "copy", or
// "test"
JSON_THROW ( parse_error : : create ( 105 , 0 , " operation value ' " + op + " ' is invalid " ) ) ;
}
}
}
return result ;
}
/*!
@ brief creates a diff as a JSON patch
Creates a [ JSON Patch ] ( http : //jsonpatch.com) so that value @a source can
be changed into the value @ a target by calling @ ref patch function .
@ invariant For two JSON values @ a source and @ a target , the following code
yields always ` true ` :
@ code { . cpp }
source . patch ( diff ( source , target ) ) = = target ;
@ endcode
@ note Currently , only ` remove ` , ` add ` , and ` replace ` operations are
generated .
@ param [ in ] source JSON value to compare from
@ param [ in ] target JSON value to compare against
@ param [ in ] path helper value to create JSON pointers
@ return a JSON patch to convert the @ a source to @ a target
@ complexity Linear in the lengths of @ a source and @ a target .
@ liveexample { The following code shows how a JSON patch is created as a
diff for two JSON values . , diff }
@ sa @ ref patch - - apply a JSON patch
2018-05-19 21:59:03 +02:00
@ sa @ ref merge_patch - - apply a JSON Merge Patch
2017-07-18 05:37:27 +02:00
@ sa [ RFC 6902 ( JSON Patch ) ] ( https : //tools.ietf.org/html/rfc6902)
@ since version 2.0 .0
*/
2018-05-19 21:59:03 +02:00
static basic_json diff ( const basic_json & source , const basic_json & target ,
2017-07-18 05:37:27 +02:00
const std : : string & path = " " )
{
// the patch
basic_json result ( value_t : : array ) ;
// if the values are the same, return empty patch
if ( source = = target )
{
return result ;
}
if ( source . type ( ) ! = target . type ( ) )
{
// different types: replace value
result . push_back (
{
2018-05-19 21:59:03 +02:00
{ " op " , " replace " } , { " path " , path } , { " value " , target }
2017-07-18 05:37:27 +02:00
} ) ;
}
else
{
switch ( source . type ( ) )
{
case value_t : : array :
{
// first pass: traverse common elements
2018-05-19 21:59:03 +02:00
std : : size_t i = 0 ;
2017-07-18 05:37:27 +02:00
while ( i < source . size ( ) and i < target . size ( ) )
{
// recursive call to compare array values at index i
auto temp_diff = diff ( source [ i ] , target [ i ] , path + " / " + std : : to_string ( i ) ) ;
result . insert ( result . end ( ) , temp_diff . begin ( ) , temp_diff . end ( ) ) ;
+ + i ;
}
// i now reached the end of at least one array
// in a second pass, traverse the remaining elements
// remove my remaining elements
const auto end_index = static_cast < difference_type > ( result . size ( ) ) ;
while ( i < source . size ( ) )
{
// add operations in reverse order to avoid invalid
// indices
result . insert ( result . begin ( ) + end_index , object (
{
{ " op " , " remove " } ,
{ " path " , path + " / " + std : : to_string ( i ) }
} ) ) ;
+ + i ;
}
// add other remaining elements
while ( i < target . size ( ) )
{
result . push_back (
{
{ " op " , " add " } ,
{ " path " , path + " / " + std : : to_string ( i ) } ,
{ " value " , target [ i ] }
} ) ;
+ + i ;
}
break ;
}
case value_t : : object :
{
// first pass: traverse this object's elements
2018-05-19 21:59:03 +02:00
for ( auto it = source . cbegin ( ) ; it ! = source . cend ( ) ; + + it )
2017-07-18 05:37:27 +02:00
{
// escape the key name to be used in a JSON patch
const auto key = json_pointer : : escape ( it . key ( ) ) ;
if ( target . find ( it . key ( ) ) ! = target . end ( ) )
{
// recursive call to compare object values at key it
auto temp_diff = diff ( it . value ( ) , target [ it . key ( ) ] , path + " / " + key ) ;
result . insert ( result . end ( ) , temp_diff . begin ( ) , temp_diff . end ( ) ) ;
}
else
{
// found a key that is not in o -> remove it
result . push_back ( object (
{
2018-05-19 21:59:03 +02:00
{ " op " , " remove " } , { " path " , path + " / " + key }
2017-07-18 05:37:27 +02:00
} ) ) ;
}
}
// second pass: traverse other object's elements
2018-05-19 21:59:03 +02:00
for ( auto it = target . cbegin ( ) ; it ! = target . cend ( ) ; + + it )
2017-07-18 05:37:27 +02:00
{
if ( source . find ( it . key ( ) ) = = source . end ( ) )
{
// found a key that is not in this -> add it
const auto key = json_pointer : : escape ( it . key ( ) ) ;
result . push_back (
{
2018-05-19 21:59:03 +02:00
{ " op " , " add " } , { " path " , path + " / " + key } ,
2017-07-18 05:37:27 +02:00
{ " value " , it . value ( ) }
} ) ;
}
}
break ;
}
default :
{
// both primitive type: replace value
result . push_back (
{
2018-05-19 21:59:03 +02:00
{ " op " , " replace " } , { " path " , path } , { " value " , target }
2017-07-18 05:37:27 +02:00
} ) ;
break ;
}
}
}
return result ;
}
/// @}
2018-05-19 21:59:03 +02:00
////////////////////////////////
// JSON Merge Patch functions //
////////////////////////////////
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @name JSON Merge Patch functions
/// @{
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/*!
@ brief applies a JSON Merge Patch
The merge patch format is primarily intended for use with the HTTP PATCH
method as a means of describing a set of modifications to a target
resource ' s content . This function applies a merge patch to the current
JSON value .
The function implements the following algorithm from Section 2 of
[ RFC 7396 ( JSON Merge Patch ) ] ( https : //tools.ietf.org/html/rfc7396):
` ` `
define MergePatch ( Target , Patch ) :
if Patch is an Object :
if Target is not an Object :
Target = { } // Ignore the contents and set it to an empty Object
for each Name / Value pair in Patch :
if Value is null :
if Name exists in Target :
remove the Name / Value pair from Target
else :
Target [ Name ] = MergePatch ( Target [ Name ] , Value )
return Target
else :
return Patch
` ` `
Thereby , ` Target ` is the current object ; that is , the patch is applied to
the current value .
@ param [ in ] patch the patch to apply
@ complexity Linear in the lengths of @ a patch .
@ liveexample { The following code shows how a JSON Merge Patch is applied to
a JSON document . , merge_patch }
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
@ sa @ ref patch - - apply a JSON patch
@ sa [ RFC 7396 ( JSON Merge Patch ) ] ( https : //tools.ietf.org/html/rfc7396)
@ since version 3.0 .0
*/
void merge_patch ( const basic_json & patch )
{
if ( patch . is_object ( ) )
{
if ( not is_object ( ) )
{
* this = object ( ) ;
}
for ( auto it = patch . begin ( ) ; it ! = patch . end ( ) ; + + it )
{
if ( it . value ( ) . is_null ( ) )
{
erase ( it . key ( ) ) ;
}
else
{
operator [ ] ( it . key ( ) ) . merge_patch ( it . value ( ) ) ;
}
}
}
else
{
* this = patch ;
}
}
2017-07-18 05:37:27 +02:00
2018-05-19 21:59:03 +02:00
/// @}
} ;
} // namespace nlohmann
2017-07-18 05:37:27 +02:00
///////////////////////
// nonmember support //
///////////////////////
// specialization of std::swap, and std::hash
namespace std
{
/*!
@ brief exchanges the values of two JSON objects
@ since version 1.0 .0
*/
template < >
inline void swap ( nlohmann : : json & j1 ,
nlohmann : : json & j2 ) noexcept (
is_nothrow_move_constructible < nlohmann : : json > : : value and
is_nothrow_move_assignable < nlohmann : : json > : : value
)
{
j1 . swap ( j2 ) ;
}
/// hash value for JSON objects
template < >
struct hash < nlohmann : : json >
{
/*!
@ brief return a hash value for a JSON object
@ since version 1.0 .0
*/
std : : size_t operator ( ) ( const nlohmann : : json & j ) const
{
// a naive hashing via the string representation
const auto & h = hash < nlohmann : : json : : string_t > ( ) ;
return h ( j . dump ( ) ) ;
}
} ;
/// specialization for std::less<value_t>
2018-05-19 21:59:03 +02:00
/// @note: do not remove the space after '<',
/// see https://github.com/nlohmann/json/pull/679
template < >
struct less < : : nlohmann : : detail : : value_t >
2017-07-18 05:37:27 +02:00
{
/*!
@ brief compare two value_t enum values
@ since version 3.0 .0
*/
bool operator ( ) ( nlohmann : : detail : : value_t lhs ,
nlohmann : : detail : : value_t rhs ) const noexcept
{
return nlohmann : : detail : : operator < ( lhs , rhs ) ;
}
} ;
} // namespace std
/*!
@ brief user - defined string literal for JSON values
This operator implements a user - defined string literal for JSON objects . It
can be used by adding ` " _json " ` to a string literal and returns a JSON object
if no parse error occurred .
@ param [ in ] s a string representation of a JSON object
@ param [ in ] n the length of string @ a s
@ return a JSON object
@ since version 1.0 .0
*/
inline nlohmann : : json operator " " _json ( const char * s , std : : size_t n )
{
return nlohmann : : json : : parse ( s , s + n ) ;
}
/*!
@ brief user - defined string literal for JSON pointer
This operator implements a user - defined string literal for JSON Pointers . It
can be used by adding ` " _json_pointer " ` to a string literal and returns a JSON pointer
object if no parse error occurred .
@ param [ in ] s a string representation of a JSON Pointer
@ param [ in ] n the length of string @ a s
@ return a JSON pointer object
@ since version 2.0 .0
*/
inline nlohmann : : json : : json_pointer operator " " _json_pointer ( const char * s , std : : size_t n )
{
return nlohmann : : json : : json_pointer ( std : : string ( s , n ) ) ;
}
2018-05-19 21:59:03 +02:00
// #include <nlohmann/detail/macro_unscope.hpp>
2017-07-18 05:37:27 +02:00
// restore GCC/clang diagnostic settings
# if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
# pragma GCC diagnostic pop
# endif
# if defined(__clang__)
# pragma GCC diagnostic pop
# endif
// clean up
# undef JSON_CATCH
# undef JSON_THROW
# undef JSON_TRY
# undef JSON_LIKELY
# undef JSON_UNLIKELY
# undef JSON_DEPRECATED
2018-05-19 21:59:03 +02:00
# undef JSON_HAS_CPP_14
# undef JSON_HAS_CPP_17
# undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
# undef NLOHMANN_BASIC_JSON_TPL
# undef NLOHMANN_JSON_HAS_HELPER
2017-07-18 05:37:27 +02:00
# endif