Commit 079bfb77 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

restricted _unsafe* access

fixed all issues but compile issue
parent 4a241b60
......@@ -140,12 +140,12 @@ public:
operator bool() { return m_out.operator bool(); } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { return m_out.operator ->(); }
template<typename T> T_ bind( T&& t) { if (_bind(std::forward<T>(t),BindSupport<TImpl,T>())) return std::move(m_out) ; else return T_ (); }
template<typename T> T_ bind(T&& t) { if (_bind(std::forward<T>(t),BindSupport<TImpl,T>())) return std::move(m_out) ; else return T_ (); }
/**/ T_ null () { if (Q_LIKELY(m_out) && m_out-> _null()) return std::move(m_out) ; else return T_ (); }
/**/ Seq<T_> sequence () { if (Q_LIKELY(m_out) && m_out-> _sequence()) return Seq<T_>(std::move(m_out)); else return Seq<T_>(); }
private:
template<typename T> bool _bind(T&& t, BindNative ) { return Q_LIKELY(m_out) && m_out->_bind( std::forward<T>(t)); }
template<typename T> bool _bind(T&& t, BindGeneric) { return QBind<TResult,T&&>::bind(m_out.value(),std::forward<T>(t)); }
template<typename T> bool _bind(T&& t, BindGeneric) { return QBind<TResult,T&&>::bind(Val<TResult>(m_out._unsafeCopy()),std::forward<T>(t)); }
T_ m_out = T_(); //!< moved context of current traversal up to TResult that will reference the val itself (be it a QIODevice or QCborValue)
};
......@@ -164,19 +164,23 @@ public:
operator bool() { return m_out.operator bool(); } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { return m_out.operator ->(); }
Val<Seq<T_>> item(int min= 1) { if (Q_LIKELY(m_out) && m_out->_item(min)) return Val<Seq<T_>>(std::move(*this)); return Val<Seq<T_>>(); }
/**/ T_ out(int max=-1) { if (Q_LIKELY(m_out) && m_out-> _out(max)) return std::move(m_out) ; return T_ (); }
Val<Seq<T_>> item(int min= 1) { if (Q_LIKELY(m_out) && m_out->_item(min)) return Val<Seq<T_>>(std::move(*this)); else return Val<Seq<T_>>(); } // TODO return Val<T_>
/**/ T_ out(int max=-1) { if (Q_LIKELY(m_out) && m_out-> _out(max)) return std::move(m_out) ; else return T_ (); }
operator TResult() { return out(); /* recursively calls operator TResult() as mandated by T_ */ }
operator TResult() { return out(); /* calls operator TResult() unless T_==TResult */ }
TResult result() { return operator TResult(); }
Val<TResult> value() { return m_out.value(); }
// Shortcuts
template<typename T> Seq<T_> bind(T&& t) { if (itemValue().bind(std::forward<T>(t))) return std::move(*this); return Seq<T_>(); }
protected:
template<class TResult, typename T, typename TEnabledIf> friend class QBind;
Val<T_> itemValue(int min= 1) { if (Q_LIKELY(m_out) && m_out->_item(min)) { T_ scopedT(m_out); return std::move(Val<T_>(std::move(scopedT))); } return Val<T_>(); } // the m_out copy must be scoped and will be invalid when the original is destroyed
template<typename T> Seq<T_> bind(T&& t) { return item().bind(std::forward<T>(t)); }
private:
template<class TSrcResult, typename TDst, typename TEnabledIf> friend class QBind; // TODO restrict to <TSrcResult, Val<TDst>&&, IsReader<TSrcResult>>;
Val<TResult> _unsafeItem(int min= 1) { if (Q_LIKELY(m_out) && m_out->_item(min)) return Val<TResult>(m_out._unsafeCopy()); else return Val<TResult>(); }
friend class Val<Seq<T_>>;
friend class Seq<Seq<T_>>;
friend class Rec<Seq<T_>>;
TResult _unsafeCopy() { return m_out._unsafeCopy(); } //!< it is the caller's responsibility to use it immediately and only one time, otherwise the backing TResult state will be unknown
T_ m_out = T_();
};
......@@ -200,6 +204,7 @@ public:
operator bool() { return m; } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { Q_ASSERT_X(m,Q_FUNC_INFO,"check operator bool() before calling operator->()"); return m; }
Val<TResult> value() { return Val<TResult>(std::move(*static_cast<TResult*>(this))); }
// Shortcuts
......@@ -210,6 +215,11 @@ public:
void reportError(const char* error) { if (m) m->reportError(error); }
protected:
QScopedResult(TImpl* result, bool owned) : m(result), m_owned(owned) {}
private:
template<typename T_> friend class Val;
template<typename T_> friend class Seq;
template<typename T_> friend class Rec;
TResult _unsafeCopy() { return TResult(m); }
TImpl* m = nullptr;
bool m_owned = true ; //!< for nested QBind only
......@@ -218,7 +228,7 @@ protected:
//! Base class for TResult classes that can exhibit high performance (they require no heap allocation and no lock)
//! \warning
//! - it may be difficult to correctly implement a TResult derived from QMovedWriter with internal state (need to understand move semantics)
//! - TResult scoped copies do not share state (such as the whole path to the current value or errors or "choice" mode)
//! - TResult unsafeCopy copies do not share state (such as the whole path to the current value or errors or "choice" mode)
//! - TResult are not pimpled (use QScopedResult if needed)
template<class TResult_>
class QMovedWriter
......@@ -232,6 +242,7 @@ public:
static constexpr BindMode Mode = BindMode::Write;
TImpl* operator->() { return static_cast<TImpl*>(this); }
Val<TResult> value() { return Val<TResult>(std::move(*static_cast<TResult*>(this))); }
// Shortcuts
......@@ -243,6 +254,11 @@ public:
protected:
friend class ScopedChoice<Val<TResult>>;
void setChoice(bool) {} // not implemented like reportError
private:
template<typename T_> friend class Val;
template<typename T_> friend class Seq;
template<typename T_> friend class Rec;
TResult _unsafeCopy() { return TResult(*static_cast<TResult*>(this)); }
};
#include <QtCore/qbuffer.h>
......@@ -346,8 +362,8 @@ struct QBind<TResult, QVector<T>&, IsReader<TResult>> { static TResult bind(Val<
Val<Seq<TResult>> i;
while (i = s.item(0)) {
T t;
if (s = i.bind(t))
dst.push_back(t);
if (s = i.bind(t)) // gives back control to s, enabling the next s.item(0) call
dst.append(t);
}
return s;
}};
......@@ -357,7 +373,7 @@ struct QBind<TResult, QVector<T>&, IsReader<TResult>> { static TResult bind(Val<
template<class TSrcResult, class TDst>
struct QBind<TSrcResult, Val<TDst>&&, IsReader<TSrcResult>> { static TSrcResult bind(Val<TSrcResult> src, Val<TDst>&& dst) {
static_assert(TDst::Mode!=Read,"Cannot Read from TSrcResult to TDst with BindMode==Read");
static_assert(TDst::Mode!=Read,"Cannot Read from TSrcResult to TDst with BindMode==Read, swapping src and dst should work though");
TSrcResult srcRes;
{
......@@ -368,8 +384,8 @@ struct QBind<TSrcResult, Val<TDst>&&, IsReader<TSrcResult>> { static TSrcResult
/**/ dstSeq = dst.sequence();
Val<TSrcResult> srcVal; Val<TDst> dstVal;
while (srcVal = srcSeq.itemValue(0)) { // using item()'s Val<Seq<TSrcResult> would cause an infinite compiler loop to generate corresponding QBind<Val<Seq<Seq<...>>,_> functions
dstVal = dstSeq.itemValue();
while (srcVal = srcSeq._unsafeItem(0)) { // using item()'s Val<Seq<TSrcResult> would cause an infinite compiler loop to generate corresponding QBind<Val<Seq<Seq<...>>,_> functions
dstVal = dstSeq._unsafeItem();
srcSeq = srcVal.bind(dstVal);
}
......
......@@ -118,11 +118,11 @@ protected:
bool _bind(const char* s) { return (putInteger(cbor::TextStringType, strlen(s)) && io->write(s)); }
// Natively supported overloads
bool _bind( bool b) { return io->putChar(b ? cbor::TrueByte : cbor::FalseByte); }
bool _bind( float n) { union { float value; quint32 bits; } number = { n };
bool _bind( bool& b) { return io->putChar(b ? cbor::TrueByte : cbor::FalseByte); }
bool _bind( float& n) { union { float value; quint32 bits; } number = { n };
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::SinglePrecisionFloat) && io->write(bytes, sizeof(bytes))); }
bool _bind( double n) { union { double value; quint64 bits; } number = { n };
bool _bind( double& n) { union { double value; quint64 bits; } number = { n };
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::DoublePrecisionFloat) && io->write(bytes, sizeof(bytes))); }
......@@ -148,6 +148,6 @@ private:
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 {};
template<> struct BindSupport<CborWriter, bool&> : BindNative {};
template<> struct BindSupport<CborWriter, float&> : BindNative {};
template<> struct BindSupport<CborWriter, double&> : BindNative {};
......@@ -60,7 +60,7 @@ public:
Q_ENABLE_MOVE_DEFAULT(QJsonBuilder)
QJsonBuilder(QJsonValue* v);
private:
template<class T_> friend class Seq;
friend class QScopedResult<QJsonBuilder, QJsonBuilderImpl, BindMode::Write>;
friend class QJsonBuilderImpl; // uses method below
QJsonBuilder(QJsonBuilderImpl* outer) : QScopedResult(outer, false) {}
};
......@@ -82,8 +82,10 @@ 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(bool b) { set(QJsonValue(b)); return true; }
bool _bind(double d) { set(QJsonValue(d)); return true; }
// Natively supported overloads
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)); }
......@@ -111,8 +113,8 @@ private:
};
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<> 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 {};
// --------------------------------------------------------------------------
......@@ -125,7 +127,7 @@ public:
Q_ENABLE_MOVE_DEFAULT(QJsonVisitor)
QJsonVisitor(const QJsonValue* v);
private:
template<class T_> friend class Seq;
friend class QScopedResult<QJsonVisitor, JsonVisitorImpl, BindMode::Read>;
friend class JsonVisitorImpl; // uses method below
QJsonVisitor(JsonVisitorImpl* outer) : QScopedResult(outer, false) {}
};
......@@ -183,9 +185,10 @@ 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 {};
template<> struct BindSupport<JsonVisitorImpl,const char*> : BindNative {};
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 {};
// --------------------------------------------------------------------------
......@@ -198,7 +201,7 @@ public:
Q_ENABLE_MOVE_DEFAULT(QJsonWriter)
QJsonWriter(QIODevice* io);
private:
template<class T_> friend class Seq;
friend class QScopedResult<QJsonWriter, QJsonWriterImpl, BindMode::Write>;
friend class QJsonWriterImpl; // uses method below
QJsonWriter(QJsonWriterImpl* outer) : QScopedResult(outer, false) {}
};
......@@ -225,11 +228,11 @@ protected:
io->write( "\"" )); }
// Natively supported overloads
bool _bind( bool n) { return io->write(n ? "true" : "false") ; }
bool _bind( float n) { return io->write(QByteArray::number(n, 'g', std::numeric_limits< float>::max_digits10)); }
bool _bind( double n) { return io->write(QByteArray::number(n, 'g', std::numeric_limits<double>::max_digits10)); }
bool _bind( qulonglong n) { return io->write(QByteArray::number(n )); }
bool _bind( qlonglong n) { return io->write(QByteArray::number(n )); }
bool _bind( bool& n) { return io->write( n? "true" : "false" ); }
bool _bind( float& n) { return io->write(QByteArray::number(n, 'g', std::numeric_limits< float>::max_digits10)); }
bool _bind( double& n) { return io->write(QByteArray::number(n, 'g', std::numeric_limits<double>::max_digits10)); }
bool _bind(qulonglong& n) { return io->write(QByteArray::number(n )); }
bool _bind( qlonglong& n) { return io->write(QByteArray::number(n )); }
// This dispatch would be more simple with C++17 constexpr if
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)); }
......@@ -237,8 +240,8 @@ protected:
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 = ","; }
bool _out(int max=-1) { Q_UNUSED(max); return io->write(levels.pop() .end) ; }
bool _item(int min= 1) { Q_UNUSED(min); auto r=io->write(levels.last().sep)==strlen(levels.last().sep); levels.last().sep = ","; return r; }
bool _out(int max=-1) { Q_UNUSED(max); auto r=io->write(levels.pop() .end) ; return r; }
private:
struct Step { const char* sep; const char* end; };
......@@ -247,11 +250,11 @@ private:
};
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 {};
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 {};
// --------------------------------------------------------------------------
......@@ -263,7 +266,7 @@ public:
Q_ENABLE_MOVE_DEFAULT(QJsonReader)
QJsonReader(QIODevice* io);
private:
template<class T_> friend class Seq;
friend class QScopedResult<QJsonReader, QJsonReaderImpl, BindMode::Read>;
friend class QJsonReaderImpl; // uses method below
QJsonReader(QJsonReaderImpl* outer) : QScopedResult(outer, false) {}
};
......@@ -457,8 +460,8 @@ 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 {};
template<> struct BindSupport<QJsonReaderImpl, bool&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, double&> : BindNative {};
// //////////////////////////////////////////////////////////////////////////
// QBind<TResult,QJson*> support
......@@ -485,7 +488,7 @@ struct QBind<TResult, QJsonValue&, IsReader<TResult>> { static TResult bind(Val<
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();
dst = QJsonValue();
return r;
}};
......@@ -503,7 +506,7 @@ template<class TResult>
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
while (i = s.item(0)) {
QJsonValue v;
if (s = i.bind(v))
dst.append(v);
......
......@@ -141,16 +141,6 @@ int main()
if (!results) return -1;
if (!samples) return -1;
QFile json( "modmed.json");
QFile xml ( "modmed.xml" );
QFile fjson("fmodmed.json");
QFile fxml ("fmodmed.xml" );
if (! json.open(QIODevice::ReadWrite|QIODevice::Truncate)) return -1;
if (! xml .open(QIODevice::ReadWrite|QIODevice::Truncate)) return -1;
if (!fjson.open(QIODevice::ReadWrite|QIODevice::Truncate)) return -1;
if (!fxml .open(QIODevice::ReadWrite|QIODevice::Truncate)) return -1;
// Read-only args
QString text("..ascii characters + U+A4 ¤ U+B0 ° U+D8 Ø U+FF ÿ..");
QVector<double> transform({1./3, 2./3, 1./3, 1.,
......@@ -322,12 +312,12 @@ int main()
// 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