From 3e15b551e01679bca7e27d08d39aaca6774465cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo@tanker.io>
Date: Tue, 17 Jan 2017 10:32:35 +0100
Subject: [PATCH] run make pretty

---
 src/json.hpp                  | 6492 ++++++++++++++++++---------------
 src/json.hpp.re2c             | 5270 +++++++++++++-------------
 test/src/unit-conversions.cpp |    8 +-
 test/src/unit-noexcept.cpp    |    4 +-
 test/src/unit-regression.cpp  |    2 +-
 test/src/unit-udt.cpp         |  214 +-
 6 files changed, 6274 insertions(+), 5716 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 9c0a8168..fc7b60f2 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -136,15 +136,15 @@ the default value for a given type
 */
 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 (signed integer)
-  number_unsigned, ///< number value (unsigned 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 (signed integer)
+    number_unsigned, ///< number value (unsigned integer)
+    number_float,    ///< number value (floating-point)
+    discarded        ///< discarded by the the parser callback function
 };
 
 // alias templates to reduce boilerplate
@@ -168,29 +168,29 @@ using is_unscoped_enum =
 
 namespace detail
 {
-template <typename Json> std::string type_name(const  Json &j)
+template <typename Json> std::string type_name(const  Json& j)
 {
-  switch (j.m_type)
-  {
-  case value_t::null:
-    return "null";
-  case value_t::object:
-    return "object";
-  case value_t::array:
-    return "array";
-  case value_t::string:
-    return "string";
-  case value_t::boolean:
-    return "boolean";
-  case value_t::discarded:
-    return "discarded";
-  default:
-    return "number";
-  }
+    switch (j.m_type)
+    {
+        case value_t::null:
+            return "null";
+        case value_t::object:
+            return "object";
+        case value_t::array:
+            return "array";
+        case value_t::string:
+            return "string";
+        case value_t::boolean:
+            return "boolean";
+        case value_t::discarded:
+            return "discarded";
+        default:
+            return "number";
+    }
 }
 
 // dispatch utility (taken from ranges-v3)
-template <unsigned N> struct priority_tag : priority_tag<N - 1> {};
+template <unsigned N> struct priority_tag : priority_tag < N - 1 > {};
 
 template <> struct priority_tag<0> {};
 
@@ -201,120 +201,120 @@ template <value_t> struct external_constructor;
 template <>
 struct external_constructor<value_t::boolean>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::boolean_t b) noexcept
-  {
-    j.m_type = value_t::boolean;
-    j.m_value = b;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, typename Json::boolean_t b) noexcept
+    {
+        j.m_type = value_t::boolean;
+        j.m_value = b;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::string>
 {
-  template <typename Json>
-  static void construct(Json &j, const typename Json::string_t& s)
-  {
-    j.m_type = value_t::string;
-    j.m_value = s;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, const typename Json::string_t& s)
+    {
+        j.m_type = value_t::string;
+        j.m_value = s;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::number_float>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::number_float_t val) noexcept
-  {
-    // replace infinity and NAN by null
-    if (not std::isfinite(val))
-      j = Json{};
-    else
+    template <typename Json>
+    static void construct(Json& j, typename Json::number_float_t val) noexcept
     {
-      j.m_type = value_t::number_float;
-      j.m_value = val;
+        // replace infinity and NAN by null
+        if (not std::isfinite(val))
+            j = Json{};
+        else
+        {
+            j.m_type = value_t::number_float;
+            j.m_value = val;
+        }
+        j.assert_invariant();
     }
-    j.assert_invariant();
-  }
 };
 
 template <>
 struct external_constructor<value_t::number_unsigned>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::number_unsigned_t val) noexcept
-  {
-    j.m_type = value_t::number_unsigned;
-    j.m_value = val;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, typename Json::number_unsigned_t val) noexcept
+    {
+        j.m_type = value_t::number_unsigned;
+        j.m_value = val;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::number_integer>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::number_integer_t val) noexcept
-  {
-    j.m_type = value_t::number_integer;
-    j.m_value = val;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, typename Json::number_integer_t val) noexcept
+    {
+        j.m_type = value_t::number_integer;
+        j.m_value = val;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::array>
 {
-  template <typename Json>
-  static void construct(Json &j, const typename Json::array_t& arr)
-  {
-    j.m_type = value_t::array;
-    j.m_value = arr;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, const typename Json::array_t& arr)
+    {
+        j.m_type = value_t::array;
+        j.m_value = arr;
+        j.assert_invariant();
+    }
 
-  template <typename Json, typename CompatibleArrayType,
-            enable_if_t<not std::is_same<CompatibleArrayType,
-                                         typename Json::array_t>::value,
-                        int> = 0>
-  static void construct(Json &j, const CompatibleArrayType &arr)
-  {
-    using std::begin;
-    using std::end;
-    j.m_type = value_t::array;
-    j.m_value.array =
-        j.template create<typename Json::array_t>(begin(arr), end(arr));
-    j.assert_invariant();
-  }
+    template <typename Json, typename CompatibleArrayType,
+              enable_if_t<not std::is_same<CompatibleArrayType,
+                                           typename Json::array_t>::value,
+                          int> = 0>
+    static void construct(Json& j, const CompatibleArrayType& arr)
+    {
+        using std::begin;
+        using std::end;
+        j.m_type = value_t::array;
+        j.m_value.array =
+            j.template create<typename Json::array_t>(begin(arr), end(arr));
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::object>
 {
-  template <typename Json>
-  static void construct(Json &j, const typename Json::object_t& obj)
-  {
-    j.m_type = value_t::object;
-    j.m_value = obj;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, const typename Json::object_t& obj)
+    {
+        j.m_type = value_t::object;
+        j.m_value = obj;
+        j.assert_invariant();
+    }
 
-  template <typename Json, typename CompatibleObjectType,
-            enable_if_t<not std::is_same<CompatibleObjectType,
-                                         typename Json::object_t>::value,
-                        int> = 0>
-  static void construct(Json &j, const CompatibleObjectType &obj)
-  {
-    using std::begin;
-    using std::end;
+    template <typename Json, typename CompatibleObjectType,
+              enable_if_t<not std::is_same<CompatibleObjectType,
+                                           typename Json::object_t>::value,
+                          int> = 0>
+    static void construct(Json& j, const CompatibleObjectType& obj)
+    {
+        using std::begin;
+        using std::end;
 
-    j.m_type = value_t::object;
-    j.m_value.object =
-        j.template create<typename Json::object_t>(begin(obj), end(obj));
-    j.assert_invariant();
-  }
+        j.m_type = value_t::object;
+        j.m_value.object =
+            j.template create<typename Json::object_t>(begin(obj), end(obj));
+        j.assert_invariant();
+    }
 };
 
 // Implementation of 2 C++17 constructs: conjunction, negation.
@@ -380,11 +380,11 @@ struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
 template<class BasicJson, class CompatibleObjectType>
 struct is_compatible_object_type
 {
-    static auto constexpr value = is_compatible_object_type_impl<
-        conjunction<negation<std::is_same<void, CompatibleObjectType>>,
-                    has_mapped_type<CompatibleObjectType>,
-                    has_key_type<CompatibleObjectType>>::value,
-        typename BasicJson::object_t, CompatibleObjectType>::value;
+    static auto constexpr value = is_compatible_object_type_impl <
+                                  conjunction<negation<std::is_same<void, CompatibleObjectType>>,
+                                  has_mapped_type<CompatibleObjectType>,
+                                  has_key_type<CompatibleObjectType>>::value,
+                                  typename BasicJson::object_t, CompatibleObjectType >::value;
 };
 
 template <typename BasicJson, typename T>
@@ -400,17 +400,17 @@ struct is_basic_json_nested_type
 template <class BasicJson, class CompatibleArrayType>
 struct is_compatible_array_type
 {
-  // TODO concept Container?
-  // this might not make VS happy
-    static auto constexpr value = 
+    // TODO concept Container?
+    // this might not make VS happy
+    static auto constexpr value =
         conjunction<negation<std::is_same<void, CompatibleArrayType>>,
-                    negation<is_compatible_object_type<
-                        BasicJson, CompatibleArrayType>>,
-                    negation<std::is_constructible<typename BasicJson::string_t,
-                                                   CompatibleArrayType>>,
-                    negation<is_basic_json_nested_type<BasicJson, CompatibleArrayType>>,
-                    has_value_type<CompatibleArrayType>,
-                    has_iterator<CompatibleArrayType>>::value;
+        negation<is_compatible_object_type<
+        BasicJson, CompatibleArrayType>>,
+        negation<std::is_constructible<typename BasicJson::string_t,
+        CompatibleArrayType>>,
+        negation<is_basic_json_nested_type<BasicJson, CompatibleArrayType>>,
+        has_value_type<CompatibleArrayType>,
+        has_iterator<CompatibleArrayType>>::value;
 };
 
 template <bool, typename, typename>
@@ -419,7 +419,7 @@ struct is_compatible_integer_type_impl : std::false_type {};
 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
 struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
 {
-  // is there an assert somewhere on overflows?
+    // is there an assert somewhere on overflows?
     using RealLimits = std::numeric_limits<RealIntegerType>;
     using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
 
@@ -433,11 +433,11 @@ struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIn
 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
 struct is_compatible_integer_type
 {
-  static constexpr auto
-      value = is_compatible_integer_type_impl <
-                  std::is_integral<CompatibleNumberIntegerType>::value and
-              not std::is_same<bool, CompatibleNumberIntegerType>::value,
-      RealIntegerType, CompatibleNumberIntegerType > ::value;
+    static constexpr auto
+    value = is_compatible_integer_type_impl <
+            std::is_integral<CompatibleNumberIntegerType>::value and
+            not std::is_same<bool, CompatibleNumberIntegerType>::value,
+            RealIntegerType, CompatibleNumberIntegerType > ::value;
 };
 
 // This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists
@@ -461,261 +461,287 @@ struct has_from_json
 template <typename Json, typename T>
 struct has_non_default_from_json
 {
-private:
-  template <
-      typename U,
-      typename = enable_if_t<std::is_same<
-          T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value>>
-  static int detect(U &&);
-  static void detect(...);
+  private:
+    template <
+        typename U,
+        typename = enable_if_t<std::is_same<
+                                   T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value >>
+    static int detect(U&&);
+    static void detect(...);
 
-public:
-  static constexpr bool value = std::is_integral<decltype(detect(
-      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
+  public:
+    static constexpr bool value = std::is_integral<decltype(detect(
+                                      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
 };
 
 // This trait checks if Json::json_serializer<T>::to_json exists
 template <typename Json, typename T>
 struct has_to_json
 {
-private:
-  template <typename U, typename = decltype(uncvref_t<U>::to_json(
-                            std::declval<Json &>(), std::declval<T>()))>
-  static int detect(U &&);
-  static void detect(...);
+  private:
+    template <typename U, typename = decltype(uncvref_t<U>::to_json(
+                  std::declval<Json&>(), std::declval<T>()))>
+    static int detect(U&&);
+    static void detect(...);
 
-public:
-  static constexpr bool value = std::is_integral<decltype(detect(
-      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
+  public:
+    static constexpr bool value = std::is_integral<decltype(detect(
+                                      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
 };
 
 // overloads for basic_json template parameters
 
 template <typename Json, typename ArithmeticType,
           enable_if_t<std::is_arithmetic<ArithmeticType>::value and
-                          not std::is_same<ArithmeticType,
-                                           typename Json::boolean_t>::value,
+                      not std::is_same<ArithmeticType,
+                                       typename Json::boolean_t>::value,
                       int> = 0>
-void get_arithmetic_value(const  Json &j, ArithmeticType &val)
+void get_arithmetic_value(const  Json& j, ArithmeticType& val)
 {
-  // unsigned must be checked first, since is_number_integer() == true for unsigned
-  if (j.is_number_unsigned())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
-  else if (j.is_number_integer())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
-  else if (j.is_number_float())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
-  else
-    throw std::domain_error("type must be number, but is " + type_name(j));
+    // unsigned must be checked first, since is_number_integer() == true for unsigned
+    if (j.is_number_unsigned())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
+    }
+    else if (j.is_number_integer())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
+    }
+    else if (j.is_number_float())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
+    }
+    else
+    {
+        throw std::domain_error("type must be number, but is " + type_name(j));
+    }
 }
 
 template <typename Json>
-void to_json(Json &j, typename Json::boolean_t b) noexcept
+void to_json(Json& j, typename Json::boolean_t b) noexcept
 {
-  external_constructor<value_t::boolean>::construct(j, b);
+    external_constructor<value_t::boolean>::construct(j, b);
 }
 
 template <typename Json, typename CompatibleString,
           enable_if_t<std::is_constructible<typename Json::string_t,
-                                            CompatibleString>::value,
+                      CompatibleString>::value,
                       int> = 0>
-void to_json(Json &j, const CompatibleString &s)
+void to_json(Json& j, const CompatibleString& s)
 {
-  external_constructor<value_t::string>::construct(j, s);
+    external_constructor<value_t::string>::construct(j, s);
 }
 
 template <typename Json, typename FloatType,
           enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
-void to_json(Json &j, FloatType val) noexcept
+void to_json(Json& j, FloatType val) noexcept
 {
-  external_constructor<value_t::number_float>::construct(j, static_cast<typename Json::number_float_t>(val));
+    external_constructor<value_t::number_float>::construct(j, static_cast<typename Json::number_float_t>(val));
 }
 
 
 template <
     typename Json, typename CompatibleNumberUnsignedType,
-   enable_if_t<is_compatible_integer_type<typename Json::number_unsigned_t,
-                                         CompatibleNumberUnsignedType>::value,
-                int> = 0>
-void to_json(Json &j, CompatibleNumberUnsignedType val) noexcept
+    enable_if_t<is_compatible_integer_type<typename Json::number_unsigned_t,
+                CompatibleNumberUnsignedType>::value,
+                int> = 0 >
+void to_json(Json& j, CompatibleNumberUnsignedType val) noexcept
 {
-  external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename Json::number_unsigned_t>(val));
+    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename Json::number_unsigned_t>(val));
 }
 
 template <
     typename Json, typename CompatibleNumberIntegerType,
-   enable_if_t<is_compatible_integer_type<typename Json::number_integer_t,
-                                         CompatibleNumberIntegerType>::value,
-                int> = 0>
-void to_json(Json &j, CompatibleNumberIntegerType val) noexcept
+    enable_if_t<is_compatible_integer_type<typename Json::number_integer_t,
+                CompatibleNumberIntegerType>::value,
+                int> = 0 >
+void to_json(Json& j, CompatibleNumberIntegerType val) noexcept
 {
-  external_constructor<value_t::number_integer>::construct(j, static_cast<typename Json::number_integer_t>(val));
+    external_constructor<value_t::number_integer>::construct(j, static_cast<typename Json::number_integer_t>(val));
 }
 
 template <typename Json, typename UnscopedEnumType,
           enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
-void to_json(Json &j, UnscopedEnumType e) noexcept
+void to_json(Json& j, UnscopedEnumType e) noexcept
 {
-  external_constructor<value_t::number_integer>::construct(j, e);
+    external_constructor<value_t::number_integer>::construct(j, e);
 }
 
 template <
     typename Json, typename CompatibleArrayType,
-    enable_if_t<
+    enable_if_t <
         is_compatible_array_type<Json, CompatibleArrayType>::value or
-            std::is_same<typename Json::array_t, CompatibleArrayType>::value,
-        int> = 0>
-void to_json(Json &j, const  CompatibleArrayType &arr)
+        std::is_same<typename Json::array_t, CompatibleArrayType>::value,
+        int > = 0 >
+void to_json(Json& j, const  CompatibleArrayType& arr)
 {
-  external_constructor<value_t::array>::construct(j, arr);
+    external_constructor<value_t::array>::construct(j, arr);
 }
 
 template <
     typename Json, typename CompatibleObjectType,
     enable_if_t<is_compatible_object_type<Json, CompatibleObjectType>::value,
-                int> = 0>
-void to_json(Json &j, const  CompatibleObjectType &arr)
+                int> = 0 >
+void to_json(Json& j, const  CompatibleObjectType& arr)
 {
-  external_constructor<value_t::object>::construct(j, arr);
+    external_constructor<value_t::object>::construct(j, arr);
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::boolean_t& b)
+void from_json(const Json& j, typename Json::boolean_t& b)
 {
-  if (!j.is_boolean())
-    throw std::domain_error("type must be boolean, but is " + type_name(j));
-  b = *j.template get_ptr<const typename Json::boolean_t*>();
+    if (!j.is_boolean())
+    {
+        throw std::domain_error("type must be boolean, but is " + type_name(j));
+    }
+    b = *j.template get_ptr<const typename Json::boolean_t*>();
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::string_t& s)
+void from_json(const Json& j, typename Json::string_t& s)
 {
-  if (!j.is_string())
-    throw std::domain_error("type must be string, but is " + type_name(j));
-  s = *j.template get_ptr<const typename Json::string_t*>();
+    if (!j.is_string())
+    {
+        throw std::domain_error("type must be string, but is " + type_name(j));
+    }
+    s = *j.template get_ptr<const typename Json::string_t*>();
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::number_float_t& val)
+void from_json(const Json& j, typename Json::number_float_t& val)
 {
-  get_arithmetic_value(j, val);
+    get_arithmetic_value(j, val);
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::number_unsigned_t& val)
+void from_json(const Json& j, typename Json::number_unsigned_t& val)
 {
-  get_arithmetic_value(j, val);
+    get_arithmetic_value(j, val);
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::number_integer_t& val)
+void from_json(const Json& j, typename Json::number_integer_t& val)
 {
-  get_arithmetic_value(j, val);
+    get_arithmetic_value(j, val);
 }
 
 template <typename Json, typename UnscopedEnumType,
           enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
-void from_json(const  Json &j, UnscopedEnumType& e)
+void from_json(const  Json& j, UnscopedEnumType& e)
 {
-  typename std::underlying_type<UnscopedEnumType>::type val = e;
-  get_arithmetic_value(j, val);
-  e = static_cast<UnscopedEnumType>(val);
+    typename std::underlying_type<UnscopedEnumType>::type val = e;
+    get_arithmetic_value(j, val);
+    e = static_cast<UnscopedEnumType>(val);
 }
 
 template <typename Json>
-void from_json(const  Json &j, typename Json::array_t &arr)
+void from_json(const  Json& j, typename Json::array_t& arr)
 {
-  if (!j.is_array())
-    throw std::domain_error("type must be array, but is " + type_name(j));
-  arr = *j.template get_ptr<const typename Json::array_t*>();
+    if (!j.is_array())
+    {
+        throw std::domain_error("type must be array, but is " + type_name(j));
+    }
+    arr = *j.template get_ptr<const typename Json::array_t*>();
 }
 
 // forward_list doesn't have an insert method, TODO find a way to avoid including forward_list
 template <typename Json, typename T, typename Allocator>
-void from_json(const Json &j, std::forward_list<T, Allocator>& l)
+void from_json(const Json& j, std::forward_list<T, Allocator>& l)
 {
-  // do not perform the check when user wants to retrieve jsons
-  // (except when it's null.. ?)
-  if (j.is_null())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  if (not std::is_same<T, Json>::value)
-  {
-    if (!j.is_array())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  }
-  for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
-    l.push_front(it->template get<T>());
+    // do not perform the check when user wants to retrieve jsons
+    // (except when it's null.. ?)
+    if (j.is_null())
+    {
+        throw std::domain_error("type must be array, but is " + type_name(j));
+    }
+    if (not std::is_same<T, Json>::value)
+    {
+        if (!j.is_array())
+        {
+            throw std::domain_error("type must be array, but is " + type_name(j));
+        }
+    }
+    for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
+    {
+        l.push_front(it->template get<T>());
+    }
 }
 
 template <typename Json, typename CompatibleArrayType>
-void from_json_array_impl(const  Json &j, CompatibleArrayType &arr, priority_tag<0>)
+void from_json_array_impl(const  Json& j, CompatibleArrayType& arr, priority_tag<0>)
 {
-  using std::begin;
-  using std::end;
+    using std::begin;
+    using std::end;
 
-  std::transform(
-      j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json &i)
-      {
+    std::transform(
+        j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json & i)
+    {
         // get<Json>() returns *this, this won't call a from_json method when
         // value_type is Json
         return i.template get<typename CompatibleArrayType::value_type>();
-      });
+    });
 }
 
 template <typename Json, typename CompatibleArrayType>
-auto from_json_array_impl(const  Json &j, CompatibleArrayType &arr, priority_tag<1>)
-    -> decltype(
-        arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
-        void())
+auto from_json_array_impl(const  Json& j, CompatibleArrayType& arr, priority_tag<1>)
+-> decltype(
+    arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
+    void())
 {
-  using std::begin;
-  using std::end;
+    using std::begin;
+    using std::end;
 
-  arr.reserve(j.size());
-  std::transform(
-      j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json &i)
-      {
+    arr.reserve(j.size());
+    std::transform(
+        j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json & i)
+    {
         // get<Json>() returns *this, this won't call a from_json method when
         // value_type is Json
         return i.template get<typename CompatibleArrayType::value_type>();
-      });
+    });
 }
 
 template <
     typename Json, typename CompatibleArrayType,
     enable_if_t<is_compatible_array_type<Json, CompatibleArrayType>::value and
-                    not std::is_same<typename Json::array_t,
-                                     CompatibleArrayType>::value,
-                int> = 0>
-void from_json(const  Json &j, CompatibleArrayType &arr)
+                not std::is_same<typename Json::array_t,
+                                 CompatibleArrayType>::value,
+                int> = 0 >
+void from_json(const  Json& j, CompatibleArrayType& arr)
 {
-  if (j.is_null())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  // when T == Json, do not check if value_t is correct
-  if (not std::is_same<typename CompatibleArrayType::value_type, Json>::value)
-  {
-    if (!j.is_array())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  }
-  from_json_array_impl(j, arr, priority_tag<1>{});
+    if (j.is_null())
+    {
+        throw std::domain_error("type must be array, but is " + type_name(j));
+    }
+    // when T == Json, do not check if value_t is correct
+    if (not std::is_same<typename CompatibleArrayType::value_type, Json>::value)
+    {
+        if (!j.is_array())
+        {
+            throw std::domain_error("type must be array, but is " + type_name(j));
+        }
+    }
+    from_json_array_impl(j, arr, priority_tag<1> {});
 }
 
 
 template <
     typename Json, typename CompatibleObjectType,
     enable_if_t<is_compatible_object_type<Json, CompatibleObjectType>::value,
-                int> = 0>
-void from_json(const  Json &j, CompatibleObjectType &obj)
+                int> = 0 >
+void from_json(const  Json& j, CompatibleObjectType& obj)
 {
-  if (!j.is_object())
-    throw std::domain_error("type must be object, but is " + type_name(j));
+    if (!j.is_object())
+    {
+        throw std::domain_error("type must be object, but is " + type_name(j));
+    }
 
-  auto inner_object = j.template get_ptr<const typename Json::object_t*>();
-  using std::begin;
-  using std::end;
-  // we could avoid the assignment, but this might require a for loop, which
-  // might be less efficient than the container constructor for some containers (would it?)
-  obj = CompatibleObjectType(begin(*inner_object), end(*inner_object));
+    auto inner_object = j.template get_ptr<const typename Json::object_t*>();
+    using std::begin;
+    using std::end;
+    // we could avoid the assignment, but this might require a for loop, which
+    // might be less efficient than the container constructor for some containers (would it?)
+    obj = CompatibleObjectType(begin(*inner_object), end(*inner_object));
 }
 
 // overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..)
@@ -724,25 +750,35 @@ void from_json(const  Json &j, CompatibleObjectType &obj)
 // in case of a custom BooleanType which is not an arithmetic type?
 template <
     typename Json, typename ArithmeticType,
-    enable_if_t<
+    enable_if_t <
         std::is_arithmetic<ArithmeticType>::value and
-            not std::is_same<ArithmeticType, typename Json::number_unsigned_t>::value and
-            not std::is_same<ArithmeticType, typename Json::number_integer_t>::value and
-            not std::is_same<ArithmeticType, typename Json::number_float_t>::value and
-            not std::is_same<ArithmeticType, typename Json::boolean_t>::value,
-        int> = 0>
-void from_json(const  Json &j, ArithmeticType &val)
+        not std::is_same<ArithmeticType, typename Json::number_unsigned_t>::value and
+        not std::is_same<ArithmeticType, typename Json::number_integer_t>::value and
+        not std::is_same<ArithmeticType, typename Json::number_float_t>::value and
+        not std::is_same<ArithmeticType, typename Json::boolean_t>::value,
+        int > = 0 >
+void from_json(const  Json& j, ArithmeticType& val)
 {
-  if (j.is_number_unsigned())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
-  else if (j.is_number_integer())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
-  else if (j.is_number_float())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
-  else if (j.is_boolean())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::boolean_t*>());
-  else
-    throw std::domain_error("type must be number, but is " + type_name(j));
+    if (j.is_number_unsigned())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
+    }
+    else if (j.is_number_integer())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
+    }
+    else if (j.is_number_float())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
+    }
+    else if (j.is_boolean())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::boolean_t*>());
+    }
+    else
+    {
+        throw std::domain_error("type must be number, but is " + type_name(j));
+    }
 }
 
 struct to_json_fn
@@ -762,39 +798,39 @@ struct to_json_fn
         static_assert(sizeof(Json) == 0, "to_json method in T's namespace can not be called");
     }
 
-public:
-  template <typename Json, typename T>
-  void operator()(Json &j, T &&val) const
-      noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1>{})))
-  {
-      return call(j, std::forward<T>(val), priority_tag<1>{});
-  }
+  public:
+    template <typename Json, typename T>
+    void operator()(Json& j, T&& val) const
+    noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
+    {
+        return call(j, std::forward<T>(val), priority_tag<1> {});
+    }
 };
 
 struct from_json_fn
 {
-private:
-  template <typename Json, typename T>
-  auto call(const  Json &j, T &val, priority_tag<1>) const
-      noexcept(noexcept(from_json(j, val)))
-          -> decltype(from_json(j, val), void())
-  {
-    return from_json(j, val);
-  }
+  private:
+    template <typename Json, typename T>
+    auto call(const  Json& j, T& val, priority_tag<1>) const
+    noexcept(noexcept(from_json(j, val)))
+    -> decltype(from_json(j, val), void())
+    {
+        return from_json(j, val);
+    }
 
-  template <typename Json, typename T>
-  void call(const Json &, T&, priority_tag<0>) const noexcept
-  {
-      static_assert(sizeof(Json) == 0, "from_json method in T's namespace can not be called");
-  }
+    template <typename Json, typename T>
+    void call(const Json&, T&, priority_tag<0>) const noexcept
+    {
+        static_assert(sizeof(Json) == 0, "from_json method in T's namespace can not be called");
+    }
 
-public:
-  template <typename Json, typename T>
-  void operator()(const  Json &j, T &val) const
-      noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1>{})))
-  {
-      return call(j, val, priority_tag<1>{});
-  }
+  public:
+    template <typename Json, typename T>
+    void operator()(const  Json& j, T& val) const
+    noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
+    {
+        return call(j, val, priority_tag<1> {});
+    }
 };
 
 // taken from ranges-v3
@@ -830,8 +866,8 @@ struct DecimalSeparator : std::numpunct<char>
 
 inline namespace
 {
-constexpr const auto & to_json = detail::static_const<detail::to_json_fn>::value;
-constexpr const auto & from_json = detail::static_const<detail::from_json_fn>::value;
+constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
+constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
 }
 
 // default JSONSerializer template argument, doesn't care about template argument
@@ -846,10 +882,10 @@ struct adl_serializer
     }
 
     template <typename Json, typename T>
-    static void to_json(Json &j, T &&val) noexcept(
+    static void to_json(Json& j, T&& val) noexcept(
         noexcept(::nlohmann::to_json(j, std::forward<T>(val))))
     {
-      ::nlohmann::to_json(j, std::forward<T>(val));
+        ::nlohmann::to_json(j, std::forward<T>(val));
     }
 };
 
@@ -947,7 +983,7 @@ class basic_json
 {
   private:
     template <::nlohmann::value_t> friend struct detail::external_constructor;
-    template <typename Json> friend std::string detail::type_name(const  Json &);
+    template <typename Json> friend std::string detail::type_name(const  Json&);
     /// workaround type for MSVC
     using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
           BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
@@ -1849,15 +1885,15 @@ class basic_json
     */
     template <typename T, typename U = uncvref_t<T>,
               enable_if_t<not std::is_base_of<std::istream, U>::value and
-                              not std::is_same<U, basic_json_t>::value and
-                              not detail::is_basic_json_nested_type<
-                                  basic_json_t, U>::value and
-                              detail::has_to_json<basic_json, U>::value,
+                          not std::is_same<U, basic_json_t>::value and
+                          not detail::is_basic_json_nested_type<
+                              basic_json_t, U>::value and
+                          detail::has_to_json<basic_json, U>::value,
                           int> = 0>
-    basic_json(T &&val) noexcept(noexcept(JSONSerializer<U>::to_json(
-        std::declval<basic_json_t &>(), std::forward<T>(val))))
+    basic_json(T && val) noexcept(noexcept(JSONSerializer<U>::to_json(
+            std::declval<basic_json_t&>(), std::forward<T>(val))))
     {
-      JSONSerializer<U>::to_json(*this, std::forward<T>(val));
+        JSONSerializer<U>::to_json(*this, std::forward<T>(val));
     }
 
     /*!
@@ -2013,7 +2049,7 @@ class basic_json
     @since version 1.0.0
     */
     static basic_json array(std::initializer_list<basic_json> init =
-                            std::initializer_list<basic_json>())
+                                std::initializer_list<basic_json>())
     {
         return basic_json(init, false, value_t::array);
     }
@@ -2053,7 +2089,7 @@ class basic_json
     @since version 1.0.0
     */
     static basic_json object(std::initializer_list<basic_json> init =
-                             std::initializer_list<basic_json>())
+                                 std::initializer_list<basic_json>())
     {
         return basic_json(init, false, value_t::object);
     }
@@ -2394,7 +2430,7 @@ class basic_json
         std::is_nothrow_move_assignable<value_t>::value and
         std::is_nothrow_move_constructible<json_value>::value and
         std::is_nothrow_move_assignable<json_value>::value
-                                       )
+    )
     {
         // check that passed value is valid
         other.assert_invariant();
@@ -3020,7 +3056,7 @@ class basic_json
               enable_if_t<std::is_same<T, basic_json_t>::value, int> = 0>
     basic_json get() const
     {
-      return *this;
+        return *this;
     }
 
     /*!
@@ -3032,7 +3068,7 @@ class basic_json
     - @ref json_serializer<U> has a from_json method of the form: void from_json(const @ref basic_json&, U&)
     - @ref json_serializer<U> does not have a from_json method of the form: U from_json(const @ref basic_json&);
 
-    @return a value of type U 
+    @return a value of type U
 
     @throw what json_serializer<U> from_json method throws
 
@@ -3040,27 +3076,27 @@ class basic_json
     */
     template <
         typename T,
-                 typename U = uncvref_t<T>,
-        enable_if_t<
+        typename U = uncvref_t<T>,
+        enable_if_t <
             not std::is_same<basic_json_t, U>::value and
-                detail::has_from_json<basic_json_t, U>::value and
-                not detail::has_non_default_from_json<basic_json_t,
-                                                      U>::value,
-            int> = 0>
+            detail::has_from_json<basic_json_t, U>::value and
+            not detail::has_non_default_from_json<basic_json_t,
+                    U>::value,
+            int > = 0 >
     // do we really want the uncvref ? if a user call get<int &>, shouldn't we
     // static assert ?
     // i know there is a special behaviour for boolean_t* and such
     auto get() const noexcept(noexcept(JSONSerializer<U>::from_json(
-        std::declval<const basic_json_t &>(), std::declval<U &>())))
-        -> U
+                                           std::declval<const basic_json_t&>(), std::declval<U&>())))
+    -> U
     {
-      static_assert(std::is_default_constructible<U>::value and
-                        std::is_copy_constructible<U>::value,
-                    "Types must be DefaultConstructible and "
-                    "CopyConstructible when used with get");
-      U ret;
-      JSONSerializer<U>::from_json(*this, ret);
-      return ret;
+        static_assert(std::is_default_constructible<U>::value and
+        std::is_copy_constructible<U>::value,
+        "Types must be DefaultConstructible and "
+        "CopyConstructible when used with get");
+        U ret;
+        JSONSerializer<U>::from_json(*this, ret);
+        return ret;
     }
 
     /*!
@@ -3072,7 +3108,7 @@ class basic_json
     - U is not @ref basic_json
     - @ref json_serializer<U> has a from_json method of the form: U from_json(const @ref basic_json&);
 
-    @return a value of type U 
+    @return a value of type U
 
     @throw what json_serializer<U> from_json method throws
 
@@ -3081,12 +3117,12 @@ class basic_json
     template <
         typename T,
         enable_if_t<not std::is_same<basic_json_t, uncvref_t<T>>::value and
-                        detail::has_non_default_from_json<basic_json_t,
-                                                          uncvref_t<T>>::value,
-                    int> = 0>
-    uncvref_t<T> get() const noexcept(noexcept(JSONSerializer<T>::from_json(std::declval<const basic_json_t &>())))
+                    detail::has_non_default_from_json<basic_json_t,
+                            uncvref_t<T>>::value,
+                    int> = 0 >
+    uncvref_t<T> get() const noexcept(noexcept(JSONSerializer<T>::from_json(std::declval<const basic_json_t&>())))
     {
-      return JSONSerializer<T>::from_json(*this);
+        return JSONSerializer<T>::from_json(*this);
     }
 
     /*!
@@ -3168,8 +3204,8 @@ class basic_json
     {
         // get the type of the PointerType (remove pointer and const)
         using pointee_t = typename std::remove_const<typename
-                std::remove_pointer<typename
-                                    std::remove_const<PointerType>::type>::type>::type;
+                          std::remove_pointer<typename
+                          std::remove_const<PointerType>::type>::type>::type;
         // make sure the type matches the allowed types
         static_assert(
             std::is_same<object_t, pointee_t>::value
@@ -3196,8 +3232,8 @@ class basic_json
     {
         // get the type of the PointerType (remove pointer and const)
         using pointee_t = typename std::remove_const<typename
-                std::remove_pointer<typename
-                                    std::remove_const<PointerType>::type>::type>::type;
+                          std::remove_pointer<typename
+                          std::remove_const<PointerType>::type>::type>::type;
         // make sure the type matches the allowed types
         static_assert(
             std::is_same<object_t, pointee_t>::value
@@ -4250,14 +4286,14 @@ class basic_json
             case value_t::object:
             {
                 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
-                        last.m_it.object_iterator);
+                                              last.m_it.object_iterator);
                 break;
             }
 
             case value_t::array:
             {
                 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
-                        last.m_it.array_iterator);
+                                             last.m_it.array_iterator);
                 break;
             }
 
@@ -5474,9 +5510,9 @@ class basic_json
         // insert to array and return iterator
         iterator result(this);
         result.m_it.array_iterator = m_value.array->insert(
-            pos.m_it.array_iterator,
-            first.m_it.array_iterator,
-            last.m_it.array_iterator);
+                                         pos.m_it.array_iterator,
+                                         first.m_it.array_iterator,
+                                         last.m_it.array_iterator);
         return result;
     }
 
@@ -5546,7 +5582,7 @@ class basic_json
         std::is_nothrow_move_assignable<value_t>::value and
         std::is_nothrow_move_constructible<json_value>::value and
         std::is_nothrow_move_assignable<json_value>::value
-                                       )
+    )
     {
         std::swap(m_type, other.m_type);
         std::swap(m_value, other.m_value);
@@ -7871,7 +7907,10 @@ class basic_json
 
     @since version 1.0.0
     */
-    std::string type_name() const { return detail::type_name(*this); }
+    std::string type_name() const
+    {
+        return detail::type_name(*this);
+    }
 
   private:
     /*!
@@ -8086,13 +8125,13 @@ class basic_json
                         o << (pretty_print ? ",\n" : ",");
                     }
                     o << string_t(new_indent, ' ') << "\""
-                                                    << escape_string(i->first) << "\":"
-                                                            << (pretty_print ? " " : "");
-                                                            i->second.dump(o, pretty_print, indent_step, new_indent);
+                      << escape_string(i->first) << "\":"
+                      << (pretty_print ? " " : "");
+                    i->second.dump(o, pretty_print, indent_step, new_indent);
                 }
 
-                                                        // decrease indentation
-                                                        if (pretty_print)
+                // decrease indentation
+                if (pretty_print)
                 {
                     new_indent -= indent_step;
                     o << "\n";
@@ -8137,16 +8176,16 @@ class basic_json
                 }
 
                 o << string_t(new_indent, ' ') << "]";
-                   return;
+                return;
             }
 
-               case value_t::string:
+            case value_t::string:
             {
                 o << string_t("\"") << escape_string(*m_value.string) << "\"";
-                                     return;
+                return;
             }
 
-                                 case value_t::boolean:
+            case value_t::boolean:
             {
                 o << (m_value.boolean ? "true" : "false");
                 return;
@@ -8220,126 +8259,126 @@ class basic_json
     */
     class primitive_iterator_t
     {
-        public:
+      public:
 
         difference_type get_value() const noexcept
-    {
-        return m_it;
-    }
-    /// set iterator to a defined beginning
-    void set_begin() noexcept
-    {
-        m_it = begin_value;
-    }
+        {
+            return m_it;
+        }
+        /// set iterator to a defined beginning
+        void set_begin() noexcept
+        {
+            m_it = begin_value;
+        }
 
-    /// set iterator to a defined past the end
-    void set_end() noexcept
-    {
-        m_it = end_value;
-    }
+        /// set iterator to a defined past the end
+        void set_end() noexcept
+        {
+            m_it = end_value;
+        }
 
-    /// return whether the iterator can be dereferenced
-    constexpr bool is_begin() const noexcept
-    {
-        return (m_it == begin_value);
-    }
+        /// return whether the iterator can be dereferenced
+        constexpr bool is_begin() const noexcept
+        {
+            return (m_it == begin_value);
+        }
 
-    /// return whether the iterator is at end
-    constexpr bool is_end() const noexcept
-    {
-        return (m_it == end_value);
-    }
+        /// return whether the iterator is at end
+        constexpr bool is_end() const noexcept
+        {
+            return (m_it == end_value);
+        }
 
-    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it == rhs.m_it;
-    }
+        friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it == rhs.m_it;
+        }
 
-    friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return !(lhs == rhs);
-    }
+        friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return !(lhs == rhs);
+        }
 
-    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it < rhs.m_it;
-    }
+        friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it < rhs.m_it;
+        }
 
-    friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it <= rhs.m_it;
-    }
+        friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it <= rhs.m_it;
+        }
 
-    friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it > rhs.m_it;
-    }
+        friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it > rhs.m_it;
+        }
 
-    friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it >= rhs.m_it;
-    }
+        friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it >= rhs.m_it;
+        }
 
-    primitive_iterator_t operator+(difference_type i)
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
+        primitive_iterator_t operator+(difference_type i)
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
 
-    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it - rhs.m_it;
-    }
+        friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it - rhs.m_it;
+        }
 
-    friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
-    {
-        return os << it.m_it;
-    }
+        friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
+        {
+            return os << it.m_it;
+        }
 
-    primitive_iterator_t& operator++()
-    {
-        ++m_it;
-        return *this;
-    }
+        primitive_iterator_t& operator++()
+        {
+            ++m_it;
+            return *this;
+        }
 
-    primitive_iterator_t& operator++(int)
-    {
-        m_it++;
-        return *this;
-    }
+        primitive_iterator_t& operator++(int)
+        {
+            m_it++;
+            return *this;
+        }
 
-    primitive_iterator_t& operator--()
-    {
-        --m_it;
-        return *this;
-    }
+        primitive_iterator_t& operator--()
+        {
+            --m_it;
+            return *this;
+        }
 
-    primitive_iterator_t& operator--(int)
-    {
-        m_it--;
-        return *this;
-    }
+        primitive_iterator_t& operator--(int)
+        {
+            m_it--;
+            return *this;
+        }
 
-    primitive_iterator_t& operator+=(difference_type n)
-    {
-        m_it += n;
-        return *this;
-    }
+        primitive_iterator_t& operator+=(difference_type n)
+        {
+            m_it += n;
+            return *this;
+        }
 
-    primitive_iterator_t& operator-=(difference_type n)
-    {
-        m_it -= n;
-        return *this;
-    }
+        primitive_iterator_t& operator-=(difference_type n)
+        {
+            m_it -= n;
+            return *this;
+        }
 
-    private:
-    static constexpr difference_type begin_value = 0;
-    static constexpr difference_type end_value = begin_value + 1;
+      private:
+        static constexpr difference_type begin_value = 0;
+        static constexpr difference_type end_value = begin_value + 1;
 
-    /// iterator as signed integer type
-    difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
-                                              };
+        /// iterator as signed integer type
+        difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
+    };
 
     /*!
     @brief an iterator value
@@ -8359,104 +8398,104 @@ class basic_json
 
         /// create an uninitialized internal_iterator
         internal_iterator() noexcept
-        : object_iterator(), array_iterator(), primitive_iterator()
-    {}
+            : object_iterator(), array_iterator(), primitive_iterator()
+        {}
     };
 
     /// proxy class for the iterator_wrapper functions
     template<typename IteratorType>
     class iteration_proxy
     {
-        private:
+      private:
         /// helper class for iteration
         class iteration_proxy_internal
         {
-            private:
+          private:
             /// the iterator
             IteratorType anchor;
             /// an index for arrays (used to create key names)
             size_t array_index = 0;
 
-            public:
+          public:
             explicit iteration_proxy_internal(IteratorType it) noexcept
-            : anchor(it)
-    {}
+                : anchor(it)
+            {}
 
-    /// dereference operator (needed for range-based for)
-    iteration_proxy_internal& operator*()
-    {
-        return *this;
-    }
-
-    /// increment operator (needed for range-based for)
-    iteration_proxy_internal& operator++()
-    {
-        ++anchor;
-        ++array_index;
-
-        return *this;
-    }
-
-    /// inequality operator (needed for range-based for)
-    bool operator!= (const iteration_proxy_internal& o) const
-    {
-        return anchor != o.anchor;
-    }
-
-    /// return key of the iterator
-    typename basic_json::string_t key() const
-    {
-        assert(anchor.m_object != nullptr);
-
-        switch (anchor.m_object->type())
-        {
-            // use integer array index as key
-            case value_t::array:
+            /// dereference operator (needed for range-based for)
+            iteration_proxy_internal& operator*()
             {
-                return std::to_string(array_index);
+                return *this;
             }
 
-            // use key from the object
-            case value_t::object:
+            /// increment operator (needed for range-based for)
+            iteration_proxy_internal& operator++()
             {
-                return anchor.key();
+                ++anchor;
+                ++array_index;
+
+                return *this;
             }
 
-            // use an empty key for all primitive types
-            default:
+            /// inequality operator (needed for range-based for)
+            bool operator!= (const iteration_proxy_internal& o) const
             {
-                return "";
+                return anchor != o.anchor;
             }
-        }
-    }
 
-    /// return value of the iterator
-    typename IteratorType::reference value() const
-    {
-        return anchor.value();
-    }
+            /// return key of the iterator
+            typename basic_json::string_t key() const
+            {
+                assert(anchor.m_object != nullptr);
+
+                switch (anchor.m_object->type())
+                {
+                    // use integer array index as key
+                    case value_t::array:
+                    {
+                        return std::to_string(array_index);
+                    }
+
+                    // use key from the object
+                    case value_t::object:
+                    {
+                        return anchor.key();
+                    }
+
+                    // use an empty key for all primitive types
+                    default:
+                    {
+                        return "";
+                    }
+                }
+            }
+
+            /// return value of the iterator
+            typename IteratorType::reference value() const
+            {
+                return anchor.value();
+            }
         };
 
-    /// the container to iterate
-    typename IteratorType::reference container;
+        /// the container to iterate
+        typename IteratorType::reference container;
 
-    public:
-    /// construct iteration proxy from a container
-    explicit iteration_proxy(typename IteratorType::reference cont)
-    : container(cont)
-    {}
+      public:
+        /// construct iteration proxy from a container
+        explicit iteration_proxy(typename IteratorType::reference cont)
+            : container(cont)
+        {}
 
-    /// return iterator begin (needed for range-based for)
-    iteration_proxy_internal begin() noexcept
-    {
-        return iteration_proxy_internal(container.begin());
-    }
+        /// return iterator begin (needed for range-based for)
+        iteration_proxy_internal begin() noexcept
+        {
+            return iteration_proxy_internal(container.begin());
+        }
 
-    /// return iterator end (needed for range-based for)
-    iteration_proxy_internal end() noexcept
-    {
-        return iteration_proxy_internal(container.end());
-    }
+        /// return iterator end (needed for range-based for)
+        iteration_proxy_internal end() noexcept
+        {
+            return iteration_proxy_internal(container.end());
+        }
     };
 
   public:
@@ -8480,7 +8519,7 @@ class basic_json
     @since version 1.0.0, simplified in version 2.0.9
     */
     template<typename U>
-  class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
+    class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
     {
         /// allow basic_json to access private members
         friend class basic_json;
@@ -8490,19 +8529,19 @@ class basic_json
                       or std::is_same<U, const basic_json>::value,
                       "iter_impl only accepts (const) basic_json");
 
-        public:
+      public:
         /// the type of the values when the iterator is dereferenced
         using value_type = typename basic_json::value_type;
         /// a type to represent differences between iterators
         using difference_type = typename basic_json::difference_type;
         /// defines a pointer to the type iterated over (value_type)
         using pointer = typename std::conditional<std::is_const<U>::value,
-                typename basic_json::const_pointer,
-                typename basic_json::pointer>::type;
+              typename basic_json::const_pointer,
+              typename basic_json::pointer>::type;
         /// defines a reference to the type iterated over (value_type)
         using reference = typename std::conditional<std::is_const<U>::value,
-                typename basic_json::const_reference,
-                typename basic_json::reference>::type;
+              typename basic_json::const_reference,
+              typename basic_json::reference>::type;
         /// the category of the iterator
         using iterator_category = std::bidirectional_iterator_tag;
 
@@ -8516,566 +8555,566 @@ class basic_json
         @post The iterator is initialized; i.e. `m_object != nullptr`.
         */
         explicit iter_impl(pointer object) noexcept
-        : m_object(object)
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
+            : m_object(object)
         {
-            case basic_json::value_t::object:
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
             {
-                m_it.object_iterator = typename object_t::iterator();
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                m_it.array_iterator = typename array_t::iterator();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator = primitive_iterator_t();
-                break;
-            }
-        }
-    }
-
-    /*
-    Use operator `const_iterator` instead of `const_iterator(const iterator&
-    other) noexcept` to avoid two class definitions for @ref iterator and
-    @ref const_iterator.
-
-    This function is only called if this class is an @ref iterator. If this
-    class is a @ref const_iterator this function is not called.
-    */
-    operator const_iterator() const
-    {
-        const_iterator ret;
-
-        if (m_object)
-        {
-            ret.m_object = m_object;
-            ret.m_it = m_it;
-        }
-
-        return ret;
-    }
-
-    /*!
-    @brief copy constructor
-    @param[in] other  iterator to copy from
-    @note It is not checked whether @a other is initialized.
-    */
-    iter_impl(const iter_impl& other) noexcept
-    : m_object(other.m_object), m_it(other.m_it)
-    {}
-
-    /*!
-    @brief copy assignment
-    @param[in,out] other  iterator to copy from
-    @note It is not checked whether @a other is initialized.
-    */
-    iter_impl& operator=(iter_impl other) noexcept(
-        std::is_nothrow_move_constructible<pointer>::value and
-        std::is_nothrow_move_assignable<pointer>::value and
-        std::is_nothrow_move_constructible<internal_iterator>::value and
-        std::is_nothrow_move_assignable<internal_iterator>::value
-                                       )
-    {
-        std::swap(m_object, other.m_object);
-        std::swap(m_it, other.m_it);
-        return *this;
-    }
-
-    private:
-    /*!
-    @brief set the iterator to the first value
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    void set_begin() noexcept
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                m_it.object_iterator = m_object->m_value.object->begin();
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                m_it.array_iterator = m_object->m_value.array->begin();
-                break;
-            }
-
-            case basic_json::value_t::null:
-            {
-                // set to end so begin()==end() is true: null is empty
-                m_it.primitive_iterator.set_end();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator.set_begin();
-                break;
-            }
-        }
-    }
-
-    /*!
-    @brief set the iterator past the last value
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    void set_end() noexcept
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                m_it.object_iterator = m_object->m_value.object->end();
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                m_it.array_iterator = m_object->m_value.array->end();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator.set_end();
-                break;
-            }
-        }
-    }
-
-    public:
-    /*!
-    @brief return a reference to the value pointed to by the iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference operator*() const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                assert(m_it.object_iterator != m_object->m_value.object->end());
-                return m_it.object_iterator->second;
-            }
-
-            case basic_json::value_t::array:
-            {
-                assert(m_it.array_iterator != m_object->m_value.array->end());
-                return *m_it.array_iterator;
-            }
-
-            case basic_json::value_t::null:
-            {
-                    JSON_THROW(std::out_of_range("cannot get value"));
-            }
-
-            default:
-            {
-                if (m_it.primitive_iterator.is_begin())
+                case basic_json::value_t::object:
                 {
-                    return *m_object;
+                    m_it.object_iterator = typename object_t::iterator();
+                    break;
                 }
 
-                    JSON_THROW(std::out_of_range("cannot get value"));
-            }
-        }
-    }
-
-    /*!
-    @brief dereference the iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    pointer operator->() const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                assert(m_it.object_iterator != m_object->m_value.object->end());
-                return &(m_it.object_iterator->second);
-            }
-
-            case basic_json::value_t::array:
-            {
-                assert(m_it.array_iterator != m_object->m_value.array->end());
-                return &*m_it.array_iterator;
-            }
-
-            default:
-            {
-                if (m_it.primitive_iterator.is_begin())
+                case basic_json::value_t::array:
                 {
-                    return m_object;
+                    m_it.array_iterator = typename array_t::iterator();
+                    break;
                 }
 
+                default:
+                {
+                    m_it.primitive_iterator = primitive_iterator_t();
+                    break;
+                }
+            }
+        }
+
+        /*
+        Use operator `const_iterator` instead of `const_iterator(const iterator&
+        other) noexcept` to avoid two class definitions for @ref iterator and
+        @ref const_iterator.
+
+        This function is only called if this class is an @ref iterator. If this
+        class is a @ref const_iterator this function is not called.
+        */
+        operator const_iterator() const
+        {
+            const_iterator ret;
+
+            if (m_object)
+            {
+                ret.m_object = m_object;
+                ret.m_it = m_it;
+            }
+
+            return ret;
+        }
+
+        /*!
+        @brief copy constructor
+        @param[in] other  iterator to copy from
+        @note It is not checked whether @a other is initialized.
+        */
+        iter_impl(const iter_impl& other) noexcept
+            : m_object(other.m_object), m_it(other.m_it)
+        {}
+
+        /*!
+        @brief copy assignment
+        @param[in,out] other  iterator to copy from
+        @note It is not checked whether @a other is initialized.
+        */
+        iter_impl& operator=(iter_impl other) noexcept(
+            std::is_nothrow_move_constructible<pointer>::value and
+            std::is_nothrow_move_assignable<pointer>::value and
+            std::is_nothrow_move_constructible<internal_iterator>::value and
+            std::is_nothrow_move_assignable<internal_iterator>::value
+        )
+        {
+            std::swap(m_object, other.m_object);
+            std::swap(m_it, other.m_it);
+            return *this;
+        }
+
+      private:
+        /*!
+        @brief set the iterator to the first value
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        void set_begin() noexcept
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = m_object->m_value.object->begin();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = m_object->m_value.array->begin();
+                    break;
+                }
+
+                case basic_json::value_t::null:
+                {
+                    // set to end so begin()==end() is true: null is empty
+                    m_it.primitive_iterator.set_end();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator.set_begin();
+                    break;
+                }
+            }
+        }
+
+        /*!
+        @brief set the iterator past the last value
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        void set_end() noexcept
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = m_object->m_value.object->end();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = m_object->m_value.array->end();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator.set_end();
+                    break;
+                }
+            }
+        }
+
+      public:
+        /*!
+        @brief return a reference to the value pointed to by the iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference operator*() const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    assert(m_it.object_iterator != m_object->m_value.object->end());
+                    return m_it.object_iterator->second;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    assert(m_it.array_iterator != m_object->m_value.array->end());
+                    return *m_it.array_iterator;
+                }
+
+                case basic_json::value_t::null:
+                {
                     JSON_THROW(std::out_of_range("cannot get value"));
-            }
-        }
-    }
+                }
 
-    /*!
-    @brief post-increment (it++)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator++(int)
-    {
-        auto result = *this;
-        ++(*this);
-        return result;
-    }
+                default:
+                {
+                    if (m_it.primitive_iterator.is_begin())
+                    {
+                        return *m_object;
+                    }
 
-    /*!
-    @brief pre-increment (++it)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator++()
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                std::advance(m_it.object_iterator, 1);
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                std::advance(m_it.array_iterator, 1);
-                break;
-            }
-
-            default:
-            {
-                ++m_it.primitive_iterator;
-                break;
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
             }
         }
 
-        return *this;
-    }
-
-    /*!
-    @brief post-decrement (it--)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator--(int)
-    {
-        auto result = *this;
-        --(*this);
-        return result;
-    }
-
-    /*!
-    @brief pre-decrement (--it)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator--()
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
+        /*!
+        @brief dereference the iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        pointer operator->() const
         {
-            case basic_json::value_t::object:
-            {
-                std::advance(m_it.object_iterator, -1);
-                break;
-            }
+            assert(m_object != nullptr);
 
-            case basic_json::value_t::array:
+            switch (m_object->m_type)
             {
-                std::advance(m_it.array_iterator, -1);
-                break;
-            }
+                case basic_json::value_t::object:
+                {
+                    assert(m_it.object_iterator != m_object->m_value.object->end());
+                    return &(m_it.object_iterator->second);
+                }
 
-            default:
-            {
-                --m_it.primitive_iterator;
-                break;
+                case basic_json::value_t::array:
+                {
+                    assert(m_it.array_iterator != m_object->m_value.array->end());
+                    return &*m_it.array_iterator;
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator.is_begin())
+                    {
+                        return m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
             }
         }
 
-        return *this;
-    }
-
-    /*!
-    @brief  comparison: equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator==(const iter_impl& other) const
-    {
-        // if objects are not the same, the comparison is undefined
-        if (m_object != other.m_object)
+        /*!
+        @brief post-increment (it++)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator++(int)
         {
+            auto result = *this;
+            ++(*this);
+            return result;
+        }
+
+        /*!
+        @brief pre-increment (++it)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator++()
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    std::advance(m_it.object_iterator, 1);
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, 1);
+                    break;
+                }
+
+                default:
+                {
+                    ++m_it.primitive_iterator;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief post-decrement (it--)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator--(int)
+        {
+            auto result = *this;
+            --(*this);
+            return result;
+        }
+
+        /*!
+        @brief pre-decrement (--it)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator--()
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    std::advance(m_it.object_iterator, -1);
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, -1);
+                    break;
+                }
+
+                default:
+                {
+                    --m_it.primitive_iterator;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief  comparison: equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator==(const iter_impl& other) const
+        {
+            // if objects are not the same, the comparison is undefined
+            if (m_object != other.m_object)
+            {
                 JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
-        }
-
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                return (m_it.object_iterator == other.m_it.object_iterator);
             }
 
-            case basic_json::value_t::array:
-            {
-                return (m_it.array_iterator == other.m_it.array_iterator);
-            }
+            assert(m_object != nullptr);
 
-            default:
+            switch (m_object->m_type)
             {
-                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+                case basic_json::value_t::object:
+                {
+                    return (m_it.object_iterator == other.m_it.object_iterator);
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return (m_it.array_iterator == other.m_it.array_iterator);
+                }
+
+                default:
+                {
+                    return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+                }
             }
         }
-    }
 
-    /*!
-    @brief  comparison: not equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator!=(const iter_impl& other) const
-    {
-        return not operator==(other);
-    }
-
-    /*!
-    @brief  comparison: smaller
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator<(const iter_impl& other) const
-    {
-        // if objects are not the same, the comparison is undefined
-        if (m_object != other.m_object)
+        /*!
+        @brief  comparison: not equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator!=(const iter_impl& other) const
         {
+            return not operator==(other);
+        }
+
+        /*!
+        @brief  comparison: smaller
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator<(const iter_impl& other) const
+        {
+            // if objects are not the same, the comparison is undefined
+            if (m_object != other.m_object)
+            {
                 JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
-        }
+            }
 
-        assert(m_object != nullptr);
+            assert(m_object != nullptr);
 
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
+            switch (m_object->m_type)
             {
+                case basic_json::value_t::object:
+                {
                     JSON_THROW(std::domain_error("cannot compare order of object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                return (m_it.array_iterator < other.m_it.array_iterator);
-            }
-
-            default:
-            {
-                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
-            }
-        }
-    }
-
-    /*!
-    @brief  comparison: less than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator<=(const iter_impl& other) const
-    {
-        return not other.operator < (*this);
-    }
-
-    /*!
-    @brief  comparison: greater than
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator>(const iter_impl& other) const
-    {
-        return not operator<=(other);
-    }
-
-    /*!
-    @brief  comparison: greater than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator>=(const iter_impl& other) const
-    {
-        return not operator<(other);
-    }
-
-    /*!
-    @brief  add to iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator+=(difference_type i)
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                std::advance(m_it.array_iterator, i);
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator += i;
-                break;
-            }
-        }
-
-        return *this;
-    }
-
-    /*!
-    @brief  subtract from iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator-=(difference_type i)
-    {
-        return operator+=(-i);
-    }
-
-    /*!
-    @brief  add to iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator+(difference_type i)
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
-
-    /*!
-    @brief  subtract from iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator-(difference_type i)
-    {
-        auto result = *this;
-        result -= i;
-        return result;
-    }
-
-    /*!
-    @brief  return difference
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    difference_type operator-(const iter_impl& other) const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                return m_it.array_iterator - other.m_it.array_iterator;
-            }
-
-            default:
-            {
-                return m_it.primitive_iterator - other.m_it.primitive_iterator;
-            }
-        }
-    }
-
-    /*!
-    @brief  access to successor
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference operator[](difference_type n) const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                return *std::next(m_it.array_iterator, n);
-            }
-
-            case basic_json::value_t::null:
-            {
-                    JSON_THROW(std::out_of_range("cannot get value"));
-            }
-
-            default:
-            {
-                if (m_it.primitive_iterator.get_value() == -n)
-                {
-                    return *m_object;
                 }
 
-                    JSON_THROW(std::out_of_range("cannot get value"));
+                case basic_json::value_t::array:
+                {
+                    return (m_it.array_iterator < other.m_it.array_iterator);
+                }
+
+                default:
+                {
+                    return (m_it.primitive_iterator < other.m_it.primitive_iterator);
+                }
             }
         }
-    }
 
-    /*!
-    @brief  return the key of an object iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    typename object_t::key_type key() const
-    {
-        assert(m_object != nullptr);
-
-        if (m_object->is_object())
+        /*!
+        @brief  comparison: less than or equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator<=(const iter_impl& other) const
         {
-            return m_it.object_iterator->first;
+            return not other.operator < (*this);
         }
 
+        /*!
+        @brief  comparison: greater than
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator>(const iter_impl& other) const
+        {
+            return not operator<=(other);
+        }
+
+        /*!
+        @brief  comparison: greater than or equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator>=(const iter_impl& other) const
+        {
+            return not operator<(other);
+        }
+
+        /*!
+        @brief  add to iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator+=(difference_type i)
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, i);
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator += i;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief  subtract from iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator-=(difference_type i)
+        {
+            return operator+=(-i);
+        }
+
+        /*!
+        @brief  add to iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator+(difference_type i)
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
+
+        /*!
+        @brief  subtract from iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator-(difference_type i)
+        {
+            auto result = *this;
+            result -= i;
+            return result;
+        }
+
+        /*!
+        @brief  return difference
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        difference_type operator-(const iter_impl& other) const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return m_it.array_iterator - other.m_it.array_iterator;
+                }
+
+                default:
+                {
+                    return m_it.primitive_iterator - other.m_it.primitive_iterator;
+                }
+            }
+        }
+
+        /*!
+        @brief  access to successor
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference operator[](difference_type n) const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return *std::next(m_it.array_iterator, n);
+                }
+
+                case basic_json::value_t::null:
+                {
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator.get_value() == -n)
+                    {
+                        return *m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+            }
+        }
+
+        /*!
+        @brief  return the key of an object iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        typename object_t::key_type key() const
+        {
+            assert(m_object != nullptr);
+
+            if (m_object->is_object())
+            {
+                return m_it.object_iterator->first;
+            }
+
             JSON_THROW(std::domain_error("cannot use key() for non-object iterators"));
-    }
+        }
 
-    /*!
-    @brief  return the value of an iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference value() const
-    {
-        return operator*();
-    }
+        /*!
+        @brief  return the value of an iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference value() const
+        {
+            return operator*();
+        }
 
-    private:
-    /// associated JSON instance
-    pointer m_object = nullptr;
-    /// the actual iterator of the associated instance
-    internal_iterator m_it = internal_iterator();
-                       };
+      private:
+        /// associated JSON instance
+        pointer m_object = nullptr;
+        /// the actual iterator of the associated instance
+        internal_iterator m_it = internal_iterator();
+    };
 
     /*!
     @brief a template for a reverse iterator class
@@ -9095,9 +9134,9 @@ class basic_json
     @since version 1.0.0
     */
     template<typename Base>
-  class json_reverse_iterator : public std::reverse_iterator<Base>
+    class json_reverse_iterator : public std::reverse_iterator<Base>
     {
-        public:
+      public:
         /// shortcut to the reverse iterator adaptor
         using base_iterator = std::reverse_iterator<Base>;
         /// the reference type for the pointed-to element
@@ -9105,89 +9144,89 @@ class basic_json
 
         /// create reverse iterator from iterator
         json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
-        : base_iterator(it)
-    {}
+            : base_iterator(it)
+        {}
 
-    /// create reverse iterator from base class
-    json_reverse_iterator(const base_iterator& it) noexcept
-    : base_iterator(it)
-    {}
+        /// create reverse iterator from base class
+        json_reverse_iterator(const base_iterator& it) noexcept
+            : base_iterator(it)
+        {}
 
-    /// post-increment (it++)
-    json_reverse_iterator operator++(int)
-    {
-        return base_iterator::operator++(1);
-    }
+        /// post-increment (it++)
+        json_reverse_iterator operator++(int)
+        {
+            return base_iterator::operator++(1);
+        }
 
-    /// pre-increment (++it)
-    json_reverse_iterator& operator++()
-    {
-        base_iterator::operator++();
-        return *this;
-    }
+        /// pre-increment (++it)
+        json_reverse_iterator& operator++()
+        {
+            base_iterator::operator++();
+            return *this;
+        }
 
-    /// post-decrement (it--)
-    json_reverse_iterator operator--(int)
-    {
-        return base_iterator::operator--(1);
-    }
+        /// post-decrement (it--)
+        json_reverse_iterator operator--(int)
+        {
+            return base_iterator::operator--(1);
+        }
 
-    /// pre-decrement (--it)
-    json_reverse_iterator& operator--()
-    {
-        base_iterator::operator--();
-        return *this;
-    }
+        /// pre-decrement (--it)
+        json_reverse_iterator& operator--()
+        {
+            base_iterator::operator--();
+            return *this;
+        }
 
-    /// add to iterator
-    json_reverse_iterator& operator+=(difference_type i)
-    {
-        base_iterator::operator+=(i);
-        return *this;
-    }
+        /// add to iterator
+        json_reverse_iterator& operator+=(difference_type i)
+        {
+            base_iterator::operator+=(i);
+            return *this;
+        }
 
-    /// add to iterator
-    json_reverse_iterator operator+(difference_type i) const
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
+        /// add to iterator
+        json_reverse_iterator operator+(difference_type i) const
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
 
-    /// subtract from iterator
-    json_reverse_iterator operator-(difference_type i) const
-    {
-        auto result = *this;
-        result -= i;
-        return result;
-    }
+        /// subtract from iterator
+        json_reverse_iterator operator-(difference_type i) const
+        {
+            auto result = *this;
+            result -= i;
+            return result;
+        }
 
-    /// return difference
-    difference_type operator-(const json_reverse_iterator& other) const
-    {
-        return this->base() - other.base();
-    }
+        /// return difference
+        difference_type operator-(const json_reverse_iterator& other) const
+        {
+            return this->base() - other.base();
+        }
 
-    /// access to successor
-    reference operator[](difference_type n) const
-    {
-        return *(this->operator+(n));
-    }
+        /// access to successor
+        reference operator[](difference_type n) const
+        {
+            return *(this->operator+(n));
+        }
 
-    /// return the key of an object iterator
-    typename object_t::key_type key() const
-    {
-        auto it = --this->base();
-        return it.key();
-    }
+        /// return the key of an object iterator
+        typename object_t::key_type key() const
+        {
+            auto it = --this->base();
+            return it.key();
+        }
 
-    /// return the value of an iterator
-    reference value() const
-    {
-        auto it = --this->base();
-        return it.operator * ();
-    }
-                                                   };
+        /// return the value of an iterator
+        reference value() const
+        {
+            auto it = --this->base();
+            return it.operator * ();
+        }
+    };
 
 
   private:
@@ -9204,1133 +9243,1611 @@ class basic_json
     */
     class lexer
     {
-        public:
+      public:
         /// token types for the parser
         enum class token_type
-    {
-        uninitialized,   ///< indicating the scanner is uninitialized
-        literal_true,    ///< the `true` literal
-        literal_false,   ///< the `false` literal
-        literal_null,    ///< the `null` literal
-        value_string,    ///< a string -- use get_string() for actual value
-        value_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
-    using lexer_char_t = unsigned char;
-
-    /// a lexer from a buffer with given length
-    lexer(const lexer_char_t* buff, const size_t len) noexcept
-    : m_content(buff)
-    {
-        assert(m_content != nullptr);
-        m_start = m_cursor = m_content;
-        m_limit = m_content + len;
-    }
-
-    /// a lexer from an input stream
-    explicit lexer(std::istream& s)
-    : m_stream(&s), m_line_buffer()
-    {
-        // immediately abort if stream is erroneous
-        if (s.fail())
         {
-                JSON_THROW(std::invalid_argument("stream error"));
-        }
-
-        // fill buffer
-        fill_line_buffer();
-
-        // skip UTF-8 byte-order mark
-        if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
-        {
-            m_line_buffer[0] = ' ';
-            m_line_buffer[1] = ' ';
-            m_line_buffer[2] = ' ';
-        }
-    }
-
-    // switch off unwanted functions (due to pointer members)
-    lexer() = delete;
-    lexer(const lexer&) = delete;
-    lexer operator=(const lexer&) = delete;
-
-    /*!
-    @brief create a string from one or two Unicode code points
-
-    There are two cases: (1) @a codepoint1 is in the Basic Multilingual
-    Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
-    @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
-    represent a code point above U+FFFF.
-
-    @param[in] codepoint1  the code point (can be high surrogate)
-    @param[in] codepoint2  the code point (can be low surrogate or 0)
-
-    @return string representation of the code point; the length of the
-    result string is between 1 and 4 characters.
-
-    @throw std::out_of_range if code point is > 0x10ffff; example: `"code
-    points above 0x10FFFF are invalid"`
-    @throw std::invalid_argument if the low surrogate is invalid; example:
-    `""missing or wrong low surrogate""`
-
-    @complexity Constant.
-
-    @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
-    */
-    static string_t to_unicode(const std::size_t codepoint1,
-                               const std::size_t codepoint2 = 0)
-    {
-        // calculate the code point from the given code points
-        std::size_t codepoint = codepoint1;
-
-        // check if codepoint1 is a high surrogate
-        if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
-        {
-            // check if codepoint2 is a low surrogate
-            if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
-            {
-                codepoint =
-                // high surrogate occupies the most significant 22 bits
-                (codepoint1 << 10)
-                 // low surrogate occupies the least significant 15 bits
-                 + codepoint2
-                 // there is still the 0xD800, 0xDC00 and 0x10000 noise
-                 // in the result so we have to subtract with:
-                 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
-                 - 0x35FDC00;
-            }
-            else
-            {
-                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
-            }
-        }
-
-        string_t result;
-
-        if (codepoint < 0x80)
-        {
-            // 1-byte characters: 0xxxxxxx (ASCII)
-            result.append(1, static_cast<typename string_t::value_type>(codepoint));
-        }
-        else if (codepoint <= 0x7ff)
-        {
-            // 2-byte characters: 110xxxxx 10xxxxxx
-            result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
-        }
-        else if (codepoint <= 0xffff)
-        {
-            // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
-            result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
-        }
-        else if (codepoint <= 0x10ffff)
-        {
-            // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-            result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
-        }
-        else
-        {
-                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
-        }
-
-        return result;
-    }
-
-    /// return name of values of type token_type (only used for errors)
-    static std::string token_type_name(const token_type t)
-    {
-        switch (t)
-        {
-            case token_type::uninitialized:
-                return "<uninitialized>";
-            case token_type::literal_true:
-                return "true literal";
-            case token_type::literal_false:
-                return "false literal";
-            case token_type::literal_null:
-                return "null literal";
-            case token_type::value_string:
-                return "string literal";
-            case token_type::value_number:
-                return "number literal";
-            case token_type::begin_array:
-                return "'['";
-            case token_type::begin_object:
-                return "'{'";
-            case token_type::end_array:
-                return "']'";
-            case token_type::end_object:
-                return "'}'";
-            case token_type::name_separator:
-                return "':'";
-            case token_type::value_separator:
-                return "','";
-            case token_type::parse_error:
-                return "<parse error>";
-            case token_type::end_of_input:
-                return "end of input";
-            default:
-            {
-                // catch non-enum values
-                return "unknown token"; // LCOV_EXCL_LINE
-            }
-        }
-    }
-
-    /*!
-    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 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
-
-    @complexity Linear in the length of the input.\n
-
-    Proposition: The loop below will always terminate for finite input.\n
-
-    Proof (by contradiction): Assume a finite input. To loop forever, the
-    loop must never hit code with a `break` statement. The only code
-    snippets without a `break` statement are the continue statements for
-    whitespace and byte-order-marks. To loop forever, the input must be an
-    infinite sequence of whitespace or byte-order-marks. This contradicts
-    the assumption of finite input, q.e.d.
-    */
-    token_type scan()
-    {
-        while (true)
-        {
-            // pointer for backtracking information
-            m_marker = nullptr;
-
-            // remember the begin of the token
-            m_start = m_cursor;
-            assert(m_start != nullptr);
-
-            
-    {
-        lexer_char_t yych;
-        unsigned int yyaccept = 0;
-        static const unsigned char yybm[] = {
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,  32,  32,   0,   0,  32,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-            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, 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, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
-              0,   0,   0,   0,   0,   0,   0,   0, 
+            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
         };
-        if ((m_limit - m_cursor) < 5) fill_line_buffer(5); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yybm[0+yych] & 32) {
-            goto basic_json_parser_6;
-        }
-        if (yych <= '[') {
-            if (yych <= '-') {
-                if (yych <= '"') {
-                    if (yych <= 0x00) goto basic_json_parser_2;
-                    if (yych <= '!') goto basic_json_parser_4;
-                    goto basic_json_parser_9;
-                } else {
-                    if (yych <= '+') goto basic_json_parser_4;
-                    if (yych <= ',') goto basic_json_parser_10;
-                    goto basic_json_parser_12;
-                }
-            } else {
-                if (yych <= '9') {
-                    if (yych <= '/') goto basic_json_parser_4;
-                    if (yych <= '0') goto basic_json_parser_13;
-                    goto basic_json_parser_15;
-                } else {
-                    if (yych <= ':') goto basic_json_parser_17;
-                    if (yych <= 'Z') goto basic_json_parser_4;
-                    goto basic_json_parser_19;
-                }
-            }
-        } else {
-            if (yych <= 'n') {
-                if (yych <= 'e') {
-                    if (yych == ']') goto basic_json_parser_21;
-                    goto basic_json_parser_4;
-                } else {
-                    if (yych <= 'f') goto basic_json_parser_23;
-                    if (yych <= 'm') goto basic_json_parser_4;
-                    goto basic_json_parser_24;
-                }
-            } else {
-                if (yych <= 'z') {
-                    if (yych == 't') goto basic_json_parser_25;
-                    goto basic_json_parser_4;
-                } else {
-                    if (yych <= '{') goto basic_json_parser_26;
-                    if (yych == '}') goto basic_json_parser_28;
-                    goto basic_json_parser_4;
-                }
-            }
-        }
-basic_json_parser_2:
-        ++m_cursor;
-        { last_token_type = token_type::end_of_input; break; }
-basic_json_parser_4:
-        ++m_cursor;
-basic_json_parser_5:
-        { last_token_type = token_type::parse_error; break; }
-basic_json_parser_6:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yybm[0+yych] & 32) {
-            goto basic_json_parser_6;
-        }
-        { continue; }
-basic_json_parser_9:
-        yyaccept = 0;
-        yych = *(m_marker = ++m_cursor);
-        if (yych <= 0x1F) goto basic_json_parser_5;
-        if (yych <= 0x7F) goto basic_json_parser_31;
-        if (yych <= 0xC1) goto basic_json_parser_5;
-        if (yych <= 0xF4) goto basic_json_parser_31;
-        goto basic_json_parser_5;
-basic_json_parser_10:
-        ++m_cursor;
-        { last_token_type = token_type::value_separator; break; }
-basic_json_parser_12:
-        yych = *++m_cursor;
-        if (yych <= '/') goto basic_json_parser_5;
-        if (yych <= '0') goto basic_json_parser_13;
-        if (yych <= '9') goto basic_json_parser_15;
-        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;
-        } else {
-            if (yych <= 'E') goto basic_json_parser_44;
-            if (yych == 'e') goto basic_json_parser_44;
-        }
-basic_json_parser_14:
-        { last_token_type = token_type::value_number; break; }
-basic_json_parser_15:
-        yyaccept = 1;
-        m_marker = ++m_cursor;
-        if ((m_limit - m_cursor) < 3) fill_line_buffer(3); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yybm[0+yych] & 64) {
-            goto basic_json_parser_15;
-        }
-        if (yych <= 'D') {
-            if (yych == '.') goto basic_json_parser_43;
-            goto basic_json_parser_14;
-        } else {
-            if (yych <= 'E') goto basic_json_parser_44;
-            if (yych == 'e') goto basic_json_parser_44;
-            goto basic_json_parser_14;
-        }
-basic_json_parser_17:
-        ++m_cursor;
-        { last_token_type = token_type::name_separator; break; }
-basic_json_parser_19:
-        ++m_cursor;
-        { last_token_type = token_type::begin_array; break; }
-basic_json_parser_21:
-        ++m_cursor;
-        { last_token_type = token_type::end_array; break; }
-basic_json_parser_23:
-        yyaccept = 0;
-        yych = *(m_marker = ++m_cursor);
-        if (yych == 'a') goto basic_json_parser_45;
-        goto basic_json_parser_5;
-basic_json_parser_24:
-        yyaccept = 0;
-        yych = *(m_marker = ++m_cursor);
-        if (yych == 'u') goto basic_json_parser_46;
-        goto basic_json_parser_5;
-basic_json_parser_25:
-        yyaccept = 0;
-        yych = *(m_marker = ++m_cursor);
-        if (yych == 'r') goto basic_json_parser_47;
-        goto basic_json_parser_5;
-basic_json_parser_26:
-        ++m_cursor;
-        { last_token_type = token_type::begin_object; break; }
-basic_json_parser_28:
-        ++m_cursor;
-        { last_token_type = token_type::end_object; break; }
-basic_json_parser_30:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-basic_json_parser_31:
-        if (yybm[0+yych] & 128) {
-            goto basic_json_parser_30;
-        }
-        if (yych <= 0xE0) {
-            if (yych <= '\\') {
-                if (yych <= 0x1F) goto basic_json_parser_32;
-                if (yych <= '"') goto basic_json_parser_33;
-                goto basic_json_parser_35;
-            } else {
-                if (yych <= 0xC1) goto basic_json_parser_32;
-                if (yych <= 0xDF) goto basic_json_parser_36;
-                goto basic_json_parser_37;
-            }
-        } else {
-            if (yych <= 0xEF) {
-                if (yych == 0xED) goto basic_json_parser_39;
-                goto basic_json_parser_38;
-            } else {
-                if (yych <= 0xF0) goto basic_json_parser_40;
-                if (yych <= 0xF3) goto basic_json_parser_41;
-                if (yych <= 0xF4) goto basic_json_parser_42;
-            }
-        }
-basic_json_parser_32:
-        m_cursor = m_marker;
-        if (yyaccept == 0) {
-            goto basic_json_parser_5;
-        } else {
-            goto basic_json_parser_14;
-        }
-basic_json_parser_33:
-        ++m_cursor;
-        { last_token_type = token_type::value_string; break; }
-basic_json_parser_35:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 'e') {
-            if (yych <= '/') {
-                if (yych == '"') goto basic_json_parser_30;
-                if (yych <= '.') goto basic_json_parser_32;
-                goto basic_json_parser_30;
-            } else {
-                if (yych <= '\\') {
-                    if (yych <= '[') goto basic_json_parser_32;
-                    goto basic_json_parser_30;
-                } else {
-                    if (yych == 'b') goto basic_json_parser_30;
-                    goto basic_json_parser_32;
-                }
-            }
-        } else {
-            if (yych <= 'q') {
-                if (yych <= 'f') goto basic_json_parser_30;
-                if (yych == 'n') goto basic_json_parser_30;
-                goto basic_json_parser_32;
-            } else {
-                if (yych <= 's') {
-                    if (yych <= 'r') goto basic_json_parser_30;
-                    goto basic_json_parser_32;
-                } else {
-                    if (yych <= 't') goto basic_json_parser_30;
-                    if (yych <= 'u') goto basic_json_parser_48;
-                    goto basic_json_parser_32;
-                }
-            }
-        }
-basic_json_parser_36:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x7F) goto basic_json_parser_32;
-        if (yych <= 0xBF) goto basic_json_parser_30;
-        goto basic_json_parser_32;
-basic_json_parser_37:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x9F) goto basic_json_parser_32;
-        if (yych <= 0xBF) goto basic_json_parser_36;
-        goto basic_json_parser_32;
-basic_json_parser_38:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x7F) goto basic_json_parser_32;
-        if (yych <= 0xBF) goto basic_json_parser_36;
-        goto basic_json_parser_32;
-basic_json_parser_39:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x7F) goto basic_json_parser_32;
-        if (yych <= 0x9F) goto basic_json_parser_36;
-        goto basic_json_parser_32;
-basic_json_parser_40:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x8F) goto basic_json_parser_32;
-        if (yych <= 0xBF) goto basic_json_parser_38;
-        goto basic_json_parser_32;
-basic_json_parser_41:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x7F) goto basic_json_parser_32;
-        if (yych <= 0xBF) goto basic_json_parser_38;
-        goto basic_json_parser_32;
-basic_json_parser_42:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 0x7F) goto basic_json_parser_32;
-        if (yych <= 0x8F) goto basic_json_parser_38;
-        goto basic_json_parser_32;
-basic_json_parser_43:
-        yych = *++m_cursor;
-        if (yych <= '/') goto basic_json_parser_32;
-        if (yych <= '9') goto basic_json_parser_49;
-        goto basic_json_parser_32;
-basic_json_parser_44:
-        yych = *++m_cursor;
-        if (yych <= ',') {
-            if (yych == '+') goto basic_json_parser_51;
-            goto basic_json_parser_32;
-        } else {
-            if (yych <= '-') goto basic_json_parser_51;
-            if (yych <= '/') goto basic_json_parser_32;
-            if (yych <= '9') goto basic_json_parser_52;
-            goto basic_json_parser_32;
-        }
-basic_json_parser_45:
-        yych = *++m_cursor;
-        if (yych == 'l') goto basic_json_parser_54;
-        goto basic_json_parser_32;
-basic_json_parser_46:
-        yych = *++m_cursor;
-        if (yych == 'l') goto basic_json_parser_55;
-        goto basic_json_parser_32;
-basic_json_parser_47:
-        yych = *++m_cursor;
-        if (yych == 'u') goto basic_json_parser_56;
-        goto basic_json_parser_32;
-basic_json_parser_48:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= '@') {
-            if (yych <= '/') goto basic_json_parser_32;
-            if (yych <= '9') goto basic_json_parser_57;
-            goto basic_json_parser_32;
-        } else {
-            if (yych <= 'F') goto basic_json_parser_57;
-            if (yych <= '`') goto basic_json_parser_32;
-            if (yych <= 'f') goto basic_json_parser_57;
-            goto basic_json_parser_32;
-        }
-basic_json_parser_49:
-        yyaccept = 1;
-        m_marker = ++m_cursor;
-        if ((m_limit - m_cursor) < 3) fill_line_buffer(3); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= 'D') {
-            if (yych <= '/') goto basic_json_parser_14;
-            if (yych <= '9') goto basic_json_parser_49;
-            goto basic_json_parser_14;
-        } else {
-            if (yych <= 'E') goto basic_json_parser_44;
-            if (yych == 'e') goto basic_json_parser_44;
-            goto basic_json_parser_14;
-        }
-basic_json_parser_51:
-        yych = *++m_cursor;
-        if (yych <= '/') goto basic_json_parser_32;
-        if (yych >= ':') goto basic_json_parser_32;
-basic_json_parser_52:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= '/') goto basic_json_parser_14;
-        if (yych <= '9') goto basic_json_parser_52;
-        goto basic_json_parser_14;
-basic_json_parser_54:
-        yych = *++m_cursor;
-        if (yych == 's') goto basic_json_parser_58;
-        goto basic_json_parser_32;
-basic_json_parser_55:
-        yych = *++m_cursor;
-        if (yych == 'l') goto basic_json_parser_59;
-        goto basic_json_parser_32;
-basic_json_parser_56:
-        yych = *++m_cursor;
-        if (yych == 'e') goto basic_json_parser_61;
-        goto basic_json_parser_32;
-basic_json_parser_57:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= '@') {
-            if (yych <= '/') goto basic_json_parser_32;
-            if (yych <= '9') goto basic_json_parser_63;
-            goto basic_json_parser_32;
-        } else {
-            if (yych <= 'F') goto basic_json_parser_63;
-            if (yych <= '`') goto basic_json_parser_32;
-            if (yych <= 'f') goto basic_json_parser_63;
-            goto basic_json_parser_32;
-        }
-basic_json_parser_58:
-        yych = *++m_cursor;
-        if (yych == 'e') goto basic_json_parser_64;
-        goto basic_json_parser_32;
-basic_json_parser_59:
-        ++m_cursor;
-        { last_token_type = token_type::literal_null; break; }
-basic_json_parser_61:
-        ++m_cursor;
-        { last_token_type = token_type::literal_true; break; }
-basic_json_parser_63:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= '@') {
-            if (yych <= '/') goto basic_json_parser_32;
-            if (yych <= '9') goto basic_json_parser_66;
-            goto basic_json_parser_32;
-        } else {
-            if (yych <= 'F') goto basic_json_parser_66;
-            if (yych <= '`') goto basic_json_parser_32;
-            if (yych <= 'f') goto basic_json_parser_66;
-            goto basic_json_parser_32;
-        }
-basic_json_parser_64:
-        ++m_cursor;
-        { last_token_type = token_type::literal_false; break; }
-basic_json_parser_66:
-        ++m_cursor;
-        if (m_limit <= m_cursor) fill_line_buffer(1); // LCOV_EXCL_LINE
-        yych = *m_cursor;
-        if (yych <= '@') {
-            if (yych <= '/') goto basic_json_parser_32;
-            if (yych <= '9') goto basic_json_parser_30;
-            goto basic_json_parser_32;
-        } else {
-            if (yych <= 'F') goto basic_json_parser_30;
-            if (yych <= '`') goto basic_json_parser_32;
-            if (yych <= 'f') goto basic_json_parser_30;
-            goto basic_json_parser_32;
-        }
-    }
 
-        }
+        /// the char type to use in the lexer
+        using lexer_char_t = unsigned char;
 
-        return last_token_type;
-    }
-
-    /*!
-    @brief append data from the stream to the line buffer
-
-    This function is called by the scan() function when the end of the
-    buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
-    incremented without leaving the limits of the line buffer. Note re2c
-    decides when to call this function.
-
-    If the lexer reads from contiguous storage, there is no trailing null
-    byte. Therefore, this function must make sure to add these padding
-    null bytes.
-
-    If the lexer reads from an input stream, this function reads the next
-    line of the input.
-
-    @pre
-        p p p p p p u u u u u x . . . . . .
-        ^           ^       ^   ^
-        m_content   m_start |   m_limit
-                            m_cursor
-
-    @post
-        u u u u u x x x x x x x . . . . . .
-        ^       ^               ^
-        |       m_cursor        m_limit
-        m_start
-        m_content
-    */
-    void fill_line_buffer(size_t n = 0)
-    {
-        // if line buffer is used, m_content points to its data
-        assert(m_line_buffer.empty()
-               or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
-
-        // if line buffer is used, m_limit is set past the end of its data
-        assert(m_line_buffer.empty()
-               or m_limit == m_content + m_line_buffer.size());
-
-        // pointer relationships
-        assert(m_content <= m_start);
-        assert(m_start <= m_cursor);
-        assert(m_cursor <= m_limit);
-        assert(m_marker == nullptr or m_marker  <= m_limit);
-
-        // number of processed characters (p)
-            const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
-        // offset for m_marker wrt. to m_start
-        const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
-        // number of unprocessed characters (u)
-        const auto offset_cursor = m_cursor - m_start;
-
-        // no stream is used or end of file is reached
-        if (m_stream == nullptr or m_stream->eof())
+        /// a lexer from a buffer with given length
+        lexer(const lexer_char_t* buff, const size_t len) noexcept
+            : m_content(buff)
         {
-            // m_start may or may not be pointing into m_line_buffer at
-            // this point. We trust the standand library to do the right
-            // thing. See http://stackoverflow.com/q/28142011/266378
-            m_line_buffer.assign(m_start, m_limit);
+            assert(m_content != nullptr);
+            m_start = m_cursor = m_content;
+            m_limit = m_content + len;
+        }
 
-            // append n characters to make sure that there is sufficient
-            // space between m_cursor and m_limit
-            m_line_buffer.append(1, '\x00');
-            if (n > 0)
+        /// a lexer from an input stream
+        explicit lexer(std::istream& s)
+            : m_stream(&s), m_line_buffer()
+        {
+            // immediately abort if stream is erroneous
+            if (s.fail())
             {
-                m_line_buffer.append(n - 1, '\x01');
+                JSON_THROW(std::invalid_argument("stream error"));
+            }
+
+            // fill buffer
+            fill_line_buffer();
+
+            // skip UTF-8 byte-order mark
+            if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
+            {
+                m_line_buffer[0] = ' ';
+                m_line_buffer[1] = ' ';
+                m_line_buffer[2] = ' ';
             }
         }
-        else
+
+        // switch off unwanted functions (due to pointer members)
+        lexer() = delete;
+        lexer(const lexer&) = delete;
+        lexer operator=(const lexer&) = delete;
+
+        /*!
+        @brief create a string from one or two Unicode code points
+
+        There are two cases: (1) @a codepoint1 is in the Basic Multilingual
+        Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
+        @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
+        represent a code point above U+FFFF.
+
+        @param[in] codepoint1  the code point (can be high surrogate)
+        @param[in] codepoint2  the code point (can be low surrogate or 0)
+
+        @return string representation of the code point; the length of the
+        result string is between 1 and 4 characters.
+
+        @throw std::out_of_range if code point is > 0x10ffff; example: `"code
+        points above 0x10FFFF are invalid"`
+        @throw std::invalid_argument if the low surrogate is invalid; example:
+        `""missing or wrong low surrogate""`
+
+        @complexity Constant.
+
+        @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
+        */
+        static string_t to_unicode(const std::size_t codepoint1,
+                                   const std::size_t codepoint2 = 0)
         {
-            // delete processed characters from line buffer
-            m_line_buffer.erase(0, num_processed_chars);
-            // read next line from input stream
-            m_line_buffer_tmp.clear();
-            std::getline(*m_stream, m_line_buffer_tmp, '\n');
+            // calculate the code point from the given code points
+            std::size_t codepoint = codepoint1;
 
-            // add line with newline symbol to the line buffer
-            m_line_buffer += m_line_buffer_tmp;
-            m_line_buffer.push_back('\n');
-        }
-
-        // set pointers
-        m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
-        assert(m_content != nullptr);
-        m_start  = m_content;
-        m_marker = m_start + offset_marker;
-        m_cursor = m_start + offset_cursor;
-        m_limit  = m_start + m_line_buffer.size();
-    }
-
-    /// return string representation of last read token
-    string_t get_token_string() const
-    {
-        assert(m_start != nullptr);
-        return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
-                        static_cast<size_t>(m_cursor - m_start));
-    }
-
-    /*!
-    @brief return string value for string tokens
-
-    The function iterates the characters between the opening and closing
-    quotes of the string value. The complete string is the range
-    [m_start,m_cursor). Consequently, we iterate from m_start+1 to
-    m_cursor-1.
-
-    We differentiate two cases:
-
-    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., `"\\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.
-
-    @pre `m_cursor - m_start >= 2`, meaning the length of the last token
-    is at least 2 bytes which is trivially true for any string (which
-    consists of at least two quotes).
-
-        " c1 c2 c3 ... "
-        ^                ^
-        m_start          m_cursor
-
-    @complexity Linear in the length of the string.\n
-
-    Lemma: The loop body will always terminate.\n
-
-    Proof (by contradiction): Assume the loop body does not terminate. As
-    the loop body does not contain another loop, one of the called
-    functions must never return. The called functions are `std::strtoul`
-    and to_unicode. Neither function can loop forever, so the loop body
-    will never loop forever which contradicts the assumption that the loop
-    body does not terminate, q.e.d.\n
-
-    Lemma: The loop condition for the for loop is eventually false.\n
-
-    Proof (by contradiction): Assume the loop does not terminate. Due to
-    the above lemma, this can only be due to a tautological loop
-    condition; that is, the loop condition i < m_cursor - 1 must always be
-    true. Let x be the change of i for any loop iteration. Then
-    m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
-    can be rephrased to m_cursor - m_start - 2 > x. With the
-    precondition, we x <= 0, meaning that the loop condition holds
-    indefinitly if i is always decreased. However, observe that the value
-    of i is strictly increasing with each iteration, as it is incremented
-    by 1 in the iteration expression and never decremented inside the loop
-    body. Hence, the loop condition will eventually be false which
-    contradicts the assumption that the loop condition is a tautology,
-    q.e.d.
-
-    @return string value of current token without opening and closing
-    quotes
-    @throw std::out_of_range if to_unicode fails
-    */
-    string_t get_string() const
-    {
-        assert(m_cursor - m_start >= 2);
-
-        string_t result;
-        result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
-
-        // iterate the result between the quotes
-        for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
-        {
-            // find next escape character
-            auto e = std::find(i, m_cursor - 1, '\\');
-            if (e != i)
+            // check if codepoint1 is a high surrogate
+            if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
             {
-                // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
-                for (auto k = i; k < e; k++)
+                // check if codepoint2 is a low surrogate
+                if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
                 {
-                    result.push_back(static_cast<typename string_t::value_type>(*k));
-                }
-                i = e - 1; // -1 because of ++i
-            }
-            else
-            {
-                // processing escaped character
-                // read next character
-                ++i;
-
-                switch (*i)
-                {
-                    // the default escapes
-                    case 't':
-                    {
-                        result += "\t";
-                        break;
-                    }
-                    case 'b':
-                    {
-                        result += "\b";
-                        break;
-                    }
-                    case 'f':
-                    {
-                        result += "\f";
-                        break;
-                    }
-                    case 'n':
-                    {
-                        result += "\n";
-                        break;
-                    }
-                    case 'r':
-                    {
-                        result += "\r";
-                        break;
-                    }
-                    case '\\':
-                    {
-                        result += "\\";
-                        break;
-                    }
-                    case '/':
-                    {
-                        result += "/";
-                        break;
-                    }
-                    case '"':
-                    {
-                        result += "\"";
-                        break;
-                    }
-
-                    // unicode
-                    case 'u':
-                    {
-                        // get code xxxx from uxxxx
-                        auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
-                                                      4).c_str(), nullptr, 16);
-
-                        // check if codepoint is a high surrogate
-                        if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
-                        {
-                            // make sure there is a subsequent unicode
-                            if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
-                            {
-                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
-                            }
-
-                            // get code yyyy from uxxxx\uyyyy
-                            auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
-                                                           (i + 7), 4).c_str(), nullptr, 16);
-                            result += to_unicode(codepoint, codepoint2);
-                            // skip the next 10 characters (xxxx\uyyyy)
-                            i += 10;
-                        }
-                        else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
-                        {
-                            // we found a lone low surrogate
-                                JSON_THROW(std::invalid_argument("missing high surrogate"));
-                        }
-                        else
-                        {
-                            // add unicode character(s)
-                            result += to_unicode(codepoint);
-                            // skip the next four characters (xxxx)
-                            i += 4;
-                        }
-                        break;
-                    }
-                }
-            }
-        }
-
-        return result;
-    }
-
-    /*!
-    @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,out] endptr recieves a pointer to the first character after
-    the number
-
-    @return the floating point number
-    */
-    long double str_to_float_t(long double* /* type */, char** endptr) const
-    {
-        return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
-    }
-
-    /*!
-    @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,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);
-    }
-
-    /*!
-    @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,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);
-    }
-
-    /*!
-    @brief return number value for number tokens
-
-    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.
-
-    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.
-    */
-    void get_number(basic_json& result) const
-    {
-        assert(m_start != nullptr);
-
-        const lexer::lexer_char_t* curptr = m_start;
-
-        // 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;
-                    continue;
-                }
-                // assume exponent (if not then will fail parse): change to
-                // float, stop counting and record exponent details
-                type = value_t::number_float;
-                break;
-            }
-
-            // skip if definitely not an integer
-            if (type != value_t::number_float)
-            {
-                auto digit = static_cast<number_unsigned_t>(*curptr - '0');
-
-                // overflow if value * 10 + digit > max, move terms around
-                // to avoid overflow in intermediate values
-                if (value > (max - digit) / 10)
-                {
-                    // overflow
-                    type = value_t::number_float;
+                    codepoint =
+                        // high surrogate occupies the most significant 22 bits
+                        (codepoint1 << 10)
+                        // low surrogate occupies the least significant 15 bits
+                        + codepoint2
+                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
+                        // in the result so we have to subtract with:
+                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
+                        - 0x35FDC00;
                 }
                 else
                 {
-                    // no overflow
-                    value = value * 10 + digit;
+                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
+                }
+            }
+
+            string_t result;
+
+            if (codepoint < 0x80)
+            {
+                // 1-byte characters: 0xxxxxxx (ASCII)
+                result.append(1, static_cast<typename string_t::value_type>(codepoint));
+            }
+            else if (codepoint <= 0x7ff)
+            {
+                // 2-byte characters: 110xxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else if (codepoint <= 0xffff)
+            {
+                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else if (codepoint <= 0x10ffff)
+            {
+                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else
+            {
+                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
+            }
+
+            return result;
+        }
+
+        /// return name of values of type token_type (only used for errors)
+        static std::string token_type_name(const token_type t)
+        {
+            switch (t)
+            {
+                case token_type::uninitialized:
+                    return "<uninitialized>";
+                case token_type::literal_true:
+                    return "true literal";
+                case token_type::literal_false:
+                    return "false literal";
+                case token_type::literal_null:
+                    return "null literal";
+                case token_type::value_string:
+                    return "string literal";
+                case token_type::value_number:
+                    return "number literal";
+                case token_type::begin_array:
+                    return "'['";
+                case token_type::begin_object:
+                    return "'{'";
+                case token_type::end_array:
+                    return "']'";
+                case token_type::end_object:
+                    return "'}'";
+                case token_type::name_separator:
+                    return "':'";
+                case token_type::value_separator:
+                    return "','";
+                case token_type::parse_error:
+                    return "<parse error>";
+                case token_type::end_of_input:
+                    return "end of input";
+                default:
+                {
+                    // catch non-enum values
+                    return "unknown token"; // LCOV_EXCL_LINE
                 }
             }
         }
 
-        // 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)
-        {
-            // invariant: if we parsed a '-', the absolute value is between
-            // 0 (we allow -0) and max == -INT64_MIN
-            assert(value >= 0);
-            assert(value <= max);
+        /*!
+        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 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.
 
-            if (value == max)
+        @return the class of the next token read from the buffer
+
+        @complexity Linear in the length of the input.\n
+
+        Proposition: The loop below will always terminate for finite input.\n
+
+        Proof (by contradiction): Assume a finite input. To loop forever, the
+        loop must never hit code with a `break` statement. The only code
+        snippets without a `break` statement are the continue statements for
+        whitespace and byte-order-marks. To loop forever, the input must be an
+        infinite sequence of whitespace or byte-order-marks. This contradicts
+        the assumption of finite input, q.e.d.
+        */
+        token_type scan()
+        {
+            while (true)
             {
-                // we cannot simply negate value (== max == -INT64_MIN),
-                // see https://github.com/nlohmann/json/issues/389
-                result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
+                // pointer for backtracking information
+                m_marker = nullptr;
+
+                // remember the begin of the token
+                m_start = m_cursor;
+                assert(m_start != nullptr);
+
+
+                {
+                    lexer_char_t yych;
+                    unsigned int yyaccept = 0;
+                    static const unsigned char yybm[] =
+                    {
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,  32,  32,   0,   0,  32,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        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, 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,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                    };
+                    if ((m_limit - m_cursor) < 5)
+                    {
+                        fill_line_buffer(5);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yybm[0 + yych] & 32)
+                    {
+                        goto basic_json_parser_6;
+                    }
+                    if (yych <= '[')
+                    {
+                        if (yych <= '-')
+                        {
+                            if (yych <= '"')
+                            {
+                                if (yych <= 0x00)
+                                {
+                                    goto basic_json_parser_2;
+                                }
+                                if (yych <= '!')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                goto basic_json_parser_9;
+                            }
+                            else
+                            {
+                                if (yych <= '+')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                if (yych <= ',')
+                                {
+                                    goto basic_json_parser_10;
+                                }
+                                goto basic_json_parser_12;
+                            }
+                        }
+                        else
+                        {
+                            if (yych <= '9')
+                            {
+                                if (yych <= '/')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                if (yych <= '0')
+                                {
+                                    goto basic_json_parser_13;
+                                }
+                                goto basic_json_parser_15;
+                            }
+                            else
+                            {
+                                if (yych <= ':')
+                                {
+                                    goto basic_json_parser_17;
+                                }
+                                if (yych <= 'Z')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                goto basic_json_parser_19;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 'n')
+                        {
+                            if (yych <= 'e')
+                            {
+                                if (yych == ']')
+                                {
+                                    goto basic_json_parser_21;
+                                }
+                                goto basic_json_parser_4;
+                            }
+                            else
+                            {
+                                if (yych <= 'f')
+                                {
+                                    goto basic_json_parser_23;
+                                }
+                                if (yych <= 'm')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                goto basic_json_parser_24;
+                            }
+                        }
+                        else
+                        {
+                            if (yych <= 'z')
+                            {
+                                if (yych == 't')
+                                {
+                                    goto basic_json_parser_25;
+                                }
+                                goto basic_json_parser_4;
+                            }
+                            else
+                            {
+                                if (yych <= '{')
+                                {
+                                    goto basic_json_parser_26;
+                                }
+                                if (yych == '}')
+                                {
+                                    goto basic_json_parser_28;
+                                }
+                                goto basic_json_parser_4;
+                            }
+                        }
+                    }
+basic_json_parser_2:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::end_of_input;
+                        break;
+                    }
+basic_json_parser_4:
+                    ++m_cursor;
+basic_json_parser_5:
+                    {
+                        last_token_type = token_type::parse_error;
+                        break;
+                    }
+basic_json_parser_6:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yybm[0 + yych] & 32)
+                    {
+                        goto basic_json_parser_6;
+                    }
+                    {
+                        continue;
+                    }
+basic_json_parser_9:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych <= 0x1F)
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_31;
+                    }
+                    if (yych <= 0xC1)
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    if (yych <= 0xF4)
+                    {
+                        goto basic_json_parser_31;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_10:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::value_separator;
+                        break;
+                    }
+basic_json_parser_12:
+                    yych = *++m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    if (yych <= '0')
+                    {
+                        goto basic_json_parser_13;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_15;
+                    }
+                    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;
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 'E')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        if (yych == 'e')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                    }
+basic_json_parser_14:
+                    {
+                        last_token_type = token_type::value_number;
+                        break;
+                    }
+basic_json_parser_15:
+                    yyaccept = 1;
+                    m_marker = ++m_cursor;
+                    if ((m_limit - m_cursor) < 3)
+                    {
+                        fill_line_buffer(3);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yybm[0 + yych] & 64)
+                    {
+                        goto basic_json_parser_15;
+                    }
+                    if (yych <= 'D')
+                    {
+                        if (yych == '.')
+                        {
+                            goto basic_json_parser_43;
+                        }
+                        goto basic_json_parser_14;
+                    }
+                    else
+                    {
+                        if (yych <= 'E')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        if (yych == 'e')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        goto basic_json_parser_14;
+                    }
+basic_json_parser_17:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::name_separator;
+                        break;
+                    }
+basic_json_parser_19:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::begin_array;
+                        break;
+                    }
+basic_json_parser_21:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::end_array;
+                        break;
+                    }
+basic_json_parser_23:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych == 'a')
+                    {
+                        goto basic_json_parser_45;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_24:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych == 'u')
+                    {
+                        goto basic_json_parser_46;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_25:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych == 'r')
+                    {
+                        goto basic_json_parser_47;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_26:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::begin_object;
+                        break;
+                    }
+basic_json_parser_28:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::end_object;
+                        break;
+                    }
+basic_json_parser_30:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+basic_json_parser_31:
+                    if (yybm[0 + yych] & 128)
+                    {
+                        goto basic_json_parser_30;
+                    }
+                    if (yych <= 0xE0)
+                    {
+                        if (yych <= '\\')
+                        {
+                            if (yych <= 0x1F)
+                            {
+                                goto basic_json_parser_32;
+                            }
+                            if (yych <= '"')
+                            {
+                                goto basic_json_parser_33;
+                            }
+                            goto basic_json_parser_35;
+                        }
+                        else
+                        {
+                            if (yych <= 0xC1)
+                            {
+                                goto basic_json_parser_32;
+                            }
+                            if (yych <= 0xDF)
+                            {
+                                goto basic_json_parser_36;
+                            }
+                            goto basic_json_parser_37;
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 0xEF)
+                        {
+                            if (yych == 0xED)
+                            {
+                                goto basic_json_parser_39;
+                            }
+                            goto basic_json_parser_38;
+                        }
+                        else
+                        {
+                            if (yych <= 0xF0)
+                            {
+                                goto basic_json_parser_40;
+                            }
+                            if (yych <= 0xF3)
+                            {
+                                goto basic_json_parser_41;
+                            }
+                            if (yych <= 0xF4)
+                            {
+                                goto basic_json_parser_42;
+                            }
+                        }
+                    }
+basic_json_parser_32:
+                    m_cursor = m_marker;
+                    if (yyaccept == 0)
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    else
+                    {
+                        goto basic_json_parser_14;
+                    }
+basic_json_parser_33:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::value_string;
+                        break;
+                    }
+basic_json_parser_35:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 'e')
+                    {
+                        if (yych <= '/')
+                        {
+                            if (yych == '"')
+                            {
+                                goto basic_json_parser_30;
+                            }
+                            if (yych <= '.')
+                            {
+                                goto basic_json_parser_32;
+                            }
+                            goto basic_json_parser_30;
+                        }
+                        else
+                        {
+                            if (yych <= '\\')
+                            {
+                                if (yych <= '[')
+                                {
+                                    goto basic_json_parser_32;
+                                }
+                                goto basic_json_parser_30;
+                            }
+                            else
+                            {
+                                if (yych == 'b')
+                                {
+                                    goto basic_json_parser_30;
+                                }
+                                goto basic_json_parser_32;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 'q')
+                        {
+                            if (yych <= 'f')
+                            {
+                                goto basic_json_parser_30;
+                            }
+                            if (yych == 'n')
+                            {
+                                goto basic_json_parser_30;
+                            }
+                            goto basic_json_parser_32;
+                        }
+                        else
+                        {
+                            if (yych <= 's')
+                            {
+                                if (yych <= 'r')
+                                {
+                                    goto basic_json_parser_30;
+                                }
+                                goto basic_json_parser_32;
+                            }
+                            else
+                            {
+                                if (yych <= 't')
+                                {
+                                    goto basic_json_parser_30;
+                                }
+                                if (yych <= 'u')
+                                {
+                                    goto basic_json_parser_48;
+                                }
+                                goto basic_json_parser_32;
+                            }
+                        }
+                    }
+basic_json_parser_36:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_30;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_37:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x9F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_36;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_38:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_36;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_39:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0x9F)
+                    {
+                        goto basic_json_parser_36;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_40:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x8F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_41:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_42:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0x8F)
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_43:
+                    yych = *++m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_49;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_44:
+                    yych = *++m_cursor;
+                    if (yych <= ',')
+                    {
+                        if (yych == '+')
+                        {
+                            goto basic_json_parser_51;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= '-')
+                        {
+                            goto basic_json_parser_51;
+                        }
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_52;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_45:
+                    yych = *++m_cursor;
+                    if (yych == 'l')
+                    {
+                        goto basic_json_parser_54;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_46:
+                    yych = *++m_cursor;
+                    if (yych == 'l')
+                    {
+                        goto basic_json_parser_55;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_47:
+                    yych = *++m_cursor;
+                    if (yych == 'u')
+                    {
+                        goto basic_json_parser_56;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_48:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_57;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_57;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_57;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_49:
+                    yyaccept = 1;
+                    m_marker = ++m_cursor;
+                    if ((m_limit - m_cursor) < 3)
+                    {
+                        fill_line_buffer(3);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 'D')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_14;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_49;
+                        }
+                        goto basic_json_parser_14;
+                    }
+                    else
+                    {
+                        if (yych <= 'E')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        if (yych == 'e')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        goto basic_json_parser_14;
+                    }
+basic_json_parser_51:
+                    yych = *++m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych >= ':')
+                    {
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_52:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_14;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_52;
+                    }
+                    goto basic_json_parser_14;
+basic_json_parser_54:
+                    yych = *++m_cursor;
+                    if (yych == 's')
+                    {
+                        goto basic_json_parser_58;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_55:
+                    yych = *++m_cursor;
+                    if (yych == 'l')
+                    {
+                        goto basic_json_parser_59;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_56:
+                    yych = *++m_cursor;
+                    if (yych == 'e')
+                    {
+                        goto basic_json_parser_61;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_57:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_63;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_63;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_63;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_58:
+                    yych = *++m_cursor;
+                    if (yych == 'e')
+                    {
+                        goto basic_json_parser_64;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_59:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::literal_null;
+                        break;
+                    }
+basic_json_parser_61:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::literal_true;
+                        break;
+                    }
+basic_json_parser_63:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_66;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_66;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_66;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_64:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::literal_false;
+                        break;
+                    }
+basic_json_parser_66:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_30;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_30;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_30;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                }
+
+            }
+
+            return last_token_type;
+        }
+
+        /*!
+        @brief append data from the stream to the line buffer
+
+        This function is called by the scan() function when the end of the
+        buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
+        incremented without leaving the limits of the line buffer. Note re2c
+        decides when to call this function.
+
+        If the lexer reads from contiguous storage, there is no trailing null
+        byte. Therefore, this function must make sure to add these padding
+        null bytes.
+
+        If the lexer reads from an input stream, this function reads the next
+        line of the input.
+
+        @pre
+            p p p p p p u u u u u x . . . . . .
+            ^           ^       ^   ^
+            m_content   m_start |   m_limit
+                                m_cursor
+
+        @post
+            u u u u u x x x x x x x . . . . . .
+            ^       ^               ^
+            |       m_cursor        m_limit
+            m_start
+            m_content
+        */
+        void fill_line_buffer(size_t n = 0)
+        {
+            // if line buffer is used, m_content points to its data
+            assert(m_line_buffer.empty()
+                   or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
+
+            // if line buffer is used, m_limit is set past the end of its data
+            assert(m_line_buffer.empty()
+                   or m_limit == m_content + m_line_buffer.size());
+
+            // pointer relationships
+            assert(m_content <= m_start);
+            assert(m_start <= m_cursor);
+            assert(m_cursor <= m_limit);
+            assert(m_marker == nullptr or m_marker  <= m_limit);
+
+            // number of processed characters (p)
+            const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
+            // offset for m_marker wrt. to m_start
+            const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
+            // number of unprocessed characters (u)
+            const auto offset_cursor = m_cursor - m_start;
+
+            // no stream is used or end of file is reached
+            if (m_stream == nullptr or m_stream->eof())
+            {
+                // m_start may or may not be pointing into m_line_buffer at
+                // this point. We trust the standand library to do the right
+                // thing. See http://stackoverflow.com/q/28142011/266378
+                m_line_buffer.assign(m_start, m_limit);
+
+                // append n characters to make sure that there is sufficient
+                // space between m_cursor and m_limit
+                m_line_buffer.append(1, '\x00');
+                if (n > 0)
+                {
+                    m_line_buffer.append(n - 1, '\x01');
+                }
             }
             else
             {
-                // all other values can be negated safely
-                result.m_value.number_integer = -static_cast<number_integer_t>(value);
+                // delete processed characters from line buffer
+                m_line_buffer.erase(0, num_processed_chars);
+                // read next line from input stream
+                m_line_buffer_tmp.clear();
+                std::getline(*m_stream, m_line_buffer_tmp, '\n');
+
+                // add line with newline symbol to the line buffer
+                m_line_buffer += m_line_buffer_tmp;
+                m_line_buffer.push_back('\n');
             }
+
+            // set pointers
+            m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
+            assert(m_content != nullptr);
+            m_start  = m_content;
+            m_marker = m_start + offset_marker;
+            m_cursor = m_start + offset_cursor;
+            m_limit  = m_start + m_line_buffer.size();
         }
-        else
+
+        /// return string representation of last read token
+        string_t get_token_string() const
         {
-            // parse with strtod
+            assert(m_start != nullptr);
+            return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
+                            static_cast<size_t>(m_cursor - m_start));
+        }
+
+        /*!
+        @brief return string value for string tokens
+
+        The function iterates the characters between the opening and closing
+        quotes of the string value. The complete string is the range
+        [m_start,m_cursor). Consequently, we iterate from m_start+1 to
+        m_cursor-1.
+
+        We differentiate two cases:
+
+        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., `"\\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.
+
+        @pre `m_cursor - m_start >= 2`, meaning the length of the last token
+        is at least 2 bytes which is trivially true for any string (which
+        consists of at least two quotes).
+
+            " c1 c2 c3 ... "
+            ^                ^
+            m_start          m_cursor
+
+        @complexity Linear in the length of the string.\n
+
+        Lemma: The loop body will always terminate.\n
+
+        Proof (by contradiction): Assume the loop body does not terminate. As
+        the loop body does not contain another loop, one of the called
+        functions must never return. The called functions are `std::strtoul`
+        and to_unicode. Neither function can loop forever, so the loop body
+        will never loop forever which contradicts the assumption that the loop
+        body does not terminate, q.e.d.\n
+
+        Lemma: The loop condition for the for loop is eventually false.\n
+
+        Proof (by contradiction): Assume the loop does not terminate. Due to
+        the above lemma, this can only be due to a tautological loop
+        condition; that is, the loop condition i < m_cursor - 1 must always be
+        true. Let x be the change of i for any loop iteration. Then
+        m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
+        can be rephrased to m_cursor - m_start - 2 > x. With the
+        precondition, we x <= 0, meaning that the loop condition holds
+        indefinitly if i is always decreased. However, observe that the value
+        of i is strictly increasing with each iteration, as it is incremented
+        by 1 in the iteration expression and never decremented inside the loop
+        body. Hence, the loop condition will eventually be false which
+        contradicts the assumption that the loop condition is a tautology,
+        q.e.d.
+
+        @return string value of current token without opening and closing
+        quotes
+        @throw std::out_of_range if to_unicode fails
+        */
+        string_t get_string() const
+        {
+            assert(m_cursor - m_start >= 2);
+
+            string_t result;
+            result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
+
+            // iterate the result between the quotes
+            for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
+            {
+                // find next escape character
+                auto e = std::find(i, m_cursor - 1, '\\');
+                if (e != i)
+                {
+                    // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
+                    for (auto k = i; k < e; k++)
+                    {
+                        result.push_back(static_cast<typename string_t::value_type>(*k));
+                    }
+                    i = e - 1; // -1 because of ++i
+                }
+                else
+                {
+                    // processing escaped character
+                    // read next character
+                    ++i;
+
+                    switch (*i)
+                    {
+                        // the default escapes
+                        case 't':
+                        {
+                            result += "\t";
+                            break;
+                        }
+                        case 'b':
+                        {
+                            result += "\b";
+                            break;
+                        }
+                        case 'f':
+                        {
+                            result += "\f";
+                            break;
+                        }
+                        case 'n':
+                        {
+                            result += "\n";
+                            break;
+                        }
+                        case 'r':
+                        {
+                            result += "\r";
+                            break;
+                        }
+                        case '\\':
+                        {
+                            result += "\\";
+                            break;
+                        }
+                        case '/':
+                        {
+                            result += "/";
+                            break;
+                        }
+                        case '"':
+                        {
+                            result += "\"";
+                            break;
+                        }
+
+                        // unicode
+                        case 'u':
+                        {
+                            // get code xxxx from uxxxx
+                            auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
+                                                          4).c_str(), nullptr, 16);
+
+                            // check if codepoint is a high surrogate
+                            if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
+                            {
+                                // make sure there is a subsequent unicode
+                                if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
+                                {
+                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
+                                }
+
+                                // get code yyyy from uxxxx\uyyyy
+                                auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
+                                                               (i + 7), 4).c_str(), nullptr, 16);
+                                result += to_unicode(codepoint, codepoint2);
+                                // skip the next 10 characters (xxxx\uyyyy)
+                                i += 10;
+                            }
+                            else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
+                            {
+                                // we found a lone low surrogate
+                                JSON_THROW(std::invalid_argument("missing high surrogate"));
+                            }
+                            else
+                            {
+                                // add unicode character(s)
+                                result += to_unicode(codepoint);
+                                // skip the next four characters (xxxx)
+                                i += 4;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        /*!
+        @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,out] endptr recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        long double str_to_float_t(long double* /* type */, char** endptr) const
+        {
+            return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
+        }
+
+        /*!
+        @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,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);
+        }
+
+        /*!
+        @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,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);
+        }
+
+        /*!
+        @brief return number value for number tokens
+
+        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.
+
+        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.
+        */
+        void get_number(basic_json& result) const
+        {
+            assert(m_start != nullptr);
+
+            const lexer::lexer_char_t* curptr = m_start;
+
+            // 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;
+                        continue;
+                    }
+                    // assume exponent (if not then will fail parse): change to
+                    // float, stop counting and record exponent details
+                    type = value_t::number_float;
+                    break;
+                }
+
+                // skip if definitely not an integer
+                if (type != value_t::number_float)
+                {
+                    auto digit = static_cast<number_unsigned_t>(*curptr - '0');
+
+                    // overflow if value * 10 + digit > max, move terms around
+                    // to avoid overflow in intermediate values
+                    if (value > (max - digit) / 10)
+                    {
+                        // overflow
+                        type = value_t::number_float;
+                    }
+                    else
+                    {
+                        // no overflow
+                        value = value * 10 + digit;
+                    }
+                }
+            }
+
+            // 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)
+            {
+                // invariant: if we parsed a '-', the absolute value is between
+                // 0 (we allow -0) and max == -INT64_MIN
+                assert(value >= 0);
+                assert(value <= max);
+
+                if (value == max)
+                {
+                    // we cannot simply negate value (== max == -INT64_MIN),
+                    // see https://github.com/nlohmann/json/issues/389
+                    result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
+                }
+                else
+                {
+                    // all other values can be negated safely
+                    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), nullptr);
 
-            // replace infinity and NAN by null
-            if (not std::isfinite(result.m_value.number_float))
-            {
-                type = value_t::null;
-                result.m_value = basic_json::json_value();
+                // replace infinity and NAN by null
+                if (not std::isfinite(result.m_value.number_float))
+                {
+                    type = value_t::null;
+                    result.m_value = basic_json::json_value();
+                }
             }
+
+            // save the type
+            result.m_type = type;
         }
 
-        // save the type
-        result.m_type = type;
-    }
-
-    private:
-    /// optional input stream
-    std::istream* m_stream = nullptr;
-    /// line buffer buffer for m_stream
-    string_t m_line_buffer {};
-    /// used for filling m_line_buffer
-    string_t m_line_buffer_tmp {};
-    /// the buffer pointer
-    const lexer_char_t* m_content = nullptr;
-    /// pointer to the beginning of the current symbol
-    const lexer_char_t* m_start = nullptr;
-    /// pointer for backtracking information
-    const lexer_char_t* m_marker = nullptr;
-    /// pointer to the current symbol
-    const lexer_char_t* m_cursor = nullptr;
-    /// pointer to the end of the buffer
-    const lexer_char_t* m_limit = nullptr;
-    /// the last token type
-    token_type last_token_type = token_type::end_of_input;
-                                                };
+      private:
+        /// optional input stream
+        std::istream* m_stream = nullptr;
+        /// line buffer buffer for m_stream
+        string_t m_line_buffer {};
+        /// used for filling m_line_buffer
+        string_t m_line_buffer_tmp {};
+        /// the buffer pointer
+        const lexer_char_t* m_content = nullptr;
+        /// pointer to the beginning of the current symbol
+        const lexer_char_t* m_start = nullptr;
+        /// pointer for backtracking information
+        const lexer_char_t* m_marker = nullptr;
+        /// pointer to the current symbol
+        const lexer_char_t* m_cursor = nullptr;
+        /// pointer to the end of the buffer
+        const lexer_char_t* m_limit = nullptr;
+        /// the last token type
+        token_type last_token_type = token_type::end_of_input;
+    };
 
     /*!
     @brief syntax analysis
@@ -10339,282 +10856,282 @@ basic_json_parser_66:
     */
     class parser
     {
-        public:
+      public:
         /// a parser reading from a string literal
         parser(const char* buff, const parser_callback_t cb = nullptr)
-        : callback(cb),
-        m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
-    {}
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
+        {}
 
-    /// a parser reading from an input stream
-    parser(std::istream& is, const parser_callback_t cb = nullptr)
-    : callback(cb), m_lexer(is)
-    {}
+        /// a parser reading from an input stream
+        parser(std::istream& is, const parser_callback_t cb = nullptr)
+            : callback(cb), m_lexer(is)
+        {}
 
-    /// a parser reading from an iterator range with contiguous storage
-    template<class IteratorType, typename std::enable_if<
-                 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
-                 , int>::type
-             = 0>
-    parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
-    : callback(cb),
-    m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
-            static_cast<size_t>(std::distance(first, last)))
-    {}
+        /// a parser reading from an iterator range with contiguous storage
+        template<class IteratorType, typename std::enable_if<
+                     std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
+                     , int>::type
+                 = 0>
+        parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
+                      static_cast<size_t>(std::distance(first, last)))
+        {}
 
-    /// public parser interface
-    basic_json parse()
-    {
-        // read first token
-        get_token();
-
-        basic_json result = parse_internal(true);
-        result.assert_invariant();
-
-        expect(lexer::token_type::end_of_input);
-
-        // return parser result and replace it with null in case the
-        // top-level value was discarded by the callback function
-        return result.is_discarded() ? basic_json() : std::move(result);
-    }
-
-    private:
-    /// the actual parser
-    basic_json parse_internal(bool keep)
-    {
-        auto result = basic_json(value_t::discarded);
-
-        switch (last_token)
+        /// public parser interface
+        basic_json parse()
         {
-            case lexer::token_type::begin_object:
+            // read first token
+            get_token();
+
+            basic_json result = parse_internal(true);
+            result.assert_invariant();
+
+            expect(lexer::token_type::end_of_input);
+
+            // return parser result and replace it with null in case the
+            // top-level value was discarded by the callback function
+            return result.is_discarded() ? basic_json() : std::move(result);
+        }
+
+      private:
+        /// the actual parser
+        basic_json parse_internal(bool keep)
+        {
+            auto result = basic_json(value_t::discarded);
+
+            switch (last_token)
             {
-                if (keep and (not callback
-                              or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
+                case lexer::token_type::begin_object:
                 {
-                    // explicitly set result to object to cope with {}
-                    result.m_type = value_t::object;
-                    result.m_value = value_t::object;
-                }
+                    if (keep and (not callback
+                                  or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
+                    {
+                        // explicitly set result to object to cope with {}
+                        result.m_type = value_t::object;
+                        result.m_value = value_t::object;
+                    }
 
-                // read next token
-                get_token();
+                    // read next token
+                    get_token();
 
-                // closing } -> we are done
-                if (last_token == lexer::token_type::end_object)
-                {
+                    // closing } -> we are done
+                    if (last_token == lexer::token_type::end_object)
+                    {
+                        get_token();
+                        if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
+                        {
+                            result = basic_json(value_t::discarded);
+                        }
+                        return result;
+                    }
+
+                    // no comma is expected here
+                    unexpect(lexer::token_type::value_separator);
+
+                    // otherwise: parse key-value pairs
+                    do
+                    {
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
+
+                        // store key
+                        expect(lexer::token_type::value_string);
+                        const auto key = m_lexer.get_string();
+
+                        bool keep_tag = false;
+                        if (keep)
+                        {
+                            if (callback)
+                            {
+                                basic_json k(key);
+                                keep_tag = callback(depth, parse_event_t::key, k);
+                            }
+                            else
+                            {
+                                keep_tag = true;
+                            }
+                        }
+
+                        // parse separator (:)
+                        get_token();
+                        expect(lexer::token_type::name_separator);
+
+                        // parse and add value
+                        get_token();
+                        auto value = parse_internal(keep);
+                        if (keep and keep_tag and not value.is_discarded())
+                        {
+                            result[key] = std::move(value);
+                        }
+                    }
+                    while (last_token == lexer::token_type::value_separator);
+
+                    // closing }
+                    expect(lexer::token_type::end_object);
                     get_token();
                     if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
                     {
                         result = basic_json(value_t::discarded);
                     }
+
                     return result;
                 }
 
-                // no comma is expected here
-                unexpect(lexer::token_type::value_separator);
-
-                // otherwise: parse key-value pairs
-                do
+                case lexer::token_type::begin_array:
                 {
-                    // ugly, but could be fixed with loop reorganization
-                    if (last_token == lexer::token_type::value_separator)
+                    if (keep and (not callback
+                                  or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
+                    {
+                        // explicitly set result to object to cope with []
+                        result.m_type = value_t::array;
+                        result.m_value = value_t::array;
+                    }
+
+                    // read next token
+                    get_token();
+
+                    // closing ] -> we are done
+                    if (last_token == lexer::token_type::end_array)
                     {
                         get_token();
+                        if (callback and not callback(--depth, parse_event_t::array_end, result))
+                        {
+                            result = basic_json(value_t::discarded);
+                        }
+                        return result;
                     }
 
-                    // store key
-                    expect(lexer::token_type::value_string);
-                    const auto key = m_lexer.get_string();
+                    // no comma is expected here
+                    unexpect(lexer::token_type::value_separator);
 
-                    bool keep_tag = false;
-                    if (keep)
+                    // otherwise: parse values
+                    do
                     {
-                        if (callback)
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
                         {
-                            basic_json k(key);
-                            keep_tag = callback(depth, parse_event_t::key, k);
+                            get_token();
                         }
-                        else
+
+                        // parse value
+                        auto value = parse_internal(keep);
+                        if (keep and not value.is_discarded())
                         {
-                            keep_tag = true;
+                            result.push_back(std::move(value));
                         }
                     }
+                    while (last_token == lexer::token_type::value_separator);
 
-                    // parse separator (:)
+                    // closing ]
+                    expect(lexer::token_type::end_array);
                     get_token();
-                    expect(lexer::token_type::name_separator);
-
-                    // parse and add value
-                    get_token();
-                    auto value = parse_internal(keep);
-                    if (keep and keep_tag and not value.is_discarded())
-                    {
-                        result[key] = std::move(value);
-                    }
-                }
-                while (last_token == lexer::token_type::value_separator);
-
-                // closing }
-                expect(lexer::token_type::end_object);
-                get_token();
-                if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
-                {
-                    result = basic_json(value_t::discarded);
-                }
-
-                return result;
-            }
-
-            case lexer::token_type::begin_array:
-            {
-                if (keep and (not callback
-                              or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
-                {
-                    // explicitly set result to object to cope with []
-                    result.m_type = value_t::array;
-                    result.m_value = value_t::array;
-                }
-
-                // read next token
-                get_token();
-
-                // closing ] -> we are done
-                if (last_token == lexer::token_type::end_array)
-                {
-                    get_token();
-                    if (callback and not callback(--depth, parse_event_t::array_end, result))
+                    if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
                     {
                         result = basic_json(value_t::discarded);
                     }
+
                     return result;
                 }
 
-                // no comma is expected here
-                unexpect(lexer::token_type::value_separator);
-
-                // otherwise: parse values
-                do
+                case lexer::token_type::literal_null:
                 {
-                    // ugly, but could be fixed with loop reorganization
-                    if (last_token == lexer::token_type::value_separator)
-                    {
-                        get_token();
-                    }
-
-                    // parse value
-                    auto value = parse_internal(keep);
-                    if (keep and not value.is_discarded())
-                    {
-                        result.push_back(std::move(value));
-                    }
-                }
-                while (last_token == lexer::token_type::value_separator);
-
-                // closing ]
-                expect(lexer::token_type::end_array);
-                get_token();
-                if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
-                {
-                    result = basic_json(value_t::discarded);
+                    get_token();
+                    result.m_type = value_t::null;
+                    break;
                 }
 
-                return result;
+                case lexer::token_type::value_string:
+                {
+                    const auto s = m_lexer.get_string();
+                    get_token();
+                    result = basic_json(s);
+                    break;
+                }
+
+                case lexer::token_type::literal_true:
+                {
+                    get_token();
+                    result.m_type = value_t::boolean;
+                    result.m_value = true;
+                    break;
+                }
+
+                case lexer::token_type::literal_false:
+                {
+                    get_token();
+                    result.m_type = value_t::boolean;
+                    result.m_value = false;
+                    break;
+                }
+
+                case lexer::token_type::value_number:
+                {
+                    m_lexer.get_number(result);
+                    get_token();
+                    break;
+                }
+
+                default:
+                {
+                    // the last token was unexpected
+                    unexpect(last_token);
+                }
             }
 
-            case lexer::token_type::literal_null:
+            if (keep and callback and not callback(depth, parse_event_t::value, result))
             {
-                get_token();
-                result.m_type = value_t::null;
-                break;
-            }
-
-            case lexer::token_type::value_string:
-            {
-                const auto s = m_lexer.get_string();
-                get_token();
-                result = basic_json(s);
-                break;
-            }
-
-            case lexer::token_type::literal_true:
-            {
-                get_token();
-                result.m_type = value_t::boolean;
-                result.m_value = true;
-                break;
-            }
-
-            case lexer::token_type::literal_false:
-            {
-                get_token();
-                result.m_type = value_t::boolean;
-                result.m_value = false;
-                break;
-            }
-
-            case lexer::token_type::value_number:
-            {
-                m_lexer.get_number(result);
-                get_token();
-                break;
-            }
-
-            default:
-            {
-                // the last token was unexpected
-                unexpect(last_token);
+                result = basic_json(value_t::discarded);
             }
+            return result;
         }
 
-        if (keep and callback and not callback(depth, parse_event_t::value, result))
+        /// get next token from lexer
+        typename lexer::token_type get_token()
         {
-            result = basic_json(value_t::discarded);
+            last_token = m_lexer.scan();
+            return last_token;
         }
-        return result;
-    }
 
-    /// get next token from lexer
-    typename lexer::token_type get_token()
-    {
-        last_token = m_lexer.scan();
-        return last_token;
-    }
-
-    void expect(typename lexer::token_type t) const
-    {
-        if (t != last_token)
+        void expect(typename lexer::token_type t) const
         {
-            std::string error_msg = "parse error - unexpected ";
-            error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
-                          "'") :
-                          lexer::token_type_name(last_token));
-            error_msg += "; expected " + lexer::token_type_name(t);
+            if (t != last_token)
+            {
+                std::string error_msg = "parse error - unexpected ";
+                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
+                              "'") :
+                              lexer::token_type_name(last_token));
+                error_msg += "; expected " + lexer::token_type_name(t);
                 JSON_THROW(std::invalid_argument(error_msg));
+            }
         }
-    }
 
-    void unexpect(typename lexer::token_type t) const
-    {
-        if (t == last_token)
+        void unexpect(typename lexer::token_type t) const
         {
-            std::string error_msg = "parse error - unexpected ";
-            error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
-                          "'") :
-                          lexer::token_type_name(last_token));
+            if (t == last_token)
+            {
+                std::string error_msg = "parse error - unexpected ";
+                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
+                              "'") :
+                              lexer::token_type_name(last_token));
                 JSON_THROW(std::invalid_argument(error_msg));
+            }
         }
-    }
 
-    private:
-    /// current level of recursion
-    int depth = 0;
-    /// callback function
-    const parser_callback_t callback = nullptr;
-    /// the type of the last read token
-    typename lexer::token_type last_token = lexer::token_type::uninitialized;
-    /// the lexer
-    lexer m_lexer;
-                            };
+      private:
+        /// current level of recursion
+        int depth = 0;
+        /// callback function
+        const parser_callback_t callback = nullptr;
+        /// the type of the last read token
+        typename lexer::token_type last_token = lexer::token_type::uninitialized;
+        /// the lexer
+        lexer m_lexer;
+    };
 
   public:
     /*!
@@ -10633,7 +11150,7 @@ basic_json_parser_66:
         /// allow basic_json to access private members
         friend class basic_json;
 
-        public:
+      public:
         /*!
         @brief create JSON pointer
 
@@ -10657,573 +11174,573 @@ basic_json_parser_66:
         @since version 2.0.0
         */
         explicit json_pointer(const std::string& s = "")
-        : reference_tokens(split(s))
-    {}
+            : reference_tokens(split(s))
+        {}
 
-    /*!
-    @brief return a string representation of the JSON pointer
+        /*!
+        @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
+        @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
+        @return a string representation of the JSON pointer
 
-    @liveexample{The example shows the result of `to_string`.,
-    json_pointer__to_string}
+        @liveexample{The example shows the result of `to_string`.,
+        json_pointer__to_string}
 
-    @since version 2.0.0
-    */
-    std::string to_string() const noexcept
-    {
-        return std::accumulate(reference_tokens.begin(),
-                               reference_tokens.end(), std::string{},
-                               [](const std::string & a, const std::string & b)
+        @since version 2.0.0
+        */
+        std::string to_string() const noexcept
         {
-            return a + "/" + escape(b);
-        });
-    }
+            return std::accumulate(reference_tokens.begin(),
+                                   reference_tokens.end(), std::string{},
+                                   [](const std::string & a, const std::string & b)
+            {
+                return a + "/" + escape(b);
+            });
+        }
 
-    /// @copydoc to_string()
-    operator std::string() const
-    {
-        return to_string();
-    }
-
-    private:
-    /// remove and return last reference pointer
-    std::string pop_back()
-    {
-        if (is_root())
+        /// @copydoc to_string()
+        operator std::string() const
         {
+            return to_string();
+        }
+
+      private:
+        /// remove and return last reference pointer
+        std::string pop_back()
+        {
+            if (is_root())
+            {
                 JSON_THROW(std::domain_error("JSON pointer has no parent"));
+            }
+
+            auto last = reference_tokens.back();
+            reference_tokens.pop_back();
+            return last;
         }
 
-        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())
+        /// return whether pointer points to the root document
+        bool is_root() const
         {
+            return reference_tokens.empty();
+        }
+
+        json_pointer top() const
+        {
+            if (is_root())
+            {
                 JSON_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
-
-    @complexity Linear in the number of reference tokens.
-    */
-    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:
-                {
-                        JSON_THROW(std::domain_error("invalid value to unflatten"));
-                }
-            }
-        }
-
-        return *result;
-    }
-
-    /*!
-    @brief return a reference to the pointed to value
-
-    @note This version does not throw if a value is not present, but tries
-    to create nested values instead. For instance, calling this function
-    with pointer `"/this/that"` on a null value is equivalent to calling
-    `operator[]("this").operator[]("that")` on that value, effectively
-    changing the null value to an object.
-
-    @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)
-        {
-            // convert null values to arrays or objects before continuing
-            if (ptr->m_type == value_t::null)
-            {
-                // check if reference token is a number
-                const bool nums = std::all_of(reference_token.begin(),
-                                              reference_token.end(),
-                                              [](const char x)
-                {
-                    return std::isdigit(x);
-                });
-
-                // change value to array for numbers or "-" or to object
-                // otherwise
-                if (nums or reference_token == "-")
-                {
-                    *ptr = value_t::array;
-                }
-                else
-                {
-                    *ptr = value_t::object;
-                }
             }
 
-            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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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(const std::string& reference_string)
-    {
-        std::vector<std::string> result;
-
-        // special case: empty reference string -> no reference tokens
-        if (reference_string.empty())
-        {
+            json_pointer result = *this;
+            result.reference_tokens = {reference_tokens[0]};
             return result;
         }
 
-        // check if nonempty reference string begins with slash
-        if (reference_string[0] != '/')
+        /*!
+        @brief create and return a reference to the pointed to value
+
+        @complexity Linear in the number of reference tokens.
+        */
+        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:
+                    {
+                        JSON_THROW(std::domain_error("invalid value to unflatten"));
+                    }
+                }
+            }
+
+            return *result;
+        }
+
+        /*!
+        @brief return a reference to the pointed to value
+
+        @note This version does not throw if a value is not present, but tries
+        to create nested values instead. For instance, calling this function
+        with pointer `"/this/that"` on a null value is equivalent to calling
+        `operator[]("this").operator[]("that")` on that value, effectively
+        changing the null value to an object.
+
+        @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)
+            {
+                // convert null values to arrays or objects before continuing
+                if (ptr->m_type == value_t::null)
+                {
+                    // check if reference token is a number
+                    const bool nums = std::all_of(reference_token.begin(),
+                                                  reference_token.end(),
+                                                  [](const char x)
+                    {
+                        return std::isdigit(x);
+                    });
+
+                    // change value to array for numbers or "-" or to object
+                    // otherwise
+                    if (nums or reference_token == "-")
+                    {
+                        *ptr = value_t::array;
+                    }
+                    else
+                    {
+                        *ptr = value_t::object;
+                    }
+                }
+
+                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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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(const 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] != '/')
+            {
                 JSON_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
+            // 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
+                // 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);
+            {
+                // 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
+                // check reference tokens are properly escaped
                 for (size_t pos = reference_token.find_first_of('~');
-                    pos != std::string::npos;
+                        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'))
                 {
+                    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'))
+                    {
                         JSON_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; changed so that all
-                      occurrences of @a f are replaced with @a t
-    @param[in]     f  the substring to replace with @a t
-    @param[in]     t  the string to replace @a f
-
-    @pre The search string @a f must not be empty.
-
-    @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;
+
+                // finally, store the reference token
+                unescape(reference_token);
+                result.push_back(reference_token);
             }
 
-            case value_t::object:
+            return result;
+        }
+
+      private:
+        /*!
+        @brief replace all occurrences of a substring by another string
+
+        @param[in,out] s  the string to manipulate; changed so that all
+                          occurrences of @a f are replaced with @a t
+        @param[in]     f  the substring to replace with @a t
+        @param[in]     t  the string to replace @a f
+
+        @pre The search string @a f must not be empty.
+
+        @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)
             {
-                if (value.m_value.object->empty())
+                case value_t::array:
                 {
-                    // 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)
+                    if (value.m_value.array->empty())
                     {
-                        flatten(reference_string + "/" + escape(element.first),
-                                element.second, result);
+                        // 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;
                 }
-                break;
-            }
 
-            default:
-            {
-                // add primitive value with its reference string
-                result[reference_string] = value;
-                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
+        /*!
+        @param[in] value  flattened JSON
 
-    @return unflattened JSON
-    */
-    static basic_json unflatten(const basic_json& value)
-    {
-        if (not value.is_object())
+        @return unflattened JSON
+        */
+        static basic_json unflatten(const basic_json& value)
         {
+            if (not value.is_object())
+            {
                 JSON_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())
-            {
-                    JSON_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;
+            basic_json result;
+
+            // iterate the JSON object values
+            for (const auto& element : *value.m_value.object)
+            {
+                if (not element.second.is_primitive())
+                {
+                    JSON_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;
         }
 
-        return result;
-    }
+      private:
+        friend bool operator==(json_pointer const& lhs,
+                               json_pointer const& rhs) noexcept
+        {
+            return lhs.reference_tokens == rhs.reference_tokens;
+        }
 
-    private:
-    friend bool operator==(json_pointer const &lhs,
-                           json_pointer const &rhs) noexcept
-    {
-      return lhs.reference_tokens == rhs.reference_tokens;
-    }
+        friend bool operator!=(json_pointer const& lhs,
+                               json_pointer const& rhs) noexcept
+        {
+            return !(lhs == rhs);
+        }
 
-    friend bool operator!=(json_pointer const &lhs,
-                           json_pointer const &rhs) noexcept
-    {
-      return !(lhs == rhs);
-    }
-
-    /// the reference tokens
-    std::vector<std::string> reference_tokens {};
+        /// the reference tokens
+        std::vector<std::string> reference_tokens {};
     };
 
     //////////////////////////
@@ -11899,25 +12416,26 @@ Returns an ordering that is similar to Python:
 */
 inline bool operator<(const value_t lhs, const value_t rhs) noexcept
 {
-  static constexpr std::array<uint8_t, 8> order = {{
-      0, // null
-      3, // object
-      4, // array
-      5, // string
-      1, // boolean
-      2, // integer
-      2, // unsigned
-      2, // float
-  }};
+    static constexpr std::array<uint8_t, 8> order = {{
+            0, // null
+            3, // object
+            4, // array
+            5, // string
+            1, // boolean
+            2, // integer
+            2, // unsigned
+            2, // float
+        }
+    };
 
-  // discarded values are not comparable
-  if (lhs == value_t::discarded or rhs == value_t::discarded)
-  {
-    return false;
-  }
+    // discarded values are not comparable
+    if (lhs == value_t::discarded or rhs == value_t::discarded)
+    {
+        return false;
+    }
 
-  return order[static_cast<std::size_t>(lhs)] <
-         order[static_cast<std::size_t>(rhs)];
+    return order[static_cast<std::size_t>(lhs)] <
+           order[static_cast<std::size_t>(rhs)];
 }
 
 /////////////
@@ -11942,38 +12460,38 @@ using json = basic_json<>;
 
 // specialization of std::swap, and std::hash
 namespace std
+{
+/*!
+@brief exchanges the values of two JSON objects
+
+@since version 1.0.0
+*/
+template<>
+inline void swap(nlohmann::json& j1,
+                 nlohmann::json& j2) noexcept(
+                     is_nothrow_move_constructible<nlohmann::json>::value and
+                     is_nothrow_move_assignable<nlohmann::json>::value
+                 )
+{
+    j1.swap(j2);
+}
+
+/// hash value for JSON objects
+template<>
+struct hash<nlohmann::json>
 {
     /*!
-    @brief exchanges the values of two JSON objects
+    @brief return a hash value for a JSON object
 
     @since version 1.0.0
     */
-    template<>
-    inline void swap(nlohmann::json& j1,
-                     nlohmann::json& j2) noexcept(
-                         is_nothrow_move_constructible<nlohmann::json>::value and
-                         is_nothrow_move_assignable<nlohmann::json>::value
-                                                   )
-    {
-        j1.swap(j2);
-    }
-
-    /// hash value for JSON objects
-    template<>
-    struct hash<nlohmann::json>
-    {
-        /*!
-        @brief return a hash value for a JSON object
-
-        @since version 1.0.0
-        */
-        std::size_t operator()(const nlohmann::json& j) const
+    std::size_t operator()(const nlohmann::json& j) const
     {
         // a naive hashing via the string representation
         const auto& h = hash<nlohmann::json::string_t>();
         return h(j.dump());
     }
-                        };
+};
 } // namespace std
 
 /*!
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 8fbff2ad..cbda7ee7 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -136,15 +136,15 @@ the default value for a given type
 */
 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 (signed integer)
-  number_unsigned, ///< number value (unsigned 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 (signed integer)
+    number_unsigned, ///< number value (unsigned integer)
+    number_float,    ///< number value (floating-point)
+    discarded        ///< discarded by the the parser callback function
 };
 
 // alias templates to reduce boilerplate
@@ -168,29 +168,29 @@ using is_unscoped_enum =
 
 namespace detail
 {
-template <typename Json> std::string type_name(const  Json &j)
+template <typename Json> std::string type_name(const  Json& j)
 {
-  switch (j.m_type)
-  {
-  case value_t::null:
-    return "null";
-  case value_t::object:
-    return "object";
-  case value_t::array:
-    return "array";
-  case value_t::string:
-    return "string";
-  case value_t::boolean:
-    return "boolean";
-  case value_t::discarded:
-    return "discarded";
-  default:
-    return "number";
-  }
+    switch (j.m_type)
+    {
+        case value_t::null:
+            return "null";
+        case value_t::object:
+            return "object";
+        case value_t::array:
+            return "array";
+        case value_t::string:
+            return "string";
+        case value_t::boolean:
+            return "boolean";
+        case value_t::discarded:
+            return "discarded";
+        default:
+            return "number";
+    }
 }
 
 // dispatch utility (taken from ranges-v3)
-template <unsigned N> struct priority_tag : priority_tag<N - 1> {};
+template <unsigned N> struct priority_tag : priority_tag < N - 1 > {};
 
 template <> struct priority_tag<0> {};
 
@@ -201,120 +201,120 @@ template <value_t> struct external_constructor;
 template <>
 struct external_constructor<value_t::boolean>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::boolean_t b) noexcept
-  {
-    j.m_type = value_t::boolean;
-    j.m_value = b;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, typename Json::boolean_t b) noexcept
+    {
+        j.m_type = value_t::boolean;
+        j.m_value = b;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::string>
 {
-  template <typename Json>
-  static void construct(Json &j, const typename Json::string_t& s)
-  {
-    j.m_type = value_t::string;
-    j.m_value = s;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, const typename Json::string_t& s)
+    {
+        j.m_type = value_t::string;
+        j.m_value = s;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::number_float>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::number_float_t val) noexcept
-  {
-    // replace infinity and NAN by null
-    if (not std::isfinite(val))
-      j = Json{};
-    else
+    template <typename Json>
+    static void construct(Json& j, typename Json::number_float_t val) noexcept
     {
-      j.m_type = value_t::number_float;
-      j.m_value = val;
+        // replace infinity and NAN by null
+        if (not std::isfinite(val))
+            j = Json{};
+        else
+        {
+            j.m_type = value_t::number_float;
+            j.m_value = val;
+        }
+        j.assert_invariant();
     }
-    j.assert_invariant();
-  }
 };
 
 template <>
 struct external_constructor<value_t::number_unsigned>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::number_unsigned_t val) noexcept
-  {
-    j.m_type = value_t::number_unsigned;
-    j.m_value = val;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, typename Json::number_unsigned_t val) noexcept
+    {
+        j.m_type = value_t::number_unsigned;
+        j.m_value = val;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::number_integer>
 {
-  template <typename Json>
-  static void construct(Json &j, typename Json::number_integer_t val) noexcept
-  {
-    j.m_type = value_t::number_integer;
-    j.m_value = val;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, typename Json::number_integer_t val) noexcept
+    {
+        j.m_type = value_t::number_integer;
+        j.m_value = val;
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::array>
 {
-  template <typename Json>
-  static void construct(Json &j, const typename Json::array_t& arr)
-  {
-    j.m_type = value_t::array;
-    j.m_value = arr;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, const typename Json::array_t& arr)
+    {
+        j.m_type = value_t::array;
+        j.m_value = arr;
+        j.assert_invariant();
+    }
 
-  template <typename Json, typename CompatibleArrayType,
-            enable_if_t<not std::is_same<CompatibleArrayType,
-                                         typename Json::array_t>::value,
-                        int> = 0>
-  static void construct(Json &j, const CompatibleArrayType &arr)
-  {
-    using std::begin;
-    using std::end;
-    j.m_type = value_t::array;
-    j.m_value.array =
-        j.template create<typename Json::array_t>(begin(arr), end(arr));
-    j.assert_invariant();
-  }
+    template <typename Json, typename CompatibleArrayType,
+              enable_if_t<not std::is_same<CompatibleArrayType,
+                                           typename Json::array_t>::value,
+                          int> = 0>
+    static void construct(Json& j, const CompatibleArrayType& arr)
+    {
+        using std::begin;
+        using std::end;
+        j.m_type = value_t::array;
+        j.m_value.array =
+            j.template create<typename Json::array_t>(begin(arr), end(arr));
+        j.assert_invariant();
+    }
 };
 
 template <>
 struct external_constructor<value_t::object>
 {
-  template <typename Json>
-  static void construct(Json &j, const typename Json::object_t& obj)
-  {
-    j.m_type = value_t::object;
-    j.m_value = obj;
-    j.assert_invariant();
-  }
+    template <typename Json>
+    static void construct(Json& j, const typename Json::object_t& obj)
+    {
+        j.m_type = value_t::object;
+        j.m_value = obj;
+        j.assert_invariant();
+    }
 
-  template <typename Json, typename CompatibleObjectType,
-            enable_if_t<not std::is_same<CompatibleObjectType,
-                                         typename Json::object_t>::value,
-                        int> = 0>
-  static void construct(Json &j, const CompatibleObjectType &obj)
-  {
-    using std::begin;
-    using std::end;
+    template <typename Json, typename CompatibleObjectType,
+              enable_if_t<not std::is_same<CompatibleObjectType,
+                                           typename Json::object_t>::value,
+                          int> = 0>
+    static void construct(Json& j, const CompatibleObjectType& obj)
+    {
+        using std::begin;
+        using std::end;
 
-    j.m_type = value_t::object;
-    j.m_value.object =
-        j.template create<typename Json::object_t>(begin(obj), end(obj));
-    j.assert_invariant();
-  }
+        j.m_type = value_t::object;
+        j.m_value.object =
+            j.template create<typename Json::object_t>(begin(obj), end(obj));
+        j.assert_invariant();
+    }
 };
 
 // Implementation of 2 C++17 constructs: conjunction, negation.
@@ -380,11 +380,11 @@ struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
 template<class BasicJson, class CompatibleObjectType>
 struct is_compatible_object_type
 {
-    static auto constexpr value = is_compatible_object_type_impl<
-        conjunction<negation<std::is_same<void, CompatibleObjectType>>,
-                    has_mapped_type<CompatibleObjectType>,
-                    has_key_type<CompatibleObjectType>>::value,
-        typename BasicJson::object_t, CompatibleObjectType>::value;
+    static auto constexpr value = is_compatible_object_type_impl <
+                                  conjunction<negation<std::is_same<void, CompatibleObjectType>>,
+                                  has_mapped_type<CompatibleObjectType>,
+                                  has_key_type<CompatibleObjectType>>::value,
+                                  typename BasicJson::object_t, CompatibleObjectType >::value;
 };
 
 template <typename BasicJson, typename T>
@@ -400,17 +400,17 @@ struct is_basic_json_nested_type
 template <class BasicJson, class CompatibleArrayType>
 struct is_compatible_array_type
 {
-  // TODO concept Container?
-  // this might not make VS happy
-    static auto constexpr value = 
+    // TODO concept Container?
+    // this might not make VS happy
+    static auto constexpr value =
         conjunction<negation<std::is_same<void, CompatibleArrayType>>,
-                    negation<is_compatible_object_type<
-                        BasicJson, CompatibleArrayType>>,
-                    negation<std::is_constructible<typename BasicJson::string_t,
-                                                   CompatibleArrayType>>,
-                    negation<is_basic_json_nested_type<BasicJson, CompatibleArrayType>>,
-                    has_value_type<CompatibleArrayType>,
-                    has_iterator<CompatibleArrayType>>::value;
+        negation<is_compatible_object_type<
+        BasicJson, CompatibleArrayType>>,
+        negation<std::is_constructible<typename BasicJson::string_t,
+        CompatibleArrayType>>,
+        negation<is_basic_json_nested_type<BasicJson, CompatibleArrayType>>,
+        has_value_type<CompatibleArrayType>,
+        has_iterator<CompatibleArrayType>>::value;
 };
 
 template <bool, typename, typename>
@@ -419,7 +419,7 @@ struct is_compatible_integer_type_impl : std::false_type {};
 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
 struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType>
 {
-  // is there an assert somewhere on overflows?
+    // is there an assert somewhere on overflows?
     using RealLimits = std::numeric_limits<RealIntegerType>;
     using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
 
@@ -433,11 +433,11 @@ struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIn
 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
 struct is_compatible_integer_type
 {
-  static constexpr auto
-      value = is_compatible_integer_type_impl <
-                  std::is_integral<CompatibleNumberIntegerType>::value and
-              not std::is_same<bool, CompatibleNumberIntegerType>::value,
-      RealIntegerType, CompatibleNumberIntegerType > ::value;
+    static constexpr auto
+    value = is_compatible_integer_type_impl <
+            std::is_integral<CompatibleNumberIntegerType>::value and
+            not std::is_same<bool, CompatibleNumberIntegerType>::value,
+            RealIntegerType, CompatibleNumberIntegerType > ::value;
 };
 
 // This trait checks if JSONSerializer<T>::from_json(json const&, udt&) exists
@@ -461,261 +461,287 @@ struct has_from_json
 template <typename Json, typename T>
 struct has_non_default_from_json
 {
-private:
-  template <
-      typename U,
-      typename = enable_if_t<std::is_same<
-          T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value>>
-  static int detect(U &&);
-  static void detect(...);
+  private:
+    template <
+        typename U,
+        typename = enable_if_t<std::is_same<
+                                   T, decltype(uncvref_t<U>::from_json(std::declval<Json>()))>::value >>
+    static int detect(U&&);
+    static void detect(...);
 
-public:
-  static constexpr bool value = std::is_integral<decltype(detect(
-      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
+  public:
+    static constexpr bool value = std::is_integral<decltype(detect(
+                                      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
 };
 
 // This trait checks if Json::json_serializer<T>::to_json exists
 template <typename Json, typename T>
 struct has_to_json
 {
-private:
-  template <typename U, typename = decltype(uncvref_t<U>::to_json(
-                            std::declval<Json &>(), std::declval<T>()))>
-  static int detect(U &&);
-  static void detect(...);
+  private:
+    template <typename U, typename = decltype(uncvref_t<U>::to_json(
+                  std::declval<Json&>(), std::declval<T>()))>
+    static int detect(U&&);
+    static void detect(...);
 
-public:
-  static constexpr bool value = std::is_integral<decltype(detect(
-      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
+  public:
+    static constexpr bool value = std::is_integral<decltype(detect(
+                                      std::declval<typename Json::template json_serializer<T, void>>()))>::value;
 };
 
 // overloads for basic_json template parameters
 
 template <typename Json, typename ArithmeticType,
           enable_if_t<std::is_arithmetic<ArithmeticType>::value and
-                          not std::is_same<ArithmeticType,
-                                           typename Json::boolean_t>::value,
+                      not std::is_same<ArithmeticType,
+                                       typename Json::boolean_t>::value,
                       int> = 0>
-void get_arithmetic_value(const  Json &j, ArithmeticType &val)
+void get_arithmetic_value(const  Json& j, ArithmeticType& val)
 {
-  // unsigned must be checked first, since is_number_integer() == true for unsigned
-  if (j.is_number_unsigned())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
-  else if (j.is_number_integer())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
-  else if (j.is_number_float())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
-  else
-    throw std::domain_error("type must be number, but is " + type_name(j));
+    // unsigned must be checked first, since is_number_integer() == true for unsigned
+    if (j.is_number_unsigned())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
+    }
+    else if (j.is_number_integer())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
+    }
+    else if (j.is_number_float())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
+    }
+    else
+    {
+        throw std::domain_error("type must be number, but is " + type_name(j));
+    }
 }
 
 template <typename Json>
-void to_json(Json &j, typename Json::boolean_t b) noexcept
+void to_json(Json& j, typename Json::boolean_t b) noexcept
 {
-  external_constructor<value_t::boolean>::construct(j, b);
+    external_constructor<value_t::boolean>::construct(j, b);
 }
 
 template <typename Json, typename CompatibleString,
           enable_if_t<std::is_constructible<typename Json::string_t,
-                                            CompatibleString>::value,
+                      CompatibleString>::value,
                       int> = 0>
-void to_json(Json &j, const CompatibleString &s)
+void to_json(Json& j, const CompatibleString& s)
 {
-  external_constructor<value_t::string>::construct(j, s);
+    external_constructor<value_t::string>::construct(j, s);
 }
 
 template <typename Json, typename FloatType,
           enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
-void to_json(Json &j, FloatType val) noexcept
+void to_json(Json& j, FloatType val) noexcept
 {
-  external_constructor<value_t::number_float>::construct(j, static_cast<typename Json::number_float_t>(val));
+    external_constructor<value_t::number_float>::construct(j, static_cast<typename Json::number_float_t>(val));
 }
 
 
 template <
     typename Json, typename CompatibleNumberUnsignedType,
-   enable_if_t<is_compatible_integer_type<typename Json::number_unsigned_t,
-                                         CompatibleNumberUnsignedType>::value,
-                int> = 0>
-void to_json(Json &j, CompatibleNumberUnsignedType val) noexcept
+    enable_if_t<is_compatible_integer_type<typename Json::number_unsigned_t,
+                CompatibleNumberUnsignedType>::value,
+                int> = 0 >
+void to_json(Json& j, CompatibleNumberUnsignedType val) noexcept
 {
-  external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename Json::number_unsigned_t>(val));
+    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename Json::number_unsigned_t>(val));
 }
 
 template <
     typename Json, typename CompatibleNumberIntegerType,
-   enable_if_t<is_compatible_integer_type<typename Json::number_integer_t,
-                                         CompatibleNumberIntegerType>::value,
-                int> = 0>
-void to_json(Json &j, CompatibleNumberIntegerType val) noexcept
+    enable_if_t<is_compatible_integer_type<typename Json::number_integer_t,
+                CompatibleNumberIntegerType>::value,
+                int> = 0 >
+void to_json(Json& j, CompatibleNumberIntegerType val) noexcept
 {
-  external_constructor<value_t::number_integer>::construct(j, static_cast<typename Json::number_integer_t>(val));
+    external_constructor<value_t::number_integer>::construct(j, static_cast<typename Json::number_integer_t>(val));
 }
 
 template <typename Json, typename UnscopedEnumType,
           enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
-void to_json(Json &j, UnscopedEnumType e) noexcept
+void to_json(Json& j, UnscopedEnumType e) noexcept
 {
-  external_constructor<value_t::number_integer>::construct(j, e);
+    external_constructor<value_t::number_integer>::construct(j, e);
 }
 
 template <
     typename Json, typename CompatibleArrayType,
-    enable_if_t<
+    enable_if_t <
         is_compatible_array_type<Json, CompatibleArrayType>::value or
-            std::is_same<typename Json::array_t, CompatibleArrayType>::value,
-        int> = 0>
-void to_json(Json &j, const  CompatibleArrayType &arr)
+        std::is_same<typename Json::array_t, CompatibleArrayType>::value,
+        int > = 0 >
+void to_json(Json& j, const  CompatibleArrayType& arr)
 {
-  external_constructor<value_t::array>::construct(j, arr);
+    external_constructor<value_t::array>::construct(j, arr);
 }
 
 template <
     typename Json, typename CompatibleObjectType,
     enable_if_t<is_compatible_object_type<Json, CompatibleObjectType>::value,
-                int> = 0>
-void to_json(Json &j, const  CompatibleObjectType &arr)
+                int> = 0 >
+void to_json(Json& j, const  CompatibleObjectType& arr)
 {
-  external_constructor<value_t::object>::construct(j, arr);
+    external_constructor<value_t::object>::construct(j, arr);
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::boolean_t& b)
+void from_json(const Json& j, typename Json::boolean_t& b)
 {
-  if (!j.is_boolean())
-    throw std::domain_error("type must be boolean, but is " + type_name(j));
-  b = *j.template get_ptr<const typename Json::boolean_t*>();
+    if (!j.is_boolean())
+    {
+        throw std::domain_error("type must be boolean, but is " + type_name(j));
+    }
+    b = *j.template get_ptr<const typename Json::boolean_t*>();
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::string_t& s)
+void from_json(const Json& j, typename Json::string_t& s)
 {
-  if (!j.is_string())
-    throw std::domain_error("type must be string, but is " + type_name(j));
-  s = *j.template get_ptr<const typename Json::string_t*>();
+    if (!j.is_string())
+    {
+        throw std::domain_error("type must be string, but is " + type_name(j));
+    }
+    s = *j.template get_ptr<const typename Json::string_t*>();
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::number_float_t& val)
+void from_json(const Json& j, typename Json::number_float_t& val)
 {
-  get_arithmetic_value(j, val);
+    get_arithmetic_value(j, val);
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::number_unsigned_t& val)
+void from_json(const Json& j, typename Json::number_unsigned_t& val)
 {
-  get_arithmetic_value(j, val);
+    get_arithmetic_value(j, val);
 }
 
 template <typename Json>
-void from_json(const Json & j, typename Json::number_integer_t& val)
+void from_json(const Json& j, typename Json::number_integer_t& val)
 {
-  get_arithmetic_value(j, val);
+    get_arithmetic_value(j, val);
 }
 
 template <typename Json, typename UnscopedEnumType,
           enable_if_t<is_unscoped_enum<UnscopedEnumType>::value, int> = 0>
-void from_json(const  Json &j, UnscopedEnumType& e)
+void from_json(const  Json& j, UnscopedEnumType& e)
 {
-  typename std::underlying_type<UnscopedEnumType>::type val = e;
-  get_arithmetic_value(j, val);
-  e = static_cast<UnscopedEnumType>(val);
+    typename std::underlying_type<UnscopedEnumType>::type val = e;
+    get_arithmetic_value(j, val);
+    e = static_cast<UnscopedEnumType>(val);
 }
 
 template <typename Json>
-void from_json(const  Json &j, typename Json::array_t &arr)
+void from_json(const  Json& j, typename Json::array_t& arr)
 {
-  if (!j.is_array())
-    throw std::domain_error("type must be array, but is " + type_name(j));
-  arr = *j.template get_ptr<const typename Json::array_t*>();
+    if (!j.is_array())
+    {
+        throw std::domain_error("type must be array, but is " + type_name(j));
+    }
+    arr = *j.template get_ptr<const typename Json::array_t*>();
 }
 
 // forward_list doesn't have an insert method, TODO find a way to avoid including forward_list
 template <typename Json, typename T, typename Allocator>
-void from_json(const Json &j, std::forward_list<T, Allocator>& l)
+void from_json(const Json& j, std::forward_list<T, Allocator>& l)
 {
-  // do not perform the check when user wants to retrieve jsons
-  // (except when it's null.. ?)
-  if (j.is_null())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  if (not std::is_same<T, Json>::value)
-  {
-    if (!j.is_array())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  }
-  for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
-    l.push_front(it->template get<T>());
+    // do not perform the check when user wants to retrieve jsons
+    // (except when it's null.. ?)
+    if (j.is_null())
+    {
+        throw std::domain_error("type must be array, but is " + type_name(j));
+    }
+    if (not std::is_same<T, Json>::value)
+    {
+        if (!j.is_array())
+        {
+            throw std::domain_error("type must be array, but is " + type_name(j));
+        }
+    }
+    for (auto it = j.rbegin(), end = j.rend(); it != end; ++it)
+    {
+        l.push_front(it->template get<T>());
+    }
 }
 
 template <typename Json, typename CompatibleArrayType>
-void from_json_array_impl(const  Json &j, CompatibleArrayType &arr, priority_tag<0>)
+void from_json_array_impl(const  Json& j, CompatibleArrayType& arr, priority_tag<0>)
 {
-  using std::begin;
-  using std::end;
+    using std::begin;
+    using std::end;
 
-  std::transform(
-      j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json &i)
-      {
+    std::transform(
+        j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json & i)
+    {
         // get<Json>() returns *this, this won't call a from_json method when
         // value_type is Json
         return i.template get<typename CompatibleArrayType::value_type>();
-      });
+    });
 }
 
 template <typename Json, typename CompatibleArrayType>
-auto from_json_array_impl(const  Json &j, CompatibleArrayType &arr, priority_tag<1>)
-    -> decltype(
-        arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
-        void())
+auto from_json_array_impl(const  Json& j, CompatibleArrayType& arr, priority_tag<1>)
+-> decltype(
+    arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
+    void())
 {
-  using std::begin;
-  using std::end;
+    using std::begin;
+    using std::end;
 
-  arr.reserve(j.size());
-  std::transform(
-      j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json &i)
-      {
+    arr.reserve(j.size());
+    std::transform(
+        j.begin(), j.end(), std::inserter(arr, end(arr)), [](const  Json & i)
+    {
         // get<Json>() returns *this, this won't call a from_json method when
         // value_type is Json
         return i.template get<typename CompatibleArrayType::value_type>();
-      });
+    });
 }
 
 template <
     typename Json, typename CompatibleArrayType,
     enable_if_t<is_compatible_array_type<Json, CompatibleArrayType>::value and
-                    not std::is_same<typename Json::array_t,
-                                     CompatibleArrayType>::value,
-                int> = 0>
-void from_json(const  Json &j, CompatibleArrayType &arr)
+                not std::is_same<typename Json::array_t,
+                                 CompatibleArrayType>::value,
+                int> = 0 >
+void from_json(const  Json& j, CompatibleArrayType& arr)
 {
-  if (j.is_null())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  // when T == Json, do not check if value_t is correct
-  if (not std::is_same<typename CompatibleArrayType::value_type, Json>::value)
-  {
-    if (!j.is_array())
-      throw std::domain_error("type must be array, but is " + type_name(j));
-  }
-  from_json_array_impl(j, arr, priority_tag<1>{});
+    if (j.is_null())
+    {
+        throw std::domain_error("type must be array, but is " + type_name(j));
+    }
+    // when T == Json, do not check if value_t is correct
+    if (not std::is_same<typename CompatibleArrayType::value_type, Json>::value)
+    {
+        if (!j.is_array())
+        {
+            throw std::domain_error("type must be array, but is " + type_name(j));
+        }
+    }
+    from_json_array_impl(j, arr, priority_tag<1> {});
 }
 
 
 template <
     typename Json, typename CompatibleObjectType,
     enable_if_t<is_compatible_object_type<Json, CompatibleObjectType>::value,
-                int> = 0>
-void from_json(const  Json &j, CompatibleObjectType &obj)
+                int> = 0 >
+void from_json(const  Json& j, CompatibleObjectType& obj)
 {
-  if (!j.is_object())
-    throw std::domain_error("type must be object, but is " + type_name(j));
+    if (!j.is_object())
+    {
+        throw std::domain_error("type must be object, but is " + type_name(j));
+    }
 
-  auto inner_object = j.template get_ptr<const typename Json::object_t*>();
-  using std::begin;
-  using std::end;
-  // we could avoid the assignment, but this might require a for loop, which
-  // might be less efficient than the container constructor for some containers (would it?)
-  obj = CompatibleObjectType(begin(*inner_object), end(*inner_object));
+    auto inner_object = j.template get_ptr<const typename Json::object_t*>();
+    using std::begin;
+    using std::end;
+    // we could avoid the assignment, but this might require a for loop, which
+    // might be less efficient than the container constructor for some containers (would it?)
+    obj = CompatibleObjectType(begin(*inner_object), end(*inner_object));
 }
 
 // overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..)
@@ -724,25 +750,35 @@ void from_json(const  Json &j, CompatibleObjectType &obj)
 // in case of a custom BooleanType which is not an arithmetic type?
 template <
     typename Json, typename ArithmeticType,
-    enable_if_t<
+    enable_if_t <
         std::is_arithmetic<ArithmeticType>::value and
-            not std::is_same<ArithmeticType, typename Json::number_unsigned_t>::value and
-            not std::is_same<ArithmeticType, typename Json::number_integer_t>::value and
-            not std::is_same<ArithmeticType, typename Json::number_float_t>::value and
-            not std::is_same<ArithmeticType, typename Json::boolean_t>::value,
-        int> = 0>
-void from_json(const  Json &j, ArithmeticType &val)
+        not std::is_same<ArithmeticType, typename Json::number_unsigned_t>::value and
+        not std::is_same<ArithmeticType, typename Json::number_integer_t>::value and
+        not std::is_same<ArithmeticType, typename Json::number_float_t>::value and
+        not std::is_same<ArithmeticType, typename Json::boolean_t>::value,
+        int > = 0 >
+void from_json(const  Json& j, ArithmeticType& val)
 {
-  if (j.is_number_unsigned())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
-  else if (j.is_number_integer())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
-  else if (j.is_number_float())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
-  else if (j.is_boolean())
-    val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::boolean_t*>());
-  else
-    throw std::domain_error("type must be number, but is " + type_name(j));
+    if (j.is_number_unsigned())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_unsigned_t*>());
+    }
+    else if (j.is_number_integer())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_integer_t*>());
+    }
+    else if (j.is_number_float())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::number_float_t*>());
+    }
+    else if (j.is_boolean())
+    {
+        val = static_cast<ArithmeticType>(*j.template get_ptr<const typename Json::boolean_t*>());
+    }
+    else
+    {
+        throw std::domain_error("type must be number, but is " + type_name(j));
+    }
 }
 
 struct to_json_fn
@@ -762,39 +798,39 @@ struct to_json_fn
         static_assert(sizeof(Json) == 0, "to_json method in T's namespace can not be called");
     }
 
-public:
-  template <typename Json, typename T>
-  void operator()(Json &j, T &&val) const
-      noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1>{})))
-  {
-      return call(j, std::forward<T>(val), priority_tag<1>{});
-  }
+  public:
+    template <typename Json, typename T>
+    void operator()(Json& j, T&& val) const
+    noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
+    {
+        return call(j, std::forward<T>(val), priority_tag<1> {});
+    }
 };
 
 struct from_json_fn
 {
-private:
-  template <typename Json, typename T>
-  auto call(const  Json &j, T &val, priority_tag<1>) const
-      noexcept(noexcept(from_json(j, val)))
-          -> decltype(from_json(j, val), void())
-  {
-    return from_json(j, val);
-  }
+  private:
+    template <typename Json, typename T>
+    auto call(const  Json& j, T& val, priority_tag<1>) const
+    noexcept(noexcept(from_json(j, val)))
+    -> decltype(from_json(j, val), void())
+    {
+        return from_json(j, val);
+    }
 
-  template <typename Json, typename T>
-  void call(const Json &, T&, priority_tag<0>) const noexcept
-  {
-      static_assert(sizeof(Json) == 0, "from_json method in T's namespace can not be called");
-  }
+    template <typename Json, typename T>
+    void call(const Json&, T&, priority_tag<0>) const noexcept
+    {
+        static_assert(sizeof(Json) == 0, "from_json method in T's namespace can not be called");
+    }
 
-public:
-  template <typename Json, typename T>
-  void operator()(const  Json &j, T &val) const
-      noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1>{})))
-  {
-      return call(j, val, priority_tag<1>{});
-  }
+  public:
+    template <typename Json, typename T>
+    void operator()(const  Json& j, T& val) const
+    noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
+    {
+        return call(j, val, priority_tag<1> {});
+    }
 };
 
 // taken from ranges-v3
@@ -830,8 +866,8 @@ struct DecimalSeparator : std::numpunct<char>
 
 inline namespace
 {
-constexpr const auto & to_json = detail::static_const<detail::to_json_fn>::value;
-constexpr const auto & from_json = detail::static_const<detail::from_json_fn>::value;
+constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
+constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
 }
 
 // default JSONSerializer template argument, doesn't care about template argument
@@ -846,10 +882,10 @@ struct adl_serializer
     }
 
     template <typename Json, typename T>
-    static void to_json(Json &j, T &&val) noexcept(
+    static void to_json(Json& j, T&& val) noexcept(
         noexcept(::nlohmann::to_json(j, std::forward<T>(val))))
     {
-      ::nlohmann::to_json(j, std::forward<T>(val));
+        ::nlohmann::to_json(j, std::forward<T>(val));
     }
 };
 
@@ -947,7 +983,7 @@ class basic_json
 {
   private:
     template <::nlohmann::value_t> friend struct detail::external_constructor;
-    template <typename Json> friend std::string detail::type_name(const  Json &);
+    template <typename Json> friend std::string detail::type_name(const  Json&);
     /// workaround type for MSVC
     using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
           BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
@@ -1849,15 +1885,15 @@ class basic_json
     */
     template <typename T, typename U = uncvref_t<T>,
               enable_if_t<not std::is_base_of<std::istream, U>::value and
-                              not std::is_same<U, basic_json_t>::value and
-                              not detail::is_basic_json_nested_type<
-                                  basic_json_t, U>::value and
-                              detail::has_to_json<basic_json, U>::value,
+                          not std::is_same<U, basic_json_t>::value and
+                          not detail::is_basic_json_nested_type<
+                              basic_json_t, U>::value and
+                          detail::has_to_json<basic_json, U>::value,
                           int> = 0>
-    basic_json(T &&val) noexcept(noexcept(JSONSerializer<U>::to_json(
-        std::declval<basic_json_t &>(), std::forward<T>(val))))
+    basic_json(T && val) noexcept(noexcept(JSONSerializer<U>::to_json(
+            std::declval<basic_json_t&>(), std::forward<T>(val))))
     {
-      JSONSerializer<U>::to_json(*this, std::forward<T>(val));
+        JSONSerializer<U>::to_json(*this, std::forward<T>(val));
     }
 
     /*!
@@ -2013,7 +2049,7 @@ class basic_json
     @since version 1.0.0
     */
     static basic_json array(std::initializer_list<basic_json> init =
-                            std::initializer_list<basic_json>())
+                                std::initializer_list<basic_json>())
     {
         return basic_json(init, false, value_t::array);
     }
@@ -2053,7 +2089,7 @@ class basic_json
     @since version 1.0.0
     */
     static basic_json object(std::initializer_list<basic_json> init =
-                             std::initializer_list<basic_json>())
+                                 std::initializer_list<basic_json>())
     {
         return basic_json(init, false, value_t::object);
     }
@@ -2394,7 +2430,7 @@ class basic_json
         std::is_nothrow_move_assignable<value_t>::value and
         std::is_nothrow_move_constructible<json_value>::value and
         std::is_nothrow_move_assignable<json_value>::value
-                                       )
+    )
     {
         // check that passed value is valid
         other.assert_invariant();
@@ -3020,7 +3056,7 @@ class basic_json
               enable_if_t<std::is_same<T, basic_json_t>::value, int> = 0>
     basic_json get() const
     {
-      return *this;
+        return *this;
     }
 
     /*!
@@ -3032,7 +3068,7 @@ class basic_json
     - @ref json_serializer<U> has a from_json method of the form: void from_json(const @ref basic_json&, U&)
     - @ref json_serializer<U> does not have a from_json method of the form: U from_json(const @ref basic_json&);
 
-    @return a value of type U 
+    @return a value of type U
 
     @throw what json_serializer<U> from_json method throws
 
@@ -3040,27 +3076,27 @@ class basic_json
     */
     template <
         typename T,
-                 typename U = uncvref_t<T>,
-        enable_if_t<
+        typename U = uncvref_t<T>,
+        enable_if_t <
             not std::is_same<basic_json_t, U>::value and
-                detail::has_from_json<basic_json_t, U>::value and
-                not detail::has_non_default_from_json<basic_json_t,
-                                                      U>::value,
-            int> = 0>
+            detail::has_from_json<basic_json_t, U>::value and
+            not detail::has_non_default_from_json<basic_json_t,
+                    U>::value,
+            int > = 0 >
     // do we really want the uncvref ? if a user call get<int &>, shouldn't we
     // static assert ?
     // i know there is a special behaviour for boolean_t* and such
     auto get() const noexcept(noexcept(JSONSerializer<U>::from_json(
-        std::declval<const basic_json_t &>(), std::declval<U &>())))
-        -> U
+                                           std::declval<const basic_json_t&>(), std::declval<U&>())))
+    -> U
     {
-      static_assert(std::is_default_constructible<U>::value and
-                        std::is_copy_constructible<U>::value,
-                    "Types must be DefaultConstructible and "
-                    "CopyConstructible when used with get");
-      U ret;
-      JSONSerializer<U>::from_json(*this, ret);
-      return ret;
+        static_assert(std::is_default_constructible<U>::value and
+        std::is_copy_constructible<U>::value,
+        "Types must be DefaultConstructible and "
+        "CopyConstructible when used with get");
+        U ret;
+        JSONSerializer<U>::from_json(*this, ret);
+        return ret;
     }
 
     /*!
@@ -3072,7 +3108,7 @@ class basic_json
     - U is not @ref basic_json
     - @ref json_serializer<U> has a from_json method of the form: U from_json(const @ref basic_json&);
 
-    @return a value of type U 
+    @return a value of type U
 
     @throw what json_serializer<U> from_json method throws
 
@@ -3081,12 +3117,12 @@ class basic_json
     template <
         typename T,
         enable_if_t<not std::is_same<basic_json_t, uncvref_t<T>>::value and
-                        detail::has_non_default_from_json<basic_json_t,
-                                                          uncvref_t<T>>::value,
-                    int> = 0>
-    uncvref_t<T> get() const noexcept(noexcept(JSONSerializer<T>::from_json(std::declval<const basic_json_t &>())))
+                    detail::has_non_default_from_json<basic_json_t,
+                            uncvref_t<T>>::value,
+                    int> = 0 >
+    uncvref_t<T> get() const noexcept(noexcept(JSONSerializer<T>::from_json(std::declval<const basic_json_t&>())))
     {
-      return JSONSerializer<T>::from_json(*this);
+        return JSONSerializer<T>::from_json(*this);
     }
 
     /*!
@@ -3168,8 +3204,8 @@ class basic_json
     {
         // get the type of the PointerType (remove pointer and const)
         using pointee_t = typename std::remove_const<typename
-                std::remove_pointer<typename
-                                    std::remove_const<PointerType>::type>::type>::type;
+                          std::remove_pointer<typename
+                          std::remove_const<PointerType>::type>::type>::type;
         // make sure the type matches the allowed types
         static_assert(
             std::is_same<object_t, pointee_t>::value
@@ -3196,8 +3232,8 @@ class basic_json
     {
         // get the type of the PointerType (remove pointer and const)
         using pointee_t = typename std::remove_const<typename
-                std::remove_pointer<typename
-                                    std::remove_const<PointerType>::type>::type>::type;
+                          std::remove_pointer<typename
+                          std::remove_const<PointerType>::type>::type>::type;
         // make sure the type matches the allowed types
         static_assert(
             std::is_same<object_t, pointee_t>::value
@@ -4250,14 +4286,14 @@ class basic_json
             case value_t::object:
             {
                 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
-                        last.m_it.object_iterator);
+                                              last.m_it.object_iterator);
                 break;
             }
 
             case value_t::array:
             {
                 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
-                        last.m_it.array_iterator);
+                                             last.m_it.array_iterator);
                 break;
             }
 
@@ -5474,9 +5510,9 @@ class basic_json
         // insert to array and return iterator
         iterator result(this);
         result.m_it.array_iterator = m_value.array->insert(
-            pos.m_it.array_iterator,
-            first.m_it.array_iterator,
-            last.m_it.array_iterator);
+                                         pos.m_it.array_iterator,
+                                         first.m_it.array_iterator,
+                                         last.m_it.array_iterator);
         return result;
     }
 
@@ -5546,7 +5582,7 @@ class basic_json
         std::is_nothrow_move_assignable<value_t>::value and
         std::is_nothrow_move_constructible<json_value>::value and
         std::is_nothrow_move_assignable<json_value>::value
-                                       )
+    )
     {
         std::swap(m_type, other.m_type);
         std::swap(m_value, other.m_value);
@@ -7871,7 +7907,10 @@ class basic_json
 
     @since version 1.0.0
     */
-    std::string type_name() const { return detail::type_name(*this); }
+    std::string type_name() const
+    {
+        return detail::type_name(*this);
+    }
 
   private:
     /*!
@@ -8086,13 +8125,13 @@ class basic_json
                         o << (pretty_print ? ",\n" : ",");
                     }
                     o << string_t(new_indent, ' ') << "\""
-                                                    << escape_string(i->first) << "\":"
-                                                            << (pretty_print ? " " : "");
-                                                            i->second.dump(o, pretty_print, indent_step, new_indent);
+                      << escape_string(i->first) << "\":"
+                      << (pretty_print ? " " : "");
+                    i->second.dump(o, pretty_print, indent_step, new_indent);
                 }
 
-                                                        // decrease indentation
-                                                        if (pretty_print)
+                // decrease indentation
+                if (pretty_print)
                 {
                     new_indent -= indent_step;
                     o << "\n";
@@ -8137,16 +8176,16 @@ class basic_json
                 }
 
                 o << string_t(new_indent, ' ') << "]";
-                   return;
+                return;
             }
 
-               case value_t::string:
+            case value_t::string:
             {
                 o << string_t("\"") << escape_string(*m_value.string) << "\"";
-                                     return;
+                return;
             }
 
-                                 case value_t::boolean:
+            case value_t::boolean:
             {
                 o << (m_value.boolean ? "true" : "false");
                 return;
@@ -8220,126 +8259,126 @@ class basic_json
     */
     class primitive_iterator_t
     {
-        public:
+      public:
 
         difference_type get_value() const noexcept
-    {
-        return m_it;
-    }
-    /// set iterator to a defined beginning
-    void set_begin() noexcept
-    {
-        m_it = begin_value;
-    }
+        {
+            return m_it;
+        }
+        /// set iterator to a defined beginning
+        void set_begin() noexcept
+        {
+            m_it = begin_value;
+        }
 
-    /// set iterator to a defined past the end
-    void set_end() noexcept
-    {
-        m_it = end_value;
-    }
+        /// set iterator to a defined past the end
+        void set_end() noexcept
+        {
+            m_it = end_value;
+        }
 
-    /// return whether the iterator can be dereferenced
-    constexpr bool is_begin() const noexcept
-    {
-        return (m_it == begin_value);
-    }
+        /// return whether the iterator can be dereferenced
+        constexpr bool is_begin() const noexcept
+        {
+            return (m_it == begin_value);
+        }
 
-    /// return whether the iterator is at end
-    constexpr bool is_end() const noexcept
-    {
-        return (m_it == end_value);
-    }
+        /// return whether the iterator is at end
+        constexpr bool is_end() const noexcept
+        {
+            return (m_it == end_value);
+        }
 
-    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it == rhs.m_it;
-    }
+        friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it == rhs.m_it;
+        }
 
-    friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return !(lhs == rhs);
-    }
+        friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return !(lhs == rhs);
+        }
 
-    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it < rhs.m_it;
-    }
+        friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it < rhs.m_it;
+        }
 
-    friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it <= rhs.m_it;
-    }
+        friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it <= rhs.m_it;
+        }
 
-    friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it > rhs.m_it;
-    }
+        friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it > rhs.m_it;
+        }
 
-    friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it >= rhs.m_it;
-    }
+        friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it >= rhs.m_it;
+        }
 
-    primitive_iterator_t operator+(difference_type i)
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
+        primitive_iterator_t operator+(difference_type i)
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
 
-    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
-    {
-        return lhs.m_it - rhs.m_it;
-    }
+        friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+        {
+            return lhs.m_it - rhs.m_it;
+        }
 
-    friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
-    {
-        return os << it.m_it;
-    }
+        friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it)
+        {
+            return os << it.m_it;
+        }
 
-    primitive_iterator_t& operator++()
-    {
-        ++m_it;
-        return *this;
-    }
+        primitive_iterator_t& operator++()
+        {
+            ++m_it;
+            return *this;
+        }
 
-    primitive_iterator_t& operator++(int)
-    {
-        m_it++;
-        return *this;
-    }
+        primitive_iterator_t& operator++(int)
+        {
+            m_it++;
+            return *this;
+        }
 
-    primitive_iterator_t& operator--()
-    {
-        --m_it;
-        return *this;
-    }
+        primitive_iterator_t& operator--()
+        {
+            --m_it;
+            return *this;
+        }
 
-    primitive_iterator_t& operator--(int)
-    {
-        m_it--;
-        return *this;
-    }
+        primitive_iterator_t& operator--(int)
+        {
+            m_it--;
+            return *this;
+        }
 
-    primitive_iterator_t& operator+=(difference_type n)
-    {
-        m_it += n;
-        return *this;
-    }
+        primitive_iterator_t& operator+=(difference_type n)
+        {
+            m_it += n;
+            return *this;
+        }
 
-    primitive_iterator_t& operator-=(difference_type n)
-    {
-        m_it -= n;
-        return *this;
-    }
+        primitive_iterator_t& operator-=(difference_type n)
+        {
+            m_it -= n;
+            return *this;
+        }
 
-    private:
-    static constexpr difference_type begin_value = 0;
-    static constexpr difference_type end_value = begin_value + 1;
+      private:
+        static constexpr difference_type begin_value = 0;
+        static constexpr difference_type end_value = begin_value + 1;
 
-    /// iterator as signed integer type
-    difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
-                                              };
+        /// iterator as signed integer type
+        difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
+    };
 
     /*!
     @brief an iterator value
@@ -8359,104 +8398,104 @@ class basic_json
 
         /// create an uninitialized internal_iterator
         internal_iterator() noexcept
-        : object_iterator(), array_iterator(), primitive_iterator()
-    {}
+            : object_iterator(), array_iterator(), primitive_iterator()
+        {}
     };
 
     /// proxy class for the iterator_wrapper functions
     template<typename IteratorType>
     class iteration_proxy
     {
-        private:
+      private:
         /// helper class for iteration
         class iteration_proxy_internal
         {
-            private:
+          private:
             /// the iterator
             IteratorType anchor;
             /// an index for arrays (used to create key names)
             size_t array_index = 0;
 
-            public:
+          public:
             explicit iteration_proxy_internal(IteratorType it) noexcept
-            : anchor(it)
-    {}
+                : anchor(it)
+            {}
 
-    /// dereference operator (needed for range-based for)
-    iteration_proxy_internal& operator*()
-    {
-        return *this;
-    }
-
-    /// increment operator (needed for range-based for)
-    iteration_proxy_internal& operator++()
-    {
-        ++anchor;
-        ++array_index;
-
-        return *this;
-    }
-
-    /// inequality operator (needed for range-based for)
-    bool operator!= (const iteration_proxy_internal& o) const
-    {
-        return anchor != o.anchor;
-    }
-
-    /// return key of the iterator
-    typename basic_json::string_t key() const
-    {
-        assert(anchor.m_object != nullptr);
-
-        switch (anchor.m_object->type())
-        {
-            // use integer array index as key
-            case value_t::array:
+            /// dereference operator (needed for range-based for)
+            iteration_proxy_internal& operator*()
             {
-                return std::to_string(array_index);
+                return *this;
             }
 
-            // use key from the object
-            case value_t::object:
+            /// increment operator (needed for range-based for)
+            iteration_proxy_internal& operator++()
             {
-                return anchor.key();
+                ++anchor;
+                ++array_index;
+
+                return *this;
             }
 
-            // use an empty key for all primitive types
-            default:
+            /// inequality operator (needed for range-based for)
+            bool operator!= (const iteration_proxy_internal& o) const
             {
-                return "";
+                return anchor != o.anchor;
             }
-        }
-    }
 
-    /// return value of the iterator
-    typename IteratorType::reference value() const
-    {
-        return anchor.value();
-    }
+            /// return key of the iterator
+            typename basic_json::string_t key() const
+            {
+                assert(anchor.m_object != nullptr);
+
+                switch (anchor.m_object->type())
+                {
+                    // use integer array index as key
+                    case value_t::array:
+                    {
+                        return std::to_string(array_index);
+                    }
+
+                    // use key from the object
+                    case value_t::object:
+                    {
+                        return anchor.key();
+                    }
+
+                    // use an empty key for all primitive types
+                    default:
+                    {
+                        return "";
+                    }
+                }
+            }
+
+            /// return value of the iterator
+            typename IteratorType::reference value() const
+            {
+                return anchor.value();
+            }
         };
 
-    /// the container to iterate
-    typename IteratorType::reference container;
+        /// the container to iterate
+        typename IteratorType::reference container;
 
-    public:
-    /// construct iteration proxy from a container
-    explicit iteration_proxy(typename IteratorType::reference cont)
-    : container(cont)
-    {}
+      public:
+        /// construct iteration proxy from a container
+        explicit iteration_proxy(typename IteratorType::reference cont)
+            : container(cont)
+        {}
 
-    /// return iterator begin (needed for range-based for)
-    iteration_proxy_internal begin() noexcept
-    {
-        return iteration_proxy_internal(container.begin());
-    }
+        /// return iterator begin (needed for range-based for)
+        iteration_proxy_internal begin() noexcept
+        {
+            return iteration_proxy_internal(container.begin());
+        }
 
-    /// return iterator end (needed for range-based for)
-    iteration_proxy_internal end() noexcept
-    {
-        return iteration_proxy_internal(container.end());
-    }
+        /// return iterator end (needed for range-based for)
+        iteration_proxy_internal end() noexcept
+        {
+            return iteration_proxy_internal(container.end());
+        }
     };
 
   public:
@@ -8480,7 +8519,7 @@ class basic_json
     @since version 1.0.0, simplified in version 2.0.9
     */
     template<typename U>
-  class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
+    class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
     {
         /// allow basic_json to access private members
         friend class basic_json;
@@ -8490,19 +8529,19 @@ class basic_json
                       or std::is_same<U, const basic_json>::value,
                       "iter_impl only accepts (const) basic_json");
 
-        public:
+      public:
         /// the type of the values when the iterator is dereferenced
         using value_type = typename basic_json::value_type;
         /// a type to represent differences between iterators
         using difference_type = typename basic_json::difference_type;
         /// defines a pointer to the type iterated over (value_type)
         using pointer = typename std::conditional<std::is_const<U>::value,
-                typename basic_json::const_pointer,
-                typename basic_json::pointer>::type;
+              typename basic_json::const_pointer,
+              typename basic_json::pointer>::type;
         /// defines a reference to the type iterated over (value_type)
         using reference = typename std::conditional<std::is_const<U>::value,
-                typename basic_json::const_reference,
-                typename basic_json::reference>::type;
+              typename basic_json::const_reference,
+              typename basic_json::reference>::type;
         /// the category of the iterator
         using iterator_category = std::bidirectional_iterator_tag;
 
@@ -8516,566 +8555,566 @@ class basic_json
         @post The iterator is initialized; i.e. `m_object != nullptr`.
         */
         explicit iter_impl(pointer object) noexcept
-        : m_object(object)
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
+            : m_object(object)
         {
-            case basic_json::value_t::object:
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
             {
-                m_it.object_iterator = typename object_t::iterator();
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                m_it.array_iterator = typename array_t::iterator();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator = primitive_iterator_t();
-                break;
-            }
-        }
-    }
-
-    /*
-    Use operator `const_iterator` instead of `const_iterator(const iterator&
-    other) noexcept` to avoid two class definitions for @ref iterator and
-    @ref const_iterator.
-
-    This function is only called if this class is an @ref iterator. If this
-    class is a @ref const_iterator this function is not called.
-    */
-    operator const_iterator() const
-    {
-        const_iterator ret;
-
-        if (m_object)
-        {
-            ret.m_object = m_object;
-            ret.m_it = m_it;
-        }
-
-        return ret;
-    }
-
-    /*!
-    @brief copy constructor
-    @param[in] other  iterator to copy from
-    @note It is not checked whether @a other is initialized.
-    */
-    iter_impl(const iter_impl& other) noexcept
-    : m_object(other.m_object), m_it(other.m_it)
-    {}
-
-    /*!
-    @brief copy assignment
-    @param[in,out] other  iterator to copy from
-    @note It is not checked whether @a other is initialized.
-    */
-    iter_impl& operator=(iter_impl other) noexcept(
-        std::is_nothrow_move_constructible<pointer>::value and
-        std::is_nothrow_move_assignable<pointer>::value and
-        std::is_nothrow_move_constructible<internal_iterator>::value and
-        std::is_nothrow_move_assignable<internal_iterator>::value
-                                       )
-    {
-        std::swap(m_object, other.m_object);
-        std::swap(m_it, other.m_it);
-        return *this;
-    }
-
-    private:
-    /*!
-    @brief set the iterator to the first value
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    void set_begin() noexcept
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                m_it.object_iterator = m_object->m_value.object->begin();
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                m_it.array_iterator = m_object->m_value.array->begin();
-                break;
-            }
-
-            case basic_json::value_t::null:
-            {
-                // set to end so begin()==end() is true: null is empty
-                m_it.primitive_iterator.set_end();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator.set_begin();
-                break;
-            }
-        }
-    }
-
-    /*!
-    @brief set the iterator past the last value
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    void set_end() noexcept
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                m_it.object_iterator = m_object->m_value.object->end();
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                m_it.array_iterator = m_object->m_value.array->end();
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator.set_end();
-                break;
-            }
-        }
-    }
-
-    public:
-    /*!
-    @brief return a reference to the value pointed to by the iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference operator*() const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                assert(m_it.object_iterator != m_object->m_value.object->end());
-                return m_it.object_iterator->second;
-            }
-
-            case basic_json::value_t::array:
-            {
-                assert(m_it.array_iterator != m_object->m_value.array->end());
-                return *m_it.array_iterator;
-            }
-
-            case basic_json::value_t::null:
-            {
-                    JSON_THROW(std::out_of_range("cannot get value"));
-            }
-
-            default:
-            {
-                if (m_it.primitive_iterator.is_begin())
+                case basic_json::value_t::object:
                 {
-                    return *m_object;
+                    m_it.object_iterator = typename object_t::iterator();
+                    break;
                 }
 
-                    JSON_THROW(std::out_of_range("cannot get value"));
-            }
-        }
-    }
-
-    /*!
-    @brief dereference the iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    pointer operator->() const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                assert(m_it.object_iterator != m_object->m_value.object->end());
-                return &(m_it.object_iterator->second);
-            }
-
-            case basic_json::value_t::array:
-            {
-                assert(m_it.array_iterator != m_object->m_value.array->end());
-                return &*m_it.array_iterator;
-            }
-
-            default:
-            {
-                if (m_it.primitive_iterator.is_begin())
+                case basic_json::value_t::array:
                 {
-                    return m_object;
+                    m_it.array_iterator = typename array_t::iterator();
+                    break;
                 }
 
+                default:
+                {
+                    m_it.primitive_iterator = primitive_iterator_t();
+                    break;
+                }
+            }
+        }
+
+        /*
+        Use operator `const_iterator` instead of `const_iterator(const iterator&
+        other) noexcept` to avoid two class definitions for @ref iterator and
+        @ref const_iterator.
+
+        This function is only called if this class is an @ref iterator. If this
+        class is a @ref const_iterator this function is not called.
+        */
+        operator const_iterator() const
+        {
+            const_iterator ret;
+
+            if (m_object)
+            {
+                ret.m_object = m_object;
+                ret.m_it = m_it;
+            }
+
+            return ret;
+        }
+
+        /*!
+        @brief copy constructor
+        @param[in] other  iterator to copy from
+        @note It is not checked whether @a other is initialized.
+        */
+        iter_impl(const iter_impl& other) noexcept
+            : m_object(other.m_object), m_it(other.m_it)
+        {}
+
+        /*!
+        @brief copy assignment
+        @param[in,out] other  iterator to copy from
+        @note It is not checked whether @a other is initialized.
+        */
+        iter_impl& operator=(iter_impl other) noexcept(
+            std::is_nothrow_move_constructible<pointer>::value and
+            std::is_nothrow_move_assignable<pointer>::value and
+            std::is_nothrow_move_constructible<internal_iterator>::value and
+            std::is_nothrow_move_assignable<internal_iterator>::value
+        )
+        {
+            std::swap(m_object, other.m_object);
+            std::swap(m_it, other.m_it);
+            return *this;
+        }
+
+      private:
+        /*!
+        @brief set the iterator to the first value
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        void set_begin() noexcept
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = m_object->m_value.object->begin();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = m_object->m_value.array->begin();
+                    break;
+                }
+
+                case basic_json::value_t::null:
+                {
+                    // set to end so begin()==end() is true: null is empty
+                    m_it.primitive_iterator.set_end();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator.set_begin();
+                    break;
+                }
+            }
+        }
+
+        /*!
+        @brief set the iterator past the last value
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        void set_end() noexcept
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = m_object->m_value.object->end();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = m_object->m_value.array->end();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator.set_end();
+                    break;
+                }
+            }
+        }
+
+      public:
+        /*!
+        @brief return a reference to the value pointed to by the iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference operator*() const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    assert(m_it.object_iterator != m_object->m_value.object->end());
+                    return m_it.object_iterator->second;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    assert(m_it.array_iterator != m_object->m_value.array->end());
+                    return *m_it.array_iterator;
+                }
+
+                case basic_json::value_t::null:
+                {
                     JSON_THROW(std::out_of_range("cannot get value"));
-            }
-        }
-    }
+                }
 
-    /*!
-    @brief post-increment (it++)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator++(int)
-    {
-        auto result = *this;
-        ++(*this);
-        return result;
-    }
+                default:
+                {
+                    if (m_it.primitive_iterator.is_begin())
+                    {
+                        return *m_object;
+                    }
 
-    /*!
-    @brief pre-increment (++it)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator++()
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                std::advance(m_it.object_iterator, 1);
-                break;
-            }
-
-            case basic_json::value_t::array:
-            {
-                std::advance(m_it.array_iterator, 1);
-                break;
-            }
-
-            default:
-            {
-                ++m_it.primitive_iterator;
-                break;
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
             }
         }
 
-        return *this;
-    }
-
-    /*!
-    @brief post-decrement (it--)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator--(int)
-    {
-        auto result = *this;
-        --(*this);
-        return result;
-    }
-
-    /*!
-    @brief pre-decrement (--it)
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator--()
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
+        /*!
+        @brief dereference the iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        pointer operator->() const
         {
-            case basic_json::value_t::object:
-            {
-                std::advance(m_it.object_iterator, -1);
-                break;
-            }
+            assert(m_object != nullptr);
 
-            case basic_json::value_t::array:
+            switch (m_object->m_type)
             {
-                std::advance(m_it.array_iterator, -1);
-                break;
-            }
+                case basic_json::value_t::object:
+                {
+                    assert(m_it.object_iterator != m_object->m_value.object->end());
+                    return &(m_it.object_iterator->second);
+                }
 
-            default:
-            {
-                --m_it.primitive_iterator;
-                break;
+                case basic_json::value_t::array:
+                {
+                    assert(m_it.array_iterator != m_object->m_value.array->end());
+                    return &*m_it.array_iterator;
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator.is_begin())
+                    {
+                        return m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
             }
         }
 
-        return *this;
-    }
-
-    /*!
-    @brief  comparison: equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator==(const iter_impl& other) const
-    {
-        // if objects are not the same, the comparison is undefined
-        if (m_object != other.m_object)
+        /*!
+        @brief post-increment (it++)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator++(int)
         {
+            auto result = *this;
+            ++(*this);
+            return result;
+        }
+
+        /*!
+        @brief pre-increment (++it)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator++()
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    std::advance(m_it.object_iterator, 1);
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, 1);
+                    break;
+                }
+
+                default:
+                {
+                    ++m_it.primitive_iterator;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief post-decrement (it--)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator--(int)
+        {
+            auto result = *this;
+            --(*this);
+            return result;
+        }
+
+        /*!
+        @brief pre-decrement (--it)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator--()
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    std::advance(m_it.object_iterator, -1);
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, -1);
+                    break;
+                }
+
+                default:
+                {
+                    --m_it.primitive_iterator;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief  comparison: equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator==(const iter_impl& other) const
+        {
+            // if objects are not the same, the comparison is undefined
+            if (m_object != other.m_object)
+            {
                 JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
-        }
-
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                return (m_it.object_iterator == other.m_it.object_iterator);
             }
 
-            case basic_json::value_t::array:
-            {
-                return (m_it.array_iterator == other.m_it.array_iterator);
-            }
+            assert(m_object != nullptr);
 
-            default:
+            switch (m_object->m_type)
             {
-                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+                case basic_json::value_t::object:
+                {
+                    return (m_it.object_iterator == other.m_it.object_iterator);
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return (m_it.array_iterator == other.m_it.array_iterator);
+                }
+
+                default:
+                {
+                    return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+                }
             }
         }
-    }
 
-    /*!
-    @brief  comparison: not equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator!=(const iter_impl& other) const
-    {
-        return not operator==(other);
-    }
-
-    /*!
-    @brief  comparison: smaller
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator<(const iter_impl& other) const
-    {
-        // if objects are not the same, the comparison is undefined
-        if (m_object != other.m_object)
+        /*!
+        @brief  comparison: not equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator!=(const iter_impl& other) const
         {
+            return not operator==(other);
+        }
+
+        /*!
+        @brief  comparison: smaller
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator<(const iter_impl& other) const
+        {
+            // if objects are not the same, the comparison is undefined
+            if (m_object != other.m_object)
+            {
                 JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
-        }
+            }
 
-        assert(m_object != nullptr);
+            assert(m_object != nullptr);
 
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
+            switch (m_object->m_type)
             {
+                case basic_json::value_t::object:
+                {
                     JSON_THROW(std::domain_error("cannot compare order of object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                return (m_it.array_iterator < other.m_it.array_iterator);
-            }
-
-            default:
-            {
-                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
-            }
-        }
-    }
-
-    /*!
-    @brief  comparison: less than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator<=(const iter_impl& other) const
-    {
-        return not other.operator < (*this);
-    }
-
-    /*!
-    @brief  comparison: greater than
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator>(const iter_impl& other) const
-    {
-        return not operator<=(other);
-    }
-
-    /*!
-    @brief  comparison: greater than or equal
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    bool operator>=(const iter_impl& other) const
-    {
-        return not operator<(other);
-    }
-
-    /*!
-    @brief  add to iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator+=(difference_type i)
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                std::advance(m_it.array_iterator, i);
-                break;
-            }
-
-            default:
-            {
-                m_it.primitive_iterator += i;
-                break;
-            }
-        }
-
-        return *this;
-    }
-
-    /*!
-    @brief  subtract from iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl& operator-=(difference_type i)
-    {
-        return operator+=(-i);
-    }
-
-    /*!
-    @brief  add to iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator+(difference_type i)
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
-
-    /*!
-    @brief  subtract from iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    iter_impl operator-(difference_type i)
-    {
-        auto result = *this;
-        result -= i;
-        return result;
-    }
-
-    /*!
-    @brief  return difference
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    difference_type operator-(const iter_impl& other) const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                return m_it.array_iterator - other.m_it.array_iterator;
-            }
-
-            default:
-            {
-                return m_it.primitive_iterator - other.m_it.primitive_iterator;
-            }
-        }
-    }
-
-    /*!
-    @brief  access to successor
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference operator[](difference_type n) const
-    {
-        assert(m_object != nullptr);
-
-        switch (m_object->m_type)
-        {
-            case basic_json::value_t::object:
-            {
-                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
-            }
-
-            case basic_json::value_t::array:
-            {
-                return *std::next(m_it.array_iterator, n);
-            }
-
-            case basic_json::value_t::null:
-            {
-                    JSON_THROW(std::out_of_range("cannot get value"));
-            }
-
-            default:
-            {
-                if (m_it.primitive_iterator.get_value() == -n)
-                {
-                    return *m_object;
                 }
 
-                    JSON_THROW(std::out_of_range("cannot get value"));
+                case basic_json::value_t::array:
+                {
+                    return (m_it.array_iterator < other.m_it.array_iterator);
+                }
+
+                default:
+                {
+                    return (m_it.primitive_iterator < other.m_it.primitive_iterator);
+                }
             }
         }
-    }
 
-    /*!
-    @brief  return the key of an object iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    typename object_t::key_type key() const
-    {
-        assert(m_object != nullptr);
-
-        if (m_object->is_object())
+        /*!
+        @brief  comparison: less than or equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator<=(const iter_impl& other) const
         {
-            return m_it.object_iterator->first;
+            return not other.operator < (*this);
         }
 
+        /*!
+        @brief  comparison: greater than
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator>(const iter_impl& other) const
+        {
+            return not operator<=(other);
+        }
+
+        /*!
+        @brief  comparison: greater than or equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator>=(const iter_impl& other) const
+        {
+            return not operator<(other);
+        }
+
+        /*!
+        @brief  add to iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator+=(difference_type i)
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, i);
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator += i;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief  subtract from iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator-=(difference_type i)
+        {
+            return operator+=(-i);
+        }
+
+        /*!
+        @brief  add to iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator+(difference_type i)
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
+
+        /*!
+        @brief  subtract from iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator-(difference_type i)
+        {
+            auto result = *this;
+            result -= i;
+            return result;
+        }
+
+        /*!
+        @brief  return difference
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        difference_type operator-(const iter_impl& other) const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return m_it.array_iterator - other.m_it.array_iterator;
+                }
+
+                default:
+                {
+                    return m_it.primitive_iterator - other.m_it.primitive_iterator;
+                }
+            }
+        }
+
+        /*!
+        @brief  access to successor
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference operator[](difference_type n) const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return *std::next(m_it.array_iterator, n);
+                }
+
+                case basic_json::value_t::null:
+                {
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator.get_value() == -n)
+                    {
+                        return *m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+            }
+        }
+
+        /*!
+        @brief  return the key of an object iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        typename object_t::key_type key() const
+        {
+            assert(m_object != nullptr);
+
+            if (m_object->is_object())
+            {
+                return m_it.object_iterator->first;
+            }
+
             JSON_THROW(std::domain_error("cannot use key() for non-object iterators"));
-    }
+        }
 
-    /*!
-    @brief  return the value of an iterator
-    @pre The iterator is initialized; i.e. `m_object != nullptr`.
-    */
-    reference value() const
-    {
-        return operator*();
-    }
+        /*!
+        @brief  return the value of an iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference value() const
+        {
+            return operator*();
+        }
 
-    private:
-    /// associated JSON instance
-    pointer m_object = nullptr;
-    /// the actual iterator of the associated instance
-    internal_iterator m_it = internal_iterator();
-                       };
+      private:
+        /// associated JSON instance
+        pointer m_object = nullptr;
+        /// the actual iterator of the associated instance
+        internal_iterator m_it = internal_iterator();
+    };
 
     /*!
     @brief a template for a reverse iterator class
@@ -9095,9 +9134,9 @@ class basic_json
     @since version 1.0.0
     */
     template<typename Base>
-  class json_reverse_iterator : public std::reverse_iterator<Base>
+    class json_reverse_iterator : public std::reverse_iterator<Base>
     {
-        public:
+      public:
         /// shortcut to the reverse iterator adaptor
         using base_iterator = std::reverse_iterator<Base>;
         /// the reference type for the pointed-to element
@@ -9105,89 +9144,89 @@ class basic_json
 
         /// create reverse iterator from iterator
         json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
-        : base_iterator(it)
-    {}
+            : base_iterator(it)
+        {}
 
-    /// create reverse iterator from base class
-    json_reverse_iterator(const base_iterator& it) noexcept
-    : base_iterator(it)
-    {}
+        /// create reverse iterator from base class
+        json_reverse_iterator(const base_iterator& it) noexcept
+            : base_iterator(it)
+        {}
 
-    /// post-increment (it++)
-    json_reverse_iterator operator++(int)
-    {
-        return base_iterator::operator++(1);
-    }
+        /// post-increment (it++)
+        json_reverse_iterator operator++(int)
+        {
+            return base_iterator::operator++(1);
+        }
 
-    /// pre-increment (++it)
-    json_reverse_iterator& operator++()
-    {
-        base_iterator::operator++();
-        return *this;
-    }
+        /// pre-increment (++it)
+        json_reverse_iterator& operator++()
+        {
+            base_iterator::operator++();
+            return *this;
+        }
 
-    /// post-decrement (it--)
-    json_reverse_iterator operator--(int)
-    {
-        return base_iterator::operator--(1);
-    }
+        /// post-decrement (it--)
+        json_reverse_iterator operator--(int)
+        {
+            return base_iterator::operator--(1);
+        }
 
-    /// pre-decrement (--it)
-    json_reverse_iterator& operator--()
-    {
-        base_iterator::operator--();
-        return *this;
-    }
+        /// pre-decrement (--it)
+        json_reverse_iterator& operator--()
+        {
+            base_iterator::operator--();
+            return *this;
+        }
 
-    /// add to iterator
-    json_reverse_iterator& operator+=(difference_type i)
-    {
-        base_iterator::operator+=(i);
-        return *this;
-    }
+        /// add to iterator
+        json_reverse_iterator& operator+=(difference_type i)
+        {
+            base_iterator::operator+=(i);
+            return *this;
+        }
 
-    /// add to iterator
-    json_reverse_iterator operator+(difference_type i) const
-    {
-        auto result = *this;
-        result += i;
-        return result;
-    }
+        /// add to iterator
+        json_reverse_iterator operator+(difference_type i) const
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
 
-    /// subtract from iterator
-    json_reverse_iterator operator-(difference_type i) const
-    {
-        auto result = *this;
-        result -= i;
-        return result;
-    }
+        /// subtract from iterator
+        json_reverse_iterator operator-(difference_type i) const
+        {
+            auto result = *this;
+            result -= i;
+            return result;
+        }
 
-    /// return difference
-    difference_type operator-(const json_reverse_iterator& other) const
-    {
-        return this->base() - other.base();
-    }
+        /// return difference
+        difference_type operator-(const json_reverse_iterator& other) const
+        {
+            return this->base() - other.base();
+        }
 
-    /// access to successor
-    reference operator[](difference_type n) const
-    {
-        return *(this->operator+(n));
-    }
+        /// access to successor
+        reference operator[](difference_type n) const
+        {
+            return *(this->operator+(n));
+        }
 
-    /// return the key of an object iterator
-    typename object_t::key_type key() const
-    {
-        auto it = --this->base();
-        return it.key();
-    }
+        /// return the key of an object iterator
+        typename object_t::key_type key() const
+        {
+            auto it = --this->base();
+            return it.key();
+        }
 
-    /// return the value of an iterator
-    reference value() const
-    {
-        auto it = --this->base();
-        return it.operator * ();
-    }
-                                                   };
+        /// return the value of an iterator
+        reference value() const
+        {
+            auto it = --this->base();
+            return it.operator * ();
+        }
+    };
 
 
   private:
@@ -9204,761 +9243,761 @@ class basic_json
     */
     class lexer
     {
-        public:
+      public:
         /// token types for the parser
         enum class token_type
-    {
-        uninitialized,   ///< indicating the scanner is uninitialized
-        literal_true,    ///< the `true` literal
-        literal_false,   ///< the `false` literal
-        literal_null,    ///< the `null` literal
-        value_string,    ///< a string -- use get_string() for actual value
-        value_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
-    using lexer_char_t = unsigned char;
-
-    /// a lexer from a buffer with given length
-    lexer(const lexer_char_t* buff, const size_t len) noexcept
-    : m_content(buff)
-    {
-        assert(m_content != nullptr);
-        m_start = m_cursor = m_content;
-        m_limit = m_content + len;
-    }
-
-    /// a lexer from an input stream
-    explicit lexer(std::istream& s)
-    : m_stream(&s), m_line_buffer()
-    {
-        // immediately abort if stream is erroneous
-        if (s.fail())
         {
+            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
+        using lexer_char_t = unsigned char;
+
+        /// a lexer from a buffer with given length
+        lexer(const lexer_char_t* buff, const size_t len) noexcept
+            : m_content(buff)
+        {
+            assert(m_content != nullptr);
+            m_start = m_cursor = m_content;
+            m_limit = m_content + len;
+        }
+
+        /// a lexer from an input stream
+        explicit lexer(std::istream& s)
+            : m_stream(&s), m_line_buffer()
+        {
+            // immediately abort if stream is erroneous
+            if (s.fail())
+            {
                 JSON_THROW(std::invalid_argument("stream error"));
-        }
-
-        // fill buffer
-        fill_line_buffer();
-
-        // skip UTF-8 byte-order mark
-        if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
-        {
-            m_line_buffer[0] = ' ';
-            m_line_buffer[1] = ' ';
-            m_line_buffer[2] = ' ';
-        }
-    }
-
-    // switch off unwanted functions (due to pointer members)
-    lexer() = delete;
-    lexer(const lexer&) = delete;
-    lexer operator=(const lexer&) = delete;
-
-    /*!
-    @brief create a string from one or two Unicode code points
-
-    There are two cases: (1) @a codepoint1 is in the Basic Multilingual
-    Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
-    @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
-    represent a code point above U+FFFF.
-
-    @param[in] codepoint1  the code point (can be high surrogate)
-    @param[in] codepoint2  the code point (can be low surrogate or 0)
-
-    @return string representation of the code point; the length of the
-    result string is between 1 and 4 characters.
-
-    @throw std::out_of_range if code point is > 0x10ffff; example: `"code
-    points above 0x10FFFF are invalid"`
-    @throw std::invalid_argument if the low surrogate is invalid; example:
-    `""missing or wrong low surrogate""`
-
-    @complexity Constant.
-
-    @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
-    */
-    static string_t to_unicode(const std::size_t codepoint1,
-                               const std::size_t codepoint2 = 0)
-    {
-        // calculate the code point from the given code points
-        std::size_t codepoint = codepoint1;
-
-        // check if codepoint1 is a high surrogate
-        if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
-        {
-            // check if codepoint2 is a low surrogate
-            if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
-            {
-                codepoint =
-                // high surrogate occupies the most significant 22 bits
-                (codepoint1 << 10)
-                 // low surrogate occupies the least significant 15 bits
-                 + codepoint2
-                 // there is still the 0xD800, 0xDC00 and 0x10000 noise
-                 // in the result so we have to subtract with:
-                 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
-                 - 0x35FDC00;
             }
-            else
+
+            // fill buffer
+            fill_line_buffer();
+
+            // skip UTF-8 byte-order mark
+            if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
             {
-                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
+                m_line_buffer[0] = ' ';
+                m_line_buffer[1] = ' ';
+                m_line_buffer[2] = ' ';
             }
         }
 
-        string_t result;
+        // switch off unwanted functions (due to pointer members)
+        lexer() = delete;
+        lexer(const lexer&) = delete;
+        lexer operator=(const lexer&) = delete;
 
-        if (codepoint < 0x80)
-        {
-            // 1-byte characters: 0xxxxxxx (ASCII)
-            result.append(1, static_cast<typename string_t::value_type>(codepoint));
-        }
-        else if (codepoint <= 0x7ff)
-        {
-            // 2-byte characters: 110xxxxx 10xxxxxx
-            result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
-        }
-        else if (codepoint <= 0xffff)
-        {
-            // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
-            result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
-        }
-        else if (codepoint <= 0x10ffff)
-        {
-            // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-            result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
-            result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
-        }
-        else
-        {
-                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
-        }
+        /*!
+        @brief create a string from one or two Unicode code points
 
-        return result;
-    }
+        There are two cases: (1) @a codepoint1 is in the Basic Multilingual
+        Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
+        @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
+        represent a code point above U+FFFF.
 
-    /// return name of values of type token_type (only used for errors)
-    static std::string token_type_name(const token_type t)
-    {
-        switch (t)
+        @param[in] codepoint1  the code point (can be high surrogate)
+        @param[in] codepoint2  the code point (can be low surrogate or 0)
+
+        @return string representation of the code point; the length of the
+        result string is between 1 and 4 characters.
+
+        @throw std::out_of_range if code point is > 0x10ffff; example: `"code
+        points above 0x10FFFF are invalid"`
+        @throw std::invalid_argument if the low surrogate is invalid; example:
+        `""missing or wrong low surrogate""`
+
+        @complexity Constant.
+
+        @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
+        */
+        static string_t to_unicode(const std::size_t codepoint1,
+                                   const std::size_t codepoint2 = 0)
         {
-            case token_type::uninitialized:
-                return "<uninitialized>";
-            case token_type::literal_true:
-                return "true literal";
-            case token_type::literal_false:
-                return "false literal";
-            case token_type::literal_null:
-                return "null literal";
-            case token_type::value_string:
-                return "string literal";
-            case token_type::value_number:
-                return "number literal";
-            case token_type::begin_array:
-                return "'['";
-            case token_type::begin_object:
-                return "'{'";
-            case token_type::end_array:
-                return "']'";
-            case token_type::end_object:
-                return "'}'";
-            case token_type::name_separator:
-                return "':'";
-            case token_type::value_separator:
-                return "','";
-            case token_type::parse_error:
-                return "<parse error>";
-            case token_type::end_of_input:
-                return "end of input";
-            default:
+            // calculate the code point from the given code points
+            std::size_t codepoint = codepoint1;
+
+            // check if codepoint1 is a high surrogate
+            if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
             {
-                // catch non-enum values
-                return "unknown token"; // LCOV_EXCL_LINE
-            }
-        }
-    }
-
-    /*!
-    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 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
-
-    @complexity Linear in the length of the input.\n
-
-    Proposition: The loop below will always terminate for finite input.\n
-
-    Proof (by contradiction): Assume a finite input. To loop forever, the
-    loop must never hit code with a `break` statement. The only code
-    snippets without a `break` statement are the continue statements for
-    whitespace and byte-order-marks. To loop forever, the input must be an
-    infinite sequence of whitespace or byte-order-marks. This contradicts
-    the assumption of finite input, q.e.d.
-    */
-    token_type scan()
-    {
-        while (true)
-        {
-            // pointer for backtracking information
-            m_marker = nullptr;
-
-            // remember the begin of the token
-            m_start = m_cursor;
-            assert(m_start != nullptr);
-
-            /*!re2c
-                re2c:define:YYCTYPE      = lexer_char_t;
-                re2c:define:YYCURSOR     = m_cursor;
-                re2c:define:YYLIMIT      = m_limit;
-                re2c:define:YYMARKER     = m_marker;
-                re2c:define:YYFILL       = "fill_line_buffer(@@); // LCOV_EXCL_LINE";
-                re2c:define:YYFILL:naked = 1;
-                re2c:yyfill:enable       = 1;
-                re2c:indent:string       = "    ";
-                re2c:indent:top          = 1;
-                re2c:labelprefix         = "basic_json_parser_";
-
-                // ignore whitespace
-                ws = [ \t\n\r]+;
-                ws   { continue; }
-
-                // structural characters
-                "[" { last_token_type = token_type::begin_array; break; }
-                "]" { last_token_type = token_type::end_array; break; }
-                "{" { last_token_type = token_type::begin_object; break; }
-                "}" { last_token_type = token_type::end_object; break; }
-                "," { last_token_type = token_type::value_separator; break; }
-                ":" { last_token_type = token_type::name_separator; break; }
-
-                // literal names
-                "null"  { last_token_type = token_type::literal_null; break; }
-                "true"  { last_token_type = token_type::literal_true; break; }
-                "false" { last_token_type = token_type::literal_false; break; }
-
-                // number
-                decimal_point = ".";
-                digit         = [0-9];
-                digit_1_9     = [1-9];
-                e             = "e" | "E";
-                minus         = "-";
-                plus          = "+";
-                zero          = "0";
-                exp           = e (minus | plus)? digit+;
-                frac          = decimal_point digit+;
-                int           = (zero | digit_1_9 digit*);
-                number        = minus? int frac? exp?;
-                number        { last_token_type = token_type::value_number; break; }
-
-                // string
-                quotation_mark  = "\"";
-                escape          = "\\";
-                unescaped       = [^"\\\x00-\x1f];
-                single_escaped  = "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t";
-                unicode_escaped = "u" [0-9a-fA-F]{4};
-                escaped         = escape (single_escaped | unicode_escaped);
-                char            = unescaped | escaped;
-                string          = quotation_mark char* quotation_mark;
-                string          { last_token_type = token_type::value_string; break; }
-
-                // end of file
-                "\x00"         { last_token_type = token_type::end_of_input; break; }
-
-                // anything else is an error
-                *              { last_token_type = token_type::parse_error; break; }
-            */
-        }
-
-        return last_token_type;
-    }
-
-    /*!
-    @brief append data from the stream to the line buffer
-
-    This function is called by the scan() function when the end of the
-    buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
-    incremented without leaving the limits of the line buffer. Note re2c
-    decides when to call this function.
-
-    If the lexer reads from contiguous storage, there is no trailing null
-    byte. Therefore, this function must make sure to add these padding
-    null bytes.
-
-    If the lexer reads from an input stream, this function reads the next
-    line of the input.
-
-    @pre
-        p p p p p p u u u u u x . . . . . .
-        ^           ^       ^   ^
-        m_content   m_start |   m_limit
-                            m_cursor
-
-    @post
-        u u u u u x x x x x x x . . . . . .
-        ^       ^               ^
-        |       m_cursor        m_limit
-        m_start
-        m_content
-    */
-    void fill_line_buffer(size_t n = 0)
-    {
-        // if line buffer is used, m_content points to its data
-        assert(m_line_buffer.empty()
-               or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
-
-        // if line buffer is used, m_limit is set past the end of its data
-        assert(m_line_buffer.empty()
-               or m_limit == m_content + m_line_buffer.size());
-
-        // pointer relationships
-        assert(m_content <= m_start);
-        assert(m_start <= m_cursor);
-        assert(m_cursor <= m_limit);
-        assert(m_marker == nullptr or m_marker  <= m_limit);
-
-        // number of processed characters (p)
-            const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
-        // offset for m_marker wrt. to m_start
-        const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
-        // number of unprocessed characters (u)
-        const auto offset_cursor = m_cursor - m_start;
-
-        // no stream is used or end of file is reached
-        if (m_stream == nullptr or m_stream->eof())
-        {
-            // m_start may or may not be pointing into m_line_buffer at
-            // this point. We trust the standand library to do the right
-            // thing. See http://stackoverflow.com/q/28142011/266378
-            m_line_buffer.assign(m_start, m_limit);
-
-            // append n characters to make sure that there is sufficient
-            // space between m_cursor and m_limit
-            m_line_buffer.append(1, '\x00');
-            if (n > 0)
-            {
-                m_line_buffer.append(n - 1, '\x01');
-            }
-        }
-        else
-        {
-            // delete processed characters from line buffer
-            m_line_buffer.erase(0, num_processed_chars);
-            // read next line from input stream
-            m_line_buffer_tmp.clear();
-            std::getline(*m_stream, m_line_buffer_tmp, '\n');
-
-            // add line with newline symbol to the line buffer
-            m_line_buffer += m_line_buffer_tmp;
-            m_line_buffer.push_back('\n');
-        }
-
-        // set pointers
-        m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
-        assert(m_content != nullptr);
-        m_start  = m_content;
-        m_marker = m_start + offset_marker;
-        m_cursor = m_start + offset_cursor;
-        m_limit  = m_start + m_line_buffer.size();
-    }
-
-    /// return string representation of last read token
-    string_t get_token_string() const
-    {
-        assert(m_start != nullptr);
-        return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
-                        static_cast<size_t>(m_cursor - m_start));
-    }
-
-    /*!
-    @brief return string value for string tokens
-
-    The function iterates the characters between the opening and closing
-    quotes of the string value. The complete string is the range
-    [m_start,m_cursor). Consequently, we iterate from m_start+1 to
-    m_cursor-1.
-
-    We differentiate two cases:
-
-    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., `"\\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.
-
-    @pre `m_cursor - m_start >= 2`, meaning the length of the last token
-    is at least 2 bytes which is trivially true for any string (which
-    consists of at least two quotes).
-
-        " c1 c2 c3 ... "
-        ^                ^
-        m_start          m_cursor
-
-    @complexity Linear in the length of the string.\n
-
-    Lemma: The loop body will always terminate.\n
-
-    Proof (by contradiction): Assume the loop body does not terminate. As
-    the loop body does not contain another loop, one of the called
-    functions must never return. The called functions are `std::strtoul`
-    and to_unicode. Neither function can loop forever, so the loop body
-    will never loop forever which contradicts the assumption that the loop
-    body does not terminate, q.e.d.\n
-
-    Lemma: The loop condition for the for loop is eventually false.\n
-
-    Proof (by contradiction): Assume the loop does not terminate. Due to
-    the above lemma, this can only be due to a tautological loop
-    condition; that is, the loop condition i < m_cursor - 1 must always be
-    true. Let x be the change of i for any loop iteration. Then
-    m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
-    can be rephrased to m_cursor - m_start - 2 > x. With the
-    precondition, we x <= 0, meaning that the loop condition holds
-    indefinitly if i is always decreased. However, observe that the value
-    of i is strictly increasing with each iteration, as it is incremented
-    by 1 in the iteration expression and never decremented inside the loop
-    body. Hence, the loop condition will eventually be false which
-    contradicts the assumption that the loop condition is a tautology,
-    q.e.d.
-
-    @return string value of current token without opening and closing
-    quotes
-    @throw std::out_of_range if to_unicode fails
-    */
-    string_t get_string() const
-    {
-        assert(m_cursor - m_start >= 2);
-
-        string_t result;
-        result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
-
-        // iterate the result between the quotes
-        for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
-        {
-            // find next escape character
-            auto e = std::find(i, m_cursor - 1, '\\');
-            if (e != i)
-            {
-                // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
-                for (auto k = i; k < e; k++)
+                // check if codepoint2 is a low surrogate
+                if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
                 {
-                    result.push_back(static_cast<typename string_t::value_type>(*k));
-                }
-                i = e - 1; // -1 because of ++i
-            }
-            else
-            {
-                // processing escaped character
-                // read next character
-                ++i;
-
-                switch (*i)
-                {
-                    // the default escapes
-                    case 't':
-                    {
-                        result += "\t";
-                        break;
-                    }
-                    case 'b':
-                    {
-                        result += "\b";
-                        break;
-                    }
-                    case 'f':
-                    {
-                        result += "\f";
-                        break;
-                    }
-                    case 'n':
-                    {
-                        result += "\n";
-                        break;
-                    }
-                    case 'r':
-                    {
-                        result += "\r";
-                        break;
-                    }
-                    case '\\':
-                    {
-                        result += "\\";
-                        break;
-                    }
-                    case '/':
-                    {
-                        result += "/";
-                        break;
-                    }
-                    case '"':
-                    {
-                        result += "\"";
-                        break;
-                    }
-
-                    // unicode
-                    case 'u':
-                    {
-                        // get code xxxx from uxxxx
-                        auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
-                                                      4).c_str(), nullptr, 16);
-
-                        // check if codepoint is a high surrogate
-                        if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
-                        {
-                            // make sure there is a subsequent unicode
-                            if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
-                            {
-                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
-                            }
-
-                            // get code yyyy from uxxxx\uyyyy
-                            auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
-                                                           (i + 7), 4).c_str(), nullptr, 16);
-                            result += to_unicode(codepoint, codepoint2);
-                            // skip the next 10 characters (xxxx\uyyyy)
-                            i += 10;
-                        }
-                        else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
-                        {
-                            // we found a lone low surrogate
-                                JSON_THROW(std::invalid_argument("missing high surrogate"));
-                        }
-                        else
-                        {
-                            // add unicode character(s)
-                            result += to_unicode(codepoint);
-                            // skip the next four characters (xxxx)
-                            i += 4;
-                        }
-                        break;
-                    }
-                }
-            }
-        }
-
-        return result;
-    }
-
-    /*!
-    @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,out] endptr recieves a pointer to the first character after
-    the number
-
-    @return the floating point number
-    */
-    long double str_to_float_t(long double* /* type */, char** endptr) const
-    {
-        return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
-    }
-
-    /*!
-    @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,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);
-    }
-
-    /*!
-    @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,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);
-    }
-
-    /*!
-    @brief return number value for number tokens
-
-    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.
-
-    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.
-    */
-    void get_number(basic_json& result) const
-    {
-        assert(m_start != nullptr);
-
-        const lexer::lexer_char_t* curptr = m_start;
-
-        // 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;
-                    continue;
-                }
-                // assume exponent (if not then will fail parse): change to
-                // float, stop counting and record exponent details
-                type = value_t::number_float;
-                break;
-            }
-
-            // skip if definitely not an integer
-            if (type != value_t::number_float)
-            {
-                auto digit = static_cast<number_unsigned_t>(*curptr - '0');
-
-                // overflow if value * 10 + digit > max, move terms around
-                // to avoid overflow in intermediate values
-                if (value > (max - digit) / 10)
-                {
-                    // overflow
-                    type = value_t::number_float;
+                    codepoint =
+                        // high surrogate occupies the most significant 22 bits
+                        (codepoint1 << 10)
+                        // low surrogate occupies the least significant 15 bits
+                        + codepoint2
+                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
+                        // in the result so we have to subtract with:
+                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
+                        - 0x35FDC00;
                 }
                 else
                 {
-                    // no overflow
-                    value = value * 10 + digit;
+                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
+                }
+            }
+
+            string_t result;
+
+            if (codepoint < 0x80)
+            {
+                // 1-byte characters: 0xxxxxxx (ASCII)
+                result.append(1, static_cast<typename string_t::value_type>(codepoint));
+            }
+            else if (codepoint <= 0x7ff)
+            {
+                // 2-byte characters: 110xxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else if (codepoint <= 0xffff)
+            {
+                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else if (codepoint <= 0x10ffff)
+            {
+                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else
+            {
+                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
+            }
+
+            return result;
+        }
+
+        /// return name of values of type token_type (only used for errors)
+        static std::string token_type_name(const token_type t)
+        {
+            switch (t)
+            {
+                case token_type::uninitialized:
+                    return "<uninitialized>";
+                case token_type::literal_true:
+                    return "true literal";
+                case token_type::literal_false:
+                    return "false literal";
+                case token_type::literal_null:
+                    return "null literal";
+                case token_type::value_string:
+                    return "string literal";
+                case token_type::value_number:
+                    return "number literal";
+                case token_type::begin_array:
+                    return "'['";
+                case token_type::begin_object:
+                    return "'{'";
+                case token_type::end_array:
+                    return "']'";
+                case token_type::end_object:
+                    return "'}'";
+                case token_type::name_separator:
+                    return "':'";
+                case token_type::value_separator:
+                    return "','";
+                case token_type::parse_error:
+                    return "<parse error>";
+                case token_type::end_of_input:
+                    return "end of input";
+                default:
+                {
+                    // catch non-enum values
+                    return "unknown token"; // LCOV_EXCL_LINE
                 }
             }
         }
 
-        // 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)
-        {
-            // invariant: if we parsed a '-', the absolute value is between
-            // 0 (we allow -0) and max == -INT64_MIN
-            assert(value >= 0);
-            assert(value <= max);
+        /*!
+        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 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.
 
-            if (value == max)
+        @return the class of the next token read from the buffer
+
+        @complexity Linear in the length of the input.\n
+
+        Proposition: The loop below will always terminate for finite input.\n
+
+        Proof (by contradiction): Assume a finite input. To loop forever, the
+        loop must never hit code with a `break` statement. The only code
+        snippets without a `break` statement are the continue statements for
+        whitespace and byte-order-marks. To loop forever, the input must be an
+        infinite sequence of whitespace or byte-order-marks. This contradicts
+        the assumption of finite input, q.e.d.
+        */
+        token_type scan()
+        {
+            while (true)
             {
-                // we cannot simply negate value (== max == -INT64_MIN),
-                // see https://github.com/nlohmann/json/issues/389
-                result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
+                // pointer for backtracking information
+                m_marker = nullptr;
+
+                // remember the begin of the token
+                m_start = m_cursor;
+                assert(m_start != nullptr);
+
+                /*!re2c
+                    re2c:define:YYCTYPE      = lexer_char_t;
+                    re2c:define:YYCURSOR     = m_cursor;
+                    re2c:define:YYLIMIT      = m_limit;
+                    re2c:define:YYMARKER     = m_marker;
+                    re2c:define:YYFILL       = "fill_line_buffer(@@); // LCOV_EXCL_LINE";
+                    re2c:define:YYFILL:naked = 1;
+                    re2c:yyfill:enable       = 1;
+                    re2c:indent:string       = "    ";
+                    re2c:indent:top          = 1;
+                    re2c:labelprefix         = "basic_json_parser_";
+
+                    // ignore whitespace
+                    ws = [ \t\n\r]+;
+                    ws   { continue; }
+
+                    // structural characters
+                    "[" { last_token_type = token_type::begin_array; break; }
+                    "]" { last_token_type = token_type::end_array; break; }
+                    "{" { last_token_type = token_type::begin_object; break; }
+                    "}" { last_token_type = token_type::end_object; break; }
+                    "," { last_token_type = token_type::value_separator; break; }
+                    ":" { last_token_type = token_type::name_separator; break; }
+
+                    // literal names
+                    "null"  { last_token_type = token_type::literal_null; break; }
+                    "true"  { last_token_type = token_type::literal_true; break; }
+                    "false" { last_token_type = token_type::literal_false; break; }
+
+                    // number
+                    decimal_point = ".";
+                    digit         = [0-9];
+                    digit_1_9     = [1-9];
+                    e             = "e" | "E";
+                    minus         = "-";
+                    plus          = "+";
+                    zero          = "0";
+                    exp           = e (minus | plus)? digit+;
+                    frac          = decimal_point digit+;
+                    int           = (zero | digit_1_9 digit*);
+                    number        = minus? int frac? exp?;
+                    number        { last_token_type = token_type::value_number; break; }
+
+                    // string
+                    quotation_mark  = "\"";
+                    escape          = "\\";
+                    unescaped       = [^"\\\x00-\x1f];
+                    single_escaped  = "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t";
+                    unicode_escaped = "u" [0-9a-fA-F]{4};
+                    escaped         = escape (single_escaped | unicode_escaped);
+                    char            = unescaped | escaped;
+                    string          = quotation_mark char* quotation_mark;
+                    string          { last_token_type = token_type::value_string; break; }
+
+                    // end of file
+                    "\x00"         { last_token_type = token_type::end_of_input; break; }
+
+                    // anything else is an error
+                    *              { last_token_type = token_type::parse_error; break; }
+                */
+            }
+
+            return last_token_type;
+        }
+
+        /*!
+        @brief append data from the stream to the line buffer
+
+        This function is called by the scan() function when the end of the
+        buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
+        incremented without leaving the limits of the line buffer. Note re2c
+        decides when to call this function.
+
+        If the lexer reads from contiguous storage, there is no trailing null
+        byte. Therefore, this function must make sure to add these padding
+        null bytes.
+
+        If the lexer reads from an input stream, this function reads the next
+        line of the input.
+
+        @pre
+            p p p p p p u u u u u x . . . . . .
+            ^           ^       ^   ^
+            m_content   m_start |   m_limit
+                                m_cursor
+
+        @post
+            u u u u u x x x x x x x . . . . . .
+            ^       ^               ^
+            |       m_cursor        m_limit
+            m_start
+            m_content
+        */
+        void fill_line_buffer(size_t n = 0)
+        {
+            // if line buffer is used, m_content points to its data
+            assert(m_line_buffer.empty()
+                   or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
+
+            // if line buffer is used, m_limit is set past the end of its data
+            assert(m_line_buffer.empty()
+                   or m_limit == m_content + m_line_buffer.size());
+
+            // pointer relationships
+            assert(m_content <= m_start);
+            assert(m_start <= m_cursor);
+            assert(m_cursor <= m_limit);
+            assert(m_marker == nullptr or m_marker  <= m_limit);
+
+            // number of processed characters (p)
+            const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
+            // offset for m_marker wrt. to m_start
+            const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
+            // number of unprocessed characters (u)
+            const auto offset_cursor = m_cursor - m_start;
+
+            // no stream is used or end of file is reached
+            if (m_stream == nullptr or m_stream->eof())
+            {
+                // m_start may or may not be pointing into m_line_buffer at
+                // this point. We trust the standand library to do the right
+                // thing. See http://stackoverflow.com/q/28142011/266378
+                m_line_buffer.assign(m_start, m_limit);
+
+                // append n characters to make sure that there is sufficient
+                // space between m_cursor and m_limit
+                m_line_buffer.append(1, '\x00');
+                if (n > 0)
+                {
+                    m_line_buffer.append(n - 1, '\x01');
+                }
             }
             else
             {
-                // all other values can be negated safely
-                result.m_value.number_integer = -static_cast<number_integer_t>(value);
+                // delete processed characters from line buffer
+                m_line_buffer.erase(0, num_processed_chars);
+                // read next line from input stream
+                m_line_buffer_tmp.clear();
+                std::getline(*m_stream, m_line_buffer_tmp, '\n');
+
+                // add line with newline symbol to the line buffer
+                m_line_buffer += m_line_buffer_tmp;
+                m_line_buffer.push_back('\n');
             }
+
+            // set pointers
+            m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
+            assert(m_content != nullptr);
+            m_start  = m_content;
+            m_marker = m_start + offset_marker;
+            m_cursor = m_start + offset_cursor;
+            m_limit  = m_start + m_line_buffer.size();
         }
-        else
+
+        /// return string representation of last read token
+        string_t get_token_string() const
         {
-            // parse with strtod
+            assert(m_start != nullptr);
+            return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
+                            static_cast<size_t>(m_cursor - m_start));
+        }
+
+        /*!
+        @brief return string value for string tokens
+
+        The function iterates the characters between the opening and closing
+        quotes of the string value. The complete string is the range
+        [m_start,m_cursor). Consequently, we iterate from m_start+1 to
+        m_cursor-1.
+
+        We differentiate two cases:
+
+        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., `"\\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.
+
+        @pre `m_cursor - m_start >= 2`, meaning the length of the last token
+        is at least 2 bytes which is trivially true for any string (which
+        consists of at least two quotes).
+
+            " c1 c2 c3 ... "
+            ^                ^
+            m_start          m_cursor
+
+        @complexity Linear in the length of the string.\n
+
+        Lemma: The loop body will always terminate.\n
+
+        Proof (by contradiction): Assume the loop body does not terminate. As
+        the loop body does not contain another loop, one of the called
+        functions must never return. The called functions are `std::strtoul`
+        and to_unicode. Neither function can loop forever, so the loop body
+        will never loop forever which contradicts the assumption that the loop
+        body does not terminate, q.e.d.\n
+
+        Lemma: The loop condition for the for loop is eventually false.\n
+
+        Proof (by contradiction): Assume the loop does not terminate. Due to
+        the above lemma, this can only be due to a tautological loop
+        condition; that is, the loop condition i < m_cursor - 1 must always be
+        true. Let x be the change of i for any loop iteration. Then
+        m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
+        can be rephrased to m_cursor - m_start - 2 > x. With the
+        precondition, we x <= 0, meaning that the loop condition holds
+        indefinitly if i is always decreased. However, observe that the value
+        of i is strictly increasing with each iteration, as it is incremented
+        by 1 in the iteration expression and never decremented inside the loop
+        body. Hence, the loop condition will eventually be false which
+        contradicts the assumption that the loop condition is a tautology,
+        q.e.d.
+
+        @return string value of current token without opening and closing
+        quotes
+        @throw std::out_of_range if to_unicode fails
+        */
+        string_t get_string() const
+        {
+            assert(m_cursor - m_start >= 2);
+
+            string_t result;
+            result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
+
+            // iterate the result between the quotes
+            for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
+            {
+                // find next escape character
+                auto e = std::find(i, m_cursor - 1, '\\');
+                if (e != i)
+                {
+                    // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
+                    for (auto k = i; k < e; k++)
+                    {
+                        result.push_back(static_cast<typename string_t::value_type>(*k));
+                    }
+                    i = e - 1; // -1 because of ++i
+                }
+                else
+                {
+                    // processing escaped character
+                    // read next character
+                    ++i;
+
+                    switch (*i)
+                    {
+                        // the default escapes
+                        case 't':
+                        {
+                            result += "\t";
+                            break;
+                        }
+                        case 'b':
+                        {
+                            result += "\b";
+                            break;
+                        }
+                        case 'f':
+                        {
+                            result += "\f";
+                            break;
+                        }
+                        case 'n':
+                        {
+                            result += "\n";
+                            break;
+                        }
+                        case 'r':
+                        {
+                            result += "\r";
+                            break;
+                        }
+                        case '\\':
+                        {
+                            result += "\\";
+                            break;
+                        }
+                        case '/':
+                        {
+                            result += "/";
+                            break;
+                        }
+                        case '"':
+                        {
+                            result += "\"";
+                            break;
+                        }
+
+                        // unicode
+                        case 'u':
+                        {
+                            // get code xxxx from uxxxx
+                            auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
+                                                          4).c_str(), nullptr, 16);
+
+                            // check if codepoint is a high surrogate
+                            if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
+                            {
+                                // make sure there is a subsequent unicode
+                                if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
+                                {
+                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
+                                }
+
+                                // get code yyyy from uxxxx\uyyyy
+                                auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
+                                                               (i + 7), 4).c_str(), nullptr, 16);
+                                result += to_unicode(codepoint, codepoint2);
+                                // skip the next 10 characters (xxxx\uyyyy)
+                                i += 10;
+                            }
+                            else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
+                            {
+                                // we found a lone low surrogate
+                                JSON_THROW(std::invalid_argument("missing high surrogate"));
+                            }
+                            else
+                            {
+                                // add unicode character(s)
+                                result += to_unicode(codepoint);
+                                // skip the next four characters (xxxx)
+                                i += 4;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        /*!
+        @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,out] endptr recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        long double str_to_float_t(long double* /* type */, char** endptr) const
+        {
+            return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
+        }
+
+        /*!
+        @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,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);
+        }
+
+        /*!
+        @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,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);
+        }
+
+        /*!
+        @brief return number value for number tokens
+
+        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.
+
+        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.
+        */
+        void get_number(basic_json& result) const
+        {
+            assert(m_start != nullptr);
+
+            const lexer::lexer_char_t* curptr = m_start;
+
+            // 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;
+                        continue;
+                    }
+                    // assume exponent (if not then will fail parse): change to
+                    // float, stop counting and record exponent details
+                    type = value_t::number_float;
+                    break;
+                }
+
+                // skip if definitely not an integer
+                if (type != value_t::number_float)
+                {
+                    auto digit = static_cast<number_unsigned_t>(*curptr - '0');
+
+                    // overflow if value * 10 + digit > max, move terms around
+                    // to avoid overflow in intermediate values
+                    if (value > (max - digit) / 10)
+                    {
+                        // overflow
+                        type = value_t::number_float;
+                    }
+                    else
+                    {
+                        // no overflow
+                        value = value * 10 + digit;
+                    }
+                }
+            }
+
+            // 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)
+            {
+                // invariant: if we parsed a '-', the absolute value is between
+                // 0 (we allow -0) and max == -INT64_MIN
+                assert(value >= 0);
+                assert(value <= max);
+
+                if (value == max)
+                {
+                    // we cannot simply negate value (== max == -INT64_MIN),
+                    // see https://github.com/nlohmann/json/issues/389
+                    result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
+                }
+                else
+                {
+                    // all other values can be negated safely
+                    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), nullptr);
 
-            // replace infinity and NAN by null
-            if (not std::isfinite(result.m_value.number_float))
-            {
-                type = value_t::null;
-                result.m_value = basic_json::json_value();
+                // replace infinity and NAN by null
+                if (not std::isfinite(result.m_value.number_float))
+                {
+                    type = value_t::null;
+                    result.m_value = basic_json::json_value();
+                }
             }
+
+            // save the type
+            result.m_type = type;
         }
 
-        // save the type
-        result.m_type = type;
-    }
-
-    private:
-    /// optional input stream
-    std::istream* m_stream = nullptr;
-    /// line buffer buffer for m_stream
-    string_t m_line_buffer {};
-    /// used for filling m_line_buffer
-    string_t m_line_buffer_tmp {};
-    /// the buffer pointer
-    const lexer_char_t* m_content = nullptr;
-    /// pointer to the beginning of the current symbol
-    const lexer_char_t* m_start = nullptr;
-    /// pointer for backtracking information
-    const lexer_char_t* m_marker = nullptr;
-    /// pointer to the current symbol
-    const lexer_char_t* m_cursor = nullptr;
-    /// pointer to the end of the buffer
-    const lexer_char_t* m_limit = nullptr;
-    /// the last token type
-    token_type last_token_type = token_type::end_of_input;
-                                                };
+      private:
+        /// optional input stream
+        std::istream* m_stream = nullptr;
+        /// line buffer buffer for m_stream
+        string_t m_line_buffer {};
+        /// used for filling m_line_buffer
+        string_t m_line_buffer_tmp {};
+        /// the buffer pointer
+        const lexer_char_t* m_content = nullptr;
+        /// pointer to the beginning of the current symbol
+        const lexer_char_t* m_start = nullptr;
+        /// pointer for backtracking information
+        const lexer_char_t* m_marker = nullptr;
+        /// pointer to the current symbol
+        const lexer_char_t* m_cursor = nullptr;
+        /// pointer to the end of the buffer
+        const lexer_char_t* m_limit = nullptr;
+        /// the last token type
+        token_type last_token_type = token_type::end_of_input;
+    };
 
     /*!
     @brief syntax analysis
@@ -9967,282 +10006,282 @@ class basic_json
     */
     class parser
     {
-        public:
+      public:
         /// a parser reading from a string literal
         parser(const char* buff, const parser_callback_t cb = nullptr)
-        : callback(cb),
-        m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
-    {}
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
+        {}
 
-    /// a parser reading from an input stream
-    parser(std::istream& is, const parser_callback_t cb = nullptr)
-    : callback(cb), m_lexer(is)
-    {}
+        /// a parser reading from an input stream
+        parser(std::istream& is, const parser_callback_t cb = nullptr)
+            : callback(cb), m_lexer(is)
+        {}
 
-    /// a parser reading from an iterator range with contiguous storage
-    template<class IteratorType, typename std::enable_if<
-                 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
-                 , int>::type
-             = 0>
-    parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
-    : callback(cb),
-    m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
-            static_cast<size_t>(std::distance(first, last)))
-    {}
+        /// a parser reading from an iterator range with contiguous storage
+        template<class IteratorType, typename std::enable_if<
+                     std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
+                     , int>::type
+                 = 0>
+        parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
+                      static_cast<size_t>(std::distance(first, last)))
+        {}
 
-    /// public parser interface
-    basic_json parse()
-    {
-        // read first token
-        get_token();
-
-        basic_json result = parse_internal(true);
-        result.assert_invariant();
-
-        expect(lexer::token_type::end_of_input);
-
-        // return parser result and replace it with null in case the
-        // top-level value was discarded by the callback function
-        return result.is_discarded() ? basic_json() : std::move(result);
-    }
-
-    private:
-    /// the actual parser
-    basic_json parse_internal(bool keep)
-    {
-        auto result = basic_json(value_t::discarded);
-
-        switch (last_token)
+        /// public parser interface
+        basic_json parse()
         {
-            case lexer::token_type::begin_object:
+            // read first token
+            get_token();
+
+            basic_json result = parse_internal(true);
+            result.assert_invariant();
+
+            expect(lexer::token_type::end_of_input);
+
+            // return parser result and replace it with null in case the
+            // top-level value was discarded by the callback function
+            return result.is_discarded() ? basic_json() : std::move(result);
+        }
+
+      private:
+        /// the actual parser
+        basic_json parse_internal(bool keep)
+        {
+            auto result = basic_json(value_t::discarded);
+
+            switch (last_token)
             {
-                if (keep and (not callback
-                              or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
+                case lexer::token_type::begin_object:
                 {
-                    // explicitly set result to object to cope with {}
-                    result.m_type = value_t::object;
-                    result.m_value = value_t::object;
-                }
+                    if (keep and (not callback
+                                  or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
+                    {
+                        // explicitly set result to object to cope with {}
+                        result.m_type = value_t::object;
+                        result.m_value = value_t::object;
+                    }
 
-                // read next token
-                get_token();
+                    // read next token
+                    get_token();
 
-                // closing } -> we are done
-                if (last_token == lexer::token_type::end_object)
-                {
+                    // closing } -> we are done
+                    if (last_token == lexer::token_type::end_object)
+                    {
+                        get_token();
+                        if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
+                        {
+                            result = basic_json(value_t::discarded);
+                        }
+                        return result;
+                    }
+
+                    // no comma is expected here
+                    unexpect(lexer::token_type::value_separator);
+
+                    // otherwise: parse key-value pairs
+                    do
+                    {
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
+
+                        // store key
+                        expect(lexer::token_type::value_string);
+                        const auto key = m_lexer.get_string();
+
+                        bool keep_tag = false;
+                        if (keep)
+                        {
+                            if (callback)
+                            {
+                                basic_json k(key);
+                                keep_tag = callback(depth, parse_event_t::key, k);
+                            }
+                            else
+                            {
+                                keep_tag = true;
+                            }
+                        }
+
+                        // parse separator (:)
+                        get_token();
+                        expect(lexer::token_type::name_separator);
+
+                        // parse and add value
+                        get_token();
+                        auto value = parse_internal(keep);
+                        if (keep and keep_tag and not value.is_discarded())
+                        {
+                            result[key] = std::move(value);
+                        }
+                    }
+                    while (last_token == lexer::token_type::value_separator);
+
+                    // closing }
+                    expect(lexer::token_type::end_object);
                     get_token();
                     if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
                     {
                         result = basic_json(value_t::discarded);
                     }
+
                     return result;
                 }
 
-                // no comma is expected here
-                unexpect(lexer::token_type::value_separator);
-
-                // otherwise: parse key-value pairs
-                do
+                case lexer::token_type::begin_array:
                 {
-                    // ugly, but could be fixed with loop reorganization
-                    if (last_token == lexer::token_type::value_separator)
+                    if (keep and (not callback
+                                  or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
+                    {
+                        // explicitly set result to object to cope with []
+                        result.m_type = value_t::array;
+                        result.m_value = value_t::array;
+                    }
+
+                    // read next token
+                    get_token();
+
+                    // closing ] -> we are done
+                    if (last_token == lexer::token_type::end_array)
                     {
                         get_token();
+                        if (callback and not callback(--depth, parse_event_t::array_end, result))
+                        {
+                            result = basic_json(value_t::discarded);
+                        }
+                        return result;
                     }
 
-                    // store key
-                    expect(lexer::token_type::value_string);
-                    const auto key = m_lexer.get_string();
+                    // no comma is expected here
+                    unexpect(lexer::token_type::value_separator);
 
-                    bool keep_tag = false;
-                    if (keep)
+                    // otherwise: parse values
+                    do
                     {
-                        if (callback)
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
                         {
-                            basic_json k(key);
-                            keep_tag = callback(depth, parse_event_t::key, k);
+                            get_token();
                         }
-                        else
+
+                        // parse value
+                        auto value = parse_internal(keep);
+                        if (keep and not value.is_discarded())
                         {
-                            keep_tag = true;
+                            result.push_back(std::move(value));
                         }
                     }
+                    while (last_token == lexer::token_type::value_separator);
 
-                    // parse separator (:)
+                    // closing ]
+                    expect(lexer::token_type::end_array);
                     get_token();
-                    expect(lexer::token_type::name_separator);
-
-                    // parse and add value
-                    get_token();
-                    auto value = parse_internal(keep);
-                    if (keep and keep_tag and not value.is_discarded())
-                    {
-                        result[key] = std::move(value);
-                    }
-                }
-                while (last_token == lexer::token_type::value_separator);
-
-                // closing }
-                expect(lexer::token_type::end_object);
-                get_token();
-                if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
-                {
-                    result = basic_json(value_t::discarded);
-                }
-
-                return result;
-            }
-
-            case lexer::token_type::begin_array:
-            {
-                if (keep and (not callback
-                              or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
-                {
-                    // explicitly set result to object to cope with []
-                    result.m_type = value_t::array;
-                    result.m_value = value_t::array;
-                }
-
-                // read next token
-                get_token();
-
-                // closing ] -> we are done
-                if (last_token == lexer::token_type::end_array)
-                {
-                    get_token();
-                    if (callback and not callback(--depth, parse_event_t::array_end, result))
+                    if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
                     {
                         result = basic_json(value_t::discarded);
                     }
+
                     return result;
                 }
 
-                // no comma is expected here
-                unexpect(lexer::token_type::value_separator);
-
-                // otherwise: parse values
-                do
+                case lexer::token_type::literal_null:
                 {
-                    // ugly, but could be fixed with loop reorganization
-                    if (last_token == lexer::token_type::value_separator)
-                    {
-                        get_token();
-                    }
-
-                    // parse value
-                    auto value = parse_internal(keep);
-                    if (keep and not value.is_discarded())
-                    {
-                        result.push_back(std::move(value));
-                    }
-                }
-                while (last_token == lexer::token_type::value_separator);
-
-                // closing ]
-                expect(lexer::token_type::end_array);
-                get_token();
-                if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
-                {
-                    result = basic_json(value_t::discarded);
+                    get_token();
+                    result.m_type = value_t::null;
+                    break;
                 }
 
-                return result;
+                case lexer::token_type::value_string:
+                {
+                    const auto s = m_lexer.get_string();
+                    get_token();
+                    result = basic_json(s);
+                    break;
+                }
+
+                case lexer::token_type::literal_true:
+                {
+                    get_token();
+                    result.m_type = value_t::boolean;
+                    result.m_value = true;
+                    break;
+                }
+
+                case lexer::token_type::literal_false:
+                {
+                    get_token();
+                    result.m_type = value_t::boolean;
+                    result.m_value = false;
+                    break;
+                }
+
+                case lexer::token_type::value_number:
+                {
+                    m_lexer.get_number(result);
+                    get_token();
+                    break;
+                }
+
+                default:
+                {
+                    // the last token was unexpected
+                    unexpect(last_token);
+                }
             }
 
-            case lexer::token_type::literal_null:
+            if (keep and callback and not callback(depth, parse_event_t::value, result))
             {
-                get_token();
-                result.m_type = value_t::null;
-                break;
-            }
-
-            case lexer::token_type::value_string:
-            {
-                const auto s = m_lexer.get_string();
-                get_token();
-                result = basic_json(s);
-                break;
-            }
-
-            case lexer::token_type::literal_true:
-            {
-                get_token();
-                result.m_type = value_t::boolean;
-                result.m_value = true;
-                break;
-            }
-
-            case lexer::token_type::literal_false:
-            {
-                get_token();
-                result.m_type = value_t::boolean;
-                result.m_value = false;
-                break;
-            }
-
-            case lexer::token_type::value_number:
-            {
-                m_lexer.get_number(result);
-                get_token();
-                break;
-            }
-
-            default:
-            {
-                // the last token was unexpected
-                unexpect(last_token);
+                result = basic_json(value_t::discarded);
             }
+            return result;
         }
 
-        if (keep and callback and not callback(depth, parse_event_t::value, result))
+        /// get next token from lexer
+        typename lexer::token_type get_token()
         {
-            result = basic_json(value_t::discarded);
+            last_token = m_lexer.scan();
+            return last_token;
         }
-        return result;
-    }
 
-    /// get next token from lexer
-    typename lexer::token_type get_token()
-    {
-        last_token = m_lexer.scan();
-        return last_token;
-    }
-
-    void expect(typename lexer::token_type t) const
-    {
-        if (t != last_token)
+        void expect(typename lexer::token_type t) const
         {
-            std::string error_msg = "parse error - unexpected ";
-            error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
-                          "'") :
-                          lexer::token_type_name(last_token));
-            error_msg += "; expected " + lexer::token_type_name(t);
+            if (t != last_token)
+            {
+                std::string error_msg = "parse error - unexpected ";
+                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
+                              "'") :
+                              lexer::token_type_name(last_token));
+                error_msg += "; expected " + lexer::token_type_name(t);
                 JSON_THROW(std::invalid_argument(error_msg));
+            }
         }
-    }
 
-    void unexpect(typename lexer::token_type t) const
-    {
-        if (t == last_token)
+        void unexpect(typename lexer::token_type t) const
         {
-            std::string error_msg = "parse error - unexpected ";
-            error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
-                          "'") :
-                          lexer::token_type_name(last_token));
+            if (t == last_token)
+            {
+                std::string error_msg = "parse error - unexpected ";
+                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
+                              "'") :
+                              lexer::token_type_name(last_token));
                 JSON_THROW(std::invalid_argument(error_msg));
+            }
         }
-    }
 
-    private:
-    /// current level of recursion
-    int depth = 0;
-    /// callback function
-    const parser_callback_t callback = nullptr;
-    /// the type of the last read token
-    typename lexer::token_type last_token = lexer::token_type::uninitialized;
-    /// the lexer
-    lexer m_lexer;
-                            };
+      private:
+        /// current level of recursion
+        int depth = 0;
+        /// callback function
+        const parser_callback_t callback = nullptr;
+        /// the type of the last read token
+        typename lexer::token_type last_token = lexer::token_type::uninitialized;
+        /// the lexer
+        lexer m_lexer;
+    };
 
   public:
     /*!
@@ -10261,7 +10300,7 @@ class basic_json
         /// allow basic_json to access private members
         friend class basic_json;
 
-        public:
+      public:
         /*!
         @brief create JSON pointer
 
@@ -10285,573 +10324,573 @@ class basic_json
         @since version 2.0.0
         */
         explicit json_pointer(const std::string& s = "")
-        : reference_tokens(split(s))
-    {}
+            : reference_tokens(split(s))
+        {}
 
-    /*!
-    @brief return a string representation of the JSON pointer
+        /*!
+        @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
+        @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
+        @return a string representation of the JSON pointer
 
-    @liveexample{The example shows the result of `to_string`.,
-    json_pointer__to_string}
+        @liveexample{The example shows the result of `to_string`.,
+        json_pointer__to_string}
 
-    @since version 2.0.0
-    */
-    std::string to_string() const noexcept
-    {
-        return std::accumulate(reference_tokens.begin(),
-                               reference_tokens.end(), std::string{},
-                               [](const std::string & a, const std::string & b)
+        @since version 2.0.0
+        */
+        std::string to_string() const noexcept
         {
-            return a + "/" + escape(b);
-        });
-    }
+            return std::accumulate(reference_tokens.begin(),
+                                   reference_tokens.end(), std::string{},
+                                   [](const std::string & a, const std::string & b)
+            {
+                return a + "/" + escape(b);
+            });
+        }
 
-    /// @copydoc to_string()
-    operator std::string() const
-    {
-        return to_string();
-    }
-
-    private:
-    /// remove and return last reference pointer
-    std::string pop_back()
-    {
-        if (is_root())
+        /// @copydoc to_string()
+        operator std::string() const
         {
+            return to_string();
+        }
+
+      private:
+        /// remove and return last reference pointer
+        std::string pop_back()
+        {
+            if (is_root())
+            {
                 JSON_THROW(std::domain_error("JSON pointer has no parent"));
+            }
+
+            auto last = reference_tokens.back();
+            reference_tokens.pop_back();
+            return last;
         }
 
-        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())
+        /// return whether pointer points to the root document
+        bool is_root() const
         {
+            return reference_tokens.empty();
+        }
+
+        json_pointer top() const
+        {
+            if (is_root())
+            {
                 JSON_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
-
-    @complexity Linear in the number of reference tokens.
-    */
-    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:
-                {
-                        JSON_THROW(std::domain_error("invalid value to unflatten"));
-                }
-            }
-        }
-
-        return *result;
-    }
-
-    /*!
-    @brief return a reference to the pointed to value
-
-    @note This version does not throw if a value is not present, but tries
-    to create nested values instead. For instance, calling this function
-    with pointer `"/this/that"` on a null value is equivalent to calling
-    `operator[]("this").operator[]("that")` on that value, effectively
-    changing the null value to an object.
-
-    @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)
-        {
-            // convert null values to arrays or objects before continuing
-            if (ptr->m_type == value_t::null)
-            {
-                // check if reference token is a number
-                const bool nums = std::all_of(reference_token.begin(),
-                                              reference_token.end(),
-                                              [](const char x)
-                {
-                    return std::isdigit(x);
-                });
-
-                // change value to array for numbers or "-" or to object
-                // otherwise
-                if (nums or reference_token == "-")
-                {
-                    *ptr = value_t::array;
-                }
-                else
-                {
-                    *ptr = value_t::object;
-                }
             }
 
-            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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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')
-                    {
-                            JSON_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:
-                {
-                        JSON_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(const std::string& reference_string)
-    {
-        std::vector<std::string> result;
-
-        // special case: empty reference string -> no reference tokens
-        if (reference_string.empty())
-        {
+            json_pointer result = *this;
+            result.reference_tokens = {reference_tokens[0]};
             return result;
         }
 
-        // check if nonempty reference string begins with slash
-        if (reference_string[0] != '/')
+        /*!
+        @brief create and return a reference to the pointed to value
+
+        @complexity Linear in the number of reference tokens.
+        */
+        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:
+                    {
+                        JSON_THROW(std::domain_error("invalid value to unflatten"));
+                    }
+                }
+            }
+
+            return *result;
+        }
+
+        /*!
+        @brief return a reference to the pointed to value
+
+        @note This version does not throw if a value is not present, but tries
+        to create nested values instead. For instance, calling this function
+        with pointer `"/this/that"` on a null value is equivalent to calling
+        `operator[]("this").operator[]("that")` on that value, effectively
+        changing the null value to an object.
+
+        @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)
+            {
+                // convert null values to arrays or objects before continuing
+                if (ptr->m_type == value_t::null)
+                {
+                    // check if reference token is a number
+                    const bool nums = std::all_of(reference_token.begin(),
+                                                  reference_token.end(),
+                                                  [](const char x)
+                    {
+                        return std::isdigit(x);
+                    });
+
+                    // change value to array for numbers or "-" or to object
+                    // otherwise
+                    if (nums or reference_token == "-")
+                    {
+                        *ptr = value_t::array;
+                    }
+                    else
+                    {
+                        *ptr = value_t::object;
+                    }
+                }
+
+                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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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')
+                        {
+                            JSON_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:
+                    {
+                        JSON_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(const 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] != '/')
+            {
                 JSON_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
+            // 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
+                // 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);
+            {
+                // 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
+                // check reference tokens are properly escaped
                 for (size_t pos = reference_token.find_first_of('~');
-                    pos != std::string::npos;
+                        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'))
                 {
+                    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'))
+                    {
                         JSON_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; changed so that all
-                      occurrences of @a f are replaced with @a t
-    @param[in]     f  the substring to replace with @a t
-    @param[in]     t  the string to replace @a f
-
-    @pre The search string @a f must not be empty.
-
-    @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;
+
+                // finally, store the reference token
+                unescape(reference_token);
+                result.push_back(reference_token);
             }
 
-            case value_t::object:
+            return result;
+        }
+
+      private:
+        /*!
+        @brief replace all occurrences of a substring by another string
+
+        @param[in,out] s  the string to manipulate; changed so that all
+                          occurrences of @a f are replaced with @a t
+        @param[in]     f  the substring to replace with @a t
+        @param[in]     t  the string to replace @a f
+
+        @pre The search string @a f must not be empty.
+
+        @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)
             {
-                if (value.m_value.object->empty())
+                case value_t::array:
                 {
-                    // 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)
+                    if (value.m_value.array->empty())
                     {
-                        flatten(reference_string + "/" + escape(element.first),
-                                element.second, result);
+                        // 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;
                 }
-                break;
-            }
 
-            default:
-            {
-                // add primitive value with its reference string
-                result[reference_string] = value;
-                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
+        /*!
+        @param[in] value  flattened JSON
 
-    @return unflattened JSON
-    */
-    static basic_json unflatten(const basic_json& value)
-    {
-        if (not value.is_object())
+        @return unflattened JSON
+        */
+        static basic_json unflatten(const basic_json& value)
         {
+            if (not value.is_object())
+            {
                 JSON_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())
-            {
-                    JSON_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;
+            basic_json result;
+
+            // iterate the JSON object values
+            for (const auto& element : *value.m_value.object)
+            {
+                if (not element.second.is_primitive())
+                {
+                    JSON_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;
         }
 
-        return result;
-    }
+      private:
+        friend bool operator==(json_pointer const& lhs,
+                               json_pointer const& rhs) noexcept
+        {
+            return lhs.reference_tokens == rhs.reference_tokens;
+        }
 
-    private:
-    friend bool operator==(json_pointer const &lhs,
-                           json_pointer const &rhs) noexcept
-    {
-      return lhs.reference_tokens == rhs.reference_tokens;
-    }
+        friend bool operator!=(json_pointer const& lhs,
+                               json_pointer const& rhs) noexcept
+        {
+            return !(lhs == rhs);
+        }
 
-    friend bool operator!=(json_pointer const &lhs,
-                           json_pointer const &rhs) noexcept
-    {
-      return !(lhs == rhs);
-    }
-
-    /// the reference tokens
-    std::vector<std::string> reference_tokens {};
+        /// the reference tokens
+        std::vector<std::string> reference_tokens {};
     };
 
     //////////////////////////
@@ -11527,25 +11566,26 @@ Returns an ordering that is similar to Python:
 */
 inline bool operator<(const value_t lhs, const value_t rhs) noexcept
 {
-  static constexpr std::array<uint8_t, 8> order = {{
-      0, // null
-      3, // object
-      4, // array
-      5, // string
-      1, // boolean
-      2, // integer
-      2, // unsigned
-      2, // float
-  }};
+    static constexpr std::array<uint8_t, 8> order = {{
+            0, // null
+            3, // object
+            4, // array
+            5, // string
+            1, // boolean
+            2, // integer
+            2, // unsigned
+            2, // float
+        }
+    };
 
-  // discarded values are not comparable
-  if (lhs == value_t::discarded or rhs == value_t::discarded)
-  {
-    return false;
-  }
+    // discarded values are not comparable
+    if (lhs == value_t::discarded or rhs == value_t::discarded)
+    {
+        return false;
+    }
 
-  return order[static_cast<std::size_t>(lhs)] <
-         order[static_cast<std::size_t>(rhs)];
+    return order[static_cast<std::size_t>(lhs)] <
+           order[static_cast<std::size_t>(rhs)];
 }
 
 /////////////
@@ -11570,38 +11610,38 @@ using json = basic_json<>;
 
 // specialization of std::swap, and std::hash
 namespace std
+{
+/*!
+@brief exchanges the values of two JSON objects
+
+@since version 1.0.0
+*/
+template<>
+inline void swap(nlohmann::json& j1,
+                 nlohmann::json& j2) noexcept(
+                     is_nothrow_move_constructible<nlohmann::json>::value and
+                     is_nothrow_move_assignable<nlohmann::json>::value
+                 )
+{
+    j1.swap(j2);
+}
+
+/// hash value for JSON objects
+template<>
+struct hash<nlohmann::json>
 {
     /*!
-    @brief exchanges the values of two JSON objects
+    @brief return a hash value for a JSON object
 
     @since version 1.0.0
     */
-    template<>
-    inline void swap(nlohmann::json& j1,
-                     nlohmann::json& j2) noexcept(
-                         is_nothrow_move_constructible<nlohmann::json>::value and
-                         is_nothrow_move_assignable<nlohmann::json>::value
-                                                   )
-    {
-        j1.swap(j2);
-    }
-
-    /// hash value for JSON objects
-    template<>
-    struct hash<nlohmann::json>
-    {
-        /*!
-        @brief return a hash value for a JSON object
-
-        @since version 1.0.0
-        */
-        std::size_t operator()(const nlohmann::json& j) const
+    std::size_t operator()(const nlohmann::json& j) const
     {
         // a naive hashing via the string representation
         const auto& h = hash<nlohmann::json::string_t>();
         return h(j.dump());
     }
-                        };
+};
 } // namespace std
 
 /*!
diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp
index 73b686d8..3c4d8bef 100644
--- a/test/src/unit-conversions.cpp
+++ b/test/src/unit-conversions.cpp
@@ -177,10 +177,10 @@ TEST_CASE("value conversion")
 
             SECTION("reserve is called on containers that supports it")
             {
-              // making the call to from_json throw in order to check capacity 
-              std::vector<float> v;
-              CHECK_THROWS_AS(nlohmann::from_json(j, v), std::logic_error);
-              CHECK(v.capacity() == j.size());
+                // making the call to from_json throw in order to check capacity
+                std::vector<float> v;
+                CHECK_THROWS_AS(nlohmann::from_json(j, v), std::logic_error);
+                CHECK(v.capacity() == j.size());
             }
         }
 
diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp
index de13e057..b939db4e 100644
--- a/test/src/unit-noexcept.cpp
+++ b/test/src/unit-noexcept.cpp
@@ -11,8 +11,8 @@ enum test
 struct pod {};
 struct pod_bis {};
 
-void to_json(json &, pod) noexcept;
-void to_json(json &, pod_bis);
+void to_json(json&, pod) noexcept;
+void to_json(json&, pod_bis);
 void from_json(const json&, pod) noexcept;
 void from_json(const json&, pod_bis);
 static json j;
diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp
index 07055bc1..6a5e0c64 100644
--- a/test/src/unit-regression.cpp
+++ b/test/src/unit-regression.cpp
@@ -63,7 +63,7 @@ TEST_CASE("regression tests")
 
     SECTION("pull request #71 - handle enum type")
     {
-        enum { t = 0 , u = 1};
+        enum { t = 0, u = 1};
         json j = json::array();
         j.push_back(t);
 
diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp
index 0590a8e5..35f86440 100644
--- a/test/src/unit-udt.cpp
+++ b/test/src/unit-udt.cpp
@@ -114,22 +114,22 @@ void to_json(Json& j, country c)
 }
 
 template <typename Json>
-void to_json(Json& j, const person & p)
+void to_json(Json& j, const person& p)
 {
     j = Json{{"age", p.m_age}, {"name", p.m_name}, {"country", p.m_country}};
 }
 
-void to_json(nlohmann::json& j, const address & a)
+void to_json(nlohmann::json& j, const address& a)
 {
     j = a.m_val;
 }
 
-void to_json(nlohmann::json& j, const contact & c)
+void to_json(nlohmann::json& j, const contact& c)
 {
     j = json{{"person", c.m_person}, {"address", c.m_address}};
 }
 
-void to_json(nlohmann::json& j, const contact_book & cb)
+void to_json(nlohmann::json& j, const contact_book& cb)
 {
     j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}};
 }
@@ -140,28 +140,28 @@ bool operator==(age lhs, age rhs)
     return lhs.m_val == rhs.m_val;
 }
 
-bool operator==(const address & lhs, const address & rhs)
+bool operator==(const address& lhs, const address& rhs)
 {
     return lhs.m_val == rhs.m_val;
 }
 
-bool operator==(const name & lhs, const name & rhs)
+bool operator==(const name& lhs, const name& rhs)
 {
     return lhs.m_val == rhs.m_val;
 }
 
-bool operator==(const person & lhs, const person & rhs)
+bool operator==(const person& lhs, const person& rhs)
 {
     return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age);
 }
 
-bool operator==(const contact & lhs, const contact & rhs)
+bool operator==(const contact& lhs, const contact& rhs)
 {
     return std::tie(lhs.m_person, lhs.m_address) ==
            std::tie(rhs.m_person, rhs.m_address);
 }
 
-bool operator==(const contact_book & lhs, const contact_book & rhs)
+bool operator==(const contact_book& lhs, const contact_book& rhs)
 {
     return std::tie(lhs.m_book_name, lhs.m_contacts) ==
            std::tie(rhs.m_book_name, rhs.m_contacts);
@@ -172,19 +172,19 @@ bool operator==(const contact_book & lhs, const contact_book & rhs)
 namespace udt
 {
 template <typename Json>
-void from_json(const Json & j, age& a)
+void from_json(const Json& j, age& a)
 {
     a.m_val = j.template get<int>();
 }
 
 template <typename Json>
-void from_json(const Json & j, name& n)
+void from_json(const Json& j, name& n)
 {
     n.m_val = j.template get<std::string>();
 }
 
 template <typename Json>
-void from_json(const Json & j, country& c)
+void from_json(const Json& j, country& c)
 {
     const auto str = j.template get<std::string>();
     static const std::map<std::string, country> m =
@@ -200,25 +200,25 @@ void from_json(const Json & j, country& c)
 }
 
 template <typename Json>
-void from_json(const Json & j, person& p)
+void from_json(const Json& j, person& p)
 {
     p.m_age = j["age"].template get<age>();
     p.m_name = j["name"].template get<name>();
     p.m_country = j["country"].template get<country>();
 }
 
-void from_json(const nlohmann::json & j, address& a)
+void from_json(const nlohmann::json& j, address& a)
 {
     a.m_val = j.get<std::string>();
 }
 
-void from_json(const nlohmann::json & j, contact& c)
+void from_json(const nlohmann::json& j, contact& c)
 {
     c.m_person = j["person"].get<person>();
     c.m_address = j["address"].get<address>();
 }
 
-void from_json(const nlohmann::json & j, contact_book& cb)
+void from_json(const nlohmann::json& j, contact_book& cb)
 {
     cb.m_book_name = j["name"].get<name>();
     cb.m_contacts = j["contacts"].get<std::vector<contact>>();
@@ -297,7 +297,7 @@ namespace nlohmann
 template <typename T>
 struct adl_serializer<std::shared_ptr<T>>
 {
-    static void to_json(json& j, const std::shared_ptr<T> & opt)
+    static void to_json(json& j, const std::shared_ptr<T>& opt)
     {
         if (opt)
         {
@@ -309,7 +309,7 @@ struct adl_serializer<std::shared_ptr<T>>
         }
     }
 
-    static void from_json(const json & j, std::shared_ptr<T>& opt)
+    static void from_json(const json& j, std::shared_ptr<T>& opt)
     {
         if (j.is_null())
         {
@@ -325,12 +325,12 @@ struct adl_serializer<std::shared_ptr<T>>
 template <>
 struct adl_serializer<udt::legacy_type>
 {
-    static void to_json(json& j, const udt::legacy_type & l)
+    static void to_json(json& j, const udt::legacy_type& l)
     {
         j = std::stoi(l.number);
     }
 
-    static void from_json(const json & j, udt::legacy_type& l)
+    static void from_json(const json& j, udt::legacy_type& l)
     {
         l.number = std::to_string(j.get<int>());
     }
@@ -394,21 +394,21 @@ namespace nlohmann
 template <>
 struct adl_serializer<std::vector<float>>
 {
-  using type = std::vector<float>;
-    static void to_json(json& j, const type &)
+    using type = std::vector<float>;
+    static void to_json(json& j, const type&)
     {
-      j = "hijacked!";
+        j = "hijacked!";
     }
 
-    static void from_json(const json &, type& opt)
+    static void from_json(const json&, type& opt)
     {
-      opt = {42.0, 42.0, 42.0};
+        opt = {42.0, 42.0, 42.0};
     }
 
     // preferred version
-    static type from_json(const json &)
+    static type from_json(const json&)
     {
-      return {4.0, 5.0, 6.0};
+        return {4.0, 5.0, 6.0};
     }
 };
 }
@@ -419,7 +419,7 @@ TEST_CASE("even supported types can be specialized", "[udt]")
     CHECK(j.dump() == R"("hijacked!")");
     auto f = j.get<std::vector<float>>();
     // the single argument from_json method is preferred
-    CHECK((f == std::vector<float>{4.0, 5.0, 6.0}));
+    CHECK((f == std::vector<float> {4.0, 5.0, 6.0}));
 }
 
 namespace nlohmann
@@ -427,7 +427,7 @@ namespace nlohmann
 template <typename T>
 struct adl_serializer<std::unique_ptr<T>>
 {
-    static void to_json(json& j, const std::unique_ptr<T> & opt)
+    static void to_json(json& j, const std::unique_ptr<T>& opt)
     {
         if (opt)
         {
@@ -440,7 +440,7 @@ struct adl_serializer<std::unique_ptr<T>>
     }
 
     // this is the overload needed for non-copyable types,
-    static std::unique_ptr<T> from_json(const json & j)
+    static std::unique_ptr<T> from_json(const json& j)
     {
         if (j.is_null())
         {
@@ -491,64 +491,64 @@ TEST_CASE("Non-copyable types", "[udt]")
 template <typename T, typename = void>
 struct pod_serializer
 {
-  // use adl for non-pods, or scalar types
-  template <
-      typename Json, typename U = T,
-      typename std::enable_if<
-          not(std::is_pod<U>::value and std::is_class<U>::value), int>::type = 0>
-  static void from_json(const Json &j, U &t)
-  {
-    using nlohmann::from_json;
-    from_json(j, t);
-  }
+    // use adl for non-pods, or scalar types
+    template <
+        typename Json, typename U = T,
+        typename std::enable_if <
+            not(std::is_pod<U>::value and std::is_class<U>::value), int >::type = 0 >
+    static void from_json(const Json& j, U& t)
+    {
+        using nlohmann::from_json;
+        from_json(j, t);
+    }
 
-  // special behaviour for pods
-  template <typename Json, typename U = T,
-            typename std::enable_if<
-                std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0>
-  static void from_json(const  Json &j, U &t)
-  {
-    std::uint64_t value;
-    // TODO The following block is no longer relevant in this serializer, make another one that shows the issue
-    // the problem arises only when one from_json method is defined without any constraint
-    //
-    // Why cannot we simply use: j.get<std::uint64_t>() ?
-    // Well, with the current experiment, the get method looks for a from_json
-    // function, which we are currently defining!
-    // This would end up in a stack overflow. Calling nlohmann::from_json is a
-    // workaround (is it?).
-    // I shall find a good way to avoid this once all constructors are converted
-    // to free methods
-    //
-    // In short, constructing a json by constructor calls to_json
-    // calling get calls from_json, for now, we cannot do this in custom
-    // serializers
-    nlohmann::from_json(j, value);
-    auto bytes = static_cast<char *>(static_cast<void *>(&value));
-    std::memcpy(&t, bytes, sizeof(value));
-  }
+    // special behaviour for pods
+    template <typename Json, typename U = T,
+              typename std::enable_if<
+                  std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0>
+    static void from_json(const  Json& j, U& t)
+    {
+        std::uint64_t value;
+        // TODO The following block is no longer relevant in this serializer, make another one that shows the issue
+        // the problem arises only when one from_json method is defined without any constraint
+        //
+        // Why cannot we simply use: j.get<std::uint64_t>() ?
+        // Well, with the current experiment, the get method looks for a from_json
+        // function, which we are currently defining!
+        // This would end up in a stack overflow. Calling nlohmann::from_json is a
+        // workaround (is it?).
+        // I shall find a good way to avoid this once all constructors are converted
+        // to free methods
+        //
+        // In short, constructing a json by constructor calls to_json
+        // calling get calls from_json, for now, we cannot do this in custom
+        // serializers
+        nlohmann::from_json(j, value);
+        auto bytes = static_cast<char*>(static_cast<void*>(&value));
+        std::memcpy(&t, bytes, sizeof(value));
+    }
 
-  template <
-      typename Json, typename U = T,
-      typename std::enable_if<
-          not(std::is_pod<U>::value and std::is_class<U>::value), int>::type = 0>
-  static void to_json(Json &j, const  T &t)
-  {
-    using nlohmann::to_json;
-    to_json(j, t);
-  }
+    template <
+        typename Json, typename U = T,
+        typename std::enable_if <
+            not(std::is_pod<U>::value and std::is_class<U>::value), int >::type = 0 >
+    static void to_json(Json& j, const  T& t)
+    {
+        using nlohmann::to_json;
+        to_json(j, t);
+    }
 
-  template <typename Json, typename U = T,
-            typename std::enable_if<
-                std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0>
-  static void to_json(Json &j, const  T &t) noexcept
-  {
-    auto bytes = static_cast< const unsigned char*>(static_cast<const void *>(&t));
-    std::uint64_t value = bytes[0];
-    for (auto i = 1; i < 8; ++i)
-      value |= std::uint64_t{bytes[i]} << 8 * i;
-    nlohmann::to_json(j, value);
-  }
+    template <typename Json, typename U = T,
+              typename std::enable_if<
+                  std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0>
+    static void to_json(Json& j, const  T& t) noexcept
+    {
+        auto bytes = static_cast< const unsigned char*>(static_cast<const void*>(&t));
+        std::uint64_t value = bytes[0];
+        for (auto i = 1; i < 8; ++i)
+            value |= std::uint64_t{bytes[i]} << 8 * i;
+        nlohmann::to_json(j, value);
+    }
 };
 
 namespace udt
@@ -562,19 +562,19 @@ struct small_pod
 
 struct non_pod
 {
-  std::string s;
+    std::string s;
 };
 
 template <typename Json>
-void to_json(Json& j, const non_pod & np)
+void to_json(Json& j, const non_pod& np)
 {
-  j = np.s;
+    j = np.s;
 }
 
 template <typename Json>
-void from_json(const Json & j, non_pod& np)
+void from_json(const Json& j, non_pod& np)
 {
-  np.s = j.template get<std::string>();
+    np.s = j.template get<std::string>();
 }
 
 bool operator==(small_pod lhs, small_pod rhs) noexcept
@@ -583,35 +583,35 @@ bool operator==(small_pod lhs, small_pod rhs) noexcept
            std::tie(rhs.begin, rhs.middle, rhs.end);
 }
 
-bool operator==(const  non_pod &lhs, const  non_pod &rhs) noexcept
+bool operator==(const  non_pod& lhs, const  non_pod& rhs) noexcept
 {
-  return lhs.s == rhs.s;
+    return lhs.s == rhs.s;
 }
 
 std::ostream& operator<<(std::ostream& os, small_pod l)
 {
-  return os << "begin: " << l.begin << ", middle: " << l.middle << ", end: " << l.end;
+    return os << "begin: " << l.begin << ", middle: " << l.middle << ", end: " << l.end;
 }
 }
 
 TEST_CASE("custom serializer for pods", "[udt]")
 {
-  using custom_json =
-      nlohmann::basic_json<std::map, std::vector, std::string, bool,
-                           std::int64_t, std::uint64_t, double, std::allocator,
-                           pod_serializer>;
+    using custom_json =
+        nlohmann::basic_json<std::map, std::vector, std::string, bool,
+        std::int64_t, std::uint64_t, double, std::allocator,
+        pod_serializer>;
 
-  auto p = udt::small_pod{42, '/', 42};
-  custom_json j = p;
+    auto p = udt::small_pod{42, '/', 42};
+    custom_json j = p;
 
-  auto p2 = j.get<udt::small_pod>();
+    auto p2 = j.get<udt::small_pod>();
 
-  CHECK(p == p2);
+    CHECK(p == p2);
 
-  auto np = udt::non_pod{{"non-pod"}};
-  custom_json j2 = np;
-  auto np2 = j2.get<udt::non_pod>();
-  CHECK(np == np2);
+    auto np = udt::non_pod{{"non-pod"}};
+    custom_json j2 = np;
+    auto np2 = j2.get<udt::non_pod>();
+    CHECK(np == np2);
 }
 
 template <typename T, typename>
@@ -622,13 +622,13 @@ using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, boo
 template <typename T, typename>
 struct another_adl_serializer
 {
-    static void from_json(const custom_json & j , T& t)
+    static void from_json(const custom_json& j, T& t)
     {
         using nlohmann::from_json;
         from_json(j, t);
     }
 
-    static void to_json(custom_json& j , const T & t)
+    static void to_json(custom_json& j, const T& t)
     {
         using nlohmann::to_json;
         to_json(j, t);