Skip to content

Commit 4e2639f

Browse files
Artemiy-dvohi
authored andcommitted
QRM: move templated index switch to a separate function
The trick is used in 2 places, and it might require optimization for gcc. It means that we should have it in one place in order to fix all cases together. Pick-to: 6.10 Change-Id: I67dc0e60e3567dbaab5cd800e9fa0ca4df381a54 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
1 parent ce02416 commit 4e2639f

File tree

1 file changed

+24
-17
lines changed

1 file changed

+24
-17
lines changed

src/corelib/itemmodels/qrangemodel_impl.h

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ QT_BEGIN_NAMESPACE
3333

3434
namespace QtPrivate {
3535

36+
template <typename Applier, size_t ...Is>
37+
void applyIndexSwitch(size_t index, Applier&& applier, std::index_sequence<Is...>)
38+
{
39+
// TODO: check if it's optimized properly on gcc.
40+
// A superficial research reveals that gcc may compile this code into a linear search,
41+
// whereas 'index' should be found in O(1) time like in a proper c++ switch.
42+
((Is == index ? applier(std::integral_constant<size_t, Is>{}) : static_cast<void>(0)), ...);
43+
}
44+
45+
template <size_t IndexCount, typename Applier>
46+
void applyIndexSwitch(size_t index, Applier&& applier)
47+
{
48+
applyIndexSwitch(index, std::forward<Applier>(applier), std::make_index_sequence<IndexCount>());
49+
}
50+
3651
// TODO: move to a separate header in Qt 6.11
3752
template <typename Interface>
3853
class QQuasiVirtualInterface
@@ -166,11 +181,10 @@ class QQuasiVirtualSubclass : public Interface
166181
static_assert(methodIndexMask == (uint64_t(1) << sizeof...(Is)) - 1,
167182
"Mapping between base and overridden methods is not unique");
168183

169-
// TODO: check if it's optimized properly on gcc
170-
((interfaceMethodIndex<Is>() == index
171-
? std::tuple_element_t<Is, Methods<>>::doInvoke(subclass, ret, args)
172-
: static_cast<void>(0))
173-
, ...);
184+
auto doInvoke = [&](auto idxConstant) {
185+
std::tuple_element_t<idxConstant.value, Methods<>>::doInvoke(subclass, ret, args);
186+
};
187+
applyIndexSwitch(index, doInvoke, std::index_sequence<interfaceMethodIndex<Is>()...>{});
174188
}
175189

176190
static void callImpl(size_t index, typename Interface::base_interface &intf, void *ret, void *args)
@@ -810,25 +824,18 @@ class QRangeModelImplBase : public QtPrivate::QQuasiVirtualInterface<QRangeModel
810824
protected:
811825
// Helpers for calling a lambda with the element of a statically
812826
// sized range (tuple or array) with a runtime index.
813-
template <typename Tuple, typename F, std::size_t ...Is>
814-
static void call_at(Tuple &&tuple, std::size_t idx, std::index_sequence<Is...>, F &&function)
815-
{
816-
static_assert(QRangeModelDetails::tuple_like_v<q20::remove_cvref_t<Tuple>>);
817-
if (QRangeModelDetails::isValid(tuple))
818-
((Is == idx ? static_cast<void>(function(get<Is>(
819-
QRangeModelDetails::refTo(std::forward<Tuple>(tuple)))))
820-
: static_cast<void>(0)), ...);
821-
}
822-
823827
template <typename T, typename F,
824828
std::enable_if_t<QRangeModelDetails::tuple_like_v<q20::remove_cvref_t<T>>, bool> = true>
825829
static auto for_element_at(T &&tuple, std::size_t idx, F &&function)
826830
{
827831
using type = QRangeModelDetails::wrapped_t<T>;
828832
constexpr size_t size = std::tuple_size_v<type>;
829833
Q_ASSERT(idx < size);
830-
return call_at(std::forward<T>(tuple), idx, std::make_index_sequence<size>{},
831-
std::forward<F>(function));
834+
if (QRangeModelDetails::isValid(tuple)) {
835+
QtPrivate::applyIndexSwitch<size>(idx, [&](auto idxConstant) {
836+
function(get<idxConstant.value>(QRangeModelDetails::refTo(std::forward<T>(tuple))));
837+
});
838+
}
832839
}
833840

834841
template <typename Array, typename F,

0 commit comments

Comments
 (0)