Guitar
jstream.h
Go to the documentation of this file.
1 // Jstream - Header-only Streaming pull-based JSON Parser and Generator
2 // Copyright (C) 2026 S.Fuchita (soramimi)
3 // This software is distributed under the MIT license.
4 
5 #ifndef JSTREAM_H_
6 #define JSTREAM_H_
7 
8 #include <assert.h>
9 #include <charconv>
10 #include <cmath>
11 #include <cstddef>
12 #include <cstdint>
13 #include <cstring>
14 #include <functional>
15 #include <string>
16 #include <string_view>
17 #include <variant>
18 #include <vector>
19 
20 namespace jstream {
21 
22 static inline std::vector<char> encode_json_string(std::string_view const &in)
23 {
24  std::vector<char> ret;
25  char const *ptr = in.data();
26  char const *end = ptr + in.size();
27  ret.reserve(end - ptr + 10);
28  while (ptr < end) {
29  int c = (unsigned char)*ptr;
30  char const *next = ptr + 1;
31  switch (c) {
32  case '\"': ret.push_back('\\'); ret.push_back('\"'); break;
33  case '\\': ret.push_back('\\'); ret.push_back('\\'); break;
34  case '\b': ret.push_back('\\'); ret.push_back('b'); break;
35  case '\f': ret.push_back('\\'); ret.push_back('f'); break;
36  case '\n': ret.push_back('\\'); ret.push_back('n'); break;
37  case '\r': ret.push_back('\\'); ret.push_back('r'); break;
38  case '\t': ret.push_back('\\'); ret.push_back('t'); break;
39  default:
40  if (c >= 0x20 && c < 0x7f) {
41  ret.push_back(c);
42  } else {
43  int utf8len = 0;
44  uint32_t unicode = 0;
45  if ((c & 0xe0) == 0xc0 && next < end) {
46  if ((next[0] & 0xc0) == 0x80) {
47  int d = (unsigned char)next[0];
48  unicode = ((c & 0x1f) << 6) | (d & 0x3f);
49  utf8len = 2;
50  }
51  } else if ((c & 0xf0) == 0xe0 && next + 1 < end) {
52  if ((next[0] & 0xc0) == 0x80 && (next[1] & 0xc0) == 0x80) {
53  int d = (unsigned char)next[0];
54  int e = (unsigned char)next[1];
55  unicode = ((c & 0x0f) << 12) | ((d & 0x3f) << 6) | (e & 0x3f);
56  utf8len = 3;
57  }
58  } else if ((c & 0xf8) == 0xf0 && next + 2 < end) {
59  if ((next[0] & 0xc0) == 0x80 && (next[1] & 0xc0) == 0x80 && (next[2] & 0xc0) == 0x80) {
60  int d = (unsigned char)next[0];
61  int e = (unsigned char)next[1];
62  int f = (unsigned char)next[2];
63  unicode = ((c & 0x0f) << 18) | ((d & 0x3f) << 12) | ((e & 0x3f) << 6) | (f & 0x3f);
64  utf8len = 4;
65  }
66  }
67  if (unicode != 0) {
68  if (1) {
69  next = ptr + utf8len;
70  ret.insert(ret.end(), ptr, next);
71  } else {
72  char tmp[20];
73  if (unicode >= 0x10000 && unicode < 0x110000) {
74  uint16_t h = (unicode - 0x10000) / 0x400 + 0xd800;
75  uint16_t l = (unicode - 0x10000) % 0x400 + 0xdc00;
76  sprintf(tmp, "\\u%04X\\u%04X", h, l);
77  ret.insert(ret.end(), tmp, tmp + 12);
78  } else {
79  sprintf(tmp, "\\u%04X", unicode);
80  ret.insert(ret.end(), tmp, tmp + 6);
81  }
82  }
83  }
84  }
85  }
86  ptr = next;
87  }
88  return ret;
89 }
90 
91 class misc {
92 private:
103  static double pow10_int(int exp)
104  {
105  // Pre‑computed powers for |exp| ≤ 16
106  static const double tbl[] = {
107  1e+00, 1e+01, 1e+02, 1e+03, 1e+04, 1e+05, 1e+06,
108  1e+07, 1e+08, 1e+09, 1e+10, 1e+11, 1e+12, 1e+13,
109  1e+14, 1e+15, 1e+16
110  };
111  if (exp >= 0 && exp < static_cast<int>(sizeof tbl / sizeof *tbl))
112  return tbl[exp];
113  if (exp <= 0 && exp > -static_cast<int>(sizeof tbl / sizeof *tbl))
114  return 1.0 / tbl[-exp];
115  // Rare case: delegate to libm
116  return std::pow(10.0, exp);
117  }
118 public:
134  static double my_strtod(const char *nptr, char **endptr)
135  {
136  const char *s = nptr;
137  bool sign = false;
138  bool saw_digit = false;
139  int frac_digits = 0;
140  long exp_val = 0;
141  bool exp_sign = false;
142  double value = 0.0;
143 
144  // Skip leading white‑space
145  while (std::isspace((unsigned char)*s)) ++s;
146 
147  // Parse optional sign
148  if (*s == '+' || *s == '-') {
149  if (*s == '-') sign = true;
150  s++;
151  }
152 
153  // Integer part
154  while (std::isdigit((unsigned char)*s)) {
155  saw_digit = true;
156  value = value * 10.0 + (*s - '0');
157  s++;
158  }
159 
160  // Fractional part
161  if (*s == '.') {
162  s++;
163  while (std::isdigit((unsigned char)*s)) {
164  saw_digit = true;
165  value = value * 10.0 + (*s - '0');
166  s++;
167  frac_digits++;
168  }
169  }
170 
171  // No digits at all -> conversion failure
172  if (!saw_digit) {
173  if (endptr) *endptr = const_cast<char *>(nptr);
174  return 0.0;
175  }
176 
177  // Exponent part
178  if (*s == 'e' || *s == 'E') {
179  s++;
180  const char *exp_start = s;
181  if (*s == '+' || *s == '-') {
182  if (*s == '-') exp_sign = true;
183  s++;
184  }
185  if (std::isdigit((unsigned char)*s)) {
186  while (std::isdigit((unsigned char)*s)) {
187  exp_val = exp_val * 10 + (*s - '0');
188  s++;
189  }
190  if (exp_sign) {
191  exp_val = -exp_val;
192  }
193  } else {
194  // Roll back if 'e' is not followed by a valid exponent
195  s = exp_start - 1;
196  }
197  }
198 
199  // Scale by 10^(exponent − #fractional‑digits)
200  int total_exp = exp_val - frac_digits;
201  if (total_exp != 0) {
202  value *= pow10_int(total_exp);
203  }
204 
205  // Apply sign
206  if (sign) {
207  value = -value;
208  }
209 
210  // Set errno on overflow/underflow
211  if (!std::isfinite(value)) {
212  // errno = ERANGE;
213  value = sign ? -HUGE_VAL : HUGE_VAL;
214  } else if (value == 0.0 && saw_digit && total_exp != 0) {
215  // errno = ERANGE; // underflow
216  }
217 
218  // Report where parsing stopped
219  if (endptr) *endptr = const_cast<char *>(s);
220  return value;
221  }
222 
223 #if 0
224  static std::string format_double(double val, bool allow_nan)
225  {
226  int precision = 15;
227  bool trim_zeros = true;
228  bool plus = false;
229 
230  if (std::isnan(val)) {
231  if (allow_nan) {
232  return "NaN";
233  }
234  return {};
235  }
236  if (std::isinf(val)) {
237  if (allow_nan) {
238  bool sign = std::signbit(val);
239  if (sign) {
240  return "-Infinity";
241  } else {
242  return "Infinity";
243  }
244  }
245  return {};
246  }
247 
248  char *ptr, *end;
249 
250  char *dot = nullptr;
251 
252  bool sign = val < 0;
253  if (sign) {
254  val = -val;
255  }
256 
257  double intval = floor(val);
258  val -= intval;
259 
260  int intlen = 0;
261  if (intval == 0) {
262  ptr = end = (char *)alloca(precision + 10) + 5;
263  } else {
264  double t = intval;
265  do {
266  t = floor(t / 10);
267  intlen++;
268  } while (t != 0);
269  ptr = end = (char *)alloca(intlen + precision + 10) + intlen + 5;
270  }
271 
272  if (precision > 0) {
273  dot = end;
274  *end++ = '.';
275  double v = val;
276  int e = 0;
277  while (v > 0 && v < 1) {
278  v *= 10;
279  e++;
280  }
281  while (v >= 1) {
282  v /= 10;
283  e--;
284  }
285  double add = 0.5;
286  for (int i = 0; i < precision - e; i++) {
287  add /= 10;
288  }
289  v += add;
290  double t = floor(v);
291  intval += t;
292  v -= t;
293  int i = 0;
294  int n = intlen;
295  int r = std::min(e, precision);
296  while (i < r) {
297  *end++ = '0';
298  if (n != 0) {
299  n++;
300  }
301  i++;
302  }
303  while (i < precision) {
304  if (n < 16) {
305  v *= 10;
306  double m = floor(v);
307  v -= m;
308  *end++ = (char)m + '0';
309  } else {
310  *end++ = '0';
311  }
312  n++;
313  i++;
314  }
315  } else {
316  intval += floor(val + 0.5);
317  }
318 
319  intlen = 0;
320  double t = intval;
321  do {
322  t = floor(t / 10);
323  intlen++;
324  } while (t != 0);
325 
326  if (intval == 0) {
327  *--ptr = '0';
328  } else {
329  double t = intval;
330  for (int i = 0; i < intlen; i++) {
331  t /= 10;
332  double u = floor(t);
333  *--ptr = (char)((t - u) * 10 + 0.49) + '0';
334  t = u;
335  }
336  }
337 
338  if (sign) {
339  *--ptr = '-';
340  } else if (plus) {
341  *--ptr = '+';
342  }
343 
344  if (trim_zeros && dot) {
345  while (dot < end) {
346  char c = end[-1];
347  if (c == '.') {
348  end--;
349  break;
350  }
351  if (c != '0') {
352  break;
353  }
354  end--;
355  }
356  }
357 
358  return std::string(ptr, end - ptr);
359  }
360 #endif
361  static std::string format_double(double val, bool allow_nan)
362  {
363  if (std::isnan(val)) {
364  if (allow_nan) {
365  return "NaN";
366  }
367  return {};
368  }
369  if (std::isinf(val)) {
370  if (allow_nan) {
371  return std::signbit(val) ? "-Infinity" : "Infinity";
372  }
373  return {};
374  }
375 
376  // std::to_chars produces the shortest round-trip representation without locale dependency
377  char buf[32];
378  auto [ptr, ec] = std::to_chars(buf, buf + sizeof(buf), val);
379  if (ec != std::errc{}) {
380  return {};
381  }
382  return std::string(buf, ptr);
383  }
384 };
385 
386 enum StateType {
387  // Symbols
388  None = 0,
392  // States
393  Key = 100,
401 };
402 
403 class Reader {
404 public:
405  struct Error {
406  std::string what_;
407  std::string what() const { return what_; }
408  };
409 private:
410  static std::string to_stdstr(std::vector<char> const &vec)
411  {
412  if (!vec.empty()) {
413  char const *begin = &vec[0];
414  char const *end = begin + vec.size();
415  return std::string(begin, end);
416  }
417  return std::string();
418  }
419 
420  int scan_space(char const *begin, char const *end)
421  {
422  char const *ptr = begin;
423  while (ptr < end) {
424  if (std::isspace((unsigned char)*ptr)) {
425  ptr++;
426  continue;
427  }
428  if (d.allow_comment && *ptr == '/' && ptr + 1 < end) {
429  if (ptr[1] == '/') {
430  ptr += 2;
431  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
432  ptr++;
433  }
434  continue;
435  }
436  if (ptr[1] == '*') {
437  ptr += 2;
438  while (ptr + 1 < end) {
439  if (*ptr == '*' && ptr[1] == '/') {
440  ptr += 2;
441  break;
442  }
443  ptr++;
444  }
445  continue;
446  }
447  }
448  break;
449  }
450  return int(ptr - begin);
451  }
452 
453  int parse_symbol(char const *begin, char const *end, std::string *out)
454  {
455  char const *ptr = begin;
456  ptr += scan_space(ptr, end);
457  std::vector<char> vec;
458  while (ptr < end) {
459  if (!isalnum((unsigned char)*ptr) && *ptr != '_') break;
460  vec.push_back(*ptr);
461  ptr++;
462  }
463  if (ptr > begin && !vec.empty()) {
464  *out = to_stdstr(vec);
465  return int(ptr - begin);
466  }
467  out->clear();
468  return 0;
469  }
470 
471  int parse_number(char const *begin, char const *end, double *out)
472  {
473  *out = 0;
474  char const *ptr = begin;
475  ptr += scan_space(ptr, end);
476 
477  std::vector<char> vec;
478 
479  if (d.allow_hexadicimal) {
480  char const *p = ptr;
481  bool sign = false;
482  if (p + 1 < end && *p == '-') {
483  p++;
484  sign = true;
485  }
486  if (p + 1 < end && *p == '0' && (p[1] == 'x' || p[1] == 'X')) {
487  p += 2;
488  while (p < end && isxdigit((unsigned char)*p)) {
489  vec.push_back(*p);
490  p++;
491  }
492  vec.push_back(0);
493  long long v = strtoll(vec.data(), nullptr, 16);
494  *out = double(sign ? -v : v);
495  return int(p - begin);
496  }
497  }
498 
500  char const *p = ptr;
501  bool sign = false;
502  if (p < end && *p == '-') {
503  p++;
504  sign = true;
505  }
506  while (p < end && isalpha((unsigned char)*p)) {
507  vec.push_back(*p);
508  p++;
509  }
510  vec.push_back(0);
511  if (strcmp(vec.data(), "Infinity") == 0) {
512  ptr = p;
513  *out = sign ? -INFINITY : INFINITY;
514  } else if (strcmp(vec.data(), "NaN") == 0) {
515  ptr = p;
516  *out = NAN;
517  }
518  if (ptr > begin) {
519  return int(ptr - begin);
520  }
521  }
522 
523  while (ptr < end) {
524  char c = *ptr;
525  if (isdigit((unsigned char)c) || c == '.' || c == '+' || c == '-' || c == 'e' || c == 'E') {
526  // thru
527  } else {
528  break;
529  }
530  vec.push_back(c);
531  ptr++;
532  }
533  vec.push_back(0);
534 
535  // use my_strtod instead of strtod, because strtod is locale dependent
536  // *out = strtod(vec.data(), nullptr);
537  // std::from_chars(vec.data(), vec.data() + vec.size(), *out); // C++17
538  *out = misc::my_strtod(vec.data(), nullptr);
539 
540  return int(ptr - begin);
541  }
542 
543  int parse_string(char const *begin, char const *end, std::string *out)
544  {
545  char const *ptr = begin;
546  ptr += scan_space(ptr, end);
547  if (*ptr == '\"') {
548  ptr++;
549  std::vector<char> vec;
550  while (ptr < end) {
551  if (*ptr == '\"') {
552  *out = to_stdstr(vec);
553  ptr++;
554  return int(ptr - begin);
555  } else if (*ptr == '\\') {
556  ptr++;
557  if (ptr < end) {
558  auto push = [&](char c){ vec.push_back(c); ptr++;};
559  switch (*ptr) {
560  case 'b': push('\b'); break;
561  case 'n': push('\n'); break;
562  case 'r': push('\r'); break;
563  case 'f': push('\f'); break;
564  case 't': push('\t'); break;
565  case 'v': push('\v'); break;
566  case '\\':
567  case '\"':
568  push(*ptr);
569  break;
570  case 'u':
571  ptr++;
572  if (ptr + 3 < end) {
573  char tmp[5];
574  tmp[0] = ptr[0];
575  tmp[1] = ptr[1];
576  tmp[2] = ptr[2];
577  tmp[3] = ptr[3];
578  tmp[4] = 0;
579  ptr += 4;
580  uint32_t unicode = (uint32_t)strtol(tmp, nullptr, 16);
581  if (unicode >= 0xd800 && unicode < 0xdc00) {
582  if (ptr + 5 < end && ptr[0] == '\\' && ptr[1] == 'u') {
583  tmp[0] = ptr[2];
584  tmp[1] = ptr[3];
585  tmp[2] = ptr[4];
586  tmp[3] = ptr[5];
587  uint32_t surrogate = (uint32_t)strtol(tmp, nullptr, 16);
588  if (surrogate >= 0xdc00 && surrogate < 0xe000) {
589  ptr += 6;
590  unicode = ((unicode - 0xd800) << 10) + (surrogate - 0xdc00) + 0x10000;
591  }
592  }
593  }
594  if (unicode < (1 << 7)) {
595  vec.push_back(unicode & 0x7f);
596  } else if (unicode < (1 << 11)) {
597  vec.push_back(((unicode >> 6) & 0x1f) | 0xc0);
598  vec.push_back((unicode & 0x3f) | 0x80);
599  } else if (unicode < (1 << 16)) {
600  vec.push_back(((unicode >> 12) & 0x0f) | 0xe0);
601  vec.push_back(((unicode >> 6) & 0x3f) | 0x80);
602  vec.push_back((unicode & 0x3f) | 0x80);
603  } else if (unicode < (1 << 21)) {
604  vec.push_back(((unicode >> 18) & 0x07) | 0xf0);
605  vec.push_back(((unicode >> 12) & 0x3f) | 0x80);
606  vec.push_back(((unicode >> 6) & 0x3f) | 0x80);
607  vec.push_back((unicode & 0x3f) | 0x80);
608  }
609  }
610  break;
611  default:
612  vec.push_back(*ptr);
613  ptr++;
614  break;
615  }
616  }
617  } else {
618  vec.push_back(*ptr);
619  ptr++;
620  }
621  }
622  }
623  return 0;
624  }
625 private:
626  struct StateItem {
628  char const *ptr = nullptr;
629  StateItem() = default;
630  StateItem(StateType type, char const *ptr = nullptr)
631  : type(type)
632  , ptr(ptr)
633  {
634  }
635  };
636  struct ParserData {
637  char const *begin = nullptr;
638  char const *end = nullptr;
639  char const *ptr = nullptr;
640  std::vector<StateItem> states;
641  bool hold = false;
642  std::string key;
643  std::string string;
644  double number = 0;
645  bool is_array = false;
646  bool allow_comment = false;
647  bool allow_ambiguous_comma = false;
648  bool allow_unquoted_key = false;
649  bool allow_hexadicimal = false;
651  bool allow_key_in_array = false;
652  std::vector<std::string> depth;
653  std::vector<int> depth_stack;
655  std::vector<Error> errors;
656  };
658 
659  void push_error(std::string const &what)
660  {
661  d.states.clear();
662 
663  Error err;
664  err.what_ = what;
665  d.errors.push_back(err);
666  }
667 
669  {
670  if (state() == Key || state() == Comma || state() == EndObject) {
671  d.states.pop_back();
672  }
673  d.states.push_back(s);
674 
675  if (isarray()) {
676  d.key.clear();
677  }
678 
679  switch (s.type) {
680  case StartArray:
681  d.is_array = true;
682  break;
683  case StartObject:
684  case Key:
685  d.is_array = false;
686  break;
687  }
688  }
689 
690  bool pop_state()
691  {
692  bool f = false;
693  if (!d.states.empty()) {
694  d.last_state = d.states.back();
695  d.states.pop_back();
696  size_t i = d.states.size();
697  while (i > 0) {
698  i--;
699  auto s = d.states[i];
700  if (s.type == StartArray) {
701  d.is_array = true;
702  break;
703  }
704  if (s.type == StartObject || s.type == Key) {
705  d.is_array = false;
706  break;
707  }
708  }
709  f = true;
710  if (state() == Key) {
711  d.states.pop_back();
712  }
713  }
714  d.key.clear();
715  return f;
716  }
717 
718  void parse(char const *begin, char const *end)
719  {
720  reset();
721  d = {};
722  d.begin = begin;
723  d.end = end;
724  d.ptr = d.begin;
725  }
726 
727  void parse(std::string_view const &sv)
728  {
729  parse(sv.data(), sv.data() + sv.size());
730  }
731 
732  void parse(char const *ptr, int len = -1)
733  {
734  if (len < 0) {
735  len = (int)strlen(ptr);
736  }
737  parse(ptr, ptr + len);
738  }
739 
741  {
742  while (d.ptr < d.end) {
743  {
744  auto n = scan_space(d.ptr, d.end);;
745  if (n > 0) {
746  d.ptr += n;
747  continue;
748  }
749  }
750  if (*d.ptr == '}') {
751  d.ptr++;
752  d.string.clear();
753  std::string key;
754  if (!d.depth.empty()) {
755  key = d.depth.back();
756  auto n = key.size();
757  if (n > 0) {
758  if (key[n - 1] == '{') {
759  key = key.substr(0, n - 1);
760  }
761  }
762  d.depth.pop_back();
763  }
764  while (1) {
765  bool f = (state() == StartObject);
766  if (!pop_state()) break;
767  if (f) {
769  d.key = key;
770  return true;
771  }
772  }
773  }
774  if (*d.ptr == ']') {
775  d.ptr++;
776  d.string.clear();
777  std::string key;
778  if (!d.depth.empty()) {
779  key = d.depth.back();
780  auto n = key.size();
781  if (n > 0) {
782  if (key[n - 1] == '[') {
783  key = key.substr(0, n - 1);
784  }
785  }
786  d.depth.pop_back();
787  }
788  while (1) {
789  bool f = (state() == StartArray);
790  if (!pop_state()) break;
791  if (f) {
793  d.key = key;
794  return true;
795  }
796  }
797  }
798  if (*d.ptr == ',') {
799  d.ptr++;
800  if (state() == Key) {
801  push_state(Null);
802  return true;
803  }
804  d.ptr += scan_space(d.ptr, d.end);
805  if (is_value()) {
806  pop_state();
807  }
808  push_state(Comma);
809  if (d.allow_ambiguous_comma) {
810  continue;
811  } else {
812  // if not allow_ambiguous_comma, fall through
813  }
814  }
815  if (*d.ptr == '{') {
816  char const *p = d.ptr++;
817  if (state() != Key) {
818  d.key.clear();
819  d.string.clear();
820  }
821  d.depth.push_back(d.key + '{');
822  push_state({StartObject, p});
823  return true;
824  }
825  if (*d.ptr == '[') {
826  char const *p = d.ptr++;
827  if (state() != Key) {
828  d.key.clear();
829  d.string.clear();
830  }
831  d.depth.push_back(d.key + '[');
832  push_state({StartArray, p});
833  return true;
834  }
835  if (*d.ptr == '\"') {
836  switch (state()) {
837  case None:
838  case StartObject:
839  case StartArray:
840  case Key:
841  case Comma:
842  // thru
843  break;
844  default:
845  if (d.allow_ambiguous_comma) {
846  break; // consider as a virtual comma is exists
847  }
848  push_error("unexpected double quote");
849  return false;
850  }
851 
852  auto n = parse_string(d.ptr, d.end, &d.string);
853  if (n > 0) {
854  d.ptr += n;
855  d.ptr += scan_space(d.ptr, d.end);
856  if (state() == Key) {
857  //
858  } else if (d.ptr < d.end && *d.ptr == ':') {
859  if (isarray()) {
860  // unusual syntax; "key":"value" in array
861  // e.g. [ "key": "value" ]
862  if (!d.allow_key_in_array) {
863  push_error("unexpected key in array");
864  return false;
865  }
866  }
867  d.ptr++;
868  d.key = d.string;
869  push_state(Key);
870  return true;
871  }
873  return true;
874  }
875  }
876  if (state() == Key || isarray()) {
877  auto n = parse_number(d.ptr, d.end, &d.number);
878  if (n > 0) {
879  d.string.assign(d.ptr, n);
880  d.ptr += n;
882  return true;
883  }
884  if (isalpha((unsigned char)*d.ptr)) {
885  auto n = parse_symbol(d.ptr, d.end, &d.string);
886  if (n > 0) {
887  if (state() == Key || state() == Comma || state() == StartArray) {
888  d.ptr += n;
889  if (d.string == "false") {
890  push_state(False);
891  return true;
892  }
893  if (d.string == "true") {
894  push_state(True);
895  return true;
896  }
897  if (d.string == "null") {
898  push_state(Null);
899  return true;
900  }
901  }
902  }
903  }
904  } else if (d.allow_unquoted_key) {
905  auto n = parse_symbol(d.ptr, d.end, &d.string);
906  if (n > 0) {
907  n += scan_space(d.ptr + n, d.end);
908  if (d.ptr[n] == ':') {
909  d.ptr += n + 1;
910  d.key = d.string;
911  push_state(Key);
912  return true;
913  }
914  }
915  }
916  push_error("syntax error");
917  break;
918  }
919  return false;
920  }
921  static void _init(ParserData *d)
922  {
923  d->begin = nullptr;
924  d->end = nullptr;
925  d->ptr = nullptr;
926  }
927 public:
928  Reader(std::string_view const &sv)
929  {
930  parse(sv);
931  }
932  Reader(char const *begin, char const *end)
933  {
934  parse(begin, end);
935  }
936  Reader(char const *ptr, int len = -1)
937  {
938  parse(ptr, len);
939  }
941  : d(std::move(r.d))
942  {
943  _init(&r.d);
944  }
946  {
947  if (this != &r) {
948  d = std::move(r.d);
949  _init(&r.d);
950  }
951  return *this;
952  }
953  Reader(Reader const &r) = delete;
954  Reader &operator=(Reader const &r) = delete;
955 
956  void allow_comment(bool allow)
957  {
958  d.allow_comment = allow;
959  }
960  void allow_ambiguous_comma(bool allow)
961  {
962  d.allow_ambiguous_comma = allow;
963  }
964  void allow_unquoted_key(bool allow)
965  {
966  d.allow_unquoted_key = allow;
967  }
968  void allow_hexadicimal(bool allow)
969  {
970  d.allow_hexadicimal = allow;
971  }
972  void allow_special_constant(bool allow)
973  {
974  d.allow_special_constant = allow;
975  }
976  void allow_key_in_array(bool allow)
977  {
978  d.allow_key_in_array = allow;
979  }
980  void reset()
981  {
982  d.errors.clear();
983  }
984  void hold()
985  {
986  d.hold = true;
987  }
988  void nest(std::function<void ()> callback_fn = {})
989  {
990  if (callback_fn) {
991  nest({});
992  do {
993  callback_fn();
994  } while (next());
995  return;
996  }
997 
998  d.depth_stack.push_back(depth());
999  }
1000  bool next()
1001  {
1002  if (d.hold) {
1003  d.hold = false;
1004  return true;
1005  }
1006  if (_internal_next()) {
1007  if (d.depth_stack.empty()) return true;
1008  if (this->depth() >= d.depth_stack.back()) {
1009  return true;
1010  }
1011  d.depth_stack.pop_back();
1012  hold();
1013  }
1014  return false;
1015  }
1016 
1018  {
1019  return d.states.empty() ? None : d.states.back().type;
1020  }
1021 
1022  bool has_error() const
1023  {
1024  return !d.errors.empty();
1025  }
1026 
1027  std::vector<Error> const &errors() const
1028  {
1029  return d.errors;
1030  }
1031 
1032  bool is_start_object() const
1033  {
1034  return state() == StartObject;
1035  }
1036 
1037  bool is_end_object() const
1038  {
1039  return state() == EndObject;
1040  }
1041 
1042  bool is_start_array() const
1043  {
1044  return state() == StartArray;
1045  }
1046 
1047  bool is_end_array() const
1048  {
1049  return state() == EndArray;
1050  }
1051 
1052  bool is_constant() const
1053  {
1054  switch (state()) {
1055  case String:
1056  case Number:
1057  case Null:
1058  case False:
1059  case True:
1060  return true;
1061  }
1062  return false;
1063  }
1064 
1065  bool is_structure() const
1066  {
1067  switch (state()) {
1068  case StartObject:
1069  case StartArray:
1070  return true;
1071  case EndObject:
1072  case EndArray:
1073  if (d.states.size() > 1) {
1074  auto s = d.states[d.states.size() - 2];
1075  switch (s.type) {
1076  case StartObject:
1077  case StartArray:
1078  return true;
1079  }
1080  }
1081  break;
1082  }
1083  return false;
1084  }
1085 
1086  bool is_value() const
1087  {
1088  return is_constant() || is_structure();
1089  }
1090 
1091  std::string key() const
1092  {
1093  return d.key;
1094  }
1095 
1096  std::string string() const
1097  {
1098  return d.string;
1099  }
1100 
1102  {
1103  StateType s = state();
1104 
1105  switch (s) {
1106  case Null:
1107  case False:
1108  case True:
1109  return s;
1110  }
1111  return None;
1112  }
1113 
1114  bool isnull() const
1115  {
1116  return symbol() == Null;
1117  }
1118 
1119  bool isfalse() const
1120  {
1121  return symbol() == False;
1122  }
1123 
1124  bool istrue() const
1125  {
1126  return symbol() == True;
1127  }
1128 
1129  bool isnumber() const
1130  {
1131  return state() == Number;
1132  }
1133 
1134  bool isstring() const
1135  {
1136  return state() == String;
1137  }
1138 
1139  double number() const
1140  {
1141  return d.number;
1142  }
1143 
1144  bool isarray() const
1145  {
1146  return d.is_array;
1147  }
1148 
1149  int depth() const
1150  {
1151  return (int)d.depth.size();
1152  }
1153 
1154  std::string path() const
1155  {
1156  std::string path;
1157  for (std::string const &s : d.depth) {
1158  path += s;
1159  }
1161  return path;
1162  }
1163  return path + d.key;
1164  }
1165 
1166  std::string_view extract()
1167  {
1168  if (d.last_state.ptr) {
1169  size_t n = d.ptr - d.last_state.ptr;
1170  return std::string_view(d.last_state.ptr, n);
1171  }
1172  return {};
1173  }
1174 
1175  bool match(std::string_view path, bool match_end_structure = false) const
1176  {
1177  if (!is_value()) return false;
1178 
1179  auto Path = [&](size_t i){ return i < path.size() ? path[i] : 0; };
1180 
1181  const auto stat = state();
1182 
1183  size_t i;
1184  for (i = 0; i < d.depth.size(); i++) {
1185  std::string const &element = d.depth[i];
1186  if (element.empty()) return false; // something wrong
1187  if (Path(0) == '*') {
1188  if (Path(1) == '*') {
1189  if (Path(2) == 0) return true; // "**" matches any path
1190  return false; // path syntax error: "**" must be at the end of path
1191  }
1192  char c = element.c_str()[element.size() - 1]; // last character of element
1193  if (c == '{' || c == '[') { // object or array
1194  if (Path(1) == c) {
1195  path = path.substr(2); // remove "*{" or "*["
1196  continue;
1197  }
1198  if (Path(1) == 0) {
1199  if (i + 1 == d.depth.size()) {
1200  if (c == '{' && stat == StartObject) return true;
1201  if (c == '[' && stat == StartArray) return true;
1202  }
1203  return false; // path syntax error: "*{" or "*[" must be at the end of path if no index specified
1204  }
1205  }
1206  }
1207  if (path.size() < element.size()) return false;
1208  if (strncmp(path.data(), element.c_str(), element.size()) != 0) return false;
1209  path = path.substr(element.size());
1210  }
1211  if (Path(0) == '*') {
1212  if (Path(1) == '*' && Path(2) == 0) return true;
1213  if (Path(1) == 0 && i == d.depth.size()) {
1214  if (is_constant()) return true;
1215  if (match_end_structure) {
1216  if (stat == EndObject || stat == EndArray) return true;
1217  }
1218  return false;
1219  }
1220  }
1221  return path == d.key;
1222  }
1223 
1224  bool match_start_object(char const *path) const
1225  {
1226  return state() == StartObject && match(path);
1227  }
1228 
1229  bool match_end_object(char const *path) const
1230  {
1231  return state() == EndObject && match(path, true);
1232  }
1233 
1234  bool match_start_array(char const *path) const
1235  {
1236  return state() == StartArray && match(path);
1237  }
1238 
1239  bool match_end_array(char const *path) const
1240  {
1241  return state() == EndArray && match(path, true);
1242  }
1243 
1244  uintptr_t tell() const
1245  {
1246  return (uintptr_t)d.ptr;
1247  }
1248  std::string_view extract(uintptr_t begin, uintptr_t end)
1249  {
1250  if (begin >= (uintptr_t)d.begin && end <= (uintptr_t)d.end && begin <= end) {
1251  return std::string_view((char *)begin, end - begin);
1252  }
1253  return {};
1254  }
1255 };
1256 
1257 class Writer {
1258 protected:
1259  void print(char const *p, int n)
1260  {
1261  if (output_fn) {
1262  output_fn(p, n);
1263  } else {
1264  string_out.append(p, n);
1265  }
1266  }
1267 
1268  void print(char c)
1269  {
1270  print(&c, 1);
1271  }
1272 
1273  void print(char const *p)
1274  {
1275  print(p, (int)strlen(p));
1276  }
1277 
1278  void print(std::string const &s)
1279  {
1280  print(s.c_str(), (int)s.size());
1281  }
1282 private:
1283  std::vector<int> stack;
1284  std::function<void (char const *p, int n)> output_fn;
1285  std::string string_out;
1286 
1287  bool enable_indent_ = true;
1288  bool enable_newline_ = true;
1289  bool allow_nan_ = false;
1290 
1292  {
1293  if (!enable_newline_) return;
1294 
1295  print('\n');
1296  }
1297 
1299  {
1300  if (!enable_indent_) return;
1301 
1302  size_t n = stack.size() - 1;
1303  for (size_t i = 0; i < n; i++) {
1304  print(' ');
1305  print(' ');
1306  }
1307  }
1308 
1309  bool print_number(double v)
1310  {
1311  std::string s = misc::format_double(v, allow_nan_);
1312  if (s.empty()) {
1313  print("null");
1314  return false;
1315  }
1316  print(s);
1317  return true;
1318  }
1319 
1320  void print_string(std::string_view const &s)
1321  {
1322  std::vector<char> buf = encode_json_string(s);
1323 
1324  print('\"');
1325  if (!buf.empty()) {
1326  print(buf.data(), (int)buf.size());
1327  }
1328  print('\"');
1329  }
1330 
1331  void print_raw(std::string const &s)
1332  {
1333  if (!s.empty()) {
1334  print(s.c_str(), (int)s.size());
1335  }
1336  }
1337 
1338  bool print_value(std::string const &name, std::function<bool ()> const &fn)
1339  {
1340  print_name(name);
1341 
1342  bool ok = fn();
1343 
1344  if (!stack.empty()) {
1345  stack.back()++;
1346  }
1347  if (stack.size() == 1) {
1348  flush();
1349  }
1350  return ok;
1351  }
1352 
1353  void print_object(std::string const &name = {}, std::function<void ()> const &fn = {})
1354  {
1355  print_name(name);
1356  print('{');
1357  stack.push_back(0);
1358  if (fn) {
1359  fn();
1360  end_object();
1361  }
1362  }
1363 
1364  void print_array(std::string const &name = {}, std::function<void ()> const &fn = {})
1365  {
1366  print_name(name);
1367  print('[');
1368  stack.push_back(0);
1369  if (fn) {
1370  fn();
1371  end_array();
1372  }
1373  }
1374 
1375  void end_block()
1376  {
1377  print_newline();
1378  if (!stack.empty()) {
1379  stack.pop_back();
1380  if (!stack.empty()) stack.back()++;
1381  }
1382  print_indent();
1383  }
1384 
1385  void reset()
1386  {
1387  stack.clear();
1388  stack.push_back(0);
1389  }
1390 
1391  void flush()
1392  {
1393  if (!stack.empty() && stack.front() > 0) {
1394  print_newline();
1395  }
1396  reset();
1397  }
1398 public:
1399  Writer(std::function<void (char const *p, int n)> fn = {})
1400  {
1401  output_fn = fn;
1402  reset();
1403  }
1404 
1406  {
1407  flush();
1408  }
1409 
1410  void enable_indent(bool enabled)
1411  {
1412  enable_indent_ = enabled;
1413  }
1414 
1415  void enable_newline(bool enabled)
1416  {
1417  enable_newline_ = enabled;
1418  }
1419 
1420  void allow_nan(bool allow)
1421  {
1422  allow_nan_ = allow;
1423  }
1424 
1425  void print_name(std::string const &name)
1426  {
1427  if (!stack.empty()) {
1428  if (stack.back() > 0) {
1429  print(',');
1430  }
1431  }
1432  if (stack.size() > 1) {
1433  print_newline();
1434  }
1435  print_indent();
1436  if (!name.empty()) {
1437  print_string(name);
1438  print(':');
1439  if (enable_indent_) {
1440  print(' ');
1441  }
1442  }
1443  }
1444 
1445  void start_object(std::string const &name = {})
1446  {
1447  print_object(name);
1448  }
1449 
1450  void end_object()
1451  {
1452  end_block();
1453  print('}');
1454 
1455  if (stack.size() == 1) {
1456  flush();
1457  }
1458  }
1459 
1460  void object(std::string const &name, std::function<void ()> const &fn)
1461  {
1462  print_object(name, fn);
1463  }
1464 
1465  void start_array(std::string const &name = {})
1466  {
1467  print_array(name, {});
1468  }
1469 
1470  void end_array()
1471  {
1472  end_block();
1473  print(']');
1474 
1475  if (stack.size() == 1) {
1476  flush();
1477  }
1478  }
1479 
1480  void array(std::string const &name, std::function<void ()> const &fn)
1481  {
1482  print_array(name, fn);
1483  }
1484 
1485  bool number(std::string const &name, double v)
1486  {
1487  return print_value(name, [&](){
1488  return print_number(v);
1489  });
1490  }
1491 
1492  void number(double v)
1493  {
1494  number({}, v);
1495  }
1496 
1497  void string(std::string const &name, std::string_view const &s)
1498  {
1499  print_value(name, [&](){
1500  print_string(s);
1501  return true;
1502  });
1503  }
1504 
1505  void string(std::string const &s)
1506  {
1507  string({}, s);
1508  }
1509 
1510  void symbol(std::string const &name, StateType v)
1511  {
1512  print_value(name, [&](){
1513  switch (v) {
1514  case False:
1515  print("false");
1516  break;
1517  case True:
1518  print("true");
1519  break;
1520  default:
1521  print("null");
1522  }
1523  return true;
1524  });
1525  }
1526 
1527  void boolean(std::string const &name, bool b)
1528  {
1529  symbol(name, b ? True : False);
1530  }
1531 
1532  void null()
1533  {
1534  symbol({}, Null);
1535  }
1536 
1537  void null(std::string const &name)
1538  {
1539  symbol(name, Null);
1540  }
1541 
1542  operator std::string () const
1543  {
1544  return string_out;
1545  }
1546 
1547  void raw(std::string const &name, std::string const &s)
1548  {
1549  print_value(name, [&](){
1550  print_raw(s);
1551  return true;
1552  });
1553  }
1554 };
1555 
1556 typedef std::nullptr_t null_t;
1557 static constexpr std::nullptr_t null = nullptr;
1558 
1559 struct Array;
1560 struct KeyValue;
1561 typedef std::vector<KeyValue> _Object;
1562 typedef std::variant<null_t, bool, double, std::string, _Object, Array> Variant;
1563 struct Array {
1564  std::vector<Variant> a;
1565  size_t size() const
1566  {
1567  return a.size();
1568  }
1569  bool empty() const
1570  {
1571  return a.empty();
1572  }
1573  Variant &operator[](size_t i)
1574  {
1575  return a[i];
1576  }
1577  Variant const &operator[](size_t i) const
1578  {
1579  return a[i];
1580  }
1581  template <typename T> T &get(size_t i)
1582  {
1583  assert(i < a.size());
1584  return std::get<T>(a[i]);
1585  }
1586  template <typename T> T const &get(size_t i) const
1587  {
1588  assert(i < a.size());
1589  return std::get<T>(a[i]);
1590  }
1591  void push_back(Variant const &v)
1592  {
1593  a.push_back(v);
1594  }
1596  {
1597  push_back(v);
1598  return *this;
1599  }
1600 };
1601 struct KeyValue {
1602  std::string key;
1604  KeyValue() = default;
1605  KeyValue(std::string const &k, Variant const &v)
1606  : key(k), value(v)
1607  {
1608  }
1609 };
1610 struct VariantRef {
1613  : var(&v)
1614  {
1615  }
1616  void operator = (Variant const &v)
1617  {
1618  *var = v;
1619  }
1620  operator Variant &()
1621  {
1622  return *var;
1623  }
1624 };
1625 struct Object {
1627  Object() : p(nullptr)
1628  {
1629  }
1631  : p(&o)
1632  {
1633  }
1635  {
1636  if (!std::holds_alternative<_Object>(v)) {
1637  v = _Object();
1638  }
1639  p = &std::get<_Object>(v);
1640  }
1641  size_t size() const
1642  {
1643  return p ? p->size() : 0;
1644  }
1645  bool empty() const
1646  {
1647  return size() == 0;
1648  }
1649  Variant *find(std::string const &key)
1650  {
1651  if (p) {
1652  for (auto &kv : *p) {
1653  if (kv.key == key) {
1654  return &kv.value;
1655  }
1656  }
1657  }
1658  return nullptr;
1659  }
1660  Variant const *find(std::string const &key) const
1661  {
1662  return const_cast<Object *>(this)->find(key);
1663  }
1664  Variant &value(std::string const &key)
1665  {
1666  Variant *v = find(key);
1667  assert(v);
1668  return *v;
1669  }
1670  Variant const &value(std::string const &key) const
1671  {
1672  return const_cast<Object *>(this)->value(key);
1673  }
1674  template <typename T> T const &get(std::string const &key) const
1675  {
1676  Variant const *v = find(key);
1677  assert(v);
1678  return std::get<T>(*v);
1679  }
1680  VariantRef operator [] (std::string const &key)
1681  {
1682  p->emplace_back(key, Variant());
1683  return p->back().value;
1684  }
1685 };
1686 
1687 static inline bool is_null(Variant const &v)
1688 {
1689  return std::holds_alternative<null_t>(v);
1690 }
1691 static inline bool is_boolean(Variant const &v)
1692 {
1693  return std::holds_alternative<bool>(v);
1694 }
1695 static inline bool is_number(Variant const &v)
1696 {
1697  return std::holds_alternative<double>(v);
1698 }
1699 static inline bool is_string(Variant const &v)
1700 {
1701  return std::holds_alternative<std::string>(v);
1702 }
1703 static inline bool is_object(Variant const &v)
1704 {
1705  return std::holds_alternative<_Object>(v);
1706 }
1707 static inline bool is_array(Variant const &v)
1708 {
1709  return std::holds_alternative<Array>(v);
1710 }
1711 static inline bool is_nan(Variant const &v)
1712 {
1713  return std::holds_alternative<double>(v) && std::isnan(std::get<double>(v));
1714 }
1715 static inline bool is_infinite(Variant const &v)
1716 {
1717  return std::holds_alternative<double>(v) && std::isinf(std::get<double>(v));
1718 }
1719 static inline Array &arr(Array &a)
1720 {
1721  return a;
1722 }
1723 static inline Array &arr(Variant &v)
1724 {
1725  if (!std::holds_alternative<Array>(v)) {
1726  v = Array();
1727  }
1728  return std::get<Array>(v);
1729 }
1730 static inline Object obj(Variant &v)
1731 {
1732  if (!std::holds_alternative<_Object>(v)) {
1733  v = _Object();
1734  }
1735  return Object(std::get<_Object>(v));
1736 }
1737 
1738 static inline Variant var(jstream::Reader const &reader)
1739 {
1740  if (reader.isnull()) {
1741  return null;
1742  } else if (reader.isfalse()) {
1743  return false;
1744  } else if (reader.istrue()) {
1745  return true;
1746  } else if (reader.isnumber()) {
1747  return reader.number();
1748  } else if (reader.isstring()) {
1749  return reader.string();
1750  }
1751  return null;
1752 }
1753 
1754 using std::get;
1755 
1756 } // namespace jstream
1757 
1758 #endif // JSTREAM_H_
Definition: jstream.h:403
bool is_end_object() const
Definition: jstream.h:1037
int depth() const
Definition: jstream.h:1149
bool isarray() const
Definition: jstream.h:1144
Reader(char const *begin, char const *end)
Definition: jstream.h:932
void allow_ambiguous_comma(bool allow)
Definition: jstream.h:960
static void _init(ParserData *d)
Definition: jstream.h:921
void allow_hexadicimal(bool allow)
Definition: jstream.h:968
bool isnull() const
Definition: jstream.h:1114
bool is_end_array() const
Definition: jstream.h:1047
ParserData d
Definition: jstream.h:657
bool has_error() const
Definition: jstream.h:1022
bool pop_state()
Definition: jstream.h:690
static std::string to_stdstr(std::vector< char > const &vec)
Definition: jstream.h:410
bool match_start_object(char const *path) const
Definition: jstream.h:1224
bool match_end_array(char const *path) const
Definition: jstream.h:1239
double number() const
Definition: jstream.h:1139
void parse(char const *ptr, int len=-1)
Definition: jstream.h:732
bool isfalse() const
Definition: jstream.h:1119
Reader(Reader &&r)
Definition: jstream.h:940
void allow_comment(bool allow)
Definition: jstream.h:956
void nest(std::function< void()> callback_fn={})
Definition: jstream.h:988
void hold()
Definition: jstream.h:984
bool istrue() const
Definition: jstream.h:1124
uintptr_t tell() const
Definition: jstream.h:1244
std::string path() const
Definition: jstream.h:1154
Reader & operator=(Reader const &r)=delete
bool match_start_array(char const *path) const
Definition: jstream.h:1234
void push_error(std::string const &what)
Definition: jstream.h:659
std::vector< Error > const & errors() const
Definition: jstream.h:1027
bool is_constant() const
Definition: jstream.h:1052
std::string key() const
Definition: jstream.h:1091
bool is_start_object() const
Definition: jstream.h:1032
int scan_space(char const *begin, char const *end)
Definition: jstream.h:420
void reset()
Definition: jstream.h:980
int parse_number(char const *begin, char const *end, double *out)
Definition: jstream.h:471
void allow_key_in_array(bool allow)
Definition: jstream.h:976
Reader(Reader const &r)=delete
Reader & operator=(Reader &&r)
Definition: jstream.h:945
Reader(char const *ptr, int len=-1)
Definition: jstream.h:936
void parse(std::string_view const &sv)
Definition: jstream.h:727
void allow_unquoted_key(bool allow)
Definition: jstream.h:964
bool is_structure() const
Definition: jstream.h:1065
void push_state(StateItem s)
Definition: jstream.h:668
std::string string() const
Definition: jstream.h:1096
bool match_end_object(char const *path) const
Definition: jstream.h:1229
bool is_value() const
Definition: jstream.h:1086
Reader(std::string_view const &sv)
Definition: jstream.h:928
bool _internal_next()
Definition: jstream.h:740
bool is_start_array() const
Definition: jstream.h:1042
StateType state() const
Definition: jstream.h:1017
int parse_symbol(char const *begin, char const *end, std::string *out)
Definition: jstream.h:453
bool isstring() const
Definition: jstream.h:1134
bool isnumber() const
Definition: jstream.h:1129
std::string_view extract()
Definition: jstream.h:1166
StateType symbol() const
Definition: jstream.h:1101
std::string_view extract(uintptr_t begin, uintptr_t end)
Definition: jstream.h:1248
bool next()
Definition: jstream.h:1000
void parse(char const *begin, char const *end)
Definition: jstream.h:718
bool match(std::string_view path, bool match_end_structure=false) const
Definition: jstream.h:1175
int parse_string(char const *begin, char const *end, std::string *out)
Definition: jstream.h:543
void allow_special_constant(bool allow)
Definition: jstream.h:972
Definition: jstream.h:1257
void end_block()
Definition: jstream.h:1375
bool allow_nan_
Definition: jstream.h:1289
void array(std::string const &name, std::function< void()> const &fn)
Definition: jstream.h:1480
void boolean(std::string const &name, bool b)
Definition: jstream.h:1527
void symbol(std::string const &name, StateType v)
Definition: jstream.h:1510
void object(std::string const &name, std::function< void()> const &fn)
Definition: jstream.h:1460
std::vector< int > stack
Definition: jstream.h:1283
void print_indent()
Definition: jstream.h:1298
void string(std::string const &s)
Definition: jstream.h:1505
void start_object(std::string const &name={})
Definition: jstream.h:1445
void allow_nan(bool allow)
Definition: jstream.h:1420
Writer(std::function< void(char const *p, int n)> fn={})
Definition: jstream.h:1399
bool number(std::string const &name, double v)
Definition: jstream.h:1485
void print(char c)
Definition: jstream.h:1268
bool print_value(std::string const &name, std::function< bool()> const &fn)
Definition: jstream.h:1338
void string(std::string const &name, std::string_view const &s)
Definition: jstream.h:1497
void end_array()
Definition: jstream.h:1470
void number(double v)
Definition: jstream.h:1492
bool print_number(double v)
Definition: jstream.h:1309
void print(std::string const &s)
Definition: jstream.h:1278
void print_name(std::string const &name)
Definition: jstream.h:1425
void enable_newline(bool enabled)
Definition: jstream.h:1415
void print_array(std::string const &name={}, std::function< void()> const &fn={})
Definition: jstream.h:1364
std::string string_out
Definition: jstream.h:1285
void print(char const *p)
Definition: jstream.h:1273
bool enable_indent_
Definition: jstream.h:1287
~Writer()
Definition: jstream.h:1405
void start_array(std::string const &name={})
Definition: jstream.h:1465
bool enable_newline_
Definition: jstream.h:1288
void end_object()
Definition: jstream.h:1450
void print_raw(std::string const &s)
Definition: jstream.h:1331
void print(char const *p, int n)
Definition: jstream.h:1259
void flush()
Definition: jstream.h:1391
std::function< void(char const *p, int n)> output_fn
Definition: jstream.h:1284
void print_string(std::string_view const &s)
Definition: jstream.h:1320
void reset()
Definition: jstream.h:1385
void print_newline()
Definition: jstream.h:1291
void raw(std::string const &name, std::string const &s)
Definition: jstream.h:1547
void print_object(std::string const &name={}, std::function< void()> const &fn={})
Definition: jstream.h:1353
void enable_indent(bool enabled)
Definition: jstream.h:1410
static std::string format_double(double val, bool allow_nan)
Definition: jstream.h:361
static double pow10_int(int exp)
Return 10 raised to an integer power.
Definition: jstream.h:103
static double my_strtod(const char *nptr, char **endptr)
Locale‑independent strtod clone.
Definition: jstream.h:134
Definition: jstream.h:20
static bool is_infinite(Variant const &v)
Definition: jstream.h:1715
static Variant var(jstream::Reader const &reader)
Definition: jstream.h:1738
static bool is_nan(Variant const &v)
Definition: jstream.h:1711
static bool is_null(Variant const &v)
Definition: jstream.h:1687
std::vector< KeyValue > _Object
Definition: jstream.h:1560
static bool is_boolean(Variant const &v)
Definition: jstream.h:1691
static Object obj(Variant &v)
Definition: jstream.h:1730
std::variant< null_t, bool, double, std::string, _Object, Array > Variant
Definition: jstream.h:1562
static bool is_object(Variant const &v)
Definition: jstream.h:1703
StateType
Definition: jstream.h:386
@ Null
Definition: jstream.h:389
@ String
Definition: jstream.h:399
@ EndObject
Definition: jstream.h:396
@ Comma
Definition: jstream.h:394
@ StartObject
Definition: jstream.h:395
@ EndArray
Definition: jstream.h:398
@ True
Definition: jstream.h:391
@ Number
Definition: jstream.h:400
@ StartArray
Definition: jstream.h:397
@ Key
Definition: jstream.h:393
@ False
Definition: jstream.h:390
@ None
Definition: jstream.h:388
static Array & arr(Array &a)
Definition: jstream.h:1719
static bool is_array(Variant const &v)
Definition: jstream.h:1707
static std::vector< char > encode_json_string(std::string_view const &in)
Definition: jstream.h:22
static bool is_number(Variant const &v)
Definition: jstream.h:1695
std::nullptr_t null_t
Definition: jstream.h:1556
static bool is_string(Variant const &v)
Definition: jstream.h:1699
Definition: misc.h:20
Definition: GitTypes.h:74
Definition: jstream.h:1563
Variant const & operator[](size_t i) const
Definition: jstream.h:1577
Array & operator+=(Variant const &v)
Definition: jstream.h:1595
bool empty() const
Definition: jstream.h:1569
T & get(size_t i)
Definition: jstream.h:1581
Variant & operator[](size_t i)
Definition: jstream.h:1573
void push_back(Variant const &v)
Definition: jstream.h:1591
size_t size() const
Definition: jstream.h:1565
T const & get(size_t i) const
Definition: jstream.h:1586
std::vector< Variant > a
Definition: jstream.h:1564
Definition: jstream.h:1601
KeyValue(std::string const &k, Variant const &v)
Definition: jstream.h:1605
Variant value
Definition: jstream.h:1603
KeyValue()=default
std::string key
Definition: jstream.h:1602
Definition: jstream.h:1625
size_t size() const
Definition: jstream.h:1641
Object(Variant &v)
Definition: jstream.h:1634
Variant & value(std::string const &key)
Definition: jstream.h:1664
Variant const * find(std::string const &key) const
Definition: jstream.h:1660
Variant const & value(std::string const &key) const
Definition: jstream.h:1670
_Object * p
Definition: jstream.h:1626
Object(_Object &o)
Definition: jstream.h:1630
Object()
Definition: jstream.h:1627
T const & get(std::string const &key) const
Definition: jstream.h:1674
VariantRef operator[](std::string const &key)
Definition: jstream.h:1680
bool empty() const
Definition: jstream.h:1645
Variant * find(std::string const &key)
Definition: jstream.h:1649
Definition: jstream.h:405
std::string what_
Definition: jstream.h:406
std::string what() const
Definition: jstream.h:407
Definition: jstream.h:636
bool allow_comment
Definition: jstream.h:646
std::vector< Error > errors
Definition: jstream.h:655
std::vector< std::string > depth
Definition: jstream.h:652
bool allow_ambiguous_comma
Definition: jstream.h:647
char const * ptr
Definition: jstream.h:639
bool allow_unquoted_key
Definition: jstream.h:648
bool is_array
Definition: jstream.h:645
bool allow_special_constant
Definition: jstream.h:650
StateItem last_state
Definition: jstream.h:654
std::string string
Definition: jstream.h:643
std::vector< StateItem > states
Definition: jstream.h:640
bool hold
Definition: jstream.h:641
std::vector< int > depth_stack
Definition: jstream.h:653
bool allow_hexadicimal
Definition: jstream.h:649
double number
Definition: jstream.h:644
char const * begin
Definition: jstream.h:637
char const * end
Definition: jstream.h:638
bool allow_key_in_array
Definition: jstream.h:651
std::string key
Definition: jstream.h:642
Definition: jstream.h:626
StateType type
Definition: jstream.h:627
char const * ptr
Definition: jstream.h:628
StateItem(StateType type, char const *ptr=nullptr)
Definition: jstream.h:630
Definition: jstream.h:1610
Variant * var
Definition: jstream.h:1611
void operator=(Variant const &v)
Definition: jstream.h:1616
VariantRef(Variant &v)
Definition: jstream.h:1612