nlohmann/json: JSON for Modern C++

repository·develop·Indexed 13 days ago

https://github.com/nlohmann/json

A header-only, single-file JSON library for C++11 and later. It provides an intuitive, Python-like syntax for handling JSON data, featuring 100% test coverage and support for serialization, deserialization, SAX parsing, and binary formats including BSON, CBOR, MessagePack, and UBJSON.

Tokens
136K
Snippets
454
Records
627
Agent score
98%

What's inside nlohmann/json

  1. Overview of nlohmann/json design goals

    develop

    nlohmann/json is a JSON library for modern C++ designed with three primary goals:

    1. Intuitive syntax: Uses C++ operator overloading to make JSON feel like a first-class data type, similar to Python.
    2. Trivial integration: The library is a single-header file (json.hpp) with no dependencies, written in vanilla C++11. It requires no complex build systems or special compiler flags.
    3. Serious testing: The codebase features 100% test coverage, memory leak checks via Valgrind/Clang Sanitizers, and continuous fuzz testing via Google OSS-Fuzz.

    Note on performance: While there are faster libraries, this library prioritizes development speed and ease of integration. It uses standard C++ types by default (std::string, int64_t/uint64_t/double, std::map, std::vector, and bool), but the basic_json class can be templated to customize these types for better memory efficiency.

  2. Access JSON elements

    develop

    The nlohmann/json library provides several methods for accessing elements within a JSON value, depending on whether you require bounds checking or default values:

    • Unchecked access: Use operator[] for fast access when you are certain the key or index exists. Note that for objects, if the key does not exist, operator[] will insert it with a null value.
    • Checked access: Use the .at() method when you want to ensure the element exists. It throws an exception if the key or index is out of bounds.
    • Access with default values: Use the .value() method to attempt to retrieve a value for a specific key, providing a fallback default if the key is missing.
    • Iterators: Use standard iterator patterns to traverse arrays or objects.
    • JSON Pointers: Use JSON Pointer syntax to access deeply nested elements.
  3. Supported binary JSON formats

    develop

    The library provides support for several binary formats to efficiently encode JSON values into byte vectors and decode them back. This is useful for reducing data size for network exchange or storage compared to standard text-based JSON.

    Supported formats include:

    • BJData (Binary JData)
    • BSON (Binary JSON)
    • CBOR (Concise Binary Object Representation)
    • MessagePack
    • UBJSON (Universal Binary JSON)
  4. Typical workflow for using nlohmann/json

    develop

    The library is designed around a standard lifecycle for JSON data manipulation. A typical developer workflow follows these stages:

    1. Create or Parse: Build JSON values from literals, initializer lists, and STL containers, or read them from strings, files, or streams.
    2. Access and Modify: Retrieve and change values using various access methods (checked or unchecked), JSON Pointers, or iterators.
    3. Convert: Transform JSON values into native C++ types (including custom structs/classes) or convert C++ types into JSON.
    4. Serialize: Turn the JSON data back into text (via dump) or compact binary formats (like BSON, CBOR, or MessagePack).
  5. Use nlohmann::ordered_map for insertion-ordered JSON objects

    develop

    nlohmann::ordered_map is a minimal map-like container that preserves the insertion order of elements. It is primarily used as the underlying storage for nlohmann::ordered_json (which is nlohmann::basic_json<nlohmann::ordered_map>).

    Unlike std::map, which sorts keys, ordered_map maintains the order in which keys were first added, making it ideal for JSON applications where key order must be preserved (e.g., for human-readable configuration files or specific API requirements).

    template<class Key, class T, class IgnoredLess = std::less<Key>, 
             class Allocator = std::allocator<std::pair<const Key, T>>>
    struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>;
  6. Writing outputs via output adapters

    develop

    Serialization (writing) is performed using output adapters. These adapters abstract the destination by providing a common interface for writing characters and strings. An output adapter must implement:

    • write_character(CharType c): Writes a single character.
    • write_characters(const CharType* s, std::size_t length): Writes a sequence of characters.
  7. Configure the underlying container for JSON arrays

    develop

    The array_t type is defined by two template parameters, allowing you to customize how JSON arrays are stored in memory:

    1. ArrayType: The container type used to store the array elements (e.g., std::vector or std::list).
    2. AllocatorType: The allocator used for the objects (e.g., std::allocator).

    By default, the library uses std::vector and std::allocator.

    // Default configuration:
    std::vector<basic_json, std::allocator<basic_json>>
  8. Compare different basic_json specializations

    develop

    Be aware that comparing different basic_json specializations (like nlohmann::json vs nlohmann::ordered_json) can yield different results if the internal ordering of keys differs.

    For example, two objects with the same keys and values might be considered unequal if one is an ordered_json with a different key insertion order than a standard json object.

  9. Iterating over strings and binary values

    develop

    When iterating over a JSON value that is a string or a binary array, the iterator dereferences to the entire JSON value (the whole string or the whole binary array), not the individual characters or bytes. *begin() is safe even if the underlying container is empty.

    json j = "Hello, world";
    for (auto it = j.begin(); it != j.end(); ++it)
    {
        std::cout << *it << std::endl;
    }
    // Output: "Hello, world"
  10. Configure JSON storage and behavior

    develop

    The library offers several configuration and storage options:

    • Type Mapping: Understand how JSON types map to C++ types and how numbers are handled.
    • Object Order: By default, JSON objects are unordered. Use ordered_json if you need to preserve the insertion order of keys.
    • Build and Runtime Configuration:
      • Runtime Assertions: Control error checking during execution.
      • Supported Macros: Configure library behavior at compile-time.
      • C++ Modules: Support for modern C++ module usage.