From a7f8c47f68240f6ea6a3d3475379bbb818bc82fb Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Wed, 27 Jul 2016 21:29:55 +0200
Subject: [PATCH] cleaned up code

- removed unnecessary assertions
- simplified simple if/return patterns
---
 ChangeLog.md      |   3 +
 src/json.hpp      | 234 ++++++++++++----------------------------------
 src/json.hpp.re2c | 234 ++++++++++++----------------------------------
 3 files changed, 121 insertions(+), 350 deletions(-)

diff --git a/ChangeLog.md b/ChangeLog.md
index e3a7cc07..901e37c1 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file. This projec
 
 [Full Changelog](https://github.com/nlohmann/json/compare/v2.0.1...HEAD)
 
+- value\(\) does not work with \_json\_pointer types [\#283](https://github.com/nlohmann/json/issues/283)
+- Easy serialization of classes [\#280](https://github.com/nlohmann/json/issues/280)
+
 - Build error for std::int64 [\#282](https://github.com/nlohmann/json/issues/282)
 
 - hexify\(\) function emits conversion warning [\#270](https://github.com/nlohmann/json/issues/270)
diff --git a/src/json.hpp b/src/json.hpp
index 15221b8b..9c80cee0 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -621,8 +621,8 @@ class basic_json
     > that implementations will agree exactly on their numeric values.
 
     As this range is a subrange (when considered in conjunction with the
-    number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
-    class's integer type is interoperable.
+    number_integer_t type) of the exactly supported range [0, UINT64_MAX],
+    this class's integer type is interoperable.
 
     #### Storage
 
@@ -760,6 +760,7 @@ class basic_json
         };
         std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
         alloc.construct(object.get(), std::forward<Args>(args)...);
+        assert(object.get() != nullptr);
         return object.release();
     }
 
@@ -1415,8 +1416,8 @@ class basic_json
 
     Create an unsigned integer number JSON value with a given content.
 
-    @tparam T  helper type to compare number_unsigned_t and unsigned int
-    (not visible in) the interface.
+    @tparam T  helper type to compare number_unsigned_t and unsigned int (not
+    visible in) the interface.
 
     @param[in] val  an integer to create a JSON number from
 
@@ -1521,8 +1522,8 @@ class basic_json
     disallows NaN values:
     > Numeric values that cannot be represented in the grammar below (such as
     > Infinity and NaN) are not permitted.
-    In case the parameter @a val is not a number, a JSON null value is
-    created instead.
+    In case the parameter @a val is not a number, a JSON null value is created
+    instead.
 
     @complexity Constant.
 
@@ -1647,8 +1648,6 @@ class basic_json
             m_type = value_t::object;
             m_value = value_t::object;
 
-            assert(m_value.object != nullptr);
-
             std::for_each(init.begin(), init.end(), [this](const basic_json & element)
             {
                 m_value.object->emplace(*(element[0].m_value.string), element[1]);
@@ -1806,7 +1805,8 @@ class basic_json
                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value
                   , int>::type
               = 0>
-    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
+    basic_json(InputIT first, InputIT last)
+        : m_type(first.m_object->m_type)
     {
         // make sure iterator fits the current value
         if (first.m_object != last.m_object)
@@ -1840,35 +1840,30 @@ class basic_json
         {
             case value_t::number_integer:
             {
-                assert(first.m_object != nullptr);
                 m_value.number_integer = first.m_object->m_value.number_integer;
                 break;
             }
 
             case value_t::number_unsigned:
             {
-                assert(first.m_object != nullptr);
                 m_value.number_unsigned = first.m_object->m_value.number_unsigned;
                 break;
             }
 
             case value_t::number_float:
             {
-                assert(first.m_object != nullptr);
                 m_value.number_float = first.m_object->m_value.number_float;
                 break;
             }
 
             case value_t::boolean:
             {
-                assert(first.m_object != nullptr);
                 m_value.boolean = first.m_object->m_value.boolean;
                 break;
             }
 
             case value_t::string:
             {
-                assert(first.m_object != nullptr);
                 m_value = *first.m_object->m_value.string;
                 break;
             }
@@ -1887,7 +1882,6 @@ class basic_json
 
             default:
             {
-                assert(first.m_object != nullptr);
                 throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
             }
         }
@@ -1951,21 +1945,18 @@ class basic_json
         {
             case value_t::object:
             {
-                assert(other.m_value.object != nullptr);
                 m_value = *other.m_value.object;
                 break;
             }
 
             case value_t::array:
             {
-                assert(other.m_value.array != nullptr);
                 m_value = *other.m_value.array;
                 break;
             }
 
             case value_t::string:
             {
-                assert(other.m_value.string != nullptr);
                 m_value = *other.m_value.string;
                 break;
             }
@@ -2020,8 +2011,7 @@ class basic_json
     @since version 1.0.0
     */
     basic_json(basic_json&& other) noexcept
-        : m_type(std::move(other.m_type)),
-          m_value(std::move(other.m_value))
+        : m_type(std::move(other.m_type)), m_value(std::move(other.m_value))
     {
         // invalidate payload
         other.m_type = value_t::null;
@@ -2543,29 +2533,17 @@ class basic_json
                   , int>::type = 0>
     T get_impl(T*) const
     {
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return T(m_value.object->begin(), m_value.object->end());
-        }
-        else
-        {
-            throw std::domain_error("type must be object, but is " + type_name());
-        }
+        return is_object()
+               ? T(m_value.object->begin(), m_value.object->end())
+               : throw std::domain_error("type must be object, but is " + type_name());
     }
 
     /// get an object (explicit)
     object_t get_impl(object_t*) const
     {
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return *(m_value.object);
-        }
-        else
-        {
-            throw std::domain_error("type must be object, but is " + type_name());
-        }
+        return is_object()
+               ? *(m_value.object)
+               : throw std::domain_error("type must be object, but is " + type_name());
     }
 
     /// get an array (explicit)
@@ -2582,7 +2560,6 @@ class basic_json
         if (is_array())
         {
             T to_vector;
-            assert(m_value.array != nullptr);
             std::transform(m_value.array->begin(), m_value.array->end(),
                            std::inserter(to_vector, to_vector.end()), [](basic_json i)
             {
@@ -2607,7 +2584,6 @@ class basic_json
         if (is_array())
         {
             std::vector<T> to_vector;
-            assert(m_value.array != nullptr);
             to_vector.reserve(m_value.array->size());
             std::transform(m_value.array->begin(), m_value.array->end(),
                            std::inserter(to_vector, to_vector.end()), [](basic_json i)
@@ -2630,29 +2606,17 @@ class basic_json
                   , int>::type = 0>
     T get_impl(T*) const
     {
-        if (is_array())
-        {
-            assert(m_value.array != nullptr);
-            return T(m_value.array->begin(), m_value.array->end());
-        }
-        else
-        {
-            throw std::domain_error("type must be array, but is " + type_name());
-        }
+        return is_array()
+               ? T(m_value.array->begin(), m_value.array->end())
+               : throw std::domain_error("type must be array, but is " + type_name());
     }
 
     /// get an array (explicit)
     array_t get_impl(array_t*) const
     {
-        if (is_array())
-        {
-            assert(m_value.array != nullptr);
-            return *(m_value.array);
-        }
-        else
-        {
-            throw std::domain_error("type must be array, but is " + type_name());
-        }
+        return is_array()
+               ? *(m_value.array)
+               : throw std::domain_error("type must be array, but is " + type_name());
     }
 
     /// get a string (explicit)
@@ -2662,15 +2626,9 @@ class basic_json
                   , int>::type = 0>
     T get_impl(T*) const
     {
-        if (is_string())
-        {
-            assert(m_value.string != nullptr);
-            return *m_value.string;
-        }
-        else
-        {
-            throw std::domain_error("type must be string, but is " + type_name());
-        }
+        return is_string()
+               ? *m_value.string
+               : throw std::domain_error("type must be string, but is " + type_name());
     }
 
     /// get a number (explicit)
@@ -3140,7 +3098,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.array != nullptr);
                 return m_value.array->at(idx);
             }
             catch (std::out_of_range&)
@@ -3184,7 +3141,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.array != nullptr);
                 return m_value.array->at(idx);
             }
             catch (std::out_of_range&)
@@ -3232,7 +3188,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.object != nullptr);
                 return m_value.object->at(key);
             }
             catch (std::out_of_range&)
@@ -3280,7 +3235,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.object != nullptr);
                 return m_value.object->at(key);
             }
             catch (std::out_of_range&)
@@ -3333,7 +3287,6 @@ class basic_json
         if (is_array())
         {
             // fill up array with null values if given idx is outside range
-            assert(m_value.array != nullptr);
             if (idx >= m_value.array->size())
             {
                 m_value.array->insert(m_value.array->end(),
@@ -3371,15 +3324,9 @@ class basic_json
     const_reference operator[](size_type idx) const
     {
         // const operator[] only works for arrays
-        if (is_array())
-        {
-            assert(m_value.array != nullptr);
-            return m_value.array->operator[](idx);
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_array()
+               ? m_value.array->operator[](idx)
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3419,15 +3366,9 @@ class basic_json
         }
 
         // operator[] only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return m_value.object->operator[](key);
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->operator[](key)
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3460,16 +3401,9 @@ class basic_json
     const_reference operator[](const typename object_t::key_type& key) const
     {
         // const operator[] only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            assert(m_value.object->find(key) != m_value.object->end());
-            return m_value.object->find(key)->second;
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->find(key)->second
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3578,15 +3512,9 @@ class basic_json
         }
 
         // at only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return m_value.object->operator[](key);
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->operator[](key)
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3620,16 +3548,9 @@ class basic_json
     const_reference operator[](T* key) const
     {
         // at only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            assert(m_value.object->find(key) != m_value.object->end());
-            return m_value.object->find(key)->second;
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->find(key)->second
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3959,14 +3880,12 @@ class basic_json
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
                 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
                 break;
             }
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
                 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
                 break;
             }
@@ -4067,7 +3986,6 @@ class basic_json
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
                 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
                                               last.m_it.object_iterator);
                 break;
@@ -4075,7 +3993,6 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
                 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
                                              last.m_it.array_iterator);
                 break;
@@ -4122,15 +4039,9 @@ class basic_json
     size_type erase(const typename object_t::key_type& key)
     {
         // this erase only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return m_value.object->erase(key);
-        }
-        else
-        {
-            throw std::domain_error("cannot use erase() with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->erase(key)
+               : throw std::domain_error("cannot use erase() with " + type_name());
     }
 
     /*!
@@ -4167,7 +4078,6 @@ class basic_json
                 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
             }
 
-            assert(m_value.array != nullptr);
             m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
         }
         else
@@ -4210,7 +4120,6 @@ class basic_json
 
         if (is_object())
         {
-            assert(m_value.object != nullptr);
             result.m_it.object_iterator = m_value.object->find(key);
         }
 
@@ -4227,7 +4136,6 @@ class basic_json
 
         if (is_object())
         {
-            assert(m_value.object != nullptr);
             result.m_it.object_iterator = m_value.object->find(key);
         }
 
@@ -4255,7 +4163,6 @@ class basic_json
     size_type count(typename object_t::key_type key) const
     {
         // return 0 for all nonobject types
-        assert(not is_object() or m_value.object != nullptr);
         return is_object() ? m_value.object->count(key) : 0;
     }
 
@@ -4597,6 +4504,10 @@ class basic_json
             object      | result of function `object_t::empty()`
             array       | result of function `array_t::empty()`
 
+    @note This function does not return whether a string stored as JSON value
+    is empty - it returns whether the JSON container itself is empty which is
+    false in the case of a string.
+
     @complexity Constant, as long as @ref array_t and @ref object_t satisfy
     the Container concept; that is, their `empty()` functions have constant
     complexity.
@@ -4626,13 +4537,13 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
+                // delegate call to array_t::empty()
                 return m_value.array->empty();
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
+                // delegate call to object_t::empty()
                 return m_value.object->empty();
             }
 
@@ -4660,6 +4571,10 @@ class basic_json
             object      | result of function object_t::size()
             array       | result of function array_t::size()
 
+    @note This function does not return the length of a string stored as JSON
+    value - it returns the number of elements in the JSON value which is 1 in
+    the case of a string.
+
     @complexity Constant, as long as @ref array_t and @ref object_t satisfy
     the Container concept; that is, their size() functions have constant
     complexity.
@@ -4690,13 +4605,13 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
+                // delegate call to array_t::size()
                 return m_value.array->size();
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
+                // delegate call to object_t::size()
                 return m_value.object->size();
             }
 
@@ -4750,13 +4665,13 @@ class basic_json
         {
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
+                // delegate call to array_t::max_size()
                 return m_value.array->max_size();
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
+                // delegate call to object_t::max_size()
                 return m_value.object->max_size();
             }
 
@@ -4833,21 +4748,18 @@ class basic_json
 
             case value_t::string:
             {
-                assert(m_value.string != nullptr);
                 m_value.string->clear();
                 break;
             }
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
                 m_value.array->clear();
                 break;
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
                 m_value.object->clear();
                 break;
             }
@@ -4895,7 +4807,6 @@ class basic_json
         }
 
         // add element to array (move semantics)
-        assert(m_value.array != nullptr);
         m_value.array->push_back(std::move(val));
         // invalidate object
         val.m_type = value_t::null;
@@ -4931,7 +4842,6 @@ class basic_json
         }
 
         // add element to array
-        assert(m_value.array != nullptr);
         m_value.array->push_back(val);
     }
 
@@ -4981,7 +4891,6 @@ class basic_json
         }
 
         // add element to array
-        assert(m_value.object != nullptr);
         m_value.object->insert(val);
     }
 
@@ -5078,7 +4987,6 @@ class basic_json
 
             // insert to array and return iterator
             iterator result(this);
-            assert(m_value.array != nullptr);
             result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
             return result;
         }
@@ -5134,7 +5042,6 @@ class basic_json
 
             // insert to array and return iterator
             iterator result(this);
-            assert(m_value.array != nullptr);
             result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
             return result;
         }
@@ -5201,7 +5108,6 @@ class basic_json
 
         // insert to array and return iterator
         iterator result(this);
-        assert(m_value.array != nullptr);
         result.m_it.array_iterator = m_value.array->insert(
                                          pos.m_it.array_iterator,
                                          first.m_it.array_iterator,
@@ -5249,7 +5155,6 @@ class basic_json
 
         // insert to array and return iterator
         iterator result(this);
-        assert(m_value.array != nullptr);
         result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
         return result;
     }
@@ -5307,7 +5212,6 @@ class basic_json
         // swap only works for arrays
         if (is_array())
         {
-            assert(m_value.array != nullptr);
             std::swap(*(m_value.array), other);
         }
         else
@@ -5341,7 +5245,6 @@ class basic_json
         // swap only works for objects
         if (is_object())
         {
-            assert(m_value.object != nullptr);
             std::swap(*(m_value.object), other);
         }
         else
@@ -5375,7 +5278,6 @@ class basic_json
         // swap only works for strings
         if (is_string())
         {
-            assert(m_value.string != nullptr);
             std::swap(*(m_value.string), other);
         }
         else
@@ -5462,14 +5364,10 @@ class basic_json
             {
                 case value_t::array:
                 {
-                    assert(lhs.m_value.array != nullptr);
-                    assert(rhs.m_value.array != nullptr);
                     return *lhs.m_value.array == *rhs.m_value.array;
                 }
                 case value_t::object:
                 {
-                    assert(lhs.m_value.object != nullptr);
-                    assert(rhs.m_value.object != nullptr);
                     return *lhs.m_value.object == *rhs.m_value.object;
                 }
                 case value_t::null:
@@ -5478,8 +5376,6 @@ class basic_json
                 }
                 case value_t::string:
                 {
-                    assert(lhs.m_value.string != nullptr);
-                    assert(rhs.m_value.string != nullptr);
                     return *lhs.m_value.string == *rhs.m_value.string;
                 }
                 case value_t::boolean:
@@ -5652,14 +5548,10 @@ class basic_json
             {
                 case value_t::array:
                 {
-                    assert(lhs.m_value.array != nullptr);
-                    assert(rhs.m_value.array != nullptr);
                     return *lhs.m_value.array < *rhs.m_value.array;
                 }
                 case value_t::object:
                 {
-                    assert(lhs.m_value.object != nullptr);
-                    assert(rhs.m_value.object != nullptr);
                     return *lhs.m_value.object < *rhs.m_value.object;
                 }
                 case value_t::null:
@@ -5668,8 +5560,6 @@ class basic_json
                 }
                 case value_t::string:
                 {
-                    assert(lhs.m_value.string != nullptr);
-                    assert(rhs.m_value.string != nullptr);
                     return *lhs.m_value.string < *rhs.m_value.string;
                 }
                 case value_t::boolean:
@@ -5844,14 +5734,14 @@ class basic_json
         // string->float->string, string->double->string or string->long
         // double->string; to be safe, we read this value from
         // std::numeric_limits<number_float_t>::digits10
-        const auto old_preicison = o.precision(std::numeric_limits<double>::digits10);
+        const auto old_precision = o.precision(std::numeric_limits<double>::digits10);
 
         // do the actual serialization
         j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
 
         // reset locale and precision
         o.imbue(old_locale);
-        o.precision(old_preicison);
+        o.precision(old_precision);
         return o;
     }
 
@@ -6201,8 +6091,6 @@ class basic_json
         {
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
-
                 if (m_value.object->empty())
                 {
                     o << "{}";
@@ -6243,8 +6131,6 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
-
                 if (m_value.array->empty())
                 {
                     o << "[]";
@@ -6283,7 +6169,6 @@ class basic_json
 
             case value_t::string:
             {
-                assert(m_value.string != nullptr);
                 o << string_t("\"") << escape_string(*m_value.string) << "\"";
                 return;
             }
@@ -9522,7 +9407,6 @@ basic_json_parser_63:
             basic_json result;
 
             // iterate the JSON object values
-            assert(value.m_value.object != nullptr);
             for (const auto& element : *value.m_value.object)
             {
                 if (not element.second.is_primitive())
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 74db214e..73e6d8e5 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -621,8 +621,8 @@ class basic_json
     > that implementations will agree exactly on their numeric values.
 
     As this range is a subrange (when considered in conjunction with the
-    number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
-    class's integer type is interoperable.
+    number_integer_t type) of the exactly supported range [0, UINT64_MAX],
+    this class's integer type is interoperable.
 
     #### Storage
 
@@ -760,6 +760,7 @@ class basic_json
         };
         std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
         alloc.construct(object.get(), std::forward<Args>(args)...);
+        assert(object.get() != nullptr);
         return object.release();
     }
 
@@ -1415,8 +1416,8 @@ class basic_json
 
     Create an unsigned integer number JSON value with a given content.
 
-    @tparam T  helper type to compare number_unsigned_t and unsigned int
-    (not visible in) the interface.
+    @tparam T  helper type to compare number_unsigned_t and unsigned int (not
+    visible in) the interface.
 
     @param[in] val  an integer to create a JSON number from
 
@@ -1521,8 +1522,8 @@ class basic_json
     disallows NaN values:
     > Numeric values that cannot be represented in the grammar below (such as
     > Infinity and NaN) are not permitted.
-    In case the parameter @a val is not a number, a JSON null value is
-    created instead.
+    In case the parameter @a val is not a number, a JSON null value is created
+    instead.
 
     @complexity Constant.
 
@@ -1647,8 +1648,6 @@ class basic_json
             m_type = value_t::object;
             m_value = value_t::object;
 
-            assert(m_value.object != nullptr);
-
             std::for_each(init.begin(), init.end(), [this](const basic_json & element)
             {
                 m_value.object->emplace(*(element[0].m_value.string), element[1]);
@@ -1806,7 +1805,8 @@ class basic_json
                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value
                   , int>::type
               = 0>
-    basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
+    basic_json(InputIT first, InputIT last)
+        : m_type(first.m_object->m_type)
     {
         // make sure iterator fits the current value
         if (first.m_object != last.m_object)
@@ -1840,35 +1840,30 @@ class basic_json
         {
             case value_t::number_integer:
             {
-                assert(first.m_object != nullptr);
                 m_value.number_integer = first.m_object->m_value.number_integer;
                 break;
             }
 
             case value_t::number_unsigned:
             {
-                assert(first.m_object != nullptr);
                 m_value.number_unsigned = first.m_object->m_value.number_unsigned;
                 break;
             }
 
             case value_t::number_float:
             {
-                assert(first.m_object != nullptr);
                 m_value.number_float = first.m_object->m_value.number_float;
                 break;
             }
 
             case value_t::boolean:
             {
-                assert(first.m_object != nullptr);
                 m_value.boolean = first.m_object->m_value.boolean;
                 break;
             }
 
             case value_t::string:
             {
-                assert(first.m_object != nullptr);
                 m_value = *first.m_object->m_value.string;
                 break;
             }
@@ -1887,7 +1882,6 @@ class basic_json
 
             default:
             {
-                assert(first.m_object != nullptr);
                 throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
             }
         }
@@ -1951,21 +1945,18 @@ class basic_json
         {
             case value_t::object:
             {
-                assert(other.m_value.object != nullptr);
                 m_value = *other.m_value.object;
                 break;
             }
 
             case value_t::array:
             {
-                assert(other.m_value.array != nullptr);
                 m_value = *other.m_value.array;
                 break;
             }
 
             case value_t::string:
             {
-                assert(other.m_value.string != nullptr);
                 m_value = *other.m_value.string;
                 break;
             }
@@ -2020,8 +2011,7 @@ class basic_json
     @since version 1.0.0
     */
     basic_json(basic_json&& other) noexcept
-        : m_type(std::move(other.m_type)),
-          m_value(std::move(other.m_value))
+        : m_type(std::move(other.m_type)), m_value(std::move(other.m_value))
     {
         // invalidate payload
         other.m_type = value_t::null;
@@ -2543,29 +2533,17 @@ class basic_json
                   , int>::type = 0>
     T get_impl(T*) const
     {
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return T(m_value.object->begin(), m_value.object->end());
-        }
-        else
-        {
-            throw std::domain_error("type must be object, but is " + type_name());
-        }
+        return is_object()
+               ? T(m_value.object->begin(), m_value.object->end())
+               : throw std::domain_error("type must be object, but is " + type_name());
     }
 
     /// get an object (explicit)
     object_t get_impl(object_t*) const
     {
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return *(m_value.object);
-        }
-        else
-        {
-            throw std::domain_error("type must be object, but is " + type_name());
-        }
+        return is_object()
+               ? *(m_value.object)
+               : throw std::domain_error("type must be object, but is " + type_name());
     }
 
     /// get an array (explicit)
@@ -2582,7 +2560,6 @@ class basic_json
         if (is_array())
         {
             T to_vector;
-            assert(m_value.array != nullptr);
             std::transform(m_value.array->begin(), m_value.array->end(),
                            std::inserter(to_vector, to_vector.end()), [](basic_json i)
             {
@@ -2607,7 +2584,6 @@ class basic_json
         if (is_array())
         {
             std::vector<T> to_vector;
-            assert(m_value.array != nullptr);
             to_vector.reserve(m_value.array->size());
             std::transform(m_value.array->begin(), m_value.array->end(),
                            std::inserter(to_vector, to_vector.end()), [](basic_json i)
@@ -2630,29 +2606,17 @@ class basic_json
                   , int>::type = 0>
     T get_impl(T*) const
     {
-        if (is_array())
-        {
-            assert(m_value.array != nullptr);
-            return T(m_value.array->begin(), m_value.array->end());
-        }
-        else
-        {
-            throw std::domain_error("type must be array, but is " + type_name());
-        }
+        return is_array()
+               ? T(m_value.array->begin(), m_value.array->end())
+               : throw std::domain_error("type must be array, but is " + type_name());
     }
 
     /// get an array (explicit)
     array_t get_impl(array_t*) const
     {
-        if (is_array())
-        {
-            assert(m_value.array != nullptr);
-            return *(m_value.array);
-        }
-        else
-        {
-            throw std::domain_error("type must be array, but is " + type_name());
-        }
+        return is_array()
+               ? *(m_value.array)
+               : throw std::domain_error("type must be array, but is " + type_name());
     }
 
     /// get a string (explicit)
@@ -2662,15 +2626,9 @@ class basic_json
                   , int>::type = 0>
     T get_impl(T*) const
     {
-        if (is_string())
-        {
-            assert(m_value.string != nullptr);
-            return *m_value.string;
-        }
-        else
-        {
-            throw std::domain_error("type must be string, but is " + type_name());
-        }
+        return is_string()
+               ? *m_value.string
+               : throw std::domain_error("type must be string, but is " + type_name());
     }
 
     /// get a number (explicit)
@@ -3140,7 +3098,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.array != nullptr);
                 return m_value.array->at(idx);
             }
             catch (std::out_of_range&)
@@ -3184,7 +3141,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.array != nullptr);
                 return m_value.array->at(idx);
             }
             catch (std::out_of_range&)
@@ -3232,7 +3188,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.object != nullptr);
                 return m_value.object->at(key);
             }
             catch (std::out_of_range&)
@@ -3280,7 +3235,6 @@ class basic_json
         {
             try
             {
-                assert(m_value.object != nullptr);
                 return m_value.object->at(key);
             }
             catch (std::out_of_range&)
@@ -3333,7 +3287,6 @@ class basic_json
         if (is_array())
         {
             // fill up array with null values if given idx is outside range
-            assert(m_value.array != nullptr);
             if (idx >= m_value.array->size())
             {
                 m_value.array->insert(m_value.array->end(),
@@ -3371,15 +3324,9 @@ class basic_json
     const_reference operator[](size_type idx) const
     {
         // const operator[] only works for arrays
-        if (is_array())
-        {
-            assert(m_value.array != nullptr);
-            return m_value.array->operator[](idx);
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_array()
+               ? m_value.array->operator[](idx)
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3419,15 +3366,9 @@ class basic_json
         }
 
         // operator[] only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return m_value.object->operator[](key);
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->operator[](key)
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3460,16 +3401,9 @@ class basic_json
     const_reference operator[](const typename object_t::key_type& key) const
     {
         // const operator[] only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            assert(m_value.object->find(key) != m_value.object->end());
-            return m_value.object->find(key)->second;
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->find(key)->second
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3578,15 +3512,9 @@ class basic_json
         }
 
         // at only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return m_value.object->operator[](key);
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->operator[](key)
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3620,16 +3548,9 @@ class basic_json
     const_reference operator[](T* key) const
     {
         // at only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            assert(m_value.object->find(key) != m_value.object->end());
-            return m_value.object->find(key)->second;
-        }
-        else
-        {
-            throw std::domain_error("cannot use operator[] with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->find(key)->second
+               : throw std::domain_error("cannot use operator[] with " + type_name());
     }
 
     /*!
@@ -3959,14 +3880,12 @@ class basic_json
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
                 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
                 break;
             }
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
                 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
                 break;
             }
@@ -4067,7 +3986,6 @@ class basic_json
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
                 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
                                               last.m_it.object_iterator);
                 break;
@@ -4075,7 +3993,6 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
                 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
                                              last.m_it.array_iterator);
                 break;
@@ -4122,15 +4039,9 @@ class basic_json
     size_type erase(const typename object_t::key_type& key)
     {
         // this erase only works for objects
-        if (is_object())
-        {
-            assert(m_value.object != nullptr);
-            return m_value.object->erase(key);
-        }
-        else
-        {
-            throw std::domain_error("cannot use erase() with " + type_name());
-        }
+        return is_object()
+               ? m_value.object->erase(key)
+               : throw std::domain_error("cannot use erase() with " + type_name());
     }
 
     /*!
@@ -4167,7 +4078,6 @@ class basic_json
                 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
             }
 
-            assert(m_value.array != nullptr);
             m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
         }
         else
@@ -4210,7 +4120,6 @@ class basic_json
 
         if (is_object())
         {
-            assert(m_value.object != nullptr);
             result.m_it.object_iterator = m_value.object->find(key);
         }
 
@@ -4227,7 +4136,6 @@ class basic_json
 
         if (is_object())
         {
-            assert(m_value.object != nullptr);
             result.m_it.object_iterator = m_value.object->find(key);
         }
 
@@ -4255,7 +4163,6 @@ class basic_json
     size_type count(typename object_t::key_type key) const
     {
         // return 0 for all nonobject types
-        assert(not is_object() or m_value.object != nullptr);
         return is_object() ? m_value.object->count(key) : 0;
     }
 
@@ -4597,6 +4504,10 @@ class basic_json
             object      | result of function `object_t::empty()`
             array       | result of function `array_t::empty()`
 
+    @note This function does not return whether a string stored as JSON value
+    is empty - it returns whether the JSON container itself is empty which is
+    false in the case of a string.
+
     @complexity Constant, as long as @ref array_t and @ref object_t satisfy
     the Container concept; that is, their `empty()` functions have constant
     complexity.
@@ -4626,13 +4537,13 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
+                // delegate call to array_t::empty()
                 return m_value.array->empty();
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
+                // delegate call to object_t::empty()
                 return m_value.object->empty();
             }
 
@@ -4660,6 +4571,10 @@ class basic_json
             object      | result of function object_t::size()
             array       | result of function array_t::size()
 
+    @note This function does not return the length of a string stored as JSON
+    value - it returns the number of elements in the JSON value which is 1 in
+    the case of a string.
+
     @complexity Constant, as long as @ref array_t and @ref object_t satisfy
     the Container concept; that is, their size() functions have constant
     complexity.
@@ -4690,13 +4605,13 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
+                // delegate call to array_t::size()
                 return m_value.array->size();
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
+                // delegate call to object_t::size()
                 return m_value.object->size();
             }
 
@@ -4750,13 +4665,13 @@ class basic_json
         {
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
+                // delegate call to array_t::max_size()
                 return m_value.array->max_size();
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
+                // delegate call to object_t::max_size()
                 return m_value.object->max_size();
             }
 
@@ -4833,21 +4748,18 @@ class basic_json
 
             case value_t::string:
             {
-                assert(m_value.string != nullptr);
                 m_value.string->clear();
                 break;
             }
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
                 m_value.array->clear();
                 break;
             }
 
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
                 m_value.object->clear();
                 break;
             }
@@ -4895,7 +4807,6 @@ class basic_json
         }
 
         // add element to array (move semantics)
-        assert(m_value.array != nullptr);
         m_value.array->push_back(std::move(val));
         // invalidate object
         val.m_type = value_t::null;
@@ -4931,7 +4842,6 @@ class basic_json
         }
 
         // add element to array
-        assert(m_value.array != nullptr);
         m_value.array->push_back(val);
     }
 
@@ -4981,7 +4891,6 @@ class basic_json
         }
 
         // add element to array
-        assert(m_value.object != nullptr);
         m_value.object->insert(val);
     }
 
@@ -5078,7 +4987,6 @@ class basic_json
 
             // insert to array and return iterator
             iterator result(this);
-            assert(m_value.array != nullptr);
             result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
             return result;
         }
@@ -5134,7 +5042,6 @@ class basic_json
 
             // insert to array and return iterator
             iterator result(this);
-            assert(m_value.array != nullptr);
             result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
             return result;
         }
@@ -5201,7 +5108,6 @@ class basic_json
 
         // insert to array and return iterator
         iterator result(this);
-        assert(m_value.array != nullptr);
         result.m_it.array_iterator = m_value.array->insert(
                                          pos.m_it.array_iterator,
                                          first.m_it.array_iterator,
@@ -5249,7 +5155,6 @@ class basic_json
 
         // insert to array and return iterator
         iterator result(this);
-        assert(m_value.array != nullptr);
         result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
         return result;
     }
@@ -5307,7 +5212,6 @@ class basic_json
         // swap only works for arrays
         if (is_array())
         {
-            assert(m_value.array != nullptr);
             std::swap(*(m_value.array), other);
         }
         else
@@ -5341,7 +5245,6 @@ class basic_json
         // swap only works for objects
         if (is_object())
         {
-            assert(m_value.object != nullptr);
             std::swap(*(m_value.object), other);
         }
         else
@@ -5375,7 +5278,6 @@ class basic_json
         // swap only works for strings
         if (is_string())
         {
-            assert(m_value.string != nullptr);
             std::swap(*(m_value.string), other);
         }
         else
@@ -5462,14 +5364,10 @@ class basic_json
             {
                 case value_t::array:
                 {
-                    assert(lhs.m_value.array != nullptr);
-                    assert(rhs.m_value.array != nullptr);
                     return *lhs.m_value.array == *rhs.m_value.array;
                 }
                 case value_t::object:
                 {
-                    assert(lhs.m_value.object != nullptr);
-                    assert(rhs.m_value.object != nullptr);
                     return *lhs.m_value.object == *rhs.m_value.object;
                 }
                 case value_t::null:
@@ -5478,8 +5376,6 @@ class basic_json
                 }
                 case value_t::string:
                 {
-                    assert(lhs.m_value.string != nullptr);
-                    assert(rhs.m_value.string != nullptr);
                     return *lhs.m_value.string == *rhs.m_value.string;
                 }
                 case value_t::boolean:
@@ -5652,14 +5548,10 @@ class basic_json
             {
                 case value_t::array:
                 {
-                    assert(lhs.m_value.array != nullptr);
-                    assert(rhs.m_value.array != nullptr);
                     return *lhs.m_value.array < *rhs.m_value.array;
                 }
                 case value_t::object:
                 {
-                    assert(lhs.m_value.object != nullptr);
-                    assert(rhs.m_value.object != nullptr);
                     return *lhs.m_value.object < *rhs.m_value.object;
                 }
                 case value_t::null:
@@ -5668,8 +5560,6 @@ class basic_json
                 }
                 case value_t::string:
                 {
-                    assert(lhs.m_value.string != nullptr);
-                    assert(rhs.m_value.string != nullptr);
                     return *lhs.m_value.string < *rhs.m_value.string;
                 }
                 case value_t::boolean:
@@ -5844,14 +5734,14 @@ class basic_json
         // string->float->string, string->double->string or string->long
         // double->string; to be safe, we read this value from
         // std::numeric_limits<number_float_t>::digits10
-        const auto old_preicison = o.precision(std::numeric_limits<double>::digits10);
+        const auto old_precision = o.precision(std::numeric_limits<double>::digits10);
 
         // do the actual serialization
         j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
 
         // reset locale and precision
         o.imbue(old_locale);
-        o.precision(old_preicison);
+        o.precision(old_precision);
         return o;
     }
 
@@ -6201,8 +6091,6 @@ class basic_json
         {
             case value_t::object:
             {
-                assert(m_value.object != nullptr);
-
                 if (m_value.object->empty())
                 {
                     o << "{}";
@@ -6243,8 +6131,6 @@ class basic_json
 
             case value_t::array:
             {
-                assert(m_value.array != nullptr);
-
                 if (m_value.array->empty())
                 {
                     o << "[]";
@@ -6283,7 +6169,6 @@ class basic_json
 
             case value_t::string:
             {
-                assert(m_value.string != nullptr);
                 o << string_t("\"") << escape_string(*m_value.string) << "\"";
                 return;
             }
@@ -8819,7 +8704,6 @@ class basic_json
             basic_json result;
 
             // iterate the JSON object values
-            assert(value.m_value.object != nullptr);
             for (const auto& element : *value.m_value.object)
             {
                 if (not element.second.is_primitive())