Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit 41113c07 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

WIP add cache to QJsonReader using QVariant

parent 7e92d744
......@@ -399,6 +399,8 @@ struct IBind {
virtual bool _bind( const char* u) = 0;
virtual bool _any() { return _null(); }
//! \warning QMetaData is ignored by default and subject to various interpretation, so users should define or adopt existing meta data standards like XSD for sake of interoperability
virtual void _meta(QMetaData&) {}
......@@ -513,8 +515,6 @@ struct IWriter : public IBind
virtual bool _bind(const float& r) { float copy(r); return _bind(std::move(copy)); }
virtual bool _bind(const double& r) { double copy(r); return _bind(std::move(copy)); }
virtual bool _bind(const QByteArray& r) { QByteArray copy(r); return _bind(std::move(copy)); }
virtual bool _any() { return _null(); }
};
//! Base IBind implementations with BindMode::Read
......@@ -531,12 +531,12 @@ struct IReader : public IBind
virtual bool _bind(QUtf8String& u) = 0;
virtual bool _bind( QString& s) { QUtf8String u; if (!_bind(u)) return false; s=QString::fromUtf8(u); return true; }
virtual bool _bind( bool& b) { QUtf8String u; if (!_bind(u)) return false; if (u.toLower()=="true") { b=true; } else if (u.toLower()=="false") { b=false; } else { _reportError(qBindExpectedBoolean); return false; } return true; }
virtual bool _bind( qint8& n) { qint64 l; if (!_bind(l)|| l<std::numeric_limits< qint8>::min() || std::numeric_limits< qint8>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= qint8(l); return true; }
virtual bool _bind( quint8& n) { quint64 l; if (!_bind(l)|| std::numeric_limits< quint8>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= quint8(l); return true; }
virtual bool _bind( qint16& n) { qint64 l; if (!_bind(l)|| l<std::numeric_limits< qint16>::min() || std::numeric_limits< qint16>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= qint16(l); return true; }
virtual bool _bind( quint16& n) { quint64 l; if (!_bind(l)|| std::numeric_limits<quint16>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n=quint16(l); return true; }
virtual bool _bind( qint32& n) { qint64 l; if (!_bind(l)|| l<std::numeric_limits< qint32>::min() || std::numeric_limits< qint32>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= qint32(l); return true; }
virtual bool _bind( quint32& n) { quint64 l; if (!_bind(l)|| std::numeric_limits<quint32>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n=quint32(l); return true; }
virtual bool _bind( qint8& n) { qint64 l; if (!_bind(l)) return false; if (l<std::numeric_limits< qint8>::min() || std::numeric_limits< qint8>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= qint8(l); return true; }
virtual bool _bind( quint8& n) { quint64 l; if (!_bind(l)) return false; if ( std::numeric_limits< quint8>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= quint8(l); return true; }
virtual bool _bind( qint16& n) { qint64 l; if (!_bind(l)) return false; if (l<std::numeric_limits< qint16>::min() || std::numeric_limits< qint16>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= qint16(l); return true; }
virtual bool _bind( quint16& n) { quint64 l; if (!_bind(l)) return false; if ( std::numeric_limits<quint16>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n=quint16(l); return true; }
virtual bool _bind( qint32& n) { qint64 l; if (!_bind(l)) return false; if (l<std::numeric_limits< qint32>::min() || std::numeric_limits< qint32>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n= qint32(l); return true; }
virtual bool _bind( quint32& n) { quint64 l; if (!_bind(l)) return false; if ( std::numeric_limits<quint32>::max()<l) { _reportError(qBindExpectedSmallerNumber); return false; } n=quint32(l); return true; }
virtual bool _bind( qint64& n) { QUtf8String s; if (!_bind(s)) return false; bool isOk=false; qint64 v; v=s.toLongLong (&isOk); if (isOk) { n=v; return true; } _reportError(qBindExpectedDecimal); return false; }
virtual bool _bind( quint64& n) { QUtf8String s; if (!_bind(s)) return false; bool isOk=false; quint64 v; v=s.toULongLong(&isOk); if (isOk) { n=v; return true; } _reportError(qBindExpectedDecimal); return false; }
virtual bool _bind( float& n) { QUtf8String s; if (!_bind(s)) return false; bool isOk=false; float v; v=s.toFloat (&isOk); if (isOk) { n=v; return true; } _reportError(qBindExpectedDecimal); return false; }
......@@ -592,8 +592,15 @@ struct IReader : public IBind
|| _null () ) {
return true;
};
bool b; // usually easier to check than types below
double d; // matches most used numbers more easily than types below
qint64 i; // matches most used integrals more easily than types below
quint64 u;
if (_bind(b) || _bind(d) || _bind(i) || _bind(u)) {
return true;
}
_setChoice(false);
QString s;
QString s; // matches any type with usually less encoding work than QUtf8String (which only captures efficiently utf-8 whereas QChar easily captures Latin1 in addition to ASCII)
return _bind(s);
}
};
......@@ -857,7 +864,7 @@ struct QBind<QColor> {
};
// --------------------------------------------------------------------------
// QBind specialization for generic Val<Cursor> for a fixed set of possibly BindNative types
// QBind<Val<Cursor>> for the set of IBind's BindNative types
template<> //!< \remark Enumerating types where BindSupport<_,Cur<TImpl>> = BindNative with C++11 seems hard, so we just handle the set of default IBind BindNative types
struct QBind<Val<Cursor>> {
......
......@@ -57,40 +57,42 @@ class QJsonBuilder : public IWriter
Q_DISABLE_COPY(QJsonBuilder)
public:
QJsonBuilder(QJsonValue* v) : json(v) { Q_ASSERT(v); }
void reset(QJsonValue* v) { json=v; Q_ASSERT(v); steps.clear(); }
// Shortcuts
/**/ Val<Cursor> value ( ) { return Cursor(this).value(); }
/**/ Seq<Cursor> sequence(quint32* s=nullptr) { return Cursor(this).value().sequence ( s); }
template<typename T> Cursor bind ( T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
bool _sequence(quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step(nullptr)); return true; }
bool _record (quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step("" )); return true; }
friend class QJsonReader; //!< Calls methods below to cachedItems out-of-order _item(s)
bool _sequence(quint32* s=nullptr) { Q_UNUSED(s); steps.push(Step(nullptr)); return true; }
bool _record (quint32* s=nullptr) { Q_UNUSED(s); steps.push(Step("" )); return true; }
bool _null ( ) { set(QJsonValue( )); return true; }
bool _bind ( const char* s) { set(QJsonValue(s)); return true; }
bool _bind ( const char* u) { set(QJsonValue(u)); return true; }
bool _bind ( bool&& b) { set(QJsonValue(b)); return true; }
bool _bind ( double&& d) { set(QJsonValue(d)); return true; }
bool _bind ( quint64&& n) { return _bind(double(n)); }
bool _bind ( qint64&& n) { return _bind(double(n)); }
bool _bind ( quint64&& n) { return _bind(double(n)); }
bool _bind ( qint64&& n) { return _bind(double(n)); }
bool _item(QName n) { levels.last().key=n ; return true; }
bool _item( ) { levels.last().key=nullptr; return true; }
bool _out ( ) { auto level = levels.pop(); set(!level.key.isNull() ? QJsonValue(level.object) : QJsonValue(level.array)); return true; }
bool _item(QName n) { steps.last().key=n ; return true; }
bool _item( ) { steps.last().key=nullptr; return true; }
bool _out ( ) { auto level = steps.pop(); set(!level.key.isNull() ? QJsonValue(level.object) : QJsonValue(level.array)); return true; }
private:
void set(const QJsonValue& v) {
if (levels.isEmpty()) {
if (steps.isEmpty()) {
*json = v;
}
else {
if (!levels.last().key.isNull())
levels.last().object[levels.last().key]=v;
if (!steps.last().key.isNull())
steps.last().object[steps.last().key]=v;
else
levels.last().array.append(v);
steps.last().array.append(v);
}
}
QJsonValue* json;
struct Step { QUtf8String key; /* TODO union */ QJsonObject object; QJsonArray array; Step(const char* k=nullptr) : key(k) {} };
QStack<Step> levels = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QJsonBuilderImpl is abandoned
QStack<Step> steps = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QJsonBuilderImpl is abandoned
};
// --------------------------------------------------------------------------
......@@ -100,6 +102,7 @@ class QJsonVisitor : public IReader
Q_DISABLE_COPY(QJsonVisitor)
public:
QJsonVisitor(const QJsonValue* v) : json(v) { Q_ASSERT(v); }
void reset(QJsonValue* v) { json=v; Q_ASSERT(v); steps.clear(); errors.clear(); }
struct Error { const char* error; QUtf8String path; template<class T> T bind(Val<T>&& value) { return value.bind(QUtf8String(error)+' '+path); } };
QVector<Error> errors;
......@@ -210,11 +213,13 @@ private:
// --------------------------------------------------------------------------
#include "QVariant_impl.h" // as cached value reader and writer for out-of-order item keys
class QJsonReader : public IReader
{
Q_DISABLE_COPY(QJsonReader)
public:
QJsonReader(QIODevice* io) : io(io) { Q_ASSERT(io); }
QJsonReader(QIODevice* io) : io(io), cacheWriter(&cachedValue), cacheReader(&cachedValue) { Q_ASSERT(io); }
struct Step { int index; const char* end; Step(int i=-1, const char* e=nullptr) : index(i), end(e) {} };
struct Error { const char* error; int line; int column; int index; template<class T> T bind(Val<T>&& value) { QUtf8String utf8(error); utf8.append(' ').append(QUtf8String::number(line)).append(':').append(QUtf8String::number(column)); return value.bind(utf8.constData()); } };
......@@ -225,73 +230,96 @@ public:
/**/ Seq<Cursor> sequence(quint32* s=nullptr) { return Cursor(this).value().sequence(s); }
template<typename T> Cursor bind ( T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
bool _sequence(quint32* =nullptr) { if (get('[', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"]")); return true; } _reportError(qBindExpectedSequence); return false; }
bool _record (quint32* =nullptr) { if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } _reportError(qBindExpectedRecord ); return false; }
bool _null ( ) { if (get('n', "[{\"ntf-0123456789.") &&
get('u', "[{\"" ) &&
get('l', "[{\"" ) &&
get('l', "[{\"" )) {
return true;
} else { _reportError(qBindExpectedNull); return false; } }
bool _bind ( QUtf8String& s) { QUtf8String u;
if ( get('"', "[{\"ntf-0123456789.")) { u.clear(); char c;
while ((c=getCharInString()) != '\0' ) { u.append(c); }
s=u;
return get('"');
} else { _reportError(qBindExpectedText); return false; } }
bool _bind ( QString& s) { QUtf8String u; if (_bind(u)) { s = QString::fromUtf8(u); return true; } return false; } // TODO Support user-defined QTextCodec
bool _bind ( bool& b) { if (get('t', "[{\"ntf-0123456789.") &&
get('r', "[{\"" ) &&
get('u', "[{\"" ) &&
get('e', "[{\"" )) { b=true;
return true;
} else
if (get('f', "[{\"ntf-0123456789.") &&
get('a', "[{\"" ) &&
get('l', "[{\"" ) &&
get('s', "[{\"" ) &&
get('e', "[{\"" )) { b=false;
return true;
} else { _reportError(qBindExpectedBoolean); return false; } }
bool _bind ( float& n) { double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { if ( d<double( std::numeric_limits<float >::min())||
double( std::numeric_limits<float >::max())<d) { n = float(d); return true; } _reportError(qBindExpectedSmallerNumber ); } return false; }
bool _bind ( double& n) { double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { n = d ; } return r; }
bool _bind ( quint64& t) { double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { if (!neg ) { t = i ; return true; } _reportError(qBindExpectedPositiveNumber); } return false; }
bool _bind ( qint64& t) { double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { if (!neg && quint64( std::numeric_limits<qint64>::max())<i) { t = qint64(i); return true; }
if ( neg && quint64(-std::numeric_limits<qint64>::min())<i) { t = -qint64(i); return true; } _reportError(qBindExpectedSmallerNumber ); } return false; }
bool _any ( ) { isChoice=true; QString t; double d; bool b; // FIXME Use QString instead of QByteArray
( (_sequence() && _out())
|| _null()
|| _bind(b)
|| _bind(d)
|| _bind(t) // including any other?
);
isChoice=false;
return true;
}
// TODO cache key:value pairs coming out of order wrt to T items() calls
bool _item(QUtf8String& k) { Step& level = levels.last();
bool _sequence(quint32* s=nullptr) { if (cached) { cacheLevel++; return cached->_sequence(s); }
if (get('[', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"]")); return true; } _reportError(qBindExpectedSequence); return false; }
bool _record (quint32* s=nullptr) { if (cached) { cacheLevel++; return cached->_record(s); }
if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } _reportError(qBindExpectedRecord ); return false; }
bool _null ( ) { if (cached) { cacheLevel++; return cached->_null() && cacheOut(); }
if (get('n', "[{\"ntf-0123456789.") &&
get('u', "[{\"" ) &&
get('l', "[{\"" ) &&
get('l', "[{\"" )) {
return true;
} else { _reportError(qBindExpectedNull); return false; } }
bool _bind ( QUtf8String& s) { if (cached) { cacheLevel++; return cached->_bind(s.constData()) && cacheOut(); }
QUtf8String u;
if ( get('"', "[{\"ntf-0123456789.")) { u.clear(); char c;
while ((c=getCharInString()) != '\0' ) { u.append(c); }
s=u;
return get('"');
} else { _reportError(qBindExpectedText); return false; } }
bool _bind ( QString& s) { QUtf8String u; if (_bind(u)) { s = QString::fromUtf8(u); return true; } return false; } // TODO Support user-defined QTextCodec
bool _bind ( bool& b) { if (cached) { cacheLevel++; return cached->_bind(bool(b)) && cacheOut(); }
if (get('t', "[{\"ntf-0123456789.") &&
get('r', "[{\"" ) &&
get('u', "[{\"" ) &&
get('e', "[{\"" )) { b=true;
return true;
} else
if (get('f', "[{\"ntf-0123456789.") &&
get('a', "[{\"" ) &&
get('l', "[{\"" ) &&
get('s', "[{\"" ) &&
get('e', "[{\"" )) { b=false;
return true;
} else { _reportError(qBindExpectedBoolean); return false; } }
bool _bind ( float& n) { if (cached) { cacheLevel++; return cached->_bind(double(n)) && cacheOut(); }
double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { if ( d<double( std::numeric_limits<float >::min())||
double( std::numeric_limits<float >::max())<d) { n = float(d); return true; } _reportError(qBindExpectedSmallerNumber ); } return false; }
bool _bind ( double& n) { if (cached) { cacheLevel++; return cached->_bind(double(n)) && cacheOut(); }
double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { n = d ; } return r; }
bool _bind ( quint64& t) { if (cached) { cacheLevel++; return cached->_bind(double(t)) && cacheOut(); }
double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { if (!neg ) { t = i ; return true; } _reportError(qBindExpectedPositiveNumber); } return false; }
bool _bind ( qint64& t) { if (cached) { cacheLevel++; return cached->_bind(double(t)) && cacheOut(); }
double d; quint64 i; bool neg; bool r=getNumber(d,i,neg); if (r) { if (!neg && quint64( std::numeric_limits<qint64>::max())<i) { t = qint64(i); return true; }
if ( neg && quint64(-std::numeric_limits<qint64>::min())<i) { t = -qint64(i); return true; } _reportError(qBindExpectedSmallerNumber ); } return false; }
bool cacheOut() { Q_ASSERT(cacheLevel>0);
cacheLevel--;
if (cacheLevel==1) { if (cached==&cacheWriter) { } cached=nullptr; }
if (cacheLevel==0) { cachedItems.clear(); }
return true; }
bool _out ( ) { if (cached) { return cached->_out() && cacheOut(); }
auto level = levels.pop();
while (get(',', level.end)) {
_any();
}
return get(*level.end, "}"); }
bool _item( QName u) { if (cached) { return cached->_item(u); }
QUtf8String s;
while (true) {
if (!_item(s)) return false;
if (u==s) return true;
if (cachedItems.contains(u)) {
cachedValue = cachedItems.take(u);
cacheReader.reset(&cachedValue);
cached = &cacheReader; // let outer Cursor drive QJsonReader depending on bound T
Q_ASSERT(cacheLevel<=1); cacheLevel = 1;
return true;
}
else {
cachedValue = QJsonValue();
cacheWriter.reset(&cachedValue);
if (!Cursor(this).value().bind(Cursor(&cacheWriter).value())) return false;
cachedItems.insert(s, cachedValue);
continue; // until error or u==s or
}
}}
bool _item(QUtf8String& k) { if (cached) { return cached->_item(k); }
Step& level = levels.last();
if (-1 < level.index && !get(',',level.end)) {
return false;
}
level.index++;
QString s;
if (!_bind(s)) return false;
k=s.toUtf8();
return get(':',level.end); }
bool _item( ) { Step& level = levels.last();
return _bind(k) && get(':',level.end); }
bool _item( ) { if (cached) { return cached->_item(); }
Step& level = levels.last();
if (-1 < level.index && !get(',',level.end)) {
return false;
}
level.index++;
return true; }
bool _out ( ) { auto level = levels.pop();
while (get(',', level.end)) {
_any();
}
return get(*level.end, "}"); }
bool _isOk() { return io; }
void _setChoice(bool v) { isChoice=v; }
......@@ -338,8 +366,7 @@ private:
return true;
}
qint8 getDigit(quint8 base = 10) { Q_ASSERT(0<base);
qint8 getDigit(quint8 base = 10) { Q_ASSERT(0<base);
qint8 digit;
if ( 0 <= (digit=nextChar()-'0' ) && digit < base && base <= 10) { getChar(); return digit; }
if (10 <= (digit=nextChar()-'a'+10) && digit < base && base <= 36) { getChar(); return digit; }
......@@ -404,6 +431,15 @@ private:
int line = 0, column = 0, index = -1;
QStack<Step> levels = QStack<Step>(); //!< dynamic context required to implement item() and report meaningful errors
bool isChoice = false;
// Read/Write caching of out-of-order item keys
quint8 cacheLevel = 0;
QMap<QUtf8String,QJsonValue> cachedItems ; //!< Only used if cacheLevel==1
QUtf8String cachedKey ; //!< Only used when cacheLevel==1
QJsonValue cachedValue ; //!< Only used AFTER --cacheLevel==1
IBind* cached = nullptr; //!< Only used when cacheLevel>=1 && key!=expectedKey
QJsonVisitor cacheReader ; //!< Only used as cached
QJsonBuilder cacheWriter ;
};
// //////////////////////////////////////////////////////////////////////////
......
......@@ -59,13 +59,14 @@ public:
/**/ Seq<Cursor> sequence(quint32* s=nullptr) { return Cursor(this).value().sequence ( s); }
template<typename T> Cursor bind ( T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
// TODO Support _meta to be able to cache and restitute all metadata as well as data+datatype
template<typename T>
bool _bind ( T&& t) { set(QVariant::fromValue(t)); return true; }
bool _bind ( const char* t) { set(QVariant (t)); return true; }
bool _null ( ) { set(QVariant ( )); return true; }
bool _bind ( T&& t) { set(QVariant::fromValue(t)); return true; }
bool _null ( ) { set(QVariant ( )); return true; }
bool _sequence(quint32* rows=nullptr) { Q_UNUSED(rows); levels.push(Step(nullptr)); return true; }
bool _record (quint32* cols=nullptr) { Q_UNUSED(cols); levels.push(Step("" )); return true; }
bool _sequence(quint32* =nullptr) { levels.push(Level(nullptr)); return true; }
bool _record (quint32* =nullptr) { levels.push(Level("" )); return true; }
bool _item(QName n) { levels.last().key=n ; return true; }
bool _item( ) { levels.last().key=nullptr; return true; }
......@@ -84,8 +85,8 @@ private:
}
QVariant* variant;
struct Step { QUtf8String key; /* TODO union */ QVariantMap object; QVariantList array; Step(const char* k=nullptr) : key(k) {} };
QStack<Step> levels = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QVariantBuilder is abandoned
struct Level { QUtf8String key; /* TODO union */ QVariantMap object; QVariantList array; Level(const char* k=nullptr) : key(k) {} };
QStack<Level> levels = QStack<Level>(); //!< minimal dynamic context to implement out() and ensure actual building in case QVariantBuilder is abandoned
};
// --------------------------------------------------------------------------
......@@ -102,39 +103,39 @@ public:
QUtf8String currentPath() {
QUtf8String path;
Q_FOREACH(Step s, steps) {
if (s.key) { path.append('{').append(s.key); }
else { path.append('[').append(QUtf8String::number(s.idx)); }
Q_FOREACH(Level l, levels) {
if (l.key) { path.append('{').append(l.key); }
else { path.append('[').append(QUtf8String::number(l.idx)); }
}
return path;
}
protected:
// TODO Support _meta to be able to cache and restitute all metadata as well as data+datatype
template<typename T>
bool _bind ( T& t) { if (current()->type()==qMetaTypeId<T>()) { t = current()->value<T>(); return true; } _reportError("Expected T" ); return false; }
bool _sequence(quint32* rows=nullptr) { Q_UNUSED(rows); if (current()->type()==QVariant::List ) { steps.push(Step()); return true; } _reportError(qBindExpectedSequence); return false; }
bool _record (quint32* cols=nullptr) { Q_UNUSED(cols); if (current()->type()==QVariant::Map ) { steps.push(Step()); return true; } _reportError(qBindExpectedRecord ); return false; }
bool _null ( ) { if (current()->isNull() ) { return true; } _reportError(qBindExpectedNull ); return false; }
bool _bind ( T& t) { if (current()->type()==qMetaTypeId<T>()) { t = current()->value<T>(); return true; } _reportError("Expected T" ); return false; }
bool _sequence(quint32* =nullptr) { if (current()->type()==QVariant::List ) { levels.push(Level()); return true; } _reportError(qBindExpectedSequence); return false; }
bool _record (quint32* =nullptr) { if (current()->type()==QVariant::Map ) { levels.push(Level()); return true; } _reportError(qBindExpectedRecord ); return false; }
bool _null ( ) { if (current()->isNull() ) { return true; } _reportError(qBindExpectedNull ); return false; }
bool _item(QUtf8String& k) { steps.last().key=k; return (steps.last().item = current(1)->toMap ().value(QString::fromUtf8(steps.last().key), QVariant())).isValid(); }
bool _item( ) { steps.last().idx++; return (steps.last().item = current(1)->toList().value( steps.last().idx , QVariant())).isValid(); }
bool _out ( ) { steps.pop() ; return true; }
bool _item(QUtf8String& k) { levels.last().key=k; return (levels.last().item = current(1)->toMap ().value(QString::fromUtf8(levels.last().key), QVariant())).isValid(); }
bool _item( ) { levels.last().idx++; return (levels.last().item = current(1)->toList().value( levels.last().idx , QVariant())).isValid(); }
bool _out ( ) { levels.pop() ; return true; }
bool _isOk() { return value; }
void _setChoice(bool v) { isChoice=v; }
void _reportError(const char* error) { if (!isChoice) errors.append(Error{ error, currentPath() }); }
private:
const QVariant* current(unsigned outer=0) const { return unsigned(steps.size())-outer <= 0 ? value : &(steps[unsigned(steps.size())-outer-1].item); }
const QVariant* current(unsigned outer=0) const { return unsigned(levels.size())-outer <= 0 ? value : &(levels[unsigned(levels.size())-outer-1].item); }
const QVariant* value;
struct Step { const char* key=nullptr; int idx=-1; QVariant item; Step() = default; };
QStack<Step> steps = QStack<Step>();
struct Level { const char* key=nullptr; int idx=-1; QVariant item; Level() = default; };
QStack<Level> levels;
bool isChoice = false;
};
// TODO BindNative other QVariant-supported types?
// //////////////////////////////////////////////////////////////////////////
// QBind<QVariant,_> example support for the fixed set of IBind's BindNative types + other convenient types
// QBind<QVariant> example support for the set of IBind's BindNative types + other convenient types
template<>
struct QBind<QVariant> {
......@@ -155,9 +156,6 @@ struct QBind<QVariant> {
if (src.type()==QVariant::Int ) return v.bind(src.value< int>());
if (src.type()==QVariant::Double ) return v.bind(src.value< double>());
// TODO convert builtin types which canConvert<QString>
// \sa QBind<Val<TDst>&&, TSrcResult, IsReader<TSrcResult>>
return v.null();
}
else { Q_ASSERT_X(false, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
......@@ -171,7 +169,7 @@ struct QBind<QVariant> {
};
//template<>
//struct QBind<QVariant&, Cursor, IsReader<Cursor>> { static Cursor bind(Val<Cursor>&& v, QVariant& dst) {
//struct QBind<QVariant, Cursor, IsReader<Cursor>> { static Cursor bind(Val<Cursor>&& v, QVariant& dst) {
// Cursor r;
// {
// QScopedChoice<Val<Cursor>> choice(src);
......@@ -187,3 +185,5 @@ struct QBind<QVariant> {
// if (!(r = src.null())) r.reportError("Expected boolean|decimal|text|sequence|record|null");
// /**/ dst = QVariant( ); return r;
//}};
// TODO convert builtin types which canConvert<QString>
......@@ -207,6 +207,7 @@ int main(int argc, char *argv[])
QVariant v;
b.open(QIODevice::ReadWrite);
QDataStream d(&b);
#if 0
GROUP("<builtin")
{
START {
......@@ -486,11 +487,12 @@ int main(int argc, char *argv[])
STOP("Writable>Json",QString::fromUtf8(b.buffer()));
}
GROUP_STOP
#endif
GROUP("Read+Write")
{
QBuffer json;
json.open(QIODevice::ReadOnly);
json.buffer() = "_{ \"names\": [ _\"John\" _, \"Doe\"] , \"height\":_1.75 , \"age\":null, \"phones\":[ \"+44 1234567\" , \"+44 2345678\" ], \"\":\"superfluous item\" _} ";
json.buffer() = "_{ \"names\": [ _\"John\" _, \"Doe\"] , \"age\":null, \"phones\":[ \"+44 1234567\" , \"+44 2345678\" ], \"\":\"superfluous item\", \"height\":_1.75 _} ";
QJsonValue v;
#if QT_VERSION>=QT_VERSION_CHECK(5,12,0)
QCborValue c;
......@@ -498,6 +500,7 @@ int main(int argc, char *argv[])
Person p;
QVector<QJsonReader ::Error> jsonReaderErrors ;
QVector<QJsonVisitor::Error> jsonVisitorErrors;
#if 0
START {
json.seek(0); b.seek(0); b.buffer().clear();
QJsonReader r(&json);
......@@ -512,6 +515,7 @@ int main(int argc, char *argv[])
jsonReaderErrors = r.errors;
}
STOP("Json>JsonValue",QString::fromUtf8(QJsonDocument(v.toObject()).toJson()+Text(jsonReaderErrors)));
#endif
START {
json.seek(0); p = {};
QJsonReader r(&json);
......@@ -519,6 +523,7 @@ int main(int argc, char *argv[])
jsonReaderErrors = r.errors;
}
STOP("Json>T",QString::fromUtf8(Text(p)+Text(jsonReaderErrors)))
#if 0
START {
v = QJsonValue();
QJsonBuilder(&v).bind(p);
......@@ -621,8 +626,10 @@ int main(int argc, char *argv[])
QCborWriter(&b).bind(v);
}
STOP("JsonValue>Cbor",QString::fromUtf8(b.buffer().toHex()));
#endif
}
GROUP_STOP
#if 0
{
QVector<Person> persons;
persons << person << person << person;
......@@ -647,5 +654,6 @@ int main(int argc, char *argv[])
QModelWriter(&m).meta({{qmSizes ,"4,4" }}).bind(transform);
}
}
#endif
return (fclose(samples)==0) &/*anyway*/ (fclose(results)==0);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment