#ifndef QJSON_H #define QJSON_H #include "cu.h" #include "QtCore/qhashfunctions.h" #include class JValue; using JObj = LinkedMap; using JArray = Vector; class JValue { public: int data[2]{0}; enum Type { Null, Bool, Int, Long, Double, Obj, Array, Str }; Type type{Null}; JValue(Type = Null) {} JValue(bool b) : type(Bool) {data[0] = b;} JValue(int n) : type(Int) {data[0] = n;} JValue(qint64 n) : type(Long) {*(qint64*) data = n;} JValue(double d) : type(Double) {*(double*) data = d;} JValue(const JObj &o) : type(Obj) {new (data) JObj(o);} JValue(const JArray &a) : type(Array) {new (data) JArray(a);} JValue(const QString &s) : type(Str) {*(SharedData**) data = new SharedData{s, 1};} JValue(const char *s) : JValue(QString::fromUtf8(s)) {} JValue(const JValue &other) { type = other.type; if(type==Obj) new (data) JObj(*(JObj*) other.data); else if(type==Array) new (data) JArray(*(JArray*) other.data); else { data[0] = other.data[0]; data[1] = other.data[1]; if(type==Str) (*(SharedData**) data)->cnt++; } } ~JValue() { if(type < Obj) return; else if(type==Obj) ((JObj*) data)->~JObj(); else if(type==Array) ((JArray*) data)->~JArray(); else if(type==Str) { auto ptr = *(SharedData**) data; if(ptr->cnt > 1) ptr->cnt--; else delete ptr; } } JValue &operator=(const JValue &other) { this->~JValue(); new (this) JValue(other); return *this; } bool isNull() const {return type==Null;} bool isObj() const {return type==Obj;} bool isArray() const {return type==Array;} bool toBool(bool def = false) const { return type==Null ? def : data[0] || data[1]; } int toInt(int def = 0) const { if(type==Bool || type==Int) return data[0]; if(type==Long) return *(qint64*) data; if(type==Double) return *(double*) data; return def; } qint64 toLong(qint64 def = 0) const { if(type==Bool || type==Int) return data[0]; if(type==Long) return *(qint64*) data; if(type==Double) return *(double*) data; return def; } double toDouble(double def = 0) const { if(type==Bool || type==Int) return data[0]; if(type==Long) return *(qint64*) data; if(type==Double) return *(double*) data; return def; } QString toStr(const QString &def = "") const { if(type==Bool) return data[0] ? "true" : "false"; if(type==Int) return QString::number(data[0]); if(type==Long) return QString::number(*(qint64*) data); if(type==Double) return QString::number(*(double*) data); if(type==Str) return (*(SharedData**) data)->data; return def; } JObj toObj() const { if(type==Obj) return *(JObj*) data; return JObj(); } JArray toArray() const { if(type==Array) return *(JArray*) data; return JArray(); } const JValue operator[](const QString &key) const { return type==Obj ? (*(JObj*) data)[key] : JValue(); } const JValue operator[](int i) const { return type==Array ? (*(JArray*) data)[i] : JValue(); } private: JValue(const void *) = delete; // avoid implicit conversions from char * to bool }; class JParser { public: JParser(QTextStream &in) : in(in) { #if(QT_VERSION_MAJOR < 6) in.setCodec("UTF-8"); #endif } inline JValue read() { skipSpace(); return readValue(); } protected: JValue readValue(); QString readStr(); void skipSpace(); QTextStream ∈ QChar ch{0}, bk{0}; }; inline JValue JFrom(const QByteArray &json, QString *err = 0) { QTextStream in(json); try { return JParser(in).read(); } catch (QString anerr) { if(err) *err = anerr; } catch (const char *anerr) { if(err) *err = anerr; } catch (...) { if(err) *err = "unknow error"; } return JValue(); } inline JValue JFrom(QIODevice *device, QString *err = 0) { QTextStream in(device); try { return JParser(in).read(); } catch (QString anerr) { if(err) *err = anerr; } catch (const char *anerr) { if(err) *err = anerr; } catch (...) { if(err) *err = "unknow error"; } return JValue(); } class JOut { public: JOut(QTextStream &out, QString indent = "") : out(out), indent(indent) { #if(QT_VERSION_MAJOR < 6) out.setCodec("UTF-8"); #endif } void write(const JValue &obj); void writeStr(const QString &str); void writeMap(const JObj &map); void writeList(const JArray &objs); protected: QTextStream &out; QString indent; int cnt{0}; }; inline QString JToStr(const JValue &obj, QString indent = "") { QString json; QTextStream out(&json); JOut(out, indent).write(obj); return json; } inline QByteArray JToBytes(const JValue &obj, QString indent = "") { QByteArray json; QTextStream out(&json); JOut(out, indent).write(obj); return json; } inline QTextStream::Status JWrite(const JValue &obj, QIODevice *device, QString indent = "") { QTextStream out(device); JOut(out, indent).write(obj); return out.status(); } #endif // QJSON_H