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,567 @@
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_DETAIL_WRITE_NUMBER_HPP
8
+ #define JSONCONS_DETAIL_WRITE_NUMBER_HPP
9
+
10
+ #include <stdexcept>
11
+ #include <string>
12
+ #include <cmath>
13
+ #include <locale>
14
+ #include <limits> // std::numeric_limits
15
+ #include <exception>
16
+ #include <stdio.h> // snprintf
17
+ #include <jsoncons/config/jsoncons_config.hpp>
18
+ #include <jsoncons/json_options.hpp>
19
+ #include <jsoncons/detail/grisu3.hpp>
20
+ #include <jsoncons/detail/parse_number.hpp>
21
+ #include <jsoncons/traits_extension.hpp>
22
+
23
+ namespace jsoncons {
24
+ namespace detail {
25
+
26
+ inline
27
+ char to_hex_character(uint8_t c)
28
+ {
29
+ return (char)((c < 10) ? ('0' + c) : ('A' - 10 + c));
30
+ }
31
+
32
+ // from_integer
33
+
34
+ template<class Integer,class Result>
35
+ typename std::enable_if<traits_extension::is_integer<Integer>::value,std::size_t>::type
36
+ from_integer(Integer value, Result& result)
37
+ {
38
+ using char_type = typename Result::value_type;
39
+
40
+ char_type buf[255];
41
+ char_type *p = buf;
42
+ const char_type* last = buf+255;
43
+
44
+ bool is_negative = value < 0;
45
+
46
+ if (value < 0)
47
+ {
48
+ do
49
+ {
50
+ *p++ = static_cast<char_type>(48 - (value % 10));
51
+ }
52
+ while ((value /= 10) && (p < last));
53
+ }
54
+ else
55
+ {
56
+
57
+ do
58
+ {
59
+ *p++ = static_cast<char_type>(48 + value % 10);
60
+ }
61
+ while ((value /= 10) && (p < last));
62
+ }
63
+ JSONCONS_ASSERT(p != last);
64
+
65
+ std::size_t count = (p - buf);
66
+ if (is_negative)
67
+ {
68
+ result.push_back('-');
69
+ ++count;
70
+ }
71
+ while (--p >= buf)
72
+ {
73
+ result.push_back(*p);
74
+ }
75
+
76
+ return count;
77
+ }
78
+
79
+ // integer_to_string_hex
80
+
81
+ template<class Integer,class Result>
82
+ typename std::enable_if<traits_extension::is_integer<Integer>::value,std::size_t>::type
83
+ integer_to_string_hex(Integer value, Result& result)
84
+ {
85
+ using char_type = typename Result::value_type;
86
+
87
+ char_type buf[255];
88
+ char_type *p = buf;
89
+ const char_type* last = buf+255;
90
+
91
+ bool is_negative = value < 0;
92
+
93
+ if (value < 0)
94
+ {
95
+ do
96
+ {
97
+ *p++ = to_hex_character(0-(value % 16));
98
+ }
99
+ while ((value /= 16) && (p < last));
100
+ }
101
+ else
102
+ {
103
+
104
+ do
105
+ {
106
+ *p++ = to_hex_character(value % 16);
107
+ }
108
+ while ((value /= 16) && (p < last));
109
+ }
110
+ JSONCONS_ASSERT(p != last);
111
+
112
+ std::size_t count = (p - buf);
113
+ if (is_negative)
114
+ {
115
+ result.push_back('-');
116
+ ++count;
117
+ }
118
+ while (--p >= buf)
119
+ {
120
+ result.push_back(*p);
121
+ }
122
+
123
+ return count;
124
+ }
125
+
126
+ // write_double
127
+
128
+ // fast exponent
129
+ template <class Result>
130
+ void fill_exponent(int K, Result& result)
131
+ {
132
+ if (K < 0)
133
+ {
134
+ result.push_back('-');
135
+ K = -K;
136
+ }
137
+ else
138
+ {
139
+ result.push_back('+'); // compatibility with sprintf
140
+ }
141
+
142
+ if (K < 10)
143
+ {
144
+ result.push_back('0'); // compatibility with sprintf
145
+ result.push_back((char)('0' + K));
146
+ }
147
+ else if (K < 100)
148
+ {
149
+ result.push_back((char)('0' + K / 10)); K %= 10;
150
+ result.push_back((char)('0' + K));
151
+ }
152
+ else if (K < 1000)
153
+ {
154
+ result.push_back((char)('0' + K / 100)); K %= 100;
155
+ result.push_back((char)('0' + K / 10)); K %= 10;
156
+ result.push_back((char)('0' + K));
157
+ }
158
+ else
159
+ {
160
+ jsoncons::detail::from_integer(K, result);
161
+ }
162
+ }
163
+
164
+ template <class Result>
165
+ void prettify_string(const char *buffer, std::size_t length, int k, int min_exp, int max_exp, Result& result)
166
+ {
167
+ int nb_digits = (int)length;
168
+ int offset;
169
+ /* v = buffer * 10^k
170
+ kk is such that 10^(kk-1) <= v < 10^kk
171
+ this way kk gives the position of the decimal point.
172
+ */
173
+ int kk = nb_digits + k;
174
+
175
+ if (nb_digits <= kk && kk <= max_exp)
176
+ {
177
+ /* the first digits are already in. Add some 0s and call it a day. */
178
+ /* the max_exp is a personal choice. Only 16 digits could possibly be relevant.
179
+ * Basically we want to print 12340000000 rather than 1234.0e7 or 1.234e10 */
180
+ for (int i = 0; i < nb_digits; ++i)
181
+ {
182
+ result.push_back(buffer[i]);
183
+ }
184
+ for (int i = nb_digits; i < kk; ++i)
185
+ {
186
+ result.push_back('0');
187
+ }
188
+ result.push_back('.');
189
+ result.push_back('0');
190
+ }
191
+ else if (0 < kk && kk <= max_exp)
192
+ {
193
+ /* comma number. Just insert a '.' at the correct location. */
194
+ for (int i = 0; i < kk; ++i)
195
+ {
196
+ result.push_back(buffer[i]);
197
+ }
198
+ result.push_back('.');
199
+ for (int i = kk; i < nb_digits; ++i)
200
+ {
201
+ result.push_back(buffer[i]);
202
+ }
203
+ }
204
+ else if (min_exp < kk && kk <= 0)
205
+ {
206
+ offset = 2 - kk;
207
+
208
+ result.push_back('0');
209
+ result.push_back('.');
210
+ for (int i = 2; i < offset; ++i)
211
+ result.push_back('0');
212
+ for (int i = 0; i < nb_digits; ++i)
213
+ {
214
+ result.push_back(buffer[i]);
215
+ }
216
+ }
217
+ else if (nb_digits == 1)
218
+ {
219
+ result.push_back(buffer[0]);
220
+ result.push_back('e');
221
+ fill_exponent(kk - 1, result);
222
+ }
223
+ else
224
+ {
225
+ result.push_back(buffer[0]);
226
+ result.push_back('.');
227
+ for (int i = 1; i < nb_digits; ++i)
228
+ {
229
+ result.push_back(buffer[i]);
230
+ }
231
+ result.push_back('e');
232
+ fill_exponent(kk - 1, result);
233
+ }
234
+ }
235
+
236
+ template<class Result>
237
+ void dump_buffer(const char *buffer, std::size_t length, char decimal_point, Result& result)
238
+ {
239
+ const char *sbeg = buffer;
240
+ const char *send = sbeg + length;
241
+
242
+ if (sbeg != send)
243
+ {
244
+ bool needs_dot = true;
245
+ for (const char* q = sbeg; q < send; ++q)
246
+ {
247
+ switch (*q)
248
+ {
249
+ case '-':
250
+ case '0':
251
+ case '1':
252
+ case '2':
253
+ case '3':
254
+ case '4':
255
+ case '5':
256
+ case '6':
257
+ case '7':
258
+ case '8':
259
+ case '9':
260
+ case '+':
261
+ result.push_back(*q);
262
+ break;
263
+ case 'e':
264
+ case 'E':
265
+ result.push_back('e');
266
+ needs_dot = false;
267
+ break;
268
+ default:
269
+ if (*q == decimal_point)
270
+ {
271
+ needs_dot = false;
272
+ result.push_back('.');
273
+ }
274
+ break;
275
+ }
276
+ }
277
+ if (needs_dot)
278
+ {
279
+ result.push_back('.');
280
+ result.push_back('0');
281
+ needs_dot = true;
282
+ }
283
+ }
284
+ }
285
+
286
+ template<class Result>
287
+ bool dtoa_scientific(double val, char decimal_point, Result& result)
288
+ {
289
+ if (val == 0)
290
+ {
291
+ result.push_back('0');
292
+ result.push_back('.');
293
+ result.push_back('0');
294
+ return true;
295
+ }
296
+
297
+ jsoncons::detail::chars_to to_double_;
298
+
299
+ char buffer[100];
300
+ int precision = std::numeric_limits<double>::digits10;
301
+ int length = snprintf(buffer, sizeof(buffer), "%1.*e", precision, val);
302
+ if (length < 0)
303
+ {
304
+ return false;
305
+ }
306
+ if (to_double_(buffer, sizeof(buffer)) != val)
307
+ {
308
+ const int precision2 = std::numeric_limits<double>::max_digits10;
309
+ length = snprintf(buffer, sizeof(buffer), "%1.*e", precision2, val);
310
+ if (length < 0)
311
+ {
312
+ return false;
313
+ }
314
+ }
315
+ dump_buffer(buffer, static_cast<std::size_t>(length), decimal_point, result);
316
+ return true;
317
+ }
318
+
319
+ template<class Result>
320
+ bool dtoa_general(double val, char decimal_point, Result& result, std::false_type)
321
+ {
322
+ if (val == 0)
323
+ {
324
+ result.push_back('0');
325
+ result.push_back('.');
326
+ result.push_back('0');
327
+ return true;
328
+ }
329
+
330
+ jsoncons::detail::chars_to to_double_;
331
+
332
+ char buffer[100];
333
+ int precision = std::numeric_limits<double>::digits10;
334
+ int length = snprintf(buffer, sizeof(buffer), "%1.*g", precision, val);
335
+ if (length < 0)
336
+ {
337
+ return false;
338
+ }
339
+ if (to_double_(buffer, sizeof(buffer)) != val)
340
+ {
341
+ const int precision2 = std::numeric_limits<double>::max_digits10;
342
+ length = snprintf(buffer, sizeof(buffer), "%1.*g", precision2, val);
343
+ if (length < 0)
344
+ {
345
+ return false;
346
+ }
347
+ }
348
+ dump_buffer(buffer, length, decimal_point, result);
349
+ return true;
350
+ }
351
+
352
+ template<class Result>
353
+ bool dtoa_general(double v, char decimal_point, Result& result, std::true_type)
354
+ {
355
+ if (v == 0)
356
+ {
357
+ result.push_back('0');
358
+ result.push_back('.');
359
+ result.push_back('0');
360
+ return true;
361
+ }
362
+
363
+ int length = 0;
364
+ int k;
365
+
366
+ char buffer[100];
367
+
368
+ double u = std::signbit(v) ? -v : v;
369
+ if (jsoncons::detail::grisu3(u, buffer, &length, &k))
370
+ {
371
+ if (std::signbit(v))
372
+ {
373
+ result.push_back('-');
374
+ }
375
+ // min exp: -4 is consistent with sprintf
376
+ // max exp: std::numeric_limits<double>::max_digits10
377
+ jsoncons::detail::prettify_string(buffer, length, k, -4, std::numeric_limits<double>::max_digits10, result);
378
+ return true;
379
+ }
380
+ else
381
+ {
382
+ return dtoa_general(v, decimal_point, result, std::false_type());
383
+ }
384
+ }
385
+
386
+ template<class Result>
387
+ bool dtoa_fixed(double val, char decimal_point, Result& result, std::false_type)
388
+ {
389
+ if (val == 0)
390
+ {
391
+ result.push_back('0');
392
+ result.push_back('.');
393
+ result.push_back('0');
394
+ return true;
395
+ }
396
+
397
+ jsoncons::detail::chars_to to_double_;
398
+
399
+ char buffer[100];
400
+ int precision = std::numeric_limits<double>::digits10;
401
+ int length = snprintf(buffer, sizeof(buffer), "%1.*f", precision, val);
402
+ if (length < 0)
403
+ {
404
+ return false;
405
+ }
406
+ if (to_double_(buffer, sizeof(buffer)) != val)
407
+ {
408
+ const int precision2 = std::numeric_limits<double>::max_digits10;
409
+ length = snprintf(buffer, sizeof(buffer), "%1.*f", precision2, val);
410
+ if (length < 0)
411
+ {
412
+ return false;
413
+ }
414
+ }
415
+ dump_buffer(buffer, length, decimal_point, result);
416
+ return true;
417
+ }
418
+
419
+ template<class Result>
420
+ bool dtoa_fixed(double v, char decimal_point, Result& result, std::true_type)
421
+ {
422
+ if (v == 0)
423
+ {
424
+ result.push_back('0');
425
+ result.push_back('.');
426
+ result.push_back('0');
427
+ return true;
428
+ }
429
+
430
+ int length = 0;
431
+ int k;
432
+
433
+ char buffer[100];
434
+
435
+ double u = std::signbit(v) ? -v : v;
436
+ if (jsoncons::detail::grisu3(u, buffer, &length, &k))
437
+ {
438
+ if (std::signbit(v))
439
+ {
440
+ result.push_back('-');
441
+ }
442
+ jsoncons::detail::prettify_string(buffer, length, k, std::numeric_limits<int>::lowest(), (std::numeric_limits<int>::max)(), result);
443
+ return true;
444
+ }
445
+ else
446
+ {
447
+ return dtoa_fixed(v, decimal_point, result, std::false_type());
448
+ }
449
+ }
450
+
451
+ template<class Result>
452
+ bool dtoa_fixed(double v, char decimal_point, Result& result)
453
+ {
454
+ return dtoa_fixed(v, decimal_point, result, std::integral_constant<bool, std::numeric_limits<double>::is_iec559>());
455
+ }
456
+
457
+ template<class Result>
458
+ bool dtoa_general(double v, char decimal_point, Result& result)
459
+ {
460
+ return dtoa_general(v, decimal_point, result, std::integral_constant<bool, std::numeric_limits<double>::is_iec559>());
461
+ }
462
+
463
+ class write_double
464
+ {
465
+ private:
466
+ chars_to to_double_;
467
+ float_chars_format float_format_;
468
+ int precision_;
469
+ char decimal_point_;
470
+ public:
471
+ write_double(float_chars_format float_format, int precision)
472
+ : float_format_(float_format), precision_(precision), decimal_point_('.')
473
+ {
474
+ #if !defined(JSONCONS_NO_LOCALECONV)
475
+ struct lconv *lc = localeconv();
476
+ if (lc != nullptr && lc->decimal_point[0] != 0)
477
+ {
478
+ decimal_point_ = lc->decimal_point[0];
479
+ }
480
+ #endif
481
+ }
482
+ write_double(const write_double&) = default;
483
+
484
+ write_double& operator=(const write_double&) = default;
485
+
486
+ template<class Result>
487
+ std::size_t operator()(double val, Result& result)
488
+ {
489
+ std::size_t count = 0;
490
+
491
+ char number_buffer[200];
492
+ int length = 0;
493
+
494
+ switch (float_format_)
495
+ {
496
+ case float_chars_format::fixed:
497
+ {
498
+ if (precision_ > 0)
499
+ {
500
+ length = snprintf(number_buffer, sizeof(number_buffer), "%1.*f", precision_, val);
501
+ if (length < 0)
502
+ {
503
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
504
+ }
505
+ dump_buffer(number_buffer, length, decimal_point_, result);
506
+ }
507
+ else
508
+ {
509
+ if (!dtoa_fixed(val, decimal_point_, result))
510
+ {
511
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
512
+ }
513
+ }
514
+ }
515
+ break;
516
+ case float_chars_format::scientific:
517
+ {
518
+ if (precision_ > 0)
519
+ {
520
+ length = snprintf(number_buffer, sizeof(number_buffer), "%1.*e", precision_, val);
521
+ if (length < 0)
522
+ {
523
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
524
+ }
525
+ dump_buffer(number_buffer, length, decimal_point_, result);
526
+ }
527
+ else
528
+ {
529
+ if (!dtoa_scientific(val, decimal_point_, result))
530
+ {
531
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
532
+ }
533
+ }
534
+ }
535
+ break;
536
+ case float_chars_format::general:
537
+ {
538
+ if (precision_ > 0)
539
+ {
540
+ length = snprintf(number_buffer, sizeof(number_buffer), "%1.*g", precision_, val);
541
+ if (length < 0)
542
+ {
543
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
544
+ }
545
+ dump_buffer(number_buffer, length, decimal_point_, result);
546
+ }
547
+ else
548
+ {
549
+ if (!dtoa_general(val, decimal_point_, result))
550
+ {
551
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
552
+ }
553
+ }
554
+ break;
555
+ }
556
+ default:
557
+ JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
558
+ break;
559
+ }
560
+ return count;
561
+ }
562
+ };
563
+
564
+ } // namespace detail
565
+ } // namespace jsoncons
566
+
567
+ #endif