CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/Data/Format/JSONWriter.cpp
Views: 1401
#include <iomanip>1#include <cmath>2#include <cstring>34#include "Common/Data/Format/JSONReader.h"5#include "Common/Data/Format/JSONWriter.h"67namespace json {89JsonWriter::JsonWriter(int flags) {10pretty_ = (flags & PRETTY) != 0;11str_.imbue(std::locale::classic());12// Let's maximize precision by default.13str_.precision(53);14}1516JsonWriter::~JsonWriter() {17}1819void JsonWriter::begin() {20str_ << "{";21stack_.push_back(StackEntry(DICT));22}2324void JsonWriter::beginArray() {25str_ << "[";26stack_.push_back(StackEntry(ARRAY));27}2829void JsonWriter::beginRaw() {30// For the uncommon case of writing a value directly, to avoid duplicated code.31stack_.push_back(StackEntry(RAW));32}3334void JsonWriter::end() {35pop();36if (pretty_)37str_ << "\n";38}3940const char *JsonWriter::indent(int n) const {41if (!pretty_)42return "";43static const char * const whitespace = " ";44if (n > 32) {45// Avoid crash.46return whitespace;47}48return whitespace + (32 - n);49}5051const char *JsonWriter::indent() const {52if (!pretty_)53return "";54int amount = (int)stack_.size() + 1;55amount *= 2; // 2-space indent.56return indent(amount);57}5859const char *JsonWriter::arrayIndent() const {60if (!pretty_)61return "";62int amount = (int)stack_.size() + 1;63amount *= 2; // 2-space indent.64return stack_.back().first ? indent(amount) : "";65}6667const char *JsonWriter::comma() const {68if (stack_.back().first) {69return "";70} else {71return pretty_ ? ",\n" : ",";72}73}7475const char *JsonWriter::arrayComma() const {76if (stack_.back().first) {77return pretty_ ? "\n" : "";78} else {79return pretty_ ? ", " : ",";80}81}8283void JsonWriter::pushDict() {84str_ << arrayComma() << arrayIndent() << "{";85stack_.back().first = false;86stack_.push_back(StackEntry(DICT));87}8889void JsonWriter::pushDict(const std::string &name) {90str_ << comma() << indent() << "\"";91writeEscapedString(name);92str_ << (pretty_ ? "\": {" : "\":{");93stack_.back().first = false;94stack_.push_back(StackEntry(DICT));95}9697void JsonWriter::pushArray() {98str_ << arrayComma() << arrayIndent() << "[";99stack_.back().first = false;100stack_.push_back(StackEntry(ARRAY));101}102103void JsonWriter::pushArray(const std::string &name) {104str_ << comma() << indent() << "\"";105writeEscapedString(name);106str_ << (pretty_ ? "\": [" : "\":[");107stack_.push_back(StackEntry(ARRAY));108}109110void JsonWriter::writeBool(bool value) {111str_ << arrayComma() << arrayIndent() << (value ? "true" : "false");112stack_.back().first = false;113}114115void JsonWriter::writeBool(const std::string &name, bool value) {116str_ << comma() << indent() << "\"";117writeEscapedString(name);118str_ << (pretty_ ? "\": " : "\":") << (value ? "true" : "false");119stack_.back().first = false;120}121122void JsonWriter::writeInt(int value) {123str_ << arrayComma() << arrayIndent() << value;124stack_.back().first = false;125}126127void JsonWriter::writeInt(const std::string &name, int value) {128str_ << comma() << indent() << "\"";129writeEscapedString(name);130str_ << (pretty_ ? "\": " : "\":") << value;131stack_.back().first = false;132}133134void JsonWriter::writeUint(uint32_t value) {135str_ << arrayComma() << arrayIndent() << value;136stack_.back().first = false;137}138139void JsonWriter::writeUint(const std::string &name, uint32_t value) {140str_ << comma() << indent() << "\"";141writeEscapedString(name);142str_ << (pretty_ ? "\": " : "\":") << value;143stack_.back().first = false;144}145146void JsonWriter::writeFloat(double value) {147str_ << arrayComma() << arrayIndent();148if (std::isfinite(value))149str_ << value;150else151str_ << "null";152stack_.back().first = false;153}154155void JsonWriter::writeFloat(const std::string &name, double value) {156str_ << comma() << indent() << "\"";157writeEscapedString(name);158str_ << (pretty_ ? "\": " : "\":");159if (std::isfinite(value))160str_ << value;161else162str_ << "null";163stack_.back().first = false;164}165166void JsonWriter::writeString(const std::string &value) {167str_ << arrayComma() << arrayIndent() << "\"";168writeEscapedString(value);169str_ << "\"";170stack_.back().first = false;171}172173void JsonWriter::writeString(const std::string &name, const std::string &value) {174str_ << comma() << indent() << "\"";175writeEscapedString(name);176str_ << (pretty_ ? "\": \"" : "\":\"");177writeEscapedString(value);178str_ << "\"";179stack_.back().first = false;180}181182void JsonWriter::writeRaw(const std::string &value) {183str_ << arrayComma() << arrayIndent() << value;184stack_.back().first = false;185}186187void JsonWriter::writeRaw(const std::string &name, const std::string &value) {188str_ << comma() << indent() << "\"";189writeEscapedString(name);190str_ << (pretty_ ? "\": " : "\":");191str_ << value;192stack_.back().first = false;193}194195void JsonWriter::writeNull() {196str_ << arrayComma() << arrayIndent() << "null";197stack_.back().first = false;198}199200void JsonWriter::writeNull(const std::string &name) {201str_ << comma() << indent() << "\"";202writeEscapedString(name);203str_ << (pretty_ ? "\": " : "\":") << "null";204stack_.back().first = false;205}206207void JsonWriter::pop() {208BlockType type = stack_.back().type;209stack_.pop_back();210if (pretty_)211str_ << "\n" << indent();212switch (type) {213case ARRAY:214str_ << "]";215break;216case DICT:217str_ << "}";218break;219case RAW:220break;221}222if (stack_.size() > 0)223stack_.back().first = false;224}225226void JsonWriter::writeEscapedString(const std::string &str) {227size_t pos = 0;228const size_t len = str.size();229230auto update = [&](size_t current, size_t skip = 0) {231size_t end = current;232if (pos < end)233str_ << str.substr(pos, end - pos);234pos = end + skip;235};236237for (size_t i = 0; i < len; ++i) {238switch (str[i]) {239case '\\':240case '"':241case '/':242update(i);243str_ << '\\';244break;245246case '\r':247update(i, 1);248str_ << "\\r";249break;250break;251252case '\n':253update(i, 1);254str_ << "\\n";255break;256break;257258case '\t':259update(i, 1);260str_ << "\\t";261break;262263case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 11:264case 12: case 14: case 15: case 16: case 17: case 18: case 19: case 20:265case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28:266case 29: case 30: case 31:267update(i, 1);268str_ << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)str[i] << std::dec << std::setw(0);269break;270271default:272break;273}274}275276if (pos != 0) {277update(len);278} else {279str_ << str;280}281}282283static void json_stringify_object(JsonWriter &writer, const JsonNode *node);284static void json_stringify_array(JsonWriter &writer, const JsonNode *node);285286std::string json_stringify(const JsonNode *node) {287JsonWriter writer;288289// Handle direct values too, not just objects.290switch (node->value.getTag()) {291case JSON_NULL:292case JSON_STRING:293case JSON_NUMBER:294case JSON_TRUE:295case JSON_FALSE:296writer.beginRaw();297// It's the same as a one entry array without brackets, so reuse.298json_stringify_array(writer, node);299break;300301case JSON_OBJECT:302writer.begin();303for (const JsonNode *it : node->value) {304json_stringify_object(writer, it);305}306break;307case JSON_ARRAY:308writer.beginArray();309for (const JsonNode *it : node->value) {310json_stringify_array(writer, it);311}312break;313}314315writer.end();316return writer.str();317}318319static void json_stringify_object(JsonWriter &writer, const JsonNode *node) {320switch (node->value.getTag()) {321case JSON_NULL:322writer.writeNull(node->key);323break;324case JSON_STRING:325writer.writeString(node->key, node->value.toString());326break;327case JSON_NUMBER:328writer.writeFloat(node->key, node->value.toNumber());329break;330case JSON_TRUE:331writer.writeBool(node->key, true);332break;333case JSON_FALSE:334writer.writeBool(node->key, false);335break;336337case JSON_OBJECT:338writer.pushDict(node->key);339for (const JsonNode *it : node->value) {340json_stringify_object(writer, it);341}342writer.pop();343break;344case JSON_ARRAY:345writer.pushArray(node->key);346for (const JsonNode *it : node->value) {347json_stringify_array(writer, it);348}349writer.pop();350break;351}352}353354static void json_stringify_array(JsonWriter &writer, const JsonNode *node) {355switch (node->value.getTag()) {356case JSON_NULL:357writer.writeRaw("null");358break;359case JSON_STRING:360writer.writeString(node->value.toString());361break;362case JSON_NUMBER:363writer.writeFloat(node->value.toNumber());364break;365case JSON_TRUE:366writer.writeBool(true);367break;368case JSON_FALSE:369writer.writeBool(false);370break;371372case JSON_OBJECT:373writer.pushDict();374for (const JsonNode *it : node->value) {375json_stringify_object(writer, it);376}377writer.pop();378break;379case JSON_ARRAY:380writer.pushArray();381for (const JsonNode *it : node->value) {382json_stringify_array(writer, it);383}384writer.pop();385break;386}387}388389} // namespace json390391392