/src/jsoncons/include/jsoncons/json_encoder.hpp
Line | Count | Source |
1 | | // Copyright 2013-2025 Daniel Parker |
2 | | // Distributed under the Boost license, Version 1.0. |
3 | | // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
4 | | |
5 | | // See https://github.com/danielaparker/jsoncons for latest version |
6 | | |
7 | | #ifndef JSONCONS_JSON_ENCODER_HPP |
8 | | #define JSONCONS_JSON_ENCODER_HPP |
9 | | |
10 | | #include <array> // std::array |
11 | | #include <cstddef> |
12 | | #include <cstdint> |
13 | | #include <cmath> // std::isfinite, std::isnan |
14 | | #include <limits> // std::numeric_limits |
15 | | #include <memory> |
16 | | #include <string> |
17 | | #include <utility> // std::move |
18 | | #include <vector> |
19 | | |
20 | | #include <jsoncons/config/compiler_support.hpp> |
21 | | #include <jsoncons/config/jsoncons_config.hpp> |
22 | | #include <jsoncons/utility/write_number.hpp> |
23 | | #include <jsoncons/json_error.hpp> |
24 | | #include <jsoncons/json_exception.hpp> |
25 | | #include <jsoncons/json_options.hpp> |
26 | | #include <jsoncons/json_type.hpp> |
27 | | #include <jsoncons/json_visitor.hpp> |
28 | | #include <jsoncons/semantic_tag.hpp> |
29 | | #include <jsoncons/ser_util.hpp> |
30 | | #include <jsoncons/sink.hpp> |
31 | | #include <jsoncons/utility/bigint.hpp> |
32 | | #include <jsoncons/utility/byte_string.hpp> |
33 | | #include <jsoncons/utility/unicode_traits.hpp> |
34 | | |
35 | | namespace jsoncons { |
36 | | namespace detail { |
37 | | |
38 | | inline |
39 | | bool is_control_character(uint32_t c) |
40 | 3.65M | { |
41 | 3.65M | return c <= 0x1F || c == 0x7f; |
42 | 3.65M | } |
43 | | |
44 | | inline |
45 | | bool is_non_ascii_codepoint(uint32_t cp) |
46 | 172k | { |
47 | 172k | return cp >= 0x80; |
48 | 172k | } |
49 | | |
50 | | template <typename CharT,typename Sink> |
51 | | std::size_t escape_string(const CharT* s, std::size_t length, |
52 | | bool escape_all_non_ascii, bool escape_solidus, |
53 | | Sink& sink) |
54 | 273k | { |
55 | 273k | std::size_t count = 0; |
56 | 273k | const CharT* begin = s; |
57 | 273k | const CharT* end = s + length; |
58 | 3.75M | for (const CharT* it = begin; it != end; ++it) |
59 | 3.48M | { |
60 | 3.48M | CharT c = *it; |
61 | 3.48M | switch (c) |
62 | 3.48M | { |
63 | 4.36k | case '\\': |
64 | 4.36k | sink.push_back('\\'); |
65 | 4.36k | sink.push_back('\\'); |
66 | 4.36k | count += 2; |
67 | 4.36k | break; |
68 | 378 | case '"': |
69 | 378 | sink.push_back('\\'); |
70 | 378 | sink.push_back('\"'); |
71 | 378 | count += 2; |
72 | 378 | break; |
73 | 716 | case '\b': |
74 | 716 | sink.push_back('\\'); |
75 | 716 | sink.push_back('b'); |
76 | 716 | count += 2; |
77 | 716 | break; |
78 | 227 | case '\f': |
79 | 227 | sink.push_back('\\'); |
80 | 227 | sink.push_back('f'); |
81 | 227 | count += 2; |
82 | 227 | break; |
83 | 279 | case '\n': |
84 | 279 | sink.push_back('\\'); |
85 | 279 | sink.push_back('n'); |
86 | 279 | count += 2; |
87 | 279 | break; |
88 | 196 | case '\r': |
89 | 196 | sink.push_back('\\'); |
90 | 196 | sink.push_back('r'); |
91 | 196 | count += 2; |
92 | 196 | break; |
93 | 220 | case '\t': |
94 | 220 | sink.push_back('\\'); |
95 | 220 | sink.push_back('t'); |
96 | 220 | count += 2; |
97 | 220 | break; |
98 | 3.47M | default: |
99 | 3.47M | if (escape_solidus && c == '/') |
100 | 0 | { |
101 | 0 | sink.push_back('\\'); |
102 | 0 | sink.push_back('/'); |
103 | 0 | count += 2; |
104 | 0 | } |
105 | 3.47M | else if (is_control_character(c) || escape_all_non_ascii) |
106 | 172k | { |
107 | | // convert to codepoint |
108 | 172k | uint32_t cp; |
109 | 172k | auto r = unicode_traits::to_codepoint(it, end, cp, unicode_traits::conv_flags::strict); |
110 | 172k | if (r.ec != unicode_traits::conv_errc()) |
111 | 0 | { |
112 | 0 | JSONCONS_THROW(ser_error(json_errc::illegal_codepoint)); |
113 | 0 | } |
114 | 172k | it = r.ptr - 1; |
115 | 172k | if (is_non_ascii_codepoint(cp) || is_control_character(c)) |
116 | 172k | { |
117 | 172k | if (cp > 0xFFFF) |
118 | 0 | { |
119 | 0 | cp -= 0x10000; |
120 | 0 | uint32_t first = (cp >> 10) + 0xD800; |
121 | 0 | uint32_t second = ((cp & 0x03FF) + 0xDC00); |
122 | |
|
123 | 0 | sink.push_back('\\'); |
124 | 0 | sink.push_back('u'); |
125 | 0 | sink.push_back(jsoncons::to_hex_character(first >> 12 & 0x000F)); |
126 | 0 | sink.push_back(jsoncons::to_hex_character(first >> 8 & 0x000F)); |
127 | 0 | sink.push_back(jsoncons::to_hex_character(first >> 4 & 0x000F)); |
128 | 0 | sink.push_back(jsoncons::to_hex_character(first & 0x000F)); |
129 | 0 | sink.push_back('\\'); |
130 | 0 | sink.push_back('u'); |
131 | 0 | sink.push_back(jsoncons::to_hex_character(second >> 12 & 0x000F)); |
132 | 0 | sink.push_back(jsoncons::to_hex_character(second >> 8 & 0x000F)); |
133 | 0 | sink.push_back(jsoncons::to_hex_character(second >> 4 & 0x000F)); |
134 | 0 | sink.push_back(jsoncons::to_hex_character(second & 0x000F)); |
135 | 0 | count += 12; |
136 | 0 | } |
137 | 172k | else |
138 | 172k | { |
139 | 172k | sink.push_back('\\'); |
140 | 172k | sink.push_back('u'); |
141 | 172k | sink.push_back(jsoncons::to_hex_character(cp >> 12 & 0x000F)); |
142 | 172k | sink.push_back(jsoncons::to_hex_character(cp >> 8 & 0x000F)); |
143 | 172k | sink.push_back(jsoncons::to_hex_character(cp >> 4 & 0x000F)); |
144 | 172k | sink.push_back(jsoncons::to_hex_character(cp & 0x000F)); |
145 | 172k | count += 6; |
146 | 172k | } |
147 | 172k | } |
148 | 0 | else |
149 | 0 | { |
150 | 0 | sink.push_back(c); |
151 | 0 | ++count; |
152 | 0 | } |
153 | 172k | } |
154 | 3.30M | else |
155 | 3.30M | { |
156 | 3.30M | sink.push_back(c); |
157 | 3.30M | ++count; |
158 | 3.30M | } |
159 | 3.47M | break; |
160 | 3.48M | } |
161 | 3.48M | } |
162 | 273k | return count; |
163 | 273k | } |
164 | | |
165 | | inline |
166 | | byte_string_chars_format resolve_byte_string_chars_format(byte_string_chars_format format1, |
167 | | byte_string_chars_format format2, |
168 | | byte_string_chars_format default_format = byte_string_chars_format::base64url) |
169 | 0 | { |
170 | 0 | byte_string_chars_format sink; |
171 | 0 | switch (format1) |
172 | 0 | { |
173 | 0 | case byte_string_chars_format::base16: |
174 | 0 | case byte_string_chars_format::base64: |
175 | 0 | case byte_string_chars_format::base64url: |
176 | 0 | sink = format1; |
177 | 0 | break; |
178 | 0 | default: |
179 | 0 | switch (format2) |
180 | 0 | { |
181 | 0 | case byte_string_chars_format::base64url: |
182 | 0 | case byte_string_chars_format::base64: |
183 | 0 | case byte_string_chars_format::base16: |
184 | 0 | sink = format2; |
185 | 0 | break; |
186 | 0 | default: // base64url |
187 | 0 | { |
188 | 0 | sink = default_format; |
189 | 0 | break; |
190 | 0 | } |
191 | 0 | } |
192 | 0 | break; |
193 | 0 | } |
194 | 0 | return sink; |
195 | 0 | } |
196 | | |
197 | | } // namespace detail |
198 | | |
199 | | template <typename CharT,typename Sink=jsoncons::stream_sink<CharT>,typename Allocator=std::allocator<char>> |
200 | | class basic_json_encoder final : public basic_json_visitor<CharT> |
201 | | { |
202 | | static const jsoncons::basic_string_view<CharT> null_constant() |
203 | 401k | { |
204 | 401k | static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "null"); |
205 | 401k | return k; |
206 | 401k | } |
207 | | static const jsoncons::basic_string_view<CharT> true_constant() |
208 | 1.63M | { |
209 | 1.63M | static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "true"); |
210 | 1.63M | return k; |
211 | 1.63M | } |
212 | | static const jsoncons::basic_string_view<CharT> false_constant() |
213 | 806k | { |
214 | 806k | static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "false"); |
215 | 806k | return k; |
216 | 806k | } |
217 | | |
218 | | static const std::array<CharT,1> colon; |
219 | | static const std::array<CharT,2> colon_space; |
220 | | static const std::array<CharT,2> space_colon; |
221 | | static const std::array<CharT,3> space_colon_space; |
222 | | static const std::array<CharT,1> comma; |
223 | | static const std::array<CharT,2> comma_space; |
224 | | static const std::array<CharT,2> space_comma; |
225 | | static const std::array<CharT,3> space_comma_space; |
226 | | static const std::array<CharT,1> left_brace; |
227 | | static const std::array<CharT,1> right_brace; |
228 | | static const std::array<CharT,2> left_brace_space; |
229 | | static const std::array<CharT,2> space_right_brace; |
230 | | static const std::array<CharT,1> left_bracket; |
231 | | static const std::array<CharT,1> right_bracket; |
232 | | static const std::array<CharT,2> left_bracket_space; |
233 | | static const std::array<CharT,2> space_right_bracket; |
234 | | public: |
235 | | using allocator_type = Allocator; |
236 | | using char_type = CharT; |
237 | | using typename basic_json_visitor<CharT>::string_view_type; |
238 | | using sink_type = Sink; |
239 | | using string_type = typename basic_json_encode_options<CharT>::string_type; |
240 | | |
241 | | private: |
242 | | enum class container_type {object, array}; |
243 | | |
244 | | class encoding_context |
245 | | { |
246 | | container_type type_; |
247 | | line_split_kind split_kind_; |
248 | | bool indent_before_; |
249 | | bool new_line_after_; |
250 | | std::size_t begin_pos_{0}; |
251 | | std::size_t data_pos_{0}; |
252 | | std::size_t count_{0}; |
253 | | public: |
254 | | encoding_context(container_type type, line_split_kind split_lines, bool indent_once, |
255 | | std::size_t begin_pos, std::size_t data_pos) noexcept |
256 | 116k | : type_(type), split_kind_(split_lines), indent_before_(indent_once), new_line_after_(false), |
257 | 116k | begin_pos_(begin_pos), data_pos_(data_pos) |
258 | 116k | { |
259 | 116k | } |
260 | | |
261 | | encoding_context(const encoding_context&) = default; |
262 | | |
263 | | ~encoding_context() = default; |
264 | | |
265 | | encoding_context& operator=(const encoding_context&) = default; |
266 | | |
267 | | void set_position(std::size_t pos) |
268 | 3.83k | { |
269 | 3.83k | data_pos_ = pos; |
270 | 3.83k | } |
271 | | |
272 | | std::size_t begin_pos() const |
273 | | { |
274 | | return begin_pos_; |
275 | | } |
276 | | |
277 | | std::size_t data_pos() const |
278 | 0 | { |
279 | 0 | return data_pos_; |
280 | 0 | } |
281 | | |
282 | | std::size_t count() const |
283 | 7.82M | { |
284 | 7.82M | return count_; |
285 | 7.82M | } |
286 | | |
287 | | void increment_count() |
288 | 7.46M | { |
289 | 7.46M | ++count_; |
290 | 7.46M | } |
291 | | |
292 | | bool new_line_after() const |
293 | 28.4k | { |
294 | 28.4k | return new_line_after_; |
295 | 28.4k | } |
296 | | |
297 | | void new_line_after(bool value) |
298 | 7.55M | { |
299 | 7.55M | new_line_after_ = value; |
300 | 7.55M | } |
301 | | |
302 | | bool is_object() const |
303 | 114k | { |
304 | 114k | return type_ == container_type::object; |
305 | 114k | } |
306 | | |
307 | | bool is_array() const |
308 | 7.55M | { |
309 | 7.55M | return type_ == container_type::array; |
310 | 7.55M | } |
311 | | |
312 | | line_split_kind split_kind() const |
313 | 114k | { |
314 | 114k | return split_kind_; |
315 | 114k | } |
316 | | |
317 | | bool is_multi_line() const |
318 | 14.8M | { |
319 | 14.8M | return split_kind_ == line_split_kind::multi_line; |
320 | 14.8M | } |
321 | | |
322 | | bool is_indent_once() const |
323 | 0 | { |
324 | 0 | return count_ == 0 ? indent_before_ : false; |
325 | 0 | } |
326 | | |
327 | | }; |
328 | | using encoding_context_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<encoding_context>; |
329 | | |
330 | | Sink sink_; |
331 | | basic_json_encode_options<CharT> options_; |
332 | | char_type indent_char_{' '}; |
333 | | jsoncons::write_double fp_; |
334 | | |
335 | | std::vector<encoding_context,encoding_context_allocator_type> stack_; |
336 | | int indent_amount_{0}; |
337 | | std::size_t column_{0}; |
338 | | jsoncons::basic_string_view<CharT> colon_str_; |
339 | | jsoncons::basic_string_view<CharT> comma_str_; |
340 | | jsoncons::basic_string_view<CharT> open_brace_str_; |
341 | | jsoncons::basic_string_view<CharT> close_brace_str_; |
342 | | jsoncons::basic_string_view<CharT> open_bracket_str_; |
343 | | jsoncons::basic_string_view<CharT> close_bracket_str_; |
344 | | int nesting_depth_{0}; |
345 | | public: |
346 | | |
347 | | // Noncopyable and nonmoveable |
348 | | basic_json_encoder(const basic_json_encoder&) = delete; |
349 | | basic_json_encoder(basic_json_encoder&&) = delete; |
350 | | |
351 | | basic_json_encoder(Sink&& sink, |
352 | | const Allocator& alloc = Allocator()) |
353 | 5.16k | : basic_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc) |
354 | 5.16k | { |
355 | 5.16k | } |
356 | | |
357 | | basic_json_encoder(Sink&& sink, |
358 | | const basic_json_encode_options<CharT>& options, |
359 | | const Allocator& alloc = Allocator()) |
360 | 5.16k | : sink_(std::forward<Sink>(sink)), |
361 | 5.16k | options_(options), |
362 | 5.16k | indent_char_(options.indent_char()), |
363 | 5.16k | fp_(options.float_format(), options.precision()), |
364 | 5.16k | stack_(alloc) |
365 | 5.16k | { |
366 | 5.16k | switch (options.spaces_around_colon()) |
367 | 5.16k | { |
368 | 5.16k | case spaces_option::space_after: |
369 | 5.16k | colon_str_ = jsoncons::basic_string_view<CharT>(colon_space.data(), colon_space.size()); |
370 | 5.16k | break; |
371 | 0 | case spaces_option::space_before: |
372 | 0 | colon_str_ = jsoncons::basic_string_view<CharT>(space_colon.data(), space_colon.size()); |
373 | 0 | break; |
374 | 0 | case spaces_option::space_before_and_after: |
375 | 0 | colon_str_ = jsoncons::basic_string_view<CharT>(space_colon_space.data(), space_colon_space.size()); |
376 | 0 | break; |
377 | 0 | default: |
378 | 0 | colon_str_ = jsoncons::basic_string_view<CharT>(colon.data(), colon.size()); |
379 | 0 | break; |
380 | 5.16k | } |
381 | 5.16k | switch (options.spaces_around_comma()) |
382 | 5.16k | { |
383 | 5.16k | case spaces_option::space_after: |
384 | 5.16k | comma_str_ = jsoncons::basic_string_view<CharT>(comma_space.data(), colon_space.size()); |
385 | 5.16k | break; |
386 | 0 | case spaces_option::space_before: |
387 | 0 | comma_str_ = jsoncons::basic_string_view<CharT>(space_comma.data(), space_comma.size()); |
388 | 0 | break; |
389 | 0 | case spaces_option::space_before_and_after: |
390 | 0 | comma_str_ = jsoncons::basic_string_view<CharT>(space_comma_space.data(), space_comma_space.size()); |
391 | 0 | break; |
392 | 0 | default: |
393 | 0 | comma_str_ = jsoncons::basic_string_view<CharT>(comma.data(), comma.size()); |
394 | 0 | break; |
395 | 5.16k | } |
396 | 5.16k | if (options.pad_inside_object_braces()) |
397 | 0 | { |
398 | 0 | open_brace_str_ = jsoncons::basic_string_view<CharT>(left_brace_space.data(), left_brace_space.size()); |
399 | 0 | close_brace_str_ = jsoncons::basic_string_view<CharT>(space_right_brace.data(), space_right_brace.size()); |
400 | 0 | } |
401 | 5.16k | else |
402 | 5.16k | { |
403 | 5.16k | open_brace_str_ = jsoncons::basic_string_view<CharT>(left_brace.data(), left_brace.size()); |
404 | 5.16k | close_brace_str_ = jsoncons::basic_string_view<CharT>(right_brace.data(), right_brace.size()); |
405 | 5.16k | } |
406 | 5.16k | if (options.pad_inside_array_brackets()) |
407 | 0 | { |
408 | 0 | open_bracket_str_ = jsoncons::basic_string_view<CharT>(left_bracket_space.data(), left_bracket_space.size()); |
409 | 0 | close_bracket_str_ = jsoncons::basic_string_view<CharT>(space_right_bracket.data(), space_right_bracket.size()); |
410 | 0 | } |
411 | 5.16k | else |
412 | 5.16k | { |
413 | 5.16k | open_bracket_str_ = jsoncons::basic_string_view<CharT>(left_bracket.data(), left_bracket.size()); |
414 | 5.16k | close_bracket_str_ = jsoncons::basic_string_view<CharT>(right_bracket.data(), right_bracket.size()); |
415 | 5.16k | } |
416 | 5.16k | } |
417 | | |
418 | | ~basic_json_encoder() noexcept |
419 | 5.16k | { |
420 | 5.16k | JSONCONS_TRY |
421 | 5.16k | { |
422 | 5.16k | sink_.flush(); |
423 | 5.16k | } |
424 | 5.16k | JSONCONS_CATCH(...) |
425 | 5.16k | { |
426 | 0 | } |
427 | 5.16k | } |
428 | | |
429 | | basic_json_encoder& operator=(const basic_json_encoder&) = delete; |
430 | | basic_json_encoder& operator=(basic_json_encoder&&) = delete; |
431 | | |
432 | | void reset() |
433 | | { |
434 | | stack_.clear(); |
435 | | indent_amount_ = 0; |
436 | | column_ = 0; |
437 | | nesting_depth_ = 0; |
438 | | } |
439 | | |
440 | | void reset(Sink&& sink) |
441 | | { |
442 | | sink_ = std::move(sink); |
443 | | reset(); |
444 | | } |
445 | | |
446 | | private: |
447 | | // Implementing methods |
448 | | void visit_flush() final |
449 | 1.85k | { |
450 | 1.85k | sink_.flush(); |
451 | 1.85k | } |
452 | | |
453 | | JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) final |
454 | 22.0k | { |
455 | 22.0k | if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) |
456 | 0 | { |
457 | 0 | ec = json_errc::max_nesting_depth_exceeded; |
458 | 0 | JSONCONS_VISITOR_RETURN; |
459 | 0 | } |
460 | 22.0k | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
461 | 19.0k | { |
462 | 19.0k | sink_.append(comma_str_.data(),comma_str_.length()); |
463 | 19.0k | column_ += comma_str_.length(); |
464 | 19.0k | } |
465 | | |
466 | 22.0k | if (!stack_.empty()) // object or array |
467 | 21.6k | { |
468 | 21.6k | if (stack_.back().is_object()) |
469 | 1.31k | { |
470 | 1.31k | line_split_kind split_kind = static_cast<uint8_t>(options_.object_object_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? |
471 | 1.31k | options_.object_object_line_splits() : stack_.back().split_kind(); |
472 | 1.31k | switch (split_kind) |
473 | 1.31k | { |
474 | 0 | case line_split_kind::same_line: |
475 | 0 | case line_split_kind::new_line: |
476 | 0 | if (column_ >= options_.line_length_limit()) |
477 | 0 | { |
478 | 0 | break_line(); |
479 | 0 | } |
480 | 0 | break; |
481 | 1.31k | default: // multi_line |
482 | 1.31k | break; |
483 | 1.31k | } |
484 | 1.31k | stack_.emplace_back(container_type::object,split_kind, false, |
485 | 1.31k | column_, column_+open_brace_str_.length()); |
486 | 1.31k | } |
487 | 20.3k | else // array |
488 | 20.3k | { |
489 | 20.3k | line_split_kind split_kind = static_cast<uint8_t>(options_.array_object_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? |
490 | 20.3k | options_.array_object_line_splits() : stack_.back().split_kind(); |
491 | 20.3k | switch (split_kind) |
492 | 20.3k | { |
493 | 0 | case line_split_kind::same_line: |
494 | 0 | if (column_ >= options_.line_length_limit()) |
495 | 0 | { |
496 | | //stack_.back().new_line_after(true); |
497 | 0 | new_line(); |
498 | 0 | } |
499 | 0 | else |
500 | 0 | { |
501 | 0 | stack_.back().new_line_after(true); |
502 | 0 | new_line(); |
503 | 0 | } |
504 | 0 | break; |
505 | 0 | case line_split_kind::new_line: |
506 | 0 | stack_.back().new_line_after(true); |
507 | 0 | new_line(); |
508 | 0 | break; |
509 | 20.3k | default: // multi_line |
510 | 20.3k | stack_.back().new_line_after(true); |
511 | 20.3k | new_line(); |
512 | 20.3k | break; |
513 | 20.3k | } |
514 | 20.3k | stack_.emplace_back(container_type::object,split_kind, false, |
515 | 20.3k | column_, column_+open_brace_str_.length()); |
516 | 20.3k | } |
517 | 21.6k | } |
518 | 463 | else |
519 | 463 | { |
520 | 463 | stack_.emplace_back(container_type::object, options_.root_line_splits(), false, |
521 | 463 | column_, column_+open_brace_str_.length()); |
522 | 463 | } |
523 | 22.0k | indent(); |
524 | | |
525 | 22.0k | sink_.append(open_brace_str_.data(), open_brace_str_.length()); |
526 | 22.0k | column_ += open_brace_str_.length(); |
527 | 22.0k | JSONCONS_VISITOR_RETURN; |
528 | 22.0k | } |
529 | | |
530 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code&) final |
531 | 19.8k | { |
532 | 19.8k | JSONCONS_ASSERT(!stack_.empty()); |
533 | 19.8k | --nesting_depth_; |
534 | | |
535 | 19.8k | unindent(); |
536 | 19.8k | if (stack_.back().new_line_after()) |
537 | 1.73k | { |
538 | 1.73k | new_line(); |
539 | 1.73k | } |
540 | 19.8k | stack_.pop_back(); |
541 | 19.8k | sink_.append(close_brace_str_.data(), close_brace_str_.length()); |
542 | 19.8k | column_ += close_brace_str_.length(); |
543 | | |
544 | 19.8k | end_value(); |
545 | 19.8k | JSONCONS_VISITOR_RETURN; |
546 | 19.8k | } |
547 | | |
548 | | JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) final |
549 | 94.7k | { |
550 | 94.7k | if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) |
551 | 0 | { |
552 | 0 | ec = json_errc::max_nesting_depth_exceeded; |
553 | 0 | JSONCONS_VISITOR_RETURN; |
554 | 0 | } |
555 | 94.7k | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
556 | 28.7k | { |
557 | 28.7k | sink_.append(comma_str_.data(),comma_str_.length()); |
558 | 28.7k | column_ += comma_str_.length(); |
559 | 28.7k | } |
560 | 94.7k | if (!stack_.empty()) |
561 | 93.0k | { |
562 | 93.0k | if (stack_.back().is_object()) |
563 | 755 | { |
564 | 755 | line_split_kind split_kind = static_cast<uint8_t>(options_.object_array_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? |
565 | 755 | options_.object_array_line_splits() : |
566 | 755 | stack_.back().split_kind(); |
567 | 755 | switch (split_kind) |
568 | 755 | { |
569 | 0 | case line_split_kind::same_line: |
570 | 0 | stack_.emplace_back(container_type::array,split_kind,false, |
571 | 0 | column_, column_ + open_bracket_str_.length()); |
572 | 0 | break; |
573 | 0 | case line_split_kind::new_line: |
574 | 0 | { |
575 | 0 | stack_.emplace_back(container_type::array,split_kind,true, |
576 | 0 | column_, column_+open_bracket_str_.length()); |
577 | 0 | break; |
578 | 0 | } |
579 | 755 | default: // multi_line |
580 | 755 | stack_.emplace_back(container_type::array,split_kind,true, |
581 | 755 | column_, column_+open_bracket_str_.length()); |
582 | 755 | break; |
583 | 755 | } |
584 | 755 | } |
585 | 92.2k | else // array |
586 | 92.2k | { |
587 | 92.2k | line_split_kind split_kind = static_cast<uint8_t>(options_.array_array_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? |
588 | 92.2k | options_.array_array_line_splits() : stack_.back().split_kind(); |
589 | 92.2k | switch (split_kind) |
590 | 92.2k | { |
591 | 0 | case line_split_kind::same_line: |
592 | 0 | if (stack_.back().is_multi_line()) |
593 | 0 | { |
594 | 0 | stack_.back().new_line_after(true); |
595 | 0 | new_line(); |
596 | 0 | } |
597 | 0 | stack_.emplace_back(container_type::array,split_kind, false, |
598 | 0 | column_, column_+open_bracket_str_.length()); |
599 | 0 | break; |
600 | 0 | case line_split_kind::new_line: |
601 | 0 | stack_.back().new_line_after(true); |
602 | 0 | new_line(); |
603 | 0 | stack_.emplace_back(container_type::array,split_kind, true, |
604 | 0 | column_, column_+open_bracket_str_.length()); |
605 | 0 | break; |
606 | 92.2k | default: // multi_line |
607 | 92.2k | stack_.back().new_line_after(true); |
608 | 92.2k | new_line(); |
609 | 92.2k | stack_.emplace_back(container_type::array,split_kind, false, |
610 | 92.2k | column_, column_+open_bracket_str_.length()); |
611 | 92.2k | break; |
612 | 92.2k | } |
613 | 92.2k | } |
614 | 93.0k | } |
615 | 1.71k | else |
616 | 1.71k | { |
617 | 1.71k | stack_.emplace_back(container_type::array, options_.root_line_splits(), false, |
618 | 1.71k | column_, column_+open_bracket_str_.length()); |
619 | 1.71k | } |
620 | 94.7k | indent(); |
621 | 94.7k | sink_.append(open_bracket_str_.data(), open_bracket_str_.length()); |
622 | 94.7k | column_ += open_bracket_str_.length(); |
623 | 94.7k | JSONCONS_VISITOR_RETURN; |
624 | 94.7k | } |
625 | | |
626 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code&) final |
627 | 8.64k | { |
628 | 8.64k | JSONCONS_ASSERT(!stack_.empty()); |
629 | 8.64k | --nesting_depth_; |
630 | | |
631 | 8.64k | unindent(); |
632 | 8.64k | if (stack_.back().new_line_after()) |
633 | 7.75k | { |
634 | 7.75k | new_line(); |
635 | 7.75k | } |
636 | 8.64k | stack_.pop_back(); |
637 | 8.64k | sink_.append(close_bracket_str_.data(), close_bracket_str_.length()); |
638 | 8.64k | column_ += close_bracket_str_.length(); |
639 | 8.64k | end_value(); |
640 | 8.64k | JSONCONS_VISITOR_RETURN; |
641 | 8.64k | } |
642 | | |
643 | | JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context&, std::error_code&) final |
644 | 272k | { |
645 | 272k | JSONCONS_ASSERT(!stack_.empty()); |
646 | 272k | if (stack_.back().count() > 0) |
647 | 269k | { |
648 | 269k | sink_.append(comma_str_.data(),comma_str_.length()); |
649 | 269k | column_ += comma_str_.length(); |
650 | 269k | } |
651 | | |
652 | 272k | if (stack_.back().is_multi_line()) |
653 | 272k | { |
654 | 272k | stack_.back().new_line_after(true); |
655 | 272k | new_line(); |
656 | 272k | } |
657 | 0 | else if (stack_.back().count() > 0 && column_ >= options_.line_length_limit()) |
658 | 0 | { |
659 | | //stack_.back().new_line_after(true); |
660 | 0 | new_line(stack_.back().data_pos()); |
661 | 0 | } |
662 | | |
663 | 272k | if (stack_.back().count() == 0) |
664 | 3.83k | { |
665 | 3.83k | stack_.back().set_position(column_); |
666 | 3.83k | } |
667 | 272k | sink_.push_back('\"'); |
668 | 272k | std::size_t length = jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); |
669 | 272k | sink_.push_back('\"'); |
670 | 272k | sink_.append(colon_str_.data(),colon_str_.length()); |
671 | 272k | column_ += (length+2+colon_str_.length()); |
672 | 272k | JSONCONS_VISITOR_RETURN; |
673 | 272k | } |
674 | | |
675 | | JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final |
676 | 133k | { |
677 | 133k | if (!stack_.empty()) |
678 | 133k | { |
679 | 133k | if (stack_.back().is_array()) |
680 | 133k | { |
681 | 133k | begin_scalar_value(); |
682 | 133k | } |
683 | 133k | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
684 | 0 | { |
685 | 0 | break_line(); |
686 | 0 | } |
687 | 133k | } |
688 | | |
689 | 133k | sink_.append(null_constant().data(), null_constant().size()); |
690 | 133k | column_ += null_constant().size(); |
691 | | |
692 | 133k | end_value(); |
693 | 133k | JSONCONS_VISITOR_RETURN; |
694 | 133k | } |
695 | | |
696 | | JSONCONS_VISITOR_RETURN_TYPE visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) final |
697 | 25.3k | { |
698 | 25.3k | if (!stack_.empty()) |
699 | 24.8k | { |
700 | 24.8k | if (stack_.back().is_array()) |
701 | 24.5k | { |
702 | 24.5k | begin_scalar_value(); |
703 | 24.5k | } |
704 | 24.8k | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
705 | 0 | { |
706 | 0 | break_line(); |
707 | 0 | } |
708 | 24.8k | } |
709 | | |
710 | 25.3k | write_string(sv, tag, context, ec); |
711 | | |
712 | 25.3k | end_value(); |
713 | 25.3k | JSONCONS_VISITOR_RETURN; |
714 | 25.3k | } |
715 | | |
716 | | void write_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) |
717 | 25.3k | { |
718 | 25.3k | if (JSONCONS_LIKELY(tag == semantic_tag::noesc && !options_.escape_all_non_ascii() && !options_.escape_solidus())) |
719 | 12.6k | { |
720 | | //std::cout << "noesc\n"; |
721 | 12.6k | sink_.push_back('\"'); |
722 | 12.6k | const CharT* begin = sv.data(); |
723 | 12.6k | const CharT* end = begin + sv.length(); |
724 | 1.34M | for (const CharT* it = begin; it != end; ++it) |
725 | 1.33M | { |
726 | 1.33M | sink_.push_back(*it); |
727 | 1.33M | } |
728 | 12.6k | sink_.push_back('\"'); |
729 | 12.6k | column_ += (sv.length()+2); |
730 | 12.6k | } |
731 | 12.6k | else if (tag == semantic_tag::bigint) |
732 | 10.7k | { |
733 | 10.7k | write_bignum_value(sv); |
734 | 10.7k | } |
735 | 1.90k | else if (tag == semantic_tag::bigdec && options_.bignum_format() == bignum_format_kind::raw) |
736 | 1.02k | { |
737 | 1.02k | write_bignum_value(sv); |
738 | 1.02k | } |
739 | 878 | else |
740 | 878 | { |
741 | | //if (tag != semantic_tag::bigdec) |
742 | | // std::cout << "esc\n"; |
743 | 878 | sink_.push_back('\"'); |
744 | 878 | std::size_t length = jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); |
745 | 878 | sink_.push_back('\"'); |
746 | 878 | column_ += (length+2); |
747 | 878 | } |
748 | 25.3k | } |
749 | | |
750 | | JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, |
751 | | semantic_tag tag, |
752 | | const ser_context&, |
753 | | std::error_code&) final |
754 | 0 | { |
755 | 0 | if (!stack_.empty()) |
756 | 0 | { |
757 | 0 | if (stack_.back().is_array()) |
758 | 0 | { |
759 | 0 | begin_scalar_value(); |
760 | 0 | } |
761 | 0 | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
762 | 0 | { |
763 | 0 | break_line(); |
764 | 0 | } |
765 | 0 | } |
766 | |
|
767 | 0 | byte_string_chars_format encoding_hint; |
768 | 0 | switch (tag) |
769 | 0 | { |
770 | 0 | case semantic_tag::base16: |
771 | 0 | encoding_hint = byte_string_chars_format::base16; |
772 | 0 | break; |
773 | 0 | case semantic_tag::base64: |
774 | 0 | encoding_hint = byte_string_chars_format::base64; |
775 | 0 | break; |
776 | 0 | case semantic_tag::base64url: |
777 | 0 | encoding_hint = byte_string_chars_format::base64url; |
778 | 0 | break; |
779 | 0 | default: |
780 | 0 | encoding_hint = byte_string_chars_format::none; |
781 | 0 | break; |
782 | 0 | } |
783 | | |
784 | 0 | byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), |
785 | 0 | encoding_hint, |
786 | 0 | byte_string_chars_format::base64url); |
787 | 0 | switch (format) |
788 | 0 | { |
789 | 0 | case byte_string_chars_format::base16: |
790 | 0 | { |
791 | 0 | sink_.push_back('\"'); |
792 | 0 | std::size_t length = bytes_to_base16(b.begin(),b.end(),sink_); |
793 | 0 | sink_.push_back('\"'); |
794 | 0 | column_ += (length + 2); |
795 | 0 | break; |
796 | 0 | } |
797 | 0 | case byte_string_chars_format::base64: |
798 | 0 | { |
799 | 0 | sink_.push_back('\"'); |
800 | 0 | std::size_t length = bytes_to_base64(b.begin(), b.end(), sink_); |
801 | 0 | sink_.push_back('\"'); |
802 | 0 | column_ += (length + 2); |
803 | 0 | break; |
804 | 0 | } |
805 | 0 | case byte_string_chars_format::base64url: |
806 | 0 | { |
807 | 0 | sink_.push_back('\"'); |
808 | 0 | std::size_t length = bytes_to_base64url(b.begin(),b.end(),sink_); |
809 | 0 | sink_.push_back('\"'); |
810 | 0 | column_ += (length + 2); |
811 | 0 | break; |
812 | 0 | } |
813 | 0 | default: |
814 | 0 | { |
815 | 0 | JSONCONS_UNREACHABLE(); |
816 | 0 | } |
817 | 0 | } |
818 | | |
819 | 0 | end_value(); |
820 | 0 | JSONCONS_VISITOR_RETURN; |
821 | 0 | } |
822 | | |
823 | | JSONCONS_VISITOR_RETURN_TYPE visit_double(double value, |
824 | | semantic_tag, |
825 | | const ser_context& context, |
826 | | std::error_code& ec) final |
827 | 1.34M | { |
828 | 1.34M | if (!stack_.empty()) |
829 | 1.34M | { |
830 | 1.34M | if (stack_.back().is_array()) |
831 | 1.34M | { |
832 | 1.34M | begin_scalar_value(); |
833 | 1.34M | } |
834 | 1.34M | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
835 | 0 | { |
836 | 0 | break_line(); |
837 | 0 | } |
838 | 1.34M | } |
839 | | |
840 | 1.34M | if (!std::isfinite(value)) |
841 | 0 | { |
842 | 0 | if ((std::isnan)(value)) |
843 | 0 | { |
844 | 0 | if (options_.enable_nan_to_num()) |
845 | 0 | { |
846 | 0 | sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length()); |
847 | 0 | column_ += options_.nan_to_num().length(); |
848 | 0 | } |
849 | 0 | else if (options_.enable_nan_to_str()) |
850 | 0 | { |
851 | 0 | write_string(options_.nan_to_str(), semantic_tag::none, context, ec); |
852 | 0 | } |
853 | 0 | else |
854 | 0 | { |
855 | 0 | sink_.append(null_constant().data(), null_constant().size()); |
856 | 0 | column_ += null_constant().size(); |
857 | 0 | } |
858 | 0 | } |
859 | 0 | else if (value == std::numeric_limits<double>::infinity()) |
860 | 0 | { |
861 | 0 | if (options_.enable_inf_to_num()) |
862 | 0 | { |
863 | 0 | sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length()); |
864 | 0 | column_ += options_.inf_to_num().length(); |
865 | 0 | } |
866 | 0 | else if (options_.enable_inf_to_str()) |
867 | 0 | { |
868 | 0 | write_string(options_.inf_to_str(), semantic_tag::none, context, ec); |
869 | 0 | } |
870 | 0 | else |
871 | 0 | { |
872 | 0 | sink_.append(null_constant().data(), null_constant().size()); |
873 | 0 | column_ += null_constant().size(); |
874 | 0 | } |
875 | 0 | } |
876 | 0 | else |
877 | 0 | { |
878 | 0 | if (options_.enable_neginf_to_num()) |
879 | 0 | { |
880 | 0 | sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length()); |
881 | 0 | column_ += options_.neginf_to_num().length(); |
882 | 0 | } |
883 | 0 | else if (options_.enable_neginf_to_str()) |
884 | 0 | { |
885 | 0 | write_string(options_.neginf_to_str(), semantic_tag::none, context, ec); |
886 | 0 | } |
887 | 0 | else |
888 | 0 | { |
889 | 0 | sink_.append(null_constant().data(), null_constant().size()); |
890 | 0 | column_ += null_constant().size(); |
891 | 0 | } |
892 | 0 | } |
893 | 0 | } |
894 | 1.34M | else |
895 | 1.34M | { |
896 | 1.34M | std::size_t length = fp_(value, sink_); |
897 | 1.34M | column_ += length; |
898 | 1.34M | } |
899 | | |
900 | 1.34M | end_value(); |
901 | 1.34M | JSONCONS_VISITOR_RETURN; |
902 | 1.34M | } |
903 | | |
904 | | JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t value, |
905 | | semantic_tag, |
906 | | const ser_context&, |
907 | | std::error_code&) final |
908 | 228k | { |
909 | 228k | if (!stack_.empty()) |
910 | 227k | { |
911 | 227k | if (stack_.back().is_array()) |
912 | 227k | { |
913 | 227k | begin_scalar_value(); |
914 | 227k | } |
915 | 227k | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
916 | 0 | { |
917 | 0 | break_line(); |
918 | 0 | } |
919 | 227k | } |
920 | 228k | std::size_t length = jsoncons::from_integer(value, sink_); |
921 | 228k | column_ += length; |
922 | 228k | end_value(); |
923 | 228k | JSONCONS_VISITOR_RETURN; |
924 | 228k | } |
925 | | |
926 | | JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t value, |
927 | | semantic_tag, |
928 | | const ser_context&, |
929 | | std::error_code&) final |
930 | 4.89M | { |
931 | 4.89M | if (!stack_.empty()) |
932 | 4.89M | { |
933 | 4.89M | if (stack_.back().is_array()) |
934 | 4.62M | { |
935 | 4.62M | begin_scalar_value(); |
936 | 4.62M | } |
937 | 4.89M | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
938 | 0 | { |
939 | 0 | break_line(); |
940 | 0 | } |
941 | 4.89M | } |
942 | 4.89M | std::size_t length = jsoncons::from_integer(value, sink_); |
943 | 4.89M | column_ += length; |
944 | 4.89M | end_value(); |
945 | 4.89M | JSONCONS_VISITOR_RETURN; |
946 | 4.89M | } |
947 | | |
948 | | JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) final |
949 | 812k | { |
950 | 812k | if (!stack_.empty()) |
951 | 812k | { |
952 | 812k | if (stack_.back().is_array()) |
953 | 812k | { |
954 | 812k | begin_scalar_value(); |
955 | 812k | } |
956 | 812k | if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit()) |
957 | 0 | { |
958 | 0 | break_line(); |
959 | 0 | } |
960 | 812k | } |
961 | | |
962 | 812k | if (value) |
963 | 543k | { |
964 | 543k | sink_.append(true_constant().data(), true_constant().size()); |
965 | 543k | column_ += true_constant().size(); |
966 | 543k | } |
967 | 268k | else |
968 | 268k | { |
969 | 268k | sink_.append(false_constant().data(), false_constant().size()); |
970 | 268k | column_ += false_constant().size(); |
971 | 268k | } |
972 | | |
973 | 812k | end_value(); |
974 | 812k | JSONCONS_VISITOR_RETURN; |
975 | 812k | } |
976 | | |
977 | | void begin_scalar_value() |
978 | 7.16M | { |
979 | 7.16M | if (!stack_.empty()) |
980 | 7.16M | { |
981 | 7.16M | if (stack_.back().count() > 0) |
982 | 7.13M | { |
983 | 7.13M | sink_.append(comma_str_.data(),comma_str_.length()); |
984 | 7.13M | column_ += comma_str_.length(); |
985 | 7.13M | } |
986 | 7.16M | if (stack_.back().is_multi_line() || stack_.back().is_indent_once()) |
987 | 7.16M | { |
988 | 7.16M | stack_.back().new_line_after(true); |
989 | 7.16M | new_line(); |
990 | 7.16M | } |
991 | 7.16M | } |
992 | 7.16M | } |
993 | | |
994 | | void write_bignum_value(const string_view_type& sv) |
995 | 11.7k | { |
996 | 11.7k | switch (options_.bignum_format()) |
997 | 11.7k | { |
998 | 11.7k | case bignum_format_kind::raw: |
999 | 11.7k | { |
1000 | 11.7k | sink_.append(sv.data(),sv.size()); |
1001 | 11.7k | column_ += sv.size(); |
1002 | 11.7k | break; |
1003 | 0 | } |
1004 | 0 | case bignum_format_kind::base64: |
1005 | 0 | { |
1006 | 0 | bigint n(sv.data(), sv.length()); |
1007 | 0 | bool is_neg = n < 0; |
1008 | 0 | if (is_neg) |
1009 | 0 | { |
1010 | 0 | n = - n -1; |
1011 | 0 | } |
1012 | 0 | int signum; |
1013 | 0 | std::vector<uint8_t> v; |
1014 | 0 | n.write_bytes_be(signum, v); |
1015 | |
|
1016 | 0 | sink_.push_back('\"'); |
1017 | 0 | if (is_neg) |
1018 | 0 | { |
1019 | 0 | sink_.push_back('~'); |
1020 | 0 | ++column_; |
1021 | 0 | } |
1022 | 0 | std::size_t length = bytes_to_base64(v.begin(), v.end(), sink_); |
1023 | 0 | sink_.push_back('\"'); |
1024 | 0 | column_ += (length+2); |
1025 | 0 | break; |
1026 | 0 | } |
1027 | 0 | case bignum_format_kind::base64url: |
1028 | 0 | { |
1029 | 0 | bigint n(sv.data(), sv.length()); |
1030 | 0 | bool is_neg = n < 0; |
1031 | 0 | if (is_neg) |
1032 | 0 | { |
1033 | 0 | n = - n -1; |
1034 | 0 | } |
1035 | 0 | int signum; |
1036 | 0 | std::vector<uint8_t> v; |
1037 | 0 | n.write_bytes_be(signum, v); |
1038 | |
|
1039 | 0 | sink_.push_back('\"'); |
1040 | 0 | if (is_neg) |
1041 | 0 | { |
1042 | 0 | sink_.push_back('~'); |
1043 | 0 | ++column_; |
1044 | 0 | } |
1045 | 0 | std::size_t length = bytes_to_base64url(v.begin(), v.end(), sink_); |
1046 | 0 | sink_.push_back('\"'); |
1047 | 0 | column_ += (length+2); |
1048 | 0 | break; |
1049 | 0 | } |
1050 | 0 | default: |
1051 | 0 | { |
1052 | 0 | sink_.push_back('\"'); |
1053 | 0 | sink_.append(sv.data(),sv.size()); |
1054 | 0 | sink_.push_back('\"'); |
1055 | 0 | column_ += (sv.size() + 2); |
1056 | 0 | break; |
1057 | 0 | } |
1058 | 11.7k | } |
1059 | 11.7k | } |
1060 | | |
1061 | | void end_value() |
1062 | 7.46M | { |
1063 | 7.46M | if (!stack_.empty()) |
1064 | 7.46M | { |
1065 | 7.46M | stack_.back().increment_count(); |
1066 | 7.46M | } |
1067 | 7.46M | } |
1068 | | |
1069 | | void indent() |
1070 | 116k | { |
1071 | 116k | indent_amount_ += static_cast<uint8_t>(options_.indent_size()); |
1072 | 116k | } |
1073 | | |
1074 | | void unindent() |
1075 | 28.4k | { |
1076 | 28.4k | indent_amount_ -= static_cast<uint8_t>(options_.indent_size()); |
1077 | 28.4k | } |
1078 | | |
1079 | | void new_line() |
1080 | 7.56M | { |
1081 | 7.56M | sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length()); |
1082 | 2.39G | for (int i = 0; i < indent_amount_; ++i) |
1083 | 2.39G | { |
1084 | 2.39G | sink_.push_back(indent_char_); |
1085 | 2.39G | } |
1086 | 7.56M | column_ = indent_amount_; |
1087 | 7.56M | } |
1088 | | |
1089 | | void new_line(std::size_t len) |
1090 | 0 | { |
1091 | 0 | sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length()); |
1092 | 0 | for (std::size_t i = 0; i < len; ++i) |
1093 | 0 | { |
1094 | 0 | sink_.push_back(' '); |
1095 | 0 | } |
1096 | 0 | column_ = len; |
1097 | 0 | } |
1098 | | |
1099 | | void break_line() |
1100 | 0 | { |
1101 | 0 | stack_.back().new_line_after(true); |
1102 | 0 | new_line(); |
1103 | 0 | } |
1104 | | }; |
1105 | | |
1106 | | template <typename CharT, typename Sink, typename Allocator> |
1107 | | const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::colon = {':'}; |
1108 | | template <typename CharT,typename Sink,typename Allocator> |
1109 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::colon_space = {':', ' '}; |
1110 | | template <typename CharT,typename Sink,typename Allocator> |
1111 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_colon = {' ', ':'}; |
1112 | | template <typename CharT,typename Sink,typename Allocator> |
1113 | | const std::array<CharT,3> basic_json_encoder<CharT,Sink,Allocator>::space_colon_space = {' ', ':', ' '}; |
1114 | | |
1115 | | template <typename CharT, typename Sink, typename Allocator> |
1116 | | const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::comma = {','}; |
1117 | | template <typename CharT,typename Sink,typename Allocator> |
1118 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::comma_space = {',', ' '}; |
1119 | | template <typename CharT,typename Sink,typename Allocator> |
1120 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_comma = {' ', ','}; |
1121 | | template <typename CharT,typename Sink,typename Allocator> |
1122 | | const std::array<CharT,3> basic_json_encoder<CharT,Sink,Allocator>::space_comma_space = {' ', ',', ' '}; |
1123 | | |
1124 | | template <typename CharT, typename Sink, typename Allocator> |
1125 | | const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::left_brace = {'{'}; |
1126 | | template <typename CharT,typename Sink,typename Allocator> |
1127 | | const std::array<CharT,1> basic_json_encoder<CharT,Sink,Allocator>::right_brace = {'}'}; |
1128 | | template <typename CharT,typename Sink,typename Allocator> |
1129 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::left_brace_space = {'{', ' '}; |
1130 | | template <typename CharT,typename Sink,typename Allocator> |
1131 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_right_brace = {' ', '}'}; |
1132 | | |
1133 | | template <typename CharT, typename Sink, typename Allocator> |
1134 | | const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::left_bracket = {'['}; |
1135 | | template <typename CharT,typename Sink,typename Allocator> |
1136 | | const std::array<CharT,1> basic_json_encoder<CharT,Sink,Allocator>::right_bracket = {']'}; |
1137 | | template <typename CharT,typename Sink,typename Allocator> |
1138 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::left_bracket_space = {'[', ' '}; |
1139 | | template <typename CharT,typename Sink,typename Allocator> |
1140 | | const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_right_bracket = {' ', ']'}; |
1141 | | |
1142 | | template <typename CharT,typename Sink=jsoncons::stream_sink<CharT>,typename Allocator=std::allocator<char>> |
1143 | | class basic_compact_json_encoder final : public basic_json_visitor<CharT> |
1144 | | { |
1145 | | static const std::array<CharT, 4>& null_constant() |
1146 | | { |
1147 | | static constexpr std::array<CharT,4> k{{'n','u','l','l'}}; |
1148 | | return k; |
1149 | | } |
1150 | | static const std::array<CharT, 4>& true_constant() |
1151 | | { |
1152 | | static constexpr std::array<CharT,4> k{{'t','r','u','e'}}; |
1153 | | return k; |
1154 | | } |
1155 | | static const std::array<CharT, 5>& false_constant() |
1156 | | { |
1157 | | static constexpr std::array<CharT,5> k{{'f','a','l','s','e'}}; |
1158 | | return k; |
1159 | | } |
1160 | | public: |
1161 | | using allocator_type = Allocator; |
1162 | | using char_type = CharT; |
1163 | | using typename basic_json_visitor<CharT>::string_view_type; |
1164 | | using sink_type = Sink; |
1165 | | using string_type = typename basic_json_encode_options<CharT>::string_type; |
1166 | | |
1167 | | private: |
1168 | | enum class container_type {object, array}; |
1169 | | |
1170 | | class encoding_context |
1171 | | { |
1172 | | container_type type_; |
1173 | | std::size_t count_{0}; |
1174 | | public: |
1175 | | encoding_context(container_type type) noexcept |
1176 | | : type_(type) |
1177 | | { |
1178 | | } |
1179 | | |
1180 | | std::size_t count() const |
1181 | | { |
1182 | | return count_; |
1183 | | } |
1184 | | |
1185 | | void increment_count() |
1186 | | { |
1187 | | ++count_; |
1188 | | } |
1189 | | |
1190 | | bool is_array() const |
1191 | | { |
1192 | | return type_ == container_type::array; |
1193 | | } |
1194 | | }; |
1195 | | using encoding_context_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<encoding_context>; |
1196 | | |
1197 | | Sink sink_; |
1198 | | basic_json_encode_options<CharT> options_; |
1199 | | jsoncons::write_double fp_; |
1200 | | std::vector<encoding_context,encoding_context_allocator_type> stack_; |
1201 | | int nesting_depth_; |
1202 | | public: |
1203 | | |
1204 | | // Noncopyable and nonmoveable |
1205 | | basic_compact_json_encoder(const basic_compact_json_encoder&) = delete; |
1206 | | basic_compact_json_encoder(basic_compact_json_encoder&&) = delete; |
1207 | | |
1208 | | basic_compact_json_encoder(Sink&& sink, |
1209 | | const Allocator& alloc = Allocator()) |
1210 | | : basic_compact_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc) |
1211 | | { |
1212 | | } |
1213 | | |
1214 | | basic_compact_json_encoder(Sink&& sink, |
1215 | | const basic_json_encode_options<CharT>& options, |
1216 | | const Allocator& alloc = Allocator()) |
1217 | | : sink_(std::forward<Sink>(sink)), |
1218 | | options_(options), |
1219 | | fp_(options.float_format(), options.precision()), |
1220 | | stack_(alloc), |
1221 | | nesting_depth_(0) |
1222 | | { |
1223 | | } |
1224 | | |
1225 | | ~basic_compact_json_encoder() noexcept |
1226 | | { |
1227 | | JSONCONS_TRY |
1228 | | { |
1229 | | sink_.flush(); |
1230 | | } |
1231 | | JSONCONS_CATCH(...) |
1232 | | { |
1233 | | } |
1234 | | } |
1235 | | |
1236 | | basic_compact_json_encoder& operator=(const basic_compact_json_encoder&) = delete; |
1237 | | basic_compact_json_encoder& operator=(basic_compact_json_encoder&&) = delete; |
1238 | | |
1239 | | void reset() |
1240 | | { |
1241 | | stack_.clear(); |
1242 | | nesting_depth_ = 0; |
1243 | | } |
1244 | | |
1245 | | void reset(Sink&& sink) |
1246 | | { |
1247 | | sink_ = std::move(sink); |
1248 | | reset(); |
1249 | | } |
1250 | | |
1251 | | private: |
1252 | | // Implementing methods |
1253 | | void visit_flush() final |
1254 | | { |
1255 | | sink_.flush(); |
1256 | | } |
1257 | | |
1258 | | JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) final |
1259 | | { |
1260 | | if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) |
1261 | | { |
1262 | | ec = json_errc::max_nesting_depth_exceeded; |
1263 | | JSONCONS_VISITOR_RETURN; |
1264 | | } |
1265 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1266 | | { |
1267 | | sink_.push_back(','); |
1268 | | } |
1269 | | |
1270 | | stack_.emplace_back(container_type::object); |
1271 | | sink_.push_back('{'); |
1272 | | JSONCONS_VISITOR_RETURN; |
1273 | | } |
1274 | | |
1275 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code&) final |
1276 | | { |
1277 | | JSONCONS_ASSERT(!stack_.empty()); |
1278 | | --nesting_depth_; |
1279 | | |
1280 | | stack_.pop_back(); |
1281 | | sink_.push_back('}'); |
1282 | | |
1283 | | if (!stack_.empty()) |
1284 | | { |
1285 | | stack_.back().increment_count(); |
1286 | | } |
1287 | | JSONCONS_VISITOR_RETURN; |
1288 | | } |
1289 | | |
1290 | | |
1291 | | JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) final |
1292 | | { |
1293 | | if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) |
1294 | | { |
1295 | | ec = json_errc::max_nesting_depth_exceeded; |
1296 | | JSONCONS_VISITOR_RETURN; |
1297 | | } |
1298 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1299 | | { |
1300 | | sink_.push_back(','); |
1301 | | } |
1302 | | stack_.emplace_back(container_type::array); |
1303 | | sink_.push_back('['); |
1304 | | JSONCONS_VISITOR_RETURN; |
1305 | | } |
1306 | | |
1307 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code&) final |
1308 | | { |
1309 | | JSONCONS_ASSERT(!stack_.empty()); |
1310 | | --nesting_depth_; |
1311 | | |
1312 | | stack_.pop_back(); |
1313 | | sink_.push_back(']'); |
1314 | | if (!stack_.empty()) |
1315 | | { |
1316 | | stack_.back().increment_count(); |
1317 | | } |
1318 | | JSONCONS_VISITOR_RETURN; |
1319 | | } |
1320 | | |
1321 | | JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context&, std::error_code&) final |
1322 | | { |
1323 | | if (!stack_.empty() && stack_.back().count() > 0) |
1324 | | { |
1325 | | sink_.push_back(','); |
1326 | | } |
1327 | | |
1328 | | sink_.push_back('\"'); |
1329 | | jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); |
1330 | | sink_.push_back('\"'); |
1331 | | sink_.push_back(':'); |
1332 | | JSONCONS_VISITOR_RETURN; |
1333 | | } |
1334 | | |
1335 | | JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final |
1336 | | { |
1337 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1338 | | { |
1339 | | sink_.push_back(','); |
1340 | | } |
1341 | | |
1342 | | sink_.append(null_constant().data(), null_constant().size()); |
1343 | | |
1344 | | if (!stack_.empty()) |
1345 | | { |
1346 | | stack_.back().increment_count(); |
1347 | | } |
1348 | | JSONCONS_VISITOR_RETURN; |
1349 | | } |
1350 | | |
1351 | | void write_bignum_value(const string_view_type& sv) |
1352 | | { |
1353 | | switch (options_.bignum_format()) |
1354 | | { |
1355 | | case bignum_format_kind::raw: |
1356 | | { |
1357 | | sink_.append(sv.data(),sv.size()); |
1358 | | break; |
1359 | | } |
1360 | | case bignum_format_kind::base64: |
1361 | | { |
1362 | | bigint n(sv.data(), sv.length()); |
1363 | | bool is_neg = n < 0; |
1364 | | if (is_neg) |
1365 | | { |
1366 | | n = - n -1; |
1367 | | } |
1368 | | int signum; |
1369 | | std::vector<uint8_t> v; |
1370 | | n.write_bytes_be(signum, v); |
1371 | | |
1372 | | sink_.push_back('\"'); |
1373 | | if (is_neg) |
1374 | | { |
1375 | | sink_.push_back('~'); |
1376 | | } |
1377 | | bytes_to_base64(v.begin(), v.end(), sink_); |
1378 | | sink_.push_back('\"'); |
1379 | | break; |
1380 | | } |
1381 | | case bignum_format_kind::base64url: |
1382 | | { |
1383 | | bigint n(sv.data(), sv.length()); |
1384 | | bool is_neg = n < 0; |
1385 | | if (is_neg) |
1386 | | { |
1387 | | n = - n -1; |
1388 | | } |
1389 | | int signum; |
1390 | | std::vector<uint8_t> v; |
1391 | | n.write_bytes_be(signum, v); |
1392 | | |
1393 | | sink_.push_back('\"'); |
1394 | | if (is_neg) |
1395 | | { |
1396 | | sink_.push_back('~'); |
1397 | | } |
1398 | | bytes_to_base64url(v.begin(), v.end(), sink_); |
1399 | | sink_.push_back('\"'); |
1400 | | break; |
1401 | | } |
1402 | | default: |
1403 | | { |
1404 | | sink_.push_back('\"'); |
1405 | | sink_.append(sv.data(),sv.size()); |
1406 | | sink_.push_back('\"'); |
1407 | | break; |
1408 | | } |
1409 | | } |
1410 | | } |
1411 | | |
1412 | | JSONCONS_VISITOR_RETURN_TYPE visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) final |
1413 | | { |
1414 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1415 | | { |
1416 | | sink_.push_back(','); |
1417 | | } |
1418 | | |
1419 | | write_string(sv, tag, context, ec); |
1420 | | |
1421 | | if (!stack_.empty()) |
1422 | | { |
1423 | | stack_.back().increment_count(); |
1424 | | } |
1425 | | JSONCONS_VISITOR_RETURN; |
1426 | | } |
1427 | | |
1428 | | void write_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) |
1429 | | { |
1430 | | if (JSONCONS_LIKELY(tag == semantic_tag::noesc && !options_.escape_all_non_ascii() && !options_.escape_solidus())) |
1431 | | { |
1432 | | //std::cout << "noesc\n"; |
1433 | | sink_.push_back('\"'); |
1434 | | const CharT* begin = sv.data(); |
1435 | | const CharT* end = begin + sv.length(); |
1436 | | for (const CharT* it = begin; it != end; ++it) |
1437 | | { |
1438 | | sink_.push_back(*it); |
1439 | | } |
1440 | | sink_.push_back('\"'); |
1441 | | } |
1442 | | else if (tag == semantic_tag::bigint) |
1443 | | { |
1444 | | write_bignum_value(sv); |
1445 | | } |
1446 | | else if (tag == semantic_tag::bigdec && options_.bignum_format() == bignum_format_kind::raw) |
1447 | | { |
1448 | | write_bignum_value(sv); |
1449 | | } |
1450 | | else |
1451 | | { |
1452 | | //if (tag != semantic_tag::bigdec) |
1453 | | // std::cout << "esc\n"; |
1454 | | sink_.push_back('\"'); |
1455 | | jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_); |
1456 | | sink_.push_back('\"'); |
1457 | | } |
1458 | | } |
1459 | | |
1460 | | JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, |
1461 | | semantic_tag tag, |
1462 | | const ser_context&, |
1463 | | std::error_code&) final |
1464 | | { |
1465 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1466 | | { |
1467 | | sink_.push_back(','); |
1468 | | } |
1469 | | |
1470 | | byte_string_chars_format encoding_hint; |
1471 | | switch (tag) |
1472 | | { |
1473 | | case semantic_tag::base16: |
1474 | | encoding_hint = byte_string_chars_format::base16; |
1475 | | break; |
1476 | | case semantic_tag::base64: |
1477 | | encoding_hint = byte_string_chars_format::base64; |
1478 | | break; |
1479 | | case semantic_tag::base64url: |
1480 | | encoding_hint = byte_string_chars_format::base64url; |
1481 | | break; |
1482 | | default: |
1483 | | encoding_hint = byte_string_chars_format::none; |
1484 | | break; |
1485 | | } |
1486 | | |
1487 | | byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), |
1488 | | encoding_hint, |
1489 | | byte_string_chars_format::base64url); |
1490 | | switch (format) |
1491 | | { |
1492 | | case byte_string_chars_format::base16: |
1493 | | { |
1494 | | sink_.push_back('\"'); |
1495 | | bytes_to_base16(b.begin(),b.end(),sink_); |
1496 | | sink_.push_back('\"'); |
1497 | | break; |
1498 | | } |
1499 | | case byte_string_chars_format::base64: |
1500 | | { |
1501 | | sink_.push_back('\"'); |
1502 | | bytes_to_base64(b.begin(), b.end(), sink_); |
1503 | | sink_.push_back('\"'); |
1504 | | break; |
1505 | | } |
1506 | | case byte_string_chars_format::base64url: |
1507 | | { |
1508 | | sink_.push_back('\"'); |
1509 | | bytes_to_base64url(b.begin(),b.end(),sink_); |
1510 | | sink_.push_back('\"'); |
1511 | | break; |
1512 | | } |
1513 | | default: |
1514 | | { |
1515 | | JSONCONS_UNREACHABLE(); |
1516 | | } |
1517 | | } |
1518 | | |
1519 | | if (!stack_.empty()) |
1520 | | { |
1521 | | stack_.back().increment_count(); |
1522 | | } |
1523 | | JSONCONS_VISITOR_RETURN; |
1524 | | } |
1525 | | |
1526 | | JSONCONS_VISITOR_RETURN_TYPE visit_double(double value, |
1527 | | semantic_tag, |
1528 | | const ser_context& context, |
1529 | | std::error_code& ec) final |
1530 | | { |
1531 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1532 | | { |
1533 | | sink_.push_back(','); |
1534 | | } |
1535 | | |
1536 | | if (JSONCONS_UNLIKELY(!std::isfinite(value))) |
1537 | | { |
1538 | | if ((std::isnan)(value)) |
1539 | | { |
1540 | | if (options_.enable_nan_to_num()) |
1541 | | { |
1542 | | sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length()); |
1543 | | } |
1544 | | else if (options_.enable_nan_to_str()) |
1545 | | { |
1546 | | write_string(options_.nan_to_str(), semantic_tag::none, context, ec); |
1547 | | } |
1548 | | else |
1549 | | { |
1550 | | sink_.append(null_constant().data(), null_constant().size()); |
1551 | | } |
1552 | | } |
1553 | | else if (value == std::numeric_limits<double>::infinity()) |
1554 | | { |
1555 | | if (options_.enable_inf_to_num()) |
1556 | | { |
1557 | | sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length()); |
1558 | | } |
1559 | | else if (options_.enable_inf_to_str()) |
1560 | | { |
1561 | | write_string(options_.inf_to_str(), semantic_tag::none, context, ec); |
1562 | | } |
1563 | | else |
1564 | | { |
1565 | | sink_.append(null_constant().data(), null_constant().size()); |
1566 | | } |
1567 | | } |
1568 | | else |
1569 | | { |
1570 | | if (options_.enable_neginf_to_num()) |
1571 | | { |
1572 | | sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length()); |
1573 | | } |
1574 | | else if (options_.enable_neginf_to_str()) |
1575 | | { |
1576 | | write_string(options_.neginf_to_str(), semantic_tag::none, context, ec); |
1577 | | } |
1578 | | else |
1579 | | { |
1580 | | sink_.append(null_constant().data(), null_constant().size()); |
1581 | | } |
1582 | | } |
1583 | | } |
1584 | | else |
1585 | | { |
1586 | | fp_(value, sink_); |
1587 | | } |
1588 | | |
1589 | | if (!stack_.empty()) |
1590 | | { |
1591 | | stack_.back().increment_count(); |
1592 | | } |
1593 | | JSONCONS_VISITOR_RETURN; |
1594 | | } |
1595 | | |
1596 | | JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t value, |
1597 | | semantic_tag, |
1598 | | const ser_context&, |
1599 | | std::error_code&) final |
1600 | | { |
1601 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1602 | | { |
1603 | | sink_.push_back(','); |
1604 | | } |
1605 | | jsoncons::from_integer(value, sink_); |
1606 | | if (!stack_.empty()) |
1607 | | { |
1608 | | stack_.back().increment_count(); |
1609 | | } |
1610 | | JSONCONS_VISITOR_RETURN; |
1611 | | } |
1612 | | |
1613 | | JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t value, |
1614 | | semantic_tag, |
1615 | | const ser_context&, |
1616 | | std::error_code&) final |
1617 | | { |
1618 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1619 | | { |
1620 | | sink_.push_back(','); |
1621 | | } |
1622 | | jsoncons::from_integer(value, sink_); |
1623 | | if (!stack_.empty()) |
1624 | | { |
1625 | | stack_.back().increment_count(); |
1626 | | } |
1627 | | JSONCONS_VISITOR_RETURN; |
1628 | | } |
1629 | | |
1630 | | JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) final |
1631 | | { |
1632 | | if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0) |
1633 | | { |
1634 | | sink_.push_back(','); |
1635 | | } |
1636 | | |
1637 | | if (value) |
1638 | | { |
1639 | | sink_.append(true_constant().data(), true_constant().size()); |
1640 | | } |
1641 | | else |
1642 | | { |
1643 | | sink_.append(false_constant().data(), false_constant().size()); |
1644 | | } |
1645 | | |
1646 | | if (!stack_.empty()) |
1647 | | { |
1648 | | stack_.back().increment_count(); |
1649 | | } |
1650 | | JSONCONS_VISITOR_RETURN; |
1651 | | } |
1652 | | }; |
1653 | | |
1654 | | using json_stream_encoder = basic_json_encoder<char,jsoncons::stream_sink<char>>; |
1655 | | using wjson_stream_encoder = basic_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>>; |
1656 | | using compact_json_stream_encoder = basic_compact_json_encoder<char,jsoncons::stream_sink<char>>; |
1657 | | using compact_wjson_stream_encoder = basic_compact_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>>; |
1658 | | |
1659 | | using json_string_encoder = basic_json_encoder<char,jsoncons::string_sink<std::string>>; |
1660 | | using wjson_string_encoder = basic_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>>; |
1661 | | using compact_json_string_encoder = basic_compact_json_encoder<char,jsoncons::string_sink<std::string>>; |
1662 | | using compact_wjson_string_encoder = basic_compact_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>>; |
1663 | | |
1664 | | } // namespace jsoncons |
1665 | | |
1666 | | #endif // JSONCONS_JSON_ENCODER_HPP |