21 #include <type_traits> 23 #include <boost/algorithm/string.hpp> 43 unsigned* indentLevel,
47 void operator()(
dynamic const&
v)
const {
50 if (!
opts_.allow_nan_inf &&
52 throw std::runtime_error(
53 "folly::toJson: JSON object value was a " 60 auto intval = v.
asInt();
61 if (
opts_.javascript_safe) {
64 intval =
int64_t(to<double>(intval));
85 CHECK(0) <<
"Bad type " << v.
type();
90 void printKV(
const std::pair<const dynamic, dynamic>& p)
const {
91 if (!
opts_.allow_non_string_keys && !p.first.isString()) {
92 throw std::runtime_error(
93 "folly::toJson: JSON object key was not a " 101 template <
typename Iterator>
102 void printKVPairs(Iterator
begin, Iterator
end)
const {
104 for (++begin; begin !=
end; ++
begin) {
111 void printObject(
dynamic const& o)
const {
121 using ref = std::reference_wrapper<decltype(o.
items())::value_type
const>;
125 auto const& sort_keys_by =
opts_.sort_keys_by
126 ? SortByRef(
opts_.sort_keys_by)
127 : SortByRef(std::less<dynamic>());
128 std::sort(
refs.begin(),
refs.end(), [&](ref
a, ref
b) {
130 return sort_keys_by(a.get().first,
b.get().first);
132 printKVPairs(
refs.cbegin(),
refs.cend());
134 printKVPairs(o.
items().begin(), o.
items().end());
141 void printArray(
dynamic const&
a)
const {
162 void outdent()
const {
168 void indent()
const {
174 void newline()
const {
180 void mapColon()
const {
197 : std::runtime_error(to<std::string>(
198 "json parse error on line ",
200 !context.empty() ? to<std::string>(
" near `",
context,
'\'') :
"",
212 Input(Input
const&) =
delete;
213 Input& operator=(Input
const&) =
delete;
215 char const*
begin()
const {
221 template <
class Predicate>
223 std::size_t skipped = 0;
224 for (; skipped <
range_.size(); ++skipped) {
225 if (!p(
range_[skipped])) {
228 if (
range_[skipped] ==
'\n') {
232 auto ret =
range_.subpiece(0, skipped);
239 return skipWhile([](
char c) {
return c >=
'0' && c <=
'9'; });
243 bool firstChar =
true;
244 return skipWhile([&firstChar](
char c) {
245 bool result = (c >=
'0' && c <=
'9') || (firstChar && c ==
'-');
264 std::size_t
size()
const {
268 int operator*()
const {
281 }
catch (std::exception
const& e) {
288 range_.advance(str.size());
296 return range_.subpiece(0, 16 ).toString();
299 dynamic
error(
char const* what)
const {
303 json::serialization_opts
const& getOpts() {
307 void incrementRecursionLevel() {
309 error(
"recursion limit exceeded");
314 void decrementRecursionLevel() {
319 void storeCurrent() {
325 json::serialization_opts
const&
opts_;
331 class RecursionGuard {
333 explicit RecursionGuard(Input& in) :
in_(in) {
334 in_.incrementRecursionLevel();
338 in_.decrementRecursionLevel();
345 dynamic parseValue(Input& in);
347 dynamic parseNumber(Input& in);
349 dynamic parseObject(Input& in) {
362 if (in.getOpts().allow_trailing_comma && *in ==
'}') {
366 auto key = parseString(in);
370 ret.insert(
std::move(key), parseValue(in));
371 }
else if (!in.getOpts().allow_non_string_keys) {
372 in.error(
"expected string for object key name");
374 auto key = parseValue(in);
378 ret.insert(
std::move(key), parseValue(in));
393 dynamic parseArray(Input& in) {
406 if (in.getOpts().allow_trailing_comma && *in ==
']') {
409 ret.push_back(parseValue(in));
422 dynamic parseNumber(Input& in) {
423 bool const negative = (*in ==
'-');
424 if (negative && in.consume(
"-Infinity")) {
425 if (in.getOpts().parse_numbers_as_strings) {
428 return -std::numeric_limits<double>::infinity();
432 auto integral = in.skipMinusAndDigits();
433 if (negative && integral.size() < 2) {
434 in.error(
"expected digits after `-'");
437 auto const wasE = *in ==
'e' || *in ==
'E';
439 constexpr
const char* maxInt =
"9223372036854775807";
440 constexpr
const char* minInt =
"-9223372036854775808";
444 if (*in !=
'.' && !wasE && in.getOpts().parse_numbers_as_strings) {
448 if (*in !=
'.' && !wasE) {
449 if (
LIKELY(!in.getOpts().double_fallback || integral.size() < maxIntLen) ||
450 (!negative && integral.size() == maxIntLen && integral <= maxInt) ||
451 (negative && integral.size() == minIntLen && integral <= minInt)) {
452 auto val = to<int64_t>(integral);
456 auto val = to<double>(integral);
462 auto end = !wasE ? (++in, in.skipDigits().end()) : in.begin();
463 if (*in ==
'e' || *in ==
'E') {
465 if (*in ==
'+' || *in ==
'-') {
468 auto expPart = in.skipDigits();
471 auto fullNum =
range(integral.begin(),
end);
472 if (in.getOpts().parse_numbers_as_strings) {
475 auto val = to<double>(fullNum);
483 c >=
'0' &&
c <=
'9' ?
c -
'0' :
484 c >=
'a' &&
c <=
'f' ?
c -
'a' + 10 :
485 c >=
'A' &&
c <=
'F' ?
c -
'A' + 10 :
486 (in.error(
"invalid hex digit"), 0));
492 in.error(
"expected 4 hex digits");
497 ret += hexVal(*in) * 256;
499 ret += hexVal(*in) * 16;
511 if (codePoint >= 0xd800 && codePoint <= 0xdbff) {
512 if (!in.consume(
"\\u")) {
514 "expected another unicode escape for second half of " 518 if (second >= 0xdc00 && second <= 0xdfff) {
519 codePoint = 0x10000 + ((codePoint & 0x3ff) << 10) + (second & 0x3ff);
521 in.error(
"second character in surrogate pair is invalid");
523 }
else if (codePoint >= 0xdc00 && codePoint <= 0xdfff) {
524 in.error(
"invalid unicode code point (in range [0xdc00,0xdfff])");
531 DCHECK_EQ(*in,
'\"');
536 auto range = in.skipWhile([](
char c) {
return c !=
'\"' && c !=
'\\'; });
547 case '\"': ret.push_back(
'\"'); ++in;
break;
548 case '\\': ret.push_back(
'\\'); ++in;
break;
549 case '/': ret.push_back(
'/'); ++in;
break;
550 case 'b': ret.push_back(
'\b'); ++in;
break;
551 case 'f': ret.push_back(
'\f'); ++in;
break;
552 case 'n': ret.push_back(
'\n'); ++in;
break;
553 case 'r': ret.push_back(
'\r'); ++in;
break;
554 case 't': ret.push_back(
'\t'); ++in;
break;
555 case 'u': ++in; ret += decodeUnicodeEscape(in);
break;
559 to<std::string>(
"unknown escape ", *in,
" in string").c_str());
564 in.error(
"unterminated string");
574 in.error(
"null byte in string");
577 ret.push_back(
char(*in));
584 dynamic parseValue(Input& in) {
585 RecursionGuard
guard(in);
590 *in ==
'[' ? parseArray(in) :
591 *in ==
'{' ? parseObject(in) :
592 *in ==
'\"' ? parseString(in) :
593 (*in ==
'-' || (*in >=
'0' && *in <=
'9')) ? parseNumber(in) :
594 in.consume(
"true") ? true :
595 in.consume(
"false") ? false :
597 in.consume(
"Infinity") ?
598 (in.getOpts().parse_numbers_as_strings ? (dynamic)
"Infinity" :
599 (dynamic)
std::numeric_limits<double>::infinity()) :
601 (in.getOpts().parse_numbers_as_strings ? (dynamic)
"NaN" :
602 (dynamic)
std::numeric_limits<double>::quiet_NaN()) :
603 in.
error(
"expected json value");
612 std::array<uint64_t, 2> escapes{{0, 0}};
614 if (
b >= 0x20 &&
b < 0x80) {
623 unsigned indentLevel = 0;
632 template <
bool EnableExtraAsciiEscapes,
class T>
635 static constexpr
T kOnes = ~
T() / 255;
636 static constexpr
T kMsbs = kOnes * 0x80;
642 return (w - kOnes *
b) & ~w & kMsbs;
647 return isLess(s ^ (kOnes * c), 1);
652 auto isHigh = s & kMsbs;
653 auto isLow = isLess(s, 0x20);
654 auto needsEscape = isHigh | isLow | isChar(
'\\') | isChar(
'"');
656 if (EnableExtraAsciiEscapes) {
662 const auto offset =
i * 64;
669 needsEscape |= isChar(offset + bit - 1);
670 bitmap &= bitmap - 1;
687 template <
bool EnableExtraAsciiEscapes>
692 auto hexDigit = [](
uint8_t c) ->
char {
693 return c < 10 ? c +
'0' : c - 10 +
'a';
698 auto* p =
reinterpret_cast<const unsigned char*
>(input.
begin());
699 auto* q =
reinterpret_cast<const unsigned char*
>(input.
begin());
700 auto* e =
reinterpret_cast<const unsigned char*
>(input.
end());
706 while (firstEsc < e) {
707 auto avail = e - firstEsc;
710 word = folly::loadUnaligned<uint64_t>(firstEsc);
712 word = folly::partialLoadUnaligned<uint64_t>(firstEsc, avail);
714 auto prefix = firstEscapableInWord<EnableExtraAsciiEscapes>(word, opts);
715 DCHECK_LE(prefix, avail);
722 out.append(reinterpret_cast<const char*>(p), firstEsc - p);
750 out.append(u8
"\ufffd");
758 if (EnableExtraAsciiEscapes) {
759 encodeUnicode = encodeUnicode ||
760 (*p >= 0x20 && *p < 0x80 &&
771 auto writeHex = [&](char16_t
v) {
772 char buf[] =
"\\u\0\0\0\0";
773 buf[2] = hexDigit((
v >> 12) & 0x0f);
774 buf[3] = hexDigit((
v >> 8) & 0x0f);
775 buf[4] = hexDigit((
v >> 4) & 0x0f);
776 buf[5] = hexDigit(
v & 0x0f);
785 writeHex(static_cast<char16_t>(cp));
790 writeHex(static_cast<char16_t>(
791 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu)));
792 writeHex(static_cast<char16_t>(0xdc00u + ((cp - 0x10000u) & 0x3ffu)));
794 }
else if (*p ==
'\\' || *p ==
'\"') {
798 }
else if (*p <= 0x1f) {
801 case '\b': out.append(
"\\b"); p++;
break;
802 case '\f': out.append(
"\\f"); p++;
break;
803 case '\n': out.append(
"\\n"); p++;
break;
804 case '\r': out.append(
"\\r"); p++;
break;
805 case '\t': out.append(
"\\t"); p++;
break;
810 char buf[] =
"\\u00\0\0";
811 buf[4] = hexDigit(
uint8_t((*p & 0xf0) >> 4));
812 buf[5] = hexDigit(
uint8_t(*p & 0xf));
817 out.push_back(
char(*p++));
831 escapeStringImpl<true>(input, out, opts);
833 escapeStringImpl<false>(input, out, opts);
844 }
state = State::None;
846 for (
size_t i = 0;
i < jsonC.
size(); ++
i) {
850 if (
s.startsWith(
"/*")) {
851 state = State::InlineComment;
854 }
else if (
s.startsWith(
"//")) {
855 state = State::LineComment;
858 }
else if (
s[0] ==
'\"') {
859 state = State::InString;
861 result.push_back(
s[0]);
863 case State::InString:
866 throw std::logic_error(
"Invalid JSONC: string is not terminated");
868 result.push_back(
s[0]);
869 result.push_back(
s[1]);
872 }
else if (
s[0] ==
'\"') {
875 result.push_back(
s[0]);
877 case State::InlineComment:
878 if (
s.startsWith(
"*/")) {
883 case State::LineComment:
890 throw std::logic_error(
"Unknown comment state");
905 json::Input in(range, &opts);
907 auto ret = parseValue(in);
909 if (in.size() && *in !=
'\0') {
910 in.error(
"parsing didn't consume all input");
static ObjectMaker object()
dynamic parseJson(StringPiece range)
BitIterator< BaseIter > findFirstSet(BitIterator< BaseIter >, BitIterator< BaseIter >)
StringPiece skipWhitespace(StringPiece sp)
constexpr detail::Map< Move > move
A reference wrapper for callable objects.
constexpr size_type size() const
auto begin(TestAdlIterable &instance)
char32_t utf8ToCodePoint(const unsigned char *&p, const unsigned char *const e, bool skipOnError)
#define FOLLY_UNLIKELY(x)
std::unordered_map< std::string, IValidator * > refs
std::string stripComments(StringPiece jsonC)
void PrintTo(const dynamic &dyn, std::ostream *os)
constexpr auto kIsLittleEndian
—— Concurrent Priority Queue Implementation ——
serialization_opts const & opts_
bool prefix(Cursor &c, uint32_t expected)
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
std::string codePointToUtf8(char32_t cp)
constexpr auto size(C const &c) -> decltype(c.size())
State
See Core for details.
std::string asString() const
auto end(TestAdlIterable &instance)
Range subpiece(size_type first, size_type length=npos) const
GuardImpl guard(ErrorHandler &&handler)
std::string toPrettyJson(dynamic const &dyn)
constexpr Range< Iter > range(Iter first, Iter last)
constexpr unsigned int findLastSet(T const v)
void print_as_pseudo_json(std::ostream &) const
void expect(LineReader &lr, const char *expected)
static const char *const value
std::array< uint64_t, 2 > buildExtraAsciiToEscapeBitmap(StringPiece chars)
void toAppend(char value, Tgt *result)
constexpr Iter end() const
constexpr Iter begin() const
unsigned *const indentLevel_
void escapeString(StringPiece input, std::string &out, const serialization_opts &opts)
constexpr size_t constexpr_strlen(const Char *s)
IterableProxy< const_item_iterator > items() const
Range< const unsigned char * > ByteRange
static void array(EmptyArrayTag)
unsigned int currentRecursionLevel_
bool allow_non_string_keys
std::array< uint64_t, 2 > extra_ascii_to_escape_bitmap
Range< const char * > StringPiece
std::string serialize(dynamic const &dyn, serialization_opts const &opts)
const_iterator begin() const
std::string toJson(dynamic const &dyn)
void escapeStringImpl(StringPiece input, std::string &out, const serialization_opts &opts)
const_iterator end() const
bool starts_with(const path &pth, const path &prefix)
size_t firstEscapableInWord(T s, const serialization_opts &opts)