value_stack.hpp
13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_VALUE_STACK_HPP
#define BOOST_JSON_VALUE_STACK_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/error.hpp>
#include <boost/json/storage_ptr.hpp>
#include <boost/json/value.hpp>
#include <stddef.h>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
/** A stack of @ref value elements, for building a document.
This stack of @ref value allows iterative
construction of a JSON document in memory.
The implementation uses temporary internal
storage to buffer elements so that arrays, objects,
and strings in the document are constructed using a
single memory allocation. This improves performance
and makes efficient use of the @ref memory_resource
used to create the resulting @ref value.
Temporary storage used by the implementation
initially comes from an optional memory buffer
owned by the caller. If that storage is exhausted,
then memory is obtained dynamically from the
@ref memory_resource provided on construction.
@par Usage
Construct the stack with an optional initial
temporary buffer, and a @ref storage_ptr to use for
more storage when the initial buffer is exhausted.
Then to build a @ref value, first call @ref reset
and optionally specify the @ref memory_resource
which will be used for the value. Then push elements
onto the stack by calling the corresponding functions.
After the document has been fully created, call
@ref release to acquire ownership of the top-level
@ref value.
@par Performance
The initial buffer and any dynamically allocated
temporary buffers are retained until the stack
is destroyed. This improves performance when using
a single stack instance to produce multiple
values.
@par Example
The following code constructs a @ref value which
when serialized produces a JSON object with three
elements. It uses a local buffer for the temporary
storage, and a separate local buffer for the storage
of the resulting value. No memory is dynamically
allocated; this shows how to construct a value
without using the heap.
@code
// This example builds a json::value without any dynamic memory allocations:
// Construct the value stack using a local buffer
unsigned char temp[4096];
value_stack st( storage_ptr(), temp, sizeof(temp) );
// Create a static resource with a local initial buffer
unsigned char buf[4096];
static_resource mr( buf, sizeof(buf) );
// All values on the stack will use `mr`
st.reset(&mr);
// Push the key/value pair "a":1.
st.push_key("a");
st.push_int64(1);
// Push "b":null
st.push_key("b");
st.push_null();
// Push "c":"hello"
st.push_key("c");
st.push_string("hello");
// Pop the three key/value pairs and push an object with those three values.
st.push_object(3);
// Pop the object from the stack and take ownership.
value jv = st.release();
assert( serialize(jv) == "{\"a\":1,\"b\":null,\"c\":\"hello\"}" );
// At this point we could re-use the stack by calling reset
@endcode
@par Thread Safety
Distinct instances may be accessed concurrently.
Non-const member functions of a shared instance
may not be called concurrently with any other
member functions of that instance.
*/
class value_stack
{
class stack
{
enum
{
min_size_ = 16
};
storage_ptr sp_;
void* temp_;
value* begin_;
value* top_;
value* end_;
// string starts at top_+1
std::size_t chars_ = 0;
bool run_dtors_ = true;
public:
inline ~stack();
inline stack(
storage_ptr sp,
void* temp, std::size_t size) noexcept;
inline void run_dtors(bool b) noexcept;
inline std::size_t size() const noexcept;
inline bool has_chars();
inline void clear() noexcept;
inline void maybe_grow();
inline void grow_one();
inline void grow(std::size_t nchars);
inline void append(string_view s);
inline string_view release_string() noexcept;
inline value* release(std::size_t n) noexcept;
template<class... Args> value& push(Args&&... args);
template<class Unchecked> void exchange(Unchecked&& u);
};
stack st_;
storage_ptr sp_;
public:
/// Copy constructor (deleted)
value_stack(
value_stack const&) = delete;
/// Copy assignment (deleted)
value_stack& operator=(
value_stack const&) = delete;
/** Destructor.
All dynamically allocated memory and
partial or complete elements is freed.
@par Complexity
Linear in the size of partial results.
@par Exception Safety
No-throw guarantee.
*/
BOOST_JSON_DECL
~value_stack();
/** Constructor.
Constructs an empty stack. Before any
@ref value can be built, the function
@ref reset must be called.
The `sp` parameter is only used to allocate
intermediate storage; it will not be used
for the @ref value returned by @ref release.
@param sp A pointer to the @ref memory_resource
to use for intermediate storage allocations. If
this argument is omitted, the default memory
resource is used.
@param temp_buffer A pointer to a caller-owned
buffer which will be used to store temporary
data used while building the value. If this
pointer is null, the builder will use the
storage pointer to allocate temporary data.
@param temp_size The number of valid bytes of
storage pointed to by `temp_buffer`.
*/
BOOST_JSON_DECL
value_stack(
storage_ptr sp = {},
unsigned char* temp_buffer = nullptr,
std::size_t temp_size = 0) noexcept;
/** Prepare to build a new document.
This function must be called before constructing
a new top-level @ref value. Any previously existing
partial or complete elements are destroyed, but
internal dynamically allocated memory is preserved
which may be reused to build new values.
@par Exception Safety
No-throw guarantee.
@param sp A pointer to the @ref memory_resource
to use for top-level @ref value and all child
values. The stack will acquire shared ownership
of the memory resource until @ref release or
@ref reset is called, or when the stack is
destroyed.
*/
BOOST_JSON_DECL
void
reset(storage_ptr sp = {}) noexcept;
/** Return the top-level @ref value.
This function transfers ownership of the
constructed top-level value to the caller.
The behavior is undefined if there is not
a single, top-level element.
@par Exception Safety
No-throw guarantee.
@return A __value__ holding the result.
Ownership of this value is transferred
to the caller. Ownership of the memory
resource used in the last call to @ref reset
is released.
*/
BOOST_JSON_DECL
value
release() noexcept;
//--------------------------------------------
/** Push an array formed by popping `n` values from the stack.
This function pushes an @ref array value
onto the stack. The array is formed by first
popping the top `n` values from the stack.
If the stack contains fewer than `n` values,
or if any of the top `n` values on the stack
is a key, the behavior is undefined.
@par Example
The following statements produce an array
with the contents 1, 2, 3:
@code
value_stack st;
// reset must be called first or else the behavior is undefined
st.reset();
// Place three values on the stack
st.push_int64( 1 );
st.push_int64( 2 );
st.push_int64( 3 );
// Remove the 3 values, and push an array with those 3 elements on the stack
st.push_array( 3 );
// Pop the object from the stack and take ownership.
value jv = st.release();
assert( serialize(jv) == "[1,2,3]" );
// At this point, reset must be called again to use the stack
@endcode
@param n The number of values to pop from the
top of the stack to form the array.
*/
BOOST_JSON_DECL
void
push_array(std::size_t n);
/** Push an object formed by popping `n` key/value pairs from the stack.
This function pushes an @ref object value
onto the stack. The object is formed by first
popping the top `n` key/value pairs from the
stack. If the stack contains fewer than `n`
key/value pairs, or if any of the top `n` key/value
pairs on the stack does not consist of exactly one
key followed by one value, the behavior is undefined.
@note
A key/value pair is formed by pushing a key, and then
pushing a value.
@par Example
The following code creates an object on the stack
with a single element, where key is "x" and value
is true:
@code
value_stack st;
// reset must be called first or else the behavior is undefined
st.reset();
// Place a key/value pair onto the stack
st.push_key( "x" );
st.push_bool( true );
// Replace the key/value pair with an object containing a single element
st.push_object( 1 );
// Pop the object from the stack and take ownership.
value jv = st.release();
assert( serialize(jv) == "{\"x\",true}" );
// At this point, reset must be called again to use the stack
@endcode
@par Duplicate Keys
If there are object elements with duplicate keys;
that is, if multiple elements in an object have
keys that compare equal, only the last equivalent
element will be inserted.
@param n The number of key/value pairs to pop from the
top of the stack to form the array.
*/
BOOST_JSON_DECL
void
push_object(std::size_t n);
/** Push part of a key or string onto the stack.
This function pushes the characters in `s` onto
the stack, appending to any existing characters
or creating new characters as needed. Once a
string part is placed onto the stack, the only
valid stack operations are:
@li @ref push_chars to append additional
characters to the key or string being built,
@li @ref push_key or @ref push_string to
finish building the key or string and place
the value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
*/
BOOST_JSON_DECL
void
push_chars(
string_view s);
/** Push a key onto the stack.
This function notionally removes all the
characters currently on the stack, then
pushes a @ref value containing a key onto
the stack formed by appending `s` to the
removed characters.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
*/
BOOST_JSON_DECL
void
push_key(
string_view s);
/** Place a string value onto the stack.
This function notionally removes all the
characters currently on the stack, then
pushes a @ref value containing a @ref string
onto the stack formed by appending `s` to the
removed characters.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
*/
BOOST_JSON_DECL
void
push_string(
string_view s);
/** Push a number onto the stack
This function pushes a number value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param i The number to insert.
*/
BOOST_JSON_DECL
void
push_int64(
int64_t i);
/** Push a number onto the stack
This function pushes a number value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param u The number to insert.
*/
BOOST_JSON_DECL
void
push_uint64(
uint64_t u);
/** Push a number onto the stack
This function pushes a number value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param d The number to insert.
*/
BOOST_JSON_DECL
void
push_double(
double d);
/** Push a `bool` onto the stack
This function pushes a boolean value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param b The boolean to insert.
*/
BOOST_JSON_DECL
void
push_bool(
bool b);
/** Push a null onto the stack
This function pushes a boolean value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
void
push_null();
};
BOOST_JSON_NS_END
#endif