Skip to content
Snippets Groups Projects
json.hpp 624 KiB
Newer Older
  • Learn to ignore specific revisions
  • 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832 11833 11834 11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000
    
    @since version 1.0.0
    
    @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;
        template<typename BasicJsonType>
        friend class ::nlohmann::detail::json_sax_dom_parser;
        template<typename BasicJsonType>
        friend class ::nlohmann::detail::json_sax_dom_callback_parser;
    
        /// workaround type for MSVC
        using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
    
        // convenience aliases for types residing in namespace detail;
        using lexer = ::nlohmann::detail::lexer<basic_json>;
        using parser = ::nlohmann::detail::parser<basic_json>;
    
        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>;
    
        template<typename CharType>
        using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
    
        using binary_reader = ::nlohmann::detail::binary_reader<basic_json>;
        template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
    
        using serializer = ::nlohmann::detail::serializer<basic_json>;
    
      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>>;
    
        using input_format_t = detail::input_format_t;
    
        ////////////////
        // exceptions //
        ////////////////
    
        /// @name exceptions
        /// Classes to implement user-defined exceptions.
        /// @{
    
        /// @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;
    
        /// @}
    
    
        /////////////////////
        // container types //
        /////////////////////
    
        /// @name container types
        /// The canonic container types to use @ref basic_json like any other STL
        /// container.
        /// @{
    
        /// the type of elements in a basic_json container
        using value_type = basic_json;
    
        /// the type of an element reference
        using reference = value_type&;
        /// the type of an element const reference
        using const_reference = const value_type&;
    
        /// 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;
    
        /// the allocator type
        using allocator_type = AllocatorType<basic_json>;
    
        /// 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;
    
        /// 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
        */
        static allocator_type get_allocator()
        {
            return allocator_type();
        }
    
        /*!
        @brief returns version information on the library
    
        This function returns a JSON object with information about the library,
        including the version number and information on the platform and compiler.
    
        @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).
    
        @liveexample{The following code shows an example output of the `meta()`
        function.,meta}
    
        @exceptionsafety Strong guarantee: if an exception is thrown, there are no
        changes to any JSON value.
    
        @complexity Constant.
    
        @since 2.1.0
        */
        static basic_json meta()
        {
            basic_json result;
    
            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;
    
    #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
    
    #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
    
    #ifdef __cplusplus
            result["compiler"]["c++"] = std::to_string(__cplusplus);
    #else
            result["compiler"]["c++"] = "unknown";
    #endif
            return result;
        }
    
    
        ///////////////////////////
        // JSON value data types //
        ///////////////////////////
    
        /// @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.
        /// @{
    
    #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
    
        /*!
        @brief a type for an object
    
        [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.
    
        To store objects in C++, a type is defined by the template parameters
        described below.
    
        @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`)
    
        #### Default type
    
        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:
    
        @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
    
        #### Behavior
    
        The choice of @a object_t influences the behavior of the JSON class. With
        the default type, objects have the following behavior:
    
        - 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.
    
        #### Limits
    
        [RFC 7159](http://rfc7159.net/rfc7159) specifies:
        > An implementation may set limits on the maximum depth of nesting.
    
        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.
    
        #### Storage
    
        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.
    
        @sa @ref array_t -- type for an array value
    
        @since version 1.0.0
    
        @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>>>;
    
        /*!
        @brief a type for an array
    
        [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
        > An array is an ordered sequence of zero or more values.
    
        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
    
        @since version 1.0.0
        */
        using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
    
        /*!
        @brief a type for a string
    
        [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
        > A string is a sequence of zero or more Unicode characters.
    
        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.
    
        @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.
    
        #### Default type
    
        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\u005Cb"` 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.
    
        @since version 1.0.0
        */
        using string_t = StringType;
    
        /*!
        @brief a type for a boolean
    
        [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
        type which differentiates the two literals `true` and `false`.
    
        To store objects in C++, a type is defined by the template parameter @a
        BooleanType which chooses the type to use.
    
        #### Default type
    
        With the default values for @a BooleanType (`bool`), the default value for
        @a boolean_t is:
    
        @code {.cpp}
        bool
        @endcode
    
        #### Storage
    
        Boolean values are stored directly inside a @ref basic_json type.
    
        @since version 1.0.0
        */
        using boolean_t = BooleanType;
    
        /*!
        @brief a type for a number (integer)
    
        [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 integer numbers in C++, a type is defined by the template
        parameter @a NumberIntegerType which chooses the type to use.
    
        #### Default type
    
        With the default values for @a NumberIntegerType (`int64_t`), the default
        value for @a number_integer_t is:
    
        @code {.cpp}
        int64_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 `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.
    
        [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 of the exactly supported range [INT64_MIN,
        INT64_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_unsigned_t -- type for number values (unsigned integer)
    
        @since version 1.0.0
        */
        using number_integer_t = NumberIntegerType;
    
        /*!
        @brief a type for a number (unsigned)
    
        [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
        > The representation of numbers is similar to that used in most
        > programming languages. A number is represented in base 10 using decimal
        > digits. It contains an integer component that may be prefixed with an
        > optional minus sign, which may be followed by a fraction part and/or an
        > exponent part. Leading zeros are not allowed. (...) Numeric values that
        > cannot be represented in the grammar below (such as Infinity and NaN)
        > are not permitted.
    
        This description includes both integer and floating-point numbers.
        However, C++ allows more precise storage if it is known whether the number
        is a signed integer, an unsigned integer or a floating-point number.
        Therefore, three different types, @ref number_integer_t, @ref
        number_unsigned_t and @ref number_float_t are used.
    
        To store unsigned integer numbers in C++, a type is defined by the
        template parameter @a NumberUnsignedType which chooses the type to use.
    
        #### Default type
    
        With the default values for @a NumberUnsignedType (`uint64_t`), the
        default value for @a number_unsigned_t is:
    
        @code {.cpp}
        uint64_t
        @endcode
    
        #### Default behavior
    
        - The restrictions about leading zeros is not enforced in C++. Instead,
          leading zeros in integer literals lead to an interpretation as octal
          number. Internally, the value will be stored as decimal number. For
          instance, the C++ integer literal `010` will be serialized to `8`.
          During deserialization, leading zeros yield an error.
        - Not-a-number (NaN) values will be serialized to `null`.
    
        #### Limits
    
        [RFC 7159](http://rfc7159.net/rfc7159) specifies:
        > An implementation may set limits on the range and precision of numbers.
    
        When the default type is used, the maximal integer number that can be
        stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
        number that can be stored is `0`. Integer numbers that are out of range
        will yield over/underflow when used in a constructor. During
        deserialization, too large or small integer numbers will be automatically
        be stored as @ref number_integer_t or @ref number_float_t.
    
        [RFC 7159](http://rfc7159.net/rfc7159) further states:
        > Note that when such software is used, numbers that are integers and are
        > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
        > that implementations will agree exactly on their numeric values.
    
        As this range is a subrange (when considered in conjunction with the
        number_integer_t type) of the exactly supported range [0, UINT64_MAX],
        this class's integer type is interoperable.
    
        #### Storage
    
        Integer number values are stored directly inside a @ref basic_json type.
    
        @sa @ref number_float_t -- type for number values (floating-point)
        @sa @ref number_integer_t -- type for number values (integer)
    
        @since version 2.0.0
        */
        using number_unsigned_t = NumberUnsignedType;
    
        /*!
        @brief a type for a number (floating-point)
    
        [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)
                {
                    case value_t::object:
                    {
                        object = create<object_t>();
                        break;
                    }
    
                    case value_t::array:
                    {
                        array = create<array_t>();
                        break;
                    }
    
                    case value_t::string:
                    {
                        string = create<string_t>("");
                        break;
                    }
    
                    case value_t::boolean:
                    {
                        boolean = boolean_t(false);
                        break;
                    }
    
                    case value_t::number_integer:
                    {
                        number_integer = number_integer_t(0);
                        break;
                    }
    
                    case value_t::number_unsigned:
                    {
                        number_unsigned = number_unsigned_t(0);
                        break;
                    }
    
                    case value_t::number_float:
                    {
                        number_float = number_float_t(0.0);
                        break;
                    }
    
                    case value_t::null:
                    {
                        object = nullptr;  // silence warning, see #821
                        break;
                    }
    
                    default:
                    {
                        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;
                    }
                }
            }
    
            /// constructor for strings
            json_value(const string_t& value)
            {
                string = create<string_t>(value);
            }
    
            /// constructor for rvalue strings
            json_value(string_t&& value)
            {
                string = create<string_t>(std::move(value));
            }
    
            /// constructor for objects
            json_value(const object_t& value)
            {
                object = create<object_t>(value);
            }
    
            /// constructor for rvalue objects
            json_value(object_t&& value)
            {
                object = create<object_t>(std::move(value));
            }
    
            /// constructor for arrays
            json_value(const array_t& value)
            {
                array = create<array_t>(value);
            }
    
            /// constructor for rvalue arrays
            json_value(array_t&& value)
            {
                array = create<array_t>(std::move(value));
            }
    
            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;
                    }
                }
            }
        };
    
        /*!
        @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.
        */
        void assert_invariant() const noexcept
        {
            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);
        }
    
      public:
        //////////////////////////
        // JSON parser callback //
        //////////////////////////
    
        /*!
        @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
        */
        using parse_event_t = typename parser::parse_event_t;
    
        /*!
        @brief per-element parser callback type
    
        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.
    
        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.
    
        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
    
        @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
    
        @since version 1.0.0
        */
        using parser_callback_t = typename parser::parser_callback_t;
    
        using json_sax_t = typename parser::json_sax_t;
    
        //////////////////
        // constructors //
        //////////////////
    
        /// @name constructors and destructors
        /// Constructors of class @ref basic_json, copy/move constructor, copy
        /// assignment, static functions creating objects, and the destructor.
        /// @{
    
        /*!
        @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
        */
        basic_json(const value_t v)