6 #if !defined(JSON_IS_AMALGAMATION)
9 #endif // if !defined(JSON_IS_AMALGAMATION)
20 #if __cplusplus >= 201103L
25 #define isnan std::isnan
28 #if !defined(isfinite)
29 #define isfinite std::isfinite
42 #if !defined(isfinite)
44 #define isfinite _finite
47 #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
48 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
49 #endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
53 #if defined(__sun) && defined(__SVR4) // Solaris
54 #if !defined(isfinite)
56 #define isfinite finite
61 #if !defined(isfinite)
62 #if defined(__ia64) && !defined(finite)
64 ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
71 #define isnan(x) (x != x)
74 #if !defined(__APPLE__)
75 #if !defined(isfinite)
76 #define isfinite finite
83 #pragma warning(disable : 4996)
88 #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
96 char* current = buffer +
sizeof(buffer);
100 }
else if (value < 0) {
106 assert(current >= buffer);
112 char* current = buffer +
sizeof(buffer);
114 assert(current >= buffer);
118 #if defined(JSON_HAS_INT64)
124 #endif // # if defined(JSON_HAS_INT64)
133 static const char*
const reps[2][3] = {{
"NaN",
"-Infinity",
"Infinity"},
134 {
"null",
"-1e+9999",
"1e+9999"}};
135 return reps[useSpecialFloats ? 0 : 1]
136 [
isnan(value) ? 0 : (value < 0) ? 1 : 2];
139 String buffer(
size_t(36),
'\0');
142 &*buffer.begin(), buffer.size(),
146 auto wouldPrint =
static_cast<size_t>(len);
147 if (wouldPrint >= buffer.size()) {
148 buffer.resize(wouldPrint + 1);
151 buffer.resize(wouldPrint);
164 if (buffer.find(
'.') == buffer.npos && buffer.find(
'e') == buffer.npos) {
173 return valueToString(value,
false, precision, precisionType);
181 return std::any_of(s, s + n, [](
unsigned char c) {
182 return c ==
'\\' || c ==
'"' || c < 0x20 || c > 0x7F;
187 const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
189 unsigned int firstByte =
static_cast<unsigned char>(*s);
191 if (firstByte < 0x80)
194 if (firstByte < 0xE0) {
196 return REPLACEMENT_CHARACTER;
198 unsigned int calculated =
199 ((firstByte & 0x1F) << 6) | (
static_cast<unsigned int>(s[1]) & 0x3F);
202 return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
205 if (firstByte < 0xF0) {
207 return REPLACEMENT_CHARACTER;
209 unsigned int calculated = ((firstByte & 0x0F) << 12) |
210 ((
static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
211 (
static_cast<unsigned int>(s[2]) & 0x3F);
215 if (calculated >= 0xD800 && calculated <= 0xDFFF)
216 return REPLACEMENT_CHARACTER;
218 return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
221 if (firstByte < 0xF8) {
223 return REPLACEMENT_CHARACTER;
225 unsigned int calculated = ((firstByte & 0x07) << 18) |
226 ((
static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
227 ((
static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
228 (
static_cast<unsigned int>(s[3]) & 0x3F);
231 return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
234 return REPLACEMENT_CHARACTER;
237 static const char hex2[] =
"000102030405060708090a0b0c0d0e0f"
238 "101112131415161718191a1b1c1d1e1f"
239 "202122232425262728292a2b2c2d2e2f"
240 "303132333435363738393a3b3c3d3e3f"
241 "404142434445464748494a4b4c4d4e4f"
242 "505152535455565758595a5b5c5d5e5f"
243 "606162636465666768696a6b6c6d6e6f"
244 "707172737475767778797a7b7c7d7e7f"
245 "808182838485868788898a8b8c8d8e8f"
246 "909192939495969798999a9b9c9d9e9f"
247 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
248 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
249 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
250 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
251 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
252 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
255 const unsigned int hi = (x >> 8) & 0xff;
256 const unsigned int lo = x & 0xff;
258 result[0] =
hex2[2 * hi];
259 result[1] =
hex2[2 * hi + 1];
260 result[2] =
hex2[2 * lo];
261 result[3] =
hex2[2 * lo + 1];
266 result +=
static_cast<char>(ch);
274 bool emitUTF8 =
false) {
275 if (value ==
nullptr)
279 return String(
"\"") + value +
"\"";
283 String::size_type maxsize = length * 2 + 3;
285 result.reserve(maxsize);
287 char const* end = value + length;
288 for (
const char* c = value; c != end; ++c) {
321 unsigned codepoint =
static_cast<unsigned char>(*c);
322 if (codepoint < 0x20) {
329 if (codepoint < 0x20) {
331 }
else if (codepoint < 0x80) {
333 }
else if (codepoint < 0x10000) {
338 codepoint -= 0x10000;
339 appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
340 appendHex(result, 0xdc00 + (codepoint & 0x3ff));
356 Writer::~Writer() =
default;
361 FastWriter::FastWriter()
365 void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ =
true; }
367 void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ =
true; }
369 void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ =
true; }
371 String FastWriter::write(
const Value& root) {
374 if (!omitEndingLineFeed_)
379 void FastWriter::writeValue(
const Value& value) {
380 switch (value.type()) {
382 if (!dropNullPlaceholders_)
398 bool ok = value.getString(&str, &end);
409 for (
ArrayIndex index = 0; index < size; ++index) {
412 writeValue(value[index]);
419 for (
auto it = members.begin(); it != members.end(); ++it) {
421 if (it != members.begin())
424 static_cast<unsigned>(name.length()));
425 document_ += yamlCompatibilityEnabled_ ?
": " :
":";
426 writeValue(value[name]);
436 StyledWriter::StyledWriter() =
default;
438 String StyledWriter::write(
const Value& root) {
440 addChildValues_ =
false;
441 indentString_.clear();
442 writeCommentBeforeValue(root);
444 writeCommentAfterValueOnSameLine(root);
449 void StyledWriter::writeValue(
const Value& value) {
450 switch (value.type()) {
467 bool ok = value.getString(&str, &end);
478 writeArrayValue(value);
485 writeWithIndent(
"{");
487 auto it = members.begin();
490 const Value& childValue = value[name];
491 writeCommentBeforeValue(childValue);
494 writeValue(childValue);
495 if (++it == members.end()) {
496 writeCommentAfterValueOnSameLine(childValue);
500 writeCommentAfterValueOnSameLine(childValue);
503 writeWithIndent(
"}");
509 void StyledWriter::writeArrayValue(
const Value& value) {
510 unsigned size = value.size();
514 bool isArrayMultiLine = isMultilineArray(value);
515 if (isArrayMultiLine) {
516 writeWithIndent(
"[");
518 bool hasChildValue = !childValues_.empty();
521 const Value& childValue = value[index];
522 writeCommentBeforeValue(childValue);
524 writeWithIndent(childValues_[index]);
527 writeValue(childValue);
529 if (++index == size) {
530 writeCommentAfterValueOnSameLine(childValue);
534 writeCommentAfterValueOnSameLine(childValue);
537 writeWithIndent(
"]");
540 assert(childValues_.size() == size);
542 for (
unsigned index = 0; index < size; ++index) {
545 document_ += childValues_[index];
552 bool StyledWriter::isMultilineArray(
const Value& value) {
554 bool isMultiLine = size * 3 >= rightMargin_;
555 childValues_.clear();
556 for (
ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
557 const Value& childValue = value[index];
558 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
559 !childValue.empty());
563 childValues_.reserve(size);
564 addChildValues_ =
true;
566 for (
ArrayIndex index = 0; index < size; ++index) {
567 if (hasCommentForValue(value[index])) {
570 writeValue(value[index]);
571 lineLength +=
static_cast<ArrayIndex>(childValues_[index].length());
573 addChildValues_ =
false;
574 isMultiLine = isMultiLine || lineLength >= rightMargin_;
579 void StyledWriter::pushValue(
const String& value) {
581 childValues_.push_back(value);
586 void StyledWriter::writeIndent() {
587 if (!document_.empty()) {
588 char last = document_[document_.length() - 1];
594 document_ += indentString_;
597 void StyledWriter::writeWithIndent(
const String& value) {
602 void StyledWriter::indent() { indentString_ +=
String(indentSize_,
' '); }
604 void StyledWriter::unindent() {
605 assert(indentString_.size() >= indentSize_);
606 indentString_.resize(indentString_.size() - indentSize_);
609 void StyledWriter::writeCommentBeforeValue(
const Value& root) {
616 String::const_iterator iter = comment.begin();
617 while (iter != comment.end()) {
619 if (*iter ==
'\n' && ((iter + 1) != comment.end() && *(iter + 1) ==
'/'))
628 void StyledWriter::writeCommentAfterValueOnSameLine(
const Value& root) {
639 bool StyledWriter::hasCommentForValue(
const Value& value) {
648 StyledStreamWriter::StyledStreamWriter(
String indentation)
649 : document_(nullptr), indentation_(std::move(indentation)),
650 addChildValues_(), indented_(false) {}
652 void StyledStreamWriter::write(
OStream& out,
const Value& root) {
654 addChildValues_ =
false;
655 indentString_.clear();
657 writeCommentBeforeValue(root);
662 writeCommentAfterValueOnSameLine(root);
667 void StyledStreamWriter::writeValue(
const Value& value) {
668 switch (value.type()) {
685 bool ok = value.getString(&str, &end);
696 writeArrayValue(value);
699 Value::Members members(value.getMemberNames());
703 writeWithIndent(
"{");
705 auto it = members.begin();
708 const Value& childValue = value[name];
709 writeCommentBeforeValue(childValue);
712 writeValue(childValue);
713 if (++it == members.end()) {
714 writeCommentAfterValueOnSameLine(childValue);
718 writeCommentAfterValueOnSameLine(childValue);
721 writeWithIndent(
"}");
727 void StyledStreamWriter::writeArrayValue(
const Value& value) {
728 unsigned size = value.size();
732 bool isArrayMultiLine = isMultilineArray(value);
733 if (isArrayMultiLine) {
734 writeWithIndent(
"[");
736 bool hasChildValue = !childValues_.empty();
739 const Value& childValue = value[index];
740 writeCommentBeforeValue(childValue);
742 writeWithIndent(childValues_[index]);
747 writeValue(childValue);
750 if (++index == size) {
751 writeCommentAfterValueOnSameLine(childValue);
755 writeCommentAfterValueOnSameLine(childValue);
758 writeWithIndent(
"]");
761 assert(childValues_.size() == size);
763 for (
unsigned index = 0; index < size; ++index) {
766 *document_ << childValues_[index];
773 bool StyledStreamWriter::isMultilineArray(
const Value& value) {
775 bool isMultiLine = size * 3 >= rightMargin_;
776 childValues_.clear();
777 for (
ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
778 const Value& childValue = value[index];
779 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
780 !childValue.empty());
784 childValues_.reserve(size);
785 addChildValues_ =
true;
787 for (
ArrayIndex index = 0; index < size; ++index) {
788 if (hasCommentForValue(value[index])) {
791 writeValue(value[index]);
792 lineLength +=
static_cast<ArrayIndex>(childValues_[index].length());
794 addChildValues_ =
false;
795 isMultiLine = isMultiLine || lineLength >= rightMargin_;
800 void StyledStreamWriter::pushValue(
const String& value) {
802 childValues_.push_back(value);
807 void StyledStreamWriter::writeIndent() {
812 *document_ <<
'\n' << indentString_;
815 void StyledStreamWriter::writeWithIndent(
const String& value) {
822 void StyledStreamWriter::indent() { indentString_ += indentation_; }
824 void StyledStreamWriter::unindent() {
825 assert(indentString_.size() >= indentation_.size());
826 indentString_.resize(indentString_.size() - indentation_.size());
829 void StyledStreamWriter::writeCommentBeforeValue(
const Value& root) {
836 String::const_iterator iter = comment.begin();
837 while (iter != comment.end()) {
839 if (*iter ==
'\n' && ((iter + 1) != comment.end() && *(iter + 1) ==
'/'))
841 *document_ << indentString_;
847 void StyledStreamWriter::writeCommentAfterValueOnSameLine(
const Value& root) {
858 bool StyledStreamWriter::hasCommentForValue(
const Value& value) {
868 struct CommentStyle {
877 struct BuiltStyledStreamWriter :
public StreamWriter {
878 BuiltStyledStreamWriter(
String indentation, CommentStyle::Enum cs,
880 String endingLineFeedSymbol,
bool useSpecialFloats,
881 bool emitUTF8,
unsigned int precision,
883 int write(Value
const& root,
OStream* sout)
override;
886 void writeValue(Value
const& value);
887 void writeArrayValue(Value
const& value);
888 bool isMultilineArray(Value
const& value);
889 void pushValue(
String const& value);
891 void writeWithIndent(
String const& value);
894 void writeCommentBeforeValue(Value
const& root);
895 void writeCommentAfterValueOnSameLine(Value
const& root);
896 static bool hasCommentForValue(
const Value& value);
898 using ChildValues = std::vector<String>;
900 ChildValues childValues_;
902 unsigned int rightMargin_;
904 CommentStyle::Enum cs_;
907 String endingLineFeedSymbol_;
908 bool addChildValues_ : 1;
910 bool useSpecialFloats_ : 1;
912 unsigned int precision_;
915 BuiltStyledStreamWriter::BuiltStyledStreamWriter(
916 String indentation, CommentStyle::Enum cs,
String colonSymbol,
917 String nullSymbol,
String endingLineFeedSymbol,
bool useSpecialFloats,
918 bool emitUTF8,
unsigned int precision,
PrecisionType precisionType)
919 : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
920 colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
921 endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
922 addChildValues_(false), indented_(false),
923 useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
924 precision_(precision), precisionType_(precisionType) {}
925 int BuiltStyledStreamWriter::write(Value
const& root,
OStream* sout) {
927 addChildValues_ =
false;
929 indentString_.clear();
930 writeCommentBeforeValue(root);
935 writeCommentAfterValueOnSameLine(root);
936 *sout_ << endingLineFeedSymbol_;
940 void BuiltStyledStreamWriter::writeValue(Value
const& value) {
941 switch (value.type()) {
943 pushValue(nullSymbol_);
952 pushValue(
valueToString(value.asDouble(), useSpecialFloats_, precision_,
959 bool ok = value.getString(&str, &end);
971 writeArrayValue(value);
974 Value::Members members(value.getMemberNames());
978 writeWithIndent(
"{");
980 auto it = members.begin();
983 Value
const& childValue = value[name];
984 writeCommentBeforeValue(childValue);
986 name.data(),
static_cast<unsigned>(name.length()), emitUTF8_));
987 *sout_ << colonSymbol_;
988 writeValue(childValue);
989 if (++it == members.end()) {
990 writeCommentAfterValueOnSameLine(childValue);
994 writeCommentAfterValueOnSameLine(childValue);
997 writeWithIndent(
"}");
1003 void BuiltStyledStreamWriter::writeArrayValue(Value
const& value) {
1004 unsigned size = value.size();
1008 bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
1010 writeWithIndent(
"[");
1012 bool hasChildValue = !childValues_.empty();
1015 Value
const& childValue = value[index];
1016 writeCommentBeforeValue(childValue);
1018 writeWithIndent(childValues_[index]);
1023 writeValue(childValue);
1026 if (++index == size) {
1027 writeCommentAfterValueOnSameLine(childValue);
1031 writeCommentAfterValueOnSameLine(childValue);
1034 writeWithIndent(
"]");
1037 assert(childValues_.size() == size);
1039 if (!indentation_.empty())
1041 for (
unsigned index = 0; index < size; ++index) {
1043 *sout_ << ((!indentation_.empty()) ?
", " :
",");
1044 *sout_ << childValues_[index];
1046 if (!indentation_.empty())
1053 bool BuiltStyledStreamWriter::isMultilineArray(Value
const& value) {
1055 bool isMultiLine = size * 3 >= rightMargin_;
1056 childValues_.clear();
1057 for (
ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
1058 Value
const& childValue = value[index];
1059 isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
1060 !childValue.empty());
1064 childValues_.reserve(size);
1065 addChildValues_ =
true;
1067 for (
ArrayIndex index = 0; index < size; ++index) {
1068 if (hasCommentForValue(value[index])) {
1071 writeValue(value[index]);
1072 lineLength +=
static_cast<ArrayIndex>(childValues_[index].length());
1074 addChildValues_ =
false;
1075 isMultiLine = isMultiLine || lineLength >= rightMargin_;
1080 void BuiltStyledStreamWriter::pushValue(
String const& value) {
1081 if (addChildValues_)
1082 childValues_.push_back(value);
1087 void BuiltStyledStreamWriter::writeIndent() {
1093 if (!indentation_.empty()) {
1095 *sout_ <<
'\n' << indentString_;
1099 void BuiltStyledStreamWriter::writeWithIndent(
String const& value) {
1106 void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
1108 void BuiltStyledStreamWriter::unindent() {
1109 assert(indentString_.size() >= indentation_.size());
1110 indentString_.resize(indentString_.size() - indentation_.size());
1113 void BuiltStyledStreamWriter::writeCommentBeforeValue(Value
const& root) {
1114 if (cs_ == CommentStyle::None)
1122 String::const_iterator iter = comment.begin();
1123 while (iter != comment.end()) {
1125 if (*iter ==
'\n' && ((iter + 1) != comment.end() && *(iter + 1) ==
'/'))
1127 *sout_ << indentString_;
1133 void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
1134 Value
const& root) {
1135 if (cs_ == CommentStyle::None)
1147 bool BuiltStyledStreamWriter::hasCommentForValue(
const Value& value) {
1156 StreamWriter::StreamWriter() : sout_(nullptr) {}
1170 CommentStyle::Enum cs = CommentStyle::All;
1171 if (cs_str ==
"All") {
1172 cs = CommentStyle::All;
1173 }
else if (cs_str ==
"None") {
1174 cs = CommentStyle::None;
1176 throwRuntimeError(
"commentStyle must be 'All' or 'None'");
1179 if (pt_str ==
"significant") {
1181 }
else if (pt_str ==
"decimal") {
1184 throwRuntimeError(
"precisionType must be 'significant' or 'decimal'");
1186 String colonSymbol =
" : ";
1189 }
else if (indentation.empty()) {
1192 String nullSymbol =
"null";
1198 String endingLineFeedSymbol;
1199 return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
1200 endingLineFeedSymbol, usf, emitUTF8, pre,
1205 static const auto& valid_keys = *
new std::set<String>{
1208 "enableYAMLCompatibility",
1209 "dropNullPlaceholders",
1216 auto key = si.name();
1217 if (valid_keys.count(key))
1220 (*invalid)[std::move(key)] = *si;
1224 return invalid ? invalid->
empty() :
true;
1233 (*settings)[
"commentStyle"] =
"All";
1234 (*settings)[
"indentation"] =
"\t";
1235 (*settings)[
"enableYAMLCompatibility"] =
false;
1236 (*settings)[
"dropNullPlaceholders"] =
false;
1237 (*settings)[
"useSpecialFloats"] =
false;
1238 (*settings)[
"emitUTF8"] =
false;
1239 (*settings)[
"precision"] = 17;
1240 (*settings)[
"precisionType"] =
"significant";
1247 writer->write(root, &sout);
1254 writer->write(root, &sout);