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

Illustrated possible designs for custom bind

parent e4d6ce80
......@@ -170,7 +170,8 @@ struct QBindDefault {
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_> using QBindSeqFunction = std::function<Seq<T_>&&(Seq<T_>&&)>;
template<class TResult>
using QBindSeqFunction = std::function<Seq<TResult>&&(Seq<TResult>&&)>;
template<class T_> class Val //!< a choice of sequence(), record(), null(), or any value with at least a textual representation and possibly binary ones
{
......@@ -224,7 +225,8 @@ public:
Val<Seq<T_>> item() { return outer->_item() ? Val<Seq<T_>>(std::move(*this)) : Val<Seq<T_>>(); }
// Shortcuts
template<typename Ts, typename T = typename Ts::value_type> Seq<T_> from(Ts& ts, std::function<TResult(Val<TResult>&&, T& t)> itemBind);
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 ( ); }
......@@ -239,7 +241,7 @@ public:
template<typename T> Seq<T_> operator<<(T&& t) { return item().bind(std::forward<T>(t)); }
private:
template<typename T, class TResult, typename TEnabledIf> friend struct QBind;
Val<TResult> unsafeItem() noexcept { return outer->_item() ? Val<TResult>(outer._unsafeCopy()) : Val<TResult>(); }
Val<TResult> unsafeItem() noexcept { return outer->_item() ? Val<TResult>(outer->_unsafeCopy()) : Val<TResult>(); }
Seq<TResult> unsafeThis() noexcept { return Seq<TResult>(outer->_unsafeCopy()) ; }
T_ outer = T_();
......@@ -764,27 +766,33 @@ public:
// QBind partial specializations (generic on TResult, usually not on v->mode() for dynamically-sized or builtin types)
template<class T_>
template<typename Ts, typename T>
Seq<T_> Seq<T_>::from(Ts& ts, std::function<TResult(Val<TResult>&&, T& t)> itemBind) {
template<class Ts, typename TItem> // = Ts::value_type
Seq<T_> Seq<T_>::from(Ts& ts,
typename T_::TResult(*itemBind)(TItem&, Val<typename T_::TResult>&&),
bool(*itemPredicate)(const TItem&)) {
if ((*this)->mode()==Write) {
for (T t : ts) {
itemBind(unsafeItem(), t);
for (auto&& t : ts) {
if (itemPredicate(t)) {
itemBind(t, unsafeItem());
}
}
return std::move(*this);
}
else if ((*this)->mode()==Read) {
auto&& i = ts.begin();
Val<typename T_::TResult> item;
while ((item = unsafeItem())) {
if (i != ts.end()) {
itemBind(std::move(item), *i);
}
else {
T newItem;
if (itemBind(std::move(item), newItem)) {
TItem newItem;
if (itemBind(newItem, std::move(item)) && itemPredicate(newItem)) {
if (i != ts.end()) {
*i = newItem;
}
else {
ts.insert(i, newItem);
}
}
}
return std::move(*this);
}
else { Q_ASSERT_X(!this, Q_FUNC_INFO, "Unsupported implementation mode()"); return null(); }
}
......
......@@ -64,6 +64,7 @@
#include <QtWidgets/qtableview.h>
#include <QtWidgets/qdialog.h>
#include <QtWidgets/qboxlayout.h>
#include <QtWidgets/qsplitter.h>
#include <QtWidgets/qapplication.h>
// //////////////////////////////////////////////////////////////////////////
......@@ -952,7 +953,7 @@ int main(int argc, char *argv[])
}
Seq<Cursor>&& flatten(const QList<Person>& ps, Seq<Cursor>&& s) {
for (auto&& p : ps) {
for (auto&& p : ps) { // Iterating on ps only works for Write but flatten cannot be Read/Write anyway
s = s
.record()
.bind("first name", p.firstName )
......@@ -966,7 +967,7 @@ Seq<Cursor>&& flatten(const QList<Person>& ps, Seq<Cursor>&& s) {
};
void doGuiExample() {
// Adapt dataset to different views
// Dataset adapted to different views
person.lastName="";
person.comments="";
person.phones.append(phone);
......@@ -981,39 +982,66 @@ void doGuiExample() {
persons[0].height=1.72;
persons[1].phones.append(Phone{Phone::Office,"112"});
QStandardItemModel matrixModel; QModelWriter<>(&matrixModel,false).meta({{qmSizes ,"4,3"}}).bind(transform);
QStandardItemModel treeModel; QModelWriter<>(& treeModel ).meta({{qmChildren,"children"}/*,{qmColumns ,"names,age"}*/}).bind(persons);
QStandardItemModel tableModel; QModelWriter<>(& tableModel ).meta({{qmColumns ,"names,age,children"}}).bind(persons);
// Generic data structures to bind with
QStandardItemModel matrixModel, treeModel, tableModel, customModel, flatModel;
QStandardItemModel flatModel; QModelWriter<>(& flatModel ).sequence().bindFrom([&](Seq<Cursor>&& s){
return std::move(flatten(persons, std::move(s)));
// Using meta() to drive various custom bind
QModelWriter<>(&matrixModel,false).meta({{qmSizes ,"4,3" } }).bind(transform);
QModelWriter<>(& treeModel ).meta({{qmChildren,"children"}/*,{qmColumns ,"names,age"}*/}).bind(persons);
QModelWriter<>(& tableModel ).meta({{qmColumns , "names,age"} }).bind(persons);
// Various possible designs for flexible custom bind
#if 0
// 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
return item
.record()
.bind("first name", p.firstName)
.sequence("phones").from<QVector<Phone>,Phone>(p.phones,
[](Phone& phone, Val<Cursor>&& item){
return item.bind(phone._n);
},
[](const Phone& phone){
return phone._t == Phone::Office;
})
.out()
.out();
});
QStandardItemModel customModel; QModelWriter<>(&customModel ).sequence().bindFrom([&](Seq<Cursor>&& s){
for (auto&& p : persons) {
s = s.record()
.bind("first name", p.firstName)
.sequence("phones")
.bindFrom([&] (Seq<Cursor>&& s) {
for (auto&& ph : p.phones) {
if (ph._t==Phone::Office) {
s = s.bind(ph);
}
#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
.record()
.bind("first name", p.firstName)
.sequence("phones")
.bindFrom([&] (Seq<Cursor>&& s) {
for (auto&& phone : p.phones) {
if (phone._t == Phone::Office) {
s = s.bind(phone._n);
}
return std::move(s);
})
.out()
.out();
}
return std::move(s);
})
.out()
.out();
}
return std::move(s);
});
#endif
// The same design allows flattening trees into a sequence
QModelWriter<>(& flatModel).sequence().bindFrom([&](Seq<Cursor>&& s){
return std::move(flatten(persons, std::move(s)));
});
QDialog dlg;
auto layout = new QHBoxLayout(&dlg); dlg.setLayout(layout);
auto matrix = new QTableView (&dlg); layout->addWidget(matrix); matrix->setModel(&matrixModel); matrix->resizeColumnsToContents();
auto tree = new QTreeView (&dlg); layout->addWidget(tree ); tree ->setModel(& treeModel); for(int i=0; i<treeModel.columnCount(); i++) tree ->resizeColumnToContents(i);
auto table = new QTableView (&dlg); layout->addWidget(table ); table ->setModel(& tableModel); table ->resizeColumnsToContents();
auto flat = new QTableView (&dlg); layout->addWidget(flat ); flat ->setModel(& flatModel); flat ->resizeColumnsToContents();
auto custom = new QTableView (&dlg); layout->addWidget(custom); custom->setModel(&customModel); custom->resizeColumnsToContents();
dlg.resize(1024,280);
auto split = new QSplitter (&dlg); layout->addWidget(split );
auto matrix = new QTableView(&dlg); split ->addWidget(matrix); matrix->setModel(&matrixModel); matrix->resizeColumnsToContents();
auto tree = new QTreeView (&dlg); split ->addWidget(tree ); tree ->setModel(& treeModel); for(int i=0; i<treeModel.columnCount(); i++) tree ->resizeColumnToContents(i);
auto table = new QTableView(&dlg); split ->addWidget(table ); table ->setModel(& tableModel); table ->resizeColumnsToContents();
auto flat = new QTableView(&dlg); split ->addWidget(flat ); flat ->setModel(& flatModel); flat ->resizeColumnsToContents();
auto custom = new QTableView(&dlg); split ->addWidget(custom); custom->setModel(&customModel); custom->resizeColumnsToContents();
dlg.resize(1280,280);
dlg.exec();
}
tests/QBind/qstandardmodel.PNG

11.5 KB | W: | H:

tests/QBind/qstandardmodel.PNG

15.4 KB | W: | H:

tests/QBind/qstandardmodel.PNG
tests/QBind/qstandardmodel.PNG
tests/QBind/qstandardmodel.PNG
tests/QBind/qstandardmodel.PNG
  • 2-up
  • Swipe
  • Onion skin
group | QDebug| Text| Json| Xml| Variant| Cbor| QCborStream| Data| QDataStream| QByteArray| Writables|Writables>Cbor|Writables>Json|total(usecs)|variation(%)
builtin> | 9.2| 3.0| 7.7| 33.5| 14.3| 0.9| 1.6| 1.1| 0.7| 0.1| 0.1| 1.0| 8.7| 82.0| 3.5
builtin> | 7.8| 2.7| 8.5| 29.9| 8.8| 0.9| 1.5| 1.1| 0.7| 0.1| 0.1| 1.0| 7.4| 70.6| 14.0
builtin> | 7.3| 2.2| 7.2| 35.6| 13.0| 1.5| 2.3| 1.9| 0.9| 0.1| 0.1| 1.1| 8.2| 81.3| 15.2
builtin> | 8.1| 2.9| 8.5| 33.7| 8.6| 0.9| 1.6| 1.1| 0.7| 0.1| 0.1| 1.1| 7.3| 74.6| 8.2
builtin> | 7.2| 2.2| 8.8| 34.6| 8.7| 0.9| 1.6| 1.1| 0.7| 0.1| 0.1| 1.0| 7.7| 74.7| 0.1
builtin> | 7.3| 2.2| 7.2| 31.1| 9.3| 0.9| 1.6| 1.1| 0.7| 0.1| 0.1| 1.0| 7.4| 70.0| 6.3
builtin> | 8.6| 2.2| 7.2| 28.9| 8.7| 1.0| 1.5| 1.1| 0.7| 0.1| 0.1| 1.0| 7.4| 68.5| 20.2
builtin> | 6.8| 2.2| 7.2| 28.5| 9.1| 1.4| 2.3| 1.8| 0.8| 0.1| 0.1| 1.2| 7.6| 69.0| 0.8
builtin> | 6.9| 2.2| 7.2| 28.5| 8.7| 0.9| 1.5| 1.1| 0.7| 0.1| 0.1| 1.0| 7.4| 66.4| 3.8
group | QDebug| Text| Json| Xml| Variant| Cbor| QCborStream| Data| QDataStream| QByteArray| Writable| Writable>Cbor| Writable>Json|total(usecs)|variation(%)
doubles> | 15.9| 14.0| 18.7| 58.0| 29.2| 1.2| 1.4| 1.5| 1.2| 0.4| 0.0| 1.1| 21.0| 163.7| 1.9
doubles> | 15.9| 13.9| 17.9| 63.8| 22.8| 1.2| 1.4| 1.5| 1.2| 0.4| 0.0| 1.1| 17.8| 158.9| 2.9
doubles> | 15.7| 14.6| 17.6| 63.0| 23.9| 1.2| 1.4| 1.4| 1.3| 0.4| 0.0| 1.1| 18.2| 159.9| 0.7
doubles> | 17.1| 13.8| 24.8| 58.0| 22.5| 1.2| 1.4| 1.4| 1.2| 0.4| 0.0| 1.2| 17.9| 161.0| 0.7
doubles> | 15.5| 19.6| 21.5| 67.0| 24.0| 1.6| 1.4| 1.4| 1.2| 0.4| 0.0| 1.2| 23.0| 177.6| 9.7
doubles> | 16.9| 14.3| 18.1| 66.1| 30.7| 1.2| 1.4| 1.8| 1.2| 0.4| 0.0| 1.2| 18.2| 171.4| 3.5
doubles> | 15.6| 14.6| 18.2| 76.8| 24.0| 1.2| 1.4| 1.4| 1.2| 0.4| 0.0| 1.6| 18.8| 175.1| 2.2
doubles> | 15.9| 14.4| 20.8| 67.6| 23.4| 1.6| 1.4| 1.4| 1.2| 0.4| 0.0| 1.2| 18.6| 167.9| 4.1
doubles> | 17.1| 13.9| 18.4| 66.2| 22.9| 1.2| 1.4| 1.5| 1.2| 0.6| 0.0| 2.1| 17.6| 164.2| 2.2
doubles> | 14.7| 13.5| 17.1| 62.2| 23.0| 1.2| 1.4| 1.4| 1.2| 0.4| 0.0| 1.2| 17.3| 154.6| 5.9
doubles> | 14.7| 13.5| 17.1| 62.3| 22.6| 1.1| 1.3| 1.4| 1.2| 0.4| 0.0| 1.2| 17.3| 154.1| 0.3
doubles> | 14.7| 14.1| 17.1| 62.4| 22.6| 1.1| 1.3| 1.4| 1.2| 0.4| 0.0| 1.2| 17.3| 154.9| 0.5
group | QDebug| Text| Json| Xml| Variant| Cbor| QCborStream| Data| QDataStream| QByteArray| Writable| Writable>Cbor| Writable>Json|total(usecs)|variation(%)
Person> | 6.3| 4.6| 13.4| 30.7| 13.5| 2.6| 3.1| 0.9| 0.7| 0.2| 0.0| 2.7| 13.4| 92.1| 3.9
Person> | 6.3| 4.6| 13.4| 28.7| 13.2| 2.7| 3.0| 0.9| 0.7| 0.2| 0.0| 2.7| 14.9| 91.2| 1.0
Person> | 6.3| 4.7| 13.4| 28.3| 13.4| 2.6| 3.0| 0.9| 0.7| 0.2| 0.0| 2.6| 13.6| 89.8| 1.6
Person> | 6.1| 4.6| 13.4| 27.9| 12.9| 2.6| 3.1| 0.9| 0.7| 0.2| 0.0| 2.6| 13.2| 88.2| 1.6
Person> | 6.0| 5.0| 14.2| 28.0| 12.9| 2.9| 3.0| 0.9| 0.7| 0.2| 0.0| 2.6| 13.2| 89.6| 1.5
Person> | 6.1| 4.6| 13.1| 27.7| 13.4| 2.6| 3.0| 0.9| 0.7| 0.2| 0.0| 2.6| 13.3| 88.2| 1.6
Person> | 6.0| 4.6| 13.1| 27.8| 13.0| 2.6| 3.0| 0.9| 0.7| 0.2| 0.0| 2.6| 13.2| 87.8| 0.4
Person> | 6.1| 4.8| 13.6| 27.4| 13.1| 2.6| 3.5| 0.9| 0.7| 0.2| 0.0| 2.6| 13.2| 88.7| 1.0
group | QDebug| Text| Json| Xml| Variant| Cbor| QCborStream| Data| QDataStream| QByteArray| Writable| Writable>Cbor| Writable>Json|total(usecs)|variation(%)
Phone> | 2.2| 3.7| 5.9| 13.6| 6.1| 3.7| 1.1| 0.5| 0.2| 0.4| 0.0| 3.8| 5.7| 46.9| 13.0
Phone> | 2.2| 3.7| 5.8| 13.6| 6.1| 3.7| 1.1| 0.5| 0.2| 0.4| 0.0| 3.7| 5.7| 46.7| 0.5
Phone> | 2.1| 3.8| 5.8| 13.5| 8.2| 3.6| 1.1| 0.5| 0.2| 0.4| 0.0| 3.8| 5.8| 48.9| 4.8
Phone> | 2.0| 3.7| 5.5| 14.6| 5.9| 3.6| 1.1| 0.5| 0.2| 0.4| 0.0| 3.8| 5.7| 47.1| 2.0
Phone> | 2.0| 3.8| 5.5| 13.1| 5.8| 3.8| 1.1| 0.5| 0.2| 0.4| 0.0| 3.7| 5.6| 45.6| 3.1
Phone> | 2.1| 3.6| 5.6| 13.0| 6.0| 3.6| 1.2| 0.5| 0.2| 0.4| 0.0| 3.6| 6.0| 45.8| 0.4
Phone> | 2.0| 3.8| 8.2| 13.0| 6.1| 3.6| 1.2| 0.5| 0.2| 0.4| 0.0| 3.7| 5.7| 48.3| 5.5
group | Json>P| P>Json| Json>P| P>JsonValue| JsonValue>P|Json>JsonValue| Json>Cbor|total(usecs)|variation(%)
Person<>Json| 14.8| 6.2| 12.2| 12.1| 3.8| 21.6| 20.8| 91.5| 0.5
Person<>Json| 14.7| 6.3| 11.9| 12.1| 3.8| 25.6| 20.8| 95.2| 4.1
Person<>Json| 14.8| 6.4| 11.8| 12.3| 3.8| 22.5| 20.6| 92.2| 4.1
Person<>Json| 14.8| 6.5| 11.8| 13.3| 4.9| 23.0| 20.7| 94.9| 2.9
Person<>Json| 14.9| 6.7| 11.8| 12.1| 3.8| 22.6| 23.2| 95.1| 0.2
Person<>Json| 15.8| 6.5| 12.0| 11.8| 3.9| 22.9| 20.7| 93.7| 1.5
group | Cbor>P| P>Cbor| Cbor>P| QCborStream>P| P>CborValue| CborValue>P|Cbor>CborValue|CborValue>Cbor| Cbor>Json|total(usecs)|variation(%)
Person<>Cbor| 15.3| 2.6| 17.8| 6.3| 10.7| 5.2| 24.6| 8.3| 17.8| 108.8| 1.7
Person<>Cbor| 15.4| 3.0| 16.2| 6.3| 10.7| 5.2| 24.5| 8.3| 17.6| 107.4| 1.3
Person<>Cbor| 15.0| 2.6| 15.0| 6.3| 14.5| 5.2| 23.5| 8.3| 16.5| 106.9| 0.5
Person<>Cbor| 13.8| 2.6| 15.2| 6.3| 10.7| 5.2| 25.6| 8.3| 16.4| 104.2| 2.5
Person<>Cbor| 15.2| 2.6| 15.3| 6.3| 9.9| 5.5| 23.4| 8.2| 16.4| 102.8| 6.1
Person<>Cbor| 16.1| 2.6| 15.2| 6.3| 9.9| 5.1| 23.3| 8.6| 16.6| 103.7| 0.8
Person<>Cbor| 14.9| 2.6| 15.0| 6.3| 9.9| 5.1| 22.0| 8.2| 15.4| 99.5| 4.0
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