The C++ Boost Library: Beyond the STL

Overview

Boost.JSON is a portable C++ library which provides containers and algorithms that implement JavaScript Object Notation, (JSON) a lightweight data-interchange format.

This library focuses on a common and popular use-case: parsing and serializing to and from a container called value which holds JSON types. Any value which you build can be serialized and then deserialized, guaranteeing that the result will be equal to the original value. Whatever JSON output you produce with this library will be readable by most common JSON implementations in any language.

The value container is designed to be well suited as a vocabulary type appropriate for use in public interfaces and libraries, allowing them to be composed. The library restricts the representable data types to the ranges which are almost universally accepted by most JSON implementations, especially JavaScript. The parser and serializer are both highly performant, meeting or exceeding the benchmark performance of the best comparable libraries. Allocators are very well supported. Code which uses these types will be easy to understand, flexible, and performant.


Boost.JSON offers these features:


To use as header-only; that is, to eliminate the requirement to link a program to a static or dynamic Boost.JSON library, simply place the following line in exactly one new or existing source file in your project:

#include <boost/json/src.hpp>

The library relies heavily on these well known C++ types in its interfaces (henceforth termed standard types):

boost::json::object and boost::json::object

In this library the types array, object, and string hold JSON arrays, objects, and strings respectively while the type value is a special variant which can hold any JSON element. Here we construct an empty object and then insert the elements above:

  object obj;                                                     // construct an empty object
  obj[ "pi" ] = 3.141;                                            // insert a double
  obj[ "happy" ] = true;                                          // insert a bool
  obj[ "name" ] = "Boost";                                        // insert a string
  obj[ "nothing" ] = nullptr;                                     // insert a null
  obj[ "answer" ].emplace_object()["everything"] = 42;            // insert an object with 1 element
  obj[ "list" ] = { 1, 0, 2 };                                    // insert an array with 3 elements
  obj[ "object" ] = { {"currency", "USD"}, {"value", 42.99} };    // insert an object with 2 elements

boost::json::value

While keys are strings, the mapped type of objects and the element type of arrays is a special type called value which can hold any JSON element, as seen in the previous assignments. Instead of building the JSON document using a series of function calls, we can build it in one statement using an initializer list:

  value jv = {
    { "pi", 3.141 },
    { "happy", true },
    { "name", "Boost" },
    { "nothing", nullptr },
    { "answer", {
        { "everything", 42 } } },
    {"list", {1, 0, 2}},
    {"object", {
        { "currency", "USD" },
        { "value", 42.99 }
            } }
  };

...

Serializing

Serialization is the process where a JSON document represented in memory by a value is turned into a sequence of characters. The library provides the following free functions and types for serialization:

Serialization Functions and Types
Name Description
operator<< Serialize a value, array, object, or string to a std::ostream.
serialize Return a std::string representing a serialized value, array, object, or string.
serializer A stateful object which may be used to efficiently serialize one or more instances of value, array, object, or string.

To facilitate debugging and ease of output, library container types may be written to standard output streams using the stream operator:

value jv = { 1, 2, 3, 4, 5 };
std::cout << jv << "\n";

The serialize function converts a value into a std::string:

value jv = { 1, 2, 3, 4, 5 };
std::string s = serialize( jv );

Implementing operator<< Using a serializer

In situations where serializing a value in its entirety is inefficient or even impossible, serializer can be used to incrementally serialize a value incrementally. This may be done for a variety of reasons, such as to avoid buffering the entire output, or to ensure that a fixed amount of work is performed in each cycle. Instances of serializer maintain an output state using internal dynamically allocated structures, with an interface to retrieve successive buffers of the serialized output into a caller provided buffer. Here is an example, demonstrating how operator<< may be implemented using a serializer:

// Serialize a value into an output stream

std::ostream&
operator<<( std::ostream& os, value const& jv )
{
    // Create a serializer
    serializer sr;

    // Set the serializer up for our value
    sr.reset( &jv );

    // Loop until all output is produced.
    while( ! sr.done() )
    {
        // Use a local buffer to avoid allocation.
        char buf[ BOOST_JSON_STACK_BUFFER_SIZE ];

        // Fill our buffer with serialized characters and write it to the output stream.
        os << sr.read( buf );
    }

    return os;
}

As with the parser, the serializer may be reused by calling serializer::reset. This sets up the object to serialize a new instance and retains previously allocated memory. This can result in performance improvements when multiple variables are serialized.