It’s not fully finished yet, but it’s getting there, and i didn’t write documentation beyond the README.md and tests/test.cpp but I’d like some feedback on it.
features
- It’s a header only library that’s currently < 3000 loc
- no 3rd-party dependencies
- support for being imported as a module
- supports inserting std containers into json nodes
- highly type safe, which is made possible by using concepts
- easy-to-use object/array iterations
- easy-to-use type casting from json value to native c++ types which is enabled by std::variant and concepts
- exception-free parsing and value casting.
- modern error handling using “expected” type
- exception-free node.try_at(“key”) access
- and more
edit:
documentation link: https://nodeluna.github.io/ljson
** AI GENERATED SHOWCASE THAT’S REVIEWED BY ME **
Here are some cool and advanced features of the ljson library, with short code snippets for each:
You can build JSON objects and arrays directly from standard containers (e.g., std::map, std::vector, std::set, etc.): C++
std::map<std::string, int> obj = {{"a", 1}, {"b", 2}}; std::vector<std::string> arr = {"x", "y", "z"}; ljson::node data; data.insert("object", obj); data.insert("array", arr);
ljson::node n = { {"name", "Alice"}, {"age", 30}, {"active", true}, {"tags", ljson::node({"dev", "cat_lover"})}, {"profile", ljson::node({{"city", "Paris"}, {"zip", 75000}})} }; // n is now a JSON object with nested objects and arrays!
if (n.at("age").is_integer()) std::cout << "Age: " << n.at("age").as_integer() << "\n"; if (n.at("tags").is_array()) { for (auto& tag : *n.at("tags").as_array()) std::cout << tag.as_string() << " "; }
n.at("name") = "Bob"; // changes value to "Bob" n.at("age") = 31; // changes value to 31 n.at("active") = false; // changes value to false n.at("tags").push_back("gamer"); // add "gamer" to tags array
auto result = ljson::parser::try_parse(R"({"x":1})"); if (result) { std::cout << "Parsed!\n"; } else { std::cerr << "Parse error: " << result.error().message() << "\n"; }
n.dump_to_stdout({'\t', 2}); // Pretty print using tabs, 2 per indent n.write_to_file("output.json"); // Write to file std::string s = n.dump_to_string(); // Get pretty JSON string
Concatenate arrays and objects in a natural way:
ljson::node a = {1, 2, 3}; ljson::node b = {4, 5}; ljson::node c = a + b; // [1,2,3,4,5] ljson::node obj1 = {{"x", 1}}; ljson::node obj2 = {{"y", 2}}; ljson::node obj3 = obj1 + obj2; // {"x":1,"y":2}
n.insert("nothing", ljson::null); if (n.at("nothing").is_null()) std::cout << "It's " << n.at("nothing").stringify() << "!\n"; // It's null!
ljson::node arr = { 1, 2, 3, ljson::node({"nested", "array"}), ljson::null }; ljson::node obj = { {"a", 1}, {"b", ljson::node({2, 3, 4})}, {"c", ljson::node({"d", 5})} };
You can set a node’s value using .set() or assignment:
n.at("val").set(123.45); n.at("flag") = true; n.at("sub").insert("newkey", "newval");
// Iterating an array for (auto& item : *n.at("tags").as_array()) std::cout << item.as_string() << "\n"; // Iterating an object for (auto& [key, value] : *n.as_object()) std::cout << key << ": " << value.stringify() << "\n";
Get error info if you try an invalid conversion:
auto res = n.at("name").try_as_integer(); if (!res) std::cerr << "Not an integer: " << res.error().message() << "\n";
Any supported type (string, int, bool, null, etc.) or nested containers can be used directly in construction or insertion.
n.dump_to_stdout({' ', 8}); // 8 spaces per indent
ljson::node obj = { {"a", 1}, {"b", 2} }; obj += ljson::object_pairs{ {"c", 3}, {"d", 4} };
Summary: ljson offers a modern, expressive, and type-safe C++ JSON API with C++ types, safety, and STL integration.