From 90eb0a91e0caffdf9b33939760880a92ec132aba Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Sat, 26 May 2018 13:26:40 +0200
Subject: [PATCH 1/2] :zap: keys are now returned as const reference #1098

---
 .../nlohmann/detail/iterators/iter_impl.hpp   |  2 +-
 .../detail/iterators/iteration_proxy.hpp      | 18 +++++++++++++----
 single_include/nlohmann/json.hpp              | 20 ++++++++++++++-----
 3 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp
index 52ede17b..08108a22 100644
--- a/include/nlohmann/detail/iterators/iter_impl.hpp
+++ b/include/nlohmann/detail/iterators/iter_impl.hpp
@@ -583,7 +583,7 @@ class iter_impl
     @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
+    const typename object_t::key_type& key() const
     {
         assert(m_object != nullptr);
 
diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp
index 7547d038..39c35a2e 100644
--- a/include/nlohmann/detail/iterators/iteration_proxy.hpp
+++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp
@@ -21,6 +21,10 @@ template<typename IteratorType> class iteration_proxy
         IteratorType anchor;
         /// an index for arrays (used to create key names)
         std::size_t array_index = 0;
+        /// a string representation of the array index
+        std::string array_index_str = "0";
+        /// an empty string (to return a reference for primitive values)
+        const std::string empty_str = "";
 
       public:
         explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
@@ -35,7 +39,13 @@ template<typename IteratorType> class iteration_proxy
         iteration_proxy_internal& operator++()
         {
             ++anchor;
-            ++array_index;
+
+            assert(anchor.m_object != nullptr);
+            if (anchor.m_object->is_array())
+            {
+                // update array index and string representation
+                array_index_str = std::to_string(++array_index);
+            }
 
             return *this;
         }
@@ -47,7 +57,7 @@ template<typename IteratorType> class iteration_proxy
         }
 
         /// return key of the iterator
-        std::string key() const
+        const std::string& key() const
         {
             assert(anchor.m_object != nullptr);
 
@@ -55,7 +65,7 @@ template<typename IteratorType> class iteration_proxy
             {
                 // use integer array index as key
                 case value_t::array:
-                    return std::to_string(array_index);
+                    return array_index_str;
 
                 // use key from the object
                 case value_t::object:
@@ -63,7 +73,7 @@ template<typename IteratorType> class iteration_proxy
 
                 // use an empty key for all primitive types
                 default:
-                    return "";
+                    return empty_str;
             }
         }
 
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 8c9942bb..0b2e055c 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -4636,7 +4636,7 @@ class iter_impl
     @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
+    const typename object_t::key_type& key() const
     {
         assert(m_object != nullptr);
 
@@ -4691,6 +4691,10 @@ template<typename IteratorType> class iteration_proxy
         IteratorType anchor;
         /// an index for arrays (used to create key names)
         std::size_t array_index = 0;
+        /// a string representation of the array index
+        std::string array_index_str = "0";
+        /// an empty string (to return a reference for primitive values)
+        const std::string empty_str = "";
 
       public:
         explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
@@ -4705,7 +4709,13 @@ template<typename IteratorType> class iteration_proxy
         iteration_proxy_internal& operator++()
         {
             ++anchor;
-            ++array_index;
+
+            assert(anchor.m_object != nullptr);
+            if (anchor.m_object->is_array())
+            {
+                // update array index and string representation
+                array_index_str = std::to_string(++array_index);
+            }
 
             return *this;
         }
@@ -4717,7 +4727,7 @@ template<typename IteratorType> class iteration_proxy
         }
 
         /// return key of the iterator
-        std::string key() const
+        const std::string& key() const
         {
             assert(anchor.m_object != nullptr);
 
@@ -4725,7 +4735,7 @@ template<typename IteratorType> class iteration_proxy
             {
                 // use integer array index as key
                 case value_t::array:
-                    return std::to_string(array_index);
+                    return array_index_str;
 
                 // use key from the object
                 case value_t::object:
@@ -4733,7 +4743,7 @@ template<typename IteratorType> class iteration_proxy
 
                 // use an empty key for all primitive types
                 default:
-                    return "";
+                    return empty_str;
             }
         }
 

From 481ace65c49dc198ab3255f71d43b5bb50fd9af1 Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Sun, 27 May 2018 12:04:22 +0200
Subject: [PATCH 2/2] :hammer: only calculate array index string when needed
 #1098

---
 .../detail/iterators/iteration_proxy.hpp      | 19 +++++++++++--------
 single_include/nlohmann/json.hpp              | 19 +++++++++++--------
 2 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp
index 39c35a2e..047e1855 100644
--- a/include/nlohmann/detail/iterators/iteration_proxy.hpp
+++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp
@@ -21,8 +21,10 @@ template<typename IteratorType> class iteration_proxy
         IteratorType anchor;
         /// an index for arrays (used to create key names)
         std::size_t array_index = 0;
+        /// last stringified array index
+        mutable std::size_t array_index_last = 0;
         /// a string representation of the array index
-        std::string array_index_str = "0";
+        mutable std::string array_index_str = "0";
         /// an empty string (to return a reference for primitive values)
         const std::string empty_str = "";
 
@@ -39,13 +41,7 @@ template<typename IteratorType> class iteration_proxy
         iteration_proxy_internal& operator++()
         {
             ++anchor;
-
-            assert(anchor.m_object != nullptr);
-            if (anchor.m_object->is_array())
-            {
-                // update array index and string representation
-                array_index_str = std::to_string(++array_index);
-            }
+            ++array_index;
 
             return *this;
         }
@@ -65,7 +61,14 @@ template<typename IteratorType> class iteration_proxy
             {
                 // use integer array index as key
                 case value_t::array:
+                {
+                    if (array_index != array_index_last)
+                    {
+                        array_index_str = std::to_string(array_index);
+                        array_index_last = array_index;
+                    }
                     return array_index_str;
+                }
 
                 // use key from the object
                 case value_t::object:
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 0b2e055c..24d2269a 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -4691,8 +4691,10 @@ template<typename IteratorType> class iteration_proxy
         IteratorType anchor;
         /// an index for arrays (used to create key names)
         std::size_t array_index = 0;
+        /// last stringified array index
+        mutable std::size_t array_index_last = 0;
         /// a string representation of the array index
-        std::string array_index_str = "0";
+        mutable std::string array_index_str = "0";
         /// an empty string (to return a reference for primitive values)
         const std::string empty_str = "";
 
@@ -4709,13 +4711,7 @@ template<typename IteratorType> class iteration_proxy
         iteration_proxy_internal& operator++()
         {
             ++anchor;
-
-            assert(anchor.m_object != nullptr);
-            if (anchor.m_object->is_array())
-            {
-                // update array index and string representation
-                array_index_str = std::to_string(++array_index);
-            }
+            ++array_index;
 
             return *this;
         }
@@ -4735,7 +4731,14 @@ template<typename IteratorType> class iteration_proxy
             {
                 // use integer array index as key
                 case value_t::array:
+                {
+                    if (array_index != array_index_last)
+                    {
+                        array_index_str = std::to_string(array_index);
+                        array_index_last = array_index;
+                    }
                     return array_index_str;
+                }
 
                 // use key from the object
                 case value_t::object: