1c5f01b2fSopenharmony_ci// __ _____ _____ _____ 2c5f01b2fSopenharmony_ci// __| | __| | | | JSON for Modern C++ (supporting code) 3c5f01b2fSopenharmony_ci// | | |__ | | | | | | version 3.11.2 4c5f01b2fSopenharmony_ci// |_____|_____|_____|_|___| https://github.com/nlohmann/json 5c5f01b2fSopenharmony_ci// 6c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 7c5f01b2fSopenharmony_ci// SPDX-License-Identifier: MIT 8c5f01b2fSopenharmony_ci 9c5f01b2fSopenharmony_ci#include "doctest_compatibility.h" 10c5f01b2fSopenharmony_ci 11c5f01b2fSopenharmony_ci#include <nlohmann/json.hpp> 12c5f01b2fSopenharmony_ciusing nlohmann::json; 13c5f01b2fSopenharmony_ci#ifdef JSON_TEST_NO_GLOBAL_UDLS 14c5f01b2fSopenharmony_ci using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) 15c5f01b2fSopenharmony_ci#endif 16c5f01b2fSopenharmony_ci 17c5f01b2fSopenharmony_ci#include <deque> 18c5f01b2fSopenharmony_ci#include <forward_list> 19c5f01b2fSopenharmony_ci#include <list> 20c5f01b2fSopenharmony_ci#include <set> 21c5f01b2fSopenharmony_ci#include <unordered_map> 22c5f01b2fSopenharmony_ci#include <unordered_set> 23c5f01b2fSopenharmony_ci#include <iostream> 24c5f01b2fSopenharmony_ci#include <sstream> 25c5f01b2fSopenharmony_ci#include <iomanip> 26c5f01b2fSopenharmony_ci 27c5f01b2fSopenharmony_ci// local variable is initialized but not referenced 28c5f01b2fSopenharmony_ciDOCTEST_MSVC_SUPPRESS_WARNING_PUSH 29c5f01b2fSopenharmony_ciDOCTEST_MSVC_SUPPRESS_WARNING(4189) 30c5f01b2fSopenharmony_ci 31c5f01b2fSopenharmony_ciTEST_CASE("README" * doctest::skip()) 32c5f01b2fSopenharmony_ci{ 33c5f01b2fSopenharmony_ci { 34c5f01b2fSopenharmony_ci // redirect std::cout for the README file 35c5f01b2fSopenharmony_ci auto* old_cout_buffer = std::cout.rdbuf(); 36c5f01b2fSopenharmony_ci std::ostringstream new_stream; 37c5f01b2fSopenharmony_ci std::cout.rdbuf(new_stream.rdbuf()); 38c5f01b2fSopenharmony_ci { 39c5f01b2fSopenharmony_ci // create an empty structure (null) 40c5f01b2fSopenharmony_ci json j; 41c5f01b2fSopenharmony_ci 42c5f01b2fSopenharmony_ci // add a number that is stored as double (note the implicit conversion of j to an object) 43c5f01b2fSopenharmony_ci j["pi"] = 3.141; 44c5f01b2fSopenharmony_ci 45c5f01b2fSopenharmony_ci // add a Boolean that is stored as bool 46c5f01b2fSopenharmony_ci j["happy"] = true; 47c5f01b2fSopenharmony_ci 48c5f01b2fSopenharmony_ci // add a string that is stored as std::string 49c5f01b2fSopenharmony_ci j["name"] = "Niels"; 50c5f01b2fSopenharmony_ci 51c5f01b2fSopenharmony_ci // add another null object by passing nullptr 52c5f01b2fSopenharmony_ci j["nothing"] = nullptr; 53c5f01b2fSopenharmony_ci 54c5f01b2fSopenharmony_ci // add an object inside the object 55c5f01b2fSopenharmony_ci j["answer"]["everything"] = 42; 56c5f01b2fSopenharmony_ci 57c5f01b2fSopenharmony_ci // add an array that is stored as std::vector (using an initializer list) 58c5f01b2fSopenharmony_ci j["list"] = { 1, 0, 2 }; 59c5f01b2fSopenharmony_ci 60c5f01b2fSopenharmony_ci // add another object (using an initializer list of pairs) 61c5f01b2fSopenharmony_ci j["object"] = { {"currency", "USD"}, {"value", 42.99} }; 62c5f01b2fSopenharmony_ci 63c5f01b2fSopenharmony_ci // instead, you could also write (which looks very similar to the JSON above) 64c5f01b2fSopenharmony_ci json j2 = 65c5f01b2fSopenharmony_ci { 66c5f01b2fSopenharmony_ci {"pi", 3.141}, 67c5f01b2fSopenharmony_ci {"happy", true}, 68c5f01b2fSopenharmony_ci {"name", "Niels"}, 69c5f01b2fSopenharmony_ci {"nothing", nullptr}, 70c5f01b2fSopenharmony_ci { 71c5f01b2fSopenharmony_ci "answer", { 72c5f01b2fSopenharmony_ci {"everything", 42} 73c5f01b2fSopenharmony_ci } 74c5f01b2fSopenharmony_ci }, 75c5f01b2fSopenharmony_ci {"list", {1, 0, 2}}, 76c5f01b2fSopenharmony_ci { 77c5f01b2fSopenharmony_ci "object", { 78c5f01b2fSopenharmony_ci {"currency", "USD"}, 79c5f01b2fSopenharmony_ci {"value", 42.99} 80c5f01b2fSopenharmony_ci } 81c5f01b2fSopenharmony_ci } 82c5f01b2fSopenharmony_ci }; 83c5f01b2fSopenharmony_ci } 84c5f01b2fSopenharmony_ci 85c5f01b2fSopenharmony_ci { 86c5f01b2fSopenharmony_ci // ways to express the empty array [] 87c5f01b2fSopenharmony_ci json empty_array_implicit = {{}}; 88c5f01b2fSopenharmony_ci CHECK(empty_array_implicit.is_array()); 89c5f01b2fSopenharmony_ci json empty_array_explicit = json::array(); 90c5f01b2fSopenharmony_ci CHECK(empty_array_explicit.is_array()); 91c5f01b2fSopenharmony_ci 92c5f01b2fSopenharmony_ci // a way to express the empty object {} 93c5f01b2fSopenharmony_ci json empty_object_explicit = json::object(); 94c5f01b2fSopenharmony_ci CHECK(empty_object_explicit.is_object()); 95c5f01b2fSopenharmony_ci 96c5f01b2fSopenharmony_ci // a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] 97c5f01b2fSopenharmony_ci json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); 98c5f01b2fSopenharmony_ci CHECK(array_not_object.is_array()); 99c5f01b2fSopenharmony_ci CHECK(array_not_object.size() == 2); 100c5f01b2fSopenharmony_ci CHECK(array_not_object[0].is_array()); 101c5f01b2fSopenharmony_ci CHECK(array_not_object[1].is_array()); 102c5f01b2fSopenharmony_ci } 103c5f01b2fSopenharmony_ci 104c5f01b2fSopenharmony_ci { 105c5f01b2fSopenharmony_ci // create object from string literal 106c5f01b2fSopenharmony_ci json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; // NOLINT(modernize-raw-string-literal) 107c5f01b2fSopenharmony_ci 108c5f01b2fSopenharmony_ci // or even nicer with a raw string literal 109c5f01b2fSopenharmony_ci auto j2 = R"({ 110c5f01b2fSopenharmony_ci "happy": true, 111c5f01b2fSopenharmony_ci "pi": 3.141 112c5f01b2fSopenharmony_ci })"_json; 113c5f01b2fSopenharmony_ci 114c5f01b2fSopenharmony_ci // or explicitly 115c5f01b2fSopenharmony_ci auto j3 = json::parse(R"({"happy": true, "pi": 3.141})"); 116c5f01b2fSopenharmony_ci 117c5f01b2fSopenharmony_ci // explicit conversion to string 118c5f01b2fSopenharmony_ci std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} 119c5f01b2fSopenharmony_ci 120c5f01b2fSopenharmony_ci // serialization with pretty printing 121c5f01b2fSopenharmony_ci // pass in the amount of spaces to indent 122c5f01b2fSopenharmony_ci std::cout << j.dump(4) << std::endl; 123c5f01b2fSopenharmony_ci // { 124c5f01b2fSopenharmony_ci // "happy": true, 125c5f01b2fSopenharmony_ci // "pi": 3.141 126c5f01b2fSopenharmony_ci // } 127c5f01b2fSopenharmony_ci 128c5f01b2fSopenharmony_ci std::cout << std::setw(2) << j << std::endl; 129c5f01b2fSopenharmony_ci } 130c5f01b2fSopenharmony_ci 131c5f01b2fSopenharmony_ci { 132c5f01b2fSopenharmony_ci // create an array using push_back 133c5f01b2fSopenharmony_ci json j; 134c5f01b2fSopenharmony_ci j.push_back("foo"); 135c5f01b2fSopenharmony_ci j.push_back(1); 136c5f01b2fSopenharmony_ci j.push_back(true); 137c5f01b2fSopenharmony_ci 138c5f01b2fSopenharmony_ci // comparison 139c5f01b2fSopenharmony_ci bool x = (j == R"(["foo", 1, true])"_json); // true 140c5f01b2fSopenharmony_ci CHECK(x == true); 141c5f01b2fSopenharmony_ci 142c5f01b2fSopenharmony_ci // iterate the array 143c5f01b2fSopenharmony_ci for (json::iterator it = j.begin(); it != j.end(); ++it) // NOLINT(modernize-loop-convert) 144c5f01b2fSopenharmony_ci { 145c5f01b2fSopenharmony_ci std::cout << *it << '\n'; 146c5f01b2fSopenharmony_ci } 147c5f01b2fSopenharmony_ci 148c5f01b2fSopenharmony_ci // range-based for 149c5f01b2fSopenharmony_ci for (auto& element : j) 150c5f01b2fSopenharmony_ci { 151c5f01b2fSopenharmony_ci std::cout << element << '\n'; 152c5f01b2fSopenharmony_ci } 153c5f01b2fSopenharmony_ci 154c5f01b2fSopenharmony_ci // getter/setter 155c5f01b2fSopenharmony_ci const auto tmp = j[0].get<std::string>(); 156c5f01b2fSopenharmony_ci j[1] = 42; 157c5f01b2fSopenharmony_ci bool foo{j.at(2)}; 158c5f01b2fSopenharmony_ci CHECK(foo == true); 159c5f01b2fSopenharmony_ci 160c5f01b2fSopenharmony_ci // other stuff 161c5f01b2fSopenharmony_ci CHECK(j.size() == 3); // 3 entries 162c5f01b2fSopenharmony_ci CHECK_FALSE(j.empty()); // false 163c5f01b2fSopenharmony_ci CHECK(j.type() == json::value_t::array); // json::value_t::array 164c5f01b2fSopenharmony_ci j.clear(); // the array is empty again 165c5f01b2fSopenharmony_ci 166c5f01b2fSopenharmony_ci // create an object 167c5f01b2fSopenharmony_ci json o; 168c5f01b2fSopenharmony_ci o["foo"] = 23; 169c5f01b2fSopenharmony_ci o["bar"] = false; 170c5f01b2fSopenharmony_ci o["baz"] = 3.141; 171c5f01b2fSopenharmony_ci 172c5f01b2fSopenharmony_ci // find an entry 173c5f01b2fSopenharmony_ci CHECK(o.find("foo") != o.end()); 174c5f01b2fSopenharmony_ci if (o.find("foo") != o.end()) 175c5f01b2fSopenharmony_ci { 176c5f01b2fSopenharmony_ci // there is an entry with key "foo" 177c5f01b2fSopenharmony_ci } 178c5f01b2fSopenharmony_ci } 179c5f01b2fSopenharmony_ci 180c5f01b2fSopenharmony_ci { 181c5f01b2fSopenharmony_ci std::vector<int> c_vector {1, 2, 3, 4}; 182c5f01b2fSopenharmony_ci json j_vec(c_vector); 183c5f01b2fSopenharmony_ci // [1, 2, 3, 4] 184c5f01b2fSopenharmony_ci 185c5f01b2fSopenharmony_ci std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f}; 186c5f01b2fSopenharmony_ci json j_deque(c_deque); 187c5f01b2fSopenharmony_ci // [1.2, 2.3, 3.4, 5.6] 188c5f01b2fSopenharmony_ci 189c5f01b2fSopenharmony_ci std::list<bool> c_list {true, true, false, true}; 190c5f01b2fSopenharmony_ci json j_list(c_list); 191c5f01b2fSopenharmony_ci // [true, true, false, true] 192c5f01b2fSopenharmony_ci 193c5f01b2fSopenharmony_ci std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; 194c5f01b2fSopenharmony_ci json j_flist(c_flist); 195c5f01b2fSopenharmony_ci // [12345678909876, 23456789098765, 34567890987654, 45678909876543] 196c5f01b2fSopenharmony_ci 197c5f01b2fSopenharmony_ci std::array<unsigned long, 4> c_array {{1, 2, 3, 4}}; 198c5f01b2fSopenharmony_ci json j_array(c_array); 199c5f01b2fSopenharmony_ci // [1, 2, 3, 4] 200c5f01b2fSopenharmony_ci 201c5f01b2fSopenharmony_ci std::set<std::string> c_set {"one", "two", "three", "four", "one"}; 202c5f01b2fSopenharmony_ci json j_set(c_set); // only one entry for "one" is used 203c5f01b2fSopenharmony_ci // ["four", "one", "three", "two"] 204c5f01b2fSopenharmony_ci 205c5f01b2fSopenharmony_ci std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"}; 206c5f01b2fSopenharmony_ci json j_uset(c_uset); // only one entry for "one" is used 207c5f01b2fSopenharmony_ci // maybe ["two", "three", "four", "one"] 208c5f01b2fSopenharmony_ci 209c5f01b2fSopenharmony_ci std::multiset<std::string> c_mset {"one", "two", "one", "four"}; 210c5f01b2fSopenharmony_ci json j_mset(c_mset); // both entries for "one" are used 211c5f01b2fSopenharmony_ci // maybe ["one", "two", "one", "four"] 212c5f01b2fSopenharmony_ci 213c5f01b2fSopenharmony_ci std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"}; 214c5f01b2fSopenharmony_ci json j_umset(c_umset); // both entries for "one" are used 215c5f01b2fSopenharmony_ci // maybe ["one", "two", "one", "four"] 216c5f01b2fSopenharmony_ci } 217c5f01b2fSopenharmony_ci 218c5f01b2fSopenharmony_ci { 219c5f01b2fSopenharmony_ci std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} }; 220c5f01b2fSopenharmony_ci json j_map(c_map); 221c5f01b2fSopenharmony_ci // {"one": 1, "two": 2, "three": 3} 222c5f01b2fSopenharmony_ci 223c5f01b2fSopenharmony_ci std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} }; 224c5f01b2fSopenharmony_ci json j_umap(c_umap); 225c5f01b2fSopenharmony_ci // {"one": 1.2, "two": 2.3, "three": 3.4} 226c5f01b2fSopenharmony_ci 227c5f01b2fSopenharmony_ci std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; 228c5f01b2fSopenharmony_ci json j_mmap(c_mmap); // only one entry for key "three" is used 229c5f01b2fSopenharmony_ci // maybe {"one": true, "two": true, "three": true} 230c5f01b2fSopenharmony_ci 231c5f01b2fSopenharmony_ci std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; 232c5f01b2fSopenharmony_ci json j_ummap(c_ummap); // only one entry for key "three" is used 233c5f01b2fSopenharmony_ci // maybe {"one": true, "two": true, "three": true} 234c5f01b2fSopenharmony_ci } 235c5f01b2fSopenharmony_ci 236c5f01b2fSopenharmony_ci { 237c5f01b2fSopenharmony_ci // strings 238c5f01b2fSopenharmony_ci std::string s1 = "Hello, world!"; 239c5f01b2fSopenharmony_ci json js = s1; 240c5f01b2fSopenharmony_ci auto s2 = js.get<std::string>(); 241c5f01b2fSopenharmony_ci 242c5f01b2fSopenharmony_ci // Booleans 243c5f01b2fSopenharmony_ci bool b1 = true; 244c5f01b2fSopenharmony_ci json jb = b1; 245c5f01b2fSopenharmony_ci bool b2{jb}; 246c5f01b2fSopenharmony_ci CHECK(b2 == true); 247c5f01b2fSopenharmony_ci 248c5f01b2fSopenharmony_ci // numbers 249c5f01b2fSopenharmony_ci int i = 42; 250c5f01b2fSopenharmony_ci json jn = i; 251c5f01b2fSopenharmony_ci double f{jn}; 252c5f01b2fSopenharmony_ci CHECK(f == 42); 253c5f01b2fSopenharmony_ci 254c5f01b2fSopenharmony_ci // etc. 255c5f01b2fSopenharmony_ci 256c5f01b2fSopenharmony_ci std::string vs = js.get<std::string>(); 257c5f01b2fSopenharmony_ci bool vb = jb.get<bool>(); 258c5f01b2fSopenharmony_ci CHECK(vb == true); 259c5f01b2fSopenharmony_ci int vi = jn.get<int>(); 260c5f01b2fSopenharmony_ci CHECK(vi == 42); 261c5f01b2fSopenharmony_ci 262c5f01b2fSopenharmony_ci // etc. 263c5f01b2fSopenharmony_ci } 264c5f01b2fSopenharmony_ci 265c5f01b2fSopenharmony_ci { 266c5f01b2fSopenharmony_ci // a JSON value 267c5f01b2fSopenharmony_ci json j_original = R"({ 268c5f01b2fSopenharmony_ci "baz": ["one", "two", "three"], 269c5f01b2fSopenharmony_ci "foo": "bar" 270c5f01b2fSopenharmony_ci })"_json; 271c5f01b2fSopenharmony_ci 272c5f01b2fSopenharmony_ci // access members with a JSON pointer (RFC 6901) 273c5f01b2fSopenharmony_ci j_original["/baz/1"_json_pointer]; 274c5f01b2fSopenharmony_ci // "two" 275c5f01b2fSopenharmony_ci 276c5f01b2fSopenharmony_ci // a JSON patch (RFC 6902) 277c5f01b2fSopenharmony_ci json j_patch = R"([ 278c5f01b2fSopenharmony_ci { "op": "replace", "path": "/baz", "value": "boo" }, 279c5f01b2fSopenharmony_ci { "op": "add", "path": "/hello", "value": ["world"] }, 280c5f01b2fSopenharmony_ci { "op": "remove", "path": "/foo"} 281c5f01b2fSopenharmony_ci ])"_json; 282c5f01b2fSopenharmony_ci 283c5f01b2fSopenharmony_ci // apply the patch 284c5f01b2fSopenharmony_ci json j_result = j_original.patch(j_patch); 285c5f01b2fSopenharmony_ci // { 286c5f01b2fSopenharmony_ci // "baz": "boo", 287c5f01b2fSopenharmony_ci // "hello": ["world"] 288c5f01b2fSopenharmony_ci // } 289c5f01b2fSopenharmony_ci 290c5f01b2fSopenharmony_ci // calculate a JSON patch from two JSON values 291c5f01b2fSopenharmony_ci auto res = json::diff(j_result, j_original); 292c5f01b2fSopenharmony_ci // [ 293c5f01b2fSopenharmony_ci // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, 294c5f01b2fSopenharmony_ci // { "op":"remove","path":"/hello" }, 295c5f01b2fSopenharmony_ci // { "op":"add","path":"/foo","value":"bar" } 296c5f01b2fSopenharmony_ci // ] 297c5f01b2fSopenharmony_ci } 298c5f01b2fSopenharmony_ci 299c5f01b2fSopenharmony_ci // restore old std::cout 300c5f01b2fSopenharmony_ci std::cout.rdbuf(old_cout_buffer); 301c5f01b2fSopenharmony_ci } 302c5f01b2fSopenharmony_ci} 303c5f01b2fSopenharmony_ci 304c5f01b2fSopenharmony_ciDOCTEST_MSVC_SUPPRESS_WARNING_POP 305