jsoncons 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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