Commit 76fdafd6 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

Replaced public IWriter::operator bool with _isOk

+ cosmetic changes
parent 9727769a
......@@ -319,7 +319,7 @@ private:
bool m_owned = true ; //!< for nested QBind only
};
//! Base class for TResult classes that can exhibit high performance (they require no heap allocation and no lock)
//! Base class for Writer 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 unsafeCopy copies do not share state (such as the whole path to the current value or errors or "choice" mode)
......@@ -347,18 +347,147 @@ public:
/**/ TResult null ( ) { return value().null ( ); }
template<typename T> TResult bind ( T&& t) { return value().bind(std::forward<T>(t)); }
void reportError(const char* s) {} // a TResult with BindMode::Write will not encounter bind mismatches but only write errors independent from the current state
void reportError(const char*) {} // a TResult with BindMode::Write will not encounter bind mismatches but only write errors independent from the current state
protected:
void setChoice(bool) {} // not implemented like reportError
private:
friend struct IWriter;
template<typename TResult> friend class QTableWriter;
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)); }
};
// //////////////////////////////////////////////////////////////////////////
// Writer with a fixed subset of scalar types
// This erases the TResult for code that do not know it like tracepoints
// without sacrificing performance by resorting to opaque pointers like QWritable that require heap allocation
struct IWriter
{
virtual ~IWriter() = default;
//! Write status for current value
virtual bool _isOk() { return true; }
//! Meta data is data about current data (e.g. tag, attribute, style, etc.)
//! \warning It is ignored by default and subject to various interpretation, so users should meta data standards or adopt existing ones like XSD for sake of interoperability
virtual void _meta ( MetaData& ) {}
virtual bool _sequence(quint32* size=nullptr) = 0;
virtual bool _record (quint32* size=nullptr) = 0;
virtual bool _null ( ) = 0;
virtual bool _item ( QByteArray& k) = 0;
virtual bool _item ( ) = 0;
//! 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)
virtual bool _out() { return true; }
virtual bool _bind ( const char* s) = 0;
virtual bool _bind ( QString& s) { return _bind(s.toUtf8().constData()); }
virtual bool _bind ( bool& s) { return _bind(s ? "true" : "false"); }
virtual bool _bind ( float& n) { auto s(QByteArray::number(double(n),'g',std::numeric_limits< float>::max_digits10)); return _bind(s.constData()); } // with specific precision
virtual bool _bind ( double& n) { auto s(QByteArray::number( n ,'g',std::numeric_limits<double>::max_digits10)); return _bind(s.constData()); } // with specific precision
#if Q_CC_MSVC
# define ulltoa _ui64toa
# define lltoa _i64toa
#endif
virtual bool _bind ( qulonglong& s) { char n[1+std::numeric_limits<qulonglong>::digits10+1]; ulltoa(s,n,sizeof(n)); return _bind(static_cast<const char*>(n)); } // handling all unsigned integral types
virtual bool _bind ( qlonglong& s) { char n[1+std::numeric_limits< qlonglong>::digits10+1]; lltoa(s,n,sizeof(n)); return _bind(static_cast<const char*>(n)); } // handling all signed integral types
virtual bool _bind ( QByteArray& s) { QByteArray hex("0x"); hex.append(s.toHex()); return _bind(hex.constData()); }
// TODO QChar, QDateTime, QDate, QTime, QUuid, QUrl, QRegularExpression
};
class Writer : public QMovedWriter<Writer>
{
protected:
Writer(const Writer &o) : QMovedWriter(), impl(o.impl) {}
Writer &operator=(const Writer &) = delete;
public:
Q_ENABLE_MOVE(Writer, std::swap(impl, o.impl); )
Writer(IWriter* i) : impl(i) { Q_ASSERT(impl); }
operator bool() { return impl && impl->_isOk(); } // for QMovedWriter
protected:
friend class QMovedWriter<Writer>;
template<class T_> friend class Val; // enables calling methods below
void _meta ( MetaData& m) { Q_ASSERT(impl); impl->_meta ( m); }
bool _sequence(quint32* cols=nullptr) { Q_ASSERT(impl); return impl->_sequence(cols); }
bool _record (quint32* rows=nullptr) { Q_ASSERT(impl); return impl->_record (rows); }
bool _null ( ) { Q_ASSERT(impl); return impl->_null ( ); }
bool _bind ( QByteArray& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( QString& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( const char* v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( bool& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( float& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( double& v) { Q_ASSERT(impl); return impl->_bind ( v); }
template<typename T> typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, bool>::type _bind(T& t) { Q_ASSERT(impl); qulonglong u(t); return impl->_bind(u); }
template<typename T> typename std::enable_if<std::is_integral<T>::value && std:: is_signed<T>::value, bool>::type _bind(T& t) { Q_ASSERT(impl); qlonglong s(t); return impl->_bind(s); }
// TODO QChar, QDateTime, QDate, QTime, QUuid, QUrl, QRegularExpression
template<class T_> friend class Seq; // enables calling methods below
template<class T_> friend class Rec; // calls methods below
bool _item(QByteArray& k) { Q_ASSERT(impl); return impl->_item(k); }
bool _item( ) { Q_ASSERT(impl); return impl->_item( ); }
bool _out ( ) { Q_ASSERT(impl); return impl->_out ( ); }
private:
IWriter* impl = nullptr; // this state has noticeable performance cost but guarantees well-formedness through a unique valid instance of Writer (with impl != nullptr)
};
template<> struct BindSupport<Writer,QByteArray&> : BindNative {};
template<> struct BindSupport<Writer, QString&> : BindNative {};
template<> struct BindSupport<Writer,const char*> : BindNative {};
template<> struct BindSupport<Writer, bool&> : BindNative {};
template<> struct BindSupport<Writer, float&> : BindNative {};
template<> struct BindSupport<Writer, double&> : BindNative {};
template<typename T> struct BindSupport<Writer,T&,typename std::enable_if<std::is_integral<T>::value>::type> : BindNative {};
#include <QtCore/qatomic.h>
class Logger : public Writer
{
static QAtomicPointer<IWriter> s_impl;
public:
static IWriter* setWriter(IWriter* i) { return s_impl.fetchAndStoreOrdered(i); }
Logger() : Writer(s_impl) {}
};
QAtomicPointer<IWriter> Logger::s_impl = nullptr;
// //////////////////////////////////////////////////////////////////////////
// Deferred write support
#include <functional>
//! A QBind<TResult,T> with T erased and captured by reference or copy (for rvalue references) that can later be bound with a TResult which Mode == Write
//! \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, typename = IsWriter<TResult>>
class QWritable
{
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); } ) {}
TResult bind(Val<TResult> v) { return f(std::move(v)); }
};
// //////////////////////////////////////////////////////////////////////////
// Simple Result classes
#include <QtCore/qbuffer.h>
template<class TWriter, typename = IsWriter<TWriter>>
......@@ -618,128 +747,3 @@ struct QBind<TSrcResult, Val<TDst>&&, IsReader<TSrcResult>> { static TSrcResult
/**/ dst.null();
return srcRes;
}};
// //////////////////////////////////////////////////////////////////////////
// Writer with a fixed subset of scalar types
// This erases the TResult for code that do not know it like tracepoints
// without sacrificing performance by resorting to opaque pointers like QWritable that require heap allocation
struct IWriter
{
virtual ~IWriter() = default;
//! Write status for current value
virtual operator bool() { return true; }
//! Meta data is data about current data (e.g. tag, attribute, style, etc.)
//! \warning It is ignored by default and subject to various interpretation, so users should meta data standards or adopt existing ones like XSD for sake of interoperability
virtual void _meta ( MetaData& ) {}
virtual bool _sequence(quint32* size=nullptr) = 0;
virtual bool _record (quint32* size=nullptr) = 0;
virtual bool _null ( ) = 0;
virtual bool _item ( QByteArray& k) = 0;
virtual bool _item ( ) = 0;
//! 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)
virtual bool _out() { return true; }
virtual bool _bind ( const char* s) = 0;
virtual bool _bind ( QString& s) { return _bind(s.toUtf8().constData()); }
virtual bool _bind ( bool& s) { return _bind(s ? "true" : "false"); }
virtual bool _bind ( float& n) { auto s(QByteArray::number(double(n),'g',std::numeric_limits< float>::max_digits10)); return _bind(s.constData()); } // with specific precision
virtual bool _bind ( double& n) { auto s(QByteArray::number( n ,'g',std::numeric_limits<double>::max_digits10)); return _bind(s.constData()); } // with specific precision
#if Q_CC_MSVC
# define ulltoa _ui64toa
# define lltoa _i64toa
#endif
virtual bool _bind ( qulonglong& s) { char n[1+std::numeric_limits<qulonglong>::digits10+1]; ulltoa(s,n,sizeof(n)); return _bind(static_cast<const char*>(n)); } // handling all unsigned integral types
virtual bool _bind ( qlonglong& s) { char n[1+std::numeric_limits< qlonglong>::digits10+1]; lltoa(s,n,sizeof(n)); return _bind(static_cast<const char*>(n)); } // handling all signed integral types
virtual bool _bind ( QByteArray& s) { QByteArray hex("0x"); hex.append(s.toHex()); return _bind(hex.constData()); }
// TODO QChar, QDateTime, QDate, QTime, QUuid, QUrl, QRegularExpression
};
class Writer : public QMovedWriter<Writer>
{
protected:
Writer(const Writer &o) : QMovedWriter(), impl(o.impl) {}
Writer &operator=(const Writer &) = delete;
public:
Q_ENABLE_MOVE(Writer, std::swap(impl, o.impl); )
Writer(IWriter* i) : impl(i) { Q_ASSERT(impl); }
operator bool() { return impl && impl->operator bool(); } // for QMovedWriter
protected:
friend class QMovedWriter<Writer>;
template<class T_> friend class Val; // enables calling methods below
void _meta ( MetaData& m) { Q_ASSERT(impl); impl->_meta ( m); }
bool _sequence(quint32* cols=nullptr) { Q_ASSERT(impl); return impl->_sequence(cols); }
bool _record (quint32* rows=nullptr) { Q_ASSERT(impl); return impl->_record (rows); }
bool _null ( ) { Q_ASSERT(impl); return impl->_null ( ); }
bool _bind ( QByteArray& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( QString& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( const char* v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( bool& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( float& v) { Q_ASSERT(impl); return impl->_bind ( v); }
bool _bind ( double& v) { Q_ASSERT(impl); return impl->_bind ( v); }
template<typename T> typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, bool>::type _bind(T& t) { Q_ASSERT(impl); qulonglong u(t); return impl->_bind(u); }
template<typename T> typename std::enable_if<std::is_integral<T>::value && std:: is_signed<T>::value, bool>::type _bind(T& t) { Q_ASSERT(impl); qlonglong s(t); return impl->_bind(s); }
// TODO QChar, QDateTime, QDate, QTime, QUuid, QUrl, QRegularExpression
template<class T_> friend class Seq; // enables calling methods below
template<class T_> friend class Rec; // calls methods below
bool _item(QByteArray& k) { Q_ASSERT(impl); return impl->_item(k); }
bool _item( ) { Q_ASSERT(impl); return impl->_item( ); }
bool _out ( ) { Q_ASSERT(impl); return impl->_out ( ); }
private:
IWriter* impl = nullptr; // this state has noticeable performance cost but guarantees well-formedness through a unique valid instance of Writer (with impl != nullptr)
};
template<> struct BindSupport<Writer,QByteArray&> : BindNative {};
template<> struct BindSupport<Writer, QString&> : BindNative {};
template<> struct BindSupport<Writer,const char*> : BindNative {};
template<> struct BindSupport<Writer, bool&> : BindNative {};
template<> struct BindSupport<Writer, float&> : BindNative {};
template<> struct BindSupport<Writer, double&> : BindNative {};
template<typename T> struct BindSupport<Writer,T&,typename std::enable_if<std::is_integral<T>::value>::type> : BindNative {};
#include <QtCore/qatomic.h>
class Logger : public Writer
{
static QAtomicPointer<IWriter> s_impl;
public:
static IWriter* setWriter(IWriter* i) { return s_impl.fetchAndStoreOrdered(i); }
Logger() : Writer(s_impl) {}
};
QAtomicPointer<IWriter> Logger::s_impl = nullptr;
// //////////////////////////////////////////////////////////////////////////
// Deferred write support
//! A QBind<TResult,T> with T erased and captured by reference or copy (for rvalue references) that can later be bound with a TResult which Mode == Write
//! \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, typename = IsWriter<TResult>>
class QWritable
{
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); } ) {}
TResult bind(Val<TResult> v) { return f(std::move(v)); }
};
......@@ -107,19 +107,17 @@ public:
~CborWriter() { while (!levels.empty()) _out(); }
CborWriter(QIODevice* io) : io(io) { Q_ASSERT(io); }
operator bool() { return io; } // for QMovedWriter
// Shortcuts
/**/ Val<Writer> value ( ) { return write().value ( ); }
/**/ Val<Writer> meta ( MetaData&& m) { return write().meta ( m); }
/**/ Val<Writer> meta ( MetaData& m) { return write().meta ( m); }
/**/ Seq<Writer> sequence(quint32* s=nullptr) { return write().sequence ( s); }
/**/ Rec<Writer> record (quint32* s=nullptr) { return write().record ( s); }
/**/ Writer null ( ) { return write().null ( ); }
template<typename T> Writer bind ( T&& t) { return write().bind(std::forward<T>(t)); }
private:
inline Writer write() { return Writer(this); }
/**/ Val<Writer> value ( ) { return Writer(this).value ( ); }
/**/ Val<Writer> meta ( MetaData&& m) { return Writer(this).meta ( m); }
/**/ Val<Writer> meta ( MetaData& m) { return Writer(this).meta ( m); }
/**/ Seq<Writer> sequence(quint32* s=nullptr) { return Writer(this).sequence ( s); }
/**/ Rec<Writer> record (quint32* s=nullptr) { return Writer(this).record ( s); }
/**/ Writer null ( ) { return Writer(this).null ( ); }
template<typename T> Writer bind ( T&& t) { return Writer(this).bind(std::forward<T>(t)); }
protected:
bool _isOk() { return io; }
bool _sequence(quint32* rows=nullptr) { levels.push_back(rows);
return Q_LIKELY (rows)
? putInteger (*rows , cbor::ArrayType )
......
......@@ -54,10 +54,12 @@
// - use the same set of registered QMetaTypeIds with operator<< defined
// - use compatible ByteOrder, FloatingPointPrecision, and Version
class DataWriter : public IWriter, public QMovedWriter<DataWriter> // allows using QDataStream << for small numeric types
class DataWriter
: public IWriter // allows runtime flexibility using a compile-time Writer
, public QMovedWriter<DataWriter> // allows using QDataStream << for small numeric types and more performance by removing an indirection level
{
protected:
DataWriter(const DataWriter &o) : QMovedWriter<DataWriter>(), io(o.io) {}
DataWriter(const DataWriter &o) : io(o.io) {}
DataWriter &operator=(const DataWriter &) = delete;
public:
Q_ENABLE_MOVE(DataWriter, std::swap(io, o.io); )
......@@ -68,6 +70,8 @@ protected:
friend class QMovedWriter<DataWriter>;
template<class T_> friend class Val; // calls methods below
bool _isOk() { return io && io->status()==QDataStream::Ok; } // for QMovedWriter
bool _sequence(quint32* rows=nullptr) { if (rows) *io << *rows; return true; }
bool _record (quint32* cols=nullptr) { if (cols) *io << *cols; return true; }
bool _null ( ) { *io << nullptr; return true; }
......
......@@ -177,15 +177,13 @@ public:
~QJsonWriter() { for (auto&& level : levels) io->write(level.end); }
// Shortcuts
/**/ Val<Writer> value ( ) { return write().value ( ); }
/**/ Val<Writer> meta ( MetaData&& m) { return write().meta ( m); }
/**/ Val<Writer> meta ( MetaData& m) { return write().meta ( m); }
/**/ Seq<Writer> sequence(quint32* s=nullptr) { return write().sequence ( s); }
/**/ Rec<Writer> record (quint32* s=nullptr) { return write().record ( s); }
/**/ Writer null ( ) { return write().null ( ); }
template<typename T> Writer bind ( T&& t) { return write().bind(std::forward<T>(t)); }
private:
inline Writer write() { return Writer(this); }
/**/ Val<Writer> value ( ) { return Writer(this).value ( ); }
/**/ Val<Writer> meta ( MetaData&& m) { return Writer(this).meta ( m); }
/**/ Val<Writer> meta ( MetaData& m) { return Writer(this).meta ( m); }
/**/ Seq<Writer> sequence(quint32* s=nullptr) { return Writer(this).sequence ( s); }
/**/ Rec<Writer> record (quint32* s=nullptr) { return Writer(this).record ( s); }
/**/ Writer null ( ) { return Writer(this).null ( ); }
template<typename T> Writer bind ( T&& t) { return Writer(this).bind(std::forward<T>(t)); }
protected:
bool _sequence(quint32* rows=nullptr) { Q_UNUSED(rows); levels.push(Step{"","]"}); return io->write("["); }
bool _record (quint32* cols=nullptr) { Q_UNUSED(cols); levels.push(Step{"","}"}); return io->write("{"); }
......
......@@ -54,18 +54,14 @@ public:
QVariantBuilder(QVariant* v) : variant(v) { Q_ASSERT(v); }
~QVariantBuilder() { while (!levels.isEmpty()) _out(); }
operator bool() { return true; } // for QMovedWriter
// Shortcuts
/**/ Val<Writer> value ( ) { return write().value ( ); }
/**/ Val<Writer> meta ( MetaData&& m) { return write().meta ( m); }
/**/ Val<Writer> meta ( MetaData& m) { return write().meta ( m); }
/**/ Seq<Writer> sequence(quint32* s=nullptr) { return write().sequence ( s); }
/**/ Rec<Writer> record (quint32* s=nullptr) { return write().record ( s); }
/**/ Writer null ( ) { return write().null ( ); }
template<typename T> Writer bind ( T&& t) { return write().bind(std::forward<T>(t)); }
private:
inline Writer write() { return Writer(this); }
/**/ Val<Writer> value ( ) { return Writer(this).value ( ); }
/**/ Val<Writer> meta ( MetaData&& m) { return Writer(this).meta ( m); }
/**/ Val<Writer> meta ( MetaData& m) { return Writer(this).meta ( m); }
/**/ Seq<Writer> sequence(quint32* s=nullptr) { return Writer(this).sequence ( s); }
/**/ Rec<Writer> record (quint32* s=nullptr) { return Writer(this).record ( s); }
/**/ Writer null ( ) { return Writer(this).null ( ); }
template<typename T> Writer bind ( T&& t) { return Writer(this).bind(std::forward<T>(t)); }
protected:
template<typename T>
bool _bind ( T& t) { set(QVariant::fromValue(t)); return true; }
......
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