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

cosmetic changes

parent 58dc4509
......@@ -54,7 +54,6 @@ protected: \
Class& operator=(Class&& o) noexcept { if (this!=&o) { Statements } return *this; }
#include <QtCore/qbytearray.h>
//!< Explicitely utf8 encoded string of char
class QUtf8String : public QByteArray
{
......@@ -83,17 +82,6 @@ static QName qBindExpectedConstant = "Expected constant" ;
static QName qBindIgnoredCharacter = "Ignored character" ;
static QName qBindIgnoredBytes = "Ignored bytes" ;
template<class T>
class QScopedChoice //!< for accurate error reporting
{
Q_DISABLE_COPY(QScopedChoice)
public:
QScopedChoice(T& t) : t(t) { if(t) t->setChoice(true ); }
~QScopedChoice() { if(t) t->setChoice(false); }
private:
T& t;
};
// //////////////////////////////////////////////////////////////////////////
// Standard meta data names
......@@ -119,21 +107,21 @@ static QName qmChildren = "children"; //!< name of a sequence of records with re
// //////////////////////////////////////////////////////////////////////////
// QBind<TResult,T>
#include <type_traits>
template<class T_> class Val;
enum BindMode { Invalid=0, Read=1, Write=2 }; //!< Specifies QBind::bind traversal and processing (the design would support other BindMode like Append or Diff)
template<class T> using RemoveCvRef = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
//! QBind is a class of template functions binding a Val<TResult> with a T, returning the TResult
//! Its least specialized definition calls a T::bind method that is more convenient to define than a QBind specialization
//! QBind is a class of template methods binding T parts with Val<TResult> obeying a simple generic data model, and returning the TResult
//! Each QBind<_,T> should provide bind(T&&) and bind(T&) overloads for convenience and may provide bind(const T&) for performance depending on T
//!
//! Its least specialized definition calls a T::bind(Val<TResult>&&) method that is more convenient to define than a QBind specialization
//! \see Person::bind() definition in main.cpp for an example
//!
//! \remark bind is not a template function to avoid conflicts with ADL and allow more precise class specialization
//! \remark Val<> is a move-only type passed by rvalue reference following http://scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html
//! \remark bind is more explicit than operator()
//! \remark bind is more explicit than operator() but could be changed to enable use as std::function
//! \remark QBind has a structure similar to a Traversable : https://wiki.haskell.org/Typeclassopedia#Traversable
//! A QTraverse<Val<TResult>,T> would be equivalent but would not mandate to actually traverse T to get from Val<TResult> to the actual TResult
//! A QFold<TResult,T> would be equivalent to a Foldable allowing to fold T to any TResult without mandating a common Val/Seq structure
//!
template<class TResult, typename T, typename TEnabledIf=void>
struct QBind {
static TResult bind(Val<TResult>&& value, T& t) { return t .bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<TResult,T>::bind(Val<TResult>,T&)
......@@ -146,18 +134,11 @@ struct QBind {
// - serializing, deserializing
// - constructing generic in-memory data structures
// - etc...
// See Person::bind() definition below for an example
#include <QtCore/qvector.h>
struct BindNative {};
struct BindGeneric {};
template<class TResult, typename T, typename TEnabledIf=void> struct BindSupport : BindGeneric {}; //!< Specifies whether Val calls TResult::_bind or QBind<TResult,T>::bind
template<class T_> class Rec; //!< a Record data structure defined below
template<class T_> class Seq; //!< a Sequence data structure defined below
template<class T_> class Val //!< a choice of sequence(), record(), null(), or any value with a textual representation
template<class T_> class Val //!< a choice of sequence(), record(), null(), or any value with at least a textual representation and possibly binary ones
{
Q_DISABLE_COPY(Val)
public:
......@@ -252,10 +233,27 @@ private:
T_ outer = T_();
};
//! A non-owning pointer to TImpl that transparently bypasses invalid calls to TImpl
//! \remark Can be used to easily implement Reader/Writers adding shortcut methods using Cur((TImpl*)this)
//! \warning Cur bypasses calls to a nullptr==impl
//! \remark A nullptr==impl results from using the same intermediate Val/Seq/Rec twice (a programmer error) or from runtime impl errors
// //////////////////////////////////////////////////////////////////////////
// Default TResult implementations
enum BindMode { Invalid=0, Read=1, Write=2 }; //!< Specifies QBind::bind traversal and processing (the design would support other BindMode like Append or Diff)
struct BindGeneric {};
struct BindNative {};
template<class TResult, typename T, typename TEnabledIf=void> struct BindSupport : BindGeneric {}; //!< Specifies whether Val calls TResult::_bind or QBind<TResult,T>::bind
#include <type_traits>
template<class T> using RemoveCvRef = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
//! A Cur(sor) is a move-only, non-owning pointer to TImpl that can be used as QBind's TResult
//! It allows to easily add QBind support to existing Reader/Writers by adding at least one value() method returning a Cursor(this).value()
//! \see TextWriter in main.cpp
//!
//! \remark Cur allows using the fluent interface without checking intermediate status by setting impl=nullptr on error
//! and subsequently bypassing impl calls. Errors can result from:
//! - using the same intermediate Val/Seq/Rec twice (a programmer error), or
//! - runtime impl errors like trying to bind a _sequence() whereas the data read matches a _record()
//!
template<class TImpl> //!< Processing associated to the traversal
class Cur
{
......@@ -274,7 +272,7 @@ public:
Val<Cur> value() { return Val<Cur>(std::move(*this)); }
void setChoice ( bool v) { if (impl) impl->_setChoice (v); }
void setChoice ( bool c) { if (impl) impl->_setChoice (c); }
void reportError(const char* e) { if (impl) impl->_reportError(e); }
protected:
template<class T_> friend class Val; // enables calling methods below
......@@ -302,6 +300,17 @@ private:
TImpl* impl = nullptr;
};
template<class TResult>
class QScopedChoice //!< for accurate error reporting
{
Q_DISABLE_COPY(QScopedChoice)
public:
QScopedChoice(TResult& t) : t(t) { if(t) t->setChoice(true ); }
~QScopedChoice( ) { if(t) t->setChoice(false); }
private:
TResult& t;
};
// //////////////////////////////////////////////////////////////////////////
// Base Cur<TImpl> implementations for Read and Write BindMode
......@@ -313,7 +322,7 @@ private:
struct IBind {
virtual ~IBind() = default;
virtual BindMode mode() const = 0;
virtual BindMode mode() const = 0; //!< \remark a static constexpr BindMode Mode did not exhibit noticeable performance improvements and may trigger twice more code generation for Read/Write independant QBind like Person::bind
virtual bool _isOk() = 0; //!< Current operation status
......@@ -384,10 +393,12 @@ struct IBind {
virtual void _reportError(const char*) {}
};
using Cursor = Cur<IBind>; //!< \remark It would be possible to implement Cursor without templates nor BindSupport by defining all IBind overloads
template<> struct BindSupport<IBind,const char*> : BindNative {};
template<> struct BindSupport<IBind,QUtf8String> : BindNative {};
template<> struct BindSupport<IBind, QString> : BindNative {};
template<> struct BindSupport<IBind, QChar> : BindNative {};
//template<> struct BindSupport<IBind, QChar> : BindNative {};
template<> struct BindSupport<IBind, bool> : BindNative {};
template<> struct BindSupport<IBind, qint8> : BindNative {};
template<> struct BindSupport<IBind, quint8> : BindNative {};
......@@ -406,8 +417,6 @@ template<> struct BindSupport<IBind, double> : BindNative {};
//template<> struct BindSupport<IBind, QUuid> : BindNative {};
template<> struct BindSupport<IBind, QByteArray> : BindNative {};
using Cursor = Cur<IBind>; //!< \remark It would be possible to implement Cursor without templates nor BindSupport by defining all IBind overloads
static char *qulltoa2(char *p, qulonglong n, int base=10)
{
*--p = '\0';
......@@ -596,17 +605,17 @@ QAtomicPointer<IWriter> QLogger::s_impl = nullptr;
#include <functional>
//! A QBind<TResult,T> polymorphic in T (erased at compile-time) which is captured by reference or copy (for rvalue references) to be bound later with a TResult which Mode == Write
//! A QBind<TResult,T> polymorphic in T (erased at compile-time) which is captured by reference or copy (for rvalue references) to be bound later
//! \warning a T&& may be allocated dynamically if its size exceeds compiler's Small Function Optimization
//! \warning copying should be forced using QWritable(T(t)) if QWritable::bind() must be called after t is destructed like when queued to another thread
template<class TResult>
class QWritable
//! \warning copying should be forced using QBindable(T(t)) if QBindable::bind() must be called after t is destructed like when queued to another thread for writing
template<class TResult = Cursor>
class QBindable
{
std::function<TResult(Val<TResult>&&)> f;
public:
QWritable() {}
template<typename T> QWritable(T& t) : f( /*captured T ref */[&t] (Val<TResult>&& v) { return v.bind(t); } ) {}
template<typename T> QWritable(T&& t) : f( /*captured T copy*/[ t] (Val<TResult>&& v) { return v.bind(t); } ) {}
QBindable() {}
template<typename T> QBindable(T& t) : f( /*captured T ref */[&t] (Val<TResult>&& v) { return v.bind(t); } ) {}
template<typename T> QBindable(T&& t) : f( /*captured T copy*/[ t] (Val<TResult>&& v) { return v.bind(t); } ) {}
TResult bind(Val<TResult>&& v) { return f(std::move(v)); }
};
......@@ -614,13 +623,6 @@ public:
// //////////////////////////////////////////////////////////////////////////
// QBind partial specializations (generic on TResult, usually not on v->mode() for dynamically-sized or builtin types)
#include <cstddef>
template<class TResult>
struct QBind<TResult, std::nullptr_t> {
static TResult bind(Val<TResult>&& v, std::nullptr_t) { return v.null(); }
};
template<class TResult, typename T>
struct QBind<TResult, T, typename std::enable_if<std::is_unsigned<T>::value && std::is_integral<T>::value && !std::is_same<T,bool>::value>::type> {
static TResult bind(Val<TResult>&& v, T&& t) {
......
......@@ -67,7 +67,7 @@ public:
Val<Cur<QDataWriter>> meta ( QMetaData& m) { return Cur<QDataWriter>(this).value().meta (m); }
Seq<Cur<QDataWriter>> sequence(quint32* s=nullptr) { return Cur<QDataWriter>(this).value().sequence(s); }
template<typename T> Cursor bind(T&& t) { return Cursor(this).value().bind(std::forward<T>(t)); } //!< Only the standard Cursor is compatible with QWritable
template<typename T> Cur<QDataWriter> bind(T&& t) { return Cur<QDataWriter>(this).value().bind(std::forward<T>(t)); }
protected:
friend class Cur<QDataWriter>;
bool _sequence(quint32* s=nullptr) { if (s) *io << *s; return true; }
......
......@@ -133,7 +133,7 @@ private:
// TODO BindNative other QVariant-supported types?
// //////////////////////////////////////////////////////////////////////////
// QBind<TResult,QVariant&> example support for the fixed set of QVariantBuilder's BindNative types + other convenient types
// QBind<_,QVariant&> example support for the fixed set of QVariantBuilder's BindNative types + other convenient types
template<class TResult>
struct QBind<TResult, QVariant> {
......
......@@ -67,7 +67,7 @@ struct Person
QString firstName, lastName; double height; int age; QVector<QString> phones; QString comments;
template<class TResult>
TResult bind(Val<TResult>&& value) { // since we only bind T& (no const T&), it works with v->mode()==Read as well as Write
TResult bind(Val<TResult>&& value) { // works with value->mode()==Read as well as Write
return value
.record()
.sequence("names")
......@@ -75,7 +75,7 @@ struct Person
.bind( lastName)
.out()
.bind("height" ,height )
.bind("age" ,age ) // or .any() to ignore
.bind("age" ,age ) // or item("age").any() to ignore
.bind("phones" ,phones ) // recursive calls to QBind will take care of that part
.bind("comments",comments)
; // automagically closes all opened structures
......@@ -114,12 +114,10 @@ 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 _isOk() { return io; }
bool _sequence(quint32* cols=nullptr) { Q_UNUSED(cols); return io->write("["); }
bool _record (quint32* rows=nullptr) { Q_UNUSED(rows); return io->write("["); }
bool _null ( ) { return true ; }
bool _bind ( const char* s) { return io->write( s ); }
bool _sequence(quint32* =nullptr) { return io->write("["); }
bool _record (quint32* =nullptr) { return io->write("["); }
bool _null ( ) { return true ; }
bool _bind ( const char* s) { return io->write( s ); }
bool _item(QName n) { return io->write(" ") && io->write(n) && io->write(":"); }
bool _item( ) { return io->write(" ") ; }
......@@ -298,7 +296,7 @@ int main(int argc, char *argv[])
<< color;
}
STOP("QDataStream",QString::fromUtf8(b.buffer().toHex()));
QWritable<Cursor> writables[5];
QBindable<> writables[5];
START {
writables[0] = 1.333333333333f;
writables[1] = PI;
......@@ -377,7 +375,7 @@ int main(int argc, char *argv[])
};
}
STOP("QDataStream",QString::fromUtf8(b.buffer().toHex()));
QWritable<Cursor> writable;
QBindable<> writable;
START {
writable = transform;
}
......@@ -462,7 +460,7 @@ int main(int argc, char *argv[])
d << person;
}
STOP("QDataStream",QString::fromUtf8(b.buffer().toHex()));
QWritable<Cursor> writable;
QBindable<> writable;
START {
writable = person;
}
......
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