jsoncons 0.1.0

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