JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
encode.hpp
Go to the documentation of this file.
1/** \file jsonv/encode.hpp
2 * Classes and functions for encoding JSON values to various representations.
3 *
4 * Copyright (c) 2014 by Travis Gockel. All rights reserved.
5 *
6 * This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
7 * as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * \author Travis Gockel (travis@gockelhut.com)
11**/
12#pragma once
13
14#include <jsonv/config.hpp>
15#include <jsonv/forward.hpp>
16#include <string_view>
17
18#include <cstdint>
19#include <iosfwd>
20#include <memory>
21
22namespace jsonv
23{
24
25/** An encoder is responsible for writing values to some form of output.
26 *
27 * It is a sink for the tokens of a JSON document: a \c writer drives the \c write_ hooks below one token at a time,
28 * writing the delimiters between elements and members itself. A whole \c value, handed to \c encode or to
29 * \c writer::write, arrives through \c write_tree, which by default walks it through those same hooks. An
30 * implementation turns each token into text, as \c ostream_encoder does, or into anything else.
31 *
32 * \see writer
33**/
35{
36public:
37 virtual ~encoder() noexcept;
38
39 /** Encode some source value into this encoder, through \c write_tree. To write a document token by token instead
40 * of from a finished \c value, construct a \c writer over this encoder; its \c writer::write does the same.
41 **/
42 void encode(const jsonv::value& source);
43
44protected:
45 /** Write the null value.
46 *
47 * \code
48 * null
49 * \endcode
50 **/
51 virtual void write_null() = 0;
52
53 /** Write the opening of an object value.
54 *
55 * \code
56 * {
57 * \endcode
58 **/
59 virtual void write_object_begin() = 0;
60
61 /** Write the closing of an object value.
62 *
63 * \code
64 * }
65 * \endcode
66 **/
67 virtual void write_object_end() = 0;
68
69 /** Write the key for an object, including the separator.
70 *
71 * \code
72 * "key":
73 * \endcode
74 **/
75 virtual void write_object_key(std::string_view key) = 0;
76
77 /** Write the delimiter between two entries in an object.
78 *
79 * \code
80 * ,
81 * \endcode
82 **/
83 virtual void write_object_delimiter() = 0;
84
85 /** Write the opening of an array value.
86 *
87 * \code
88 * [
89 * \endcode
90 **/
91 virtual void write_array_begin() = 0;
92
93 /** Write the closing of an array value.
94 *
95 * \code
96 * ]
97 * \endcode
98 **/
99 virtual void write_array_end() = 0;
100
101 /** Write the delimiter between two entries in an array.
102 *
103 * \code
104 * ,
105 * \endcode
106 **/
107 virtual void write_array_delimiter() = 0;
108
109 /** Write a string value.
110 *
111 * \param value is the string to write. It will \e hopefully be encoded as valid UTF-8. It is the implementation's
112 * choice of how to deal with malformed string values. Two common options are to replace malformed
113 * sequences with ?s or to simply output these encodings and let the receiver deal with them.
114 *
115 * \code
116 * "value"
117 * \endcode
118 **/
119 virtual void write_string(std::string_view value) = 0;
120
121 /** Write an integer value.
122 *
123 * \code
124 * 902
125 * \endcode
126 **/
127 virtual void write_integer(std::int64_t value) = 0;
128
129 /** Write a decimal value.
130 *
131 * \param value is the decimal to write. Keep in mind that standard JSON does not support special IEEE 754 values
132 * such as NaN and infinity. It is the implementation's choice of how to deal with such values. Two
133 * common options are to output \c null or to encode a string description of the special value.
134 *
135 * \code
136 * 4.9
137 * \endcode
138 **/
139 virtual void write_decimal(double value) = 0;
140
141 /** Write a boolean value.
142 *
143 * \code
144 * true
145 * \endcode
146 **/
147 virtual void write_boolean(bool value) = 0;
148
149 /** Write \a source and everything under it as one value, taking it over. A \c writer calls this for a \c value it
150 * is handed as an rvalue. The default writes it as an lvalue is written, through the overload below; a sink
151 * which builds a tree, as \c value_encoder does, overrides it to take the value as it is rather than copy it.
152 **/
153 virtual void write_tree(jsonv::value&& source);
154
155 /** Write \a source and everything under it as one value. \c encode calls this, and so does a \c writer for a
156 * \c value it is handed as an lvalue. The default walks the tree through the hooks above, with an object's
157 * members in the order the object keeps them and the delimiters written here, which is what a sink producing
158 * text wants: a \c value is well-formed by construction, so nothing checks the grammar inside one. A sink which
159 * builds a tree, as \c value_encoder does, overrides it to copy the value whole rather than rebuild it node by
160 * node.
161 **/
162 virtual void write_tree(const jsonv::value& source);
163
164private:
165 /** The walk behind the default \c write_tree. It recurses into itself rather than into the hook, which is for a
166 * whole value handed in and not for each subtree of one.
167 **/
168 void walk_tree(const jsonv::value& source);
169
170 /// The hooks above are driven by a \c writer, which is what keeps the sequence of calls spelling a valid document.
171 friend class writer;
172};
173
174/** An encoder that outputs to an \c std::ostream. This implementation is used for \c operator<< on a \c value.
175**/
177 public encoder
178{
179public:
180 /** Create an instance which places text into \a output. **/
181 explicit ostream_encoder(std::ostream& output);
182
183 virtual ~ostream_encoder() noexcept;
184
185 /** If set to true (the default), then all non-ASCII characters in strings will be replaced with their numeric
186 * encodings. Since JSON allows for encoded text to be contained in a document, this is inefficient if you have
187 * many non-ASCII characters. If you know that your decoding side can properly handle UTF-8 encoding, then you
188 * should turn this off, and well-formed UTF-8 will be written out as it is. An \c ostream_pretty_encoder follows
189 * this setting too.
190 *
191 * \note
192 * This functionality cannot be used to passthrough malformed UTF-8 encoded strings or control characters. If a
193 * given string is invalid UTF-8, it will still get replaced with a numeric encoding, and so will any character
194 * JSON requires to be escaped.
195 **/
196 void ensure_ascii(bool value);
197
198protected:
199 virtual void write_null() override;
200
201 virtual void write_object_begin() override;
202
203 virtual void write_object_end() override;
204
205 virtual void write_object_key(std::string_view key) override;
206
207 virtual void write_object_delimiter() override;
208
209 virtual void write_array_begin() override;
210
211 virtual void write_array_end() override;
212
213 virtual void write_array_delimiter() override;
214
215 virtual void write_string(std::string_view value) override;
216
217 virtual void write_integer(std::int64_t value) override;
218
219 /** When a special value is given, this will output \c null. **/
220 virtual void write_decimal(double value) override;
221
222 virtual void write_boolean(bool value) override;
223
224protected:
225 std::ostream& output();
226
227private:
228 std::ostream& _output;
229 bool _ensure_ascii;
230};
231
232/** Like \c ostream_encoder, but pretty prints output to an \c std::ostream. For example, to pretty-print JSON to
233 * \c std::cout:
234 *
235 * \code
236 * jsonv::ostream_pretty_encoder encoder(std::cout);
237 * encoder.encode(some_value);
238 * encoder.encode(another_value);
239 * \endcode
240**/
242 public ostream_encoder
243{
244public:
245 /** Create an instance which places text into \a output. **/
246 explicit ostream_pretty_encoder(std::ostream& output, std::size_t indent_size = 2);
247
248 virtual ~ostream_pretty_encoder() noexcept;
249
250protected:
251 virtual void write_null() override;
252
253 virtual void write_object_begin() override;
254
255 virtual void write_object_end() override;
256
257 virtual void write_object_key(std::string_view key) override;
258
259 virtual void write_object_delimiter() override;
260
261 virtual void write_array_begin() override;
262
263 virtual void write_array_end() override;
264
265 virtual void write_array_delimiter() override;
266
267 virtual void write_string(std::string_view value) override;
268
269 virtual void write_integer(std::int64_t value) override;
270
271 virtual void write_decimal(double value) override;
272
273 virtual void write_boolean(bool value) override;
274
275private:
276 void write_prefix();
277
278 void write_eol();
279
280private:
281 std::size_t _indent;
282 std::size_t _indent_size;
283 bool _defer_indent;
284};
285
286/** An encoder which builds a \c value from the tokens it is given: the sink for a document which is produced token by
287 * token through a \c writer but is wanted as a tree. It is the mirror of \c reader::from_value, which hands a tree
288 * out as tokens.
289 *
290 * \code
291 * jsonv::value_encoder sink;
292 * jsonv::writer to(sink);
293 * to.object_begin()
294 * .key("a").integer(1)
295 * .key("b").array_begin().string("x").string("y").array_end()
296 * .object_end();
297 * jsonv::value built = std::move(sink).take(); // {"a":1,"b":["x","y"]}
298 * \endcode
299 *
300 * An object is built as a \c value keeps one, so a key which repeats within it keeps the value written last, as
301 * \c parse keeps it by default; a document built from tokens and the same document parsed from text select the same
302 * data. The encoder holds one document at a time: a second root value written before \c take replaces the first, as
303 * a repeated key does.
304 *
305 * \see writer
306 * \see reader::from_value
307**/
309 public encoder
310{
311public:
312 /** Create an instance holding nothing. **/
313 explicit value_encoder();
314
315 // Not copyable or movable. A writer keeps a pointer to its encoder, so an encoder which moved out from under it
316 // would be a bug rather than a feature, and nothing else needs one to move.
317 value_encoder(const value_encoder&) = delete;
318 value_encoder& operator=(const value_encoder&) = delete;
319 value_encoder(value_encoder&&) = delete;
320 value_encoder& operator=(value_encoder&&) = delete;
321
322 virtual ~value_encoder() noexcept override;
323
324 /** Hand out the document written so far. This instance is left holding nothing, as it was constructed, so another
325 * document may follow.
326 *
327 * \throws std::logic_error if an object or array is still open, or if nothing has been written at all. A JSON
328 * document is never empty, so a writer which has produced nothing has not produced
329 * \c null.
330 **/
332 value take() &&;
333
334protected:
335 virtual void write_null() override;
336
337 virtual void write_object_begin() override;
338
339 virtual void write_object_end() override;
340
341 /** Keep \a key for the member whose value comes next. **/
342 virtual void write_object_key(std::string_view key) override;
343
344 /** Does nothing: a tree has no punctuation. **/
345 virtual void write_object_delimiter() override;
346
347 virtual void write_array_begin() override;
348
349 virtual void write_array_end() override;
350
351 /** Does nothing: a tree has no punctuation. **/
352 virtual void write_array_delimiter() override;
353
354 /** The string is copied into the tree as it is, valid UTF-8 or not. **/
355 virtual void write_string(std::string_view value) override;
356
357 virtual void write_integer(std::int64_t value) override;
358
359 /** Kept as given: a \c value can hold a NaN or an infinity, so nothing is substituted for one. **/
360 virtual void write_decimal(double value) override;
361
362 virtual void write_boolean(bool value) override;
363
364 /** Takes \a source as it is. A tree handed over whole is placed where the next value goes without being rebuilt,
365 * which is what keeps a serializer on the \c value bridge linear in the depth of what it serializes.
366 **/
367 virtual void write_tree(jsonv::value&& source) override;
368
369 /** Copies \a source in whole. A tree written as an lvalue -- \c to_json of a \c value, or of anything holding
370 * one -- costs what copying it does rather than a rebuild through the hooks above, which inserts each member and
371 * grows each array one element at a time.
372 **/
373 virtual void write_tree(const jsonv::value& source) override;
374
375private:
376 class impl;
377
378private:
379 std::unique_ptr<impl> _impl;
380};
381
382}
An encoder is responsible for writing values to some form of output.
Definition encode.hpp:35
virtual void write_object_begin()=0
Write the opening of an object value.
virtual void write_tree(const jsonv::value &source)
Write source and everything under it as one value.
virtual void write_decimal(double value)=0
Write a decimal value.
virtual void write_array_begin()=0
Write the opening of an array value.
virtual void write_array_delimiter()=0
Write the delimiter between two entries in an array.
virtual void write_string(std::string_view value)=0
Write a string value.
virtual void write_object_end()=0
Write the closing of an object value.
void encode(const jsonv::value &source)
Encode some source value into this encoder, through write_tree.
virtual void write_object_key(std::string_view key)=0
Write the key for an object, including the separator.
virtual void write_integer(std::int64_t value)=0
Write an integer value.
virtual void write_tree(jsonv::value &&source)
Write source and everything under it as one value, taking it over.
virtual void write_null()=0
Write the null value.
virtual void write_object_delimiter()=0
Write the delimiter between two entries in an object.
virtual void write_boolean(bool value)=0
Write a boolean value.
virtual void write_array_end()=0
Write the closing of an array value.
An encoder that outputs to an std::ostream.
Definition encode.hpp:178
ostream_encoder(std::ostream &output)
Create an instance which places text into output.
Like ostream_encoder, but pretty prints output to an std::ostream.
Definition encode.hpp:243
ostream_pretty_encoder(std::ostream &output, std::size_t indent_size=2)
Create an instance which places text into output.
An encoder which builds a value from the tokens it is given: the sink for a document which is produce...
Definition encode.hpp:310
value_encoder()
Create an instance holding nothing.
Represents a single JSON value, which can be any one of a potential kind, each behaving slightly diff...
Definition value.hpp:113
A writer instance writes a JSON ast_node sequence to some form of sink: an encoder,...
Definition writer.hpp:68
Copyright (c) 2014-2020 by Travis Gockel.
Copyright (c) 2012-2020 by Travis Gockel.
#define JSONV_NODISCARD
Warn if the caller discards the result of this function.
Definition config.hpp:132
#define JSONV_PUBLIC
This function or class is part of the public API for JSON Voorhees.
Definition config.hpp:113
STL namespace.