36 constexpr bool boolResult = (std::is_same_v<
37 std::invoke_result_t<Applier, std::integral_constant<size_t, Is>>,
39 auto doApply = [&applier](
auto i) {
40 if constexpr (boolResult)
41 return std::forward<Applier>(applier)(i);
43 return (
std::forward<Applier>(applier)(i),
true);
46 return ((Is == index && doApply(std::integral_constant<size_t, Is>{})) || ...);
60 template <
typename Arg>
61 static constexpr bool passArgAsValue =
sizeof(
Arg) <=
sizeof(
size_t)
64 template <
typename C = Interface>
using Methods =
typename C::
template MethodTemplates<C>;
66 template <
typename ...>
69 template <
typename M,
typename R,
typename I,
typename... Args>
70 struct MethodImpl<M, R, I, Args...>
72 static_assert(
std::is_base_of_v<I, Interface>,
"The method must belong to the interface");
73 using return_type = R;
74 using call_args = std::tuple<std::conditional_t<passArgAsValue<Args>, Args, Args&&>...>;
76 static constexpr size_t index()
78 return index(std::make_index_sequence<std::tuple_size_v<Methods<>>>());
83 static constexpr bool matchesAt()
85 return std::is_base_of_v<M, std::tuple_element_t<Ix, Methods<>>>;
88 template <size_t... Is>
89 static constexpr size_t index(std::index_sequence<Is...>)
91 constexpr size_t matchesCount = (size_t(matchesAt<Is>()) + ...);
92 static_assert(matchesCount == 1,
"Expected exactly one match");
93 return ((size_t(matchesAt<Is>()) * Is) + ...);
96 static R invoke(I &intf , Args... args)
98 Q_ASSERT(intf.m_callFN);
100 auto& baseIntf =
static_cast<
base_interface&>(
const_cast<std::remove_const_t<I>&>(intf));
101 call_args callArgs(
std::forward<Args>(args)...);
102 if constexpr (
std::is_void_v<R>) {
103 intf.m_callFN(index(), baseIntf,
nullptr, &callArgs);
105 alignas(R)
std::byte buf[
sizeof(R)];
106 intf.m_callFN(index(), baseIntf, buf, &callArgs);
108 R* result =
std::launder(
reinterpret_cast<R*>(buf));
109 QScopeGuard destroyBuffer([result]() {
std::destroy_at(result); });
110 return std::forward<R>(*result);
117 template <
typename M,
typename R,
typename I,
typename... Args>
118 struct MethodImpl<M, R(I::*)(Args...)> : MethodImpl<M, R, I, Args...> {
119 template <
typename Subclass>
120 using Overridden = R(Subclass::*)(Args...);
123 template <
typename M,
typename R,
typename I,
typename... Args>
124 struct MethodImpl<M, R(I::*)(Args...)
const> : MethodImpl<M, R,
const I, Args...> {
125 template <
typename Subclass>
126 using Overridden = R(Subclass::*)(Args...)
const;
130 template <
auto prototype>
133 template <
typename Method,
typename... Args>
134 auto call(Args &&... args)
const
136 return Method::invoke(
static_cast<
const Interface &>(*
this),
std::forward<Args>(args)...);
139 template <
typename Method,
typename... Args>
142 return Method::invoke(
static_cast<Interface &>(*
this),
std::forward<Args>(args)...);
170 template <
typename C = Subclass>
using Methods =
typename C::
template MethodTemplates<C>;
172 template <size_t OverriddenIndex>
173 static constexpr size_t interfaceMethodIndex() {
174 return std::tuple_element_t<OverriddenIndex, Methods<>>::index();
177 template <size_t... Is>
178 static void callImpl(size_t index, Subclass &subclass,
void *ret,
void *args, std::index_sequence<Is...>)
180 constexpr auto methodIndexMask = []() {
181 std::array<
bool,
sizeof...(Is)> result = {};
182 (
static_cast<
void>(
std::get<interfaceMethodIndex<Is>()>(result) =
true), ...);
185 static_assert((methodIndexMask[Is] && ...),
186 "Mapping between base and overridden methods is not unique");
188 auto doInvoke = [&](
auto idxConstant) {
189 std::tuple_element_t<idxConstant.value, Methods<>>::doInvoke(subclass, ret, args);
191 QtPrivate::applyIndexSwitch(index, doInvoke,
192 std::index_sequence<interfaceMethodIndex<Is>()...>{});
195 static void callImpl(size_t index,
typename Interface::base_interface &intf,
void *ret,
void *args)
197 constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Methods<>>>();
198 callImpl(index,
static_cast<Subclass&>(intf), ret, args, seq);
201 template <
typename BaseMethod>
202 using OverridenSignature =
typename BaseMethod::
template Overridden<Subclass>;
205 template <
typename... Args>
207 : Interface(
std::forward<Args>(args)...)
209 Interface::initCallFN(&QQuasiVirtualSubclass::callImpl);
213 template <
typename BaseMethod, OverridenSignature<BaseMethod> overridden>
217 static constexpr void doInvoke(Subclass &subclass,
void *ret,
void *args)
219 using Return =
typename BaseMethod::return_type;
220 using PackedArgs =
typename BaseMethod::call_args;
223 Q_ASSERT(
std::is_void_v<Return> == !ret);
225 auto invoke = [&subclass](
auto &&...params)
227 return std::invoke(overridden, &subclass, std::forward<
decltype(params)>(params)...);
230 if constexpr (
std::is_void_v<Return>) {
231 std::apply(invoke,
std::move(*
static_cast<PackedArgs *>(args)));
233 q20::construct_at(
static_cast<Return *>(ret),
234 std::apply(invoke, std::move(*
static_cast<PackedArgs *>(args))));