From 7b3cbfff23d601706bf8257009d1d6b8277e6165 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Sun, 23 Jul 2017 23:47:15 +0300
Subject: [PATCH 1/8] Add some tests for std::move from std::initializer_list

---
 test/src/unit-constructor1.cpp | 119 +++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp
index 7822b634..a8f5deb8 100644
--- a/test/src/unit-constructor1.cpp
+++ b/test/src/unit-constructor1.cpp
@@ -1034,6 +1034,125 @@ TEST_CASE("constructors")
                 CHECK(j.type() == json::value_t::array);
             }
         }
+
+        SECTION("move from initializer_list")
+        {
+            SECTION("string")
+            {
+                // This should break through any short string optimization in std::string
+                std::string source(1024, '!');
+                const char* source_addr = source.data();
+
+                SECTION("constructor with implicit types (array)")
+                {
+                    json j = {std::move(source)};
+                    CHECK(j[0].get_ref<std::string const&>().data() == source_addr);
+                }
+
+                SECTION("constructor with implicit types (object)")
+                {
+                    json j = {{"key", std::move(source)}};
+                    CHECK(j["key"].get_ref<std::string const&>().data() == source_addr);
+                }
+
+                SECTION("constructor with implicit types (object key)")
+                {
+                    json j = {{std::move(source), 42}};
+                    CHECK(j.get_ref<json::object_t&>().begin()->first.data() == source_addr);
+                }
+            }
+
+            SECTION("array")
+            {
+                json::array_t source = {1, 2, 3};
+                const json* source_addr = source.data();
+
+                SECTION("constructor with implicit types (array)")
+                {
+                    json j {std::move(source)};
+                    CHECK(j[0].get_ref<json::array_t const&>().data() == source_addr);
+                }
+
+                SECTION("constructor with implicit types (object)")
+                {
+                    json j {{"key", std::move(source)}};
+                    CHECK(j["key"].get_ref<json::array_t const&>().data() == source_addr);
+                }
+
+                SECTION("assignment with implicit types (array)")
+                {
+                    json j = {std::move(source)};
+                    CHECK(j[0].get_ref<json::array_t const&>().data() == source_addr);
+                }
+
+                SECTION("assignment with implicit types (object)")
+                {
+                    json j = {{"key", std::move(source)}};
+                    CHECK(j["key"].get_ref<json::array_t const&>().data() == source_addr);
+                }
+            }
+
+            SECTION("object")
+            {
+                json::object_t source = {{"hello", "world"}};
+                const json* source_addr = &source.at("hello");
+
+                SECTION("constructor with implicit types (array)")
+                {
+                    json j {std::move(source)};
+                    CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
+                }
+
+                SECTION("constructor with implicit types (object)")
+                {
+                    json j {{"key", std::move(source)}};
+                    CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
+                }
+
+                SECTION("assignment with implicit types (array)")
+                {
+                    json j = {std::move(source)};
+                    CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
+                }
+
+                SECTION("assignment with implicit types (object)")
+                {
+                    json j = {{"key", std::move(source)}};
+                    CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
+                }
+            }
+
+            SECTION("json")
+            {
+                json source {1, 2, 3};
+                const json* source_addr = &source[0];
+
+                SECTION("constructor with implicit types (array)")
+                {
+                    json j {std::move(source)};
+                    CHECK(&j[0][0] == source_addr);
+                }
+
+                SECTION("constructor with implicit types (object)")
+                {
+                    json j {{"key", std::move(source)}};
+                    CHECK(&j["key"][0] == source_addr);
+                }
+
+                SECTION("assignment with implicit types (array)")
+                {
+                    json j = {std::move(source)};
+                    CHECK(&j[0][0] == source_addr);
+                }
+
+                SECTION("assignment with implicit types (object)")
+                {
+                    json j = {{"key", std::move(source)}};
+                    CHECK(&j["key"][0] == source_addr);
+                }
+            }
+
+        }
     }
 
     SECTION("create an array of n copies of a given value")

From cf3ca3b78c09eb0c2e834d2185d4f3d36f8a6ab2 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Sun, 23 Jul 2017 23:50:59 +0300
Subject: [PATCH 2/8] Optimize json construction from rvalue
 string_t/array_t/object_t

---
 src/json.hpp | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 63f5d2b8..bca6b833 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -579,6 +579,14 @@ struct external_constructor<value_t::string>
         j.m_value = s;
         j.assert_invariant();
     }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&&  s)
+    {
+        j.m_type = value_t::string;
+        j.m_value = std::move(s);
+        j.assert_invariant();
+    }
 };
 
 template<>
@@ -628,6 +636,14 @@ struct external_constructor<value_t::array>
         j.assert_invariant();
     }
 
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&&  arr)
+    {
+        j.m_type = value_t::array;
+        j.m_value = std::move(arr);
+        j.assert_invariant();
+    }
+
     template<typename BasicJsonType, typename CompatibleArrayType,
              enable_if_t<not std::is_same<CompatibleArrayType,
                                           typename BasicJsonType::array_t>::value,
@@ -666,6 +682,14 @@ struct external_constructor<value_t::object>
         j.assert_invariant();
     }
 
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&&  obj)
+    {
+        j.m_type = value_t::object;
+        j.m_value = std::move(obj);
+        j.assert_invariant();
+    }
+
     template<typename BasicJsonType, typename CompatibleObjectType,
              enable_if_t<not std::is_same<CompatibleObjectType,
                                           typename BasicJsonType::object_t>::value,
@@ -858,6 +882,12 @@ void to_json(BasicJsonType& j, const CompatibleString& s)
     external_constructor<value_t::string>::construct(j, s);
 }
 
+template <typename BasicJsonType>
+void to_json(BasicJsonType& j, typename BasicJsonType::string_t&&  s)
+{
+    external_constructor<value_t::string>::construct(j, std::move(s));
+}
+
 template<typename BasicJsonType, typename FloatType,
          enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
 void to_json(BasicJsonType& j, FloatType val) noexcept
@@ -908,13 +938,25 @@ void to_json(BasicJsonType& j, const  CompatibleArrayType& arr)
     external_constructor<value_t::array>::construct(j, arr);
 }
 
+template <typename BasicJsonType>
+void to_json(BasicJsonType& j, typename BasicJsonType::array_t&&  arr)
+{
+    external_constructor<value_t::array>::construct(j, std::move(arr));
+}
+
 template <
     typename BasicJsonType, typename CompatibleObjectType,
     enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value,
                 int> = 0 >
-void to_json(BasicJsonType& j, const  CompatibleObjectType& arr)
+void to_json(BasicJsonType& j, const  CompatibleObjectType& obj)
 {
-    external_constructor<value_t::object>::construct(j, arr);
+    external_constructor<value_t::object>::construct(j, obj);
+}
+
+template <typename BasicJsonType>
+void to_json(BasicJsonType& j, typename BasicJsonType::object_t&&  obj)
+{
+    external_constructor<value_t::object>::construct(j, std::move(obj));
 }
 
 template <typename BasicJsonType, typename T, std::size_t N,
@@ -8269,18 +8311,36 @@ class basic_json
             string = create<string_t>(value);
         }
 
+        /// constructor for rvalue strings
+        json_value(string_t&&  value)
+        {
+            string = create<string_t>(std::move(value));
+        }
+
         /// constructor for objects
         json_value(const object_t& value)
         {
             object = create<object_t>(value);
         }
 
+        /// constructor for rvalue objects
+        json_value(object_t&&  value)
+        {
+            object = create<object_t>(std::move(value));
+        }
+
         /// constructor for arrays
         json_value(const array_t& value)
         {
             array = create<array_t>(value);
         }
 
+        /// constructor for rvalue arrays
+        json_value(array_t&&  value)
+        {
+            array = create<array_t>(std::move(value));
+        }
+
         void destroy(value_t t)
         {
             switch (t)

From 09cda573096f125877b9e6195af6f11082607bc0 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Sun, 23 Jul 2017 23:57:17 +0300
Subject: [PATCH 3/8] Support moving from rvalues in an std::initializer_list

This commit works around an issue in std::initializer_list design.
By using a detail::json_ref proxy with a mutable value inside,
rvalue-ness of an input to list initializer is remembered and
used later to move from the proxy instead of copying.
---
 src/json.hpp | 129 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 95 insertions(+), 34 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index bca6b833..79ae9978 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -7081,6 +7081,60 @@ class serializer
     /// the indentation string
     string_t indent_string;
 };
+
+template<typename BasicJsonType>
+struct json_ref
+{
+    typedef BasicJsonType value_type;
+
+    json_ref(value_type&&  value)
+        : value_(std::move(value))
+        , is_rvalue_(true)
+    {}
+
+    json_ref(const value_type& value)
+        : value_(value)
+        , is_rvalue_(false)
+    {}
+
+    json_ref(std::initializer_list<json_ref> init)
+        : value_(init)
+        , is_rvalue_(true)
+    {}
+
+    template <class... Args>
+    json_ref(Args... args)
+        : value_(std::forward<Args>(args)...)
+        , is_rvalue_(true)
+    {}
+
+    value_type moved() const
+    {
+        if (is_rvalue_)
+        {
+            return std::move(value_);
+        }
+        else
+        {
+            return value_;
+        }
+    }
+
+    value_type const& operator*() const
+    {
+        return value_;
+    }
+
+    value_type const* operator->() const
+    {
+        return &value_;
+    }
+
+  private:
+    mutable value_type value_;
+    bool is_rvalue_;
+};
+
 } // namespace detail
 
 /// namespace to hold default `to_json` / `from_json` functions
@@ -7583,6 +7637,7 @@ class basic_json
     template<typename T, typename SFINAE>
     using json_serializer = JSONSerializer<T, SFINAE>;
 
+    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
 
     ////////////////
     // exceptions //
@@ -8614,10 +8669,10 @@ class basic_json
     With the rules described above, the following JSON values cannot be
     expressed by an initializer list:
 
-    - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>)
+    - the empty array (`[]`): use @ref array(initializer_list_t)
       with an empty initializer list in this case
     - arrays whose elements satisfy rule 2: use @ref
-      array(std::initializer_list<basic_json>) with the same initializer list
+      array(initializer_list_t) with the same initializer list
       in this case
 
     @note When used without parentheses around an empty initializer list, @ref
@@ -8629,8 +8684,8 @@ class basic_json
     @param[in] type_deduction internal parameter; when set to `true`, the type
     of the JSON value is deducted from the initializer list @a init; when set
     to `false`, the type provided via @a manual_type is forced. This mode is
-    used by the functions @ref array(std::initializer_list<basic_json>) and
-    @ref object(std::initializer_list<basic_json>).
+    used by the functions @ref array(initializer_list_t) and
+    @ref object(initializer_list_t).
 
     @param[in] manual_type internal parameter; when @a type_deduction is set
     to `false`, the created JSON value will use the provided type (only @ref
@@ -8641,7 +8696,7 @@ class basic_json
     `value_t::object`, but @a init contains an element which is not a pair
     whose first element is a string. In this case, the constructor could not
     create an object. If @a type_deduction would have be `true`, an array
-    would have been created. See @ref object(std::initializer_list<basic_json>)
+    would have been created. See @ref object(initializer_list_t)
     for an example.
 
     @complexity Linear in the size of the initializer list @a init.
@@ -8649,23 +8704,23 @@ class basic_json
     @liveexample{The example below shows how JSON values are created from
     initializer lists.,basic_json__list_init_t}
 
-    @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
+    @sa @ref array(initializer_list_t) -- create a JSON array
     value from an initializer list
-    @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
+    @sa @ref object(initializer_list_t) -- create a JSON object
     value from an initializer list
 
     @since version 1.0.0
     */
-    basic_json(std::initializer_list<basic_json> init,
+    basic_json(initializer_list_t init,
                bool type_deduction = true,
                value_t manual_type = value_t::array)
     {
         // check if each element is an array with two elements whose first
         // element is a string
         bool is_an_object = std::all_of(init.begin(), init.end(),
-                                        [](const basic_json & element)
+                                        [](const detail::json_ref<basic_json>& element_ref)
         {
-            return element.is_array() and element.size() == 2 and element[0].is_string();
+            return element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string();
         });
 
         // adjust type if type deduction is not wanted
@@ -8690,16 +8745,19 @@ class basic_json
             m_type = value_t::object;
             m_value = value_t::object;
 
-            std::for_each(init.begin(), init.end(), [this](const basic_json & element)
+            std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
             {
-                m_value.object->emplace(*(element[0].m_value.string), element[1]);
+                basic_json element = element_ref.moved();
+                m_value.object->emplace(
+                    std::move(*((*element.m_value.array)[0].m_value.string)),
+                    std::move((*element.m_value.array)[1]));
             });
         }
         else
         {
             // the initializer list describes an array -> create array
             m_type = value_t::array;
-            m_value.array = create<array_t>(init);
+            m_value.array = create<array_t>(init.begin(), init.end());
         }
 
         assert_invariant();
@@ -8714,7 +8772,7 @@ class basic_json
 
     @note This function is only needed to express two edge cases that cannot
     be realized with the initializer list constructor (@ref
-    basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
+    basic_json(initializer_list_t, bool, value_t)). These cases
     are:
     1. creating an array whose elements are all pairs whose first element is a
     string -- in this case, the initializer list constructor would create an
@@ -8732,15 +8790,14 @@ class basic_json
     @liveexample{The following code shows an example for the `array`
     function.,array}
 
-    @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
+    @sa @ref basic_json(initializer_list_t, bool, value_t) --
     create a JSON value from an initializer list
-    @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
+    @sa @ref object(initializer_list_t) -- create a JSON object
     value from an initializer list
 
     @since version 1.0.0
     */
-    static basic_json array(std::initializer_list<basic_json> init =
-                                std::initializer_list<basic_json>())
+    static basic_json array(initializer_list_t init = {})
     {
         return basic_json(init, false, value_t::array);
     }
@@ -8753,10 +8810,10 @@ class basic_json
     the initializer list is empty, the empty object `{}` is created.
 
     @note This function is only added for symmetry reasons. In contrast to the
-    related function @ref array(std::initializer_list<basic_json>), there are
+    related function @ref array(initializer_list_t), there are
     no cases which can only be expressed by this function. That is, any
     initializer list @a init can also be passed to the initializer list
-    constructor @ref basic_json(std::initializer_list<basic_json>, bool, value_t).
+    constructor @ref basic_json(initializer_list_t, bool, value_t).
 
     @param[in] init  initializer list to create an object from (optional)
 
@@ -8764,7 +8821,7 @@ class basic_json
 
     @throw type_error.301 if @a init is not a list of pairs whose first
     elements are strings. In this case, no object can be created. When such a
-    value is passed to @ref basic_json(std::initializer_list<basic_json>, bool, value_t),
+    value is passed to @ref basic_json(initializer_list_t, bool, value_t),
     an array would have been created from the passed initializer list @a init.
     See example below.
 
@@ -8773,15 +8830,14 @@ class basic_json
     @liveexample{The following code shows an example for the `object`
     function.,object}
 
-    @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
+    @sa @ref basic_json(initializer_list_t, bool, value_t) --
     create a JSON value from an initializer list
-    @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
+    @sa @ref array(initializer_list_t) -- create a JSON array
     value from an initializer list
 
     @since version 1.0.0
     */
-    static basic_json object(std::initializer_list<basic_json> init =
-                                 std::initializer_list<basic_json>())
+    static basic_json object(initializer_list_t init = {})
     {
         return basic_json(init, false, value_t::object);
     }
@@ -8953,6 +9009,11 @@ class basic_json
     // other constructors and destructor //
     ///////////////////////////////////////
 
+    basic_json(const detail::json_ref<basic_json>& ref)
+        : basic_json(ref.moved())
+    {
+    }
+
     /*!
     @brief copy constructor
 
@@ -11755,7 +11816,7 @@ class basic_json
     @brief add an object to an array
     @copydoc push_back(basic_json&&)
     */
-    reference operator+=(basic_json&& val)
+    reference operator+=(basic_json && val)
     {
         push_back(std::move(val));
         return *this;
@@ -11870,12 +11931,12 @@ class basic_json
     @liveexample{The example shows how initializer lists are treated as
     objects when possible.,push_back__initializer_list}
     */
-    void push_back(std::initializer_list<basic_json> init)
+    void push_back(initializer_list_t init)
     {
-        if (is_object() and init.size() == 2 and init.begin()->is_string())
+        if (is_object() and init.size() == 2 and (*init.begin())->is_string())
         {
-            const string_t key = *init.begin();
-            push_back(typename object_t::value_type(key, *(init.begin() + 1)));
+            basic_json&&  key = init.begin()->moved();
+            push_back(typename object_t::value_type(std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved()));
         }
         else
         {
@@ -11885,9 +11946,9 @@ class basic_json
 
     /*!
     @brief add an object to an object
-    @copydoc push_back(std::initializer_list<basic_json>)
+    @copydoc push_back(initializer_list_t)
     */
-    reference operator+=(std::initializer_list<basic_json> init)
+    reference operator+=(initializer_list_t init)
     {
         push_back(init);
         return *this;
@@ -12172,7 +12233,7 @@ class basic_json
 
     @since version 1.0.0
     */
-    iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
+    iterator insert(const_iterator pos, initializer_list_t ilist)
     {
         // insert only works for arrays
         if (not is_array())
@@ -12188,7 +12249,7 @@ 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, ilist);
+        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end());
         return result;
     }
 

From f5cae64e525715e715fca97d0b2634a0968dc789 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Sun, 23 Jul 2017 23:59:34 +0300
Subject: [PATCH 4/8] Update tests while fixing possible UB

std::initializer_list does not own the temporaries created in
its initialization. Therefore, storing it in an independent
stack variable is unsafe.
---
 test/src/unit-constructor1.cpp | 27 +++++++++------------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp
index a8f5deb8..446bb0b3 100644
--- a/test/src/unit-constructor1.cpp
+++ b/test/src/unit-constructor1.cpp
@@ -842,8 +842,7 @@ TEST_CASE("constructors")
         {
             SECTION("explicit")
             {
-                std::initializer_list<json> l;
-                json j(l);
+                json j(json::initializer_list_t {});
                 CHECK(j.type() == json::value_t::object);
             }
 
@@ -860,8 +859,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json(json::array_t())};
-                    json j(l);
+                    json j(json::initializer_list_t {json(json::array_t())});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -876,8 +874,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json(json::object_t())};
-                    json j(l);
+                    json j(json::initializer_list_t {json(json::object_t())});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -892,8 +889,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json("Hello world")};
-                    json j(l);
+                    json j(json::initializer_list_t {json("Hello world")});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -908,8 +904,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json(true)};
-                    json j(l);
+                    json j(json::initializer_list_t {json(true)});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -924,8 +919,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json(1)};
-                    json j(l);
+                    json j(json::initializer_list_t {json(1)});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -940,8 +934,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json(1u)};
-                    json j(l);
+                    json j(json::initializer_list_t {json(1u)});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -956,8 +949,7 @@ TEST_CASE("constructors")
             {
                 SECTION("explicit")
                 {
-                    std::initializer_list<json> l = {json(42.23)};
-                    json j(l);
+                    json j(json::initializer_list_t {json(42.23)});
                     CHECK(j.type() == json::value_t::array);
                 }
 
@@ -973,8 +965,7 @@ TEST_CASE("constructors")
         {
             SECTION("explicit")
             {
-                std::initializer_list<json> l = {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()};
-                json j(l);
+                json j(json::initializer_list_t {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()});
                 CHECK(j.type() == json::value_t::array);
             }
 

From 0f4978e503eb378e5efd3f6628ec7af7ca01a3a7 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Mon, 24 Jul 2017 01:02:03 +0300
Subject: [PATCH 5/8] Fix an actually invalid test

C++ overload resolution/list initialization rules are hard.
---
 test/src/unit-constructor1.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp
index 446bb0b3..5130e505 100644
--- a/test/src/unit-constructor1.cpp
+++ b/test/src/unit-constructor1.cpp
@@ -1120,7 +1120,7 @@ TEST_CASE("constructors")
 
                 SECTION("constructor with implicit types (array)")
                 {
-                    json j {std::move(source)};
+                    json j {std::move(source), {}};
                     CHECK(&j[0][0] == source_addr);
                 }
 
@@ -1132,7 +1132,7 @@ TEST_CASE("constructors")
 
                 SECTION("assignment with implicit types (array)")
                 {
-                    json j = {std::move(source)};
+                    json j = {std::move(source), {}};
                     CHECK(&j[0][0] == source_addr);
                 }
 

From 897879bccbf3b4f1203d0c97360874ee4479dc53 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Mon, 24 Jul 2017 12:29:06 +0300
Subject: [PATCH 6/8] Make detail::json_ref do less work by deferring
 moves/copies

---
 src/json.hpp | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 79ae9978..ab725f55 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -7088,50 +7088,55 @@ struct json_ref
     typedef BasicJsonType value_type;
 
     json_ref(value_type&&  value)
-        : value_(std::move(value))
+        : value_ref_(&value)
         , is_rvalue_(true)
     {}
 
     json_ref(const value_type& value)
-        : value_(value)
+        : value_ref_(const_cast<value_type*>(&value))
         , is_rvalue_(false)
     {}
 
     json_ref(std::initializer_list<json_ref> init)
-        : value_(init)
+        : owned_value_(init)
         , is_rvalue_(true)
-    {}
+    {
+        value_ref_ = &owned_value_;
+    }
 
     template <class... Args>
     json_ref(Args... args)
-        : value_(std::forward<Args>(args)...)
+        : owned_value_(std::forward<Args>(args)...)
         , is_rvalue_(true)
-    {}
+    {
+        value_ref_ = &owned_value_;
+    }
 
-    value_type moved() const
+    value_type moved_or_copied() const
     {
         if (is_rvalue_)
         {
-            return std::move(value_);
+            return std::move(*value_ref_);
         }
         else
         {
-            return value_;
+            return *value_ref_;
         }
     }
 
     value_type const& operator*() const
     {
-        return value_;
+        return *static_cast<value_type const*>(value_ref_);
     }
 
     value_type const* operator->() const
     {
-        return &value_;
+        return static_cast<value_type const*>(value_ref_);
     }
 
   private:
-    mutable value_type value_;
+    value_type * value_ref_;
+    mutable value_type owned_value_;
     bool is_rvalue_;
 };
 
@@ -8747,7 +8752,7 @@ class basic_json
 
             std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
             {
-                basic_json element = element_ref.moved();
+                basic_json element = element_ref.moved_or_copied();
                 m_value.object->emplace(
                     std::move(*((*element.m_value.array)[0].m_value.string)),
                     std::move((*element.m_value.array)[1]));
@@ -9010,7 +9015,7 @@ class basic_json
     ///////////////////////////////////////
 
     basic_json(const detail::json_ref<basic_json>& ref)
-        : basic_json(ref.moved())
+        : basic_json(ref.moved_or_copied())
     {
     }
 
@@ -11935,8 +11940,9 @@ class basic_json
     {
         if (is_object() and init.size() == 2 and (*init.begin())->is_string())
         {
-            basic_json&&  key = init.begin()->moved();
-            push_back(typename object_t::value_type(std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved()));
+            basic_json&&  key = init.begin()->moved_or_copied();
+            push_back(typename object_t::value_type(
+                        std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
         }
         else
         {

From 93bb71232da8be4d30b16a3c0a3b5fd596077870 Mon Sep 17 00:00:00 2001
From: Nikita Ofitserov <himikof@gmail.com>
Date: Tue, 25 Jul 2017 12:17:32 +0300
Subject: [PATCH 7/8] Move from rvalues eagerly to work around MSVC problem

On MSVC compiler, temporaries that are constructed during a
list initialization, are sometimes destroyed even before calling
the initializing constructor, instead of at the end of the
containing full-expression. This is clearly non-conforming to
[class.temporary].
As the impact of this bug is silently producing incorrect
JSON values, move eagerly from rvalues to be safe.

See https://stackoverflow.com/questions/24586411
---
 src/json.hpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index ab725f55..20c2f618 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -7088,9 +7088,11 @@ struct json_ref
     typedef BasicJsonType value_type;
 
     json_ref(value_type&&  value)
-        : value_ref_(&value)
+        : owned_value_(std::move(value))
         , is_rvalue_(true)
-    {}
+    {
+        value_ref_ = &owned_value_;
+    }
 
     json_ref(const value_type& value)
         : value_ref_(const_cast<value_type*>(&value))

From f434942371c2da33dc7f1f263e5c377cb6932d13 Mon Sep 17 00:00:00 2001
From: dan-42 <daniel@duerrenbuehl.de>
Date: Sat, 29 Jul 2017 11:59:09 +0200
Subject: [PATCH 8/8] REFACTOR: rewrite CMakeLists.txt for better inlcude and
 reuse

The rewrite uses more cmake build-in automatisms and build-in generates
variables to allow better generic reuse.
* cmake  files are installed to
``` <install_prefix>/lib/cmake/nlohmann_json/ ``` for best support on
most systems
* include path is set to ``` include ```  for usage as ``` #include
<nlohmann/json.hpp> ```
---
 CMakeLists.txt        | 110 +++++++++++++++++++++++++-----------------
 cmake/config.cmake.in |   8 +--
 2 files changed, 68 insertions(+), 50 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc660c24..cc30013b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,56 +1,78 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.0.0)
 
-# define the project
-project(nlohmann_json VERSION 2.1.1 LANGUAGES CXX)
+##
+## PROJECT
+## name and version
+##
+project(nlohmann_json VERSION 2.1.1)
 
+##
+## OPTIONS
+##
 option(JSON_BuildTests "Build the unit tests" ON)
 
-# define project variables
-set(JSON_TARGET_NAME ${PROJECT_NAME})
-set(JSON_PACKAGE_NAME ${JSON_TARGET_NAME})
-set(JSON_TARGETS_FILENAME "${JSON_PACKAGE_NAME}Targets.cmake")
-set(JSON_CONFIG_FILENAME "${JSON_PACKAGE_NAME}Config.cmake")
-set(JSON_CONFIGVERSION_FILENAME "${JSON_PACKAGE_NAME}ConfigVersion.cmake")
-set(JSON_CONFIG_DESTINATION "cmake")
-set(JSON_INCLUDE_DESTINATION "include/nlohmann")
+##
+## CONFIGURATION
+##
+set(NLOHMANN_JSON_TARGET_NAME               ${PROJECT_NAME})
+set(NLOHMANN_JSON_SOURCE_DIR                "src/")
+set(NLOHMANN_JSON_CONFIG_INSTALL_DIR        "lib/cmake/${PROJECT_NAME}")
+set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR       "include")
+set(NLOHMANN_JSON_HEADER_INSTALL_DIR        "${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}/nlohmann")
+set(NLOHMANN_JSON_TARGETS_EXPORT_NAME       "${PROJECT_NAME}Targets")
+set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE     "cmake/config.cmake.in")
+set(NLOHMANN_JSON_CMAKE_CONFIG_DIR          "${CMAKE_CURRENT_BINARY_DIR}/cmake_config")
+set(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
+set(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
 
-set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+##
+## TARGET
+## create target and add include path
+##
+add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE)
 
-# create and configure the library target
-add_library(${JSON_TARGET_NAME} INTERFACE)
-target_include_directories(${JSON_TARGET_NAME} INTERFACE
-  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
-  $<INSTALL_INTERFACE:${JSON_INCLUDE_DESTINATION}>)
-
-# create and configure the unit test target
+target_include_directories(
+    ${NLOHMANN_JSON_TARGET_NAME}
+    INTERFACE $<INSTALL_INTERFACE:include/>
+)
+            
+##
+## TESTS
+## create and configure the unit test target
+##
 if(JSON_BuildTests)
     enable_testing()
+    include_directories(${NLOHMANN_JSON_SOURCE_DIR})
     add_subdirectory(test)
 endif()
 
-# generate a config and config version file for the package
+##
+## INSTALL
+## install header files, generate and install cmake config files for find_package()
+##
 include(CMakePackageConfigHelpers)
-configure_package_config_file("cmake/config.cmake.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/${JSON_CONFIG_FILENAME}"
-    INSTALL_DESTINATION ${JSON_CONFIG_DESTINATION}
-    PATH_VARS JSON_INCLUDE_DESTINATION)
-write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${JSON_CONFIGVERSION_FILENAME}"
-    VERSION ${PROJECT_VERSION}
-    COMPATIBILITY SameMajorVersion)
-
-# export the library target and store build directory in package registry
-export(TARGETS ${JSON_TARGET_NAME}
-    FILE "${CMAKE_CURRENT_BINARY_DIR}/${JSON_TARGETS_FILENAME}")
-export(PACKAGE ${JSON_PACKAGE_NAME})
-
-# install library target and config files
-install(TARGETS ${JSON_TARGET_NAME}
-    EXPORT ${JSON_PACKAGE_NAME})
-install(FILES "src/json.hpp"
-    DESTINATION ${JSON_INCLUDE_DESTINATION})
-install(EXPORT ${JSON_PACKAGE_NAME}
-    FILE ${JSON_TARGETS_FILENAME}
-    DESTINATION ${JSON_CONFIG_DESTINATION})
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${JSON_CONFIG_FILENAME}"
-    "${CMAKE_CURRENT_BINARY_DIR}/${JSON_CONFIGVERSION_FILENAME}"
-    DESTINATION ${JSON_CONFIG_DESTINATION})
+write_basic_package_version_file(
+    ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE} COMPATIBILITY SameMajorVersion
+)
+configure_package_config_file(
+    ${NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE}
+    ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE}
+    INSTALL_DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
+)
+install(
+    DIRECTORY ${NLOHMANN_JSON_SOURCE_DIR}
+    DESTINATION ${NLOHMANN_JSON_HEADER_INSTALL_DIR}
+)
+install(
+    FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
+    DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
+)
+install(
+    TARGETS ${NLOHMANN_JSON_TARGET_NAME}
+    EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
+    INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
+)
+install(
+    EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
+    DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
+)
diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in
index a1e9488d..b4fd29d9 100644
--- a/cmake/config.cmake.in
+++ b/cmake/config.cmake.in
@@ -1,7 +1,3 @@
 @PACKAGE_INIT@
-set_and_check(JSON_INCLUDE_DIR "@PACKAGE_JSON_INCLUDE_DESTINATION@")
-
-cmake_policy(PUSH)
-cmake_policy(SET CMP0024 OLD)
-include(${CMAKE_CURRENT_LIST_DIR}/@JSON_TARGETS_FILENAME@)
-cmake_policy(POP)
+include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake")
+check_required_components("@PROJECT_NAME@")