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

WIP

parent 84232b5b
......@@ -54,7 +54,7 @@ protected: \
Class& operator=(Class&& o) noexcept { if (this!=&o) { Statements } return *this; }
#include <QtCore/qbytearray.h>
//!< Explicitely utf8 encoded string of char
//! Explicitely utf8 encoded string of char
class QUtf8String : public QByteArray
{
public:
......@@ -199,9 +199,12 @@ public:
/**/ Seq<T_> sequence( quint32 s) { return sequence(&s); }
/**/ Rec<T_> record ( quint32 s) { return record (&s); }
// Sequence comprehension support
T_ bindSequence(QBindSeqFunction<TResult> customBind) { return sequence().bindFrom(customBind).out(); }
// Shortcuts
template<typename T> Seq<T_> operator<<( T&& t) { return sequence().bind(std::forward<T>(t)); } // stream compatible
/**/ Rec<T_> record (QName n) { return meta({{qmName,n}}).record(); }
template<typename T> Seq<T_> operator<< ( T&& t) { return sequence().bind(std::forward<T>(t)); } // stream compatible
/**/ Rec<T_> record (QName n) { return meta({{qmName,n}}).record(); }
private:
T_ outer = T_(); //!< moved context of current traversal up to TResult that will point to the value itself (be it a QIODevice or QCborValue)
};
......@@ -225,8 +228,6 @@ public:
Val<Seq<T_>> item() { return outer->_item() ? Val<Seq<T_>>(std::move(*this)) : Val<Seq<T_>>(); }
// Shortcuts
template<class Ts, typename TItem = typename Ts::value_type>
/**/ Seq<T_> from (Ts&, typename T_::TResult(*)(TItem&, Val<typename T_::TResult>&&), bool(*)(const TItem&) = [](const TItem&){ return true; });
/**/ Seq<Seq<T_>> sequence(quint32* s=nullptr) { return item().sequence ( s); }
/**/ Rec<Seq<T_>> record (quint32* s=nullptr) { return item().record ( s); }
/**/ Seq<T_> null ( ) { return item().null ( ); }
......@@ -235,7 +236,10 @@ public:
template<typename T> Rec<T_> bind (T& t, T&& defaultT) { return item().bind(t,std::forward<T>(defaultT)); }
// Sequence comprehension support
Seq<T_> bindFrom(QBindSeqFunction<TResult> customBind) { customBind(std::move(unsafeThis())); return std::move(*this); }
template<class Ts>
Seq<T_> from (Ts&, TResult(*)(typename Ts::value_type&, Val<TResult>&&), bool(*)(const typename Ts::value_type&) = [](const typename Ts::value_type&) { return true; });
Seq<T_> bindFrom (QBindSeqFunction<TResult> customBind) { return bool(customBind(std::move(unsafeThis()))) ? std::move(*this) : Seq<T_>(); }
/**/T_ bindSequence(QBindSeqFunction<TResult> customBind) { return item().bindSequence(customBind); }
// Stream compatible shortcut
template<typename T> Seq<T_> operator<<(T&& t) { return item().bind(std::forward<T>(t)); }
......@@ -266,6 +270,9 @@ public:
Val<Rec<T_>> item(QUtf8String& n) { return outer->_item(n) ? Val<Rec<T_>>(std::move(*this)) : Val<Rec<T_>>(); }
Val<Rec<T_>> item( QName n) { return outer->_item(n) ? Val<Rec<T_>>(std::move(*this)) : Val<Rec<T_>>(); }
// Sequence comprehension support
T_ bindSequence(QName n, QBindSeqFunction<TResult> customBind) { return item(n).bindSequence(customBind); }
// Shortcuts
/**/ Seq<Rec<T_>> sequence(QName n, quint32* s=nullptr) { return item(n).sequence ( s); }
/**/ Rec<Rec<T_>> record (QName n, quint32* s=nullptr) { return item(n).record ( s); }
......@@ -766,10 +773,10 @@ public:
// QBind partial specializations (generic on TResult, usually not on v->mode() for dynamically-sized or builtin types)
template<class T_>
template<class Ts, typename TItem> // = Ts::value_type
template<class Ts>
Seq<T_> Seq<T_>::from(Ts& ts,
typename T_::TResult(*itemBind)(TItem&, Val<typename T_::TResult>&&),
bool(*itemPredicate)(const TItem&)) {
TResult(*itemBind)(typename Ts::value_type&, Val<TResult>&&),
bool(*itemPredicate)(const typename Ts::value_type&)) {
if ((*this)->mode()==Write) {
for (auto&& t : ts) {
if (itemPredicate(t)) {
......@@ -782,7 +789,7 @@ Seq<T_> Seq<T_>::from(Ts& ts,
auto&& i = ts.begin();
Val<typename T_::TResult> item;
while ((item = unsafeItem())) {
TItem newItem;
typename Ts::value_type newItem;
if (itemBind(newItem, std::move(item)) && itemPredicate(newItem)) {
if (i != ts.end()) {
*i = newItem;
......
......@@ -64,8 +64,9 @@ class QModelWriter : public IWriter
public:
QModelWriter(QAbstractItemModel* m, bool rowFirst=true) : m(m), rowFirst(rowFirst), w(&io) { Q_ASSERT(m); }
Seq<Cursor> sequence( ) { return Cursor(this).value().sequence( ); }
Val<Cursor> meta (QMetaData&& m) { return Cursor(this).value().meta (m); }
/**/Cursor bindSequence(QBindSeqFunction<Cursor> customBind) { return Cursor(this).value().bindSequence(customBind); }
Seq<Cursor> sequence ( ) { return Cursor(this).value().sequence(); }
Val<Cursor> meta ( QMetaData&& m) { return Cursor(this).value().meta(m); }
protected:
void _meta(QMetaData& meta) {
if (T==d) {
......
......@@ -959,7 +959,7 @@ Seq<Cursor>&& flatten(const QList<Person>& ps, Seq<Cursor>&& s) {
.bind("first name", p.firstName )
.bind("height(ft)", p.height*3.28)
.out()
.bindFrom([&](Seq<Cursor>&& s){
.bindFrom([&](Seq<Cursor>&& s)->Seq<Cursor>&& {
return std::move(flatten(p.children, std::move(s)));
});
}
......@@ -991,46 +991,42 @@ void doGuiExample() {
QModelWriter<>(& tableModel ).meta({{qmColumns , "names,age"} }).bind(persons);
// Various possible designs for flexible custom bind
#if 0
#if 1
// Safest design that works for Read/Write but requires several cumbersome functions
QModelWriter<>(&customModel).sequence().from<QList<Person>,Person>(persons, [](Person& p, Val<Cursor>&& item){ // ADL cannot deduce Person
QModelWriter<>(&customModel).sequence().from(persons, [](Person& p, Val<Cursor>&& item)->Cursor { // ADL cannot deduce Person
return item
.record()
.bind("first name", p.firstName)
.sequence("phones").from<QVector<Phone>,Phone>(p.phones,
.sequence("phones").from(p.phones,
[](Phone& phone, Val<Cursor>&& item){
return item.bind(phone._n);
},
[](const Phone& phone){
return phone._t == Phone::Office;
})
.out()
.out();
}); // automagically closed while cast to returned Cursor type
});
#else
// More powerful design similar to Pyhton list comprehensions that does not work by default for Read/Write
QModelWriter<>(&customModel).sequence().bindFrom([&](Seq<Cursor>&& s){
for (auto&& p : persons) { // Iterating on persons only works for Write
s = s // Required to keep working with active Cursor
// More powerful design similar to Python list comprehensions that does not work by default for Read/Write
QModelWriter<>(&customModel).bindSequence([&](Seq<Cursor>&& s)->Seq<Cursor>&& {
for (auto&& p : persons) { // Read would require looping while !s.item()
s = s // To keep working with the active Cursor
.record()
.bind("first name", p.firstName)
.sequence("phones")
.bindFrom([&] (Seq<Cursor>&& s) {
.bind("first name", p.firstName)
.bindSequence("phones", [&](Seq<Cursor>&& s)->Seq<Cursor>&& {
for (auto&& phone : p.phones) {
if (phone._t == Phone::Office) {
s = s.bind(phone._n);
}
}
return std::move(s);
})
.out()
.out();
});
//.out();
}
return std::move(s);
return std::move(s); // So caller stops calling IBind if user function was unable to keep track of the active Cursor
});
#endif
// The same design allows flattening trees into a sequence
QModelWriter<>(& flatModel).sequence().bindFrom([&](Seq<Cursor>&& s){
QModelWriter<>(& flatModel).bindSequence([&](Seq<Cursor>&& s)->Seq<Cursor>&& {
return std::move(flatten(persons, std::move(s)));
});
......
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