From f0883dda8f12ab11a6d89a507f67bffdd9d20362 Mon Sep 17 00:00:00 2001
From: Isaac Nickaein <nickaein.i@gmail.com>
Date: Tue, 15 Jan 2019 20:28:01 +0330
Subject: [PATCH] During destruction, flatten children of objects to avoid
 recursion

---
 include/nlohmann/json.hpp        | 49 ++++++++++++++++++++++++++++++++
 single_include/nlohmann/json.hpp | 49 ++++++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+)

diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index 3b3da50f..6639ce62 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -994,6 +994,55 @@ class basic_json
 
         void destroy(value_t t) noexcept
         {
+            // flatten the current json_value to a heap-allocated stack
+            std::vector<basic_json> stack;
+
+            // move the top-level items to stack
+            if (t == value_t::array)
+            {
+                stack.reserve(array->size());
+                std::move(array->begin(), array->end(), std::back_inserter(stack));
+            }
+            else if (t == value_t::object)
+            {
+                stack.reserve(object->size());
+
+                for (auto&& it : *object)
+                {
+                    stack.push_back(std::move(it.second));
+                }
+            }
+
+            while (!stack.empty())
+            {
+                // move the last item to local variable to be processed
+                basic_json current_item(std::move(stack.back()));
+                stack.pop_back();
+
+                // if current_item is array/object, move
+                // its children to the stack to be processed later
+                if (current_item.is_array())
+                {
+                    stack.reserve(stack.size() + current_item.m_value.array->size());
+
+                    std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(),
+                              std::back_inserter(stack));
+
+                    current_item.m_value.array->clear();
+                }
+                else if (current_item.is_object())
+                {
+                    stack.reserve(stack.size() + current_item.m_value.object->size());
+
+                    for (auto&& it : *current_item.m_value.object)
+                    {
+                        stack.push_back(std::move(it.second));
+                    }
+                }
+
+                // current_item is destroyed here
+            }
+
             switch (t)
             {
                 case value_t::object:
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 70b6c8a8..3e882353 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -13462,6 +13462,55 @@ class basic_json
 
         void destroy(value_t t) noexcept
         {
+            // flatten the current json_value to a heap-allocated stack
+            std::vector<basic_json> stack;
+
+            // move the top-level items to stack
+            if (t == value_t::array)
+            {
+                stack.reserve(array->size());
+                std::move(array->begin(), array->end(), std::back_inserter(stack));
+            }
+            else if (t == value_t::object)
+            {
+                stack.reserve(object->size());
+
+                for (auto&& it : *object)
+                {
+                    stack.push_back(std::move(it.second));
+                }
+            }
+
+            while (!stack.empty())
+            {
+                // move the last item to local variable to be processed
+                basic_json current_item(std::move(stack.back()));
+                stack.pop_back();
+
+                // if current_item is array/object, move
+                // its children to the stack to be processed later
+                if (current_item.is_array())
+                {
+                    stack.reserve(stack.size() + current_item.m_value.array->size());
+
+                    std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(),
+                              std::back_inserter(stack));
+
+                    current_item.m_value.array->clear();
+                }
+                else if (current_item.is_object())
+                {
+                    stack.reserve(stack.size() + current_item.m_value.object->size());
+
+                    for (auto&& it : *current_item.m_value.object)
+                    {
+                        stack.push_back(std::move(it.second));
+                    }
+                }
+
+                // current_item is destroyed here
+            }
+
             switch (t)
             {
                 case value_t::object: