Commit 02da707b authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

Small changes + WIP JsonVisitor

parent 0d92bae2
......@@ -75,9 +75,8 @@ public:
Q_ENABLE_MOVE_DEFAULT(Val)
Val(T_&& out) { std::swap(m_out, out); }
using TResult = typename T_::TResult; //!< the start and end point of the traversal as well as the associated processing (see QJsonWriter for an example)
using TImpl = typename TResult::TImpl;
//static constexpr BindMode Mode = TResult::Mode;
using TResult = typename T_::TResult; //!< the result of the traversal
using TImpl = typename TResult::TImpl; //!< the processing associated to the traversal (see QJsonWriter for an example)
operator bool() { return m_out.operator bool(); } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { return m_out.operator ->(); }
......@@ -103,7 +102,6 @@ public:
// T_ can be either a TResult or any combination of nested Seq or Rec like Rec<Seq<TResult>
using TResult = typename T_::TResult; //!< the start and end point of the traversal as well as the associated processing (see QJsonWriter for an example)
using TImpl = typename TResult::TImpl;
static constexpr BindMode Mode = TResult::Mode;
Seq(T_&& out) { std::swap(m_out, out); }
......@@ -158,12 +156,13 @@ protected:
QScopedResult(TImpl* result, bool owned) : m(result), m_owned(owned) {}
TImpl* m = nullptr;
bool m_owned = true; //!< for nested QBind only
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)
//! \warning
//! - it is more difficult to implement TResult correctly, especially with internal state (need to understand move semantics)
//! - it is more difficult to correctly implement a TResult derived from QMovedResult, especially with internal state (need to understand move semantics)
//! - TResult scoped copies do not share state (such as the whole path to the current value)
//! - TResult is not pimpled by default
template<class TResult_, BindMode Mode_>
class QMovedResult
......@@ -251,6 +250,23 @@ struct QBind<TResult, double> {
}
};
template<class TResult>
struct QBind<TResult, const float> { static TResult bind(Val<TResult> dst, const float& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const float&");
  • Forced to put this static_assert in every new QBind ?

  • It just seemed better to tell the user "it is impossible" (to bind a Reader with a const float) rather than "i don't know how to do that"

    BTW, the QBind signature probably needs to be changed to support T&& in addition to const T& + the hidden parameter used to distinguish Read/Write of QBind<_,T&> (not const T&) should be changed to work with C++ and msvc, so...

    If it's possible to generically static_assert that all QBind<TResult,const T&> and QBind<TResult,T&&> are impossible when TResult::Mode==Read, let's do it !

Please register or sign in to reply
// 8 = std::numeric_limits<float>::max_digits10
char n[1+std::numeric_limits<float>::digits10+1+8+1+1+std::numeric_limits<float>::max_exponent10+1];
sprintf(n, "%.8g", src);
return dst.bind(static_cast<const char*>(n));
}};
template<class TResult>
struct QBind<TResult, float> {
static TResult bind(Val<TResult> dst, float& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
char n[1+std::numeric_limits<float>::digits10+1+8+1+1+std::numeric_limits<float>::max_exponent10+1];
sprintf(n, "%.8g", src);
return dst.bind(static_cast<const char*>(n));
}
};
#include <QtCore/qstring.h>
template<class TResult>
......
......@@ -109,7 +109,7 @@ private:
class CborWriter : public QMovedResult<CborWriter, BindMode::Write>
{
protected:
CborWriter(const CborWriter &o) : QMovedResult(), io(o.io), levels(0) {} // It is important that scoped copies start again from level 0
CborWriter(const CborWriter &o) : QMovedResult(), io(o.io), levels(0) {} // It is important that scoped copies start again from level 0 to avoid duplicate _out() calls
CborWriter &operator=(const CborWriter &) = delete;
public:
Q_ENABLE_MOVE(CborWriter, std::swap(io, o.io); std::swap(levels, o.levels); )
......
......@@ -68,21 +68,21 @@ class QJsonBuilderImpl
{
Q_DISABLE_COPY(QJsonBuilderImpl)
QJsonValue* result;
struct Step { const char* key; /* TODO union */ QJsonObject object; QJsonArray array; Step(const char* k=nullptr) : key(k) {}};
QJsonValue* value;
struct Step { const char* key; /* TODO union */ QJsonObject object; QJsonArray array; Step(const char* k=nullptr) : key(k) {} };
QStack<Step> levels = QStack<Step>(); //!< minimal dynamic context to implement out() and ensure actual building in case QJsonBuilderImpl is abandoned
public:
QJsonBuilderImpl(QJsonValue* v) : result(v) { Q_ASSERT(v); }
QJsonBuilderImpl(QJsonValue* v) : value(v) { Q_ASSERT(v); }
protected:
friend class QScopedResult<QJsonBuilder, QJsonBuilderImpl, BindMode::Write>; // for slight optimization of fluent interface shortcuts
template<class T_> friend class Val; // calls methods below
bool _record() { levels.push(Step("" )); return true; }
bool _sequence() { levels.push(Step(nullptr)); return true; }
bool _null() { set(QJsonValue ()); return true; }
bool _bind(const char* s) { set(s ); return true; }
bool _bind(double d) { set(d ); return true; }
bool _bind(bool b) { set(b ); 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; }
template<typename T> bool _bind(T t, std::enable_if_t<std::is_arithmetic<T>::value>* = nullptr) { return _bind(double(t)); }
......@@ -96,9 +96,9 @@ protected:
bool _item(const char* key=nullptr) { levels.last().key=key; return true; }
bool _out() { auto level = levels.pop(); set(level.key ? QJsonValue(level.object) : QJsonValue(level.array)); return true; }
private:
void set(QJsonValue v) {
void set(const QJsonValue& v) {
if (levels.isEmpty()) {
*result = v;
*value = v;
}
else {
if (levels.last().key)
......@@ -110,6 +110,45 @@ private:
};
QJsonBuilder::QJsonBuilder(QJsonValue* v) : QScopedResult(new QJsonBuilderImpl(v), true) {}
//class JsonVisitor : public QMovedResult<JsonVisitor, BindMode::Read>
//{
//protected:
// JsonVisitor(const JsonVisitor &o) : QMovedResult(), value(o.current()), steps(o.steps) {}
// JsonVisitor &operator=(const JsonVisitor &) = delete;
//public:
// Q_ENABLE_MOVE(JsonVisitor, std::swap(value, o.value); std::swap(steps, o.steps); )
// JsonVisitor(const QJsonValue* v) : value(v) { Q_ASSERT(v); }
//
// operator bool() { return value; } // for QMovedResult
//protected:
// friend class QMovedResult<JsonVisitor, BindMode::Read>; // for slight optimization of fluent interface shortcuts
// template<class T_> friend class Val; // calls methods below
//
// bool _null() { if (current()->isNull ()) { return true; } return false; }
// bool _record() { if (current()->isObject()) { steps.push(Step()); return true; } return false; }
// bool _sequence() { if (current()->isArray ()) { steps.push(Step()); return true; } return false; }
// bool _bind(QString& v) { if (current()->isString()) { v = current()->toString(); return true; } return false; }
// bool _bind( double& v) { if (current()->isDouble()) { v = current()->toDouble(); return true; } return false; }
// bool _bind( bool& v) { if (current()->isBool ()) { v = current()->toBool (); return true; } 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<TResult,T>::bind(TResult(*this).value(), t); }
//
// template<class T_> friend class Seq; // calls methods below
//
// bool _item(const char* key) { steps.last().key=key; steps.last().item=current(1)->toObject()[QString::fromUtf8(steps.last().key)]; return true; }
// bool _item( ) { steps.last().idx++ ; steps.last().item=current(1)->toArray ()[ steps.last().idx ]; return true; }
// bool _out() { steps.pop(); return true; }
//private:
// const QJsonValue* current(unsigned outer=0) const { return steps.size()-outer <= 0 ? value : &(steps[steps.size()-outer-1].item); }
//
// const QJsonValue* value;
// struct Step { const char* key=nullptr; int idx=-1; QJsonValue item; Step() = default; };
// QStack<Step> steps = QStack<Step>();
//};
class QJsonWriterImpl;
class QJsonWriter : public QScopedResult<QJsonWriter, QJsonWriterImpl, BindMode::Write>
{
......
......@@ -46,7 +46,7 @@
// Extensible set of TResult implementations providing concrete syntax to the logical data structure in a specific Mode among Write, Read, ...
#include "QJson_impl.h" // QJsonWriter, QJsonReader, QJsonBuilder and QBind<_,QJsonValue> support
#include "QJson_impl.h" // QJsonWriter, QJsonReader, QJsonBuilder and QBind<_,QJsonValue> support
#include "QCbor_impl.h" // QCborWriter demonstrating the performance potential of the approach
// //////////////////////////////////////////////////////////////////////////
......@@ -86,22 +86,20 @@ protected:
friend class QMovedResult<TextWriter, BindMode::Write>;
template<class T_> friend class Val; // enables calling methods below through operator->()
bool _sequence() { io->write("["); return true; }
bool _null() { return true; }
bool _sequence() { 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<TResult,T>::bind(Val<TResult>(TResult(io)), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<TResult,T>::bind(Val<TResult>(TResult(io)), t ); }
template<typename T> bool _bind( T&& t) { return QBind<TResult,T>::bind(Val<TResult>(TResult(io)), t ); } // TODO return TResult(*this).bind(t);
template<typename T> bool _bind(const T& t) { return QBind<TResult,T>::bind(TResult(io).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<TResult,T>::bind(TResult(io).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<TResult,T>::bind(TResult(io).value(), t ); }
template<class T_> friend class Seq; // enables calling methods below through operator->()
bool _item() { io->write(" "); return true; }
bool _out() { io->write("]"); return true; }
private:
template<class T_> friend class Seq;
QIODevice* io = nullptr; // for QMovedResult
};
......@@ -182,7 +180,7 @@ int main()
b.seek(0); b.buffer().clear();
TextWriter(&b)
.sequence()
.bind(123)
.bind(1.333333333333f)
.bind(text)
;
}
......@@ -211,12 +209,12 @@ int main()
writables.append(1.333333333333f);
writables.append(text);
}
STOP("QWritable","");
STOP("Writables","");
START {
b.seek(0); b.buffer().clear();
CborWriter(&b).bind(writables);
}
STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
STOP("Writables>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP;
GROUP("<doubles")
......@@ -249,12 +247,12 @@ int main()
START {
writable = transform;
}
STOP("QWritable","");
STOP("Writable","");
START {
b.seek(0); b.buffer().clear();
CborWriter(&b).bind(writable);
}
STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
STOP("Writable>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP
GROUP("<Person")
......@@ -288,12 +286,12 @@ int main()
START {
writable = person;
}
STOP("QWritable","");
STOP("Writable","");
START {
b.seek(0); b.buffer().clear();
CborWriter(&b).bind(writable);
}
STOP("QWritable>Cbor",QString::fromUtf8(b.buffer().toHex()));
STOP("Writable>Cbor",QString::fromUtf8(b.buffer().toHex()));
}
GROUP_STOP
GROUP("Read+Write")
......@@ -313,6 +311,10 @@ int main()
QJsonBuilder(&v).bind(p);
}
STOP("T>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()));
// START {
// JsonVisitor(&v).bind(p);
// }
// STOP("JsonValue>T",QString("[%1,%2,%3,[..%4..]] errors:%5").arg(p.firstName,p.lastName).arg(p.height).arg(p.phones.size()).arg(errors.size()))
START {
json.seek(0); v = QJsonValue();
errors = QJsonReader(&json).bind(v)->errors;
......
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