ledok
This commit is contained in:
parent
0cb71807e6
commit
2cfa0cc514
|
@ -0,0 +1,2 @@
|
||||||
|
//#include "cu.h"
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
#ifndef CU_H
|
||||||
|
#define CU_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
inline long long steady_milli() {
|
||||||
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
inline long long system_milli() {
|
||||||
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
inline long long steady_micro() {
|
||||||
|
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
inline long long system_micro() {
|
||||||
|
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct SharedData {
|
||||||
|
T data;
|
||||||
|
uint64_t cnt{1};
|
||||||
|
};
|
||||||
|
template <class T>
|
||||||
|
class SharedPtr {
|
||||||
|
public:
|
||||||
|
SharedPtr(SharedData<T> *ptr = 0) : ptr{ptr} {}
|
||||||
|
SharedPtr(const SharedPtr &other) : ptr{other.ptr} {
|
||||||
|
if(ptr) ptr->cnt++;
|
||||||
|
}
|
||||||
|
~SharedPtr() {
|
||||||
|
if(ptr==0) return;
|
||||||
|
if(ptr->cnt > 1) ptr->cnt--;
|
||||||
|
else delete ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNull() {return ptr==0;}
|
||||||
|
SharedPtr &operator=(const SharedPtr &other) {
|
||||||
|
this->~SharedPtr();
|
||||||
|
new (this) SharedPtr(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T &operator*() {
|
||||||
|
if(ptr==0) ptr = new SharedData<T>;
|
||||||
|
return ptr->data;
|
||||||
|
}
|
||||||
|
T *operator->() {
|
||||||
|
if(ptr==0) ptr = new SharedData<T>;
|
||||||
|
return &ptr->data;
|
||||||
|
}
|
||||||
|
const T &operator*() const {
|
||||||
|
return ptr->data;
|
||||||
|
}
|
||||||
|
const T *operator->() const {
|
||||||
|
return &ptr->data;
|
||||||
|
}
|
||||||
|
SharedData<T> *ptr{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class V>
|
||||||
|
class Vector : public SharedPtr<std::vector<V>> {
|
||||||
|
public:
|
||||||
|
using SharedPtr<std::vector<V>>::SharedPtr;
|
||||||
|
|
||||||
|
using iterator = std::_Vector_iterator<std::_Vector_val<std::_Simple_types<V>>>;
|
||||||
|
using const_iterator = std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<V>>>;
|
||||||
|
|
||||||
|
Vector(std::initializer_list<V> _Ilist) {
|
||||||
|
this->ptr = new SharedData<std::vector<V>>{_Ilist, 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const noexcept {
|
||||||
|
return this->ptr ? this->ptr->data.empty() : true;
|
||||||
|
}
|
||||||
|
uint64_t size() const noexcept {
|
||||||
|
return this->ptr ? this->ptr->data.size() : 0;
|
||||||
|
}
|
||||||
|
Vector &append(const V &val) {
|
||||||
|
(**this).push_back(val);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V &operator[](const uint64_t pos) noexcept {
|
||||||
|
return (**this)[pos];
|
||||||
|
}
|
||||||
|
const V &operator[](const uint64_t pos) const noexcept {
|
||||||
|
return this->ptr ? this->ptr->data[pos] : V();
|
||||||
|
}
|
||||||
|
const const_iterator begin() const noexcept {
|
||||||
|
return this->ptr ? this->ptr->data.begin() : const_iterator();
|
||||||
|
}
|
||||||
|
const const_iterator end() const noexcept {
|
||||||
|
return this->ptr ? this->ptr->data.end() : const_iterator();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct NodeBase {
|
||||||
|
NodeBase *next{this};
|
||||||
|
NodeBase *prev{this};
|
||||||
|
};
|
||||||
|
template <class V>
|
||||||
|
struct _Node : NodeBase {
|
||||||
|
V value;
|
||||||
|
~_Node() {
|
||||||
|
if(next) delete (_Node<V>*) next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class V>
|
||||||
|
class LinkedMapIterator {
|
||||||
|
public:
|
||||||
|
LinkedMapIterator(_Node<V> *node) : node(node) {}
|
||||||
|
bool operator==(const LinkedMapIterator& that) const {
|
||||||
|
return node == that.node;
|
||||||
|
}
|
||||||
|
bool operator!=(const LinkedMapIterator& that) const {
|
||||||
|
return node != that.node;
|
||||||
|
}
|
||||||
|
LinkedMapIterator& operator++() {
|
||||||
|
node = (_Node<V>*) node->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
LinkedMapIterator& operator--() {
|
||||||
|
node = (_Node<V>*) node->prev;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
V &operator*() const {
|
||||||
|
return node->value;
|
||||||
|
}
|
||||||
|
V *operator->() const {
|
||||||
|
return &node->value;
|
||||||
|
}
|
||||||
|
_Node<V> *node{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class K, class V>
|
||||||
|
struct LinkedMapPri : NodeBase {
|
||||||
|
std::unordered_map<K, _Node<std::pair<K, V>>*> map;
|
||||||
|
uint64_t cnt{1};
|
||||||
|
~LinkedMapPri() {
|
||||||
|
if(prev) prev->next = 0;
|
||||||
|
if(next) delete (_Node<std::pair<K, V>>*) next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <class K, class V>
|
||||||
|
class LinkedMap {
|
||||||
|
public:
|
||||||
|
using Node = _Node<std::pair<K, V>>;
|
||||||
|
|
||||||
|
using iterator = LinkedMapIterator<std::pair<K, V>>;
|
||||||
|
using const_iterator = LinkedMapIterator<std::pair<K, V>>;
|
||||||
|
|
||||||
|
LinkedMap() {}
|
||||||
|
LinkedMap(std::initializer_list<std::pair<K, V>> pairs) : _pri{new LinkedMapPri<K, V>} {
|
||||||
|
for(auto pair : pairs) insert(pair.first, pair.second);
|
||||||
|
}
|
||||||
|
LinkedMap(std::unordered_map<K, Node*> &&map) : _pri{new LinkedMapPri<K, V>{0, 0, map}} {
|
||||||
|
_pri->next = _pri->prev = _pri;
|
||||||
|
}
|
||||||
|
LinkedMap(const LinkedMap &other) : _pri{other._pri} {
|
||||||
|
if(_pri) _pri->cnt++;
|
||||||
|
}
|
||||||
|
~LinkedMap() {
|
||||||
|
if(_pri==0) return;
|
||||||
|
if(_pri->cnt > 1) _pri->cnt--;
|
||||||
|
else delete _pri;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedMap &operator=(const LinkedMap &other) {
|
||||||
|
this->~LinkedMap();
|
||||||
|
new (this) LinkedMap(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const V operator[](const K &k) const {
|
||||||
|
if(_pri==0) return V();
|
||||||
|
auto it = _pri->map.find(k);
|
||||||
|
if(it==_pri->map.end()) return V();
|
||||||
|
return it->second->value.second;
|
||||||
|
}
|
||||||
|
LinkedMap &insert(const K &k, const V &v) {
|
||||||
|
if(_pri==0) _pri = new LinkedMapPri<K, V>;
|
||||||
|
auto pair = _pri->map.emplace(k, nullptr);
|
||||||
|
if(pair.second) {
|
||||||
|
auto node = new Node{_pri, _pri->prev, {k, v}};
|
||||||
|
_pri->prev->next = node;
|
||||||
|
_pri->prev = node;
|
||||||
|
pair.first->second = node;
|
||||||
|
} else pair.first->second->value.second = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void erase(const K& k) {
|
||||||
|
if(_pri==0) return;
|
||||||
|
auto it = _pri->map.find(k);
|
||||||
|
if(it==_pri->map.end()) return;
|
||||||
|
auto node = it->second;
|
||||||
|
_pri->map.erase(it);
|
||||||
|
node->prev->next = node->next;
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
node->next = 0;
|
||||||
|
node->prev = 0;
|
||||||
|
delete node;
|
||||||
|
}
|
||||||
|
inline bool empty() const {
|
||||||
|
return _pri==0 || _pri->map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return const_iterator((Node*) (_pri ? _pri->next : 0));
|
||||||
|
}
|
||||||
|
const_iterator end() const {
|
||||||
|
return const_iterator((Node*) _pri);
|
||||||
|
}
|
||||||
|
LinkedMapPri<K, V> *_pri{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CU_H
|
|
@ -62,17 +62,13 @@ public:
|
||||||
inline VBox(QBoxLayout *parent) : QBoxLayout(TopToBottom) {
|
inline VBox(QBoxLayout *parent) : QBoxLayout(TopToBottom) {
|
||||||
parent->addLayout(this);
|
parent->addLayout(this);
|
||||||
};
|
};
|
||||||
inline VBox(QStackedLayout *parent) : QBoxLayout(TopToBottom) {
|
inline VBox(QStackedLayout *stack) : QBoxLayout(TopToBottom, new QWidget) {
|
||||||
|
stack->addWidget(parentWidget());
|
||||||
setContentsMargins(0,0,0,0);
|
setContentsMargins(0,0,0,0);
|
||||||
auto wgt = new QWidget;
|
|
||||||
wgt->setLayout(this);
|
|
||||||
parent->addWidget(wgt);
|
|
||||||
};
|
};
|
||||||
inline VBox(QSplitter *parent) : QBoxLayout(TopToBottom) {
|
inline VBox(QSplitter *splitter) : QBoxLayout(TopToBottom, new QWidget) {
|
||||||
|
splitter->addWidget(parentWidget());
|
||||||
setContentsMargins(0,0,0,0);
|
setContentsMargins(0,0,0,0);
|
||||||
auto wgt = new QWidget;
|
|
||||||
wgt->setLayout(this);
|
|
||||||
parent->addWidget(wgt);
|
|
||||||
};
|
};
|
||||||
inline QLabel *addLabel(const QString &text) {
|
inline QLabel *addLabel(const QString &text) {
|
||||||
auto lb = new QLabel(text);
|
auto lb = new QLabel(text);
|
||||||
|
@ -86,17 +82,13 @@ public:
|
||||||
inline HBox(QBoxLayout *parent) : QBoxLayout(LeftToRight) {
|
inline HBox(QBoxLayout *parent) : QBoxLayout(LeftToRight) {
|
||||||
parent->addLayout(this);
|
parent->addLayout(this);
|
||||||
};
|
};
|
||||||
inline HBox(QStackedLayout *parent) : QBoxLayout(LeftToRight) {
|
inline HBox(QStackedLayout *stack) : QBoxLayout(LeftToRight, new QWidget) {
|
||||||
|
stack->addWidget(parentWidget());
|
||||||
setContentsMargins(0,0,0,0);
|
setContentsMargins(0,0,0,0);
|
||||||
auto wgt = new QWidget;
|
|
||||||
wgt->setLayout(this);
|
|
||||||
parent->addWidget(wgt);
|
|
||||||
};
|
};
|
||||||
inline HBox(QSplitter *parent) : QBoxLayout(LeftToRight) {
|
inline HBox(QSplitter *splitter) : QBoxLayout(LeftToRight, new QWidget) {
|
||||||
|
splitter->addWidget(parentWidget());
|
||||||
setContentsMargins(0,0,0,0);
|
setContentsMargins(0,0,0,0);
|
||||||
auto wgt = new QWidget;
|
|
||||||
wgt->setLayout(this);
|
|
||||||
parent->addWidget(wgt);
|
|
||||||
};
|
};
|
||||||
inline QLabel *addLabel(const QString &text) {
|
inline QLabel *addLabel(const QString &text) {
|
||||||
auto lb = new QLabel(text);
|
auto lb = new QLabel(text);
|
||||||
|
@ -110,11 +102,17 @@ public:
|
||||||
inline Grid(QBoxLayout *parent) {
|
inline Grid(QBoxLayout *parent) {
|
||||||
parent->addLayout(this);
|
parent->addLayout(this);
|
||||||
};
|
};
|
||||||
inline Grid(QStackedLayout *parent) {
|
inline Grid(QStackedLayout *stack) : QGridLayout(new QWidget) {
|
||||||
auto wgt = new QWidget;
|
stack->addWidget(parentWidget());
|
||||||
wgt->setLayout(this);
|
|
||||||
parent->addWidget(wgt);
|
|
||||||
};
|
};
|
||||||
|
inline Grid(QSplitter *splitter) : QGridLayout(new QWidget) {
|
||||||
|
splitter->addWidget(parentWidget());
|
||||||
|
};
|
||||||
|
inline QLabel *addLabel(const QString &text) {
|
||||||
|
auto lb = new QLabel(text);
|
||||||
|
addWidget(lb);
|
||||||
|
return lb;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ListWgt : public QListWidget {
|
class ListWgt : public QListWidget {
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
#include "qjson.h"
|
||||||
|
|
||||||
|
inline QChar readOne(QTextStream &in) {
|
||||||
|
QChar ch;
|
||||||
|
in >> ch;
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
JValue JParser::readValue() {
|
||||||
|
if(ch=='{') {
|
||||||
|
JObj obj;
|
||||||
|
while(true) {
|
||||||
|
do skipSpace(); //ch有三种可能
|
||||||
|
while(ch==',');
|
||||||
|
if(ch=='}') return obj;
|
||||||
|
QString key;
|
||||||
|
if(ch == '"') key = readStr();
|
||||||
|
else if(ch!='n' || in.read(3)!="ull") throw QString("Unexpected char ")+ch+" (code "+ch+"): was expecting double-quote to start field name or null";
|
||||||
|
skipSpace();
|
||||||
|
if(ch != ':') throw QString("Unexpected char ")+ch+" (code "+ch+"): was expecting a colon to separate field name and value";
|
||||||
|
skipSpace();
|
||||||
|
obj.insert(key, readValue());
|
||||||
|
skipSpace(); //ch有两种可能
|
||||||
|
if(ch=='}') return obj;
|
||||||
|
if(ch!=',') throw QString("Unexpected char ")+ch+"' (code "+ch+"): was expecting } to end Object or comma to separate Object entries";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ch=='[') {
|
||||||
|
JArray list;
|
||||||
|
while(true) {
|
||||||
|
do skipSpace(); //ch有三种可能
|
||||||
|
while(ch==',');
|
||||||
|
if(ch==']') return list;
|
||||||
|
list->push_back(readValue());
|
||||||
|
skipSpace(); //ch有两种可能
|
||||||
|
if(ch==']') return list;
|
||||||
|
if(ch!=',') throw QString("Unexpected char ")+ch+" (code "+ch+"): was expecting ] to end Array or comma to separate Array entries";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ch=='"') return readStr();
|
||||||
|
if((ch>='0' && ch<='9') || ch=='-') {
|
||||||
|
QString buf;
|
||||||
|
buf += ch;
|
||||||
|
bool isInt = true;
|
||||||
|
while(0 != (ch = readOne(in))) {
|
||||||
|
if((ch>'*' && ch<':' && ch!=',' && ch!='/') || ch=='e' || ch=='E') {
|
||||||
|
buf.append(ch);
|
||||||
|
if(isInt && ch=='.') isInt = false;
|
||||||
|
} else {
|
||||||
|
bk = ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
if(isInt) {
|
||||||
|
auto num = buf.toLongLong(&ok);
|
||||||
|
if(! ok) throw "Illegal number: "+buf;
|
||||||
|
return num;
|
||||||
|
} else {
|
||||||
|
auto num = buf.toDouble(&ok);
|
||||||
|
if(! ok) throw "Illegal number: "+buf;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ch=='n') {
|
||||||
|
if(in.read(3)=="ull") return JValue();
|
||||||
|
else throw "Unexpected char n: expected null";
|
||||||
|
}
|
||||||
|
if(ch=='t') {
|
||||||
|
if(in.read(3)=="rue") return true;
|
||||||
|
else throw "Unexpected char t: expected true";
|
||||||
|
}
|
||||||
|
if(ch=='f') {
|
||||||
|
if(in.read(4)=="alse") return false;
|
||||||
|
else throw "Unexpected char f: expected false";
|
||||||
|
}
|
||||||
|
throw QString("Unexpected char ")+ch+" (code "+ch+"): expected {}, [], \"string\", number, null, true or false";
|
||||||
|
}
|
||||||
|
QString JParser::readStr() {
|
||||||
|
QString buf;
|
||||||
|
while((ch = readOne(in)) != '"') {
|
||||||
|
if(ch==0) throw "Unexpected end-of-input: was expecting closing quote for string";
|
||||||
|
if(ch=='\\') {
|
||||||
|
in>>ch;
|
||||||
|
if(ch==0) throw "Unexpected end-of-input in char escape sequence";
|
||||||
|
if(ch=='"' || ch=='\\' || ch=='/') buf.append(ch);
|
||||||
|
else if(ch=='n') buf.append('\n');
|
||||||
|
else if(ch=='r') buf.append('\r');
|
||||||
|
else if(ch=='t') buf.append('\t');
|
||||||
|
else if(ch=='f') buf.append('\f');
|
||||||
|
else if(ch=='b') buf.append('\b');
|
||||||
|
else if(ch=='u') {
|
||||||
|
auto hex = in.read(4);
|
||||||
|
if(hex.size()<4) throw "Unexpected end-of-input in char escape sequence";
|
||||||
|
bool ok;
|
||||||
|
buf.append(hex.toUShort(&ok, 16));
|
||||||
|
if(! ok) throw "Illegal hex-digits in char escape sequence: \\u"+hex;
|
||||||
|
} else throw QString("Unrecognized char-escape ")+ch+" (code "+ch+")";
|
||||||
|
} else buf.append(ch);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
void JParser::skipSpace() {
|
||||||
|
if(bk.unicode()) {
|
||||||
|
bk = QChar::Null;
|
||||||
|
if(! ch.isSpace()) return;
|
||||||
|
}
|
||||||
|
in.skipWhiteSpace();
|
||||||
|
in >> ch;
|
||||||
|
if(ch==0) throw "Unexpected end-of-input";
|
||||||
|
}
|
||||||
|
|
||||||
|
void JOut::write(const JValue &value) {
|
||||||
|
if(value.type==JValue::Null) out << "null";
|
||||||
|
else if(value.type==JValue::Str) writeStr(value.toStr());
|
||||||
|
else if(value.type==JValue::Obj) writeMap(value.toObj());
|
||||||
|
else if(value.type==JValue::Array) writeList(value.toArray());
|
||||||
|
else out << value.toStr();
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
void JOut::writeStr(const QString &str) {
|
||||||
|
out << '"';
|
||||||
|
QChar ch;
|
||||||
|
for(int i=0; i<str.length(); i++) {
|
||||||
|
ch = str[i];
|
||||||
|
if(ch=='"'||ch=='\\') out<<'\\'<<ch;
|
||||||
|
else if(ch < ' ') {
|
||||||
|
if(ch=='\n') out<<"\\n";
|
||||||
|
else if(ch=='\r') out<<"\\r";
|
||||||
|
else if(ch=='\t') out<<"\\t";
|
||||||
|
else if(ch=='\f') out<<"\\f";
|
||||||
|
else if(ch=='\b') out<<"\\b";
|
||||||
|
else {
|
||||||
|
out<<"\\u00";
|
||||||
|
auto aa = QString::number(ch.unicode(), 16);
|
||||||
|
if(aa.size()==1) out<<'0';
|
||||||
|
out<<aa;
|
||||||
|
}
|
||||||
|
} else out << ch;
|
||||||
|
}
|
||||||
|
out << '"';
|
||||||
|
}
|
||||||
|
void JOut::writeMap(const JObj &map) {
|
||||||
|
out << '{';
|
||||||
|
if(! map.empty()) {
|
||||||
|
if(indent.size()) {
|
||||||
|
out << '\n';
|
||||||
|
cnt++;
|
||||||
|
for(int c=0; c<cnt; c++) out << indent;
|
||||||
|
}
|
||||||
|
bool addSep = false;
|
||||||
|
for(const auto &pair : map) {
|
||||||
|
if(addSep) {
|
||||||
|
out << ',';
|
||||||
|
if(indent.size()) {
|
||||||
|
out << '\n';
|
||||||
|
for(int c=0; c<cnt; c++) out << indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else addSep = true;
|
||||||
|
out << '"' << pair.first << "\":";
|
||||||
|
if(indent.size()) out << ' ';
|
||||||
|
write(pair.second);
|
||||||
|
}
|
||||||
|
if(indent.size()) {
|
||||||
|
out << '\n';
|
||||||
|
cnt--;
|
||||||
|
for(int c=0; c<cnt; c++) out << indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << '}';
|
||||||
|
}
|
||||||
|
void JOut::writeList(const JArray &vals) {
|
||||||
|
out << '[';
|
||||||
|
auto iter = vals.begin();
|
||||||
|
auto end = vals.end();
|
||||||
|
if(iter!=end) write(*iter++);
|
||||||
|
while(iter!=end) {
|
||||||
|
out << ',';
|
||||||
|
if(indent.size()) out << ' ';
|
||||||
|
write(*iter++);
|
||||||
|
}
|
||||||
|
out << ']';
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
JValue(const void *) = delete; // avoid implicit conversions from char * to bool
|
||||||
|
};
|
||||||
|
|
||||||
|
class JParser {
|
||||||
|
public:
|
||||||
|
JParser(QTextStream &in) : in(in) {}
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
|
||||||
|
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
|
|
@ -5,16 +5,16 @@
|
||||||
|
|
||||||
const char *const FormBoundary = "----GangphonQtBoundary_.oOo._";
|
const char *const FormBoundary = "----GangphonQtBoundary_.oOo._";
|
||||||
|
|
||||||
QNetworkAccessManager &netAccess() {
|
QNetworkAccessManager *netAccess() {
|
||||||
static QNetworkAccessManager access;
|
static QNetworkAccessManager access;
|
||||||
return access;
|
return &access;
|
||||||
};
|
};
|
||||||
|
|
||||||
QString errStr(QNetworkReply *reply) {
|
QString errStr(QNetworkReply *reply) {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
auto error = reply->error();
|
auto error = reply->error();
|
||||||
if(error != QNetworkReply::NoError) {
|
if(error != QNetworkReply::NoError) {
|
||||||
if(error==QNetworkReply::OperationCanceledError) return QString(QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(QNetworkReply::TimeoutError))+" ("+QString::number(QNetworkReply::TimeoutError)+") "+QCoreApplication::translate("Net","Connection Timeout");
|
if(error==QNetworkReply::OperationCanceledError) return "TimeoutError ("+QString::number(QNetworkReply::TimeoutError)+") "+QCoreApplication::translate("Net","Connection Timeout");
|
||||||
auto errStr = reply->errorString();
|
auto errStr = reply->errorString();
|
||||||
if(error!=QNetworkReply::InternalServerError || ! errStr.endsWith("replied: Unknown")) return QString(QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(error))+" ("+QString::number(error)+") "+errStr;
|
if(error!=QNetworkReply::InternalServerError || ! errStr.endsWith("replied: Unknown")) return QString(QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(error))+" ("+QString::number(error)+") "+errStr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,38 @@
|
||||||
|
|
||||||
extern const char *const FormBoundary;
|
extern const char *const FormBoundary;
|
||||||
|
|
||||||
QNetworkAccessManager &netAccess();
|
QNetworkAccessManager *netAccess();
|
||||||
|
|
||||||
class NetReq : public QNetworkRequest {
|
class NetReq : public QNetworkRequest {
|
||||||
public:
|
public:
|
||||||
|
#if(QT_VERSION_MAJOR > 5)
|
||||||
|
using QNetworkRequest::QNetworkRequest;
|
||||||
|
explicit NetReq(const QString &url) : QNetworkRequest{url} {};
|
||||||
|
explicit NetReq(QNetworkAccessManager *access) : mAccess(access) {};
|
||||||
|
#else
|
||||||
NetReq() {init();};
|
NetReq() {init();};
|
||||||
explicit NetReq(const QString &url) : QNetworkRequest{url} {init();};
|
explicit NetReq(QNetworkAccessManager *access) : mAccess(access) {init();};
|
||||||
explicit NetReq(const QUrl &url) : QNetworkRequest{url} {init();};
|
explicit NetReq(const QUrl &url) : QNetworkRequest{url} {init();};
|
||||||
NetReq(const QNetworkRequest &other) : QNetworkRequest{other} {init();};
|
|
||||||
|
|
||||||
inline void init() {
|
inline void init() {
|
||||||
#if(QT_VERSION_MAJOR < 6)
|
|
||||||
setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
using QNetworkRequest::url;
|
||||||
|
inline NetReq &url(const QUrl &url) {
|
||||||
|
setUrl(url);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline NetReq &access(QNetworkAccessManager *access) {
|
||||||
|
mAccess = access;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline NetReq &header(const QByteArray &headerName, const QByteArray &value) {
|
||||||
|
setRawHeader(headerName, value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline NetReq &header(KnownHeaders header, const QVariant &value) {
|
||||||
|
setHeader(header, value);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline NetReq &type(const QByteArray &value) {
|
inline NetReq &type(const QByteArray &value) {
|
||||||
|
@ -37,14 +56,16 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QNetworkReply *get() {
|
inline QNetworkReply *get() {
|
||||||
return netAccess().get(*this);
|
if(mAccess==0) mAccess = netAccess();
|
||||||
|
return mAccess->get(*this);
|
||||||
}
|
}
|
||||||
inline QNetworkReply *post(const QByteArray &data) {
|
inline QNetworkReply *post(const QByteArray &data) {
|
||||||
return netAccess().post(*this, data);
|
if(mAccess==0) mAccess = netAccess();
|
||||||
|
return mAccess->post(*this, data);
|
||||||
}
|
}
|
||||||
inline QNetworkReply *post(const QJsonDocument &json) {
|
inline QNetworkReply *post(const QJsonDocument &json) {
|
||||||
setRawHeader("Content-Type", "application/json");
|
setRawHeader("Content-Type", "application/json");
|
||||||
return netAccess().post(*this, json.toJson(QJsonDocument::Compact));
|
return post(json.toJson(QJsonDocument::Compact));
|
||||||
}
|
}
|
||||||
inline QNetworkReply *post(const QJsonObject &json) {
|
inline QNetworkReply *post(const QJsonObject &json) {
|
||||||
return post(QJsonDocument{json});
|
return post(QJsonDocument{json});
|
||||||
|
@ -53,13 +74,20 @@ public:
|
||||||
return post(QJsonDocument{json});
|
return post(QJsonDocument{json});
|
||||||
}
|
}
|
||||||
inline QNetworkReply *post(QHttpMultiPart *multiPart) {
|
inline QNetworkReply *post(QHttpMultiPart *multiPart) {
|
||||||
return netAccess().post(*this, multiPart);
|
if(mAccess==0) mAccess = netAccess();
|
||||||
|
return mAccess->post(*this, multiPart);
|
||||||
}
|
}
|
||||||
|
QNetworkAccessManager *mAccess{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
QString errStr(QNetworkReply *);
|
QString errStr(QNetworkReply *);
|
||||||
QString errStrWithData(QNetworkReply *, QJsonDocument * = 0);
|
QString errStrWithData(QNetworkReply *, QJsonDocument * = 0);
|
||||||
|
|
||||||
|
inline int waitFinished(QNetworkReply *reply, bool excludeUser = false) {
|
||||||
|
QEventLoop loop;
|
||||||
|
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||||
|
return excludeUser ? loop.exec(QEventLoop::ExcludeUserInputEvents) : loop.exec();
|
||||||
|
}
|
||||||
inline void abortSilence(QNetworkReply *reply) {
|
inline void abortSilence(QNetworkReply *reply) {
|
||||||
reply->blockSignals(true);
|
reply->blockSignals(true);
|
||||||
reply->abort();
|
reply->abort();
|
||||||
|
|
|
@ -143,7 +143,7 @@ void SendProgThread::run() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while(remain > 0) {
|
while(remain > 0) {
|
||||||
auto readed = file->read(qMin(4096LL, remain));
|
auto readed = file->read(qMin(4*4096LL, remain));
|
||||||
if(readed.isEmpty()) {
|
if(readed.isEmpty()) {
|
||||||
emit emErr(tr("Read file failed")+" "+file->errorString());
|
emit emErr(tr("Read file failed")+" "+file->errorString());
|
||||||
tcp.close();
|
tcp.close();
|
||||||
|
|
|
@ -124,21 +124,10 @@ QBrush Tools::getBrush(const QColor& color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Tools::color2Int(const QColor& color) {
|
int Tools::color2Int(const QColor& color) {
|
||||||
int res = 0;
|
return color.red() << 24 | color.green() << 16 | color.blue() << 8 | color.alpha();
|
||||||
res |= (color.red() & 0xFF) << 24;
|
|
||||||
res |= (color.green() & 0xFF) << 16;
|
|
||||||
res |= (color.blue() & 0xFF) << 8;
|
|
||||||
res |= (color.alpha() & 0xFF);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor Tools::int2Color(int value) {
|
QColor Tools::int2Color(int value) {
|
||||||
QColor res;
|
return QColor((value >> 24) & 0xff, (value >> 16) & 0xff, (value >> 8) & 0xff, value & 0xff);
|
||||||
res.setRed ((value >> 24) & 0xFF);
|
|
||||||
res.setGreen((value >> 16) & 0xFF);
|
|
||||||
res.setBlue ((value >> 8) & 0xFF);
|
|
||||||
res.setAlpha((value ) & 0xFF);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Tools::selectStr(bool f, const QString &s0, const QString &s1) {
|
QString Tools::selectStr(bool f, const QString &s0, const QString &s1) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user