Commit 4a241b60 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

partial solution to:

- remove QBind::bind::overloads that do not allow both definitions to
coexist
- handle T&&, T& and const T& universally using perfect forwarding,
- factor out static_assert when QBind Read to const T&,
- factor out QBind Write const_cast<T&>
parent 17b56280
This diff is collapsed.
......@@ -126,11 +126,6 @@ protected:
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::DoublePrecisionFloat) && io->write(bytes, sizeof(bytes))); }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(const T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<class T_> friend class Seq; // calls methods below
bool _item(int min= 1) { Q_UNUSED(min); return true ; }
......@@ -152,3 +147,7 @@ private:
QIODevice* io = nullptr;
int levels = 0; //!< minimal dynamic context to ensure well-formedness in case TResult is abandoned
};
template<> struct BindSupport<CborWriter,const char*> : BindNative {};
template<> struct BindSupport<CborWriter,bool > : BindNative {};
template<> struct BindSupport<CborWriter,float > : BindNative {};
template<> struct BindSupport<CborWriter,double > : BindNative {};
......@@ -82,16 +82,11 @@ protected:
bool _sequence() { levels.push(Step(nullptr)); return true; }
bool _null() { set(QJsonValue( )); return true; }
bool _bind(const char* s) { set(QJsonValue(s)); return true; }
bool _bind(double d) { set(QJsonValue(d)); return true; }
bool _bind(bool b) { set(QJsonValue(b)); return true; }
bool _bind(double d) { set(QJsonValue(d)); return true; }
template<typename T> bool _bind(T t, std::enable_if_t<std::is_arithmetic<T>::value>* = nullptr) { return _bind(double(t)); }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(const T& t) { return QBind<QJsonBuilder,T>::bind(QJsonBuilder(this).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<QJsonBuilder,T>::bind(QJsonBuilder(this).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<QJsonBuilder,T>::bind(QJsonBuilder(this).value(), t ); }
template<class T_> friend class Seq; // calls methods below
bool _item(const char* key) { levels.last().key=key ; return true; }
......@@ -115,6 +110,12 @@ private:
QStack<Step> levels = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QJsonBuilderImpl is abandoned
};
QJsonBuilder::QJsonBuilder(QJsonValue* v) : QScopedResult(new QJsonBuilderImpl(v), true) {}
template<> struct BindSupport<QJsonBuilderImpl,const char*> : BindNative {};
template<> struct BindSupport<QJsonBuilderImpl,bool > : BindNative {};
template<> struct BindSupport<QJsonBuilderImpl,double > : BindNative {};
//template<typename T> struct BindSupport<QJsonBuilderImpl,std::enable_if_t<std::is_arithmetic<T>::value,T>> : BindNative {};
// --------------------------------------------------------------------------
class JsonVisitorImpl;
class QJsonVisitor : public QScopedResult<QJsonVisitor, JsonVisitorImpl, BindMode::Read>
......@@ -164,14 +165,10 @@ protected:
bool _record() { if (current()->isObject()) { steps.push(Step()); return true; } reportError(qBindExpectedRecord ); return false; }
bool _sequence() { if (current()->isArray ()) { steps.push(Step()); return true; } reportError(qBindExpectedSequence); return false; }
bool _bind(QString& v) { if (current()->isString()) { v = current()->toString(); return true; } reportError(qBindExpectedText ); return false; }
bool _bind( double& v) { if (current()->isDouble()) { v = current()->toDouble(); return true; } reportError(qBindExpectedDecimal ); return false; }
bool _bind( bool& v) { if (current()->isBool ()) { v = current()->toBool (); return true; } reportError(qBindExpectedBoolean ); return false; }
bool _bind( double& v) { if (current()->isDouble()) { v = current()->toDouble(); return true; } reportError(qBindExpectedDecimal ); return false; }
//template<typename T> bool _bind(T& t, std::enable_if_t<std::is_arithmetic<T>::value>* = nullptr) { double d; if (_bind(d)) { t = d; return true; } return false; }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(T& t) { return QBind<QJsonVisitor,T>::bind(Val<QJsonVisitor>(QJsonVisitor(this)), t); } // TODO check why .value() does not work
template<class T_> friend class Seq; // calls methods below
bool _item(const char* key) { steps.last().key=key; if (!(steps.last().item = current(1)->toObject().value(QString::fromUtf8(steps.last().key))).isUndefined()) { return true; } return false; }
......@@ -186,6 +183,12 @@ private:
bool isChoice = false;
};
QJsonVisitor::QJsonVisitor(const QJsonValue* v) : QScopedResult(new JsonVisitorImpl(v), true) {}
template<> struct BindSupport<JsonVisitorImpl,QString&> : BindNative {};
template<> struct BindSupport<JsonVisitorImpl,bool &> : BindNative {};
template<> struct BindSupport<JsonVisitorImpl,double &> : BindNative {};
// TODO template<> struct BindSupport<JsonVisitorImpl,std::enable_if_t<std::is_arithmetic<T>::value,T&> : BindNative {};
// --------------------------------------------------------------------------
class QJsonWriterImpl;
class QJsonWriter : public QScopedResult<QJsonWriter, QJsonWriterImpl, BindMode::Write>
......@@ -232,11 +235,6 @@ protected:
template<typename T> bool _bind(T t,std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value>* =nullptr) { return _bind(qulonglong(t)); }
template<typename T> bool _bind(T t,std::enable_if_t<std::is_integral<T>::value && std:: is_signed<T>::value>* =nullptr) { return _bind( qlonglong(t)); }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(const T& t) { return QBind<QJsonWriter,T>::bind(QJsonWriter(this).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<QJsonWriter,T>::bind(QJsonWriter(this).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<QJsonWriter,T>::bind(QJsonWriter(this).value(), t ); }
template<class T_> friend class Seq; // calls methods below
bool _item(int min= 1) { Q_UNUSED(min); return io->write(levels.last().sep)==strlen(levels.last().sep) ; levels.last().sep = ","; }
......@@ -248,6 +246,14 @@ private:
QStack<Step> levels = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure well-formedness in case TResult is abandoned
};
QJsonWriter::QJsonWriter(QIODevice* io) : QScopedResult(new QJsonWriterImpl(io), true) {}
template<> struct BindSupport<QJsonWriterImpl,const char*> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, bool> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, float> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, double> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, qulonglong> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, qlonglong> : BindNative {};
// --------------------------------------------------------------------------
class QJsonReaderImpl;
class QJsonReader : public QScopedResult<QJsonReader, QJsonReaderImpl, BindMode::Read>
......@@ -371,9 +377,6 @@ protected:
|| _bind(b)
|| _null(); }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(T& t) { return QBind<QJsonReader,T>::bind(QJsonReader(this).value(), t); } // TODO this "mode" (min<=0 or mode==Optional=='?') must be hidden in TResult
template<class T_> friend class Seq; // calls methods below
// bool item(QByteArray& key) would require to cache key:value pairs coming out of order wrt to T items() calls
......@@ -453,6 +456,9 @@ private:
}
};
QJsonReader::QJsonReader(QIODevice* io) : QScopedResult(new QJsonReaderImpl(io), true) {}
template<> struct BindSupport<QJsonReaderImpl,QByteArray&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl,bool &> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl,double &> : BindNative {};
// //////////////////////////////////////////////////////////////////////////
// QBind<TResult,QJson*> support
......@@ -461,8 +467,7 @@ QJsonReader::QJsonReader(QIODevice* io) : QScopedResult(new QJsonReaderImpl(io),
#include <QtCore/qjsonarray.h>
template<class TResult>
struct QBind<TResult, const QJsonValue> { static TResult bind(Val<TResult> dst, const QJsonValue& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const QJsonValue&");
struct QBind<TResult, QJsonValue&, IsWriter<TResult>> { static TResult bind(Val<TResult> dst, QJsonValue& src) {
if (src.isArray ()) return dst.bind(src.toArray ());
if (src.isBool ()) return dst.bind(src.toBool ());
if (src.isDouble()) return dst.bind(src.toDouble());
......@@ -470,57 +475,38 @@ struct QBind<TResult, const QJsonValue> { static TResult bind(Val<TResult> dst,
return dst.null();
}};
template<class TResult>
struct QBind<TResult, QJsonValue> {
static TResult bind(Val<TResult> dst, QJsonValue& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
if (src.isArray ()) return dst.bind(src.toArray ());
if (src.isBool ()) return dst.bind(src.toBool ());
if (src.isDouble()) return dst.bind(src.toDouble());
if (src.isString()) return dst.bind(src.toString());
return dst.null();
}
static TResult bind(Val<TResult> src, QJsonValue& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
TResult r;
{
ScopedChoice<Val<TResult>> choice(src);
bool b; if (r = src.bind(b)) { dst = QJsonValue(b); return r; }
double d; if (r = src.bind(d)) { dst = QJsonValue(d); return r; }
QString t; if (r = src.bind(t)) { dst = QJsonValue(t); return r; }
QJsonArray a; if (r = src.bind(a)) { dst = a ; return r; }
}
if (!(r = src.null())) r.reportError("Expected bool|double|QString|QJsonArray|null");
/**/ dst = QJsonValue();
return r;
struct QBind<TResult, QJsonValue&, IsReader<TResult>> { static TResult bind(Val<TResult> src, QJsonValue& dst) {
TResult r;
{
ScopedChoice<Val<TResult>> choice(src);
bool b; if (r = src.bind(b)) { dst = QJsonValue(b); return r; }
double d; if (r = src.bind(d)) { dst = QJsonValue(d); return r; }
QString t; if (r = src.bind(t)) { dst = QJsonValue(t); return r; }
QJsonArray a; if (r = src.bind(a)) { dst = a ; return r; }
}
};
if (!(r = src.null())) r.reportError("Expected bool|double|QString|QJsonArray|null");
/**/ dst = QJsonValue();
return r;
}};
#include <QtCore/qjsonarray.h>
template<class TResult>
struct QBind<TResult, const QJsonArray> { static TResult bind(Val<TResult> dst, const QJsonArray& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const QJsonArray&");
struct QBind<TResult, QJsonArray&, IsWriter<TResult>> { static TResult bind(Val<TResult> dst, QJsonArray& src) {
auto s(dst.sequence());
for (auto&& item : src) {
for (QJsonValue&& item : src) {
s = s.bind(item);
}
return s;
}};
template<class TResult>
struct QBind<TResult, QJsonArray> {
static TResult bind(Val<TResult> dst, QJsonArray& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
auto s(dst.sequence());
for (QJsonValue&& item : src) {
s = s.bind(item);
}
return s;
struct QBind<TResult, QJsonArray&, IsReader<TResult>> { static TResult bind(Val<TResult> src, QJsonArray& dst) {
auto s(src.sequence());
Val<Seq<TResult>> i;
while (i = s.item(0)) { // s = s.bind(v) would assign s an invalid Seq<TResult> on the last item
QJsonValue v;
if (s = i.bind(v))
dst.append(v);
}
static TResult bind(Val<TResult> src, QJsonArray& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
auto s(src.sequence());
Val<Seq<TResult>> i;
while (i = s.item(0)) { // s = s.bind(v) would assign s an invalid Seq<TResult> on the last item
QJsonValue v;
if (s = i.bind(v))
dst.append(v);
}
return s;
}
};
return s;
}};
......@@ -92,11 +92,6 @@ protected:
bool _sequence() { return io->write("["); }
bool _bind(const char* s) { return io->write( s ); }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(const T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<class T_> friend class Seq; // enables calling methods below through operator->()
bool _item(int min= 1) { Q_UNUSED(min); return io->write(" "); }
......@@ -104,6 +99,7 @@ protected:
private:
QIODevice* io = nullptr; // for QMovedWriter
};
template<> struct BindSupport<TextWriter,const char*> : BindNative {};
using Text = Utf8Result<TextWriter>;
// //////////////////////////////////////////////////////////////////////////
......@@ -162,6 +158,7 @@ int main()
1./3, 2./3, 1./3, 1.,
0. , 0. , 0. , 1.});
Person person{"John","Doe",1.75,{"+44 1234567","+44 2345678"}};
const double PI=3.141592653589793;
// Temporary buffers
QString s;
......@@ -175,6 +172,7 @@ int main()
s.clear();
QDebug(&s)
<< '[' << 1.333333333333f
<< ',' << PI
<< ',' << text
<< ',' << false
<< ']'
......@@ -186,6 +184,7 @@ int main()
TextWriter(&b)
.sequence()
.bind(1.333333333333f)
.bind(PI)
.bind(text)
.bind(false)
;
......@@ -196,6 +195,7 @@ int main()
QJsonWriter(&b)
.sequence()
.bind(1.333333333333f)
.bind(PI)
.bind(text)
.bind(false)
;
......@@ -206,6 +206,7 @@ int main()
CborWriter(&b)
.sequence()
.bind(1.333333333333f)
.bind(PI)
.bind(text)
.bind(false)
;
......@@ -215,6 +216,7 @@ int main()
START {
writables.clear();
writables.append(1.333333333333f);
writables.append(PI);
writables.append(text);
writables.append(false);
}
......@@ -312,19 +314,20 @@ int main()
Person p;
QVector<QJsonReaderImpl::Error> jsonReaderErrors ;
QVector<JsonVisitorImpl::Error> jsonVisitorErrors;
START {
json.seek(0); b.seek(0); b.buffer().clear();
jsonReaderErrors = QJsonReader(&json).bind(CborWriter(&b).value())->errors;
}
STOP("Json>Cbor",QString::fromUtf8(b.buffer().toHex()))
// START {
// json.seek(0); b.seek(0); b.buffer().clear();
// jsonReaderErrors = QJsonReader(&json).bind(CborWriter(&b).value())->errors;
// }
// STOP("Json>Cbor",QString::fromUtf8(b.buffer().toHex()))
START {
json.seek(0); v = QJsonValue();
jsonReaderErrors = QJsonReader(&json).bind(v)->errors;
/*jsonReaderErrors =*/ QJsonReader(&json).bind(v)/*->errors*/;
}
STOP("Json>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()+Text(jsonReaderErrors)));
START {
json.seek(0); p = {};
jsonReaderErrors = QJsonReader(&json).bind(p)->errors;
/*jsonReaderErrors =*/ QJsonReader(&json).bind(p)/*->errors*/;
}
STOP("Json>T",QString::fromUtf8(Text(p)+Text(jsonReaderErrors)))
START {
......
Supports Markdown
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