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 0ef133dc authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

Added size to QName const char* ptr for safety and efficiency by

replacing a few strlen with constexpr QName(const char[Size])
parent bc4cdfc3
......@@ -40,10 +40,6 @@
#pragma once
#include <QtCore/qglobal.h>
#define Q_PROTECTED_COPY(Class) \
protected: \
Class(const Class &) noexcept = default; \
Class &operator=(const Class &) = delete;
#define Q_ENABLE_MOVE_DEFAULT(Class) \
Class ( ) noexcept = default; \
Class (Class&& o) noexcept = default; \
......@@ -55,38 +51,53 @@ protected: \
#include <QtCore/qbytearray.h>
//! Explicitely utf8 encoded string of char
//! \warning This implementation opportunistically uses inheritance whereas QBind only needs distinct types
//! for QString, QByteArray, and utf8 strings to avoid costly utf8-utf16 conversions and bytes-utf8 ambiguities
class QUtf8String : public QByteArray
{
public:
using QByteArray::QByteArray;
QUtf8String(const QByteArray& o) : QByteArray(o) {}
QUtf8String() : QByteArray() {}
const char* utf8() const { return constData() ; }
};
#include <QtCore/qmetatype.h>
Q_DECLARE_METATYPE(QUtf8String)
//! String literal explicitely utf8 encoded
using QName = const char*; // TODO Use std::string_view for convenience
#include <QtCore/qstring.h>
//! Read-only view of a string literal using a highly-interoperable, printable, subset of ASCII that is
//! compatible with utf8, latin1 and other ANSI codepages without transformation
//! \warning This implementation does not enforce input ASCII subset
class QName : public QLatin1String
{
public:
using QLatin1String::QLatin1String;
QName() : QLatin1String(nullptr) {}
template<int Size> constexpr QName(const char(&p)[Size]) : QName(p, Size-int(sizeof('\0'))) { /*Q_ASSERT(QtPrivate::isAscii(*this));*/ }
const char* latin1() const { return data() ; }
const char* utf8() const { return data() ; }
QUtf8String toUtf8() const { return QUtf8String(data()); }
};
// //////////////////////////////////////////////////////////////////////////
// Standard error names
static QName qBindExpectedNull = "Expected null" ;
static QName qBindExpectedSequence = "Expected sequence" ;
static QName qBindExpectedRecord = "Expected record" ;
static QName qBindExpectedText = "Expected text" ;
static QName qBindExpectedBytes = "Expected bytes" ;
static QName qBindExpectedInteger = "Expected integer" ;
static QName qBindExpectedDecimal = "Expected decimal" ;
static QName qBindExpectedSmallerNumber = "Expected smaller number" ;
static QName qBindExpectedPositiveNumber= "Expected positive number";
static QName qBindExpectedBoolean = "Expected boolean" ;
static QName qBindExpectedConstant = "Expected constant" ;
static QName qBindIgnoredItem = "Ignored item" ;
static QName qBindIgnoredItemName = "Ignored item name" ;
static QName qBindIgnoredCharacter = "Ignored character" ;
static QName qBindIgnoredBytes = "Ignored bytes" ;
static QName qBindExpectedNull ("Expected null" );
static QName qBindExpectedSequence ("Expected sequence" );
static QName qBindExpectedRecord ("Expected record" );
static QName qBindExpectedText ("Expected text" );
static QName qBindExpectedBytes ("Expected bytes" );
static QName qBindExpectedInteger ("Expected integer" );
static QName qBindExpectedDecimal ("Expected decimal" );
static QName qBindExpectedSmallerNumber ("Expected smaller number" );
static QName qBindExpectedPositiveNumber("Expected positive number");
static QName qBindExpectedBoolean ("Expected boolean" );
static QName qBindExpectedConstant ("Expected constant" );
static QName qBindIgnoredItem ("Ignored item" );
static QName qBindIgnoredItemName ("Ignored item name" );
static QName qBindIgnoredCharacter ("Ignored character" );
static QName qBindIgnoredBytes ("Ignored bytes" );
// //////////////////////////////////////////////////////////////////////////
// Standard meta data names
......@@ -103,28 +114,28 @@ class QMetaData : public std::vector<std::pair<QName,QUtf8String>>
{
public:
using vector::vector;
iterator find(QName n) { return std::find_if(begin(), end(), [n](std::pair<QName,QUtf8String>& item){ return strcmp(item.first, n)==0; }); }
iterator find(QName n) { return std::find_if(begin(), end(), [n](std::pair<QName,QUtf8String>& item){ return item.first==n; }); }
QUtf8String& operator[](QName n) { return find(n)->second; }
};
static QName qmDataStreamVersion = "qmDataStreamVersion"; //!< Allows IBind support of QDataStream
static QName qmDataStreamVersion("qmDataStreamVersion"); //!< Allows IBind support of QDataStream
// N-dimensional data structures for which specific IWriter may have optimized implementations
// BEWARE though that nested calls to IWriter are not guaranteed to follow the declared structure (this would prevent reusing general QBind functors for nested data structures)
//! Sequence of records can be implemented as table with columns below (record item names are always the same in a fixed order)
static QName qmColumns = "columns" ; //!< comma-separated names
static QName qmColumns ("columns" ); //!< comma-separated names
//! Sequence of nested non-empty sequences of definite sizes can be implemented as multi-dimensional array
static QName qmSizes = "sizes" ; //!< comma-separated natural numbers
static QName qmSizes ("sizes" ); //!< comma-separated natural numbers
//! Sequence of records where item(qmNodes) contains children can be implemented as trees
static QName qmChildren = "children"; //!< name of a sequence of records with recursively the same name
static QName qmChildren("children"); //!< name of a sequence of records with recursively the same name
//! Name of current data
static QName qmName = "name";
static QName qmName ("name" );
static QName qmColor = "color" ; //!< comma-separated names
static QName qmColor ("color" ); //!< comma-separated names
// //////////////////////////////////////////////////////////////////////////
// QBind<T,TResult>
......@@ -213,8 +224,8 @@ public:
/**/ Rec<T_> record ( quint32 s) { return record (&s); }
// Shortcuts
template<typename T> Seq<T_> operator<< ( T&& t) { return sequence().bind(std::forward<T>(t)); } // stream compatible
/**/ Rec<T_> record (QName n) { return meta({{qmName,n}}).record(); }
template<typename T> Seq<T_> operator<<( T&& t) { return sequence().bind(std::forward<T>(t)); } // stream compatible
/**/ Rec<T_> record (QName n) { return meta({{qmName,n.toUtf8()}}).record(); }
private:
Val<TResult> unsafeThis() noexcept { return Val<TResult>(outer->_unsafeCopy()); }
......@@ -338,8 +349,8 @@ public:
Val<Cur> value() noexcept { return Val<Cur>(std::move(*this)); }
void setChoice ( bool c) { if (impl) impl->_setChoice (c); }
void reportError(const char* e) { if (impl) impl->_reportError(e); }
void setChoice ( bool c) { if (impl) impl->_setChoice (c); }
void reportError(QName e) { if (impl) impl->_reportError(e); }
protected:
template<class T_> friend class Val; // enables calling methods below
template<class T_> friend class Seq;
......@@ -454,7 +465,7 @@ struct IBind {
virtual bool _bind( QByteArray&& r) = 0;
virtual bool _bind( QVariant&& r) = 0;
virtual bool _bind( const char* u) = 0;
virtual bool _bind( const char* u8) = 0;
virtual bool _any() { return _null(); }
......@@ -462,7 +473,7 @@ struct IBind {
virtual void _meta(QMetaData&) {}
virtual void _setChoice(bool) {}
virtual void _reportError(const char*) {}
virtual void _reportError(QName) {}
};
template<> struct BindSupport<const char*> : BindNative {};
......@@ -523,7 +534,7 @@ struct IWriter : public IBind
virtual bool _item( ) = 0;
virtual bool _item( QName n) = 0;
virtual bool _item(QUtf8String& n) { return _item(n.constData()); }
virtual bool _item(QUtf8String& n) { return _item(QName(n)); }
//! End of sequence or record
//! Few IWriter need to process this (contiguous IWriter need to mark the end of indefinite sequences and records for instance)
......@@ -568,7 +579,7 @@ struct IWriter : public IBind
QAssociativeIterable::const_iterator i = ts.begin();
const QAssociativeIterable::const_iterator end = ts.end();
for ( ; i != end; ++i) {
if (!_item(i.key().toString().toUtf8().constData()) || !_bind(QVariant(*i))) {
if (!_item(QName(i.key().toString().toLatin1())) || !_bind(QVariant(*i))) {
return false;
}
}
......@@ -639,7 +650,7 @@ struct IReader : public IBind
virtual bool _item( ) = 0;
virtual bool _item(QUtf8String& n) = 0;
virtual bool _item( QName u) { QUtf8String s; return _item(s) && s==u; }
virtual bool _item( QName u) { QUtf8String s; return _item(s) && u==s; }
virtual bool _bind(QUtf8String& u) = 0;
virtual bool _bind( QString& s) { QUtf8String u; if (!_bind(u)) return false; s=QString::fromUtf8(u); return true; }
......@@ -704,7 +715,7 @@ struct IReader : public IBind
virtual bool _bind( QByteArray&& k) { QByteArray r; if (_bind(r) && k==r) return true; _reportError(qBindExpectedConstant); return false; }
virtual bool _bind( QVariant&& k) { QVariant r; if (_bind(r) && k==r) return true; _reportError(qBindExpectedConstant); return false; }
virtual bool _bind( const char* k) { QUtf8String r; if (_bind(r) && k==r) return true; _reportError(qBindExpectedConstant); return false; }
virtual bool _bind( const char* u8) { QUtf8String r; if (_bind(r) && u8==r) return true; _reportError(qBindExpectedConstant); return false; }
// TODO QStringView, QLatin1String(View), etc.
virtual bool _any() { _setChoice(true);
......@@ -828,13 +839,13 @@ template<class T, class TResult>
TResult qbind(Val<TResult>&& v, T* t) {
auto rw = v->mode();
auto mo = T::staticMetaObject;
auto r = v.record(mo.className());
auto r = v.record(QName(mo.className()));
for (int i = 0; i<mo.propertyCount(); i++) {
auto p = mo.property(i);
if (p.isStored()) {
if (rw==Read) {
QVariant pv;
r = r.bind(p.name(),pv);
r = r.bind(QName(p.name()),pv);
if (!r || !pv.isValid() || pv.isNull()) {
if (p.isResettable() && !p.resetOnGadget(t)) {
v->reportError(qBindIgnoredItem);
......@@ -855,7 +866,7 @@ TResult qbind(Val<TResult>&& v, T* t) {
v->reportError(qBindIgnoredItem);
}
else if (!pv.isNull()) {
auto i = r.item(p.name());
auto i = r.item(QName(p.name()));
if (p.isEnumType()) {
pv.convert(QVariant::Int);
i = i.meta({{qmName, p.isFlagType() ?
......
......@@ -122,7 +122,7 @@ protected:
if (Q_LIKELY(cols)) { putInteger (*cols , cbor::MapType ); }
else { putMajorValue(cbor::IndefiniteLength, cbor::MapType ); } return true; }
bool _null ( ) { putSimpleValue(cbor::Null ); return true; }
bool _bind ( const char* s) { auto size = qstrlen(s); putInteger(size, cbor::TextStringType); io->append(s, size); return true; }
bool _bind ( const char* u8) { auto size = qstrlen(u8); putInteger(size, cbor::TextStringType); io->append(u8, size); return true; }
bool _bind ( QString&& s) { QUtf8String u(s.toUtf8());
putInteger (quint64(u.size()), cbor::TextStringType); io->append(u); return true; }
//static const char mimeHeader[] = "Content-Type:text/plain;charset=utf-16\xD\xA\xD\xA";
......@@ -140,7 +140,7 @@ protected:
bool _bind ( qint64&& t) { if (t<0) { putInteger(quint64(-1-t), cbor::NegativeIntType); } // see https://tools.ietf.org/html/rfc7049#section-2.1
else { putInteger(quint64( t), cbor::UnsignedIntType); } return true; }
bool _item(QName n) { putInteger(qstrlen(n), cbor::TextStringType); io->append(n); return true; }
bool _item(QName n) { putInteger(n.size(), cbor::TextStringType); io->append(n.utf8()); return true; }
bool _item( ) { return true; }
bool _out ( ) { bool definite = levels.back(); levels.pop_back(); if (!definite) putSimpleValue(cbor::Break); return true; }
private:
......@@ -190,20 +190,20 @@ 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) { levels.push(Step(nullptr)); return true; }
bool _record (quint32* =nullptr) { levels.push(Step("" )); return true; }
bool _null ( ) { set(QCborValue( )); return true; }
bool _bind ( const char* s) { set(QCborValue(s)); return true; }
bool _bind ( bool&& b) { set(QCborValue(b)); return true; }
bool _sequence(quint32* =nullptr) { levels.push(Step( )); return true; }
bool _record (quint32* =nullptr) { levels.push(Step("")); return true; }
bool _null ( ) { set(QCborValue( )); return true; }
bool _bind ( const char* u8) { set(QCborValue( u8 )); return true; }
bool _bind ( bool&& b) { set(QCborValue( b )); return true; }
bool _bind ( float&& d) { set(QCborValue(double(d))); return true; }
bool _bind ( double&& d) { set(QCborValue(d)); return true; }
bool _bind ( double&& d) { set(QCborValue( d )); return true; }
bool _bind ( quint64&& n) { if (std::numeric_limits<qint64>::max()<n) { _reportError(qBindExpectedSmallerNumber); return false; }
set(QCborValue(qint64(n))); return true; }
bool _bind ( qint64&& n) { set(QCborValue(n)); return true; }
bool _bind ( QByteArray&& s) { set(QCborValue(s)); return true; }
bool _bind ( qint64&& n) { set(QCborValue( n )); return true; }
bool _bind ( QByteArray&& s) { set(QCborValue( s )); return true; }
bool _item(QName n) { levels.last().key=n ; return true; }
bool _item( ) { levels.last().key=nullptr; return true; }
bool _item( ) { levels.last().key=QName(); return true; }
bool _out ( ) { auto level = levels.pop(); set(!level.key.isNull() ? QCborValue(level.object) : QCborValue(level.array)); return true; }
private:
void set(const QCborValue& v) {
......@@ -212,14 +212,14 @@ private:
}
else {
if (!levels.last().key.isNull())
levels.last().object[QString::fromUtf8(levels.last().key)]=v;
levels.last().object[QString::fromLatin1(levels.last().key.latin1())]=v;
else
levels.last().array.append(v);
}
}
QCborValue* cbor;
struct Step { QUtf8String key; /* TODO union */ QCborMap object; QCborArray array; Step(const char* k=nullptr) : key(k) {} };
struct Step { QName key; /* TODO union */ QCborMap object; QCborArray array; Step(QName k=QName()) : key(k) {} };
QStack<Step> levels = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QCborBuilder is abandoned
};
......@@ -232,7 +232,7 @@ public:
QCborVisitor(QCborValue* v) : cbor(v) { Q_ASSERT(v); }
void reset(QCborValue* v) { cbor=v; Q_ASSERT(v); steps.resize(0); errors.resize(0); }
struct Error { const char* error; QUtf8String path; template<class T> T bind(Val<T>&& value) { return value.bind(QUtf8String(error)+' '+path); } };
struct Error { QName error; QUtf8String path; template<class T> T bind(Val<T>&& value) { return value.bind(QUtf8String(error.utf8())+' '+path); } };
QVector<Error> errors;
QUtf8String currentPath() {
......@@ -261,20 +261,20 @@ protected:
bool _bind ( double& v) { if (current().isDouble ()) { v = current().toDouble (); return true; } _reportError(qBindExpectedDecimal ); return false; }
bool _bind ( QByteArray& v) { QString s; if (current().isByteArray()) { v = current().toByteArray(); return true; } _reportError(qBindExpectedBytes ); return false; }
bool _item(QName k) { steps.last().key=k; return !(steps.last().item = current(1).toMap ().value(QString::fromUtf8(steps.last().key))).isUndefined(); }
bool _item(QUtf8String& k) { steps.last().key=k; return !(steps.last().item = current(1).toMap ().value(QString::fromUtf8(steps.last().key))).isUndefined(); }
bool _item( ) { steps.last().idx++; return !(steps.last().item = current(1).toArray(). at( steps.last().idx )).isUndefined(); }
bool _out ( ) { steps.pop() ; return true; }
bool _item(QName k) { steps.last().key= k ; return !(steps.last().item = current(1).toMap ().value(QString::fromLatin1(steps.last().key.latin1()))).isUndefined(); }
bool _item(QUtf8String& k) { steps.last().key=QName(k); return !(steps.last().item = current(1).toMap ().value(QString::fromLatin1(steps.last().key.latin1()))).isUndefined(); }
bool _item( ) { steps.last().idx++ ; return !(steps.last().item = current(1).toArray(). at( steps.last().idx )).isUndefined(); }
bool _out ( ) { steps.pop() ; return true; }
bool _isOk() { return cbor; }
void _setChoice(bool v) { isChoice=v; }
void _reportError(const char* e) { if (!isChoice)
void _reportError(QName e) { if (!isChoice)
errors.append(Error{ e, currentPath() }); }
private:
const QCborValue& current(int outer=0) const { Q_ASSERT(0<=outer); return steps.size()-outer <= 0 ? *cbor : steps[steps.size()-outer-1].item; }
QCborValue* cbor;
struct Step { QUtf8String key; int idx=-1; QCborValue item; Step() = default; };
struct Step { QName key; int idx=-1; QCborValue item; Step() = default; };
QStack<Step> steps = QStack<Step>();
bool isChoice = false;
};
......@@ -290,7 +290,7 @@ class QCborReader : public IReader, public QCborStreamReader
public:
QCborReader(QIODevice* io) : QCborStreamReader(io), cacheVisitor(&cachedValue) { Q_ASSERT(io); }
struct Error { const char* error; qint64 index; QCborError cborError; template<class T> T bind(Val<T>&& value) { QUtf8String utf8(error); utf8.append(' ').append(QUtf8String::number(index)); return value.bind(utf8.constData()); } };
struct Error { QName error; qint64 index; QCborError cborError; template<class T> T bind(Val<T>&& value) { QUtf8String utf8(error.utf8()); utf8.append(' ').append(QUtf8String::number(index)); return value.bind(utf8.constData()); } };
QVector<Error> errors;
// Shortcuts
......@@ -368,8 +368,8 @@ protected:
bool _item( QName u) { if (caching) { return caching->_item(u); }
QUtf8String s;
while (true) {
if (levels.last().cachedItems.contains(u)) { // must be checked before we consume _item(s)
cachedValue = levels.last().cachedItems.take(u);
if (levels.last().cachedItems. contains(u.utf8())) { // must be checked before we consume _item(s)
cachedValue = levels.last().cachedItems.take(u.utf8());
Q_ASSERT(!cacheLevel);
if (!device()->isSequential()) {
cachingAfter = device()->pos();
......@@ -430,7 +430,7 @@ protected:
bool _any() { return next(); }
bool _isOk() { return lastError()==QCborError::NoError; }
void _setChoice(bool b) { isChoice = b; }
void _reportError(const char* e) { if (!isChoice) errors.append(Error{ e, currentOffset(), lastError() }); }
void _reportError(QName e) { if (!isChoice) errors.append(Error{ e, currentOffset(), lastError() }); }
private:
void skipTag() { if (isTag()) next(); }
bool getNumber(double& d) { skipTag();
......@@ -552,7 +552,7 @@ struct QBind<QCborMap, TResult> {
quint32 size=quint32(j.size());
auto s(v.record(&size));
for (QCborValue key : j.keys()) {
s = s.bind(key.toString().toUtf8().constData(),QCborValue(j[key]));
s = s.bind(QName(key.toString().toUtf8()),QCborValue(j[key])); // TODO directly use toUtf8 to remove utf8>utf16>utf8 encoding
}
return s;
}
......
......@@ -72,7 +72,7 @@ protected:
bool _sequence(quint32* s=nullptr) { if (s) *io << *s; return true; }
bool _record (quint32* s=nullptr) { if (s) *io << *s; return true; }
bool _null ( ) { *io << nullptr; return true; }
bool _bind ( const char* s) { QByteArray ba = QByteArray::fromRawData(s, int(qstrlen(s)+sizeof('\0'))); return _bind(ba); }
bool _bind ( const char* u8) { QByteArray ba = QByteArray::fromRawData(u8, int(qstrlen(u8)+sizeof('\0'))); return _bind(ba); }
template<typename T>
bool _bind ( T&& t) { *io << t; return true; }
......
......@@ -65,17 +65,17 @@ public:
template<typename T> Cursor bind ( T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
friend class QJsonReader; //!< Calls methods below for out-of-order cachedItems
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* 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 _sequence(quint32* s=nullptr) { Q_UNUSED(s); steps.push(Step( )); 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* u8) { set(QJsonValue(u8)); 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 _item(QName n) { steps.last().key=n ; return true; }
bool _item( ) { steps.last().key=nullptr; return true; }
bool _item( ) { steps.last().key=QName(); 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) {
......@@ -91,7 +91,7 @@ private:
}
QJsonValue* json;
struct Step { QUtf8String key; /* TODO union */ QJsonObject object; QJsonArray array; Step(const char* k=nullptr) : key(k) {} };
struct Step { QName key; /* TODO union */ QJsonObject object; QJsonArray array; Step(QName k=QName()) : key(k) {} };
QStack<Step> steps = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QJsonBuilderImpl is abandoned
};
......@@ -104,7 +104,7 @@ public:
QJsonVisitor(const QJsonValue* v) : json(v) { Q_ASSERT(v); }
void reset(QJsonValue* v) { json=v; Q_ASSERT(v); steps.resize(0); errors.resize(0); }
struct Error { const char* error; QUtf8String path; template<class T> T bind(Val<T>&& value) { return value.bind(QUtf8String(error)+' '+path); } };
struct Error { QName error; QUtf8String path; template<class T> T bind(Val<T>&& value) { return value.bind(QUtf8String(error.utf8())+' '+path); } };
QVector<Error> errors;
QUtf8String currentPath() {
......@@ -141,7 +141,7 @@ protected:
bool _isOk() { return true; }
void _setChoice(bool v) { isChoice=v; }
void _reportError(const char* e) { if (!isChoice) errors.append(Error{ e, currentPath() }); }
void _reportError(QName e) { if (!isChoice) errors.append(Error{ e, currentPath() }); }
private:
const QJsonValue& current(int outer=0) const { Q_ASSERT(0<=outer && json); return steps.size()-outer <= 0 ? *json : steps[steps.size()-outer-1].item; }
......@@ -171,7 +171,7 @@ protected:
bool _sequence(quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step{"","]"}); return io->write("["); }
bool _record (quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step{"","}"}); return io->write("{"); }
bool _null ( ) { return io->write( "null" ); }
bool _bind ( const char* s) { return putString( s ); }
bool _bind ( const char* u8) { return putString( u8 ); }
// JSON literals
bool _bind ( bool&& n) { return io->write( n?"true":"false" ); }
bool _bind ( float&& n) { return io->write(QUtf8String::number(n,'g',std::numeric_limits< float>::max_digits10)); }
......@@ -179,8 +179,8 @@ protected:
bool _bind ( quint64&& t) { return io->write(QUtf8String::number(t)); }
bool _bind ( qint64&& t) { return io->write(QUtf8String::number(t)); }
bool _item(QName n) { auto r=(io->write(levels.last().sep) || *levels.last().sep=='\0') && putString(n) && io->write(":"); levels.last().sep = ","; return r; }
bool _item( ) { auto r=(io->write(levels.last().sep) || *levels.last().sep=='\0') ; levels.last().sep = ","; return r; }
bool _item(QName n) { auto r=(io->write(levels.last().sep) || *levels.last().sep=='\0') && putString(n.utf8()) && io->write(":"); levels.last().sep = ","; return r; }
bool _item( ) { auto r=(io->write(levels.last().sep) || *levels.last().sep=='\0') ; levels.last().sep = ","; return r; }
bool _out ( ) { return io->write(levels.pop() .end); }
private:
struct Step { const char* sep; const char* end; };
......@@ -228,7 +228,7 @@ public:
QJsonReader(QIODevice* io) : io(io), cacheWriter(&cachedValue), cacheReader(&cachedValue) { Q_ASSERT(io); }
struct Step { int index; const char* end; QMap<QUtf8String,QJsonValue/*TODO QVariant for meta() support*/> cachedItems; 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()); } };
struct Error { QName error; int line; int column; int index; template<class T> T bind(Val<T>&& value) { QUtf8String utf8(error.utf8()); utf8.append(' ').append(QUtf8String::number(line)).append(':').append(QUtf8String::number(column)); return value.bind(utf8); } };
QVector<Error> errors;
// Shortcuts
......@@ -321,8 +321,8 @@ protected:
bool _item( QName u) { if (caching) { return caching->_item(u); }
QUtf8String s;
while (true) {
if (levels.last().cachedItems.contains(u)) { // must be checked before we consume _item(s)
cachedValue = levels.last().cachedItems.take(u);
if (levels.last().cachedItems. contains(u.utf8())) { // must be checked before we consume _item(s)
cachedValue = levels.last().cachedItems.take(u.utf8());
cacheReader.reset(&cachedValue);
Q_ASSERT(!cacheLevel);
caching = &cacheReader; // let outer Cursor drive QJsonReader depending on bound T
......@@ -359,7 +359,7 @@ protected:
bool _isOk() { return io; }
void _setChoice(bool v) { isChoice=v; }
void _reportError(const char* e) { if (!isChoice) errors.append(Error{ e, line, column, index }); }
void _reportError(QName e) { if (!isChoice) errors.append(Error{ e, line, column, index }); }
private:
CachedNumber getNumber() {
if (cachedNumber!=None) return cachedNumber;
......@@ -569,7 +569,7 @@ struct QBind<QJsonObject, TResult> {
quint32 size=quint32(j.size());
auto s(v.record(&size));
for (QString key : j.keys()) {
s = s.bind(key.toUtf8().constData(),QJsonValue(j[key]));
s = s.bind(QName(key.toLatin1()),QJsonValue(j[key]));
}
return s;
}
......
......@@ -100,19 +100,19 @@ protected:
}
}
bool _null( ) { return hidden() ? true : I<=d ? w._null() : m->setData(current(), QVariant()); }
bool _null( ) { return hidden() ? true : I<=d ? w._null() : m->setData(current(), QVariant()); }
bool _bind(const char* s) { return hidden() ? true : I<=d ? w._bind(std::move(s)) : m->setData(current(), s ); }
bool _bind( bool&& b) { return hidden() ? true : I<=d ? w._bind(std::move(b)) : m->setData(current(), b ); }
bool _bind( float&& f) { return hidden() ? true : I<=d ? w._bind(std::move(f)) : m->setData(current(), f ); }
bool _bind( double&& f) { return hidden() ? true : I<=d ? w._bind(std::move(f)) : m->setData(current(), f ); }
bool _bind( quint64&& i) { return hidden() ? true : I<=d ? w._bind(std::move(i)) :
i<=quint64(std::numeric_limits<unsigned int>::max()) ? m->setData(current(), static_cast<unsigned int>(i)) // with QSpinBox delegate
: m->setData(current(), i ); }
bool _bind( qint64&& i) { return hidden() ? true : I<=d ? w._bind(std::move(i)) :
i<= qint64(std::numeric_limits< int>::max()) ? m->setData(current(), static_cast< int>(i)) // with QSpinBox delegate
: m->setData(current(), i ); }
bool _bind( QVariant&& t) { return hidden() ? true : I<=d ? static_cast<IWriter*>(&w)->_bind(QVariant(t)) : m->setData(current(), t); }
bool _bind(const char* u8) { return hidden() ? true : I<=d ? w._bind(std::move(u8)) : m->setData(current(), u8 ); }
bool _bind( bool&& b) { return hidden() ? true : I<=d ? w._bind(std::move( b)) : m->setData(current(), b ); }
bool _bind( float&& f) { return hidden() ? true : I<=d ? w._bind(std::move( f)) : m->setData(current(), f ); }
bool _bind( double&& f) { return hidden() ? true : I<=d ? w._bind(std::move( f)) : m->setData(current(), f ); }
bool _bind( quint64&& i) { return hidden() ? true : I<=d ? w._bind(std::move( i)) :
i<=quint64(std::numeric_limits<unsigned int>::max()) ? m->setData(current(), static_cast<unsigned int>(i)) // with QSpinBox delegate
: m->setData(current(), i ); }
bool _bind( qint64&& i) { return hidden() ? true : I<=d ? w._bind(std::move( i)) :
i<= qint64(std::numeric_limits< int>::max()) ? m->setData(current(), static_cast< int>(i)) // with QSpinBox delegate
: m->setData(current(), i ); }
bool _bind( QVariant&& t) { return hidden() ? true : I<=d ? static_cast<IWriter*>(&w)->_bind(QVariant(t)) : m->setData(current(), t); }
// TODO QDate*, QTime
// TODO QPixmap if metadata suggests a QMimeData image ?
......@@ -206,11 +206,11 @@ protected:
int i = m->columnCount();
m->insertColumn(i);
m->setHeaderData(i,Qt::Horizontal,n);
columnNames.insert(i,n);
columnNames.insert(i,n.utf8());
}
}
else {
col=columnNames.indexOf(n);
col=columnNames.indexOf(n.utf8());
// TODO if (max(dimension())<=col) col=-1;
if (col<0) {
_reportError(qBindIgnoredItem);
......
......@@ -60,12 +60,12 @@ public:
template<typename T> Cursor bind ( T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); }
protected:
template<typename T>
bool _bind ( T&& t) { settings->setValue(key(), QVariant::fromValue(t) ); return true; }
bool _bind ( quint8&& t) { settings->setValue(key(), QVariant (int(t))); return true; }
bool _bind ( quint16&& t) { settings->setValue(key(), QVariant (int(t))); return true; }
bool _bind ( quint32&& t) { settings->setValue(key(), QVariant (int(t))); return true; }
bool _bind (const char* u) { settings->setValue(key(), QVariant (u) ); return true; }
bool _null ( ) { settings->setValue(key(), QVariant ( ) ); return true; }
bool _bind ( T&& t) { settings->setValue(key(), QVariant::fromValue( t) ); return true; }
bool _bind ( quint8&& t) { settings->setValue(key(), QVariant (int( t))); return true; }
bool _bind ( quint16&& t) { settings->setValue(key(), QVariant (int( t))); return true; }
bool _bind ( quint32&& t) { settings->setValue(key(), QVariant (int( t))); return true; }
bool _bind (const char* u8) { settings->setValue(key(), QVariant (u8) ); return true; }
bool _null ( ) { settings->setValue(key(), QVariant ( ) ); return true; }
bool _sequence(quint32* =nullptr) { settings->beginGroup(key()); levels.push(Level( )); return true; }
bool _record (quint32* =nullptr) { settings->beginGroup(key()); levels.push(Level("")); return true; }
......@@ -82,7 +82,7 @@ private:
}
QSettings* settings;
struct Level { QName key; quint32 idx=0; Level(QName k=nullptr) : key(k) {} };
struct Level { QName key; quint32 idx=0; Level(QName k=QName()) : key(k) {} };
QStack<Level> levels = QStack<Level>(); //!< minimal dynamic context to implement out() and ensure actual building in case QSettingsWriter is abandoned