From 35bdc544bc0a072ac84bd351c0f45dd7c853c73c Mon Sep 17 00:00:00 2001
From: Francesco Bariatti <francesco.bariatti@insa-rennes.fr>
Date: Wed, 11 May 2016 14:11:31 +0200
Subject: [PATCH] The game now loads initial state from stdin

---
 gui/src/controller/Controller.java |    4 +
 src/game/penguin.cpp               |   51 +
 src/game/penguin.hpp               |   22 +-
 src/json/json.hpp                  | 3748 +++++++++++++++++++++-------
 src/mcts/allocator.hpp             |    2 +-
 5 files changed, 2910 insertions(+), 917 deletions(-)

diff --git a/gui/src/controller/Controller.java b/gui/src/controller/Controller.java
index 1dbc42e..94eb160 100644
--- a/gui/src/controller/Controller.java
+++ b/gui/src/controller/Controller.java
@@ -83,6 +83,10 @@ public class Controller implements Initializable
 			e.printStackTrace();
 			System.exit(1);
 		}
+		// SENDING STATE TO THE GAME
+		// TODO: 5/10/16 Creating a state and sending it to the game
+		String state = "{}";
+		gameInput.println(state);
 		//Choice: who will start?
 		ChoiceDialog<Player> playerChoice = new ChoiceDialog<>(Player.Red, Player.Red, Player.Blue);
 		playerChoice.setTitle("Penguin game!");
diff --git a/src/game/penguin.cpp b/src/game/penguin.cpp
index d0b6943..cffd460 100644
--- a/src/game/penguin.cpp
+++ b/src/game/penguin.cpp
@@ -5,8 +5,48 @@ using namespace std;
 
 namespace game
 {
+	/**
+	 * Creates the game: load the state from standard input.
+	 * Penguins in state can be composed of just their position: the moves will be updated automatically.
+	**/
 	penguin::penguin()
 	{
+		cout << "Enter penguin game state as JSON on one line" << endl;
+		string line;
+		getline(cin, line);
+		json json_state = json::parse(line);
+		//Charging every element of the state if it exists
+		if(json_state.count("bitboards"))
+		{
+			if(json_state["bitboards"].count("onefish")) {state.one_fish = json_state["bitboards"]["onefish"];}
+			if(json_state["bitboards"].count("twofish")) {state.two_fish = json_state["bitboards"]["twofish"];}
+			if(json_state["bitboards"].count("threefish")) {state.three_fish = json_state["bitboards"]["threefish"];}
+		}
+		if(json_state.count("current_player"))
+			state.current_player_red = json_state["current_player"] == "Red" ? true : false;
+		if(json_state.count("penguins"))
+		{
+			if(json_state["penguins"].count("red"))
+			{
+				state.p1_red = json_state["penguins"]["red"][0];
+				state.p2_red = json_state["penguins"]["red"][1];
+				state.p3_red = json_state["penguins"]["red"][2];
+				state.p4_red = json_state["penguins"]["red"][3];
+			}
+			if(json_state["penguins"].count("blue"))
+			{
+				state.p1_blue = json_state["penguins"]["blue"][0];
+				state.p2_blue = json_state["penguins"]["blue"][1];
+				state.p3_blue = json_state["penguins"]["blue"][2];
+				state.p4_blue = json_state["penguins"]["blue"][3];
+			}
+		}
+		if(json_state.count("score"))
+		{
+			if(json_state["score"].count("red")) { state.score_red = json_state["score"]["red"]; }
+			if(json_state["score"].count("blue")) { state.score_blue = json_state["score"]["blue"]; }
+		}
+		
 		//Update moves on all penguins
 		uint64_t obstacles = (~(state.one_fish | state.two_fish | state.three_fish));
 		obstacles |= ((uint64_t) 1) << (state.p1_red & 63);
@@ -28,6 +68,17 @@ namespace game
 		state.nb_moves_blue += update_moves(&state.p2_blue, obstacles);
 		state.nb_moves_blue += update_moves(&state.p3_blue, obstacles);
 		state.nb_moves_blue += update_moves(&state.p4_blue, obstacles);
+		
+		if (state.nb_moves_red == 0)
+		{
+			state.canPlay_red = false;
+			state.nb_moves_red = 1; //We create an artificial move so that the mcts works
+		}
+		if (state.nb_moves_blue == 0)
+		{
+			state.canPlay_blue = false;
+			state.nb_moves_blue = 1; //We create an artificial move so that the mcts works
+		}
 	}
 
 	shared_ptr<game<penguin_state>> penguin::do_copy() const
diff --git a/src/game/penguin.hpp b/src/game/penguin.hpp
index c322c0a..e1364fc 100644
--- a/src/game/penguin.hpp
+++ b/src/game/penguin.hpp
@@ -13,19 +13,19 @@ namespace game
 {
 	struct penguin_state
 	{
-		uint64_t one_fish = 533050011236269409; //Position of one-fish tiles (bitboard) 
-		uint64_t two_fish = 40552008684274318; //Position of two-fish tiles (bitboard)
-		uint64_t three_fish = 579319484686303248; //Position of three-fish tiles (bitboard)
+		uint64_t one_fish = 1152921504606846975; //Position of one-fish tiles (bitboard) 
+		uint64_t two_fish = 0; //Position of two-fish tiles (bitboard)
+		uint64_t three_fish = 0; //Position of three-fish tiles (bitboard)
 		
 		//Penguins
-		uint32_t p1_red = 24;
-		uint32_t p2_red = 28;
-		uint32_t p3_red = 48;
-		uint32_t p4_red = 50;
-		uint32_t p1_blue = 10;
-		uint32_t p2_blue = 13;
-		uint32_t p3_blue = 35;
-		uint32_t p4_blue = 32;
+		uint32_t p1_red = 0;
+		uint32_t p2_red = 1;
+		uint32_t p3_red = 6;
+		uint32_t p4_red = 7;
+		uint32_t p1_blue = 59;
+		uint32_t p2_blue = 58;
+		uint32_t p3_blue = 53;
+		uint32_t p4_blue = 54;
 		
 		int score_red = 0;
 		int score_blue = 0;
diff --git a/src/json/json.hpp b/src/json/json.hpp
index db73336..37080eb 100644
--- a/src/json/json.hpp
+++ b/src/json/json.hpp
@@ -1,38 +1,29 @@
-/*!
-@mainpage
-
-These pages contain the API documentation of JSON for Modern C++, a C++11
-header-only JSON class.
-
-Class @ref nlohmann::basic_json is a good entry point for the documentation.
-
-@copyright The code is licensed under the [MIT
-  License](http://opensource.org/licenses/MIT):
-  <br>
-  Copyright &copy; 2013-2016 Niels Lohmann.
-  <br>
-  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:
-  <br>
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-  <br>
-  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.
-
-@author [Niels Lohmann](http://nlohmann.me)
-@see https://github.com/nlohmann/json to download the source code
-
-@version 1.1.0
+/*
+    __ _____ _____ _____
+ __|  |   __|     |   | |  JSON for Modern C++
+|  |  |__   |  |  | | | |  version 2.0.0
+|_____|_____|_____|_|___|  https://github.com/nlohmann/json
+
+Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
+
+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
@@ -41,6 +32,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
 #include <algorithm>
 #include <array>
 #include <cassert>
+#include <cerrno>
 #include <ciso646>
 #include <cmath>
 #include <cstddef>
@@ -61,25 +53,12 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
 #include <utility>
 #include <vector>
 
-// enable ssize_t on MinGW
-#ifdef __GNUC__
-    #ifdef __MINGW32__
-        #include <sys/types.h>
-    #endif
-#endif
-
 // disable float-equal warnings on GCC/clang
 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
     #pragma GCC diagnostic push
     #pragma GCC diagnostic ignored "-Wfloat-equal"
 #endif
 
-// enable ssize_t for MSVC
-#ifdef _MSC_VER
-    #include <basetsd.h>
-    using ssize_t = SSIZE_T;
-#endif
-
 /*!
 @brief namespace for Niels Lohmann
 @see https://github.com/nlohmann
@@ -109,24 +88,39 @@ struct has_mapped_type
     static constexpr bool value = sizeof(test<T>(0)) == 1;
 };
 
+/*!
+@brief helper class to create locales with decimal point
+@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
+*/
+class DecimalSeparator : public std::numpunct<char>
+{
+  protected:
+    char do_decimal_point() const
+    {
+        return '.';
+    }
+};
+
 }
 
 /*!
 @brief a class to store JSON values
 
-@tparam ObjectType type for JSON objects (@c std::map by default; will be used
+@tparam ObjectType type for JSON objects (`std::map` by default; will be used
 in @ref object_t)
-@tparam ArrayType type for JSON arrays (@c std::vector by default; will be used
+@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 (@c std::string by
+@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 (@c `bool` by default; will be used
+@tparam BooleanType type for JSON booleans (`bool` by default; will be used
 in @ref boolean_t)
-@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
+@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
 default; will be used in @ref number_integer_t)
-@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
+@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 (@c `std::allocator` by
+@tparam AllocatorType type of the allocator to use (`std::allocator` by
 default)
 
 @requirement The class satisfies the following concept requirements:
@@ -173,7 +167,8 @@ default)
 @note ObjectType trick from http://stackoverflow.com/a/9860911
 @endinternal
 
-@see RFC 7159 <http://rfc7159.net/rfc7159>
+@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
+Format](http://rfc7159.net/rfc7159)
 
 @since version 1.0.0
 
@@ -184,7 +179,8 @@ template <
     template<typename U, typename... Args> class ArrayType = std::vector,
     class StringType = std::string,
     class BooleanType = bool,
-    class NumberIntegerType = int64_t,
+    class NumberIntegerType = std::int64_t,
+    class NumberUnsignedType = std::uint64_t,
     class NumberFloatType = double,
     template<typename U> class AllocatorType = std::allocator
     >
@@ -197,10 +193,14 @@ class basic_json
           StringType,
           BooleanType,
           NumberIntegerType,
+          NumberUnsignedType,
           NumberFloatType,
           AllocatorType>;
 
   public:
+    // forward declarations
+    template<typename Base> class json_reverse_iterator;
+    class json_pointer;
 
     /////////////////////
     // container types //
@@ -230,9 +230,6 @@ class basic_json
     /// the type of an element const pointer
     using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
 
-    // forward declaration
-    template<typename Base> class json_reverse_iterator;
-
     /// an iterator for a basic_json container
     class iterator;
     /// a const iterator for a basic_json container
@@ -481,9 +478,10 @@ class basic_json
     > permitted.
 
     This description includes both integer and floating-point numbers. However,
-    C++ allows more precise storage if it is known whether the number is an
-    integer or a floating-point number. Therefore, two different types, @ref
-    number_integer_t and @ref number_float_t are used.
+    C++ allows more precise storage if it is known whether the number is a
+    signed integer, an unsigned integer or a floating-point number. Therefore,
+    three different types, @ref number_integer_t, @ref number_unsigned_t and
+    @ref number_float_t are used.
 
     To store integer numbers in C++, a type is defined by the template
     parameter @a NumberIntegerType which chooses the type to use.
@@ -516,7 +514,7 @@ class basic_json
     that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
     that are out of range will yield over/underflow when used in a constructor.
     During deserialization, too large or small integer numbers will be
-    automatically be stored as @ref number_float_t.
+    automatically be stored as @ref number_unsigned_t or @ref number_float_t.
 
     [RFC 7159](http://rfc7159.net/rfc7159) further states:
     > Note that when such software is used, numbers that are integers and are
@@ -532,10 +530,84 @@ class basic_json
 
     @sa @ref number_float_t -- type for number values (floating-point)
 
+    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
+
     @since version 1.0.0
     */
     using number_integer_t = NumberIntegerType;
 
+    /*!
+    @brief a type for a number (unsigned)
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
+    > The representation of numbers is similar to that used in most programming
+    > languages. A number is represented in base 10 using decimal digits. It
+    > contains an integer component that may be prefixed with an optional minus
+    > sign, which may be followed by a fraction part and/or an exponent part.
+    > Leading zeros are not allowed. (...) Numeric values that cannot be
+    > represented in the grammar below (such as Infinity and NaN) are not
+    > permitted.
+
+    This description includes both integer and floating-point numbers. However,
+    C++ allows more precise storage if it is known whether the number is a
+    signed integer, an unsigned integer or a floating-point number. Therefore,
+    three different types, @ref number_integer_t, @ref number_unsigned_t and
+    @ref number_float_t are used.
+
+    To store unsigned integer numbers in C++, a type is defined by the template
+    parameter @a NumberUnsignedType which chooses the type to use.
+
+    #### Default type
+
+    With the default values for @a NumberUnsignedType (`uint64_t`), the default
+    value for @a number_unsigned_t is:
+
+    @code {.cpp}
+    uint64_t
+    @endcode
+
+    #### Default behavior
+
+    - The restrictions about leading zeros is not enforced in C++. Instead,
+      leading zeros in integer literals lead to an interpretation as octal
+      number. Internally, the value will be stored as decimal number. For
+      instance, the C++ integer literal `010` will be serialized to `8`. During
+      deserialization, leading zeros yield an error.
+    - Not-a-number (NaN) values will be serialized to `null`.
+
+    #### Limits
+
+    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
+    > An implementation may set limits on the range and precision of numbers.
+
+    When the default type is used, the maximal integer number that can be
+    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
+    number that can be stored is `0`. Integer numbers that are out of range
+    will yield over/underflow when used in a constructor. During
+    deserialization, too large or small integer numbers will be automatically
+    be stored as @ref number_integer_t or @ref number_float_t.
+
+    [RFC 7159](http://rfc7159.net/rfc7159) further states:
+    > Note that when such software is used, numbers that are integers and are
+    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
+    > that implementations will agree exactly on their numeric values.
+
+    As this range is a subrange (when considered in conjunction with the
+    number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
+    class's integer type is interoperable.
+
+    #### Storage
+
+    Integer number values are stored directly inside a @ref basic_json type.
+
+    @sa @ref number_float_t -- type for number values (floating-point)
+
+    @sa @ref number_integer_t -- type for number values (integer)
+
+    @since version 2.0.0
+    */
+    using number_unsigned_t = NumberUnsignedType;
+
     /*!
     @brief a type for a number (floating-point)
 
@@ -549,9 +621,10 @@ class basic_json
     > permitted.
 
     This description includes both integer and floating-point numbers. However,
-    C++ allows more precise storage if it is known whether the number is an
-    integer or a floating-point number. Therefore, two different types, @ref
-    number_integer_t and @ref number_float_t are used.
+    C++ allows more precise storage if it is known whether the number is a
+    signed integer, an unsigned integer or a floating-point number. Therefore,
+    three different types, @ref number_integer_t, @ref number_unsigned_t and
+    @ref number_float_t are used.
 
     To store floating-point numbers in C++, a type is defined by the template
     parameter @a NumberFloatType which chooses the type to use.
@@ -597,6 +670,8 @@ class basic_json
 
     @sa @ref number_integer_t -- type for number values (integer)
 
+    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
+
     @since version 1.0.0
     */
     using number_float_t = NumberFloatType;
@@ -620,18 +695,87 @@ class basic_json
     */
     enum class value_t : uint8_t
     {
-        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 (integer)
-        number_float,   ///< number value (floating-point)
-        discarded       ///< discarded by the the parser callback function
+        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 (integer)
+        number_unsigned, ///< number value (unsigned integer)
+        number_float,    ///< number value (floating-point)
+        discarded        ///< discarded by the the parser callback function
     };
 
 
   private:
+
+    /*!
+    @brief a type to hold JSON type information
+
+    This bitfield type holds information about JSON types. It is internally
+    used to hold the basic JSON type enumeration, as well as additional
+    information in the case of values that have been parsed from a string
+    including whether of not it was created directly or parsed, and in the
+    case of floating point numbers the number of significant figures in the
+    original representaiton and if it was in exponential form, if a '+' was
+    included in the exponent and the capitilization of the exponent marker.
+    The sole purpose of this information is to permit accurate round trips.
+
+    @since version 2.0.0
+    */
+    union type_data_t
+    {
+        struct
+        {
+            /// the type of the value (@ref value_t)
+            uint16_t type : 4;
+            /// whether the number was parsed from a string
+            uint16_t parsed : 1;
+            /// whether parsed number contained an exponent ('e'/'E')
+            uint16_t has_exp : 1;
+            /// whether parsed number contained a plus in the exponent
+            uint16_t exp_plus : 1;
+            /// whether parsed number's exponent was capitalized ('E')
+            uint16_t exp_cap : 1;
+            /// the number of figures for a parsed number
+            uint16_t precision : 8;
+        } bits;
+        uint16_t data;
+
+        /// return the type as value_t
+        operator value_t() const
+        {
+            return static_cast<value_t>(bits.type);
+        }
+
+        /// test type for equality (ignore other fields)
+        bool operator==(const value_t& rhs) const
+        {
+            return static_cast<value_t>(bits.type) == rhs;
+        }
+
+        /// assignment
+        type_data_t& operator=(value_t rhs)
+        {
+            bits.type = static_cast<uint16_t>(rhs);
+            return *this;
+        }
+
+        /// construct from value_t
+        type_data_t(value_t t) noexcept
+        {
+            *reinterpret_cast<uint16_t*>(this) = 0;
+            bits.type = static_cast<uint16_t>(t);
+        }
+
+        /// default constructor
+        type_data_t() noexcept
+        {
+            data = 0;
+            bits.type = reinterpret_cast<uint16_t>(value_t::null);
+        }
+    };
+
     /// helper for exception-safe object creation
     template<typename T, typename... Args>
     static T* create(Args&& ... args)
@@ -669,15 +813,19 @@ class basic_json
         boolean_t boolean;
         /// number (integer)
         number_integer_t number_integer;
+        /// number (unsigned integer)
+        number_unsigned_t number_unsigned;
         /// number (floating-point)
         number_float_t number_float;
 
         /// default constructor (for null values)
-        json_value() noexcept = default;
+        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
@@ -715,6 +863,12 @@ class basic_json
                     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);
@@ -870,6 +1024,8 @@ class basic_json
     (floating-point) value
     @sa @ref basic_json(const number_integer_t) -- create a number (integer)
     value
+    @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
+    value
 
     @since version 1.0.0
     */
@@ -885,7 +1041,12 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the Container requirements:
+    @exceptionsafety No-throw guarantee: this constructor 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.
     - As postcondition, it holds: `basic_json().empty() == true`.
 
@@ -896,19 +1057,22 @@ class basic_json
 
     @since version 1.0.0
     */
-    basic_json() noexcept = default;
+    basic_json() = default;
 
     /*!
     @brief create a null object (explicitly)
 
     Create a `null` JSON value. This is the explicitly version of the `null`
     value constructor as it takes a null pointer as parameter. It allows to
-    create `null` values by explicitly assigning a @c nullptr to a JSON value.
+    create `null` values by explicitly assigning a `nullptr` to a JSON value.
     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 null pointer
     parameter.,basic_json__nullptr_t}
 
@@ -948,11 +1112,14 @@ class basic_json
     @brief create an object (implicit)
 
     Create an object JSON value with a given content. This constructor allows
-    any type that can be used to construct values of type @ref object_t.
-    Examples include the types `std::map` and `std::unordered_map`.
+    any type @a CompatibleObjectType that can be used to construct values of
+    type @ref object_t.
 
-    @tparam CompatibleObjectType an object type whose `key_type` and
-    `value_type` is compatible to @ref object_t
+    @tparam CompatibleObjectType An object type whose `key_type` and
+    `value_type` is compatible to @ref object_t. Examples include `std::map`,
+    `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with
+    a `key_type` of `std::string`, and a `value_type` from which a @ref
+    basic_json value can be constructed.
 
     @param[in] val  a value for the object
 
@@ -1007,11 +1174,14 @@ class basic_json
     @brief create an array (implicit)
 
     Create an array JSON value with a given content. This constructor allows
-    any type that can be used to construct values of type @ref array_t.
-    Examples include the types `std::vector`, `std::list`, and `std::set`.
+    any type @a CompatibleArrayType that can be used to construct values of
+    type @ref array_t.
 
-    @tparam CompatibleArrayType an object type whose `value_type` is compatible
-    to @ref array_t
+    @tparam CompatibleArrayType An object type whose `value_type` is compatible
+    to @ref array_t. Examples include `std::vector`, `std::deque`, `std::list`,
+    `std::forward_list`, `std::array`, `std::set`, `std::unordered_set`,
+    `std::multiset`, and `unordered_multiset` with a `value_type` from which a
+    @ref basic_json value can be constructed.
 
     @param[in] val  a value for the array
 
@@ -1101,7 +1271,7 @@ class basic_json
     @param[in] val  a value for the string
 
     @tparam CompatibleStringType an string type which is compatible to @ref
-    string_t
+    string_t, for instance `std::string`.
 
     @complexity Linear in the size of the passed @a val.
 
@@ -1138,7 +1308,7 @@ class basic_json
 
     @since version 1.0.0
     */
-    basic_json(boolean_t val)
+    basic_json(boolean_t val) noexcept
         : m_type(value_t::boolean), m_value(val)
     {}
 
@@ -1147,18 +1317,16 @@ class basic_json
 
     Create an integer number JSON value with a given content.
 
-    @tparam T  helper type to compare number_integer_t and int (not visible in)
-    the interface.
+    @tparam T A helper type to remove this function via SFINAE in case @ref
+    number_integer_t is the same as `int`. In this case, this constructor would
+    have the same signature as @ref basic_json(const int value). Note the
+    helper type @a T is not visible in this constructor's interface.
 
     @param[in] val  an integer to create a JSON number from
 
-    @note This constructor would have the same signature as @ref
-    basic_json(const int value), so we need to switch this one off in case
-    number_integer_t is the same as int. This is done via the helper type @a T.
-
     @complexity Constant.
 
-    @liveexample{The example below shows the construction of a JSON integer
+    @liveexample{The example below shows the construction of an integer
     number value.,basic_json__number_integer_t}
 
     @sa @ref basic_json(const int) -- create a number value (integer)
@@ -1171,8 +1339,9 @@ class basic_json
              typename std::enable_if<
                  not (std::is_same<T, int>::value)
                  and std::is_same<T, number_integer_t>::value
-                 , int>::type = 0>
-    basic_json(const number_integer_t val)
+                 , int>::type
+             = 0>
+    basic_json(const number_integer_t val) noexcept
         : m_type(value_t::number_integer), m_value(val)
     {}
 
@@ -1191,7 +1360,7 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The example below shows the construction of a JSON integer
+    @liveexample{The example below shows the construction of an integer
     number value from an anonymous enum.,basic_json__const_int}
 
     @sa @ref basic_json(const number_integer_t) -- create a number value
@@ -1201,7 +1370,7 @@ class basic_json
 
     @since version 1.0.0
     */
-    basic_json(const int val)
+    basic_json(const int val) noexcept
         : m_type(value_t::number_integer),
           m_value(static_cast<number_integer_t>(val))
     {}
@@ -1210,19 +1379,19 @@ class basic_json
     @brief create an integer number (implicit)
 
     Create an integer number JSON value with a given content. This constructor
-    allows any type that can be used to construct values of type @ref
-    number_integer_t. Examples may include the types `int`, `int32_t`, or
-    `short`.
+    allows any type @a CompatibleNumberIntegerType that can be used to
+    construct values of type @ref number_integer_t.
 
-    @tparam CompatibleNumberIntegerType an integer type which is compatible to
-    @ref number_integer_t.
+    @tparam CompatibleNumberIntegerType An integer type which is compatible to
+    @ref number_integer_t. Examples include the types `int`, `int32_t`, `long`,
+    and `short`.
 
     @param[in] val  an integer to create a JSON number from
 
     @complexity Constant.
 
-    @liveexample{The example below shows the construction of several JSON
-    integer number values from compatible
+    @liveexample{The example below shows the construction of several integer
+    number values from compatible
     types.,basic_json__CompatibleIntegerNumberType}
 
     @sa @ref basic_json(const number_integer_t) -- create a number value
@@ -1234,13 +1403,74 @@ class basic_json
     template<typename CompatibleNumberIntegerType, typename
              std::enable_if<
                  std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
-                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
+                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
+                 std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
+                 CompatibleNumberIntegerType>::type
              = 0>
     basic_json(const CompatibleNumberIntegerType val) noexcept
         : m_type(value_t::number_integer),
           m_value(static_cast<number_integer_t>(val))
     {}
 
+    /*!
+    @brief create an unsigned integer number (explicit)
+
+    Create an unsigned integer number JSON value with a given content.
+
+    @tparam T  helper type to compare number_unsigned_t and unsigned int
+    (not visible in) the interface.
+
+    @param[in] val  an integer to create a JSON number from
+
+    @complexity Constant.
+
+    @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
+    value (unsigned integer) from a compatible number type
+
+    @since version 2.0.0
+    */
+    template<typename T,
+             typename std::enable_if<
+                 not (std::is_same<T, int>::value)
+                 and std::is_same<T, number_unsigned_t>::value
+                 , int>::type
+             = 0>
+    basic_json(const number_unsigned_t val) noexcept
+        : m_type(value_t::number_unsigned), m_value(val)
+    {}
+
+    /*!
+    @brief create an unsigned number (implicit)
+
+    Create an unsigned number JSON value with a given content. This constructor
+    allows any type @a CompatibleNumberUnsignedType that can be used to
+    construct values of type @ref number_unsigned_t.
+
+    @tparam CompatibleNumberUnsignedType An integer type which is compatible to
+    @ref number_unsigned_t. Examples may include the types `unsigned int`,
+    `uint32_t`, or `unsigned short`.
+
+    @param[in] val  an unsigned integer to create a JSON number from
+
+    @complexity Constant.
+
+    @sa @ref basic_json(const number_unsigned_t) -- create a number value
+    (unsigned)
+
+    @since version 2.0.0
+    */
+    template < typename CompatibleNumberUnsignedType, typename
+               std::enable_if <
+                   std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
+                   std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
+                   !std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
+                   CompatibleNumberUnsignedType >::type
+               = 0 >
+    basic_json(const CompatibleNumberUnsignedType val) noexcept
+        : m_type(value_t::number_unsigned),
+          m_value(static_cast<number_unsigned_t>(val))
+    {}
+
     /*!
     @brief create a floating-point number (explicit)
 
@@ -1248,7 +1478,7 @@ class basic_json
 
     @param[in] val  a floating-point value to create a JSON number from
 
-    @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
+    @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
     disallows NaN values:
     > Numeric values that cannot be represented in the grammar below (such
     > as Infinity and NaN) are not permitted.
@@ -1265,7 +1495,7 @@ class basic_json
 
     @since version 1.0.0
     */
-    basic_json(const number_float_t val)
+    basic_json(const number_float_t val) noexcept
         : m_type(value_t::number_float), m_value(val)
     {
         // replace infinity and NAN by null
@@ -1280,15 +1510,15 @@ class basic_json
     @brief create an floating-point number (implicit)
 
     Create an floating-point number JSON value with a given content. This
-    constructor allows any type that can be used to construct values of type
-    @ref number_float_t. Examples may include the types `float`.
+    constructor allows any type @a CompatibleNumberFloatType that can be used
+    to construct values of type @ref number_float_t.
 
-    @tparam CompatibleNumberFloatType a floating-point type which is compatible
-    to @ref number_float_t.
+    @tparam CompatibleNumberFloatType A floating-point type which is compatible
+    to @ref number_float_t. Examples may include the types `float` or `double`.
 
     @param[in] val  a floating-point to create a JSON number from
 
-    @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
+    @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
     disallows NaN values:
     > Numeric values that cannot be represented in the grammar below (such
     > as Infinity and NaN) are not permitted.
@@ -1297,7 +1527,7 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The example below shows the construction of several JSON
+    @liveexample{The example below shows the construction of several
     floating-point number values from compatible
     types.,basic_json__CompatibleNumberFloatType}
 
@@ -1375,7 +1605,7 @@ class basic_json
     @complexity Linear in the size of the initializer list @a init.
 
     @liveexample{The example below shows how JSON values are created from
-    initializer lists,basic_json__list_init_t}
+    initializer lists.,basic_json__list_init_t}
 
     @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
     value from an initializer list
@@ -1431,14 +1661,14 @@ class basic_json
 
             for (auto& element : init)
             {
-                m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1]));
+                m_value.object->emplace(*(element[0].m_value.string), element[1]);
             }
         }
         else
         {
             // the initializer list describes an array -> create array
             m_type = value_t::array;
-            m_value.array = create<array_t>(std::move(init));
+            m_value.array = create<array_t>(init);
         }
     }
 
@@ -1466,7 +1696,7 @@ class basic_json
 
     @complexity Linear in the size of @a init.
 
-    @liveexample{The following code shows an example for the @ref array
+    @liveexample{The following code shows an example for the `array`
     function.,array}
 
     @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
@@ -1506,7 +1736,7 @@ class basic_json
 
     @complexity Linear in the size of @a init.
 
-    @liveexample{The following code shows an example for the @ref object
+    @liveexample{The following code shows an example for the `object`
     function.,object}
 
     @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
@@ -1600,6 +1830,7 @@ class basic_json
             case value_t::boolean:
             case value_t::number_float:
             case value_t::number_integer:
+            case value_t::number_unsigned:
             case value_t::string:
             {
                 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
@@ -1624,6 +1855,13 @@ class basic_json
                 break;
             }
 
+            case value_t::number_unsigned:
+            {
+                assert(first.m_object != nullptr);
+                m_value.number_unsigned = first.m_object->m_value.number_unsigned;
+                break;
+            }
+
             case value_t::number_float:
             {
                 assert(first.m_object != nullptr);
@@ -1665,6 +1903,31 @@ class basic_json
         }
     }
 
+    /*!
+    @brief construct a JSON value given an input stream
+
+    @param[in,out] i  stream to read a serialized JSON value 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)
+
+    @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.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates constructing a JSON value from
+    a `std::stringstream` with and without callback
+    function.,basic_json__istream}
+
+    @since version 2.0.0
+    */
+    explicit basic_json(std::istream& i, parser_callback_t cb = nullptr)
+    {
+        *this = parser(i, cb).parse();
+    }
+
     ///////////////////////////////////////
     // other constructors and destructor //
     ///////////////////////////////////////
@@ -1678,7 +1941,9 @@ class basic_json
 
     @complexity Linear in the size of @a other.
 
-    @requirement This function satisfies the Container requirements:
+    @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)`.
 
@@ -1727,6 +1992,12 @@ class basic_json
                 break;
             }
 
+            case value_t::number_unsigned:
+            {
+                m_value = other.m_value.number_unsigned;
+                break;
+            }
+
             case value_t::number_float:
             {
                 m_value = other.m_value.number_float;
@@ -1778,7 +2049,9 @@ class basic_json
 
     @complexity Linear.
 
-    @requirement This function satisfies the Container requirements:
+    @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
@@ -1808,7 +2081,9 @@ class basic_json
 
     @complexity Linear.
 
-    @requirement This function satisfies the Container requirements:
+    @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.
 
@@ -1909,12 +2184,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref type() for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `type()` for all JSON
     types.,type}
 
     @since version 1.0.0
     */
-    value_t type() const noexcept
+    constexpr value_t type() const noexcept
     {
         return m_type;
     }
@@ -1930,12 +2208,21 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_primitive for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_primitive()` for all JSON
     types.,is_primitive}
 
+    @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
+
     @since version 1.0.0
     */
-    bool is_primitive() const noexcept
+    constexpr bool is_primitive() const noexcept
     {
         return is_null() or is_string() or is_boolean() or is_number();
     }
@@ -1950,12 +2237,19 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_structured for all JSON
+    @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
     */
-    bool is_structured() const noexcept
+    constexpr bool is_structured() const noexcept
     {
         return is_array() or is_object();
     }
@@ -1969,12 +2263,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_null for all JSON
+    @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
     */
-    bool is_null() const noexcept
+    constexpr bool is_null() const noexcept
     {
         return m_type == value_t::null;
     }
@@ -1988,12 +2285,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_boolean for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_boolean()` for all JSON
     types.,is_boolean}
 
     @since version 1.0.0
     */
-    bool is_boolean() const noexcept
+    constexpr bool is_boolean() const noexcept
     {
         return m_type == value_t::boolean;
     }
@@ -2004,20 +2304,26 @@ class basic_json
     This function returns true iff the JSON value is a number. This includes
     both integer and floating-point values.
 
-    @return `true` if type is number (regardless whether integer or
-    floating-type), `false` otherwise.
+    @return `true` if type is number (regardless whether integer, unsigned
+    integer or floating-type), `false` otherwise.
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_number for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number()` for all JSON
     types.,is_number}
 
-    @sa @ref is_number_integer() -- check if value is an integer number
+    @sa @ref is_number_integer() -- check if value is an integer or unsigned
+    integer number
+    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+    number
     @sa @ref is_number_float() -- check if value is a floating-point number
 
     @since version 1.0.0
     */
-    bool is_number() const noexcept
+    constexpr bool is_number() const noexcept
     {
         return is_number_integer() or is_number_float();
     }
@@ -2025,45 +2331,84 @@ class basic_json
     /*!
     @brief return whether value is an integer number
 
-    This function returns true iff the JSON value is an integer number. This
-    excludes floating-point values.
+    This function returns true iff the JSON value is an integer or unsigned
+    integer number. This excludes floating-point values.
 
-    @return `true` if type is an integer number, `false` otherwise.
+    @return `true` if type is an integer or unsigned integer number, `false`
+    otherwise.
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_number_integer for all
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number_integer()` for all
     JSON types.,is_number_integer}
 
     @sa @ref is_number() -- check if value is a number
+    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+    number
     @sa @ref is_number_float() -- check if value is a floating-point number
 
     @since version 1.0.0
     */
-    bool is_number_integer() const noexcept
+    constexpr bool is_number_integer() const noexcept
+    {
+        return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
+    }
+
+    /*!
+    @brief return whether value is an unsigned integer number
+
+    This function returns true iff the JSON value is an unsigned integer
+    number. This excludes floating-point and (signed) integer values.
+
+    @return `true` if type is an unsigned integer number, `false` otherwise.
+
+    @complexity Constant.
+
+    @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
+    */
+    constexpr bool is_number_unsigned() const noexcept
     {
-        return m_type == value_t::number_integer;
+        return m_type == value_t::number_unsigned;
     }
 
     /*!
     @brief return whether value is a floating-point number
 
     This function returns true iff the JSON value is a floating-point number.
-    This excludes integer values.
+    This excludes integer and unsigned integer values.
 
     @return `true` if type is a floating-point number, `false` otherwise.
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_number_float for all
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number_float()` for all
     JSON types.,is_number_float}
 
     @sa @ref is_number() -- check if value is number
     @sa @ref is_number_integer() -- check if value is an integer number
+    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+    number
 
     @since version 1.0.0
     */
-    bool is_number_float() const noexcept
+    constexpr bool is_number_float() const noexcept
     {
         return m_type == value_t::number_float;
     }
@@ -2077,12 +2422,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_object for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_object()` for all JSON
     types.,is_object}
 
     @since version 1.0.0
     */
-    bool is_object() const noexcept
+    constexpr bool is_object() const noexcept
     {
         return m_type == value_t::object;
     }
@@ -2096,12 +2444,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_array for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_array()` for all JSON
     types.,is_array}
 
     @since version 1.0.0
     */
-    bool is_array() const noexcept
+    constexpr bool is_array() const noexcept
     {
         return m_type == value_t::array;
     }
@@ -2115,12 +2466,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_string for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_string()` for all JSON
     types.,is_string}
 
     @since version 1.0.0
     */
-    bool is_string() const noexcept
+    constexpr bool is_string() const noexcept
     {
         return m_type == value_t::string;
     }
@@ -2139,12 +2493,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies @ref is_discarded for all JSON
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_discarded()` for all JSON
     types.,is_discarded}
 
     @since version 1.0.0
     */
-    bool is_discarded() const noexcept
+    constexpr bool is_discarded() const noexcept
     {
         return m_type == value_t::discarded;
     }
@@ -2159,12 +2516,15 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The following code exemplifies the value_t operator for all
-    JSON types.,operator__value_t}
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies the @ref value_t operator for
+    all JSON types.,operator__value_t}
 
     @since version 1.0.0
     */
-    operator value_t() const noexcept
+    constexpr operator value_t() const noexcept
     {
         return m_type;
     }
@@ -2328,6 +2688,11 @@ class basic_json
                 return static_cast<T>(m_value.number_integer);
             }
 
+            case value_t::number_unsigned:
+            {
+                return static_cast<T>(m_value.number_unsigned);
+            }
+
             case value_t::number_float:
             {
                 return static_cast<T>(m_value.number_float);
@@ -2341,16 +2706,11 @@ class basic_json
     }
 
     /// get a boolean (explicit)
-    boolean_t get_impl(boolean_t*) const
+    constexpr boolean_t get_impl(boolean_t*) const
     {
-        if (is_boolean())
-        {
-            return m_value.boolean;
-        }
-        else
-        {
-            throw std::domain_error("type must be boolean, but is " + type_name());
-        }
+        return is_boolean()
+               ? m_value.boolean
+               : throw std::domain_error("type must be boolean, but is " + type_name());
     }
 
     /// get a pointer to the value (object)
@@ -2360,7 +2720,7 @@ class basic_json
     }
 
     /// get a pointer to the value (object)
-    const object_t* get_impl_ptr(const object_t*) const noexcept
+    constexpr const object_t* get_impl_ptr(const object_t*) const noexcept
     {
         return is_object() ? m_value.object : nullptr;
     }
@@ -2372,7 +2732,7 @@ class basic_json
     }
 
     /// get a pointer to the value (array)
-    const array_t* get_impl_ptr(const array_t*) const noexcept
+    constexpr const array_t* get_impl_ptr(const array_t*) const noexcept
     {
         return is_array() ? m_value.array : nullptr;
     }
@@ -2384,7 +2744,7 @@ class basic_json
     }
 
     /// get a pointer to the value (string)
-    const string_t* get_impl_ptr(const string_t*) const noexcept
+    constexpr const string_t* get_impl_ptr(const string_t*) const noexcept
     {
         return is_string() ? m_value.string : nullptr;
     }
@@ -2396,7 +2756,7 @@ class basic_json
     }
 
     /// get a pointer to the value (boolean)
-    const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
+    constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
     {
         return is_boolean() ? &m_value.boolean : nullptr;
     }
@@ -2408,11 +2768,23 @@ class basic_json
     }
 
     /// get a pointer to the value (integer number)
-    const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
+    constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
     {
         return is_number_integer() ? &m_value.number_integer : nullptr;
     }
 
+    /// get a pointer to the value (unsigned number)
+    number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept
+    {
+        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+    }
+
+    /// get a pointer to the value (unsigned number)
+    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept
+    {
+        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+    }
+
     /// get a pointer to the value (floating-point number)
     number_float_t* get_impl_ptr(number_float_t*) noexcept
     {
@@ -2420,7 +2792,7 @@ class basic_json
     }
 
     /// get a pointer to the value (floating-point number)
-    const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
+    constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
     {
         return is_number_float() ? &m_value.number_float : nullptr;
     }
@@ -2510,8 +2882,8 @@ class basic_json
     @warning The pointer becomes invalid if the underlying JSON object changes.
 
     @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
-    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
-    number_float_t.
+    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+    @ref number_unsigned_t, or @ref number_float_t.
 
     @return pointer to the internally stored JSON value if the requested
     pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2545,7 +2917,7 @@ class basic_json
              std::enable_if<
                  std::is_pointer<PointerType>::value
                  , int>::type = 0>
-    const PointerType get() const noexcept
+    constexpr const PointerType get() const noexcept
     {
         // delegate the call to get_ptr
         return get_ptr<PointerType>();
@@ -2561,8 +2933,8 @@ class basic_json
     state.
 
     @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
-    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
-    number_float_t.
+    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+    @ref number_unsigned_t, or @ref number_float_t.
 
     @return pointer to the internally stored JSON value if the requested
     pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2595,7 +2967,7 @@ class basic_json
                  std::is_pointer<PointerType>::value
                  and std::is_const<typename std::remove_pointer<PointerType>::type>::value
                  , int>::type = 0>
-    const PointerType get_ptr() const noexcept
+    constexpr const PointerType get_ptr() const noexcept
     {
         // delegate the call to get_impl_ptr<>() const
         return get_impl_ptr(static_cast<const PointerType>(nullptr));
@@ -2660,9 +3032,9 @@ class basic_json
 
     @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`.
+    `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`.
 
     @return copy of the JSON value, converted to type @a ValueType
 
@@ -2722,7 +3094,7 @@ class basic_json
     @complexity Constant.
 
     @liveexample{The example below shows how array elements can be read and
-    written using at.,at__size_type}
+    written using `at()`.,at__size_type}
 
     @since version 1.0.0
     */
@@ -2766,7 +3138,7 @@ class basic_json
     @complexity Constant.
 
     @liveexample{The example below shows how array elements can be read using
-    at.,at__size_type_const}
+    `at()`.,at__size_type_const}
 
     @since version 1.0.0
     */
@@ -2810,7 +3182,7 @@ class basic_json
     @complexity Logarithmic in the size of the container.
 
     @liveexample{The example below shows how object elements can be read and
-    written using at.,at__object_t_key_type}
+    written using `at()`.,at__object_t_key_type}
 
     @sa @ref operator[](const typename object_t::key_type&) for unchecked
     access by reference
@@ -2858,7 +3230,7 @@ class basic_json
     @complexity Logarithmic in the size of the container.
 
     @liveexample{The example below shows how object elements can be read using
-    at.,at__object_t_key_type_const}
+    `at()`.,at__object_t_key_type_const}
 
     @sa @ref operator[](const typename object_t::key_type&) for unchecked
     access by reference
@@ -2901,30 +3273,31 @@ class basic_json
 
     @return reference to the element at index @a idx
 
-    @throw std::domain_error if JSON is not an array or null; example: `"cannot
-    use operator[] with null"`
+    @throw std::domain_error if JSON is not an array or null; example:
+    `"cannot use operator[] with string"`
 
     @complexity Constant if @a idx is in the range of the array. Otherwise
     linear in `idx - size()`.
 
     @liveexample{The example below shows how array elements can be read and
-    written using [] operator. Note the addition of `null`
+    written using `[]` operator. Note the addition of `null`
     values.,operatorarray__size_type}
 
     @since version 1.0.0
     */
     reference operator[](size_type idx)
     {
-        // implicitly convert null to object
+        // implicitly convert null value to an empty array
         if (is_null())
         {
             m_type = value_t::array;
             m_value.array = create<array_t>();
         }
 
-        // [] only works for arrays
+        // operator[] only works for arrays
         if (is_array())
         {
+            // fill up array with null values until given idx is reached
             assert(m_value.array != nullptr);
             for (size_t i = m_value.array->size(); i <= idx; ++i)
             {
@@ -2954,13 +3327,13 @@ class basic_json
     @complexity Constant.
 
     @liveexample{The example below shows how array elements can be read using
-    the [] operator.,operatorarray__size_type_const}
+    the `[]` operator.,operatorarray__size_type_const}
 
     @since version 1.0.0
     */
     const_reference operator[](size_type idx) const
     {
-        // at only works for arrays
+        // const operator[] only works for arrays
         if (is_array())
         {
             assert(m_value.array != nullptr);
@@ -2986,12 +3359,12 @@ class basic_json
     @return reference to the element at key @a key
 
     @throw std::domain_error if JSON is not an object or null; example:
-    `"cannot use operator[] with null"`
+    `"cannot use operator[] with string"`
 
     @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}
+    written using the `[]` operator.,operatorarray__key_type}
 
     @sa @ref at(const typename object_t::key_type&) for access by reference
     with range checking
@@ -3001,14 +3374,14 @@ class basic_json
     */
     reference operator[](const typename object_t::key_type& key)
     {
-        // implicitly convert null to object
+        // implicitly convert null value to an empty object
         if (is_null())
         {
             m_type = value_t::object;
             m_value.object = create<object_t>();
         }
 
-        // [] only works for objects
+        // operator[] only works for objects
         if (is_object())
         {
             assert(m_value.object != nullptr);
@@ -3039,7 +3412,7 @@ class basic_json
     @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}
+    the `[]` operator.,operatorarray__key_type_const}
 
     @sa @ref at(const typename object_t::key_type&) for access by reference
     with range checking
@@ -3049,7 +3422,7 @@ class basic_json
     */
     const_reference operator[](const typename object_t::key_type& key) const
     {
-        // [] only works for objects
+        // const operator[] only works for objects
         if (is_object())
         {
             assert(m_value.object != nullptr);
@@ -3076,12 +3449,12 @@ class basic_json
     @return reference to the element at key @a key
 
     @throw std::domain_error if JSON is not an object or null; example:
-    `"cannot use operator[] with null"`
+    `"cannot use operator[] with string"`
 
     @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}
+    written using the `[]` operator.,operatorarray__key_type}
 
     @sa @ref at(const typename object_t::key_type&) for access by reference
     with range checking
@@ -3116,7 +3489,7 @@ class basic_json
     @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}
+    the `[]` operator.,operatorarray__key_type_const}
 
     @sa @ref at(const typename object_t::key_type&) for access by reference
     with range checking
@@ -3144,12 +3517,12 @@ class basic_json
     @return reference to the element at key @a key
 
     @throw std::domain_error if JSON is not an object or null; example:
-    `"cannot use operator[] with null"`
+    `"cannot use operator[] with string"`
 
     @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}
+    written using the `[]` operator.,operatorarray__key_type}
 
     @sa @ref at(const typename object_t::key_type&) for access by reference
     with range checking
@@ -3198,7 +3571,7 @@ class basic_json
     @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}
+    the `[]` operator.,operatorarray__key_type_const}
 
     @sa @ref at(const typename object_t::key_type&) for access by reference
     with range checking
@@ -3317,11 +3690,15 @@ class basic_json
 
     @complexity Constant.
 
-    @note Calling `front` on an empty container is undefined.
+    @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.
+
+    @throw std::out_of_range when called on `null` value
 
-    @throw std::out_of_range when called on null value
+    @liveexample{The following code shows an example for `front()`.,front}
 
-    @liveexample{The following code shows an example for @ref front.,front}
+    @sa @ref back() -- access the last element
 
     @since version 1.0.0
     */
@@ -3342,8 +3719,12 @@ class basic_json
     @brief access the last element
 
     Returns a reference to the last element in the container. For a JSON
-    container `c`, the expression `c.back()` is equivalent to `{ auto tmp =
-    c.end(); --tmp; return *tmp; }`.
+    container `c`, the expression `c.back()` is equivalent to
+    @code {.cpp}
+    auto tmp = c.end();
+    --tmp;
+    return *tmp;
+    @endcode
 
     @return In case of a structured type (array or object), a reference to the
     last element is returned. In cast of number, string, or boolean values, a
@@ -3351,11 +3732,15 @@ class basic_json
 
     @complexity Constant.
 
-    @note Calling `back` on an empty container is undefined.
+    @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.
 
-    @throw std::out_of_range when called on null value.
+    @throw std::out_of_range when called on `null` value.
 
-    @liveexample{The following code shows an example for @ref back.,back}
+    @liveexample{The following code shows an example for `back()`.,back}
+
+    @sa @ref front() -- access the first element
 
     @since version 1.0.0
     */
@@ -3379,28 +3764,29 @@ class basic_json
     /*!
     @brief remove element given an iterator
 
-    Removes the element specified by iterator @a pos. Invalidates iterators and
-    references at or after the point of the erase, including the end()
-    iterator. 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.
+    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.
 
-    If called on a primitive type other than null, the resulting JSON value
+    If called on a primitive type other than `null`, the resulting JSON value
     will be `null`.
 
     @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.
+    refers to the last element, the `end()` iterator is returned.
 
     @tparam InteratorType 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 std::domain_error if called on a `null` value; example: `"cannot use
     erase() with null"`
     @throw std::domain_error if called on an iterator which does not belong to
     the current JSON value; example: `"iterator does not fit current value"`
     @throw std::out_of_range if called on a primitive type with invalid
-    iterator (i.e., any iterator which is not end()); example: `"iterator out
-    of range"`
+    iterator (i.e., any iterator which is not `begin()`); example: `"iterator
+    out of range"`
 
     @complexity The complexity depends on the type:
     - objects: amortized constant
@@ -3408,7 +3794,7 @@ class basic_json
     - strings: linear in the length of the string
     - other types: constant
 
-    @liveexample{The example shows the result of erase for different JSON
+    @liveexample{The example shows the result of `erase()` for different JSON
     types.,erase__IteratorType}
 
     @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
@@ -3441,6 +3827,7 @@ class basic_json
             case value_t::boolean:
             case value_t::number_float:
             case value_t::number_integer:
+            case value_t::number_unsigned:
             case value_t::string:
             {
                 if (not pos.m_it.primitive_iterator.is_begin())
@@ -3484,21 +3871,23 @@ class basic_json
     /*!
     @brief remove elements given an iterator range
 
-    Removes the element specified by the range `[first; last)`. Invalidates
-    iterators and references at or after the point of the erase, including the
-    end() iterator. The iterator @a first does not need to be dereferenceable
-    if `first == last`: erasing an empty range is a no-op.
+    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.
 
-    If called on a primitive type other than null, the resulting JSON value
+    If called on a primitive type other than `null`, the resulting JSON value
     will be `null`.
 
     @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.
+    second refers to the last element, the `end()` iterator is returned.
 
     @tparam InteratorType 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 std::domain_error if called on a `null` value; example: `"cannot use
     erase() with null"`
     @throw std::domain_error if called on iterators which does not belong to
@@ -3514,7 +3903,7 @@ class basic_json
     - strings: linear in the length of the string
     - other types: constant
 
-    @liveexample{The example shows the result of erase for different JSON
+    @liveexample{The example shows the result of `erase()` for different JSON
     types.,erase__IteratorType_IteratorType}
 
     @sa @ref erase(InteratorType) -- removes the element at a given position
@@ -3546,6 +3935,7 @@ class basic_json
             case value_t::boolean:
             case value_t::number_float:
             case value_t::number_integer:
+            case value_t::number_unsigned:
             case value_t::string:
             {
                 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
@@ -3595,16 +3985,19 @@ class basic_json
 
     @param[in] key value of the elements to remove
 
-    @return Number of elements removed. 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).
+    @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).
+
+    @post References and iterators to the erased elements are invalidated.
+    Other references and iterators are not affected.
 
     @throw std::domain_error 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}
+    @liveexample{The example shows the effect of `erase()`.,erase__key_type}
 
     @sa @ref erase(InteratorType) -- removes the element at a given position
     @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
@@ -3637,12 +4030,12 @@ class basic_json
 
     @throw std::domain_error when called on a type other than JSON array;
     example: `"cannot use erase() with null"`
-    @throw std::out_of_range when `idx >= size()`; example: `"index out of
-    range"`
+    @throw std::out_of_range 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}
+    @liveexample{The example shows the effect of `erase()`.,erase__size_type}
 
     @sa @ref erase(InteratorType) -- removes the element at a given position
     @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
@@ -3659,7 +4052,7 @@ class basic_json
         {
             if (idx >= size())
             {
-                throw std::out_of_range("index out of range");
+                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
             }
 
             assert(m_value.array != nullptr);
@@ -3671,6 +4064,16 @@ class basic_json
         }
     }
 
+    /// @}
+
+
+    ////////////
+    // lookup //
+    ////////////
+
+    /// @name lookup
+    /// @{
+
     /*!
     @brief find an element in a JSON object
 
@@ -3684,7 +4087,7 @@ class basic_json
 
     @complexity Logarithmic in the size of the JSON object.
 
-    @liveexample{The example shows how find is used.,find__key_type}
+    @liveexample{The example shows how `find()` is used.,find__key_type}
 
     @since version 1.0.0
     */
@@ -3732,7 +4135,7 @@ class basic_json
 
     @complexity Logarithmic in the size of the JSON object.
 
-    @liveexample{The example shows how count is used.,count}
+    @liveexample{The example shows how `count()` is used.,count}
 
     @since version 1.0.0
     */
@@ -3764,14 +4167,20 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the Container requirements:
+    @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 @ref begin.,begin}
+    @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()
+    iterator begin() noexcept
     {
         iterator result(this);
         result.set_begin();
@@ -3781,7 +4190,7 @@ class basic_json
     /*!
     @copydoc basic_json::cbegin()
     */
-    const_iterator begin() const
+    const_iterator begin() const noexcept
     {
         return cbegin();
     }
@@ -3797,15 +4206,21 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the Container requirements:
+    @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 @ref cbegin.,cbegin}
+    @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
+    const_iterator cbegin() const noexcept
     {
         const_iterator result(this);
         result.set_begin();
@@ -3823,14 +4238,20 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the Container requirements:
+    @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 @ref end.,end}
+    @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()
+    iterator end() noexcept
     {
         iterator result(this);
         result.set_end();
@@ -3840,7 +4261,7 @@ class basic_json
     /*!
     @copydoc basic_json::cend()
     */
-    const_iterator end() const
+    const_iterator end() const noexcept
     {
         return cend();
     }
@@ -3856,15 +4277,21 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the Container requirements:
+    @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 @ref cend.,cend}
+    @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
+    const_iterator cend() const noexcept
     {
         const_iterator result(this);
         result.set_end();
@@ -3880,15 +4307,21 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the ReversibleContainer requirements:
+    @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 @ref rbegin.,rbegin}
+    @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()
+    reverse_iterator rbegin() noexcept
     {
         return reverse_iterator(end());
     }
@@ -3896,7 +4329,7 @@ class basic_json
     /*!
     @copydoc basic_json::crbegin()
     */
-    const_reverse_iterator rbegin() const
+    const_reverse_iterator rbegin() const noexcept
     {
         return crbegin();
     }
@@ -3911,15 +4344,21 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the ReversibleContainer requirements:
+    @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 @ref rend.,rend}
+    @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()
+    reverse_iterator rend() noexcept
     {
         return reverse_iterator(begin());
     }
@@ -3927,7 +4366,7 @@ class basic_json
     /*!
     @copydoc basic_json::crend()
     */
-    const_reverse_iterator rend() const
+    const_reverse_iterator rend() const noexcept
     {
         return crend();
     }
@@ -3942,15 +4381,21 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the ReversibleContainer requirements:
+    @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 @ref crbegin.,crbegin}
+    @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
+    const_reverse_iterator crbegin() const noexcept
     {
         return const_reverse_iterator(cend());
     }
@@ -3965,15 +4410,21 @@ class basic_json
 
     @complexity Constant.
 
-    @requirement This function satisfies the ReversibleContainer requirements:
+    @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 @ref crend.,crend}
+    @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
+    const_reverse_iterator crend() const noexcept
     {
         return const_reverse_iterator(cbegin());
     }
@@ -4026,24 +4477,28 @@ class basic_json
             defined as follows:
             Value type  | return value
             ----------- | -------------
-            null        | @c true
-            boolean     | @c false
-            string      | @c false
-            number      | @c false
-            object      | result of function object_t::empty()
-            array       | result of function array_t::empty()
+            null        | `true`
+            boolean     | `false`
+            string      | `false`
+            number      | `false`
+            object      | result of function `object_t::empty()`
+            array       | result of function `array_t::empty()`
 
     @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
-    Container concept; that is, their empty() functions have constant
+    Container concept; that is, their `empty()` functions have constant
     complexity.
 
-    @requirement This function satisfies the Container requirements:
+    @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()`.
 
-    @liveexample{The following code uses @ref empty to check if a @ref json
+    @liveexample{The following code uses `empty()` to check if a JSON
     object contains any elements.,empty}
 
+    @sa @ref size() -- returns the number of elements
+
     @since version 1.0.0
     */
     bool empty() const noexcept
@@ -4085,23 +4540,28 @@ class basic_json
             defined as follows:
             Value type  | return value
             ----------- | -------------
-            null        | @c 0
-            boolean     | @c 1
-            string      | @c 1
-            number      | @c 1
+            null        | `0`
+            boolean     | `1`
+            string      | `1`
+            number      | `1`
             object      | result of function object_t::size()
             array       | result of function array_t::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.
 
-    @requirement This function satisfies the Container requirements:
+    @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())`.
 
-    @liveexample{The following code calls @ref size on the different value
+    @liveexample{The following code calls `size()` on the different value
     types.,size}
 
+    @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
@@ -4145,25 +4605,29 @@ class basic_json
             defined as follows:
             Value type  | return value
             ----------- | -------------
-            null        | @c 0 (same as size())
-            boolean     | @c 1 (same as size())
-            string      | @c 1 (same as size())
-            number      | @c 1 (same as size())
-            object      | result of function object_t::max_size()
-            array       | result of function array_t::max_size()
+            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()`
 
     @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
-    Container concept; that is, their max_size() functions have constant
+    Container concept; that is, their `max_size()` functions have constant
     complexity.
 
-    @requirement This function satisfies the Container requirements:
+    @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.
 
-    @liveexample{The following code calls @ref max_size on the different value
+    @liveexample{The following code calls `max_size()` on the different value
     types. Note the output is implementation specific.,max_size}
 
+    @sa @ref size() -- returns the number of elements
+
     @since version 1.0.0
     */
     size_type max_size() const noexcept
@@ -4220,7 +4684,7 @@ class basic_json
 
     @complexity Linear in the size of the JSON value.
 
-    @liveexample{The example below shows the effect of @ref clear to different
+    @liveexample{The example below shows the effect of `clear()` to different
     JSON types.,clear}
 
     @since version 1.0.0
@@ -4235,6 +4699,12 @@ class basic_json
                 break;
             }
 
+            case value_t::number_unsigned:
+            {
+                m_value.number_unsigned = 0;
+                break;
+            }
+
             case value_t::number_float:
             {
                 m_value.number_float = 0.0;
@@ -4282,16 +4752,16 @@ class basic_json
     function is called on a JSON null value, an empty array is created before
     appending @a val.
 
-    @param val the value to add to the JSON array
+    @param[in] val the value to add to the JSON array
 
     @throw std::domain_error 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}
+    @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
     */
@@ -4375,9 +4845,9 @@ class basic_json
 
     @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}
+    @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
     */
@@ -4408,32 +4878,80 @@ class basic_json
     reference operator+=(const typename object_t::value_type& val)
     {
         push_back(val);
-        return operator[](val.first);
+        return *this;
     }
 
     /*!
-    @brief inserts element
+    @brief add an object to an object
 
-    Inserts element @a val before iterator @a pos.
+    This function allows to use `push_back` with an initializer list. In case
 
-    @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.
+    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,
 
-    @throw std::domain_error if called on JSON values other than arrays;
-    example: `"cannot use insert() with string"`
-    @throw std::domain_error if @a pos is not an iterator of *this; example:
-    `"iterator does not fit current value"`
+    @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&&).
 
-    @complexity Constant plus linear in the distance between pos and end of the
-    container.
+    @param init  an initializer list
 
-    @liveexample{The example shows how insert is used.,insert}
+    @complexity Linear in the size of the initializer list @a init.
 
-    @since version 1.0.0
+    @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}
     */
-    iterator insert(const_iterator pos, const basic_json& val)
+    void push_back(std::initializer_list<basic_json> init)
+    {
+        if (is_object() and init.size() == 2 and init.begin()->is_string())
+        {
+            const string_t key = *init.begin();
+            push_back(typename object_t::value_type(key, *(init.begin() + 1)));
+        }
+        else
+        {
+            push_back(basic_json(init));
+        }
+    }
+
+    /*!
+    @brief add an object to an object
+    @copydoc push_back(std::initializer_list<basic_json>)
+    */
+    reference operator+=(std::initializer_list<basic_json> init)
+    {
+        push_back(init);
+        return *this;
+    }
+
+    /*!
+    @brief inserts element
+
+    Inserts element @a val before iterator @a pos.
+
+    @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.
+
+    @throw std::domain_error if called on JSON values other than arrays;
+    example: `"cannot use insert() with string"`
+    @throw std::domain_error if @a pos is not an iterator of *this; example:
+    `"iterator does not fit current value"`
+
+    @complexity Constant plus linear in the distance between pos and end of the
+    container.
+
+    @liveexample{The example shows how `insert()` is used.,insert}
+
+    @since version 1.0.0
+    */
+    iterator insert(const_iterator pos, const basic_json& val)
     {
         // insert only works for arrays
         if (is_array())
@@ -4485,7 +5003,7 @@ class basic_json
     @complexity Linear in @a cnt plus linear in the distance between @a pos
     and end of the container.
 
-    @liveexample{The example shows how insert is used.,insert__count}
+    @liveexample{The example shows how `insert()` is used.,insert__count}
 
     @since version 1.0.0
     */
@@ -4538,7 +5056,7 @@ class basic_json
     @complexity Linear in `std::distance(first, last)` plus linear in the
     distance between @a pos and end of the container.
 
-    @liveexample{The example shows how insert is used.,insert__range}
+    @liveexample{The example shows how `insert()` is used.,insert__range}
 
     @since version 1.0.0
     */
@@ -4596,7 +5114,7 @@ class basic_json
     @complexity Linear in `ilist.size()` plus linear in the distance between @a
     pos and end of the container.
 
-    @liveexample{The example shows how insert is used.,insert__ilist}
+    @liveexample{The example shows how `insert()` is used.,insert__ilist}
 
     @since version 1.0.0
     */
@@ -4633,8 +5151,8 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The example below shows how JSON arrays can be
-    swapped.,swap__reference}
+    @liveexample{The example below shows how JSON values can be swapped with
+    `swap()`.,swap__reference}
 
     @since version 1.0.0
     */
@@ -4664,8 +5182,8 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The example below shows how JSON values can be
-    swapped.,swap__array_t}
+    @liveexample{The example below shows how arrays can be swapped with
+    `swap()`.,swap__array_t}
 
     @since version 1.0.0
     */
@@ -4698,8 +5216,8 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The example below shows how JSON values can be
-    swapped.,swap__object_t}
+    @liveexample{The example below shows how objects can be swapped with
+    `swap()`.,swap__object_t}
 
     @since version 1.0.0
     */
@@ -4732,8 +5250,8 @@ class basic_json
 
     @complexity Constant.
 
-    @liveexample{The example below shows how JSON values can be
-    swapped.,swap__string_t}
+    @liveexample{The example below shows how strings can be swapped with
+    `swap()`.,swap__string_t}
 
     @since version 1.0.0
     */
@@ -4771,16 +5289,17 @@ class basic_json
 
     @since version 1.0.0
     */
-    friend bool operator<(const value_t lhs, const value_t rhs)
+    friend bool operator<(const value_t lhs, const value_t rhs) noexcept
     {
-        static constexpr std::array<uint8_t, 7> order = {{
+        static constexpr std::array<uint8_t, 8> order = {{
                 0, // null
                 3, // object
                 4, // array
                 5, // string
                 1, // boolean
                 2, // integer
-                2  // float
+                2, // unsigned
+                2, // float
             }
         };
 
@@ -4856,6 +5375,10 @@ class basic_json
                 {
                     return lhs.m_value.number_integer == rhs.m_value.number_integer;
                 }
+                case value_t::number_unsigned:
+                {
+                    return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
+                }
                 case value_t::number_float:
                 {
                     return lhs.m_value.number_float == rhs.m_value.number_float;
@@ -4874,6 +5397,23 @@ class basic_json
         {
             return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
         }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+        {
+            return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
+        }
+        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+        {
+            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
+        }
+        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
+        }
+
         return false;
     }
 
@@ -5025,6 +5565,10 @@ class basic_json
                 {
                     return lhs.m_value.number_integer < rhs.m_value.number_integer;
                 }
+                case value_t::number_unsigned:
+                {
+                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
+                }
                 case value_t::number_float:
                 {
                     return lhs.m_value.number_float < rhs.m_value.number_float;
@@ -5037,13 +5581,27 @@ class basic_json
         }
         else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
         {
-            return static_cast<number_float_t>(lhs.m_value.number_integer) <
-                   rhs.m_value.number_float;
+            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
         }
         else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
         {
-            return lhs.m_value.number_float <
-                   static_cast<number_float_t>(rhs.m_value.number_integer);
+            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+        {
+            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
+        }
+        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
+        }
+        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+        {
+            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
         }
 
         // We only reach this line if we cannot compare values. In that case,
@@ -5199,7 +5757,7 @@ class basic_json
 
     @note A UTF-8 byte order mark is silently ignored.
 
-    @liveexample{The example below demonstrates the parse function with and
+    @liveexample{The example below demonstrates the `parse()` function with and
     without callback function.,parse__string__parser_callback_t}
 
     @sa @ref parse(std::istream&, parser_callback_t) for a version that reads
@@ -5228,7 +5786,7 @@ class basic_json
 
     @note A UTF-8 byte order mark is silently ignored.
 
-    @liveexample{The example below demonstrates the parse function with and
+    @liveexample{The example below demonstrates the `parse()` function with and
     without callback function.,parse__istream__parser_callback_t}
 
     @sa @ref parse(const string_t&, parser_callback_t) for a version that reads
@@ -5297,7 +5855,7 @@ class basic_json
     ///////////////////////////
 
     /// return the type as string
-    string_t type_name() const
+    string_t type_name() const noexcept
     {
         switch (m_type)
         {
@@ -5375,7 +5933,7 @@ class basic_json
 
     @complexity Linear in the length of string @a s.
     */
-    static string_t escape_string(const string_t& s) noexcept
+    static string_t escape_string(const string_t& s)
     {
         const auto space = extra_space(s);
         if (space == 0)
@@ -5451,7 +6009,8 @@ class basic_json
                 {
                     if (c >= 0x00 and c <= 0x1f)
                     {
-                        // convert a number 0..15 to its hex representation (0..f)
+                        // convert a number 0..15 to its hex representation
+                        // (0..f)
                         auto hexify = [](const char v) -> char
                         {
                             return (v < 10) ? ('0' + v) : ('a' + v - 10);
@@ -5488,9 +6047,9 @@ class basic_json
     additional parameter. In case of arrays and objects, the function is called
     recursively. Note that
 
-    - 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
+    - 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
 
     @param[out] o              stream to write to
     @param[in] pretty_print    whether the output shall be pretty-printed
@@ -5608,25 +6167,88 @@ class basic_json
                 return;
             }
 
+            case value_t::number_unsigned:
+            {
+                o << m_value.number_unsigned;
+                return;
+            }
+
             case value_t::number_float:
             {
-                // If the number is an integer then output as a fixed with with
-                // precision 1 to output "0.0", "1.0" etc as expected for some
-                // round trip tests otherwise  15 digits of precision allows
-                // round-trip IEEE 754 string->double->string; to be safe, we
-                // read this value from
-                // std::numeric_limits<number_float_t>::digits10
-                if (std::fmod(m_value.number_float, 1) == 0)
+                // check if number was parsed from a string
+                if (m_type.bits.parsed)
                 {
-                    o << std::fixed << std::setprecision(1);
+                    // check if parsed number had an exponent given
+                    if (m_type.bits.has_exp)
+                    {
+                        // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
+                        char buf[263];
+                        int len;
+
+                        // handle capitalization of the exponent
+                        if (m_type.bits.exp_cap)
+                        {
+                            len = snprintf(buf, sizeof(buf), "%.*E",
+                                           m_type.bits.precision, m_value.number_float) + 1;
+                        }
+                        else
+                        {
+                            len = snprintf(buf, sizeof(buf), "%.*e",
+                                           m_type.bits.precision, m_value.number_float) + 1;
+                        }
+
+                        // remove '+' sign from the exponent if necessary
+                        if (not m_type.bits.exp_plus)
+                        {
+                            if (len > static_cast<int>(sizeof(buf)))
+                            {
+                                len = sizeof(buf);
+                            }
+                            for (int i = 0; i < len; i++)
+                            {
+                                if (buf[i] == '+')
+                                {
+                                    for (; i + 1 < len; i++)
+                                    {
+                                        buf[i] = buf[i + 1];
+                                    }
+                                }
+                            }
+                        }
+
+                        o << buf;
+                    }
+                    else
+                    {
+                        // no exponent - output as a decimal
+                        std::stringstream ss;
+                        ss.imbue(std::locale(std::locale(), new DecimalSeparator));  // fix locale problems
+                        ss << std::setprecision(m_type.bits.precision)
+                           << std::fixed << m_value.number_float;
+                        o << ss.str();
+                    }
                 }
                 else
                 {
-                    // std::defaultfloat not supported in gcc version < 5
-                    o.unsetf(std::ios_base::floatfield);
-                    o << std::setprecision(std::numeric_limits<double>::digits10);
+                    if (m_value.number_float == 0)
+                    {
+                        // special case for zero to get "0.0"/"-0.0"
+                        o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
+                    }
+                    else
+                    {
+                        // Otherwise 6, 15 or 16 digits of precision allows
+                        // round-trip IEEE 754 string->float->string,
+                        // string->double->string or string->long double->string;
+                        // to be safe, we read this value from
+                        // std::numeric_limits<number_float_t>::digits10
+                        std::stringstream ss;
+                        ss.imbue(std::locale(std::locale(), new DecimalSeparator));  // fix locale problems
+                        ss << std::setprecision(std::numeric_limits<double>::digits10)
+                           << m_value.number_float;
+                        o << ss.str();
+                    }
                 }
-                o << m_value.number_float;
                 return;
             }
 
@@ -5650,7 +6272,7 @@ class basic_json
     //////////////////////
 
     /// the type of the current element
-    value_t m_type = value_t::null;
+    type_data_t m_type = value_t::null;
 
     /// the value of the current element
     json_value m_value = {};
@@ -5674,37 +6296,37 @@ class basic_json
     {
       public:
         /// set iterator to a defined beginning
-        void set_begin()
+        void set_begin() noexcept
         {
             m_it = begin_value;
         }
 
         /// set iterator to a defined past the end
-        void set_end()
+        void set_end() noexcept
         {
             m_it = end_value;
         }
 
         /// return whether the iterator can be dereferenced
-        bool is_begin() const
+        constexpr bool is_begin() const noexcept
         {
             return (m_it == begin_value);
         }
 
         /// return whether the iterator is at end
-        bool is_end() const
+        constexpr bool is_end() const noexcept
         {
             return (m_it == end_value);
         }
 
         /// return reference to the value to change and compare
-        operator difference_type& ()
+        operator difference_type& () noexcept
         {
             return m_it;
         }
 
         /// return value to compare
-        operator difference_type () const
+        constexpr operator difference_type () const noexcept
         {
             return m_it;
         }
@@ -5734,7 +6356,7 @@ class basic_json
         primitive_iterator_t primitive_iterator;
 
         /// create an uninitialized internal_iterator
-        internal_iterator()
+        internal_iterator() noexcept
             : object_iterator(), array_iterator(), primitive_iterator()
         {}
     };
@@ -5754,7 +6376,7 @@ class basic_json
             size_t array_index = 0;
 
           public:
-            iteration_proxy_internal(IteratorType it)
+            explicit iteration_proxy_internal(IteratorType it) noexcept
                 : anchor(it)
             {}
 
@@ -5818,18 +6440,18 @@ class basic_json
 
       public:
         /// construct iteration proxy from a container
-        iteration_proxy(typename IteratorType::reference cont)
+        explicit iteration_proxy(typename IteratorType::reference cont)
             : container(cont)
         {}
 
         /// return iterator begin (needed for range-based for)
-        iteration_proxy_internal begin()
+        iteration_proxy_internal begin() noexcept
         {
             return iteration_proxy_internal(container.begin());
         }
 
         /// return iterator end (needed for range-based for)
-        iteration_proxy_internal end()
+        iteration_proxy_internal end() noexcept
         {
             return iteration_proxy_internal(container.end());
         }
@@ -5870,7 +6492,8 @@ class basic_json
         const_iterator() = default;
 
         /// constructor for a given JSON instance
-        const_iterator(pointer object) : m_object(object)
+        explicit const_iterator(pointer object) noexcept
+            : m_object(object)
         {
             assert(m_object != nullptr);
 
@@ -5897,7 +6520,8 @@ class basic_json
         }
 
         /// copy constructor given a nonconst iterator
-        const_iterator(const iterator& other) : m_object(other.m_object)
+        explicit const_iterator(const iterator& other) noexcept
+            : m_object(other.m_object)
         {
             assert(m_object != nullptr);
 
@@ -5943,7 +6567,7 @@ class basic_json
 
       private:
         /// set the iterator to the first value
-        void set_begin()
+        void set_begin() noexcept
         {
             assert(m_object != nullptr);
 
@@ -5979,7 +6603,7 @@ class basic_json
         }
 
         /// set the iterator past the last value
-        void set_end()
+        void set_end() noexcept
         {
             assert(m_object != nullptr);
 
@@ -6402,7 +7026,7 @@ class basic_json
         iterator() = default;
 
         /// constructor for a given JSON instance
-        iterator(pointer object) noexcept
+        explicit iterator(pointer object) noexcept
             : base_iterator(object)
         {}
 
@@ -6424,13 +7048,13 @@ class basic_json
         }
 
         /// return a reference to the value pointed to by the iterator
-        reference operator*()
+        reference operator*() const
         {
             return const_cast<reference>(base_iterator::operator*());
         }
 
         /// dereference the iterator
-        pointer operator->()
+        pointer operator->() const
         {
             return const_cast<pointer>(base_iterator::operator->());
         }
@@ -6495,6 +7119,7 @@ class basic_json
             return result;
         }
 
+        /// return difference
         difference_type operator-(const iterator& other) const
         {
             return base_iterator::operator-(other);
@@ -6540,12 +7165,12 @@ class basic_json
         using reference = typename Base::reference;
 
         /// create reverse iterator from iterator
-        json_reverse_iterator(const typename base_iterator::iterator_type& it)
+        json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
             : base_iterator(it)
         {}
 
         /// create reverse iterator from base class
-        json_reverse_iterator(const base_iterator& it)
+        json_reverse_iterator(const base_iterator& it) noexcept
             : base_iterator(it)
         {}
 
@@ -6635,7 +7260,7 @@ class basic_json
     @brief lexical analysis
 
     This class organizes the lexical analysis during JSON deserialization. The
-    core of it is a scanner generated by re2c <http://re2c.org> that processes
+    core of it is a scanner generated by [re2c](http://re2c.org) that processes
     a buffer and recognizes tokens according to RFC 7159.
     */
     class lexer
@@ -6644,20 +7269,20 @@ class basic_json
         /// 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_number,     ///< a number -- use get_number() 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
+            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_number,    ///< a number -- use get_number() 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
         };
 
         /// the char type to use in the lexer
@@ -6710,8 +7335,6 @@ class basic_json
         static string_t to_unicode(const std::size_t codepoint1,
                                    const std::size_t codepoint2 = 0)
         {
-            string_t result;
-
             // calculate the codepoint from the given code points
             std::size_t codepoint = codepoint1;
 
@@ -6737,6 +7360,8 @@ class basic_json
                 }
             }
 
+            string_t result;
+
             if (codepoint < 0x80)
             {
                 // 1-byte characters: 0xxxxxxx (ASCII)
@@ -6815,10 +7440,10 @@ class basic_json
         /*!
         This function implements a scanner for JSON. It is specified using
         regular expressions that try to follow RFC 7159 as close as possible.
-        These regular expressions are then translated into a deterministic
-        finite automaton (DFA) by the tool re2c <http://re2c.org>. As a result,
-        the translated code for this function consists of a large block of code
-        with goto jumps.
+        These regular expressions are then translated into a minimized
+        deterministic finite automaton (DFA) by the tool
+        [re2c](http://re2c.org). As a result, the translated code for this
+        function consists of a large block of code with `goto` jumps.
 
         @return the class of the next token read from the buffer
         */
@@ -6839,354 +7464,360 @@ class basic_json
                 {
                     0,   0,   0,   0,   0,   0,   0,   0,
                     0,  32,  32,   0,   0,  32,   0,   0,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    96,  64,   0,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    160, 128,   0, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
                     192, 192, 192, 192, 192, 192, 192, 192,
-                    192, 192,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,   0,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
-                    64,  64,  64,  64,  64,  64,  64,  64,
+                    192, 192, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128,   0, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
+                    128, 128, 128, 128, 128, 128, 128, 128,
                 };
                 if ((m_limit - m_cursor) < 5)
                 {
                     yyfill();    // LCOV_EXCL_LINE;
                 }
                 yych = *m_cursor;
-                if (yych <= ':')
+                if (yybm[0 + yych] & 32)
                 {
-                    if (yych <= ' ')
+                    goto basic_json_parser_6;
+                }
+                if (yych <= '\\')
+                {
+                    if (yych <= '-')
                     {
-                        if (yych <= '\n')
+                        if (yych <= '"')
                         {
                             if (yych <= 0x00)
                             {
-                                goto basic_json_parser_28;
-                            }
-                            if (yych <= 0x08)
-                            {
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_2;
                             }
-                            if (yych >= '\n')
+                            if (yych <= '!')
                             {
                                 goto basic_json_parser_4;
                             }
+                            goto basic_json_parser_9;
                         }
                         else
                         {
-                            if (yych == '\r')
+                            if (yych <= '+')
                             {
-                                goto basic_json_parser_2;
+                                goto basic_json_parser_4;
                             }
-                            if (yych <= 0x1F)
+                            if (yych <= ',')
                             {
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_10;
                             }
+                            goto basic_json_parser_12;
                         }
                     }
                     else
                     {
-                        if (yych <= ',')
+                        if (yych <= '9')
                         {
-                            if (yych == '"')
+                            if (yych <= '/')
                             {
-                                goto basic_json_parser_27;
+                                goto basic_json_parser_4;
                             }
-                            if (yych <= '+')
+                            if (yych <= '0')
                             {
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_13;
                             }
-                            goto basic_json_parser_16;
+                            goto basic_json_parser_15;
                         }
                         else
                         {
-                            if (yych <= '/')
+                            if (yych <= ':')
                             {
-                                if (yych <= '-')
-                                {
-                                    goto basic_json_parser_23;
-                                }
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_17;
                             }
-                            else
+                            if (yych == '[')
                             {
-                                if (yych <= '0')
-                                {
-                                    goto basic_json_parser_24;
-                                }
-                                if (yych <= '9')
-                                {
-                                    goto basic_json_parser_26;
-                                }
-                                goto basic_json_parser_18;
+                                goto basic_json_parser_19;
                             }
+                            goto basic_json_parser_4;
                         }
                     }
                 }
                 else
                 {
-                    if (yych <= 'n')
+                    if (yych <= 't')
                     {
-                        if (yych <= ']')
+                        if (yych <= 'f')
                         {
-                            if (yych == '[')
+                            if (yych <= ']')
                             {
-                                goto basic_json_parser_8;
+                                goto basic_json_parser_21;
                             }
-                            if (yych <= '\\')
+                            if (yych <= 'e')
                             {
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_4;
                             }
-                            goto basic_json_parser_10;
+                            goto basic_json_parser_23;
                         }
                         else
                         {
-                            if (yych == 'f')
+                            if (yych == 'n')
                             {
-                                goto basic_json_parser_22;
+                                goto basic_json_parser_24;
                             }
-                            if (yych <= 'm')
+                            if (yych <= 's')
                             {
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_4;
                             }
-                            goto basic_json_parser_20;
+                            goto basic_json_parser_25;
                         }
                     }
                     else
                     {
-                        if (yych <= '{')
+                        if (yych <= '|')
                         {
-                            if (yych == 't')
-                            {
-                                goto basic_json_parser_21;
-                            }
-                            if (yych <= 'z')
+                            if (yych == '{')
                             {
-                                goto basic_json_parser_30;
+                                goto basic_json_parser_26;
                             }
-                            goto basic_json_parser_12;
+                            goto basic_json_parser_4;
                         }
                         else
                         {
                             if (yych <= '}')
                             {
-                                if (yych <= '|')
-                                {
-                                    goto basic_json_parser_30;
-                                }
-                                goto basic_json_parser_14;
+                                goto basic_json_parser_28;
                             }
-                            else
+                            if (yych == 0xEF)
                             {
-                                if (yych == 0xEF)
-                                {
-                                    goto basic_json_parser_6;
-                                }
                                 goto basic_json_parser_30;
                             }
+                            goto basic_json_parser_4;
                         }
                     }
                 }
 basic_json_parser_2:
                 ++m_cursor;
-                yych = *m_cursor;
-                goto basic_json_parser_5;
-basic_json_parser_3:
                 {
-                    return scan();
+                    return token_type::end_of_input;
                 }
 basic_json_parser_4:
                 ++m_cursor;
-                if (m_limit <= m_cursor)
-                {
-                    yyfill();    // LCOV_EXCL_LINE;
-                }
-                yych = *m_cursor;
 basic_json_parser_5:
-                if (yybm[0 + yych] & 32)
-                {
-                    goto basic_json_parser_4;
-                }
-                goto basic_json_parser_3;
-basic_json_parser_6:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych == 0xBB)
-                {
-                    goto basic_json_parser_64;
-                }
-basic_json_parser_7:
                 {
                     return token_type::parse_error;
                 }
-basic_json_parser_8:
-                ++m_cursor;
-                {
-                    return token_type::begin_array;
-                }
-basic_json_parser_10:
-                ++m_cursor;
-                {
-                    return token_type::end_array;
-                }
-basic_json_parser_12:
-                ++m_cursor;
-                {
-                    return token_type::begin_object;
-                }
-basic_json_parser_14:
-                ++m_cursor;
-                {
-                    return token_type::end_object;
-                }
-basic_json_parser_16:
+basic_json_parser_6:
                 ++m_cursor;
+                if (m_limit <= m_cursor)
                 {
-                    return token_type::value_separator;
+                    yyfill();    // LCOV_EXCL_LINE;
                 }
-basic_json_parser_18:
-                ++m_cursor;
+                yych = *m_cursor;
+                if (yybm[0 + yych] & 32)
                 {
-                    return token_type::name_separator;
+                    goto basic_json_parser_6;
                 }
-basic_json_parser_20:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych == 'u')
                 {
-                    goto basic_json_parser_60;
+                    return scan();
                 }
-                goto basic_json_parser_7;
-basic_json_parser_21:
+basic_json_parser_9:
                 yyaccept = 0;
                 yych = *(m_marker = ++m_cursor);
-                if (yych == 'r')
+                if (yych <= 0x0F)
                 {
-                    goto basic_json_parser_56;
+                    goto basic_json_parser_5;
                 }
-                goto basic_json_parser_7;
-basic_json_parser_22:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych == 'a')
+                goto basic_json_parser_32;
+basic_json_parser_10:
+                ++m_cursor;
                 {
-                    goto basic_json_parser_51;
+                    return token_type::value_separator;
                 }
-                goto basic_json_parser_7;
-basic_json_parser_23:
+basic_json_parser_12:
                 yych = *++m_cursor;
                 if (yych <= '/')
                 {
-                    goto basic_json_parser_7;
+                    goto basic_json_parser_5;
                 }
                 if (yych <= '0')
                 {
-                    goto basic_json_parser_50;
+                    goto basic_json_parser_13;
                 }
                 if (yych <= '9')
                 {
-                    goto basic_json_parser_41;
+                    goto basic_json_parser_15;
                 }
-                goto basic_json_parser_7;
-basic_json_parser_24:
+                goto basic_json_parser_5;
+basic_json_parser_13:
                 yyaccept = 1;
                 yych = *(m_marker = ++m_cursor);
                 if (yych <= 'D')
                 {
                     if (yych == '.')
                     {
-                        goto basic_json_parser_43;
+                        goto basic_json_parser_37;
                     }
                 }
                 else
                 {
                     if (yych <= 'E')
                     {
-                        goto basic_json_parser_44;
+                        goto basic_json_parser_38;
                     }
                     if (yych == 'e')
                     {
-                        goto basic_json_parser_44;
+                        goto basic_json_parser_38;
                     }
                 }
-basic_json_parser_25:
+basic_json_parser_14:
                 {
                     return token_type::value_number;
                 }
-basic_json_parser_26:
+basic_json_parser_15:
                 yyaccept = 1;
-                yych = *(m_marker = ++m_cursor);
-                goto basic_json_parser_42;
-basic_json_parser_27:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych <= 0x0F)
-                {
-                    goto basic_json_parser_7;
-                }
-                goto basic_json_parser_32;
-basic_json_parser_28:
-                ++m_cursor;
-                {
-                    return token_type::end_of_input;
-                }
-basic_json_parser_30:
-                yych = *++m_cursor;
-                goto basic_json_parser_7;
-basic_json_parser_31:
-                ++m_cursor;
-                if (m_limit <= m_cursor)
+                m_marker = ++m_cursor;
+                if ((m_limit - m_cursor) < 3)
                 {
                     yyfill();    // LCOV_EXCL_LINE;
                 }
                 yych = *m_cursor;
-basic_json_parser_32:
                 if (yybm[0 + yych] & 64)
                 {
-                    goto basic_json_parser_31;
+                    goto basic_json_parser_15;
                 }
-                if (yych <= 0x0F)
+                if (yych <= 'D')
                 {
-                    goto basic_json_parser_33;
+                    if (yych == '.')
+                    {
+                        goto basic_json_parser_37;
+                    }
+                    goto basic_json_parser_14;
                 }
-                if (yych <= '"')
+                else
                 {
-                    goto basic_json_parser_35;
+                    if (yych <= 'E')
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    if (yych == 'e')
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_14;
                 }
-                goto basic_json_parser_34;
-basic_json_parser_33:
-                m_cursor = m_marker;
-                if (yyaccept == 0)
+basic_json_parser_17:
+                ++m_cursor;
                 {
-                    goto basic_json_parser_7;
+                    return token_type::name_separator;
+                }
+basic_json_parser_19:
+                ++m_cursor;
+                {
+                    return token_type::begin_array;
+                }
+basic_json_parser_21:
+                ++m_cursor;
+                {
+                    return token_type::end_array;
+                }
+basic_json_parser_23:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych == 'a')
+                {
+                    goto basic_json_parser_39;
+                }
+                goto basic_json_parser_5;
+basic_json_parser_24:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych == 'u')
+                {
+                    goto basic_json_parser_40;
+                }
+                goto basic_json_parser_5;
+basic_json_parser_25:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych == 'r')
+                {
+                    goto basic_json_parser_41;
+                }
+                goto basic_json_parser_5;
+basic_json_parser_26:
+                ++m_cursor;
+                {
+                    return token_type::begin_object;
+                }
+basic_json_parser_28:
+                ++m_cursor;
+                {
+                    return token_type::end_object;
+                }
+basic_json_parser_30:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych == 0xBB)
+                {
+                    goto basic_json_parser_42;
+                }
+                goto basic_json_parser_5;
+basic_json_parser_31:
+                ++m_cursor;
+                if (m_limit <= m_cursor)
+                {
+                    yyfill();    // LCOV_EXCL_LINE;
+                }
+                yych = *m_cursor;
+basic_json_parser_32:
+                if (yybm[0 + yych] & 128)
+                {
+                    goto basic_json_parser_31;
+                }
+                if (yych <= 0x0F)
+                {
+                    goto basic_json_parser_33;
+                }
+                if (yych <= '"')
+                {
+                    goto basic_json_parser_34;
+                }
+                goto basic_json_parser_36;
+basic_json_parser_33:
+                m_cursor = m_marker;
+                if (yyaccept == 0)
+                {
+                    goto basic_json_parser_5;
                 }
                 else
                 {
-                    goto basic_json_parser_25;
+                    goto basic_json_parser_14;
                 }
 basic_json_parser_34:
+                ++m_cursor;
+                {
+                    return token_type::value_string;
+                }
+basic_json_parser_36:
                 ++m_cursor;
                 if (m_limit <= m_cursor)
                 {
@@ -7259,18 +7890,78 @@ basic_json_parser_34:
                             }
                             if (yych <= 'u')
                             {
-                                goto basic_json_parser_37;
+                                goto basic_json_parser_43;
                             }
                             goto basic_json_parser_33;
                         }
                     }
                 }
-basic_json_parser_35:
-                ++m_cursor;
+basic_json_parser_37:
+                yych = *++m_cursor;
+                if (yych <= '/')
                 {
-                    return token_type::value_string;
+                    goto basic_json_parser_33;
                 }
-basic_json_parser_37:
+                if (yych <= '9')
+                {
+                    goto basic_json_parser_44;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_38:
+                yych = *++m_cursor;
+                if (yych <= ',')
+                {
+                    if (yych == '+')
+                    {
+                        goto basic_json_parser_46;
+                    }
+                    goto basic_json_parser_33;
+                }
+                else
+                {
+                    if (yych <= '-')
+                    {
+                        goto basic_json_parser_46;
+                    }
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_33;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_47;
+                    }
+                    goto basic_json_parser_33;
+                }
+basic_json_parser_39:
+                yych = *++m_cursor;
+                if (yych == 'l')
+                {
+                    goto basic_json_parser_49;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_40:
+                yych = *++m_cursor;
+                if (yych == 'l')
+                {
+                    goto basic_json_parser_50;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_41:
+                yych = *++m_cursor;
+                if (yych == 'u')
+                {
+                    goto basic_json_parser_51;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_42:
+                yych = *++m_cursor;
+                if (yych == 0xBF)
+                {
+                    goto basic_json_parser_52;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_43:
                 ++m_cursor;
                 if (m_limit <= m_cursor)
                 {
@@ -7283,27 +7974,113 @@ basic_json_parser_37:
                     {
                         goto basic_json_parser_33;
                     }
-                    if (yych >= ':')
+                    if (yych <= '9')
                     {
-                        goto basic_json_parser_33;
+                        goto basic_json_parser_54;
                     }
+                    goto basic_json_parser_33;
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto basic_json_parser_38;
+                        goto basic_json_parser_54;
                     }
                     if (yych <= '`')
                     {
                         goto basic_json_parser_33;
                     }
-                    if (yych >= 'g')
+                    if (yych <= 'f')
                     {
-                        goto basic_json_parser_33;
+                        goto basic_json_parser_54;
                     }
+                    goto basic_json_parser_33;
                 }
-basic_json_parser_38:
+basic_json_parser_44:
+                yyaccept = 1;
+                m_marker = ++m_cursor;
+                if ((m_limit - m_cursor) < 3)
+                {
+                    yyfill();    // LCOV_EXCL_LINE;
+                }
+                yych = *m_cursor;
+                if (yych <= 'D')
+                {
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_14;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_44;
+                    }
+                    goto basic_json_parser_14;
+                }
+                else
+                {
+                    if (yych <= 'E')
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    if (yych == 'e')
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_14;
+                }
+basic_json_parser_46:
+                yych = *++m_cursor;
+                if (yych <= '/')
+                {
+                    goto basic_json_parser_33;
+                }
+                if (yych >= ':')
+                {
+                    goto basic_json_parser_33;
+                }
+basic_json_parser_47:
+                ++m_cursor;
+                if (m_limit <= m_cursor)
+                {
+                    yyfill();    // LCOV_EXCL_LINE;
+                }
+                yych = *m_cursor;
+                if (yych <= '/')
+                {
+                    goto basic_json_parser_14;
+                }
+                if (yych <= '9')
+                {
+                    goto basic_json_parser_47;
+                }
+                goto basic_json_parser_14;
+basic_json_parser_49:
+                yych = *++m_cursor;
+                if (yych == 's')
+                {
+                    goto basic_json_parser_55;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_50:
+                yych = *++m_cursor;
+                if (yych == 'l')
+                {
+                    goto basic_json_parser_56;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_51:
+                yych = *++m_cursor;
+                if (yych == 'e')
+                {
+                    goto basic_json_parser_58;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_52:
+                ++m_cursor;
+                {
+                    return scan();
+                }
+basic_json_parser_54:
                 ++m_cursor;
                 if (m_limit <= m_cursor)
                 {
@@ -7316,27 +8093,46 @@ basic_json_parser_38:
                     {
                         goto basic_json_parser_33;
                     }
-                    if (yych >= ':')
+                    if (yych <= '9')
                     {
-                        goto basic_json_parser_33;
+                        goto basic_json_parser_60;
                     }
+                    goto basic_json_parser_33;
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto basic_json_parser_39;
+                        goto basic_json_parser_60;
                     }
                     if (yych <= '`')
                     {
                         goto basic_json_parser_33;
                     }
-                    if (yych >= 'g')
+                    if (yych <= 'f')
                     {
-                        goto basic_json_parser_33;
+                        goto basic_json_parser_60;
                     }
+                    goto basic_json_parser_33;
                 }
-basic_json_parser_39:
+basic_json_parser_55:
+                yych = *++m_cursor;
+                if (yych == 'e')
+                {
+                    goto basic_json_parser_61;
+                }
+                goto basic_json_parser_33;
+basic_json_parser_56:
+                ++m_cursor;
+                {
+                    return token_type::literal_null;
+                }
+basic_json_parser_58:
+                ++m_cursor;
+                {
+                    return token_type::literal_true;
+                }
+basic_json_parser_60:
                 ++m_cursor;
                 if (m_limit <= m_cursor)
                 {
@@ -7349,27 +8145,34 @@ basic_json_parser_39:
                     {
                         goto basic_json_parser_33;
                     }
-                    if (yych >= ':')
+                    if (yych <= '9')
                     {
-                        goto basic_json_parser_33;
+                        goto basic_json_parser_63;
                     }
+                    goto basic_json_parser_33;
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto basic_json_parser_40;
+                        goto basic_json_parser_63;
                     }
                     if (yych <= '`')
                     {
                         goto basic_json_parser_33;
                     }
-                    if (yych >= 'g')
+                    if (yych <= 'f')
                     {
-                        goto basic_json_parser_33;
+                        goto basic_json_parser_63;
                     }
+                    goto basic_json_parser_33;
                 }
-basic_json_parser_40:
+basic_json_parser_61:
+                ++m_cursor;
+                {
+                    return token_type::literal_false;
+                }
+basic_json_parser_63:
                 ++m_cursor;
                 if (m_limit <= m_cursor)
                 {
@@ -7404,218 +8207,8 @@ basic_json_parser_40:
                     }
                     goto basic_json_parser_33;
                 }
-basic_json_parser_41:
-                yyaccept = 1;
-                m_marker = ++m_cursor;
-                if ((m_limit - m_cursor) < 3)
-                {
-                    yyfill();    // LCOV_EXCL_LINE;
-                }
-                yych = *m_cursor;
-basic_json_parser_42:
-                if (yybm[0 + yych] & 128)
-                {
-                    goto basic_json_parser_41;
-                }
-                if (yych <= 'D')
-                {
-                    if (yych != '.')
-                    {
-                        goto basic_json_parser_25;
-                    }
-                }
-                else
-                {
-                    if (yych <= 'E')
-                    {
-                        goto basic_json_parser_44;
-                    }
-                    if (yych == 'e')
-                    {
-                        goto basic_json_parser_44;
-                    }
-                    goto basic_json_parser_25;
-                }
-basic_json_parser_43:
-                yych = *++m_cursor;
-                if (yych <= '/')
-                {
-                    goto basic_json_parser_33;
-                }
-                if (yych <= '9')
-                {
-                    goto basic_json_parser_48;
-                }
-                goto basic_json_parser_33;
-basic_json_parser_44:
-                yych = *++m_cursor;
-                if (yych <= ',')
-                {
-                    if (yych != '+')
-                    {
-                        goto basic_json_parser_33;
-                    }
-                }
-                else
-                {
-                    if (yych <= '-')
-                    {
-                        goto basic_json_parser_45;
-                    }
-                    if (yych <= '/')
-                    {
-                        goto basic_json_parser_33;
-                    }
-                    if (yych <= '9')
-                    {
-                        goto basic_json_parser_46;
-                    }
-                    goto basic_json_parser_33;
-                }
-basic_json_parser_45:
-                yych = *++m_cursor;
-                if (yych <= '/')
-                {
-                    goto basic_json_parser_33;
-                }
-                if (yych >= ':')
-                {
-                    goto basic_json_parser_33;
-                }
-basic_json_parser_46:
-                ++m_cursor;
-                if (m_limit <= m_cursor)
-                {
-                    yyfill();    // LCOV_EXCL_LINE;
-                }
-                yych = *m_cursor;
-                if (yych <= '/')
-                {
-                    goto basic_json_parser_25;
-                }
-                if (yych <= '9')
-                {
-                    goto basic_json_parser_46;
-                }
-                goto basic_json_parser_25;
-basic_json_parser_48:
-                yyaccept = 1;
-                m_marker = ++m_cursor;
-                if ((m_limit - m_cursor) < 3)
-                {
-                    yyfill();    // LCOV_EXCL_LINE;
-                }
-                yych = *m_cursor;
-                if (yych <= 'D')
-                {
-                    if (yych <= '/')
-                    {
-                        goto basic_json_parser_25;
-                    }
-                    if (yych <= '9')
-                    {
-                        goto basic_json_parser_48;
-                    }
-                    goto basic_json_parser_25;
-                }
-                else
-                {
-                    if (yych <= 'E')
-                    {
-                        goto basic_json_parser_44;
-                    }
-                    if (yych == 'e')
-                    {
-                        goto basic_json_parser_44;
-                    }
-                    goto basic_json_parser_25;
-                }
-basic_json_parser_50:
-                yyaccept = 1;
-                yych = *(m_marker = ++m_cursor);
-                if (yych <= 'D')
-                {
-                    if (yych == '.')
-                    {
-                        goto basic_json_parser_43;
-                    }
-                    goto basic_json_parser_25;
-                }
-                else
-                {
-                    if (yych <= 'E')
-                    {
-                        goto basic_json_parser_44;
-                    }
-                    if (yych == 'e')
-                    {
-                        goto basic_json_parser_44;
-                    }
-                    goto basic_json_parser_25;
-                }
-basic_json_parser_51:
-                yych = *++m_cursor;
-                if (yych != 'l')
-                {
-                    goto basic_json_parser_33;
-                }
-                yych = *++m_cursor;
-                if (yych != 's')
-                {
-                    goto basic_json_parser_33;
-                }
-                yych = *++m_cursor;
-                if (yych != 'e')
-                {
-                    goto basic_json_parser_33;
-                }
-                ++m_cursor;
-                {
-                    return token_type::literal_false;
-                }
-basic_json_parser_56:
-                yych = *++m_cursor;
-                if (yych != 'u')
-                {
-                    goto basic_json_parser_33;
-                }
-                yych = *++m_cursor;
-                if (yych != 'e')
-                {
-                    goto basic_json_parser_33;
-                }
-                ++m_cursor;
-                {
-                    return token_type::literal_true;
-                }
-basic_json_parser_60:
-                yych = *++m_cursor;
-                if (yych != 'l')
-                {
-                    goto basic_json_parser_33;
-                }
-                yych = *++m_cursor;
-                if (yych != 'l')
-                {
-                    goto basic_json_parser_33;
-                }
-                ++m_cursor;
-                {
-                    return token_type::literal_null;
-                }
-basic_json_parser_64:
-                yych = *++m_cursor;
-                if (yych != 0xBF)
-                {
-                    goto basic_json_parser_33;
-                }
-                ++m_cursor;
-                {
-                    return scan();
-                }
             }
 
-
         }
 
         /// append data from the stream to the internal buffer
@@ -7626,9 +8219,9 @@ basic_json_parser_64:
                 return;
             }
 
-            const ssize_t offset_start = m_start - m_content;
-            const ssize_t offset_marker = m_marker - m_start;
-            const ssize_t offset_cursor = m_cursor - m_start;
+            const auto offset_start = m_start - m_content;
+            const auto offset_marker = m_marker - m_start;
+            const auto offset_cursor = m_cursor - m_start;
 
             m_buffer.erase(0, static_cast<size_t>(offset_start));
             std::string line;
@@ -7645,7 +8238,7 @@ basic_json_parser_64:
         }
 
         /// return string representation of last read token
-        string_t get_token() const noexcept
+        string_t get_token() const
         {
             assert(m_start != nullptr);
             return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
@@ -7664,9 +8257,9 @@ basic_json_parser_64:
 
         1. Escaped characters. In this case, a new character is constructed
            according to the nature of the escape. Some escapes create new
-           characters (e.g., @c "\\n" is replaced by @c "\n"), some are copied
-           as is (e.g., @c "\\\\"). Furthermore, Unicode escapes of the shape
-           @c "\\uxxxx" need special care. In this case, to_unicode takes care
+           characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied as
+           is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape
+           `"\\uxxxx"` need special care. In this case, to_unicode takes care
            of the construction of the values.
         2. Unescaped characters are copied as is.
 
@@ -7780,9 +8373,9 @@ basic_json_parser_64:
         @brief parse floating point number
 
         This function (and its overloads) serves to select the most approprate
-        standard floating point number parsing function (i.e., `std::strtof`,
-        `std::strtod`, or `std::strtold`) based on the type supplied via the
-        first parameter. Set this to @a static_cast<number_float_t>(nullptr).
+        standard floating point number parsing function based on the type
+        supplied via the first parameter.  Set this to
+        @a static_cast<number_float_t*>(nullptr).
 
         @param[in] type  the @ref number_float_t in use
 
@@ -7801,14 +8394,42 @@ basic_json_parser_64:
             return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
         }
 
-        /// @copydoc str_to_float_t
-        double str_to_float_t(double*, char** endptr) const
+        /*!
+        @brief parse floating point number
+
+        This function (and its overloads) serves to select the most approprate
+        standard floating point number parsing function based on the type
+        supplied via the first parameter.  Set this to
+        @a static_cast<number_float_t*>(nullptr).
+
+        @param[in] type  the @ref number_float_t in use
+
+        @param[in,out] endptr  recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        double str_to_float_t(double* /* type */, char** endptr) const
         {
             return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
         }
 
-        /// @copydoc str_to_float_t
-        float str_to_float_t(float*, char** endptr) const
+        /*!
+        @brief parse floating point number
+
+        This function (and its overloads) serves to select the most approprate
+        standard floating point number parsing function based on the type
+        supplied via the first parameter.  Set this to
+        @a static_cast<number_float_t*>(nullptr).
+
+        @param[in] type  the @ref number_float_t in use
+
+        @param[in,out] endptr  recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        float str_to_float_t(float* /* type */, char** endptr) const
         {
             return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
         }
@@ -7816,30 +8437,138 @@ basic_json_parser_64:
         /*!
         @brief return number value for number tokens
 
-        This function translates the last token into a floating point number.
-        The pointer m_start points to the beginning of the parsed number. We
-        pass this pointer to std::strtod which sets endptr to the first
-        character past the converted number. If this pointer is not the same as
-        m_cursor, then either more or less characters have been used during the
-        comparison. This can happen for inputs like "01" which will be treated
-        like number 0 followed by number 1.
-
-        @return the result of the number conversion or NAN if the conversion
-        read past the current token. The latter case needs to be treated by the
-        caller function.
-
-        @throw std::range_error if passed value is out of range
+        This function translates the last token into the most appropriate
+        number type (either integer, unsigned integer or floating point),
+        which is passed back to the caller via the result parameter.
+
+        This function parses the integer component up to the radix point or
+        exponent while collecting information about the 'floating point
+        representation', which it stores in the result parameter. If there is
+        no radix point or exponent, and the number can fit into a
+        @ref number_integer_t or @ref number_unsigned_t then it sets the
+        result parameter accordingly.
+
+        The 'floating point representation' includes the number of significant
+        figures after the radix point, whether the number is in exponential
+        or decimal form, the capitalization of the exponent marker, and if the
+        optional '+' is present in the exponent. This information is necessary
+        to perform accurate round trips of floating point numbers.
+
+        If the number is a floating point number the number is then parsed
+        using @a std:strtod (or @a std:strtof or @a std::strtold).
+
+        @param[out] result  @ref basic_json object to receive the number, or
+          NAN if the conversion read past the current token. The latter case
+          needs to be treated by the caller function.
         */
-        number_float_t get_number() const
+        void get_number(basic_json& result) const
         {
-            // conversion
-            typename string_t::value_type* endptr;
             assert(m_start != nullptr);
-            number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
 
-            // return float_val if the whole number was translated and NAN
-            // otherwise
-            return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
+            const lexer::lexer_char_t* curptr = m_start;
+
+            // remember this number was parsed (for later serialization)
+            result.m_type.bits.parsed = true;
+
+            // 'found_radix_point' will be set to 0xFF upon finding a radix
+            // point and later used to mask in/out the precision depending
+            // whether a radix is found i.e. 'precision &= found_radix_point'
+            uint8_t found_radix_point = 0;
+            uint8_t precision = 0;
+
+            // accumulate the integer conversion result (unsigned for now)
+            number_unsigned_t value = 0;
+
+            // maximum absolute value of the relevant integer type
+            number_unsigned_t max;
+
+            // temporarily store the type to avoid unecessary bitfield access
+            value_t type;
+
+            // look for sign
+            if (*curptr == '-')
+            {
+                type = value_t::number_integer;
+                max = static_cast<uint64_t>(std::numeric_limits<number_integer_t>::max()) + 1;
+                curptr++;
+            }
+            else
+            {
+                type = value_t::number_unsigned;
+                max = static_cast<uint64_t>(std::numeric_limits<number_unsigned_t>::max());
+            }
+
+            // count the significant figures
+            for (; curptr < m_cursor; curptr++)
+            {
+                // quickly skip tests if a digit
+                if (*curptr < '0' || *curptr > '9')
+                {
+                    if (*curptr == '.')
+                    {
+                        // don't count '.' but change to float
+                        type = value_t::number_float;
+
+                        // reset precision count
+                        precision = 0;
+                        found_radix_point = 0xFF;
+                        continue;
+                    }
+                    // assume exponent (if not then will fail parse): change to
+                    // float, stop counting and record exponent details
+                    type = value_t::number_float;
+                    result.m_type.bits.has_exp = true;
+
+                    // exponent capitalization
+                    result.m_type.bits.exp_cap = (*curptr == 'E');
+
+                    // exponent '+' sign
+                    result.m_type.bits.exp_plus = (*(++curptr) == '+');
+                    break;
+                }
+
+                // skip if definitely not an integer
+                if (type != value_t::number_float)
+                {
+                    // multiply last value by ten and add the new digit
+                    auto temp = value * 10 + *curptr - 0x30;
+
+                    // test for overflow
+                    if (temp < value || temp > max)
+                    {
+                        // overflow
+                        type = value_t::number_float;
+                    }
+                    else
+                    {
+                        // no overflow - save it
+                        value = temp;
+                    }
+                }
+                ++precision;
+            }
+
+            // If no radix point was found then precision would now be set to
+            // the number of digits, which is wrong - clear it.
+            result.m_type.bits.precision = precision & found_radix_point;
+
+            // save the value (if not a float)
+            if (type == value_t::number_unsigned)
+            {
+                result.m_value.number_unsigned = value;
+            }
+            else if (type == value_t::number_integer)
+            {
+                result.m_value.number_integer = -static_cast<number_integer_t>(value);
+            }
+            else
+            {
+                // parse with strtod
+                result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
+            }
+
+            // save the type
+            result.m_type = type;
         }
 
       private:
@@ -7868,7 +8597,7 @@ basic_json_parser_64:
     {
       public:
         /// constructor for strings
-        parser(const string_t& s, parser_callback_t cb = nullptr)
+        parser(const string_t& s, parser_callback_t cb = nullptr) noexcept
             : callback(cb), m_lexer(s)
         {
             // read first token
@@ -7876,7 +8605,7 @@ basic_json_parser_64:
         }
 
         /// a parser reading from an input stream
-        parser(std::istream& _is, parser_callback_t cb = nullptr)
+        parser(std::istream& _is, parser_callback_t cb = nullptr) noexcept
             : callback(cb), m_lexer(&_is)
         {
             // read first token
@@ -8069,32 +8798,8 @@ basic_json_parser_64:
 
                 case lexer::token_type::value_number:
                 {
-                    result.m_value = m_lexer.get_number();
-
-                    // NAN is returned if token could not be translated
-                    // completely
-                    if (std::isnan(result.m_value.number_float))
-                    {
-                        throw std::invalid_argument(std::string("parse error - ") +
-                                                    m_lexer.get_token() + " is not a number");
-                    }
-
+                    m_lexer.get_number(result);
                     get_token();
-
-                    // check if conversion loses precision (special case -0.0 always loses precision)
-                    const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
-                    if (result.m_value.number_float == static_cast<number_float_t>(int_val) and
-                            result.m_value.number_integer != json_value(-0.0f).number_integer)
-                    {
-                        // we would not lose precision -> return int
-                        result.m_type = value_t::number_integer;
-                        result.m_value = int_val;
-                    }
-                    else
-                    {
-                        // we would lose precision -> return float
-                        result.m_type = value_t::number_float;
-                    }
                     break;
                 }
 
@@ -8113,7 +8818,7 @@ basic_json_parser_64:
         }
 
         /// get next token from lexer
-        typename lexer::token_type get_token()
+        typename lexer::token_type get_token() noexcept
         {
             last_token = m_lexer.scan();
             return last_token;
@@ -8152,15 +8857,1238 @@ basic_json_parser_64:
         /// the lexer
         lexer m_lexer;
     };
-};
 
+  public:
+    /*!
+    @brief JSON Pointer
 
-/////////////
-// presets //
-/////////////
+    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.
 
-/*!
-@brief default JSON class
+    @sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
+
+    @since version 2.0.0
+    */
+    class json_pointer
+    {
+        /// allow basic_json to access private members
+        friend class basic_json;
+
+      public:
+        /*!
+        @brief create JSON pointer
+
+        Create a JSON pointer according to the syntax described in
+        [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
+
+        @param[in] s  string representing the JSON pointer; if omitted, the
+                      empty string is assumed which references the whole JSON
+                      value
+
+        @throw std::domain_error if reference token is nonempty and does not
+        begin with a slash (`/`); example: `"JSON pointer must be empty or
+        begin with /"`
+        @throw std::domain_error if a tilde (`~`) is not followed by `0`
+        (representing `~`) or `1` (representing `/`); example: `"escape error:
+        ~ must be followed with 0 or 1"`
+
+        @liveexample{The example shows the construction several valid JSON
+        pointers as well as the exceptional behavior.,json_pointer}
+
+        @since version 2.0.0
+        */
+        explicit json_pointer(const std::string& s = "")
+            : reference_tokens(split(s))
+        {}
+
+        /*!
+        @brief return a string representation of the JSON pointer
+
+        @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
+        */
+        std::string to_string() const noexcept
+        {
+            std::string result;
+
+            for (const auto& reference_token : reference_tokens)
+            {
+                result += "/" + escape(reference_token);
+            }
+
+            return result;
+        }
+
+        /// @copydoc to_string()
+        operator std::string() const
+        {
+            return to_string();
+        }
+
+      private:
+        /// remove and return last reference pointer
+        std::string pop_back()
+        {
+            if (is_root())
+            {
+                throw std::domain_error("JSON pointer has no parent");
+            }
+
+            auto last = reference_tokens.back();
+            reference_tokens.pop_back();
+            return last;
+        }
+
+        /// return whether pointer points to the root document
+        bool is_root() const
+        {
+            return reference_tokens.empty();
+        }
+
+        json_pointer top() const
+        {
+            if (is_root())
+            {
+                throw std::domain_error("JSON pointer has no parent");
+            }
+
+            json_pointer result = *this;
+            result.reference_tokens = {reference_tokens[0]};
+            return result;
+        }
+
+        /*!
+        @brief create and return a reference to the pointed to value
+        */
+        reference get_and_create(reference j) const
+        {
+            pointer 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)
+            {
+                switch (result->m_type)
+                {
+                    case 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;
+                    }
+
+                    case value_t::object:
+                    {
+                        // create an entry in the object
+                        result = &result->operator[](reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        // create an entry in the array
+                        result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    /*
+                    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:
+                    {
+                        throw std::domain_error("invalid value to unflatten");
+                    }
+                }
+            }
+
+            return *result;
+        }
+
+        /*!
+        @brief return a reference to the pointed to value
+
+        @param[in] ptr  a JSON value
+
+        @return reference to the JSON value pointed to by the JSON pointer
+
+        @complexity Linear in the length of the JSON pointer.
+
+        @throw std::out_of_range      if the JSON pointer can not be resolved
+        @throw std::domain_error      if an array index begins with '0'
+        @throw std::invalid_argument  if an array index was not a number
+        */
+        reference get_unchecked(pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // use unchecked object access
+                        ptr = &ptr->operator[](reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            throw std::domain_error("array index must not begin with '0'");
+                        }
+
+                        if (reference_token == "-")
+                        {
+                            // explicityly treat "-" as index beyond the end
+                            ptr = &ptr->operator[](ptr->m_value.array->size());
+                        }
+                        else
+                        {
+                            // convert array index to number; unchecked access
+                            ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
+                        }
+                        break;
+                    }
+
+                    default:
+                    {
+                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        reference get_checked(pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // note: at performs range check
+                        ptr = &ptr->at(reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (reference_token == "-")
+                        {
+                            // "-" always fails the range check
+                            throw std::out_of_range("array index '-' (" +
+                                                    std::to_string(ptr->m_value.array->size()) +
+                                                    ") is out of range");
+                        }
+
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            throw std::domain_error("array index must not begin with '0'");
+                        }
+
+                        // note: at performs range check
+                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    default:
+                    {
+                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        /*!
+        @brief return a const reference to the pointed to value
+
+        @param[in] ptr  a JSON value
+
+        @return const reference to the JSON value pointed to by the JSON
+                pointer
+        */
+        const_reference get_unchecked(const_pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // use unchecked object access
+                        ptr = &ptr->operator[](reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (reference_token == "-")
+                        {
+                            // "-" cannot be used for const access
+                            throw std::out_of_range("array index '-' (" +
+                                                    std::to_string(ptr->m_value.array->size()) +
+                                                    ") is out of range");
+                        }
+
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            throw std::domain_error("array index must not begin with '0'");
+                        }
+
+                        // use unchecked array access
+                        ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    default:
+                    {
+                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        const_reference get_checked(const_pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // note: at performs range check
+                        ptr = &ptr->at(reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (reference_token == "-")
+                        {
+                            // "-" always fails the range check
+                            throw std::out_of_range("array index '-' (" +
+                                                    std::to_string(ptr->m_value.array->size()) +
+                                                    ") is out of range");
+                        }
+
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            throw std::domain_error("array index must not begin with '0'");
+                        }
+
+                        // note: at performs range check
+                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    default:
+                    {
+                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        /// split the string input to reference tokens
+        static std::vector<std::string> split(std::string reference_string)
+        {
+            std::vector<std::string> result;
+
+            // special case: empty reference string -> no reference tokens
+            if (reference_string.empty())
+            {
+                return result;
+            }
+
+            // check if nonempty reference string begins with slash
+            if (reference_string[0] != '/')
+            {
+                throw std::domain_error("JSON pointer must be empty or begin with '/'");
+            }
+
+            // 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
+                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 (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 (pos == reference_token.size() - 1 or
+                            (reference_token[pos + 1] != '0' and
+                             reference_token[pos + 1] != '1'))
+                    {
+                        throw std::domain_error("escape error: '~' must be followed with '0' or '1'");
+                    }
+                }
+
+                // finally, store the reference token
+                unescape(reference_token);
+                result.push_back(reference_token);
+            }
+
+            return result;
+        }
+
+      private:
+        /*!
+        @brief replace all occurrences of a substring by another string
+
+        @param[in,out] s  the string to manipulate
+        @param[in]     f  the substring to replace with @a t
+        @param[out]    t  the string to replace @a f
+
+        @return The string @a s where all occurrences of @a f are replaced
+                with @a t.
+
+        @pre The search string @a f must not be empty.
+
+        @since version 2.0.0
+        */
+        static void replace_substring(std::string& s,
+                                      const std::string& f,
+                                      const std::string& t)
+        {
+            assert(not f.empty());
+
+            for (
+                size_t 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
+                pos = s.find(f, pos + t.size()) // find next occurrence of f
+            );
+        }
+
+        /// escape tilde and slash
+        static std::string escape(std::string s)
+        {
+            // escape "~"" to "~0" and "/" to "~1"
+            replace_substring(s, "~", "~0");
+            replace_substring(s, "/", "~1");
+            return s;
+        }
+
+        /// unescape tilde and slash
+        static void unescape(std::string& s)
+        {
+            // first transform any occurrence of the sequence '~1' to '/'
+            replace_substring(s, "~1", "/");
+            // then transform any occurrence of the sequence '~0' to '~'
+            replace_substring(s, "~0", "~");
+        }
+
+        /*!
+        @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
+
+        @note Empty objects or arrays are flattened to `null`.
+        */
+        static void flatten(const std::string& reference_string,
+                            const basic_json& value,
+                            basic_json& result)
+        {
+            switch (value.m_type)
+            {
+                case 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 (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;
+                }
+
+                case 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;
+                }
+
+                default:
+                {
+                    // add primitive value with its reference string
+                    result[reference_string] = value;
+                    break;
+                }
+            }
+        }
+
+        /*!
+        @param[in] value  flattened JSON
+
+        @return unflattened JSON
+        */
+        static basic_json unflatten(const basic_json& value)
+        {
+            if (not value.is_object())
+            {
+                throw std::domain_error("only objects can be unflattened");
+            }
+
+            basic_json result;
+
+            // iterate the JSON object values
+            for (const auto& element : *value.m_value.object)
+            {
+                if (not element.second.is_primitive())
+                {
+                    throw std::domain_error("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;
+            }
+
+            return result;
+        }
+
+      private:
+        /// the reference tokens
+        std::vector<std::string> reference_tokens {};
+    };
+
+    //////////////////////////
+    // 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 std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @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 std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @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
+
+    @complexity Constant.
+
+    @throw std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @liveexample{The behavior is shown in the example.,at_json_pointer}
+
+    @since version 2.0.0
+    */
+    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
+
+    @complexity Constant.
+
+    @throw std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
+
+    @since version 2.0.0
+    */
+    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 primitve 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.
+
+    @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 funcion, a JSON Patch is applied to the current JSON value by
+    executing all operations from the patch.
+
+    @param[in] 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 std::out_of_range if a JSON pointer inside the patch could not
+    be resolved successfully in the current JSON value; example: `"key baz
+    not found"`
+    @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
+    attributes are missing); example: `"operation add must have member path"`
+
+    @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& 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)
+                {
+                    basic_json& x = 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
+                        {
+                            const auto idx = std::stoi(last_path);
+                            if (static_cast<size_type>(idx) > parent.size())
+                            {
+                                // avoid undefined behavior
+                                throw std::out_of_range("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);
+                if (it != parent.end())
+                {
+                    parent.erase(it);
+                }
+                else
+                {
+                    throw std::out_of_range("key '" + last_path + "' not found");
+                }
+            }
+            else if (parent.is_array())
+            {
+                // note erase performs range check
+                parent.erase(static_cast<size_type>(std::stoi(last_path)));
+            }
+        };
+
+        // type check
+        if (not patch.is_array())
+        {
+            // a JSON patch must be an array of objects
+            throw std::invalid_argument("JSON patch must be an array of objects");
+        }
+
+        // iterate and apply th eoperations
+        for (const auto& val : patch)
+        {
+            // wrapper to get a value for an operation
+            const auto get_value = [&val](const std::string & op,
+                                          const std::string & member,
+                                          bool string_type) -> basic_json&
+            {
+                // 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
+                if (it == val.m_value.object->end())
+                {
+                    throw std::invalid_argument(error_msg + " must have member '" + member + "'");
+                }
+
+                // check if result is of type string
+                if (string_type and not it->second.is_string())
+                {
+                    throw std::invalid_argument(error_msg + " must have string member '" + member + "'");
+                }
+
+                // no error: return value
+                return it->second;
+            };
+
+            // type check
+            if (not val.is_object())
+            {
+                throw std::invalid_argument("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()
+                    result[ptr] = result.at(from_ptr);
+                    break;
+                }
+
+                case patch_operations::test:
+                {
+                    bool success = false;
+                    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));
+                    }
+                    catch (std::out_of_range&)
+                    {
+                        // ignore out of range errors: success remains false
+                    }
+
+                    // throw an exception if test fails
+                    if (not success)
+                    {
+                        throw std::domain_error("unsuccessful: " + val.dump());
+                    }
+
+                    break;
+                }
+
+                case patch_operations::invalid:
+                {
+                    // op must be "add", "remove", "replace", "move", "copy", or
+                    // "test"
+                    throw std::invalid_argument("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 copare from
+    @param[in] target  JSON value to copare 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
+
+    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
+
+    @since version 2.0.0
+    */
+    static basic_json diff(const basic_json& source,
+                           const basic_json& target,
+                           std::string path = "") noexcept
+    {
+        // 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(
+            {
+                {"op", "replace"},
+                {"path", path},
+                {"value", target}
+            });
+        }
+        else
+        {
+            switch (source.type())
+            {
+                case value_t::array:
+                {
+                    // first pass: traverse common elements
+                    size_t i = 0;
+                    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
+                    while (i < source.size())
+                    {
+                        result.push_back(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
+                    for (auto it = source.begin(); it != source.end(); ++it)
+                    {
+                        // 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(
+                            {
+                                {"op", "remove"},
+                                {"path", path + "/" + key}
+                            }));
+                        }
+                    }
+
+                    // second pass: traverse other object's elements
+                    for (auto it = target.begin(); it != target.end(); ++it)
+                    {
+                        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(
+                            {
+                                {"op", "add"},
+                                {"path", path + "/" + key},
+                                {"value", it.value()}
+                            });
+                        }
+                    }
+
+                    break;
+                }
+
+                default:
+                {
+                    // both primitive type: replace value
+                    result.push_back(
+                    {
+                        {"op", "replace"},
+                        {"path", path},
+                        {"value", target}
+                    });
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /// @}
+};
+
+
+/////////////
+// presets //
+/////////////
+
+/*!
+@brief default JSON class
 
 This type is the default specialization of the @ref basic_json class which uses
 the standard template types.
@@ -8171,9 +10099,9 @@ using json = basic_json<>;
 }
 
 
-/////////////////////////
-// nonmember functions //
-/////////////////////////
+///////////////////////
+// nonmember support //
+///////////////////////
 
 // specialization of std::swap, and std::hash
 namespace std
@@ -8214,9 +10142,9 @@ struct hash<nlohmann::json>
 /*!
 @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 \p "_json" to a string literal and returns a JSON object if
-no parse error occurred.
+This operator implements a user-defined string literal for JSON objects. It
+can be used by adding \p "_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
 @return a JSON object
@@ -8228,6 +10156,16 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
     return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
 }
 
+/*!
+@brief user-defined string literal for JSON pointer
+
+@since version 2.0.0
+*/
+inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t)
+{
+    return nlohmann::json::json_pointer(s);
+}
+
 // restore GCC/clang diagnostic settings
 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
     #pragma GCC diagnostic pop
diff --git a/src/mcts/allocator.hpp b/src/mcts/allocator.hpp
index f765282..73e64d8 100644
--- a/src/mcts/allocator.hpp
+++ b/src/mcts/allocator.hpp
@@ -15,7 +15,7 @@ namespace mcts
     void copy(node* n1, node* n2, unsigned int prunning = 0);
 
   public:
-    allocator(unsigned int size = 10000000U);
+    allocator(unsigned int size = 40000000U);
     ~allocator();
     node* allocate(unsigned int size);
     void clear();
-- 
GitLab