Merge branch 'feature/detect_unsupported_compilers' into develop
- added error macros to exclude unsupported compilers
diff --git a/README.md b/README.md
index 4ad4037..f6b8408 100644
--- a/README.md
+++ b/README.md
@@ -485,6 +485,7 @@
- [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).
- [Mário Feroldi](https://github.com/thelostt) fixed a small typo.
- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
+- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
Thanks a lot for helping out!
diff --git a/src/json.hpp b/src/json.hpp
index d73abe0..4d5e9dd 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -46,6 +46,7 @@
#include <limits>
#include <map>
#include <memory>
+#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
@@ -1567,22 +1568,13 @@
bool type_deduction = true,
value_t manual_type = value_t::array)
{
- // the initializer list could describe an object
- bool is_an_object = true;
-
// check if each element is an array with two elements whose first
// element is a string
- for (const auto& element : init)
+ bool is_an_object = std::all_of(init.begin(), init.end(),
+ [](const basic_json & element)
{
- if (not element.is_array() or element.size() != 2
- or not element[0].is_string())
- {
- // we found an element that makes it impossible to use the
- // initializer list as object
- is_an_object = false;
- break;
- }
- }
+ return element.is_array() and element.size() == 2 and element[0].is_string();
+ });
// adjust type if type deduction is not wanted
if (not type_deduction)
@@ -1608,10 +1600,10 @@
assert(m_value.object != nullptr);
- for (auto& element : init)
+ std::for_each(init.begin(), init.end(), [this](const basic_json & element)
{
m_value.object->emplace(*(element[0].m_value.string), element[1]);
- }
+ });
}
else
{
@@ -3248,11 +3240,13 @@
// operator[] only works for arrays
if (is_array())
{
- // fill up array with null values until given idx is reached
+ // fill up array with null values if given idx is outside range
assert(m_value.array != nullptr);
- for (size_t i = m_value.array->size(); i <= idx; ++i)
+ if (idx >= m_value.array->size())
{
- m_value.array->push_back(basic_json());
+ m_value.array->insert(m_value.array->end(),
+ idx - m_value.array->size() + 1,
+ basic_json());
}
return m_value.array->operator[](idx);
@@ -5814,7 +5808,7 @@
///////////////////////////
/// return the type as string
- string_t type_name() const noexcept
+ std::string type_name() const
{
switch (m_type)
{
@@ -5845,9 +5839,8 @@
*/
static std::size_t extra_space(const string_t& s) noexcept
{
- std::size_t result = 0;
-
- for (const auto& c : s)
+ return std::accumulate(s.begin(), s.end(), size_t{},
+ [](size_t res, typename string_t::value_type c)
{
switch (c)
{
@@ -5860,8 +5853,7 @@
case '\t':
{
// from c (1 byte) to \x (2 bytes)
- result += 1;
- break;
+ return res + 1;
}
default:
@@ -5869,14 +5861,15 @@
if (c >= 0x00 and c <= 0x1f)
{
// from c (1 byte) to \uxxxx (6 bytes)
- result += 5;
+ return res + 5;
}
- break;
+ else
+ {
+ return res;
+ }
}
}
- }
-
- return result;
+ });
}
/*!
@@ -5970,16 +5963,15 @@
{
// convert a number 0..15 to its hex representation
// (0..f)
- const auto hexify = [](const int v) -> char
+ static const char hexify[16] =
{
- return (v < 10)
- ? ('0' + static_cast<char>(v))
- : ('a' + static_cast<char>((v - 10) & 0x1f));
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
// print character c as \uxxxx
for (const char m :
- { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f)
+ { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
})
{
result[++pos] = m;
@@ -6626,13 +6618,13 @@
{
case basic_json::value_t::object:
{
- ++m_it.object_iterator;
+ std::advance(m_it.object_iterator, 1);
break;
}
case basic_json::value_t::array:
{
- ++m_it.array_iterator;
+ std::advance(m_it.array_iterator, 1);
break;
}
@@ -6663,13 +6655,13 @@
{
case basic_json::value_t::object:
{
- --m_it.object_iterator;
+ std::advance(m_it.object_iterator, -1);
break;
}
case basic_json::value_t::array:
{
- --m_it.array_iterator;
+ std::advance(m_it.array_iterator, -1);
break;
}
@@ -6781,7 +6773,7 @@
case basic_json::value_t::array:
{
- m_it.array_iterator += i;
+ std::advance(m_it.array_iterator, i);
break;
}
@@ -6855,7 +6847,7 @@
case basic_json::value_t::array:
{
- return *(m_it.array_iterator + n);
+ return *std::next(m_it.array_iterator, n);
}
case basic_json::value_t::null:
@@ -8791,14 +8783,12 @@
*/
std::string to_string() const noexcept
{
- std::string result;
-
- for (const auto& reference_token : reference_tokens)
+ return std::accumulate(reference_tokens.begin(),
+ reference_tokens.end(), std::string{},
+ [](const std::string & a, const std::string & b)
{
- result += "/" + escape(reference_token);
- }
-
- return result;
+ return a + "/" + escape(b);
+ });
}
/// @copydoc to_string()
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 2d57325..7441e29 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -46,6 +46,7 @@
#include <limits>
#include <map>
#include <memory>
+#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
@@ -1567,22 +1568,13 @@
bool type_deduction = true,
value_t manual_type = value_t::array)
{
- // the initializer list could describe an object
- bool is_an_object = true;
-
// check if each element is an array with two elements whose first
// element is a string
- for (const auto& element : init)
+ bool is_an_object = std::all_of(init.begin(), init.end(),
+ [](const basic_json & element)
{
- if (not element.is_array() or element.size() != 2
- or not element[0].is_string())
- {
- // we found an element that makes it impossible to use the
- // initializer list as object
- is_an_object = false;
- break;
- }
- }
+ return element.is_array() and element.size() == 2 and element[0].is_string();
+ });
// adjust type if type deduction is not wanted
if (not type_deduction)
@@ -1608,10 +1600,10 @@
assert(m_value.object != nullptr);
- for (auto& element : init)
+ std::for_each(init.begin(), init.end(), [this](const basic_json & element)
{
m_value.object->emplace(*(element[0].m_value.string), element[1]);
- }
+ });
}
else
{
@@ -3248,11 +3240,13 @@
// operator[] only works for arrays
if (is_array())
{
- // fill up array with null values until given idx is reached
+ // fill up array with null values if given idx is outside range
assert(m_value.array != nullptr);
- for (size_t i = m_value.array->size(); i <= idx; ++i)
+ if (idx >= m_value.array->size())
{
- m_value.array->push_back(basic_json());
+ m_value.array->insert(m_value.array->end(),
+ idx - m_value.array->size() + 1,
+ basic_json());
}
return m_value.array->operator[](idx);
@@ -5814,7 +5808,7 @@
///////////////////////////
/// return the type as string
- string_t type_name() const noexcept
+ std::string type_name() const
{
switch (m_type)
{
@@ -5845,9 +5839,8 @@
*/
static std::size_t extra_space(const string_t& s) noexcept
{
- std::size_t result = 0;
-
- for (const auto& c : s)
+ return std::accumulate(s.begin(), s.end(), size_t{},
+ [](size_t res, typename string_t::value_type c)
{
switch (c)
{
@@ -5860,8 +5853,7 @@
case '\t':
{
// from c (1 byte) to \x (2 bytes)
- result += 1;
- break;
+ return res + 1;
}
default:
@@ -5869,14 +5861,15 @@
if (c >= 0x00 and c <= 0x1f)
{
// from c (1 byte) to \uxxxx (6 bytes)
- result += 5;
+ return res + 5;
}
- break;
+ else
+ {
+ return res;
+ }
}
}
- }
-
- return result;
+ });
}
/*!
@@ -5970,16 +5963,15 @@
{
// convert a number 0..15 to its hex representation
// (0..f)
- const auto hexify = [](const int v) -> char
+ static const char hexify[16] =
{
- return (v < 10)
- ? ('0' + static_cast<char>(v))
- : ('a' + static_cast<char>((v - 10) & 0x1f));
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
// print character c as \uxxxx
for (const char m :
- { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f)
+ { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
})
{
result[++pos] = m;
@@ -6626,13 +6618,13 @@
{
case basic_json::value_t::object:
{
- ++m_it.object_iterator;
+ std::advance(m_it.object_iterator, 1);
break;
}
case basic_json::value_t::array:
{
- ++m_it.array_iterator;
+ std::advance(m_it.array_iterator, 1);
break;
}
@@ -6663,13 +6655,13 @@
{
case basic_json::value_t::object:
{
- --m_it.object_iterator;
+ std::advance(m_it.object_iterator, -1);
break;
}
case basic_json::value_t::array:
{
- --m_it.array_iterator;
+ std::advance(m_it.array_iterator, -1);
break;
}
@@ -6781,7 +6773,7 @@
case basic_json::value_t::array:
{
- m_it.array_iterator += i;
+ std::advance(m_it.array_iterator, i);
break;
}
@@ -6855,7 +6847,7 @@
case basic_json::value_t::array:
{
- return *(m_it.array_iterator + n);
+ return *std::next(m_it.array_iterator, n);
}
case basic_json::value_t::null:
@@ -8101,14 +8093,12 @@
*/
std::string to_string() const noexcept
{
- std::string result;
-
- for (const auto& reference_token : reference_tokens)
+ return std::accumulate(reference_tokens.begin(),
+ reference_tokens.end(), std::string{},
+ [](const std::string & a, const std::string & b)
{
- result += "/" + escape(reference_token);
- }
-
- return result;
+ return a + "/" + escape(b);
+ });
}
/// @copydoc to_string()
diff --git a/test/src/unit.cpp b/test/src/unit.cpp
index 3b8909a..a12f052 100644
--- a/test/src/unit.cpp
+++ b/test/src/unit.cpp
@@ -10309,252 +10309,261 @@
TEST_CASE("README", "[hide]")
{
{
- // create an empty structure (null)
- json j;
-
- // add a number that is stored as double (note the implicit conversion of j to an object)
- j["pi"] = 3.141;
-
- // add a Boolean that is stored as bool
- j["happy"] = true;
-
- // add a string that is stored as std::string
- j["name"] = "Niels";
-
- // add another null object by passing nullptr
- j["nothing"] = nullptr;
-
- // add an object inside the object
- j["answer"]["everything"] = 42;
-
- // add an array that is stored as std::vector (using an initializer list)
- j["list"] = { 1, 0, 2 };
-
- // add another object (using an initializer list of pairs)
- j["object"] = { {"currency", "USD"}, {"value", 42.99} };
-
- // instead, you could also write (which looks very similar to the JSON above)
- json j2 =
+ // redirect std::cout for the README file
+ auto old_cout_buffer = std::cout.rdbuf();
+ std::ostringstream new_stream;
+ std::cout.rdbuf(new_stream.rdbuf());
{
- {"pi", 3.141},
- {"happy", true},
- {"name", "Niels"},
- {"nothing", nullptr},
+ // create an empty structure (null)
+ json j;
+
+ // add a number that is stored as double (note the implicit conversion of j to an object)
+ j["pi"] = 3.141;
+
+ // add a Boolean that is stored as bool
+ j["happy"] = true;
+
+ // add a string that is stored as std::string
+ j["name"] = "Niels";
+
+ // add another null object by passing nullptr
+ j["nothing"] = nullptr;
+
+ // add an object inside the object
+ j["answer"]["everything"] = 42;
+
+ // add an array that is stored as std::vector (using an initializer list)
+ j["list"] = { 1, 0, 2 };
+
+ // add another object (using an initializer list of pairs)
+ j["object"] = { {"currency", "USD"}, {"value", 42.99} };
+
+ // instead, you could also write (which looks very similar to the JSON above)
+ json j2 =
{
- "answer", {
- {"everything", 42}
+ {"pi", 3.141},
+ {"happy", true},
+ {"name", "Niels"},
+ {"nothing", nullptr},
+ {
+ "answer", {
+ {"everything", 42}
+ }
+ },
+ {"list", {1, 0, 2}},
+ {
+ "object", {
+ {"currency", "USD"},
+ {"value", 42.99}
+ }
}
- },
- {"list", {1, 0, 2}},
- {
- "object", {
- {"currency", "USD"},
- {"value", 42.99}
- }
- }
- };
- }
+ };
+ }
- {
- // ways to express the empty array []
- json empty_array_implicit = {{}};
- json empty_array_explicit = json::array();
+ {
+ // ways to express the empty array []
+ json empty_array_implicit = {{}};
+ json empty_array_explicit = json::array();
- // a way to express the empty object {}
- json empty_object_explicit = json::object();
+ // a way to express the empty object {}
+ json empty_object_explicit = json::object();
- // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
- json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) };
- }
+ // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
+ json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) };
+ }
- {
- // create object from string literal
- json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
+ {
+ // create object from string literal
+ json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
- // or even nicer with a raw string literal
- auto j2 = R"(
+ // or even nicer with a raw string literal
+ auto j2 = R"(
{
"happy": true,
"pi": 3.141
}
)"_json;
- // or explicitly
- auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
+ // or explicitly
+ auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
- // explicit conversion to string
- std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
+ // explicit conversion to string
+ std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
- // serialization with pretty printing
- // pass in the amount of spaces to indent
- std::cout << j.dump(4) << std::endl;
- // {
- // "happy": true,
- // "pi": 3.141
- // }
+ // serialization with pretty printing
+ // pass in the amount of spaces to indent
+ std::cout << j.dump(4) << std::endl;
+ // {
+ // "happy": true,
+ // "pi": 3.141
+ // }
- std::cout << std::setw(2) << j << std::endl;
- }
-
- {
- // create an array using push_back
- json j;
- j.push_back("foo");
- j.push_back(1);
- j.push_back(true);
-
- // iterate the array
- for (json::iterator it = j.begin(); it != j.end(); ++it)
- {
- std::cout << *it << '\n';
+ std::cout << std::setw(2) << j << std::endl;
}
- // range-based for
- for (auto element : j)
{
- std::cout << element << '\n';
+ // create an array using push_back
+ json j;
+ j.push_back("foo");
+ j.push_back(1);
+ j.push_back(true);
+
+ // iterate the array
+ for (json::iterator it = j.begin(); it != j.end(); ++it)
+ {
+ std::cout << *it << '\n';
+ }
+
+ // range-based for
+ for (auto element : j)
+ {
+ std::cout << element << '\n';
+ }
+
+ // getter/setter
+ const std::string tmp = j[0];
+ j[1] = 42;
+ bool foo = j.at(2);
+
+ // other stuff
+ j.size(); // 3 entries
+ j.empty(); // false
+ j.type(); // json::value_t::array
+ j.clear(); // the array is empty again
+
+ // comparison
+ j == "[\"foo\", 1, true]"_json; // true
+
+ // create an object
+ json o;
+ o["foo"] = 23;
+ o["bar"] = false;
+ o["baz"] = 3.141;
+
+ // find an entry
+ if (o.find("foo") != o.end())
+ {
+ // there is an entry with key "foo"
+ }
}
- // getter/setter
- const std::string tmp = j[0];
- j[1] = 42;
- bool foo = j.at(2);
-
- // other stuff
- j.size(); // 3 entries
- j.empty(); // false
- j.type(); // json::value_t::array
- j.clear(); // the array is empty again
-
- // comparison
- j == "[\"foo\", 1, true]"_json; // true
-
- // create an object
- json o;
- o["foo"] = 23;
- o["bar"] = false;
- o["baz"] = 3.141;
-
- // find an entry
- if (o.find("foo") != o.end())
{
- // there is an entry with key "foo"
+ std::vector<int> c_vector {1, 2, 3, 4};
+ json j_vec(c_vector);
+ // [1, 2, 3, 4]
+
+ std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
+ json j_deque(c_deque);
+ // [1.2, 2.3, 3.4, 5.6]
+
+ std::list<bool> c_list {true, true, false, true};
+ json j_list(c_list);
+ // [true, true, false, true]
+
+ std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
+ json j_flist(c_flist);
+ // [12345678909876, 23456789098765, 34567890987654, 45678909876543]
+
+ std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
+ json j_array(c_array);
+ // [1, 2, 3, 4]
+
+ std::set<std::string> c_set {"one", "two", "three", "four", "one"};
+ json j_set(c_set); // only one entry for "one" is used
+ // ["four", "one", "three", "two"]
+
+ std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
+ json j_uset(c_uset); // only one entry for "one" is used
+ // maybe ["two", "three", "four", "one"]
+
+ std::multiset<std::string> c_mset {"one", "two", "one", "four"};
+ json j_mset(c_mset); // only one entry for "one" is used
+ // maybe ["one", "two", "four"]
+
+ std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
+ json j_umset(c_umset); // both entries for "one" are used
+ // maybe ["one", "two", "one", "four"]
}
- }
- {
- std::vector<int> c_vector {1, 2, 3, 4};
- json j_vec(c_vector);
- // [1, 2, 3, 4]
+ {
+ std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
+ json j_map(c_map);
+ // {"one": 1, "two": 2, "three": 3}
- std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
- json j_deque(c_deque);
- // [1.2, 2.3, 3.4, 5.6]
+ std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
+ json j_umap(c_umap);
+ // {"one": 1.2, "two": 2.3, "three": 3.4}
- std::list<bool> c_list {true, true, false, true};
- json j_list(c_list);
- // [true, true, false, true]
+ std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
+ json j_mmap(c_mmap); // only one entry for key "three" is used
+ // maybe {"one": true, "two": true, "three": true}
- std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
- json j_flist(c_flist);
- // [12345678909876, 23456789098765, 34567890987654, 45678909876543]
+ std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
+ json j_ummap(c_ummap); // only one entry for key "three" is used
+ // maybe {"one": true, "two": true, "three": true}
+ }
- std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
- json j_array(c_array);
- // [1, 2, 3, 4]
+ {
+ // strings
+ std::string s1 = "Hello, world!";
+ json js = s1;
+ std::string s2 = js;
- std::set<std::string> c_set {"one", "two", "three", "four", "one"};
- json j_set(c_set); // only one entry for "one" is used
- // ["four", "one", "three", "two"]
+ // Booleans
+ bool b1 = true;
+ json jb = b1;
+ bool b2 = jb;
- std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
- json j_uset(c_uset); // only one entry for "one" is used
- // maybe ["two", "three", "four", "one"]
+ // numbers
+ int i = 42;
+ json jn = i;
+ double f = jn;
- std::multiset<std::string> c_mset {"one", "two", "one", "four"};
- json j_mset(c_mset); // only one entry for "one" is used
- // maybe ["one", "two", "four"]
+ // etc.
- std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
- json j_umset(c_umset); // both entries for "one" are used
- // maybe ["one", "two", "one", "four"]
- }
+ std::string vs = js.get<std::string>();
+ bool vb = jb.get<bool>();
+ int vi = jn.get<int>();
- {
- std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
- json j_map(c_map);
- // {"one": 1, "two": 2, "three": 3}
+ // etc.
+ }
- std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
- json j_umap(c_umap);
- // {"one": 1.2, "two": 2.3, "three": 3.4}
-
- std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
- json j_mmap(c_mmap); // only one entry for key "three" is used
- // maybe {"one": true, "two": true, "three": true}
-
- std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
- json j_ummap(c_ummap); // only one entry for key "three" is used
- // maybe {"one": true, "two": true, "three": true}
- }
-
- {
- // strings
- std::string s1 = "Hello, world!";
- json js = s1;
- std::string s2 = js;
-
- // Booleans
- bool b1 = true;
- json jb = b1;
- bool b2 = jb;
-
- // numbers
- int i = 42;
- json jn = i;
- double f = jn;
-
- // etc.
-
- std::string vs = js.get<std::string>();
- bool vb = jb.get<bool>();
- int vi = jn.get<int>();
-
- // etc.
- }
-
- {
- // a JSON value
- json j_original = R"({
+ {
+ // a JSON value
+ json j_original = R"({
"baz": ["one", "two", "three"],
"foo": "bar"
})"_json;
- // access members with a JSON pointer (RFC 6901)
- j_original["/baz/1"_json_pointer];
- // "two"
+ // access members with a JSON pointer (RFC 6901)
+ j_original["/baz/1"_json_pointer];
+ // "two"
- // a JSON patch (RFC 6902)
- json j_patch = R"([
+ // a JSON patch (RFC 6902)
+ json j_patch = R"([
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
])"_json;
- // apply the patch
- json j_result = j_original.patch(j_patch);
- // {
- // "baz": "boo",
- // "hello": ["world"]
- // }
+ // apply the patch
+ json j_result = j_original.patch(j_patch);
+ // {
+ // "baz": "boo",
+ // "hello": ["world"]
+ // }
- // calculate a JSON patch from two JSON values
- json::diff(j_result, j_original);
- // [
- // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
- // { "op":"remove","path":"/hello" },
- // { "op":"add","path":"/foo","value":"bar" }
- // ]
+ // calculate a JSON patch from two JSON values
+ json::diff(j_result, j_original);
+ // [
+ // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
+ // { "op":"remove","path":"/hello" },
+ // { "op":"add","path":"/foo","value":"bar" }
+ // ]
+ }
+
+ // restore old std::cout
+ std::cout.rdbuf(old_cout_buffer);
}
}