JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
jsonv::writer Class Referencefinal

A writer instance writes a JSON ast_node sequence to some form of sink: an encoder, which turns the tokens into text or into whatever else it builds. More...

#include <jsonv/writer.hpp>

Public Member Functions

 writer (encoder &to)
 Create a writer which writes into to. The encoder must outlive this instance.
 
 writer (std::ostream &to)
 Create a writer which writes compact JSON text into to, as to_string does for a value: through an ostream_encoder it owns, with ostream_encoder::ensure_ascii on.
 
 writer (const writer &)=delete
 
writer & operator= (const writer &)=delete
 
bool good () const noexcept
 Check if this writer is still good to write to, which is to say that it has not been moved-from.
 
std::size_t depth () const noexcept
 The number of structures – objects and arrays – currently open.
 
const path & current_path () const
 Get the path of the slot the next token fills.
 
writer & key (std::string_view key)
 Write the key of the next member of the open object, including the separator.
 
writer & write (const value &source)
 Write the whole of source as one value, as encoder::encode does.
 
writer & write (value &&source)
 Write the whole of source as one value, handing it over to the sink.
 
 writer (writer &&) noexcept
 Moving a writer transfers its state and its sink, leaving the source moved-from: good is false, depth is 0 and every other member throws std::invalid_argument.
 
writer & operator= (writer &&) noexcept
 Moving a writer transfers its state and its sink, leaving the source moved-from: good is false, depth is 0 and every other member throws std::invalid_argument.
 
writer & object_begin ()
 Write the token which opens or closes an object or an array.
 
writer & object_end ()
 Write the token which opens or closes an object or an array.
 
writer & array_begin ()
 Write the token which opens or closes an object or an array.
 
writer & array_end ()
 Write the token which opens or closes an object or an array.
 
writer & null ()
 Write a scalar value.
 
writer & boolean (bool value)
 Write a scalar value.
 
writer & integer (std::int64_t value)
 Write a scalar value.
 
writer & decimal (double value)
 Write a scalar value.
 
writer & string (std::string_view value)
 Write a scalar value.
 

Detailed Description

A writer instance writes a JSON ast_node sequence to some form of sink: an encoder, which turns the tokens into text or into whatever else it builds.

This is the mirror of reader. A reader is a forward cursor over the tokens of a document somebody else wrote; a writer is a forward cursor over the tokens of the document you are writing. Each token method writes one token and returns *this, so calls chain. Writing an object means opening it, writing each member as a key followed by its value, and closing it:

struct my_object
{
std::int64_t a = 0;
std::vector<std::string> tags;
};
void write_my_object(jsonv::writer& to, const my_object& from)
{
to.key("a").integer(from.a);
to.key("tags").array_begin();
for (const auto& tag : from.tags)
to.string(tag);
to.array_end();
to.object_end();
}
jsonv::writer to(sink);
write_my_object(to, my_object{ 1, { "x", "y" } });
Like ostream_encoder, but pretty prints output to an std::ostream.
Definition encode.hpp:243
A writer instance writes a JSON ast_node sequence to some form of sink: an encoder,...
Definition writer.hpp:68
writer & object_begin()
Write the token which opens or closes an object or an array.
writer & key(std::string_view key)
Write the key of the next member of the open object, including the separator.
writer & object_end()
Write the token which opens or closes an object or an array.
writer & array_begin()
Write the token which opens or closes an object or an array.
writer & integer(std::int64_t value)
Write a scalar value.
writer & array_end()
Write the token which opens or closes an object or an array.

The writer owns the grammar and the punctuation. It refuses a token the grammar does not allow where the cursor is – a key outside an object, a value in an object with no key before it, an end which does not match the open structure – with std::logic_error, before the sink sees anything; and it writes the delimiters between elements and between members itself, so an encoder only ever sees a sequence of tokens which spells a valid document. A writer at depth zero accepts another root value, which is how two documents end up in one stream.

See also
encoder
reader

Definition at line 67 of file writer.hpp.

Constructor & Destructor Documentation

◆ writer() [1/2]

jsonv::writer::writer ( std::ostream &  to)
explicit

Create a writer which writes compact JSON text into to, as to_string does for a value: through an ostream_encoder it owns, with ostream_encoder::ensure_ascii on.

To pretty-print, or to write well-formed UTF-8 as it is, construct the encoder yourself and use the overload above. The stream must outlive this instance.

◆ writer() [2/2]

jsonv::writer::writer ( writer &&  )
noexcept

Moving a writer transfers its state and its sink, leaving the source moved-from: good is false, depth is 0 and every other member throws std::invalid_argument.

These are out-of-line because destroying the state needs a complete writer::impl, which this header does not have – the same reason the destructor is.

Member Function Documentation

◆ array_begin()

writer & jsonv::writer::array_begin ( )

Write the token which opens or closes an object or an array.

{

Opening one is writing a value, so it is allowed wherever a value is: at depth zero, as an array element, or as the value of the key just written. Closing one must match the innermost open structure, and an object cannot close while a key is waiting for its value.

Exceptions
std::logic_errorif the grammar does not allow the token here. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ array_end()

writer & jsonv::writer::array_end ( )

Write the token which opens or closes an object or an array.

{

Opening one is writing a value, so it is allowed wherever a value is: at depth zero, as an array element, or as the value of the key just written. Closing one must match the innermost open structure, and an object cannot close while a key is waiting for its value.

Exceptions
std::logic_errorif the grammar does not allow the token here. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ boolean()

writer & jsonv::writer::boolean ( bool  value)

Write a scalar value.

true
902
4.9
"value"
writer & null()
Write a scalar value.

A value is allowed at depth zero, as an array element, or as the value of the key just written. What a decimal with no JSON representation – a NaN or an infinity – becomes is the encoder's choice, as is what happens to a string which is not valid UTF-8 (see encoder::write_decimal and encoder::write_string).

Exceptions
std::logic_errorif an object is open and no key is waiting for its value. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ current_path()

const path & jsonv::writer::current_path ( ) const

Get the path of the slot the next token fills.

jsonv::writer to(sink); /* "." -- the root */
to.object_begin(); /* "." -- the object fills the root; the next token is a key, which has no slot */
to.key("a"); /* ".a" -- the value of "a" comes next */
to.array_begin(); /* ".a[0]" -- the first element comes next */
to.integer(1); /* ".a[1]" */
to.integer(2); /* ".a[2]" */
to.array_end(); /* "." -- back in the object, where the next token is a key */
to.key("b"); /* ".b" */
to.object_begin(); /* ".b" */
to.key("x"); /* ".b.x" */
to.string("taco"); /* ".b" */
to.object_end(); /* "." */
to.object_end(); /* "." -- the document is complete; another root may follow */

This is where a serializer is when it finds it cannot write the value it was asked for, which is what the path is for. It is built from the stack of open structures on demand and kept until the next token, so a document which never asks never pays for it – unlike reader::current_path over text, which rescans the document. The convention differs from the reader's, which names the token it is on: a reader on an element and a writer about to write that element agree, as do the two at a key, while a reader on a closing token names the structure it closes and a writer which has just closed one names where its next token goes.

Exceptions
std::invalid_argumentif this instance has been moved-from.

◆ decimal()

writer & jsonv::writer::decimal ( double  value)

Write a scalar value.

true
902
4.9
"value"

A value is allowed at depth zero, as an array element, or as the value of the key just written. What a decimal with no JSON representation – a NaN or an infinity – becomes is the encoder's choice, as is what happens to a string which is not valid UTF-8 (see encoder::write_decimal and encoder::write_string).

Exceptions
std::logic_errorif an object is open and no key is waiting for its value. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ depth()

std::size_t jsonv::writer::depth ( ) const
noexcept

The number of structures – objects and arrays – currently open.

This is 0 before the first token, between root values, and for a moved-from writer.

◆ integer()

writer & jsonv::writer::integer ( std::int64_t  value)

Write a scalar value.

true
902
4.9
"value"

A value is allowed at depth zero, as an array element, or as the value of the key just written. What a decimal with no JSON representation – a NaN or an infinity – becomes is the encoder's choice, as is what happens to a string which is not valid UTF-8 (see encoder::write_decimal and encoder::write_string).

Exceptions
std::logic_errorif an object is open and no key is waiting for its value. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ key()

writer & jsonv::writer::key ( std::string_view  key)

Write the key of the next member of the open object, including the separator.

"key":

The value must follow before the next key or the end of the object. key is viewed, not kept: it has to live until this returns and no longer.

Exceptions
std::logic_errorif no object is open, if the innermost open structure is an array, or if the key before this one is still waiting for its value. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ null()

writer & jsonv::writer::null ( )

Write a scalar value.

true
902
4.9
"value"

A value is allowed at depth zero, as an array element, or as the value of the key just written. What a decimal with no JSON representation – a NaN or an infinity – becomes is the encoder's choice, as is what happens to a string which is not valid UTF-8 (see encoder::write_decimal and encoder::write_string).

Exceptions
std::logic_errorif an object is open and no key is waiting for its value. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ object_begin()

writer & jsonv::writer::object_begin ( )

Write the token which opens or closes an object or an array.

{

Opening one is writing a value, so it is allowed wherever a value is: at depth zero, as an array element, or as the value of the key just written. Closing one must match the innermost open structure, and an object cannot close while a key is waiting for its value.

Exceptions
std::logic_errorif the grammar does not allow the token here. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ object_end()

writer & jsonv::writer::object_end ( )

Write the token which opens or closes an object or an array.

{

Opening one is writing a value, so it is allowed wherever a value is: at depth zero, as an array element, or as the value of the key just written. Closing one must match the innermost open structure, and an object cannot close while a key is waiting for its value.

Exceptions
std::logic_errorif the grammar does not allow the token here. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ operator=()

writer & jsonv::writer::operator= ( writer &&  )
noexcept

Moving a writer transfers its state and its sink, leaving the source moved-from: good is false, depth is 0 and every other member throws std::invalid_argument.

These are out-of-line because destroying the state needs a complete writer::impl, which this header does not have – the same reason the destructor is.

◆ string()

writer & jsonv::writer::string ( std::string_view  value)

Write a scalar value.

true
902
4.9
"value"

A value is allowed at depth zero, as an array element, or as the value of the key just written. What a decimal with no JSON representation – a NaN or an infinity – becomes is the encoder's choice, as is what happens to a string which is not valid UTF-8 (see encoder::write_decimal and encoder::write_string).

Exceptions
std::logic_errorif an object is open and no key is waiting for its value. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ write() [1/2]

writer & jsonv::writer::write ( const value &  source)

Write the whole of source as one value, as encoder::encode does.

An encoder producing text walks it, writing every node in order with an object's members in the order the object keeps them, which is sorted by key; one which builds a tree copies it as it is rather than rebuilding it node by node.

Exceptions
std::logic_errorif a value is not allowed here, as for the scalar functions. Nothing has reached the sink.
std::invalid_argumentif this instance has been moved-from.

◆ write() [2/2]

writer & jsonv::writer::write ( value &&  source)

Write the whole of source as one value, handing it over to the sink.

An encoder which builds a tree takes it as it is rather than copying it, and one producing text walks it exactly as the overload above does. source is left moved-from.

Exceptions
std::logic_errorif a value is not allowed here, as for the scalar functions. Nothing has reached the sink and source is untouched.
std::invalid_argumentif this instance has been moved-from.

The documentation for this class was generated from the following file: