Files
qt-creator/tests/manual/layoutbuilder/experimental/main.cpp
hjk 02ac595a2e LayoutBuilder: Add some playground for potential implementations
Change-Id: I0955c503dc03f9e4d81d6cfe4df7af63cf86a638
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
2023-07-05 14:26:06 +00:00

171 lines
3.7 KiB
C++

// Copyright (C) 2023 André Pönitz
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <array>
#include <initializer_list>
#include <tuple>
#include <stdio.h>
#include <string.h>
using namespace std;
// std::tuple implementations are quite fat, we might want to use a cut-down version of it.
template <typename ...Args>
using Tuple = std::tuple<Args...>;
// The main dispatcher(s)
auto doit_tuple(auto x, auto t); // Tuple-based
auto doit(auto x, auto ...a); // Args expanded.
// Convenience for the setter implementors. Removes the need to use get<n>
// in the setters explicitly.
template <typename X, typename Id, typename Arg1>
void doit_tuple(X *x, const Tuple<Id, Arg1> *a)
{
doit(x, get<0>(*a), get<1>(*a));
}
template <typename X, typename Id, typename Arg1, typename Arg2>
void doit_tuple(X *x, const Tuple<Id, Arg1, Arg2> *a)
{
doit(x, get<0>(*a), get<1>(*a), get<2>(*a));
}
// "Builder base".
template <typename X>
struct B
{
private:
template <typename ...Args>
struct Doer
{
static void doit(X *x, const Tuple<Args...> *args)
{
doit_tuple(x, args);
}
};
public:
struct I
{
template <typename ...Args>
I(const Tuple<Args...> &p)
{
auto f = &Doer<Args...>::doit;
memcpy(&f_, &f, sizeof(f_));
p_ = &p;
}
void (*f_)(X *, const void *);
const void *p_;
};
B(initializer_list<I> ps) {
for (auto && p : ps)
(*p.f_)(static_cast<X *>(this), p.p_);
}
};
//////////////////////////////////////////////
// Builder Classes preparation
// We need one class for each user visible Builder type.
// This is usually wrappeng one "backend" type, e.g. there
// could be a PushButton wrapping QPushButton.
struct D : B<D> { using B<D>::B; };
struct E : B<E> { using B<E>::B; };
// "Setters" preparation
// We need one 'Id' (and a corresponding function wrapping arguments into a
// tuple marked by this id) per 'name' of "backend" setter member function,
// i.e. one 'text' is sufficient for QLabel::setText, QLineEdit::setText.
// The name of the Id does not have to match the backend names as it
// is mapped per-backend-type in the respective setter implementation
// but we assume that it generally makes sense to stay close to the
// wrapped API name-wise.
struct TextId {};
auto text(auto ...x) { return Tuple{TextId{}, x...}; }
struct SumId {};
auto sum(auto ...x) { return Tuple{SumId{}, x...}; }
struct OtherId {};
auto other(auto ...x) { return Tuple{OtherId{}, x...}; }
struct LargeId {};
auto large(auto ...x) { return Tuple{LargeId{}, x...}; }
struct Large {
Large() { for (int i = 0; i < 100; ++i) x[i] = i; }
int x[100];
};
// Setter implementation
// These are free functions overloaded on the type of builder object
// and setter id. The function implementations are independent, but
// the base expectation is that they will forwards to the backend
// type's setter.
void doit(D *, TextId, const char *t)
{
printf("D text: %s\n", t);
}
void doit(D *, OtherId, int t)
{
printf("D other: %d\n", t);
}
void doit(D *, OtherId, double t)
{
printf("D other: %f\n", t);
}
void doit(D *, LargeId, Large t)
{
printf("D other: %d\n", t.x[50]);
}
void doit(E *, OtherId, double t)
{
printf("E other: %f\n", t);
}
void doit(E *, SumId, int a, int b)
{
printf("E sum: %d + %d = %d\n", a, b, a + b);
}
int main()
{
E {
other(4.55),
sum(1, 2)
};
D {
//other(5),
other(5.5), // - does not compile as there is no doit(D*, OtherId, double)
text("abc"),
large(Large())
};
}