Adobe Source Libraries 2.0.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
json.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef ADOBE_JSON_HPP
9#define ADOBE_JSON_HPP
10
11#include <cfloat>
12#include <cmath>
13#include <cstddef>
14#include <cstdint>
15#include <stdexcept>
16#include <string>
17#include <vector>
18
19#include <adobe/cassert.hpp>
21
22/**************************************************************************************************/
26namespace adobe {
27
28/**************************************************************************************************/
48template <typename T>
50 constexpr static double kNaN = std::numeric_limits<double>::quiet_NaN();
51
52public:
53 typedef typename T::object_type object_type;
54 typedef typename T::array_type array_type;
55 typedef typename T::value_type value_type;
56 typedef typename T::string_type string_type;
57 typedef typename T::key_type key_type;
58
59 /*
60 We want both empty and error values to be infinity as it will be an invalid
61 JSON value and is something we can check against to assert validity. We also
62 allow 'junk' as it is the end of this token and on to the next one.
63 */
64 explicit json_parser(const char* p)
65 : p_(p) {}
66
68 value_type result;
69 require(is_object(result) || is_array(result), "object or array");
70 return result;
71 }
72
73private:
74 bool is_object(value_type& t) {
75 if (!is_structural_char('{'))
76 return false;
79 if (is_string(string)) {
80 require(is_structural_char(':'), ":");
81 value_type value;
82 require(is_value(value), "value");
83 T::move_append(object, string, value);
84
85 while (is_structural_char(',')) {
86 require(is_string(string), "string");
87 require(is_structural_char(':'), ":");
88 require(is_value(value), "value");
89 T::move_append(object, string, value);
90 }
91 }
92 require(is_structural_char('}'), "}");
93 t = value_type(std::move(object));
94 return true;
95 }
96
97 bool is_array(value_type& t) {
98 if (!is_structural_char('['))
99 return false;
101 value_type value;
102 if (is_value(value)) {
103 T::move_append(array, value);
104 while (is_structural_char(',')) {
105 require(is_value(value), "value");
106 T::move_append(array, value);
107 }
108 }
109 require(is_structural_char(']'), "]");
110 t = value_type(std::move(array));
111 return true;
112 }
113
114 // REVISIT (sparent) : should use peek to avoid steping in/out of multiple functions.
115
116 bool is_value(value_type& t) {
117 return is_string(t) || is_number(t) || is_object(t) || is_array(t) || is_bool(t) ||
118 is_null(t);
119 }
120
121 // requires at least one character
122
123 bool is_sequence(const char* p) {
124 if (!is_char(*p))
125 return false;
126 ++p;
127 while (is_char(*p))
128 ++p;
129 require(*p == 0, "valid constant");
130 return true;
131 }
132
133 bool is_bool(value_type& t) {
134 if (is_sequence("true")) {
135 t = value_type(true);
136 return true;
137 }
138 if (is_sequence("false")) {
139 t = value_type(false);
140 return true;
141 }
142 return false;
143 }
144
145 bool is_null(value_type& t) {
146 if (!is_sequence("null"))
147 return false;
148 t = value_type();
149 return true;
150 }
151
152 template <typename S> // S is string_type or key_type
153 bool is_string(S& s) {
154 if (!is_char('"'))
155 return false;
156 while (!is_char('"')) {
157 const char* f = p_;
158 while (!('\x00' <= *p_ && *p_ < '\x20') && *p_ != '"' && *p_ != '\\')
159 ++p_;
160 require(!('\x00' <= *p_ && *p_ < '\x20'), "valid character");
161 T::append(s, f, p_);
162 if (!is_char('\\'))
163 continue;
164 char c = escape()[static_cast<unsigned char>(*p_++)];
165 require(c, "valid escape character");
166 if (c == 'u') {
167 std::uint32_t utf = get_four_digits();
168 // handle surrogate leading
169 if (0xD800 <= utf && utf <= 0xDBFF) {
170 require(is_char('u'), "trail surrogate");
171 std::uint32_t trailing = get_four_digits();
172 require(0xDC00 <= trailing && trailing <= 0xDFFF, "trail surrogate");
173 utf = ((utf - 0xD800) << 10) + (trailing - 0xDC00);
174 }
175 char buffer[4];
176 auto end = utf8(utf, buffer);
177 T::append(s, buffer, end);
178 } else
179 T::append(s, &c, &c + 1);
180 }
181 return true;
182 }
183
184 bool is_string(value_type& t) {
186 bool result = is_string(string);
187 if (result)
188 t = value_type(std::move(string));
189 return result;
190 }
191
192 bool is_number(value_type& t) {
193 const char* p = p_;
194 bool neg = is_char('-');
195 if (!is_int()) {
196 require(!neg, "digit");
197 return false;
198 }
199 frac();
200 exp();
201
202 char* p_end = nullptr;
203 double value = std::strtod(p, &p_end);
204 require(std::isfinite(value), "finite number");
205 ADOBE_ASSERT((p_ - p) == (p_end - p) && "std::strtod() failure");
206
207 t = value_type(value);
208
209 return true;
210 }
211
212 void frac() {
213 if (!is_char('.'))
214 return;
215 require(is_digit(), "digit");
216
217 while (is_digit())
218 ;
219 }
220
221 void exp() {
222 if (!is_char('e') && !is_char('E'))
223 return;
224 is_char('-') || is_char('+');
225 require(is_digit(), "exponent digit");
226 while (is_digit())
227 ;
228 }
229
230 bool is_digit() {
231 if (!('0' <= *p_ && *p_ <= '9'))
232 return false;
233 ++p_;
234 return true;
235 }
236
237 bool is_int() {
238 if (is_char('0'))
239 return true;
240 if (!is_digit())
241 return false;
242 while (is_digit())
243 ;
244 return true;
245 }
246
247 std::uint32_t get_four_digits() {
248 std::uint32_t result;
249 char digit = hex_digit()[static_cast<unsigned char>(*p_++)];
250 if (digit == '\xFF')
251 goto fail;
252 result = digit * 0x1000;
253 digit = hex_digit()[static_cast<unsigned char>(*p_++)];
254 if (digit == '\xFF')
255 goto fail;
256 result += digit * 0x0100;
257 digit = hex_digit()[static_cast<unsigned char>(*p_++)];
258 if (digit == '\xFF')
259 goto fail;
260 result += digit * 0x0010;
261 digit = hex_digit()[static_cast<unsigned char>(*p_++)];
262 if (digit == '\xFF')
263 goto fail;
264 result += digit;
265 return result;
266 fail:
267 require(false, "four hex digits");
268 return 0;
269 }
270
275 void require(bool x, const char* failure) {
276 using namespace std;
277
278 if (!x)
279 throw logic_error(failure + string(" is required"));
280 }
281
283 void skip_white_space() {
284 while (ws()[static_cast<unsigned char>(*p_)]) {
285 ++p_;
286 }
287 }
288
289 bool is_char(char x) {
290 if (*p_ != x)
291 return false;
292 ++p_;
293 return true;
294 }
295
296 bool is_structural_char(char x) {
297 skip_white_space();
298 if (!is_char(x))
299 return false;
300 skip_white_space();
301 return true;
302 }
303
305 char* utf8(std::uint32_t x, char* f) {
306 // Should assert non-surrogate
307 std::size_t bytes_to_write(0);
308
309 if (x < 0x80)
310 bytes_to_write = 1;
311 else if (x < 0x800)
312 bytes_to_write = 2;
313 else if (x < 0x10000)
314 bytes_to_write = 3;
315 else if (x < 0x0010FFFF)
316 bytes_to_write = 4;
317 else
318 require(false, "valid utf-32 character");
319
320 const std::uint32_t mark = 0x80;
321 const std::uint32_t mask = 0xBF;
322
323 static const unsigned char first_mark[] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
324
325 f += bytes_to_write;
326
327 switch (bytes_to_write) { /* note: everything falls through. */
328 case 4:
329 *--f = static_cast<char>((x | mark) & mask);
330 x >>= 6;
331 case 3:
332 *--f = static_cast<char>((x | mark) & mask);
333 x >>= 6;
334 case 2:
335 *--f = static_cast<char>((x | mark) & mask);
336 x >>= 6;
337 case 1:
338 *--f = static_cast<char>(x | first_mark[bytes_to_write]);
339 }
340
341 return f + bytes_to_write;
342 }
343
344 const char* p_;
345
346 typedef char table_t_[256];
347
348 static const table_t_& hex_digit() {
349 static const char hex_digit_[] = {
350 /* 0 1 2 3 4 5 6 7 8 9 A
351 B C D E F */
352 /* 0 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
353 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
354 /* 1 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
355 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
356 /* 2 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
357 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
358 /* 3 */ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
359 '\x08', '\x09', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
360 /* 4 */ '\xFF', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\xFF',
361 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
362 /* 5 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
363 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
364 /* 6 */ '\xFF', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\xFF',
365 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
366 /* 7 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
367 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
368 /* 8 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
369 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
370 /* 9 */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
371 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
372 /* A */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
373 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
374 /* B */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
375 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
376 /* C */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
377 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
378 /* D */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
379 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
380 /* E */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
381 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
382 /* F */ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
383 '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
384 return hex_digit_;
385 }
386
387 static const table_t_& escape() {
388 static const char escape_[] = {
389 /* 0 1 2 3 4 5 6 7 8 9 A
390 B C D E F */
391 /* 0 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
392 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
393 /* 1 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
394 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
395 /* 2 */ '\x00', '\x00', '\x22', '\x00', '\x00', '\x00', '\x00', '\x00',
396 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x2F',
397 /* 3 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
398 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
399 /* 4 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
400 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
401 /* 5 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
402 '\x00', '\x00', '\x00', '\x00', '\x5C', '\x00', '\x00', '\x00',
403 /* 6 */ '\x00', '\x00', '\x08', '\x00', '\x00', '\x00', '\x0C', '\x00',
404 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0A', '\x00',
405 /* 7 */ '\x00', '\x00', '\x0D', '\x00', '\x09', '\x75', '\x00', '\x00',
406 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
407 /* 8 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
408 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
409 /* 9 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
410 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
411 /* A */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
412 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
413 /* B */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
414 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
415 /* C */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
416 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
417 /* D */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
418 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
419 /* E */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
420 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
421 /* F */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
422 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
423 return escape_;
424 }
425
426 static const table_t_& ws() {
427 static const char ws_[] = {
428 /* 0 1 2 3 4 5 6 7 8 9 A
429 B C D E F */
430 /* 0 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
431 '\x00', '\x01', '\x01', '\x00', '\x00', '\x01', '\x00', '\x00',
432 /* 1 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
433 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
434 /* 2 */ '\x01', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
435 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
436 /* 3 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
437 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
438 /* 4 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
439 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
440 /* 5 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
441 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
442 /* 6 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
443 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
444 /* 7 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
445 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
446 /* 8 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
447 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
448 /* 9 */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
449 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
450 /* A */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
451 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
452 /* B */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
453 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
454 /* C */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
455 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
456 /* D */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
457 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
458 /* E */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
459 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
460 /* F */ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
461 '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
462 return ws_;
463 }
464};
465
466/**************************************************************************************************/
467
469
470/**************************************************************************************************/
480template <typename T, typename O>
482public:
483 typedef typename T::object_type object_type;
484 typedef typename T::pair_type pair_type; // type returned for *begin(object_type)
485 typedef typename T::array_type array_type;
486 typedef typename T::value_type value_type;
487 typedef typename T::string_type string_type;
488 typedef typename T::key_type key_type;
489
490 json_generator(O out) : out_(out){};
491
492 O generate(const value_type& value, std::size_t indent = 0) {
493 switch (T::type(value)) {
495 case json_type::array:
496 generate_(value, indent);
497 break;
498 default:
499 require(false, "object or array");
500 }
501 return out_;
502 }
503
504private:
505 void require(bool x, const char* message) {
506 if (!x)
507 throw std::logic_error(message);
508 }
509
510 void generate_(const value_type& value, std::size_t indent) {
511 switch (T::type(value)) {
513 generate_(as<object_type>(value), indent);
514 break;
515 case json_type::array:
516 generate_(as<array_type>(value), indent);
517 break;
519 generate_string(as<string_type>(value));
520 break;
522 generate_(as<double>(value));
523 break;
525 generate_(as<bool>(value));
526 break;
527 case json_type::null:
528 generate_();
529 break;
530 default:
531 require(false, "valid type");
532 break;
533 }
534 }
535
536 void generate_() {
537 static const char null_[] = "null";
538 out_ = std::copy(std::begin(null_), std::end(null_) - 1, out_);
539 }
540
541 void generate_(bool x) {
542 static const char true_[] = "true";
543 static const char false_[] = "false";
544 if (x)
545 out_ = std::copy(std::begin(true_), std::end(true_) - 1, out_);
546 else
547 out_ = std::copy(std::begin(false_), std::end(false_) - 1, out_);
548 }
549
550 void generate_(double x) {
551 require(!std::isnan(x) && !std::isinf(x), "valid double");
552 out_ = adobe::to_string(x, out_);
553 }
554
555 template <typename U>
556 static const U& as(const value_type& x) {
557 return T::template as<U>(x);
558 }
559
560 void indent(std::size_t n) {
561 for (std::size_t n_ = 0; n_ != n; ++n_)
562 *out_++ = '\t';
563 }
564 void space() { *out_++ = ' '; }
565 void endl() { *out_++ = '\n'; }
566
567 template <typename S>
568 void generate_string(const S& x) {
569 static const char hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
570 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
571
572 *out_++ = '"';
573 // REVISIT (sparent) : do escape handling here
574 for (const auto& e : x) {
575 if (('\x00' <= e && e <= '\x1F') || e == '"' || e == '\\') {
576 *out_++ = '\\';
577 switch (e) {
578 case '"':
579 *out_++ = '"';
580 break;
581 case '\\':
582 *out_++ = '\\';
583 break;
584 case '\b':
585 *out_++ = 'b';
586 break;
587 case '\f':
588 *out_++ = 'f';
589 break;
590 case '\n':
591 *out_++ = 'n';
592 break;
593 case '\r':
594 *out_++ = 'r';
595 break;
596 case '\t':
597 *out_++ = 't';
598 break;
599 default:
600 *out_++ = 'u';
601 *out_++ = '0';
602 *out_++ = '0';
603 *out_++ = hex_digits[static_cast<unsigned char>((e >> 4) & '\x0F')];
604 *out_++ = hex_digits[static_cast<unsigned char>(e & '\x0F')];
605 break;
606 }
607 } else
608 *out_++ = e;
609 }
610 *out_++ = '"';
611 }
612
613 void generate_(const pair_type& value, std::size_t n) {
614 generate_string(value.first);
615 *out_++ = ':';
616 space();
617 generate_(value.second, n);
618 }
619
620 template <typename I> // I models forward iterator
621 bool list(I f, I l, std::size_t n) {
622 if (f == l)
623 return false;
624 I next = f;
625 ++next;
626
627 bool is_one = next == l;
628
629 if (is_one) {
630 space();
631 } else {
632 endl();
633 n += 1;
634 indent(n);
635 }
636
637 generate_(*f, n);
638
639 if (is_one) {
640 return false;
641 }
642
643 f = next;
644 while (f != l) {
645 *out_++ = ',';
646 endl();
647 indent(n);
648 generate_(*f, n);
649 ++f;
650 }
651 endl();
652 return true;
653 }
654
655 void generate_(const object_type& value, std::size_t n) {
656 *out_++ = '{';
657 if (list(std::begin(value), std::end(value), n))
658 indent(n);
659 else
660 space();
661 *out_++ = '}';
662 }
663
664 void generate_(const array_type& value, std::size_t n) {
665 *out_++ = '[';
666 if (list(std::begin(value), std::end(value), n))
667 indent(n);
668 else
669 space();
670 *out_++ = ']';
671 }
672
673 O out_;
674};
675
676/**************************************************************************************************/
677
678} // namespace adobe
679
680/**************************************************************************************************/
681// ADOBE_JSON_HPP
682#endif
683
684/**************************************************************************************************/
#define ADOBE_ASSERT(p)
Definition cassert.hpp:32
T::key_type key_type
Definition json.hpp:488
T::pair_type pair_type
Definition json.hpp:484
T::value_type value_type
Definition json.hpp:486
T::array_type array_type
Definition json.hpp:485
T::string_type string_type
Definition json.hpp:487
O generate(const value_type &value, std::size_t indent=0)
Definition json.hpp:492
T::object_type object_type
Definition json.hpp:483
json_parser(const char *p)
Definition json.hpp:64
T::key_type key_type
Definition json.hpp:57
T::value_type value_type
Definition json.hpp:55
T::array_type array_type
Definition json.hpp:54
T::string_type string_type
Definition json.hpp:56
T::object_type object_type
Definition json.hpp:53
value_type parse()
Definition json.hpp:67
O to_string(double x, O out, bool precise=false)
Convert double precision floating point numbers to ascii representation.
Definition to_string.hpp:86
json_type
Definition json.hpp:468