Skip to content

Unbinilium/JSerializer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

83 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JSerializer

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, variants, maps, and nested structures, while maintaining type safety (SFINAE) and extreme performance (SIMD).

Features

  • Simple & Efficient: Features a clean, intuitive API for serializing data structures with minimal boilerplate and maximum performance (SIMD).
  • Stream-Oriented: Natively works with any writable output stream, from stdout to file or network sockets, integrating seamlessly into your I/O pipeline.
  • Static Memory Allocation: Guarantees no dynamic memory allocation during serialization, making it ideal for latency-sensitive and real-time applications.
  • Zero Runtime Overhead: Built for raw performance by avoiding RTTI, exceptions, and other runtime costs, ensuring a minimal footprint.
  • Type-Safe: Provides a compile-time, type-safe interface that prevents data corruption and ensures output correctness by design.
  • Header-Only & STL Compliant: A single-header, dependency-free library with out-of-the-box support for standard library containers. Just include and go.

Example

#include <map>
#include <vector>
#include <unordered_map>

#include "jserializer.hpp"

using namespace ubn;

auto main() -> int {
    auto serializer = JSerializer::create( // Create a serializer instance wraped in a smart pointer.
        StdoutStream::write,               // Default write callback, takes data pointer and size, returns the number
                                           // of bytes written or a negative error code.
        StdoutStream::flush,               // Default flush callback, called with the error code of current instance, returns
                                           // 0 or a positive number when successful, otherwise a negative error code.
        nullptr, 0);                       // Optional data buffer and size, set nullptr to allocate buffer internally, in
                                           // this case the default buffer size can be updated by setting a non-zero size.
    if (!serializer) { return -1; }        // Check if the serializer was created successfully.

    std::string_view str = "你好";
    const char* c_str = "world.execute(me);";
    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 and flush
                                        // callback here.
    writer[str] << str << ", 🌍 "       // Add strings, use [] to skip the escape characters check for the key,
                << 123 << "!";          // with << the remain variables is automatically appended to the string.
    writer("A \"Pie\"") << 3.141;       // Use () if you're not sure whether key contains escape characters.
    writer["Cat"] += "Kawaii";          // Use += to skip escaping or force a fixed-point notation, otherwise
                                        // use << to let writer handle them automatically.
    writer["Matrix"] << mat;            // Easily write a 2D vector as a JSON array.
    writer["Tensor"] << tsr;            // Integrates N-D STL container support.
    writer << map;                      // Serialize a map to current JSON object, variants are supported as well.
    writer["Consistent"] += map;        // Writing map to a specified object with consistent representation is fine.
    {
        auto writer_2 = writer["Nested"]();               // Create a nested object writer.
        writer_2["一生、バンドしてくれる?"] << 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.
        {
            auto writer_3 = writer_2["Nested"]();         // Endless nesting is supported, take it easy with loops.
            writer_3["ThisLine"] << __LINE__;             // Work with both integral and floating point values.
            writer_3("\t Exec") += c_str;                 // Write a null-terminated C-style string without escape checking.
            writer_3["Null"] << nullptr;                  // Write a null object.
        }
        writer_2["Bytes"].writer<StringWriter>()          // Write string as raw bytes, this would invoke the write callback
            .write(c_str, std::strlen(c_str));            // directly after the buffer is synchronized for maximum performance.
    }
    writer["Another"] << another_map; // Serialize another map with automatic escap checking and general number representation.

    // 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 raw bytes write 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.
    // General number representation would use both fixed or scientific representation when formatting a number,
    // integrals would always be fixed and floating point numbers would be formated to the nearest length to the limits.
    // You can also modify some predefined macros if needed:
    // JS_DEFAULT_BUFFER_SIZE: (1024 * 16)     // Default buffer size for the serializer.
    // JS_DEFAULT_FMT_BUFFER_SIZE: 64          // Default buffer size for the number formatter.
    // JS_DEFAULT_FLOATING_POINT_PRECISION: 3  // Default length of general number representation for floating point numbers.
    // JS_EXPERIMENTAL_SIMD: AUTO              // Auto detect experimental SIMD support if not defined, requires parallelism TS v2.
    // JS_DEFAULT_SIMD_ENABLE_LEN_FACTOR: 3    // Multiplied with SIMD vector size, determines the minimal length to use SIMD.

    return serializer->state(); // Should return 0 on success, otherwise a positive error code (POSIX standard).
}

Outputs:

{"你好":"你好, 🌍 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":{"一生、バンドしてくれる?":true,"42":"Catching on, our paths unknown","BadNumber":null,"Nested":{"ThisLine":44,"\t Exec":"world.execute(me);","Null":null},"Bytes":"world.execute(me);"},"Another":{"\u000bKey\\":"unsafe \rvalue\n"}}

Pretty-printed output:

{
  "你好": "你好, 🌍 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": {
    "一生、バンドしてくれる?": true,
    "42": "Catching on, our paths unknown",
    "BadNumber": null,
    "Nested": {
      "ThisLine": 44,
      "\t Exec": "world.execute(me);",
      "Null": null
    },
    "Bytes": "world.execute(me);"
  },
  "Another": {
    "\u000bKey\\": "unsafe \rvalue\n"
  }
}

License

JSerializer is released under the MIT License. See the LICENSE file for more information.

About

An exceptionally fast, stream-oriented, header-only C++ JSON serialization library.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published