JSerializer is a single header C++ library for serializing data structures into JSON format, it provides a simple and efficient way to write various data types, including strings, numbers, maps, and nested structures, while maintaining type safety and extreme performance.
#include <map>
#include <vector>
#include <unordered_map>
#include "jserializer.hpp"
auto main() -> int {
auto serializer = ubn::JSerializer::create( // Create a thread-safe serializer instance.
[](const void* data, size_t size) -> int { // Specify a write callback, write to stdout by
if (!data || size == 0) { return 0; } // default.
return std::fwrite(data, 1, size, stdout); // Returns bytes written or negative error code.
},
[](int error_code) -> int { // Specify a flush callback, flush stdout.
std::fwrite("\n", 1, 1, stdout);
return std::fflush(stdout); // Return 0 on success, negative error code on failure.
}); // You can also bring your own buffer here.
if (!serializer) { return -1; } // Check if the serializer was created successfully.
std::string_view str = "Hello";
std::vector<std::vector<int>> mat = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
std::vector<std::vector<std::vector<float>>> tsr = { { { -0.57721f, 2.71828f }, { INFINITY, NAN } }, { { 5.67f, 6.626f }, { 7.0f, 8.314f } } };
std::map<std::string, std::variant<int, float>> map = { { "Nucleosynthesis", 0 }, { "Formation", 1.2025f }, { "Heat Death", -1 } };
std::unordered_map<std::string_view, const char*> another_map = { {"\vKey\\", "unsafe \rvalue\n" } };
auto writer = serializer->writer(); // Create a writer instance, you can update the write callback, flush
// callback and wait callback here.
writer[str] << str << ", World " // Use [] to skip check for escape characters for key, and stream remain
<< 123 << "!"; // variables to the object using <<.
writer("A \"Pie\"") << 3.141; // Use () if you're not sure if the key is a valid string.
writer["Cat"] += "Kawaii"; // Use += to skip escaping or floating point rounding, otherwise
// use << to let writer handle them automatically.
writer["Matrix"] << mat; // Easily write a 2D vector as a JSON array.
writer["Tensor"] << tsr; // N-D STL container is also supported.
writer << map; // Serialize a map as a JSON object, variants are supported as well.
writer["Consistent"] += map; // Also supports writing to a specified key with consistent representation.
{
auto writer_2 = writer["Nested"](); // Create a nested object writer.
writer_2["Isshō, bando shite kureru?"] << true; // Write a boolean value.
writer_2[42] << "Catching on, our paths unknown"; // Interger key will atomatically convert to string.
writer_2["BadNumber"] << -INFINITY; // +-Inf/Nan will atomatically convert to null.
const char* c_str = "world.execute(me);";
{
auto writer_3 = writer_2["Nested - 2"](); // Endless nesting is supported.
writer_3["ThisLine"] << __LINE__; // Both integral and floating point value are supported.
writer_3("\t Exec") += c_str; // Write a C-style string, assuming no escaping needed.
}
writer_2["Bytes"].writer<ubn::StringWriter>() // Write raw bytes, this would call write callback directly
.write(c_str, std::strlen(c_str)); // after the buffer is synchronized for maximum performance.
}
writer["Another"] << another_map; // Serialize another map with automatic escaping and number rounding, since the
// 1st writer is still in scope.
// While adding new elements to the JSON object, the serializer will automatically call write callback to
// write the data to the output stream when the buffer is full or writing raw bytes method is called.
// The writers handle all type overloading automatically at compile time, there's almost no overhead, and
// the serializer will automatically flush the output stream when the last writer is destroyed.
// You can also modify some predefinitions if needed:
// - JS_LOG_LEVEL: JS_WARNING
// - JS_DEFAULT_BUFFER_SIZE: 1024
// - JS_DEFAULT_FMT_BUFFER_SIZE: 64
// - JS_DEFAULT_FLOATING_POINT_PRECISION: 3
return serializer->state(); // Should return 0 on success, otherwise a positive error code.
}
Outputs:
{"Hello":"Hello, World 123!","A \"Pie\"":3.14,"Cat":"Kawaii","Matrix":[[1,2,3],[4,5,6],[7,8,9]],"Tensor":[[[-0.577,2.72],[null,null]],[[5.67,6.63],[7,8.31]]],"Formation":1.2,"Heat Death":-1,"Nucleosynthesis":0,"Consistent":{"Formation":1.2025,"Heat Death":-1,"Nucleosynthesis":0},"Nested":{"Isshō, bando shite kureru?":true,"42":"Catching on, our paths unknown","BadNumber":null,"Nested - 2":{"ThisLine":112,"\t Exec":"world.execute(me);"},"Bytes":"world.execute(me);"},"Another":{"Key\\":"unsafe \rvalue\n"}}
Pretty-printed output:
{
"Hello": "Hello, World 123!",
"A \"Pie\"": 3.14,
"Cat": "Kawaii",
"Matrix": [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
"Tensor": [
[[-0.577, 2.72], [null, null]],
[[5.67, 6.63], [7, 8.31]]
],
"Formation": 1.2,
"Heat Death": -1,
"Nucleosynthesis": 0,
"Consistent": {
"Formation": 1.2025,
"Heat Death": -1,
"Nucleosynthesis": 0
},
"Nested": {
"Isshō, bando shite kureru?": true,
"42": "Catching on, our paths unknown",
"BadNumber": null,
"Nested - 2": {
"ThisLine": 112,
"\t Exec": "world.execute(me);"
},
"Bytes": "world.execute(me);"
},
"Another": {
"Key\\": "unsafe \rvalue\n"
}
}
JSerializer is released under the MIT License. See the LICENSE file for more information.