From 0f073e26eb62df4743b8da03679ed8e43cc95583 Mon Sep 17 00:00:00 2001
From: Julien Hamaide <julien.hamaide@gmail.com>
Date: Thu, 26 Sep 2019 13:13:01 +0200
Subject: [PATCH 1/2] Allow items() to be used with custom string

---
 .../detail/iterators/iteration_proxy.hpp      | 13 ++++---
 single_include/nlohmann/json.hpp              | 13 ++++---
 test/src/unit-alt-string.cpp                  | 34 +++++++++++++++++++
 3 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp
index da2e32b4..30c5e0c5 100644
--- a/include/nlohmann/detail/iterators/iteration_proxy.hpp
+++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp
@@ -12,6 +12,10 @@ namespace nlohmann
 {
 namespace detail
 {
+void int_to_string( std::string& target, int value )
+{
+    target = std::to_string(value);
+}
 template <typename IteratorType> class iteration_proxy_value
 {
   public:
@@ -20,6 +24,7 @@ template <typename IteratorType> class iteration_proxy_value
     using pointer = value_type * ;
     using reference = value_type & ;
     using iterator_category = std::input_iterator_tag;
+    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
 
   private:
     /// the iterator
@@ -29,9 +34,9 @@ template <typename IteratorType> class iteration_proxy_value
     /// last stringified array index
     mutable std::size_t array_index_last = 0;
     /// a string representation of the array index
-    mutable std::string array_index_str = "0";
+    mutable string_type array_index_str = "0";
     /// an empty string (to return a reference for primitive values)
-    const std::string empty_str = "";
+    const string_type empty_str = "";
 
   public:
     explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
@@ -64,7 +69,7 @@ template <typename IteratorType> class iteration_proxy_value
     }
 
     /// return key of the iterator
-    const std::string& key() const
+    const string_type& key() const
     {
         assert(anchor.m_object != nullptr);
 
@@ -75,7 +80,7 @@ template <typename IteratorType> class iteration_proxy_value
             {
                 if (array_index != array_index_last)
                 {
-                    array_index_str = std::to_string(array_index);
+                    int_to_string( array_index_str, array_index );
                     array_index_last = array_index;
                 }
                 return array_index_str;
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index d27940b8..9b4df8a1 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -3186,6 +3186,10 @@ namespace nlohmann
 {
 namespace detail
 {
+void int_to_string( std::string& target, int value )
+{
+    target = std::to_string(value);
+}
 template <typename IteratorType> class iteration_proxy_value
 {
   public:
@@ -3194,6 +3198,7 @@ template <typename IteratorType> class iteration_proxy_value
     using pointer = value_type * ;
     using reference = value_type & ;
     using iterator_category = std::input_iterator_tag;
+    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
 
   private:
     /// the iterator
@@ -3203,9 +3208,9 @@ template <typename IteratorType> class iteration_proxy_value
     /// last stringified array index
     mutable std::size_t array_index_last = 0;
     /// a string representation of the array index
-    mutable std::string array_index_str = "0";
+    mutable string_type array_index_str = "0";
     /// an empty string (to return a reference for primitive values)
-    const std::string empty_str = "";
+    const string_type empty_str = "";
 
   public:
     explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
@@ -3238,7 +3243,7 @@ template <typename IteratorType> class iteration_proxy_value
     }
 
     /// return key of the iterator
-    const std::string& key() const
+    const string_type& key() const
     {
         assert(anchor.m_object != nullptr);
 
@@ -3249,7 +3254,7 @@ template <typename IteratorType> class iteration_proxy_value
             {
                 if (array_index != array_index_last)
                 {
-                    array_index_str = std::to_string(array_index);
+                    int_to_string( array_index_str, array_index );
                     array_index_last = array_index;
                 }
                 return array_index_str;
diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp
index 6a9e36a3..57ddc83a 100644
--- a/test/src/unit-alt-string.cpp
+++ b/test/src/unit-alt-string.cpp
@@ -154,6 +154,11 @@ class alt_string
     friend bool ::operator<(const char*, const alt_string&);
 };
 
+void int_to_string( alt_string& target, int value )
+{
+    target = std::to_string(value).c_str();
+}
+
 using alt_json = nlohmann::basic_json <
                  std::map,
                  std::vector,
@@ -232,6 +237,35 @@ TEST_CASE("alternative string type")
         CHECK(dump == R"({"foo":"bar"})");
     }
 
+    SECTION("items")
+    {
+        auto doc = alt_json::parse("{\"foo\": \"bar\"}");
+
+        for ( auto item : doc.items() )
+        {
+            CHECK( item.key() == "foo" );
+            CHECK( item.value() == "bar" );
+        }
+
+        auto doc_array = alt_json::parse("[\"foo\", \"bar\"]");
+
+        for ( auto item : doc_array.items() )
+        {
+            if (item.key() == "0" )
+            {
+                CHECK( item.value() == "foo" );
+            }
+            else if (item.key() == "1" )
+            {
+                CHECK( item.value() == "bar" );
+            }
+            else
+            {
+                CHECK( false );
+            }
+        }
+    }
+
     SECTION("equality")
     {
         alt_json doc;

From 4615f5a980af447b372b953df7632818cd4fd44e Mon Sep 17 00:00:00 2001
From: Julien Hamaide <julien.hamaide@gmail.com>
Date: Tue, 1 Oct 2019 10:34:21 +0200
Subject: [PATCH 2/2] Provide default implementation for int_to_string, but
 allow for overloaded function

---
 include/nlohmann/detail/iterators/iteration_proxy.hpp | 3 ++-
 single_include/nlohmann/json.hpp                      | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp
index 30c5e0c5..8c54746f 100644
--- a/include/nlohmann/detail/iterators/iteration_proxy.hpp
+++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp
@@ -12,7 +12,8 @@ namespace nlohmann
 {
 namespace detail
 {
-void int_to_string( std::string& target, int value )
+template<typename string_type>
+void int_to_string( string_type& target, int value )
 {
     target = std::to_string(value);
 }
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 9b4df8a1..84fa6882 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -3186,7 +3186,8 @@ namespace nlohmann
 {
 namespace detail
 {
-void int_to_string( std::string& target, int value )
+template<typename string_type>
+void int_to_string( string_type& target, int value )
 {
     target = std::to_string(value);
 }