Commit 8c357b03 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

removed redundant pointers (more simple to debug)

WIP: replaced allocation of TResultShared with move semantic (copy only used for nested QBind) for very slight perf improvement
parent b6f35450
......@@ -40,14 +40,10 @@
#pragma once
#include <QtCore/qglobal.h>
#define Q_ENABLE_MOVE(Class) \
#define Q_ENABLE_DEFAULT_MOVE(Class) \
Class ( ) = default; \
Class (Class&& o) = default; \
Class& operator=(Class&& o) = default;
#define Q_ENABLE_SWAP(Class, Statements) \
Class ( ) = default; \
Class (Class&& o) noexcept { Statements } \
Class& operator=(Class&& o) noexcept { if (this!=&o) { Statements } return *this; }
// //////////////////////////////////////////////////////////////////////////
// Generic fluent interface for traversing and processing structured value types (serialize, deserialize, construct generic in-memory data structures, etc...)
......@@ -59,46 +55,45 @@ template<class T_> class Rec; //!< a Record data structure (not defined in this
template<class T_> class Seq; //!< a Sequence data structure defined below
template<class T_> class Val //!< a choice of sequence(), null(), or any value with a textual representation
{
Q_DISABLE_COPY(Val) // but not swap
Q_DISABLE_COPY(Val)
public:
Q_ENABLE_SWAP(Val, std::swap(m_val, o.m_val); std::swap(m_out, o.m_out);)
Q_ENABLE_DEFAULT_MOVE(Val)
// T_ can be either a TResult or any combination of nested Seq or Rec like T_ = Rec<Seq<TResult>
using TResult = typename T_::TResult; //!< the start and end point of the traversal as well as the associated processing (see QJsonWriter below for an example)
using TValue = typename TResult::TValue;
static const BindMode Mode = TResult::Mode;
Val(TValue val, T_&& out) { std::swap(m_val, val); std::swap(m_out, out); }
Val(T_&& out) { std::swap(m_out, out); }
operator bool() { return bool(m_val); } //!< to drive QBind<TResult,T>() traversal
operator bool() { return bool(m_out); } //!< to drive QBind<TResult,T>() traversal
Seq<T_> sequence() { auto seq = Q_LIKELY(m_val) ? m_val->sequence() : nullptr ; return Seq<T_>(seq, seq ? std::move(m_out) : T_()); }
/**/T_ null() { auto n = Q_LIKELY(m_val) ? m_val-> null() : false ; return n ? std::move(m_out) : T_() ; }
/**/ Seq<T_> sequence() { if (Q_LIKELY(m_out) && m_out->sequence()) return Seq<T_>(std::move(m_out)); return Seq<T_>(); }
/**/ T_ null() { if (Q_LIKELY(m_out) && m_out-> null()) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind(const T& t) { auto v = Q_LIKELY(m_val) ? m_val->bind(t) : false ; return v ? std::move(m_out) : T_() ; }
template<typename T> T_ bind( T& t) { auto v = Q_LIKELY(m_val) ? m_val->bind(t) : false ; return v ? std::move(m_out) : T_() ; }
template<typename T> T_ bind( T&& t) { auto v = Q_LIKELY(m_val) ? m_val->bind(t) : false ; return v ? std::move(m_out) : T_() ; }
template<typename T> T_ bind(const T& t) { if (Q_LIKELY(m_out) && m_out-> bind(t)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind( T& t) { if (Q_LIKELY(m_out) && m_out-> bind(t)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind( T&& t) { if (Q_LIKELY(m_out) && m_out-> bind(t)) return std::move(m_out) ; return T_ (); }
private:
TValue m_val = TValue(); //!< gives semantic to the traversal (nullptr if already moved)
T_ m_out = T_ (); //!< moved context of current traversal up to TResult that will reference the val itself (be it a QIODevice or QCborValue)
T_ m_out = T_(); //!< moved context of current traversal up to TResult that will reference the val itself (be it a QIODevice or QCborValue)
};
template<class T_> class Seq
{
Q_DISABLE_COPY(Seq) // but not swap
Q_DISABLE_COPY(Seq)
public:
Q_ENABLE_SWAP(Seq, std::swap(m_seq, o.m_seq); std::swap(m_out, o.m_out);)
Q_ENABLE_DEFAULT_MOVE(Seq)
using TResult = typename T_::TResult;
using TValue = typename TResult::TValue;
static const BindMode Mode = TResult::Mode;
Seq(TValue seq, T_&& out) { std::swap(m_seq, seq); std::swap(m_out, out); }
Seq(T_&& out) { std::swap(m_out, out); }
operator bool() { return m_seq; } //!< to drive QBind<TResult,T>() traversal
operator bool() { return m_out; } //!< to drive QBind<TResult,T>() traversal
Val<Seq<T_>> item() { auto v = Q_LIKELY(m_seq) ? m_seq->item() : nullptr; return Val<Seq<T_>>(v, v ? std::move(*this) : Seq<T_>()); }
T_ out() { if (Q_LIKELY(m_seq) ) m_seq->out () ; return std::move(m_out) ; }
Val<Seq<T_>> item() { if (Q_LIKELY(m_out) && m_out->item()) return Val<Seq<T_>>(std::move(*this)); return Seq<T_>(); }
T_ out() { if (Q_LIKELY(m_out) && m_out-> out()) return std::move(m_out) ; return T_ (); }
operator TResult() { return out(); /* recursively calls operator TResult() as mandated by T_ */ }
TResult result() { return operator TResult(); }
......@@ -107,29 +102,30 @@ public:
template<typename T> Seq<T_> bind(const T& t) { return item().bind(t); }
template<typename T> Seq<T_> bind( T& t) { return item().bind(t); }
template<typename T> Seq<T_> bind( T&& t) { return item().bind(t); }
TValue operator->() { return m_out.operator->(); }
private:
TValue m_seq = TValue();
T_ m_out = T_ ();
T_ m_out = T_();
};
template<class TResultPtr, class TResultShared>
template<class TDerived, class TResultShared>
class QBindResult
{
Q_DISABLE_COPY(QBindResult) // but not swap
Q_DISABLE_COPY(QBindResult)
public:
Q_ENABLE_SWAP(QBindResult, std::swap(m, o.m); std::swap(m_owned, o.m_owned); )
Q_ENABLE_DEFAULT_MOVE(QBindResult)
using TResult = TResultPtr;
using TResult = TDerived;
using TValue = TResultShared*;
~QBindResult() { if (m && m_owned) delete m; }
static const BindMode Mode = TResult::Mode;
operator bool() { return m; } //!< to drive QBind<TResult,T>() traversal
TValue operator->() { return m ? &m : nullptr; }
protected:
QBindResult(TResultShared* m, bool owned = true) : m(m), m_owned(owned) {}
QBindResult( TResultShared&& m) : m(m) {}
QBindResult(const TResultShared& m) : m(m) {} // for nested QBind only
TResultShared* m = nullptr;
bool m_owned = true;
TResultShared m = TResultShared(); //!< gives semantic to the traversal (nullptr if already moved)
};
// //////////////////////////////////////////////////////////////////////////
......@@ -158,6 +154,39 @@ struct QBind<TResult, std::nullptr_t> { static TResult bind(Val<TResult> value,
return value.null();
}};
template<class TResult>
struct QBind<TResult, const int> { static TResult bind(Val<TResult> dst, const int& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const int&");
char n[1+std::numeric_limits<int>::digits10+1];
itoa(src, n, 10);
return dst.bind(static_cast<const char*>(n));
}};
template<class TResult>
struct QBind<TResult, int> {
static TResult bind(Val<TResult> dst, int& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
char n[1+std::numeric_limits<int>::digits10+1];
itoa(src, n, 10);
return dst.bind(static_cast<const char*>(n));
}
};
template<class TResult>
struct QBind<TResult, const double> { static TResult bind(Val<TResult> dst, const double& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const double&");
// 17 = std::numeric_limits<double>::max_digits10
char n[1+std::numeric_limits<double>::digits10+1+17+1+1+std::numeric_limits<double>::max_exponent10+1];
sprintf(n, "%.17g", src);
return dst.bind(static_cast<const char*>(n));
}};
template<class TResult>
struct QBind<TResult, double> {
static TResult bind(Val<TResult> dst, double& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
char n[1+std::numeric_limits<double>::digits10+1+17+1+1+std::numeric_limits<double>::max_exponent10+1];
sprintf(n, "%.17g", src);
return dst.bind(static_cast<const char*>(n));
}
};
#include <QtCore/qstring.h>
template<class TResult>
......@@ -170,14 +199,14 @@ struct QBind<TResult, QString> {
static TResult bind(Val<TResult> dst, QString& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
return dst.bind(src.toUtf8().constData());
}
static TResult bind(Val<TResult> src, QString& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
QByteArray ba;
auto result = src.bind(ba);
if (result)
dst = QString::fromUtf8(ba);
return result;
}
//static TResult bind(Val<TResult> src, QString& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
// QByteArray ba;
// auto result = src.bind(ba);
// if (result)
// dst = QString::fromUtf8(ba);
//
// return result;
//}
};
#include <QtCore/qvector.h>
......@@ -200,16 +229,16 @@ struct QBind<TResult, QVector<T>> {
}
return s;
}
static TResult bind(Val<TResult> src, QVector<T>& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
auto s(src.sequence());
for (auto i = s.item(); i; i = s.item()) {
T t;
s = i.bind(t);
if (s)
dst.push_back(t);
}
return s;
}
//static TResult bind(Val<TResult> src, QVector<T>& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
// auto s(src.sequence());
// for (auto i = s.item(); i; i = s.item()) {
// T t;
// s = i.bind(t);
// if (s)
// dst.push_back(t);
// }
// return s;
//}
};
// --------------------------------------------------------------------------
......
......@@ -156,7 +156,7 @@ class QCborWriter : public QBindResult<QCborWriter, QCborWriterShared>
{
Q_DISABLE_COPY(QCborWriter) // but not swap
public:
Q_ENABLE_MOVE(QCborWriter)
Q_ENABLE_DEFAULT_MOVE(QCborWriter)
static const BindMode Mode = BindMode::Write;
......
......@@ -98,7 +98,7 @@ class QJsonBuilder : public QBindResult<QJsonBuilder, QJsonBuilderShared>
{
Q_DISABLE_COPY(QJsonBuilder) // but not swap
public:
Q_ENABLE_MOVE(QJsonBuilder)
Q_ENABLE_DEFAULT_MOVE(QJsonBuilder)
static const BindMode Mode = BindMode::Write;
......@@ -162,7 +162,7 @@ class QJsonWriter : public QBindResult<QJsonWriter, QJsonWriterShared>
{
Q_DISABLE_COPY(QJsonWriter) // but not swap
public:
Q_ENABLE_MOVE(QJsonWriter)
Q_ENABLE_DEFAULT_MOVE(QJsonWriter)
static const BindMode Mode = BindMode::Write;
......@@ -364,7 +364,7 @@ class QJsonReader : public QBindResult<QJsonReader, QJsonReaderShared>
{
Q_DISABLE_COPY(QJsonReader) // but not swap
public:
Q_ENABLE_MOVE(QJsonReader)
Q_ENABLE_DEFAULT_MOVE(QJsonReader)
static const BindMode Mode = BindMode::Read;
......
......@@ -46,8 +46,8 @@
// Extensible set of TResult implementations providing concrete syntax to the logical data structure in a specific Mode among Write, Read, ...
#include "QJson.hpp" // QJsonWriter, QJsonReader, QJsonBuilder and QBind<_,QJsonValue> support
#include "QCborWriter.hpp" // QCborWriter demonstrating the performance potential of the approach
//#include "QJson.hpp" // QJsonWriter, QJsonReader, QJsonBuilder and QBind<_,QJsonValue> support
//#include "QCborWriter.hpp" // QCborWriter demonstrating the performance potential of the approach
// //////////////////////////////////////////////////////////////////////////
// QBind<_,T> basic example using an internal bind<TResult> method
......@@ -75,40 +75,44 @@ struct Person
#include <QtCore/qiodevice.h>
class QTextWriter;
class QTextWriterShared {
QIODevice* io;
class QTextWriterShared
{
QIODevice* io = nullptr;
public:
QTextWriterShared() = default;
QTextWriterShared(QIODevice* io) : io(io) { Q_ASSERT(io); }
operator bool() { return io; } //!< to drive QBind<TResult,T>() traversal
protected:
template<class T_> friend class Val; // calls methods below
template<class T_> friend class Val; // enables calling methods below through operator->()
QTextWriterShared* sequence() { io->write( "[" ); return this; }
bool sequence() { io->write( "[" ); return true; }
bool null() { return true; }
bool bind(const char* s) { io->write("\"" );
io->write( s );
io->write("\"" ); return true; }
bool bind(const char* s) { io->write( s ); return true; }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool bind(const T& t) { return QBind<QTextWriter,T>::bind(Val<QTextWriter>(this, QTextWriter(this)), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool bind( T& t) { return QBind<QTextWriter,T>::bind(Val<QTextWriter>(this, QTextWriter(this)), t ); }
template<typename T> bool bind( T&& t) { return QBind<QTextWriter,T>::bind(Val<QTextWriter>(this, QTextWriter(this)), t ); }
template<typename T> bool bind(const T& t) { return QBind<QTextWriter,T>::bind(Val<QTextWriter>(QTextWriter(*this)), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool bind( T& t) { return QBind<QTextWriter,T>::bind(Val<QTextWriter>(QTextWriter(*this)), t ); }
template<typename T> bool bind( T&& t) { return QBind<QTextWriter,T>::bind(Val<QTextWriter>(QTextWriter(*this)), t ); }
template<class T_> friend class Seq; // calls methods below
template<class T_> friend class Seq; // enables calling methods below through operator->()
QTextWriterShared* item() { io->write(" "); return this; }
QTextWriterShared* out() { io->write("]"); return this; }
bool item() { io->write(" "); return true; }
bool out() { io->write("]"); return true; }
};
class QTextWriter : public QBindResult<QTextWriter, QTextWriterShared>
{
Q_DISABLE_COPY(QTextWriter)
public:
Q_ENABLE_MOVE(QTextWriter)
Q_ENABLE_DEFAULT_MOVE(QTextWriter)
static const BindMode Mode = BindMode::Write;
QTextWriter(QIODevice* io) : QBindResult(new QTextWriterShared(io)) {}
QTextWriter(QIODevice* io) : QBindResult(std::move(QTextWriterShared(io))) {}
Val<QTextWriter> begin() { return std::move(Val<TResult>(std::move(*this))); }
private:
friend class QTextWriterShared; // uses method below
QTextWriter(QTextWriterShared* shared) : QBindResult(shared, false) {}
QTextWriter(const QTextWriterShared& shared) : QBindResult(shared) {}
};
// //////////////////////////////////////////////////////////////////////////
......@@ -187,34 +191,42 @@ int main()
STOP("QDebug",s);
START {
b.seek(0); b.buffer().clear();
QJsonWriter(&b)
.sequence()
.bind(1.333333333333f)
.bind(text)
;
}
STOP("Json",QString::fromUtf8(b.buffer()));
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b)
QTextWriter(&b).begin()
.sequence()
.bind(1.333333333333f)
.bind(123)
.bind(text)
;
}
STOP("Cbor",QString::fromUtf8(b.buffer().toHex()));
QVector<QWritable<QCborWriter>> writables;
START {
writables.clear();
writables.append(1.333333333333f);
writables.append(text);
}
STOP("QWritable","");
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b).bind(writables);
}
STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
STOP("Text",QString::fromUtf8(b.buffer()));
// START {
// b.seek(0); b.buffer().clear();
// QJsonWriter(&b)
// .sequence()
// .bind(1.333333333333f)
// .bind(text)
// ;
// }
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b)
// .sequence()
// .bind(1.333333333333f)
// .bind(text)
// ;
// }
// STOP("Cbor",QString::fromUtf8(b.buffer().toHex()));
// QVector<QWritable<QCborWriter>> writables;
// START {
// writables.clear();
// writables.append(1.333333333333f);
// writables.append(text);
// }
// STOP("QWritable","");
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b).bind(writables);
// }
// STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP;
GROUP("Format << doubles")
......@@ -230,24 +242,31 @@ int main()
STOP("QDebug",s);
START {
b.seek(0); b.buffer().clear();
QJsonWriter(&b).bind(transform);
}
STOP("Json",b.buffer())
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b).bind(transform);
}
STOP("Cbor",QString::fromUtf8(b.buffer().toHex()));
QWritable<QCborWriter> writable;
START {
writable = transform;
}
STOP("QWritable","");
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b).bind(writable);
QTextWriter(&b).begin()
.bind(transform)
;
}
STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
STOP("Text",QString::fromUtf8(b.buffer()));
// START {
// b.seek(0); b.buffer().clear();
// QJsonWriter(&b).bind(transform);
// }
// STOP("Json",b.buffer())
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b).bind(transform);
// }
// STOP("Cbor",QString::fromUtf8(b.buffer().toHex()));
// QWritable<QCborWriter> writable;
// START {
// writable = transform;
// }
// STOP("QWritable","");
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b).bind(writable);
// }
// STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP
GROUP("Format << struct")
......@@ -264,55 +283,60 @@ int main()
STOP("QDebug",s);
START {
b.seek(0); b.buffer().clear();
QJsonWriter(&b).bind(person);
}
STOP("Json",b.buffer())
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b).bind(person);
}
STOP("Cbor",QString::fromUtf8(b.buffer().toHex()));
QWritable<QCborWriter> writable;
START {
writable = person;
}
STOP("QWritable","");
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b).bind(writable);
}
STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP
GROUP("Read+Write")
{
b.buffer()="[\"John\",\"Doe\",1.75,[\"+44 1234567\",\"+44 2345678\"]]";
Person p;
START {
b.seek(0); p = {};
QJsonReader(&b).bind(p);
}
STOP("Json>struct",QString("[%1,%2,%3]").arg(p.firstName,p.lastName,QString::number(p.height)))
START {
b.seek(0); b.buffer().clear();
QJsonWriter(&b).bind(p);
}
STOP("struct>Json",b.buffer())
QJsonValue v;
START {
QJsonBuilder(&v).bind(p);
}
STOP("struct>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()));
START {
b.seek(0); v = QJsonValue();
QJsonReader(&b).bind(v);
}
STOP("Json>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()));
START {
b.seek(0); b.buffer().clear();
QCborWriter(&b).bind(v);
QTextWriter(&b).begin().bind(person);
}
STOP("JsonValue>Cbor",QString::fromUtf8(b.buffer().toHex()));
STOP("Text",QString::fromUtf8(b.buffer()));
// START {
// b.seek(0); b.buffer().clear();
// QJsonWriter(&b).bind(person);
// }
// STOP("Json",b.buffer())
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b).bind(person);
// }
// STOP("Cbor",QString::fromUtf8(b.buffer().toHex()));
// QWritable<QCborWriter> writable;
// START {
// writable = person;
// }
// STOP("QWritable","");
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b).bind(writable);
// }
// STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
// }
// GROUP_STOP
// GROUP("Read+Write")
// {
// b.buffer()="[\"John\",\"Doe\",1.75,[\"+44 1234567\",\"+44 2345678\"]]";
// Person p;
// START {
// b.seek(0); p = {};
// QJsonReader(&b).bind(p);
// }
// STOP("Json>struct",QString("[%1,%2,%3]").arg(p.firstName,p.lastName,QString::number(p.height)))
// START {
// b.seek(0); b.buffer().clear();
// QJsonWriter(&b).bind(p);
// }
// STOP("struct>Json",b.buffer())
// QJsonValue v;
// START {
// QJsonBuilder(&v).bind(p);
// }
// STOP("struct>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()));
// START {
// b.seek(0); v = QJsonValue();
// QJsonReader(&b).bind(v);
// }
// STOP("Json>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()));
// START {
// b.seek(0); b.buffer().clear();
// QCborWriter(&b).bind(v);
// }
// STOP("JsonValue>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP
return fclose(samples);
......
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