qt/ledset/gutil/qjson.h
2023-08-21 11:21:00 +08:00

192 lines
5.3 KiB
C++

#ifndef QJSON_H
#define QJSON_H
#include "cu.h"
#include "QtCore/qhashfunctions.h"
#include <QTextStream>
class JValue;
using JObj = LinkedMap<QString, JValue>;
using JArray = Vector<JValue>;
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<QString>**) data = new SharedData<QString>{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<QString>**) 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<QString>**) 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<QString>**) 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 &in;
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