From faccc37d0d99a30c9de6fc4a68f683482a790638 Mon Sep 17 00:00:00 2001
From: Vitaliy Manushkin <agri@yandex-team.ru>
Date: Sat, 10 Mar 2018 17:19:28 +0300
Subject: [PATCH 1/7] dump to alternate implementation of string, as defined in
 basic_json template

---
 include/nlohmann/detail/output/output_adapters.hpp | 10 +++++-----
 include/nlohmann/json.hpp                          |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp
index fe9e1b36..aa6217ec 100644
--- a/include/nlohmann/detail/output/output_adapters.hpp
+++ b/include/nlohmann/detail/output/output_adapters.hpp
@@ -68,11 +68,11 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
 };
 
 /// output adapter for basic_string
-template<typename CharType>
+template<typename CharType, typename StringType = std::basic_string<CharType>>
 class output_string_adapter : public output_adapter_protocol<CharType>
 {
   public:
-    explicit output_string_adapter(std::basic_string<CharType>& s) : str(s) {}
+    explicit output_string_adapter(StringType& s) : str(s) {}
 
     void write_character(CharType c) override
     {
@@ -85,10 +85,10 @@ class output_string_adapter : public output_adapter_protocol<CharType>
     }
 
   private:
-    std::basic_string<CharType>& str;
+    StringType& str;
 };
 
-template<typename CharType>
+template<typename CharType, typename StringType = std::basic_string<CharType>>
 class output_adapter
 {
   public:
@@ -98,7 +98,7 @@ class output_adapter
     output_adapter(std::basic_ostream<CharType>& s)
         : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
 
-    output_adapter(std::basic_string<CharType>& s)
+    output_adapter(StringType& s)
         : oa(std::make_shared<output_string_adapter<CharType>>(s)) {}
 
     operator output_adapter_t<CharType>()
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index 91de782f..a4f2748d 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -1947,7 +1947,7 @@ class basic_json
                   const bool ensure_ascii = false) const
     {
         string_t result;
-        serializer s(detail::output_adapter<char>(result), indent_char);
+        serializer s(detail::output_adapter<char, string_t>(result), indent_char);
 
         if (indent >= 0)
         {

From ed6b1464f98afd179d0bddb332dc1ef370d14812 Mon Sep 17 00:00:00 2001
From: Vitaliy Manushkin <agri@yandex-team.ru>
Date: Sat, 10 Mar 2018 17:36:51 +0300
Subject: [PATCH 2/7] dump to alternate implementation of string, as defined in
 basic_json template (changes to amalgamated code)

---
 single_include/nlohmann/json.hpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 1d8e4e82..b37c21c6 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -4777,11 +4777,11 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
 };
 
 /// output adapter for basic_string
-template<typename CharType>
+template<typename CharType, typename StringType = std::basic_string<CharType>>
 class output_string_adapter : public output_adapter_protocol<CharType>
 {
   public:
-    explicit output_string_adapter(std::basic_string<CharType>& s) : str(s) {}
+    explicit output_string_adapter(StringType& s) : str(s) {}
 
     void write_character(CharType c) override
     {
@@ -4794,10 +4794,10 @@ class output_string_adapter : public output_adapter_protocol<CharType>
     }
 
   private:
-    std::basic_string<CharType>& str;
+    StringType& str;
 };
 
-template<typename CharType>
+template<typename CharType, typename StringType = std::basic_string<CharType>>
 class output_adapter
 {
   public:
@@ -4807,7 +4807,7 @@ class output_adapter
     output_adapter(std::basic_ostream<CharType>& s)
         : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
 
-    output_adapter(std::basic_string<CharType>& s)
+    output_adapter(StringType& s)
         : oa(std::make_shared<output_string_adapter<CharType>>(s)) {}
 
     operator output_adapter_t<CharType>()
@@ -11556,7 +11556,7 @@ class basic_json
                   const bool ensure_ascii = false) const
     {
         string_t result;
-        serializer s(detail::output_adapter<char>(result), indent_char);
+        serializer s(detail::output_adapter<char, string_t>(result), indent_char);
 
         if (indent >= 0)
         {

From 830f3e5290bf0ab2cda15ea45a4e036c9f7d4919 Mon Sep 17 00:00:00 2001
From: Vitaliy Manushkin <agri@yandex-team.ru>
Date: Sat, 10 Mar 2018 23:58:16 +0300
Subject: [PATCH 3/7] forward alternative string class from output_adapter to
 output_string_adapter

---
 include/nlohmann/detail/output/output_adapters.hpp | 2 +-
 single_include/nlohmann/json.hpp                   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp
index aa6217ec..ff86a6e1 100644
--- a/include/nlohmann/detail/output/output_adapters.hpp
+++ b/include/nlohmann/detail/output/output_adapters.hpp
@@ -99,7 +99,7 @@ class output_adapter
         : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
 
     output_adapter(StringType& s)
-        : oa(std::make_shared<output_string_adapter<CharType>>(s)) {}
+        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
 
     operator output_adapter_t<CharType>()
     {
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index b37c21c6..4713d4da 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -4808,7 +4808,7 @@ class output_adapter
         : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
 
     output_adapter(StringType& s)
-        : oa(std::make_shared<output_string_adapter<CharType>>(s)) {}
+        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
 
     operator output_adapter_t<CharType>()
     {

From 51349537fc4be2106e450a03fa0c8c09e5d3fa6c Mon Sep 17 00:00:00 2001
From: Vitaliy Manushkin <agri@yandex-team.ru>
Date: Sat, 10 Mar 2018 23:59:10 +0300
Subject: [PATCH 4/7] add unit test: checking dump to alternative string type

---
 test/src/unit-alt-string.cpp | 165 +++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)
 create mode 100644 test/src/unit-alt-string.cpp

diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp
new file mode 100644
index 00000000..f458aab2
--- /dev/null
+++ b/test/src/unit-alt-string.cpp
@@ -0,0 +1,165 @@
+/*
+    __ _____ _____ _____
+ __|  |   __|     |   | |  JSON for Modern C++ (test suite)
+|  |  |__   |  |  | | | |  version 3.1.1
+|_____|_____|_____|_|___|  https://github.com/nlohmann/json
+
+Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.
+
+Permission is hereby  granted, free of charge, to any  person obtaining a copy
+of this software and associated  documentation files (the "Software"), to deal
+in the Software  without restriction, including without  limitation the rights
+to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
+copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
+IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
+FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
+AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
+LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include "catch.hpp"
+
+#include <nlohmann/json.hpp>
+#include <string>
+#include <utility>
+
+/*
+ * This is virtually a string class.
+ * It covers std::string under the hood.
+ */
+class alt_string
+{
+  public:
+    using value_type = std::string::value_type;
+
+    alt_string(const char* str): str_impl(str) {}
+    alt_string(const char* str, size_t count): str_impl(str, count) {}
+    alt_string(size_t count, char chr): str_impl(count, chr) {}
+    alt_string() = default;
+
+    template <typename...TParams>
+    alt_string& append(TParams&& ...params)
+    {
+        str_impl.append(std::forward<TParams>(params)...);
+        return *this;
+    }
+
+    void push_back(char c)
+    {
+        str_impl.push_back(c);
+    }
+
+    template <typename op_type>
+    bool operator==(op_type&& op) const
+    {
+        return str_impl == op;
+    }
+
+    template <typename op_type>
+    bool operator!=(op_type&& op) const
+    {
+        return str_impl != op;
+    }
+
+    size_t size() const noexcept
+    {
+        return str_impl.size();
+    }
+
+    void resize (size_t n)
+    {
+        str_impl.resize(n);
+    }
+
+    void resize (size_t n, char c)
+    {
+        str_impl.resize(n, c);
+    }
+
+    template <typename op_type>
+    bool operator<(op_type&& op) const
+    {
+        return str_impl < op;
+    }
+
+    bool operator<(const alt_string& op) const
+    {
+        return str_impl < op.str_impl;
+    }
+
+    const char* c_str() const
+    {
+        return str_impl.c_str();
+    }
+
+    char& operator[](int index)
+    {
+        return str_impl[index];
+    }
+
+    const char& operator[](int index) const
+    {
+        return str_impl[index];
+    }
+
+    char& back()
+    {
+        return str_impl.back();
+    }
+
+    const char& back() const
+    {
+        return str_impl.back();
+    }
+
+  private:
+    std::string str_impl;
+};
+
+
+using alt_json = nlohmann::basic_json <
+                 std::map,
+                 std::vector,
+                 alt_string,
+                 bool,
+                 std::int64_t,
+                 std::uint64_t,
+                 double,
+                 std::allocator,
+                 nlohmann::adl_serializer >;
+
+
+
+TEST_CASE("alternative string type")
+{
+    SECTION("dump")
+    {
+        alt_json doc;
+        doc["pi"] = 3.141;
+        doc["happy"] = true;
+        doc["name"] = "I'm Batman";
+        doc["nothing"] = nullptr;
+        doc["answer"]["everything"] = 42;
+        doc["list"] = { 1, 0, 2 };
+        doc["object"] = { {"currency", "USD"}, {"value", 42.99} };
+
+        alt_string dump = doc.dump();
+
+        const char* const expect_str =
+            R"({"answer":{"everything":42},)"
+            R"("happy":true,"list":[1,0,2],)"
+            R"("name":"I'm Batman","nothing":null,)"
+            R"("object":{"currency":"USD","value":42.99},)"
+            R"("pi":3.141})";
+        CHECK(dump == expect_str);
+    }
+}

From 392c03380503b8cd9679ba1a6374df69f346b549 Mon Sep 17 00:00:00 2001
From: Vitaliy Manushkin <agri@yandex-team.ru>
Date: Sun, 11 Mar 2018 00:29:04 +0300
Subject: [PATCH 5/7] test refactoring

---
 test/src/unit-alt-string.cpp | 62 ++++++++++++++++++++++++++----------
 1 file changed, 46 insertions(+), 16 deletions(-)

diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp
index f458aab2..3f8b8c98 100644
--- a/test/src/unit-alt-string.cpp
+++ b/test/src/unit-alt-string.cpp
@@ -143,23 +143,53 @@ TEST_CASE("alternative string type")
 {
     SECTION("dump")
     {
-        alt_json doc;
-        doc["pi"] = 3.141;
-        doc["happy"] = true;
-        doc["name"] = "I'm Batman";
-        doc["nothing"] = nullptr;
-        doc["answer"]["everything"] = 42;
-        doc["list"] = { 1, 0, 2 };
-        doc["object"] = { {"currency", "USD"}, {"value", 42.99} };
+        {
+            alt_json doc;
+            doc["pi"] = 3.141;
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"pi":3.141})");
+        }
 
-        alt_string dump = doc.dump();
+        {
+            alt_json doc;
+            doc["happy"] = true;
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"happy":true})");
+        }
 
-        const char* const expect_str =
-            R"({"answer":{"everything":42},)"
-            R"("happy":true,"list":[1,0,2],)"
-            R"("name":"I'm Batman","nothing":null,)"
-            R"("object":{"currency":"USD","value":42.99},)"
-            R"("pi":3.141})";
-        CHECK(dump == expect_str);
+        {
+            alt_json doc;
+            doc["name"] = "I'm Batman";
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"name":"I'm Batman"})");
+        }
+
+        {
+            alt_json doc;
+            doc["nothing"] = nullptr;
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"nothing":null})");
+        }
+
+        {
+            alt_json doc;
+            doc["answer"]["everything"] = 42;
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"answer":{"everything":42}})");
+        }
+
+        {
+            alt_json doc;
+            doc["list"] = { 1, 0, 2 };
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"list":[1,0,2]})");
+        }
+
+        {
+            alt_json doc;
+            doc["list"] = { 1, 0, 2 };
+            alt_string dump = doc.dump();
+            CHECK(dump == R"({"list":[1,0,2]})");
+        }
     }
 }

From b56ac864712948f98043ccd4d21d06ec00e9d6eb Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Mon, 12 Mar 2018 18:44:19 +0100
Subject: [PATCH 6/7] :memo: thanks for #1006

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 1d065407..8c6eca8f 100644
--- a/README.md
+++ b/README.md
@@ -975,6 +975,7 @@ I deeply appreciate the help of the following people.
 - [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.
 - [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.
 - [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.
+- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type
 
 Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
 

From 8557151d903ec10f57d8f220708eb9960b3252ab Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Mon, 12 Mar 2018 19:15:11 +0100
Subject: [PATCH 7/7] :recycle: adjusting lexer/parser in symmetry to #1006

---
 include/nlohmann/detail/input/lexer.hpp  |  5 ++--
 include/nlohmann/detail/input/parser.hpp |  3 ++-
 single_include/nlohmann/json.hpp         |  8 ++++---
 test/Makefile                            |  1 +
 test/src/unit-alt-string.cpp             | 29 +++++++++++++++++++-----
 5 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp
index ea116093..98cc1b69 100644
--- a/include/nlohmann/detail/input/lexer.hpp
+++ b/include/nlohmann/detail/input/lexer.hpp
@@ -32,6 +32,7 @@ class lexer
     using number_integer_t = typename BasicJsonType::number_integer_t;
     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
     using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
 
   public:
     /// token types for the parser
@@ -1130,7 +1131,7 @@ scan_number_done:
     }
 
     /// return current string value (implicitly resets the token; useful only once)
-    std::string&& move_string()
+    string_t&& move_string()
     {
         return std::move(token_buffer);
     }
@@ -1260,7 +1261,7 @@ scan_number_done:
     std::vector<char> token_string {};
 
     /// buffer for variable-length tokens (numbers, strings)
-    std::string token_buffer {};
+    string_t token_buffer {};
 
     /// a description of occurred lexer errors
     const char* error_message = "";
diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp
index 58d42bbe..e58aaaf9 100644
--- a/include/nlohmann/detail/input/parser.hpp
+++ b/include/nlohmann/detail/input/parser.hpp
@@ -32,6 +32,7 @@ class parser
     using number_integer_t = typename BasicJsonType::number_integer_t;
     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
     using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
     using lexer_t = lexer<BasicJsonType>;
     using token_type = typename lexer_t::token_type;
 
@@ -175,7 +176,7 @@ class parser
                 }
 
                 // parse values
-                std::string key;
+                string_t key;
                 BasicJsonType value;
                 while (true)
                 {
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 4713d4da..436ea89b 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -1871,6 +1871,7 @@ class lexer
     using number_integer_t = typename BasicJsonType::number_integer_t;
     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
     using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
 
   public:
     /// token types for the parser
@@ -2969,7 +2970,7 @@ scan_number_done:
     }
 
     /// return current string value (implicitly resets the token; useful only once)
-    std::string&& move_string()
+    string_t&& move_string()
     {
         return std::move(token_buffer);
     }
@@ -3099,7 +3100,7 @@ scan_number_done:
     std::vector<char> token_string {};
 
     /// buffer for variable-length tokens (numbers, strings)
-    std::string token_buffer {};
+    string_t token_buffer {};
 
     /// a description of occurred lexer errors
     const char* error_message = "";
@@ -3155,6 +3156,7 @@ class parser
     using number_integer_t = typename BasicJsonType::number_integer_t;
     using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
     using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
     using lexer_t = lexer<BasicJsonType>;
     using token_type = typename lexer_t::token_type;
 
@@ -3298,7 +3300,7 @@ class parser
                 }
 
                 // parse values
-                std::string key;
+                string_t key;
                 BasicJsonType value;
                 while (true)
                 {
diff --git a/test/Makefile b/test/Makefile
index 51edae66..f373451f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -9,6 +9,7 @@ CPPFLAGS += -I ../single_include -I . -I thirdparty/catch -I thirdparty/fifo_map
 SOURCES = src/unit.cpp \
           src/unit-algorithms.cpp \
           src/unit-allocator.cpp \
+          src/unit-alt-string.cpp \
           src/unit-capacity.cpp \
           src/unit-cbor.cpp \
           src/unit-class_const_iterator.cpp \
diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp
index 3f8b8c98..30159fc3 100644
--- a/test/src/unit-alt-string.cpp
+++ b/test/src/unit-alt-string.cpp
@@ -42,7 +42,7 @@ class alt_string
     using value_type = std::string::value_type;
 
     alt_string(const char* str): str_impl(str) {}
-    alt_string(const char* str, size_t count): str_impl(str, count) {}
+    alt_string(const char* str, std::size_t count): str_impl(str, count) {}
     alt_string(size_t count, char chr): str_impl(count, chr) {}
     alt_string() = default;
 
@@ -70,17 +70,17 @@ class alt_string
         return str_impl != op;
     }
 
-    size_t size() const noexcept
+    std::size_t size() const noexcept
     {
         return str_impl.size();
     }
 
-    void resize (size_t n)
+    void resize (std::size_t n)
     {
         str_impl.resize(n);
     }
 
-    void resize (size_t n, char c)
+    void resize (std::size_t n, char c)
     {
         str_impl.resize(n, c);
     }
@@ -101,12 +101,12 @@ class alt_string
         return str_impl.c_str();
     }
 
-    char& operator[](int index)
+    char& operator[](std::size_t index)
     {
         return str_impl[index];
     }
 
-    const char& operator[](int index) const
+    const char& operator[](std::size_t index) const
     {
         return str_impl[index];
     }
@@ -121,6 +121,16 @@ class alt_string
         return str_impl.back();
     }
 
+    void clear()
+    {
+        str_impl.clear();
+    }
+
+    const value_type* data()
+    {
+        return str_impl.data();
+    }
+
   private:
     std::string str_impl;
 };
@@ -192,4 +202,11 @@ TEST_CASE("alternative string type")
             CHECK(dump == R"({"list":[1,0,2]})");
         }
     }
+
+    SECTION("parse")
+    {
+        auto doc = alt_json::parse("{\"foo\": \"bar\"}");
+        alt_string dump = doc.dump();
+        CHECK(dump == R"({"foo":"bar"})");
+    }
 }