Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-07 10:16:28

0001 // Copyright (C) 2025 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 // Qt-Security score:significant reason:default
0004 
0005 #ifndef QRANGEMODEL_IMPL_H
0006 #define QRANGEMODEL_IMPL_H
0007 
0008 #ifndef Q_QDOC
0009 
0010 #ifndef QRANGEMODEL_H
0011 #error Do not include qrangemodel_impl.h directly
0012 #endif
0013 
0014 #if 0
0015 #pragma qt_sync_skip_header_check
0016 #pragma qt_sync_stop_processing
0017 #endif
0018 
0019 #include <QtCore/qabstractitemmodel.h>
0020 #include <QtCore/qmetaobject.h>
0021 #include <QtCore/qvariant.h>
0022 #include <QtCore/qmap.h>
0023 
0024 #include <algorithm>
0025 #include <functional>
0026 #include <iterator>
0027 #include <type_traits>
0028 #include <QtCore/q20type_traits.h>
0029 #include <tuple>
0030 #include <QtCore/q23utility.h>
0031 
0032 QT_BEGIN_NAMESPACE
0033 
0034 namespace QtPrivate {
0035 
0036 template <typename Applier, size_t ...Is>
0037 void applyIndexSwitch(size_t index, Applier&& applier, std::index_sequence<Is...>)
0038 {
0039     // Performance considerations:
0040     // The folding expression used here represents the same logic as a sequence of
0041     // linear if/else if/... statements. Experiments show that Clang, GCC, and MSVC
0042     // optimize it to essentially the same bytecode as a normal C++ switch,
0043     // ensuring O(1) lookup complexity.
0044     static_cast<void>(((Is == index ? (applier(std::integral_constant<size_t, Is>{}), true) : false)
0045                        || ...));
0046 }
0047 
0048 template <size_t IndexCount, typename Applier>
0049 void applyIndexSwitch(size_t index, Applier&& applier)
0050 {
0051     applyIndexSwitch(index, std::forward<Applier>(applier), std::make_index_sequence<IndexCount>());
0052 }
0053 
0054 // TODO: move to a separate header in Qt 6.11
0055 template <typename Interface>
0056 class QQuasiVirtualInterface
0057 {
0058 private:
0059     template <typename Arg>
0060     static constexpr bool passArgAsValue = sizeof(Arg) <= sizeof(size_t)
0061                                         && std::is_trivially_destructible_v<Arg>;
0062 
0063     template <typename ...>
0064     struct MethodImpl;
0065 
0066     template <typename M, typename R, typename I, typename... Args>
0067     struct MethodImpl<M, R, I, Args...>
0068     {
0069         static_assert(std::is_base_of_v<I, Interface>, "The method must belong to the interface");
0070         using return_type = R;
0071         using call_args = std::tuple<std::conditional_t<passArgAsValue<Args>, Args, Args&&>...>;
0072 
0073         static constexpr size_t index()
0074         {
0075             return index(std::make_index_sequence<std::tuple_size_v<Methods<>>>());
0076         }
0077 
0078     private:
0079         template <size_t Ix>
0080         static constexpr bool matchesAt()
0081         {
0082             return std::is_base_of_v<M, std::tuple_element_t<Ix, Methods<>>>;
0083         }
0084 
0085         template <size_t... Is>
0086         static constexpr size_t index(std::index_sequence<Is...>)
0087         {
0088             constexpr size_t matchesCount = (size_t(matchesAt<Is>()) + ...);
0089             static_assert(matchesCount == 1, "Expected exactly one match");
0090             return ((size_t(matchesAt<Is>()) * Is) + ...);
0091         }
0092 
0093         static R invoke(I &intf /*const validation*/, Args... args)
0094         {
0095             Q_ASSERT(intf.m_callFN);
0096 
0097             auto& baseIntf = static_cast<base_interface&>(const_cast<std::remove_const_t<I>&>(intf));
0098             call_args callArgs(std::forward<Args>(args)...);
0099             if constexpr (std::is_void_v<R>) {
0100                 intf.m_callFN(index(), baseIntf, nullptr, &callArgs);
0101             } else {
0102                 alignas(R) std::byte buf[sizeof(R)];
0103                 intf.m_callFN(index(), baseIntf, buf, &callArgs);
0104 
0105                 R* result = std::launder(reinterpret_cast<R*>(buf));
0106                 QScopeGuard destroyBuffer([result]() { std::destroy_at(result); });
0107                 return std::forward<R>(*result);
0108             }
0109         }
0110 
0111         friend class QQuasiVirtualInterface<Interface>;
0112     };
0113 
0114     template <typename M, typename R, typename I, typename... Args>
0115     struct MethodImpl<M, R(I::*)(Args...)> : MethodImpl<M, R, I, Args...> {
0116         template <typename Subclass>
0117         using Overridden = R(Subclass::*)(Args...);
0118     };
0119 
0120     template <typename M, typename R, typename I, typename... Args>
0121     struct MethodImpl<M, R(I::*)(Args...) const> : MethodImpl<M, R, const I, Args...> {
0122         template <typename Subclass>
0123         using Overridden = R(Subclass::*)(Args...) const;
0124     };
0125 
0126     template <typename C = Interface> using Methods = typename C::template MethodTemplates<C>;
0127 
0128 public:
0129     template <auto prototype>
0130     struct Method : MethodImpl<Method<prototype>, decltype(prototype)> {};
0131 
0132     template <typename Method, typename... Args>
0133     auto call(Args &&... args) const
0134     {
0135         return Method::invoke(static_cast<const Interface &>(*this), std::forward<Args>(args)...);
0136     }
0137 
0138     template <typename Method, typename... Args>
0139     auto call(Args &&... args)
0140     {
0141         return Method::invoke(static_cast<Interface &>(*this), std::forward<Args>(args)...);
0142     }
0143 
0144     void destroy(); // quasi-virtual pure destructor
0145     using Destroy = Method<&QQuasiVirtualInterface::destroy>;
0146 
0147     struct Deleter
0148     {
0149         void operator () (QQuasiVirtualInterface* self) const { self->call<Destroy>(); }
0150     };
0151 
0152 protected:
0153     using base_interface = QQuasiVirtualInterface<Interface>;
0154     using CallFN = void (*)(size_t index, base_interface &intf, void *ret, void *args);
0155     void initCallFN(CallFN func) { m_callFN = func; }
0156 
0157     QQuasiVirtualInterface() = default;
0158     ~QQuasiVirtualInterface() = default;
0159 
0160 private:
0161     Q_DISABLE_COPY_MOVE(QQuasiVirtualInterface)
0162     CallFN m_callFN = nullptr;
0163 };
0164 
0165 template <typename Subclass, typename Interface>
0166 class QQuasiVirtualSubclass : public Interface
0167 {
0168 private:
0169     template <typename C = Subclass> using Methods = typename C::template MethodTemplates<C>;
0170 
0171     template <size_t OverriddenIndex>
0172     static constexpr size_t interfaceMethodIndex() {
0173         return std::tuple_element_t<OverriddenIndex, Methods<>>::index();
0174     }
0175 
0176     template <size_t... Is>
0177     static void callImpl(size_t index, Subclass &subclass, void *ret, void *args, std::index_sequence<Is...>)
0178     {
0179         // TODO: come up with more sophisticated check if methods count becomes more than 64
0180         static constexpr std::uint64_t methodIndexMask = ((uint64_t(1)
0181                                                       << interfaceMethodIndex<Is>()) | ...);
0182         static_assert(sizeof...(Is) == std::tuple_size_v<Methods<Interface>>,
0183                       "Base and overridden methods count are different");
0184         static_assert(methodIndexMask == (uint64_t(1) << sizeof...(Is)) - 1,
0185                       "Mapping between base and overridden methods is not unique");
0186 
0187         auto doInvoke = [&](auto idxConstant) {
0188             std::tuple_element_t<idxConstant.value, Methods<>>::doInvoke(subclass, ret, args);
0189         };
0190         applyIndexSwitch(index, doInvoke, std::index_sequence<interfaceMethodIndex<Is>()...>{});
0191     }
0192 
0193     static void callImpl(size_t index, typename Interface::base_interface &intf, void *ret, void *args)
0194     {
0195         constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Methods<>>>();
0196         callImpl(index, static_cast<Subclass&>(intf), ret, args, seq);
0197     }
0198 
0199     template <typename BaseMethod>
0200     using OverridenSignature = typename BaseMethod::template Overridden<Subclass>;
0201 
0202 protected:
0203     template <typename... Args>
0204     QQuasiVirtualSubclass(Args &&... args)
0205         : Interface(std::forward<Args>(args)...)
0206     {
0207         Interface::initCallFN(&QQuasiVirtualSubclass::callImpl);
0208     }
0209 
0210 public:
0211     template <typename BaseMethod, OverridenSignature<BaseMethod> overridden>
0212     struct Override : BaseMethod
0213     {
0214     private:
0215         static constexpr void doInvoke(Subclass &subclass, void *ret, void *args)
0216         {
0217             using Return = typename BaseMethod::return_type;
0218             using PackedArgs = typename BaseMethod::call_args;
0219 
0220             Q_ASSERT(args);
0221             Q_ASSERT(std::is_void_v<Return> == !ret);
0222 
0223             auto invoke = [&subclass](auto &&...params)
0224             {
0225                 return std::invoke(overridden, &subclass, std::forward<decltype(params)>(params)...);
0226             };
0227 
0228             if constexpr (std::is_void_v<Return>) {
0229                 std::apply(invoke, std::move(*static_cast<PackedArgs *>(args)));
0230             } else {
0231                 // Note, that ::new Return(...) fails on Integrity.
0232                 // TODO: use std::construct_at for c++20
0233                 using Alloc = std::allocator<Return>;
0234                 Alloc alloc;
0235                 std::allocator_traits<Alloc>::construct(alloc, static_cast<Return *>(ret),
0236                                std::apply(invoke, std::move(*static_cast<PackedArgs *>(args))));
0237             }
0238 
0239         }
0240 
0241         friend class QQuasiVirtualSubclass<Subclass, Interface>;
0242     };
0243 };
0244 
0245 }
0246 
0247 namespace QRangeModelDetails
0248 {
0249     template <typename T, template <typename...> typename... Templates>
0250     struct is_any_of_impl : std::false_type {};
0251 
0252     template <template <typename...> typename Template,
0253               typename... Params,
0254               template <typename...> typename... Templates>
0255     struct is_any_of_impl<Template<Params...>, Template, Templates...> : std::true_type {};
0256 
0257     template <typename T,
0258               template <typename...> typename Template,
0259               template <typename...> typename... Templates>
0260     struct is_any_of_impl<T, Template, Templates...> : is_any_of_impl<T, Templates...> {};
0261 
0262     template <typename T, template <typename...> typename... Templates>
0263     using is_any_of = is_any_of_impl<std::remove_cv_t<T>, Templates...>;
0264 
0265     template <typename T, typename = void>
0266     struct is_validatable : std::false_type {};
0267 
0268     template <typename T>
0269     struct is_validatable<T, std::void_t<decltype(*std::declval<T>())>>
0270         : std::is_constructible<bool, T> {};
0271 
0272     template <typename T, typename = void>
0273     struct is_smart_ptr : std::false_type {};
0274 
0275     template <typename T>
0276     struct is_smart_ptr<T,
0277         std::enable_if_t<std::conjunction_v<
0278                 std::is_pointer<decltype(std::declval<T&>().get())>,
0279                 std::is_same<decltype(*std::declval<T&>().get()), decltype(*std::declval<T&>())>,
0280                 is_validatable<T>
0281             >>>
0282         : std::true_type
0283     {};
0284 
0285     // TODO: shouldn't we check is_smart_ptr && !is_copy_constructible && !is_copy_assignable
0286     //       to support users-specific ptrs?
0287     template <typename T>
0288     using is_any_unique_ptr = is_any_of<T,
0289 #ifndef QT_NO_SCOPED_POINTER
0290             QScopedPointer,
0291 #endif
0292             std::unique_ptr
0293         >;
0294 
0295     template <typename T>
0296     using is_any_shared_ptr = is_any_of<T, std::shared_ptr, QSharedPointer,
0297                                            QExplicitlySharedDataPointer, QSharedDataPointer>;
0298 
0299     template <typename T>
0300     using is_owning_or_raw_pointer = std::disjunction<is_any_shared_ptr<T>, is_any_unique_ptr<T>,
0301                                                       std::is_pointer<T>>;
0302 
0303     template <typename T>
0304     static auto pointerTo(T&& t) {
0305         using Type = q20::remove_cvref_t<T>;
0306         if constexpr (is_any_of<Type, std::optional>())
0307             return t ? std::addressof(*std::forward<T>(t)) : nullptr;
0308         else if constexpr (std::is_pointer<Type>())
0309             return t;
0310         else if constexpr (is_smart_ptr<Type>())
0311             return t.get();
0312         else if constexpr (is_any_of<Type, std::reference_wrapper>())
0313             return std::addressof(t.get());
0314         else
0315             return std::addressof(std::forward<T>(t));
0316     }
0317 
0318     template <typename T>
0319     using wrapped_t = std::remove_pointer_t<decltype(pointerTo(std::declval<T&>()))>;
0320 
0321     template <typename T>
0322     using is_wrapped = std::negation<std::is_same<wrapped_t<T>, std::remove_reference_t<T>>>;
0323 
0324     template <typename T, typename = void>
0325     struct tuple_like : std::false_type {};
0326     template <typename T, std::size_t N>
0327     struct tuple_like<std::array<T, N>> : std::false_type {};
0328     template <typename T>
0329     struct tuple_like<T, std::void_t<std::tuple_element_t<0, wrapped_t<T>>>> : std::true_type {};
0330     template <typename T>
0331     [[maybe_unused]] static constexpr bool tuple_like_v = tuple_like<T>::value;
0332 
0333     template <typename T, typename = void>
0334     struct array_like : std::false_type {};
0335     template <typename T, std::size_t N>
0336     struct array_like<std::array<T, N>> : std::true_type {};
0337     template <typename T, std::size_t N>
0338     struct array_like<T[N]> : std::true_type {};
0339     template <typename T>
0340     [[maybe_unused]] static constexpr bool array_like_v = array_like<T>::value;
0341 
0342     template <typename T, typename = void>
0343     struct has_metaobject : std::false_type {};
0344     template <typename T>
0345     struct has_metaobject<T, std::void_t<decltype(wrapped_t<T>::staticMetaObject)>>
0346         : std::true_type {};
0347     template <typename T>
0348     [[maybe_unused]] static constexpr bool has_metaobject_v = has_metaobject<T>::value;
0349 
0350     template <typename T>
0351     static constexpr bool isValid(const T &t) noexcept
0352     {
0353         if constexpr (is_validatable<T>())
0354             return bool(t);
0355         else
0356             return true;
0357     }
0358 
0359     template <typename T>
0360     static decltype(auto) refTo(T&& t) {
0361         Q_ASSERT(isValid(t));
0362         // it's allowed to move only if the object holds unique ownership of the wrapped data
0363         using Type = q20::remove_cvref_t<T>;
0364         if constexpr (is_any_of<T, std::optional>())
0365             return *std::forward<T>(t); // let std::optional resolve dereferencing
0366         if constexpr (!is_wrapped<Type>() || is_any_unique_ptr<Type>())
0367             return q23::forward_like<T>(*pointerTo(t));
0368         else
0369             return *pointerTo(t);
0370     }
0371 
0372     template <typename It>
0373     auto key(It&& it) -> decltype(it.key()) { return std::forward<It>(it).key(); }
0374     template <typename It>
0375     auto key(It&& it) -> decltype((it->first)) { return std::forward<It>(it)->first; }
0376 
0377     template <typename It>
0378     auto value(It&& it) -> decltype(it.value()) { return std::forward<It>(it).value(); }
0379     template <typename It>
0380     auto value(It&& it) -> decltype((it->second)) { return std::forward<It>(it)->second; }
0381 
0382     // use our own version of begin/end so that we can overload for pointers
0383     template <typename C>
0384     static auto begin(C &&c) -> decltype(std::begin(refTo(std::forward<C>(c))))
0385     { return std::begin(refTo(std::forward<C>(c))); }
0386     template <typename C>
0387     static auto end(C &&c) -> decltype(std::end(refTo(std::forward<C>(c))))
0388     { return std::end(refTo(std::forward<C>(c))); }
0389     template <typename C>
0390     static auto pos(C &&c, int i)
0391     { return std::next(QRangeModelDetails::begin(std::forward<C>(c)), i); }
0392 
0393     // Test if a type is a range, and whether we can modify it using the
0394     // standard C++ container member functions insert, erase, and resize.
0395     // For the sake of QAIM, we cannot modify a range if it holds const data
0396     // even if the range itself is not const; we'd need to initialize new rows
0397     // and columns, and move old row and column data.
0398     template <typename C, typename = void>
0399     struct test_insert : std::false_type {};
0400 
0401     template <typename C>
0402     struct test_insert<C, std::void_t<decltype(std::declval<C>().insert(
0403         std::declval<typename C::const_iterator>(),
0404         std::declval<typename C::size_type>(),
0405         std::declval<typename C::value_type>()
0406     ))>>
0407         : std::true_type
0408     {};
0409 
0410     // Can we insert from another (identical) range? Required to support
0411     // move-only types
0412     template <typename C, typename = void>
0413     struct test_insert_range : std::false_type {};
0414 
0415     template <typename C>
0416     struct test_insert_range<C, std::void_t<decltype(std::declval<C&>().insert(
0417       std::declval<typename C::const_iterator&>(),
0418       std::declval<std::move_iterator<typename C::iterator>&>(),
0419       std::declval<std::move_iterator<typename C::iterator>&>()
0420     ))>>
0421         : std::true_type
0422     {};
0423 
0424     template <typename C, typename = void>
0425     struct test_erase : std::false_type {};
0426 
0427     template <typename C>
0428     struct test_erase<C, std::void_t<decltype(std::declval<C>().erase(
0429         std::declval<typename C::const_iterator>(),
0430         std::declval<typename C::const_iterator>()
0431     ))>>
0432         : std::true_type
0433     {};
0434 
0435     template <typename C, typename = void>
0436     struct test_resize : std::false_type {};
0437 
0438     template <typename C>
0439     struct test_resize<C, std::void_t<decltype(std::declval<C>().resize(
0440         std::declval<typename C::size_type>(),
0441         std::declval<typename C::value_type>()
0442     ))>>
0443         : std::true_type
0444     {};
0445 
0446     // we use std::rotate in moveRows/Columns, which requires std::swap
0447     template <typename It, typename = void>
0448     struct test_rotate : std::false_type {};
0449 
0450     template <typename It>
0451     struct test_rotate<It, std::void_t<decltype(std::swap(*std::declval<It>(),
0452                                                           *std::declval<It>()))>>
0453         : std::true_type
0454     {};
0455 
0456     // Test if a type is an associative container that we can use for multi-role
0457     // data, i.e. has a key_type and a mapped_type typedef, and maps from int,
0458     // Qt::ItemDataRole, or QString to QVariant. This excludes std::set (and
0459     // unordered_set), which are not useful for us anyway even though they are
0460     // considered associative containers.
0461     template <typename C, typename = void> struct is_multi_role : std::false_type
0462     {
0463         static constexpr bool int_key = false;
0464     };
0465     template <typename C> // Qt::ItemDataRole -> QVariant, or QString -> QVariant, int -> QVariant
0466     struct is_multi_role<C, std::void_t<typename C::key_type, typename C::mapped_type>>
0467         : std::conjunction<std::disjunction<std::is_same<typename C::key_type, int>,
0468                                             std::is_same<typename C::key_type, Qt::ItemDataRole>,
0469                                             std::is_same<typename C::key_type, QString>>,
0470                            std::is_same<typename C::mapped_type, QVariant>>
0471     {
0472         static constexpr bool int_key = !std::is_same_v<typename C::key_type, QString>;
0473     };
0474     template <typename C>
0475     [[maybe_unused]]
0476     static constexpr bool is_multi_role_v = is_multi_role<C>::value;
0477 
0478     template <typename C, typename = void>
0479     struct test_size : std::false_type {};
0480     template <typename C>
0481     struct test_size<C, std::void_t<decltype(std::size(std::declval<C&>()))>> : std::true_type {};
0482 
0483     template <typename C, typename = void>
0484     struct range_traits : std::false_type {
0485         static constexpr bool is_mutable = !std::is_const_v<C>;
0486         static constexpr bool has_insert = false;
0487         static constexpr bool has_insert_range = false;
0488         static constexpr bool has_erase = false;
0489         static constexpr bool has_resize = false;
0490         static constexpr bool has_rotate = false;
0491     };
0492     template <typename C>
0493     struct range_traits<C, std::void_t<decltype(begin(std::declval<C&>())),
0494                                        decltype(end(std::declval<C&>())),
0495                                        std::enable_if_t<!is_multi_role_v<C>>
0496                                       >> : std::true_type
0497     {
0498         using iterator = decltype(begin(std::declval<C&>()));
0499         using value_type = std::remove_reference_t<decltype(*std::declval<iterator&>())>;
0500         static constexpr bool is_mutable = !std::is_const_v<C> && !std::is_const_v<value_type>;
0501         static constexpr bool has_insert = test_insert<C>();
0502         static constexpr bool has_insert_range = test_insert_range<C>();
0503         static constexpr bool has_erase = test_erase<C>();
0504         static constexpr bool has_resize = test_resize<C>();
0505         static constexpr bool has_rotate = test_rotate<iterator>();
0506     };
0507 
0508     // Specializations for types that look like ranges, but should be
0509     // treated as values.
0510     enum class Mutable { Yes, No };
0511     template <Mutable IsMutable>
0512     struct iterable_value : std::false_type {
0513         static constexpr bool is_mutable = IsMutable == Mutable::Yes;
0514         static constexpr bool has_insert = false;
0515         static constexpr bool has_erase = false;
0516         static constexpr bool has_resize = false;
0517         static constexpr bool has_rotate = false;
0518     };
0519     template <> struct range_traits<QByteArray> : iterable_value<Mutable::Yes> {};
0520     template <> struct range_traits<QString> : iterable_value<Mutable::Yes> {};
0521     template <class CharT, class Traits, class Allocator>
0522     struct range_traits<std::basic_string<CharT, Traits, Allocator>> : iterable_value<Mutable::Yes>
0523     {};
0524 
0525     // const T * and views are read-only
0526     template <typename T> struct range_traits<const T *> : iterable_value<Mutable::No> {};
0527     template <> struct range_traits<QLatin1StringView> : iterable_value<Mutable::No> {};
0528 
0529     template <typename C>
0530     using is_range = range_traits<C>;
0531     template <typename C>
0532     [[maybe_unused]] static constexpr bool is_range_v = is_range<C>();
0533 
0534     // Detect which options are set to override default heuristics. Since
0535     // QRangeModel is not yet defined we need to delay the evaluation.
0536     template <typename T> struct QRangeModelRowOptions;
0537 
0538     template <typename T, typename = void>
0539     struct row_category : std::false_type
0540     {
0541         static constexpr bool isMultiRole = false;
0542     };
0543 
0544     template <typename T>
0545     struct row_category<T, std::void_t<decltype(QRangeModelRowOptions<T>::rowCategory)>>
0546         : std::true_type
0547     {
0548         static constexpr auto rowCategory = QRangeModelRowOptions<T>::rowCategory;
0549         using RowCategory = decltype(rowCategory);
0550         static constexpr bool isMultiRole = rowCategory == RowCategory::MultiRoleItem;
0551     };
0552 
0553     // Find out how many fixed elements can be retrieved from a row element.
0554     // main template for simple values and ranges. Specializing for ranges
0555     // is ambiguous with arrays, as they are also ranges
0556     template <typename T, typename = void>
0557     struct row_traits {
0558         static constexpr bool is_range = is_range_v<q20::remove_cvref_t<T>>;
0559         // A static size of -1 indicates dynamically sized range
0560         // A static size of 0 indicates that the specified type doesn't
0561         // represent static or dynamic range.
0562         static constexpr int static_size = is_range ? -1 : 0;
0563         using item_type = std::conditional_t<is_range, typename range_traits<T>::value_type, T>;
0564         static constexpr int fixed_size() { return 1; }
0565         static constexpr bool hasMetaObject = false;
0566     };
0567 
0568     // Specialization for tuple-like semantics (prioritized over metaobject)
0569     template <typename T>
0570     struct row_traits<T, std::enable_if_t<tuple_like_v<T>>>
0571     {
0572         static constexpr std::size_t size64 = std::tuple_size_v<T>;
0573         static_assert(q20::in_range<int>(size64));
0574         static constexpr int static_size = int(size64);
0575 
0576         // are the types in a tuple all the same
0577         template <std::size_t ...I>
0578         static constexpr bool allSameTypes(std::index_sequence<I...>)
0579         {
0580             return (std::is_same_v<std::tuple_element_t<0, T>,
0581                                    std::tuple_element_t<I, T>> && ...);
0582         }
0583 
0584         using item_type = std::conditional_t<allSameTypes(std::make_index_sequence<size64>{}),
0585                                              std::tuple_element_t<0, T>, void>;
0586         static constexpr int fixed_size() { return 0; }
0587         static constexpr bool hasMetaObject = false;
0588     };
0589 
0590     // Specialization for C arrays and std::array
0591     template <typename T, std::size_t N>
0592     struct row_traits<std::array<T, N>>
0593     {
0594         static_assert(q20::in_range<int>(N));
0595         static constexpr int static_size = int(N);
0596         using item_type = T;
0597         static constexpr int fixed_size() { return 0; }
0598         static constexpr bool hasMetaObject = false;
0599     };
0600 
0601     template <typename T, std::size_t N>
0602     struct row_traits<T[N]> : row_traits<std::array<T, N>> {};
0603 
0604     // prioritize tuple-like over metaobject
0605     template <typename T>
0606     struct row_traits<T, std::enable_if_t<has_metaobject_v<T> && !tuple_like_v<T>>>
0607     {
0608         static constexpr int static_size = 0;
0609         using item_type = std::conditional_t<row_category<T>::isMultiRole, T, void>;
0610         static int fixed_size() {
0611             if constexpr (row_category<T>::isMultiRole) {
0612                 return 1;
0613             } else {
0614                 // Interpret a gadget in a list as a multi-column row item. To make
0615                 // a list of multi-role items, wrap it into SingleColumn.
0616                 static const int columnCount = []{
0617                     const QMetaObject &mo = T::staticMetaObject;
0618                     return mo.propertyCount() - mo.propertyOffset();
0619                 }();
0620                 return columnCount;
0621             }
0622         }
0623         static constexpr bool hasMetaObject = true;
0624     };
0625 
0626     template <typename T>
0627     [[maybe_unused]] static constexpr int static_size_v =
0628                             row_traits<std::remove_cv_t<wrapped_t<T>>>::static_size;
0629 
0630     template <typename Range>
0631     struct ListProtocol
0632     {
0633         using row_type = typename range_traits<wrapped_t<Range>>::value_type;
0634 
0635         template <typename R = row_type>
0636         auto newRow() -> decltype(R{}) { return R{}; }
0637     };
0638 
0639     template <typename Range>
0640     struct TableProtocol
0641     {
0642         using row_type = typename range_traits<wrapped_t<Range>>::value_type;
0643 
0644         template <typename R = row_type,
0645                   std::enable_if_t<std::conjunction_v<std::is_destructible<wrapped_t<R>>,
0646                                                       is_owning_or_raw_pointer<R>>, bool> = true>
0647         auto newRow() -> decltype(R(new wrapped_t<R>)) {
0648             if constexpr (is_any_of<R, std::shared_ptr>())
0649                 return std::make_shared<wrapped_t<R>>();
0650             else
0651                 return R(new wrapped_t<R>);
0652         }
0653 
0654         template <typename R = row_type,
0655                   std::enable_if_t<!is_owning_or_raw_pointer<R>::value, bool> = true>
0656         auto newRow() -> decltype(R{}) { return R{}; }
0657 
0658         template <typename R = row_type,
0659                   std::enable_if_t<std::is_pointer_v<std::remove_reference_t<R>>, bool> = true>
0660         auto deleteRow(R&& row) -> decltype(delete row) { delete row; }
0661     };
0662 
0663     template <typename Range, typename R = typename range_traits<wrapped_t<Range>>::value_type>
0664     using table_protocol_t = std::conditional_t<static_size_v<R> == 0 && !has_metaobject_v<R>,
0665                                                 ListProtocol<Range>, TableProtocol<Range>>;
0666 
0667     // Default tree traversal protocol implementation for row types that have
0668     // the respective member functions. The trailing return type implicitly
0669     // removes those functions that are not available.
0670     template <typename Range>
0671     struct DefaultTreeProtocol : TableProtocol<Range>
0672     {
0673         template <typename R /*wrapped_row_type*/>
0674         auto parentRow(const R& row) const -> decltype(row.parentRow())
0675         {
0676             return row.parentRow();
0677         }
0678 
0679         template <typename R /* = wrapped_row_type*/>
0680         auto setParentRow(R &row, R* parent) -> decltype(row.setParentRow(parent))
0681         {
0682             row.setParentRow(parent);
0683         }
0684 
0685         template <typename R /* = wrapped_row_type*/>
0686         auto childRows(const R &row) const -> decltype(row.childRows())
0687         {
0688             return row.childRows();
0689         }
0690 
0691         template <typename R /* = wrapped_row_type*/>
0692         auto childRows(R &row) -> decltype(row.childRows())
0693         {
0694             return row.childRows();
0695         }
0696     };
0697 
0698     template <typename P, typename R, typename = void>
0699     struct protocol_parentRow : std::false_type {};
0700     template <typename P, typename R>
0701     struct protocol_parentRow<P, R,
0702             std::void_t<decltype(std::declval<P&>().parentRow(std::declval<wrapped_t<R>&>()))>>
0703         : std::true_type {};
0704 
0705     template <typename P, typename R, typename = void>
0706     struct protocol_childRows : std::false_type {};
0707     template <typename P, typename R>
0708     struct protocol_childRows<P, R,
0709             std::void_t<decltype(std::declval<P&>().childRows(std::declval<wrapped_t<R>&>()))>>
0710         : std::true_type {};
0711 
0712     template <typename P, typename R, typename = void>
0713     struct protocol_setParentRow : std::false_type {};
0714     template <typename P, typename R>
0715     struct protocol_setParentRow<P, R,
0716             std::void_t<decltype(std::declval<P&>().setParentRow(std::declval<wrapped_t<R>&>(),
0717                                                                  std::declval<wrapped_t<R>*>()))>>
0718         : std::true_type {};
0719 
0720     template <typename P, typename R, typename = void>
0721     struct protocol_mutable_childRows : std::false_type {};
0722     template <typename P, typename R>
0723     struct protocol_mutable_childRows<P, R,
0724             std::void_t<decltype(refTo(std::declval<P&>().childRows(std::declval<wrapped_t<R>&>()))
0725                                                                                             = {}) >>
0726         : std::true_type {};
0727 
0728     template <typename P, typename = void>
0729     struct protocol_newRow : std::false_type {};
0730     template <typename P>
0731     struct protocol_newRow<P, std::void_t<decltype(std::declval<P&>().newRow())>>
0732         : std::true_type {};
0733 
0734     template <typename P, typename R, typename = void>
0735     struct protocol_deleteRow : std::false_type {};
0736     template <typename P, typename R>
0737     struct protocol_deleteRow<P, R,
0738             std::void_t<decltype(std::declval<P&>().deleteRow(std::declval<R&&>()))>>
0739         : std::true_type {};
0740 
0741     template <typename Range,
0742               typename Protocol = DefaultTreeProtocol<Range>,
0743               typename R = typename range_traits<Range>::value_type,
0744               typename = void>
0745     struct is_tree_range : std::false_type {};
0746 
0747     template <typename Range, typename Protocol, typename R>
0748     struct is_tree_range<Range, Protocol, R,
0749                          std::enable_if_t<std::conjunction_v<
0750                             protocol_parentRow<Protocol, R>, protocol_childRows<Protocol, R>>>
0751             > : std::true_type {};
0752 
0753     template <typename Range>
0754     using if_table_range = std::enable_if_t<std::conjunction_v<is_range<wrapped_t<Range>>,
0755                                                     std::negation<is_tree_range<wrapped_t<Range>>>>,
0756                                             bool>;
0757 
0758     template <typename Range, typename Protocol = DefaultTreeProtocol<Range>>
0759     using if_tree_range = std::enable_if_t<std::conjunction_v<is_range<wrapped_t<Range>>,
0760                                               is_tree_range<wrapped_t<Range>, wrapped_t<Protocol>>>,
0761                                            bool>;
0762 
0763     template <typename Range, typename Protocol>
0764     struct protocol_traits
0765     {
0766         using protocol = wrapped_t<Protocol>;
0767         using row = typename range_traits<wrapped_t<Range>>::value_type;
0768 
0769         static constexpr bool has_newRow = protocol_newRow<protocol>();
0770         static constexpr bool has_deleteRow = protocol_deleteRow<protocol, row>();
0771         static constexpr bool has_setParentRow = protocol_setParentRow<protocol, row>();
0772         static constexpr bool has_mutable_childRows = protocol_mutable_childRows<protocol, row>();
0773 
0774         static constexpr bool is_default = is_any_of<protocol, ListProtocol, TableProtocol, DefaultTreeProtocol>();
0775     };
0776 
0777     template <bool cacheProperties>
0778     struct PropertyData {
0779         static constexpr bool cachesProperties = false;
0780 
0781         void invalidateCaches() {}
0782     };
0783 
0784     template <>
0785     struct PropertyData<true>
0786     {
0787         static constexpr bool cachesProperties = true;
0788         mutable QHash<int, QMetaProperty> properties;
0789 
0790         void invalidateCaches()
0791         {
0792             properties.clear();
0793         }
0794     };
0795 
0796     // The storage of the model data. We might store it as a pointer, or as a
0797     // (copied- or moved-into) value (or smart pointer). But we always return a
0798     // raw pointer.
0799     template <typename ModelStorage, typename ItemType>
0800     struct ModelData : PropertyData<has_metaobject_v<ItemType>>
0801     {
0802         auto model() { return pointerTo(m_model); }
0803         auto model() const { return pointerTo(m_model); }
0804 
0805         template <typename Model = ModelStorage>
0806         ModelData(Model &&model)
0807             : m_model(std::forward<Model>(model))
0808         {}
0809         ModelStorage m_model;
0810     };
0811 } // namespace QRangeModelDetails
0812 
0813 class QRangeModel;
0814 
0815 class QRangeModelImplBase : public QtPrivate::QQuasiVirtualInterface<QRangeModelImplBase>
0816 {
0817 private:
0818     using Self = QRangeModelImplBase;
0819     using QtPrivate::QQuasiVirtualInterface<Self>::Method;
0820 protected:
0821     // Helper for calling a lambda with the element of a statically
0822     // sized range (tuple or array) with a runtime index.
0823     template <typename StaticContainer, typename F>
0824     static auto for_element_at(StaticContainer &&container, std::size_t idx, F &&function)
0825     {
0826         using type = std::remove_cv_t<QRangeModelDetails::wrapped_t<StaticContainer>>;
0827         static_assert(QRangeModelDetails::array_like_v<type> || QRangeModelDetails::tuple_like_v<type>,
0828                       "Internal error: expected an array-like or a tuple-like type");
0829 
0830         if (QRangeModelDetails::isValid(container)) {
0831             auto& ref = QRangeModelDetails::refTo(std::forward<StaticContainer>(container));
0832             if constexpr (QRangeModelDetails::array_like_v<type>) {
0833                 Q_ASSERT(idx < std::size(ref));
0834                 function(ref[idx]);
0835             } else {
0836                 constexpr size_t size = std::tuple_size_v<type>;
0837                 Q_ASSERT(idx < std::tuple_size_v<type>);
0838                 QtPrivate::applyIndexSwitch<size>(idx, [&](auto idxConstant) {
0839                     function(get<idxConstant>(ref));
0840                 });
0841             }
0842         }
0843     }
0844 
0845     // Get the QMetaType for a tuple-element at a runtime index.
0846     // Used in the headerData implementation.
0847     template <typename T>
0848     static constexpr QMetaType meta_type_at(size_t idx)
0849     {
0850         using type = QRangeModelDetails::wrapped_t<T>;
0851         if constexpr (QRangeModelDetails::array_like_v<type>) {
0852             Q_UNUSED(idx);
0853             return QMetaType::fromType<std::tuple_element_t<0, type>>();
0854         } else {
0855             constexpr auto size = std::tuple_size_v<type>;
0856             Q_ASSERT(idx < size);
0857             QMetaType metaType;
0858             QtPrivate::applyIndexSwitch<size>(idx, [&metaType](auto idxConstant) {
0859                 using ElementType = std::tuple_element_t<idxConstant.value, type>;
0860                 metaType = QMetaType::fromType<QRangeModelDetails::wrapped_t<ElementType>>();
0861             });
0862             return metaType;
0863         }
0864     }
0865 
0866 public:
0867     // overridable prototypes (quasi-pure-virtual methods)
0868 
0869     void invalidateCaches();
0870     bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role);
0871     bool setData(const QModelIndex &index, const QVariant &data, int role);
0872     bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &data);
0873     bool clearItemData(const QModelIndex &index);
0874     bool insertColumns(int column, int count, const QModelIndex &parent);
0875     bool removeColumns(int column, int count, const QModelIndex &parent);
0876     bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn);
0877     bool insertRows(int row, int count, const QModelIndex &parent);
0878     bool removeRows(int row, int count, const QModelIndex &parent);
0879     bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow);
0880 
0881     QModelIndex index(int row, int column, const QModelIndex &parent) const;
0882     QModelIndex sibling(int row, int column, const QModelIndex &index) const;
0883     int rowCount(const QModelIndex &parent) const;
0884     int columnCount(const QModelIndex &parent) const;
0885     Qt::ItemFlags flags(const QModelIndex &index) const;
0886     QVariant headerData(int section, Qt::Orientation orientation, int role) const;
0887     QVariant data(const QModelIndex &index, int role) const;
0888     QMap<int, QVariant> itemData(const QModelIndex &index) const;
0889     QHash<int, QByteArray> roleNames() const;
0890     QModelIndex parent(const QModelIndex &child) const;
0891 
0892     // bindings for overriding
0893 
0894     using InvalidateCaches = Method<&Self::invalidateCaches>;
0895     using SetHeaderData = Method<&Self::setHeaderData>;
0896     using SetData = Method<&Self::setData>;
0897     using SetItemData = Method<&Self::setItemData>;
0898     using ClearItemData = Method<&Self::clearItemData>;
0899     using InsertColumns = Method<&Self::insertColumns>;
0900     using RemoveColumns = Method<&Self::removeColumns>;
0901     using MoveColumns = Method<&Self::moveColumns>;
0902     using InsertRows = Method<&Self::insertRows>;
0903     using RemoveRows = Method<&Self::removeRows>;
0904     using MoveRows = Method<&Self::moveRows>;
0905 
0906     using Index = Method<&Self::index>;
0907     using Sibling = Method<&Self::sibling>;
0908     using RowCount = Method<&Self::rowCount>;
0909     using ColumnCount = Method<&Self::columnCount>;
0910     using Flags = Method<&Self::flags>;
0911     using HeaderData = Method<&Self::headerData>;
0912     using Data = Method<&Self::data>;
0913     using ItemData = Method<&Self::itemData>;
0914     using RoleNames = Method<&Self::roleNames>;
0915     using Parent = Method<&Self::parent>;
0916 
0917     template <typename C>
0918     using MethodTemplates = std::tuple<
0919         typename C::Destroy,
0920         typename C::InvalidateCaches,
0921         typename C::SetHeaderData,
0922         typename C::SetData,
0923         typename C::SetItemData,
0924         typename C::ClearItemData,
0925         typename C::InsertColumns,
0926         typename C::RemoveColumns,
0927         typename C::MoveColumns,
0928         typename C::InsertRows,
0929         typename C::RemoveRows,
0930         typename C::MoveRows,
0931         typename C::Index,
0932         typename C::Parent,
0933         typename C::Sibling,
0934         typename C::RowCount,
0935         typename C::ColumnCount,
0936         typename C::Flags,
0937         typename C::HeaderData,
0938         typename C::Data,
0939         typename C::ItemData,
0940         typename C::RoleNames
0941     >;
0942 
0943 private:
0944     friend class QRangeModelPrivate;
0945     QRangeModel *m_rangeModel;
0946 
0947 protected:
0948     explicit QRangeModelImplBase(QRangeModel *itemModel)
0949         : m_rangeModel(itemModel)
0950     {}
0951 
0952     inline QModelIndex createIndex(int row, int column, const void *ptr = nullptr) const;
0953     inline void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to);
0954     inline void dataChanged(const QModelIndex &from, const QModelIndex &to,
0955                             const QList<int> &roles);
0956     inline void beginInsertColumns(const QModelIndex &parent, int start, int count);
0957     inline void endInsertColumns();
0958     inline void beginRemoveColumns(const QModelIndex &parent, int start, int count);
0959     inline void endRemoveColumns();
0960     inline bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast,
0961                                  const QModelIndex &destParent, int destRow);
0962     inline void endMoveColumns();
0963     inline void beginInsertRows(const QModelIndex &parent, int start, int count);
0964     inline void endInsertRows();
0965     inline void beginRemoveRows(const QModelIndex &parent, int start, int count);
0966     inline void endRemoveRows();
0967     inline bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast,
0968                               const QModelIndex &destParent, int destRow);
0969     inline void endMoveRows();
0970     inline QAbstractItemModel &itemModel();
0971     inline const QAbstractItemModel &itemModel() const;
0972 
0973     // implemented in qrangemodel.cpp
0974     Q_CORE_EXPORT static QHash<int, QByteArray> roleNamesForMetaObject(const QAbstractItemModel &model,
0975                                                                        const QMetaObject &metaObject);
0976     Q_CORE_EXPORT static QHash<int, QByteArray> roleNamesForSimpleType();
0977 };
0978 
0979 template <typename Structure, typename Range,
0980           typename Protocol = QRangeModelDetails::table_protocol_t<Range>>
0981 class QRangeModelImpl
0982         : public QtPrivate::QQuasiVirtualSubclass<QRangeModelImpl<Structure, Range, Protocol>,
0983                                                   QRangeModelImplBase>
0984 {
0985 public:
0986     using range_type = QRangeModelDetails::wrapped_t<Range>;
0987     using row_reference = decltype(*QRangeModelDetails::begin(std::declval<range_type&>()));
0988     using const_row_reference = decltype(*QRangeModelDetails::begin(std::declval<const range_type&>()));
0989     using row_type = std::remove_reference_t<row_reference>;
0990     using protocol_type = QRangeModelDetails::wrapped_t<Protocol>;
0991 
0992     static_assert(!QRangeModelDetails::is_any_of<range_type, std::optional>() &&
0993                   !QRangeModelDetails::is_any_of<row_type, std::optional>(),
0994                   "Currently, std::optional is not supported for ranges and rows, as "
0995                   "it has range semantics in c++26. Once the required behavior is clarified, "
0996                   "std::optional for ranges and rows will be supported.");
0997 
0998 protected:
0999 
1000     using Self = QRangeModelImpl<Structure, Range, Protocol>;
1001     using Ancestor = QtPrivate::QQuasiVirtualSubclass<Self, QRangeModelImplBase>;
1002 
1003     Structure& that() { return static_cast<Structure &>(*this); }
1004     const Structure& that() const { return static_cast<const Structure &>(*this); }
1005 
1006     template <typename C>
1007     static constexpr int size(const C &c)
1008     {
1009         if (!QRangeModelDetails::isValid(c))
1010             return 0;
1011 
1012         if constexpr (QRangeModelDetails::test_size<C>()) {
1013             return int(std::size(c));
1014         } else {
1015 #if defined(__cpp_lib_ranges)
1016             return int(std::ranges::distance(QRangeModelDetails::begin(c),
1017                                              QRangeModelDetails::end(c)));
1018 #else
1019             return int(std::distance(QRangeModelDetails::begin(c),
1020                                      QRangeModelDetails::end(c)));
1021 #endif
1022         }
1023     }
1024 
1025     using range_features = QRangeModelDetails::range_traits<range_type>;
1026     using wrapped_row_type = QRangeModelDetails::wrapped_t<row_type>;
1027     using row_features = QRangeModelDetails::range_traits<wrapped_row_type>;
1028     using row_traits = QRangeModelDetails::row_traits<std::remove_cv_t<wrapped_row_type>>;
1029     using protocol_traits = QRangeModelDetails::protocol_traits<Range, protocol_type>;
1030 
1031     static constexpr bool isMutable()
1032     {
1033         return range_features::is_mutable && row_features::is_mutable
1034             && std::is_reference_v<row_reference>
1035             && Structure::is_mutable_impl;
1036     }
1037 
1038     static constexpr int static_row_count = QRangeModelDetails::static_size_v<range_type>;
1039     static constexpr bool rows_are_raw_pointers = std::is_pointer_v<row_type>;
1040     static constexpr bool rows_are_owning_or_raw_pointers =
1041             QRangeModelDetails::is_owning_or_raw_pointer<row_type>();
1042     static constexpr int static_column_count = QRangeModelDetails::static_size_v<row_type>;
1043     static constexpr bool one_dimensional_range = static_column_count == 0;
1044 
1045     static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; }
1046     static constexpr bool dynamicColumns() { return static_column_count < 0; }
1047 
1048     // A row might be a value (or range of values), or a pointer.
1049     // row_ptr is always a pointer, and const_row_ptr is a pointer to const.
1050     using row_ptr = wrapped_row_type *;
1051     using const_row_ptr = const wrapped_row_type *;
1052 
1053     template <typename T>
1054     static constexpr bool has_metaobject = QRangeModelDetails::has_metaobject_v<
1055                                                 std::remove_pointer_t<std::remove_reference_t<T>>>;
1056 
1057     using ModelData = QRangeModelDetails::ModelData<std::conditional_t<
1058                                                         std::is_pointer_v<Range>,
1059                                                         Range, std::remove_reference_t<Range>
1060                                                     >,
1061                                                     typename row_traits::item_type
1062                                                 >;
1063 
1064     // A iterator type to use as the input iterator with the
1065     // range_type::insert(pos, start, end) overload if available (it is in
1066     // std::vector, but not in QList). Generates a prvalue when dereferenced,
1067     // which then gets moved into the newly constructed row, which allows us to
1068     // implement insertRows() for move-only row types.
1069     struct EmptyRowGenerator
1070     {
1071         using value_type = row_type;
1072         using reference = value_type;
1073         using pointer = value_type *;
1074         using iterator_category = std::input_iterator_tag;
1075         using difference_type = int;
1076 
1077         value_type operator*() { return impl->makeEmptyRow(*parent); }
1078         EmptyRowGenerator &operator++() { ++n; return *this; }
1079         friend bool operator==(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
1080         { return lhs.n == rhs.n; }
1081         friend bool operator!=(const EmptyRowGenerator &lhs, const EmptyRowGenerator &rhs) noexcept
1082         { return !(lhs == rhs); }
1083 
1084         difference_type n = 0;
1085         Structure *impl = nullptr;
1086         const QModelIndex* parent = nullptr;
1087     };
1088 
1089     // If we have a move-only row_type and can add/remove rows, then the range
1090     // must have an insert-from-range overload.
1091     static_assert(static_row_count || range_features::has_insert_range
1092                                    || std::is_copy_constructible_v<row_type>,
1093                   "The range holding a move-only row-type must support insert(pos, start, end)");
1094 
1095 public:
1096     explicit QRangeModelImpl(Range &&model, Protocol&& protocol, QRangeModel *itemModel)
1097         : Ancestor(itemModel)
1098         , m_data{std::forward<Range>(model)}
1099         , m_protocol(std::forward<Protocol>(protocol))
1100     {
1101     }
1102 
1103 
1104     // static interface, called by QRangeModelImplBase
1105 
1106     void invalidateCaches() { m_data.invalidateCaches(); }
1107 
1108     // Not implemented
1109     bool setHeaderData(int , Qt::Orientation , const QVariant &, int ) { return false; }
1110 
1111     // actual implementations
1112     QModelIndex index(int row, int column, const QModelIndex &parent) const
1113     {
1114         if (row < 0 || column < 0 || column >= columnCount(parent)
1115                                   || row >= rowCount(parent)) {
1116             return {};
1117         }
1118 
1119         return that().indexImpl(row, column, parent);
1120     }
1121 
1122     QModelIndex sibling(int row, int column, const QModelIndex &index) const
1123     {
1124         if (row == index.row() && column == index.column())
1125             return index;
1126 
1127         if (column < 0 || column >= this->itemModel().columnCount())
1128             return {};
1129 
1130         if (row == index.row())
1131             return this->createIndex(row, column, index.constInternalPointer());
1132 
1133         const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer());
1134         const auto siblingCount = size(that().childrenOf(parentRow));
1135         if (row < 0 || row >= int(siblingCount))
1136             return {};
1137         return this->createIndex(row, column, parentRow);
1138     }
1139 
1140     Qt::ItemFlags flags(const QModelIndex &index) const
1141     {
1142         if (!index.isValid())
1143             return Qt::NoItemFlags;
1144 
1145         Qt::ItemFlags f = Structure::defaultFlags();
1146 
1147         if constexpr (isMutable()) {
1148             if constexpr (row_traits::hasMetaObject) {
1149                 if (index.column() < row_traits::fixed_size()) {
1150                     const QMetaObject mo = wrapped_row_type::staticMetaObject;
1151                     const QMetaProperty prop = mo.property(index.column() + mo.propertyOffset());
1152                     if (prop.isWritable())
1153                         f |= Qt::ItemIsEditable;
1154                 }
1155             } else if constexpr (static_column_count <= 0) {
1156                 f |= Qt::ItemIsEditable;
1157             } else if constexpr (std::is_reference_v<row_reference> && !std::is_const_v<row_reference>) {
1158                 // we want to know if the elements in the tuple are const; they'd always be, if
1159                 // we didn't remove the const of the range first.
1160                 const_row_reference row = rowData(index);
1161                 row_reference mutableRow = const_cast<row_reference>(row);
1162                 if (QRangeModelDetails::isValid(mutableRow)) {
1163                     QRangeModelImplBase::for_element_at(mutableRow, index.column(), [&f](auto &&ref){
1164                         using target_type = decltype(ref);
1165                         if constexpr (std::is_const_v<std::remove_reference_t<target_type>>)
1166                             f &= ~Qt::ItemIsEditable;
1167                         else if constexpr (std::is_lvalue_reference_v<target_type>)
1168                             f |= Qt::ItemIsEditable;
1169                     });
1170                 } else {
1171                     // If there's no usable value stored in the row, then we can't
1172                     // do anything with this item.
1173                     f &= ~Qt::ItemIsEditable;
1174                 }
1175             }
1176         }
1177         return f;
1178     }
1179 
1180     QVariant headerData(int section, Qt::Orientation orientation, int role) const
1181     {
1182         QVariant result;
1183         if (role != Qt::DisplayRole || orientation != Qt::Horizontal
1184          || section < 0 || section >= columnCount({})) {
1185             return this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1186         }
1187 
1188         if constexpr (row_traits::hasMetaObject) {
1189             if (row_traits::fixed_size() == 1) {
1190                 const QMetaType metaType = QMetaType::fromType<wrapped_row_type>();
1191                 result = QString::fromUtf8(metaType.name());
1192             } else if (section <= row_traits::fixed_size()) {
1193                 const QMetaProperty prop = wrapped_row_type::staticMetaObject.property(
1194                                     section + wrapped_row_type::staticMetaObject.propertyOffset());
1195                 result = QString::fromUtf8(prop.name());
1196             }
1197         } else if constexpr (static_column_count >= 1) {
1198             if constexpr (QRangeModelDetails::array_like_v<wrapped_row_type>) {
1199                 return section;
1200             } else {
1201                 const QMetaType metaType = QRangeModelImplBase::meta_type_at<wrapped_row_type>(section);
1202                 if (metaType.isValid())
1203                     result = QString::fromUtf8(metaType.name());
1204             }
1205         }
1206         if (!result.isValid())
1207             result = this->itemModel().QAbstractItemModel::headerData(section, orientation, role);
1208         return result;
1209     }
1210 
1211     QVariant data(const QModelIndex &index, int role) const
1212     {
1213         QVariant result;
1214         const auto readData = [this, column = index.column(), &result, role](const auto &value) {
1215             Q_UNUSED(this);
1216             using value_type = q20::remove_cvref_t<decltype(value)>;
1217             using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1218             if constexpr (has_metaobject<value_type>) {
1219                 if (row_traits::fixed_size() <= 1) {
1220                     if (role == Qt::RangeModelDataRole) {
1221                         using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1222                         // Qt QML support: "modelData" role returns the entire multi-role item.
1223                         // QML can only use raw pointers to QObject (so we unwrap), and gadgets
1224                         // only by value (so we take the reference).
1225                         if constexpr (std::is_copy_assignable_v<wrapped_value_type>)
1226                             result = QVariant::fromValue(QRangeModelDetails::refTo(value));
1227                         else
1228                             result = QVariant::fromValue(QRangeModelDetails::pointerTo(value));
1229                     } else {
1230                         result = readRole(role, QRangeModelDetails::pointerTo(value));
1231                     }
1232                 } else if (column <= row_traits::fixed_size()
1233                         && (role == Qt::DisplayRole || role == Qt::EditRole)) {
1234                     result = readProperty(column, QRangeModelDetails::pointerTo(value));
1235                 }
1236             } else if constexpr (multi_role::value) {
1237                 const auto it = [this, &value, role]{
1238                     Q_UNUSED(this);
1239                     if constexpr (multi_role::int_key)
1240                         return std::as_const(value).find(Qt::ItemDataRole(role));
1241                     else
1242                         return std::as_const(value).find(this->itemModel().roleNames().value(role));
1243                 }();
1244                 if (it != QRangeModelDetails::end(value))
1245                     result = QRangeModelDetails::value(it);
1246             } else if (role == Qt::DisplayRole || role == Qt::EditRole
1247                     || role == Qt::RangeModelDataRole) {
1248                 result = read(value);
1249             }
1250         };
1251 
1252         if (index.isValid())
1253             readAt(index, readData);
1254 
1255         return result;
1256     }
1257 
1258     QMap<int, QVariant> itemData(const QModelIndex &index) const
1259     {
1260         QMap<int, QVariant> result;
1261         bool tried = false;
1262         const auto readItemData = [this, &result, &tried](const auto &value){
1263             Q_UNUSED(this);
1264             using value_type = q20::remove_cvref_t<decltype(value)>;
1265             using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1266             if constexpr (multi_role()) {
1267                 tried = true;
1268                 if constexpr (std::is_convertible_v<value_type, decltype(result)>) {
1269                     result = value;
1270                 } else {
1271                     const auto roleNames = [this]() -> QHash<int, QByteArray> {
1272                         Q_UNUSED(this);
1273                         if constexpr (!multi_role::int_key)
1274                             return this->itemModel().roleNames();
1275                         else
1276                             return {};
1277                     }();
1278                     for (auto it = std::begin(value); it != std::end(value); ++it) {
1279                         const int role = [&roleNames, key = QRangeModelDetails::key(it)]() {
1280                             Q_UNUSED(roleNames);
1281                             if constexpr (multi_role::int_key)
1282                                 return int(key);
1283                             else
1284                                 return roleNames.key(key.toUtf8(), -1);
1285                         }();
1286 
1287                         if (role != -1 && role != Qt::RangeModelDataRole)
1288                             result.insert(role, QRangeModelDetails::value(it));
1289                     }
1290                 }
1291             } else if constexpr (has_metaobject<value_type>) {
1292                 if (row_traits::fixed_size() <= 1) {
1293                     tried = true;
1294                     const auto roleNames = this->itemModel().roleNames();
1295                     const auto end = roleNames.keyEnd();
1296                     for (auto it = roleNames.keyBegin(); it != end; ++it) {
1297                         const int role = *it;
1298                         if (role == Qt::RangeModelDataRole)
1299                             continue;
1300                         QVariant data = readRole(role, QRangeModelDetails::pointerTo(value));
1301                         if (data.isValid())
1302                             result[role] = std::move(data);
1303                     }
1304                 }
1305             }
1306         };
1307 
1308         if (index.isValid()) {
1309             readAt(index, readItemData);
1310 
1311             if (!tried) // no multi-role item found
1312                 result = this->itemModel().QAbstractItemModel::itemData(index);
1313         }
1314         return result;
1315     }
1316 
1317     bool setData(const QModelIndex &index, const QVariant &data, int role)
1318     {
1319         if (!index.isValid())
1320             return false;
1321 
1322         bool success = false;
1323         if constexpr (isMutable()) {
1324             auto emitDataChanged = qScopeGuard([&success, this, &index, role]{
1325                 if (success) {
1326                     Q_EMIT this->dataChanged(index, index,
1327                                        role == Qt::EditRole || role == Qt::RangeModelDataRole
1328                                             ? QList<int>{} : QList<int>{role});
1329                 }
1330             });
1331 
1332             const auto writeData = [this, column = index.column(), &data, role](auto &&target) -> bool {
1333                 using value_type = q20::remove_cvref_t<decltype(target)>;
1334                 using wrapped_value_type = QRangeModelDetails::wrapped_t<value_type>;
1335                 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1336                 if constexpr (has_metaobject<value_type>) {
1337                     if (role == Qt::RangeModelDataRole) {
1338                         auto &targetRef = QRangeModelDetails::refTo(target);
1339                         constexpr auto targetMetaType = QMetaType::fromType<value_type>();
1340                         const auto dataMetaType = data.metaType();
1341                         if constexpr (!std::is_copy_assignable_v<wrapped_value_type>) {
1342                             // This covers move-only types, but also polymorph types like QObject.
1343                             // We don't support replacing a stored object with another one, as this
1344                             // makes object ownership very messy.
1345                             // fall through to error handling
1346                         } else if constexpr (QRangeModelDetails::is_wrapped<value_type>()) {
1347                             if (QRangeModelDetails::isValid(target)) {
1348                                 // we need to get a wrapped value type out of the QVariant, which
1349                                 // might carry a pointer. We have to try all alternatives.
1350                                 if (const auto mt = QMetaType::fromType<wrapped_value_type>();
1351                                     data.canConvert(mt)) {
1352                                     targetRef = data.value<wrapped_value_type>();
1353                                     return true;
1354                                 } else if (const auto mtp = QMetaType::fromType<wrapped_value_type *>();
1355                                            data.canConvert(mtp)) {
1356                                     targetRef = *data.value<wrapped_value_type *>();
1357                                     return true;
1358                                 }
1359                             }
1360                         } else if (targetMetaType == dataMetaType) {
1361                             targetRef = data.value<value_type>();
1362                             return true;
1363                         } else if (dataMetaType.flags() & QMetaType::PointerToGadget) {
1364                             targetRef = *data.value<value_type *>();
1365                             return true;
1366                         }
1367 #ifndef QT_NO_DEBUG
1368                         qCritical("Not able to assign %s to %s",
1369                                   qPrintable(QDebug::toString(data)), targetMetaType.name());
1370 #endif
1371                         return false;
1372                     } else if (row_traits::fixed_size() <= 1) {
1373                         return writeRole(role, QRangeModelDetails::pointerTo(target), data);
1374                     } else if (column <= row_traits::fixed_size()
1375                             && (role == Qt::DisplayRole || role == Qt::EditRole)) {
1376                         return writeProperty(column, QRangeModelDetails::pointerTo(target), data);
1377                     }
1378                 } else if constexpr (multi_role::value) {
1379                     Qt::ItemDataRole roleToSet = Qt::ItemDataRole(role);
1380                     // If there is an entry for EditRole, overwrite that; otherwise,
1381                     // set the entry for DisplayRole.
1382                     const auto roleNames = [this]() -> QHash<int, QByteArray> {
1383                         Q_UNUSED(this);
1384                         if constexpr (!multi_role::int_key)
1385                             return this->itemModel().roleNames();
1386                         else
1387                             return {};
1388                     }();
1389                     if (role == Qt::EditRole) {
1390                         if constexpr (multi_role::int_key) {
1391                             if (target.find(roleToSet) == target.end())
1392                                 roleToSet = Qt::DisplayRole;
1393                         } else {
1394                             if (target.find(roleNames.value(roleToSet)) == target.end())
1395                                 roleToSet = Qt::DisplayRole;
1396                         }
1397                     }
1398                     if constexpr (multi_role::int_key)
1399                         return write(target[roleToSet], data);
1400                     else
1401                         return write(target[roleNames.value(roleToSet)], data);
1402                 } else if (role == Qt::DisplayRole || role == Qt::EditRole
1403                         || role == Qt::RangeModelDataRole) {
1404                     return write(target, data);
1405                 }
1406                 return false;
1407             };
1408 
1409             success = writeAt(index, writeData);
1410         }
1411         return success;
1412     }
1413 
1414     bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &data)
1415     {
1416         if (!index.isValid() || data.isEmpty())
1417             return false;
1418 
1419         bool success = false;
1420         if constexpr (isMutable()) {
1421             auto emitDataChanged = qScopeGuard([&success, this, &index, &data]{
1422                 if (success)
1423                     Q_EMIT this->dataChanged(index, index, data.keys());
1424             });
1425 
1426             bool tried = false;
1427             auto writeItemData = [this, &tried, &data](auto &target) -> bool {
1428                 Q_UNUSED(this);
1429                 using value_type = q20::remove_cvref_t<decltype(target)>;
1430                 using multi_role = QRangeModelDetails::is_multi_role<value_type>;
1431                 if constexpr (multi_role()) {
1432                     using key_type = typename value_type::key_type;
1433                     tried = true;
1434                     const auto roleName = [map = this->itemModel().roleNames()](int role) {
1435                         return map.value(role);
1436                     };
1437 
1438                     // transactional: only update target if all values from data
1439                     // can be stored. Storing never fails with int-keys.
1440                     if constexpr (!multi_role::int_key)
1441                     {
1442                         auto invalid = std::find_if(data.keyBegin(), data.keyEnd(),
1443                             [&roleName](int role) { return roleName(role).isEmpty(); }
1444                         );
1445 
1446                         if (invalid != data.keyEnd()) {
1447 #ifndef QT_NO_DEBUG
1448                             qWarning("No role name set for %d", *invalid);
1449 #endif
1450                             return false;
1451                         }
1452                     }
1453 
1454                     for (auto &&[role, value] : data.asKeyValueRange()) {
1455                         if constexpr (multi_role::int_key)
1456                             target[static_cast<key_type>(role)] = value;
1457                         else
1458                             target[QString::fromUtf8(roleName(role))] = value;
1459                     }
1460                     return true;
1461                 } else if constexpr (has_metaobject<value_type>) {
1462                     if (row_traits::fixed_size() <= 1) {
1463                         tried = true;
1464                         using wrapped_type = QRangeModelDetails::wrapped_t<value_type>;
1465                         // transactional: if possible, modify a copy and only
1466                         // update target if all values from data could be stored.
1467                         auto targetCopy = [](auto &&origin) {
1468                             if constexpr (!std::is_copy_assignable_v<wrapped_type>)
1469                                 return QRangeModelDetails::pointerTo(origin); // no transaction support
1470                             else if constexpr (std::is_pointer_v<decltype(target)>)
1471                                 return *origin;
1472                             else if constexpr (std::is_copy_assignable_v<value_type>)
1473                                 return origin;
1474                             else
1475                                 return QRangeModelDetails::pointerTo(origin);
1476                         }(target);
1477                         const auto roleNames = this->itemModel().roleNames();
1478                         for (auto &&[role, value] : data.asKeyValueRange()) {
1479                             if (role == Qt::RangeModelDataRole)
1480                                 continue;
1481                             if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) {
1482                                 const QByteArray roleName = roleNames.value(role);
1483 #ifndef QT_NO_DEBUG
1484                                 qWarning("Failed to write value '%s' to role '%s'",
1485                                          qPrintable(QDebug::toString(value)), roleName.data());
1486 #endif
1487                                 return false;
1488                             }
1489                         }
1490                         if constexpr (std::is_pointer_v<decltype(targetCopy)>)
1491                             ; // couldn't copy
1492                         else if constexpr (std::is_pointer_v<decltype(target)>)
1493                             qSwap(*target, targetCopy);
1494                         else
1495                             qSwap(target, targetCopy);
1496                         return true;
1497                     }
1498                 }
1499                 return false;
1500             };
1501 
1502             success = writeAt(index, writeItemData);
1503 
1504             if (!tried) {
1505                 // setItemData will emit the dataChanged signal
1506                 Q_ASSERT(!success);
1507                 emitDataChanged.dismiss();
1508                 success = this->itemModel().QAbstractItemModel::setItemData(index, data);
1509             }
1510         }
1511         return success;
1512     }
1513 
1514     bool clearItemData(const QModelIndex &index)
1515     {
1516         if (!index.isValid())
1517             return false;
1518 
1519         bool success = false;
1520         if constexpr (isMutable()) {
1521             auto emitDataChanged = qScopeGuard([&success, this, &index]{
1522                 if (success)
1523                     Q_EMIT this->dataChanged(index, index, {});
1524             });
1525 
1526             auto clearData = [column = index.column()](auto &&target) {
1527                 if constexpr (row_traits::hasMetaObject) {
1528                     if (row_traits::fixed_size() <= 1) {
1529                         // multi-role object/gadget: reset all properties
1530                         return resetProperty(-1, QRangeModelDetails::pointerTo(target));
1531                     } else if (column <= row_traits::fixed_size()) {
1532                         return resetProperty(column, QRangeModelDetails::pointerTo(target));
1533                     }
1534                 } else { // normal structs, values, associative containers
1535                     target = {};
1536                     return true;
1537                 }
1538                 return false;
1539             };
1540 
1541             success = writeAt(index, clearData);
1542         }
1543         return success;
1544     }
1545 
1546     QHash<int, QByteArray> roleNames() const
1547     {
1548         // will be 'void' if columns don't all have the same type
1549         using item_type = typename row_traits::item_type;
1550         if constexpr (QRangeModelDetails::has_metaobject_v<item_type>) {
1551             return QRangeModelImplBase::roleNamesForMetaObject(this->itemModel(),
1552                                         QRangeModelDetails::wrapped_t<item_type>::staticMetaObject);
1553         } else if constexpr (std::negation_v<std::disjunction<std::is_void<item_type>,
1554                                              QRangeModelDetails::is_multi_role<item_type>>>) {
1555             return QRangeModelImplBase::roleNamesForSimpleType();
1556         }
1557 
1558         return this->itemModel().QAbstractItemModel::roleNames();
1559     }
1560 
1561     bool insertColumns(int column, int count, const QModelIndex &parent)
1562     {
1563         if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
1564             if (count == 0)
1565                 return false;
1566             range_type * const children = childRange(parent);
1567             if (!children)
1568                 return false;
1569 
1570             this->beginInsertColumns(parent, column, column + count - 1);
1571             for (auto &child : *children) {
1572                 auto it = QRangeModelDetails::pos(child, column);
1573                 QRangeModelDetails::refTo(child).insert(it, count, {});
1574             }
1575             this->endInsertColumns();
1576             return true;
1577         }
1578         return false;
1579     }
1580 
1581     bool removeColumns(int column, int count, const QModelIndex &parent)
1582     {
1583         if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) {
1584             if (column < 0 || column + count > columnCount(parent))
1585                 return false;
1586 
1587             range_type * const children = childRange(parent);
1588             if (!children)
1589                 return false;
1590 
1591             this->beginRemoveColumns(parent, column, column + count - 1);
1592             for (auto &child : *children) {
1593                 const auto start = QRangeModelDetails::pos(child, column);
1594                 QRangeModelDetails::refTo(child).erase(start, std::next(start, count));
1595             }
1596             this->endRemoveColumns();
1597             return true;
1598         }
1599         return false;
1600     }
1601 
1602     bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
1603                      const QModelIndex &destParent, int destColumn)
1604     {
1605         // we only support moving columns within the same parent
1606         if (sourceParent != destParent)
1607             return false;
1608         if constexpr (isMutable() && row_features::has_rotate) {
1609             if (!Structure::canMoveColumns(sourceParent, destParent))
1610                 return false;
1611 
1612             if constexpr (dynamicColumns()) {
1613                 // we only support ranges as columns, as other types might
1614                 // not have the same data type across all columns
1615                 range_type * const children = childRange(sourceParent);
1616                 if (!children)
1617                     return false;
1618 
1619                 if (!this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
1620                                       destParent, destColumn)) {
1621                     return false;
1622                 }
1623 
1624                 for (auto &child : *children) {
1625                     const auto first = QRangeModelDetails::pos(child, sourceColumn);
1626                     const auto middle = std::next(first, count);
1627                     const auto last = QRangeModelDetails::pos(child, destColumn);
1628 
1629                     if (sourceColumn < destColumn) // moving right
1630                         std::rotate(first, middle, last);
1631                     else // moving left
1632                         std::rotate(last, first, middle);
1633                 }
1634 
1635                 this->endMoveColumns();
1636                 return true;
1637             }
1638         }
1639         return false;
1640     }
1641 
1642     bool insertRows(int row, int count, const QModelIndex &parent)
1643     {
1644         if constexpr (canInsertRows()) {
1645             range_type *children = childRange(parent);
1646             if (!children)
1647                 return false;
1648 
1649             EmptyRowGenerator generator{0, &that(), &parent};
1650 
1651             this->beginInsertRows(parent, row, row + count - 1);
1652 
1653             const auto pos = QRangeModelDetails::pos(children, row);
1654             if constexpr (range_features::has_insert_range) {
1655                 children->insert(pos, generator, EmptyRowGenerator{count});
1656             } else if constexpr (rows_are_owning_or_raw_pointers) {
1657                 auto start = children->insert(pos, count, row_type{});
1658                 std::copy(generator, EmptyRowGenerator{count}, start);
1659             } else {
1660                 children->insert(pos, count, *generator);
1661             }
1662 
1663             // fix the parent in all children of the modified row, as the
1664             // references back to the parent might have become invalid.
1665             that().resetParentInChildren(children);
1666 
1667             this->endInsertRows();
1668             return true;
1669         } else {
1670             return false;
1671         }
1672     }
1673 
1674     bool removeRows(int row, int count, const QModelIndex &parent = {})
1675     {
1676         if constexpr (canRemoveRows()) {
1677             const int prevRowCount = rowCount(parent);
1678             if (row < 0 || row + count > prevRowCount)
1679                 return false;
1680 
1681             range_type *children = childRange(parent);
1682             if (!children)
1683                 return false;
1684 
1685             this->beginRemoveRows(parent, row, row + count - 1);
1686             [[maybe_unused]] bool callEndRemoveColumns = false;
1687             if constexpr (dynamicColumns()) {
1688                 // if we remove the last row in a dynamic model, then we no longer
1689                 // know how many columns we should have, so they will be reported as 0.
1690                 if (prevRowCount == count) {
1691                     if (const int columns = columnCount(parent)) {
1692                         callEndRemoveColumns = true;
1693                         this->beginRemoveColumns(parent, 0, columns - 1);
1694                     }
1695                 }
1696             }
1697             { // erase invalidates iterators
1698                 const auto begin = QRangeModelDetails::pos(children, row);
1699                 const auto end = std::next(begin, count);
1700                 that().deleteRemovedRows(begin, end);
1701                 children->erase(begin, end);
1702             }
1703             // fix the parent in all children of the modified row, as the
1704             // references back to the parent might have become invalid.
1705             that().resetParentInChildren(children);
1706 
1707             if constexpr (dynamicColumns()) {
1708                 if (callEndRemoveColumns) {
1709                     Q_ASSERT(columnCount(parent) == 0);
1710                     this->endRemoveColumns();
1711                 }
1712             }
1713             this->endRemoveRows();
1714             return true;
1715         } else {
1716             return false;
1717         }
1718     }
1719 
1720     bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
1721                   const QModelIndex &destParent, int destRow)
1722     {
1723         if constexpr (isMutable() && range_features::has_rotate) {
1724             if (!Structure::canMoveRows(sourceParent, destParent))
1725                 return false;
1726 
1727             if (sourceParent != destParent) {
1728                 return that().moveRowsAcross(sourceParent, sourceRow, count,
1729                                              destParent, destRow);
1730             }
1731 
1732             if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0
1733              || sourceRow < 0 || sourceRow + count - 1 >= this->itemModel().rowCount(sourceParent)
1734              || destRow < 0 || destRow > this->itemModel().rowCount(destParent)) {
1735                 return false;
1736             }
1737 
1738             range_type *source = childRange(sourceParent);
1739             // moving within the same range
1740             if (!this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow))
1741                 return false;
1742 
1743             const auto first = QRangeModelDetails::pos(source, sourceRow);
1744             const auto middle = std::next(first, count);
1745             const auto last = QRangeModelDetails::pos(source, destRow);
1746 
1747             if (sourceRow < destRow) // moving down
1748                 std::rotate(first, middle, last);
1749             else // moving up
1750                 std::rotate(last, first, middle);
1751 
1752             that().resetParentInChildren(source);
1753 
1754             this->endMoveRows();
1755             return true;
1756         } else {
1757             return false;
1758         }
1759     }
1760 
1761     QModelIndex parent(const QModelIndex &child) const { return that().parent(child); }
1762 
1763     int rowCount(const QModelIndex &parent) const { return that().rowCount(parent); }
1764 
1765     int columnCount(const QModelIndex &parent) const { return that().columnCount(parent); }
1766 
1767     void destroy() { delete std::addressof(that()); }
1768 
1769     template <typename BaseMethod, typename BaseMethod::template Overridden<Self> overridden>
1770     using Override = typename Ancestor::template Override<BaseMethod, overridden>;
1771 
1772     using Destroy = Override<QRangeModelImplBase::Destroy, &Self::destroy>;
1773     using Index = Override<QRangeModelImplBase::Index, &Self::index>;
1774     using Parent = Override<QRangeModelImplBase::Parent, &Self::parent>;
1775     using Sibling = Override<QRangeModelImplBase::Sibling, &Self::sibling>;
1776     using RowCount = Override<QRangeModelImplBase::RowCount, &Self::rowCount>;
1777     using ColumnCount = Override<QRangeModelImplBase::ColumnCount, &Self::columnCount>;
1778     using Flags = Override<QRangeModelImplBase::Flags, &Self::flags>;
1779     using HeaderData = Override<QRangeModelImplBase::HeaderData, &Self::headerData>;
1780 
1781     using Data = Override<QRangeModelImplBase::Data, &Self::data>;
1782     using ItemData = Override<QRangeModelImplBase::ItemData, &Self::itemData>;
1783     using RoleNames = Override<QRangeModelImplBase::RoleNames, &Self::roleNames>;
1784     using InvalidateCaches = Override<QRangeModelImplBase::InvalidateCaches, &Self::invalidateCaches>;
1785     using SetHeaderData = Override<QRangeModelImplBase::SetHeaderData, &Self::setHeaderData>;
1786     using SetData = Override<QRangeModelImplBase::SetData, &Self::setData>;
1787     using SetItemData = Override<QRangeModelImplBase::SetItemData, &Self::setItemData>;
1788     using ClearItemData = Override<QRangeModelImplBase::ClearItemData, &Self::clearItemData>;
1789     using InsertColumns = Override<QRangeModelImplBase::InsertColumns, &Self::insertColumns>;
1790     using RemoveColumns = Override<QRangeModelImplBase::RemoveColumns, &Self::removeColumns>;
1791     using MoveColumns = Override<QRangeModelImplBase::MoveColumns, &Self::moveColumns>;
1792     using InsertRows = Override<QRangeModelImplBase::InsertRows, &Self::insertRows>;
1793     using RemoveRows = Override<QRangeModelImplBase::RemoveRows, &Self::removeRows>;
1794     using MoveRows = Override<QRangeModelImplBase::MoveRows, &Self::moveRows>;
1795 
1796 protected:
1797     ~QRangeModelImpl()
1798     {
1799         // We delete row objects if we are not operating on a reference or pointer
1800         // to a range, as in that case, the owner of the referenced/pointed to
1801         // range also owns the row entries.
1802         // ### Problem: if we get a copy of a range (no matter if shared or not),
1803         // then adding rows will create row objects in the model's copy, and the
1804         // client can never delete those. But copied rows will be the same pointer,
1805         // which we must not delete (as we didn't create them).
1806 
1807         static constexpr bool modelCopied = !QRangeModelDetails::is_wrapped<Range>() &&
1808                 (std::is_reference_v<Range> || std::is_const_v<std::remove_reference_t<Range>>);
1809 
1810         static constexpr bool modelShared = QRangeModelDetails::is_any_shared_ptr<Range>();
1811 
1812         static constexpr bool default_row_deleter = protocol_traits::is_default &&
1813                 protocol_traits::has_deleteRow;
1814 
1815         static constexpr bool ambiguousRowOwnership = (modelCopied || modelShared) &&
1816                 rows_are_raw_pointers && default_row_deleter;
1817 
1818         static_assert(!ambiguousRowOwnership,
1819                 "Using of copied and shared tree and table models with rows as raw pointers, "
1820                 "and the default protocol is not allowed due to ambiguity of rows ownership. "
1821                 "Move the model in, use another row type, or implement a custom tree protocol.");
1822 
1823         if constexpr (protocol_traits::has_deleteRow && !std::is_pointer_v<Range>
1824                    && !QRangeModelDetails::is_any_of<Range, std::reference_wrapper>()) {
1825             const auto begin = QRangeModelDetails::begin(*m_data.model());
1826             const auto end = QRangeModelDetails::end(*m_data.model());
1827             that().deleteRemovedRows(begin, end);
1828         }
1829     }
1830 
1831     static constexpr bool canInsertRows()
1832     {
1833         if constexpr (dynamicColumns() && !row_features::has_resize) {
1834             // If we operate on dynamic columns and cannot resize a newly
1835             // constructed row, then we cannot insert.
1836             return false;
1837         } else if constexpr (!protocol_traits::has_newRow) {
1838             // We also cannot insert if we cannot create a new row element
1839             return false;
1840         } else if constexpr (!range_features::has_insert_range
1841                           && !std::is_copy_constructible_v<row_type>) {
1842             // And if the row is a move-only type, then the range needs to be
1843             // backed by a container that can move-insert default-constructed
1844             // row elements.
1845             return false;
1846         } else {
1847             return Structure::canInsertRowsImpl();
1848         }
1849     }
1850 
1851     static constexpr bool canRemoveRows()
1852     {
1853         return Structure::canRemoveRowsImpl();
1854     }
1855 
1856     template <typename F>
1857     bool writeAt(const QModelIndex &index, F&& writer)
1858     {
1859         bool result = false;
1860         row_reference row = rowData(index);
1861 
1862         if constexpr (one_dimensional_range) {
1863             result = writer(row);
1864         } else if (QRangeModelDetails::isValid(row)) {
1865             if constexpr (dynamicColumns()) {
1866                 result = writer(*QRangeModelDetails::pos(row, index.column()));
1867             } else {
1868                 QRangeModelImplBase::for_element_at(row, index.column(), [&writer, &result](auto &&target) {
1869                     using target_type = decltype(target);
1870                     // we can only assign to an lvalue reference
1871                     if constexpr (std::is_lvalue_reference_v<target_type>
1872                               && !std::is_const_v<std::remove_reference_t<target_type>>) {
1873                         result = writer(std::forward<target_type>(target));
1874                     }
1875                 });
1876             }
1877         }
1878 
1879         return result;
1880     }
1881 
1882     template <typename F>
1883     void readAt(const QModelIndex &index, F&& reader) const {
1884         const_row_reference row = rowData(index);
1885         if constexpr (one_dimensional_range) {
1886             return reader(row);
1887         } else if (QRangeModelDetails::isValid(row)) {
1888             if constexpr (dynamicColumns())
1889                 reader(*QRangeModelDetails::pos(row, index.column()));
1890             else
1891                 QRangeModelImplBase::for_element_at(row, index.column(), std::forward<F>(reader));
1892         }
1893     }
1894 
1895     template <typename Value>
1896     static QVariant read(const Value &value)
1897     {
1898         if constexpr (std::is_constructible_v<QVariant, Value>)
1899             return QVariant(value);
1900         else
1901             return QVariant::fromValue(value);
1902     }
1903     template <typename Value>
1904     static QVariant read(Value *value)
1905     {
1906         if (value) {
1907             if constexpr (std::is_constructible_v<QVariant, Value *>)
1908                 return QVariant(value);
1909             else
1910                 return read(*value);
1911         }
1912         return {};
1913     }
1914 
1915     template <typename Target>
1916     static bool write(Target &target, const QVariant &value)
1917     {
1918         using Type = std::remove_reference_t<Target>;
1919         if constexpr (std::is_constructible_v<Target, QVariant>) {
1920             target = value;
1921             return true;
1922         } else if (value.canConvert<Type>()) {
1923             target = value.value<Type>();
1924             return true;
1925         }
1926         return false;
1927     }
1928     template <typename Target>
1929     static bool write(Target *target, const QVariant &value)
1930     {
1931         if (target)
1932             return write(*target, value);
1933         return false;
1934     }
1935 
1936     template <typename ItemType>
1937     QMetaProperty roleProperty(int role) const
1938     {
1939         struct {
1940             operator QMetaProperty() const {
1941                 const QByteArray roleName = that.itemModel().roleNames().value(role);
1942                 const QMetaObject &mo = ItemType::staticMetaObject;
1943                 if (const int index = mo.indexOfProperty(roleName.data());
1944                     index >= 0) {
1945                     return mo.property(index);
1946                 }
1947                 return {};
1948             }
1949             const QRangeModelImpl &that;
1950             const int role;
1951         } findProperty{*this, role};
1952 
1953         if constexpr (ModelData::cachesProperties)
1954             return *m_data.properties.tryEmplace(role, findProperty).iterator;
1955         else
1956             return findProperty;
1957     }
1958 
1959     template <typename ItemType>
1960     QVariant readRole(int role, ItemType *gadget) const
1961     {
1962         using item_type = std::remove_pointer_t<ItemType>;
1963         QVariant result;
1964         QMetaProperty prop = roleProperty<item_type>(role);
1965         if (!prop.isValid() && role == Qt::EditRole)
1966             prop = roleProperty<item_type>(Qt::DisplayRole);
1967 
1968         if (prop.isValid())
1969             result = readProperty(prop, gadget);
1970         return result;
1971     }
1972 
1973     template <typename ItemType>
1974     QVariant readRole(int role, const ItemType &gadget) const
1975     {
1976         return readRole(role, &gadget);
1977     }
1978 
1979     template <typename ItemType>
1980     static QVariant readProperty(const QMetaProperty &prop, ItemType *gadget)
1981     {
1982         if constexpr (std::is_base_of_v<QObject, ItemType>)
1983             return prop.read(gadget);
1984         else
1985             return prop.readOnGadget(gadget);
1986     }
1987     template <typename ItemType>
1988     static QVariant readProperty(int property, ItemType *gadget)
1989     {
1990         using item_type = std::remove_pointer_t<ItemType>;
1991         const QMetaObject &mo = item_type::staticMetaObject;
1992         const QMetaProperty prop = mo.property(property + mo.propertyOffset());
1993         return readProperty(prop, gadget);
1994     }
1995 
1996     template <typename ItemType>
1997     static QVariant readProperty(int property, const ItemType &gadget)
1998     {
1999         return readProperty(property, &gadget);
2000     }
2001 
2002     template <typename ItemType>
2003     bool writeRole(int role, ItemType *gadget, const QVariant &data)
2004     {
2005         using item_type = std::remove_pointer_t<ItemType>;
2006         auto prop = roleProperty<item_type>(role);
2007         if (!prop.isValid() && role == Qt::EditRole)
2008             prop = roleProperty<item_type>(Qt::DisplayRole);
2009 
2010         return prop.isValid() ? writeProperty(prop, gadget, data) : false;
2011     }
2012 
2013     template <typename ItemType>
2014     bool writeRole(int role, ItemType &&gadget, const QVariant &data)
2015     {
2016         return writeRole(role, &gadget, data);
2017     }
2018 
2019     template <typename ItemType>
2020     static bool writeProperty(const QMetaProperty &prop, ItemType *gadget, const QVariant &data)
2021     {
2022         if constexpr (std::is_base_of_v<QObject, ItemType>)
2023             return prop.write(gadget, data);
2024         else
2025             return prop.writeOnGadget(gadget, data);
2026     }
2027     template <typename ItemType>
2028     static bool writeProperty(int property, ItemType *gadget, const QVariant &data)
2029     {
2030         using item_type = std::remove_pointer_t<ItemType>;
2031         const QMetaObject &mo = item_type::staticMetaObject;
2032         return writeProperty(mo.property(property + mo.propertyOffset()), gadget, data);
2033     }
2034 
2035     template <typename ItemType>
2036     static bool writeProperty(int property, ItemType &&gadget, const QVariant &data)
2037     {
2038         return writeProperty(property, &gadget, data);
2039     }
2040 
2041     template <typename ItemType>
2042     static bool resetProperty(int property, ItemType *object)
2043     {
2044         using item_type = std::remove_pointer_t<ItemType>;
2045         const QMetaObject &mo = item_type::staticMetaObject;
2046         bool success = true;
2047         if (property == -1) {
2048             // reset all properties
2049             if constexpr (std::is_base_of_v<QObject, item_type>) {
2050                 for (int p = mo.propertyOffset(); p < mo.propertyCount(); ++p)
2051                     success = writeProperty(mo.property(p), object, {}) && success;
2052             } else { // reset a gadget by assigning a default-constructed
2053                 *object = {};
2054             }
2055         } else {
2056             success = writeProperty(mo.property(property + mo.propertyOffset()), object, {});
2057         }
2058         return success;
2059     }
2060 
2061     template <typename ItemType>
2062     static bool resetProperty(int property, ItemType &&object)
2063     {
2064         return resetProperty(property, &object);
2065     }
2066 
2067     // helpers
2068     const_row_reference rowData(const QModelIndex &index) const
2069     {
2070         Q_ASSERT(index.isValid());
2071         return that().rowDataImpl(index);
2072     }
2073 
2074     row_reference rowData(const QModelIndex &index)
2075     {
2076         Q_ASSERT(index.isValid());
2077         return that().rowDataImpl(index);
2078     }
2079 
2080     const range_type *childRange(const QModelIndex &index) const
2081     {
2082         if (!index.isValid())
2083             return m_data.model();
2084         if (index.column()) // only items at column 0 can have children
2085             return nullptr;
2086         return that().childRangeImpl(index);
2087     }
2088 
2089     range_type *childRange(const QModelIndex &index)
2090     {
2091         if (!index.isValid())
2092             return m_data.model();
2093         if (index.column()) // only items at column 0 can have children
2094             return nullptr;
2095         return that().childRangeImpl(index);
2096     }
2097 
2098 
2099     const protocol_type& protocol() const { return QRangeModelDetails::refTo(m_protocol); }
2100     protocol_type& protocol() { return QRangeModelDetails::refTo(m_protocol); }
2101 
2102     ModelData m_data;
2103     Protocol m_protocol;
2104 };
2105 
2106 // Implementations that depends on the model structure (flat vs tree) that will
2107 // be specialized based on a protocol type. The main template implements tree
2108 // support through a protocol type.
2109 template <typename Range, typename Protocol>
2110 class QGenericTreeItemModelImpl
2111     : public QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>
2112 {
2113     using Base = QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>;
2114     friend class QRangeModelImpl<QGenericTreeItemModelImpl<Range, Protocol>, Range, Protocol>;
2115 
2116     using range_type = typename Base::range_type;
2117     using range_features = typename Base::range_features;
2118     using row_type = typename Base::row_type;
2119     using row_ptr = typename Base::row_ptr;
2120     using const_row_ptr = typename Base::const_row_ptr;
2121 
2122     using tree_traits = typename Base::protocol_traits;
2123     static constexpr bool is_mutable_impl = tree_traits::has_mutable_childRows;
2124 
2125     static constexpr bool rows_are_any_refs_or_pointers = Base::rows_are_raw_pointers ||
2126                                  QRangeModelDetails::is_smart_ptr<row_type>() ||
2127                                  QRangeModelDetails::is_any_of<row_type, std::reference_wrapper>();
2128     static_assert(!Base::dynamicColumns(), "A tree must have a static number of columns!");
2129 
2130 public:
2131     QGenericTreeItemModelImpl(Range &&model, Protocol &&p, QRangeModel *itemModel)
2132         : Base(std::forward<Range>(model), std::forward<Protocol>(p), itemModel)
2133     {};
2134 
2135 protected:
2136     QModelIndex indexImpl(int row, int column, const QModelIndex &parent) const
2137     {
2138         if (!parent.isValid())
2139             return this->createIndex(row, column);
2140         // only items at column 0 can have children
2141         if (parent.column())
2142             return QModelIndex();
2143 
2144         const_row_ptr grandParent = static_cast<const_row_ptr>(parent.constInternalPointer());
2145         const auto &parentSiblings = childrenOf(grandParent);
2146         const auto it = QRangeModelDetails::pos(parentSiblings, parent.row());
2147         return this->createIndex(row, column, QRangeModelDetails::pointerTo(*it));
2148     }
2149 
2150     QModelIndex parent(const QModelIndex &child) const
2151     {
2152         if (!child.isValid())
2153             return {};
2154 
2155         // no pointer to parent row - no parent
2156         const_row_ptr parentRow = static_cast<const_row_ptr>(child.constInternalPointer());
2157         if (!parentRow)
2158             return {};
2159 
2160         // get the siblings of the parent via the grand parent
2161         auto &&grandParent = this->protocol().parentRow(QRangeModelDetails::refTo(parentRow));
2162         const range_type &parentSiblings = childrenOf(QRangeModelDetails::pointerTo(grandParent));
2163         // find the index of parentRow
2164         const auto begin = QRangeModelDetails::begin(parentSiblings);
2165         const auto end = QRangeModelDetails::end(parentSiblings);
2166         const auto it = std::find_if(begin, end, [parentRow](auto &&s){
2167             return QRangeModelDetails::pointerTo(std::forward<decltype(s)>(s)) == parentRow;
2168         });
2169         if (it != end)
2170             return this->createIndex(std::distance(begin, it), 0,
2171                                      QRangeModelDetails::pointerTo(grandParent));
2172         return {};
2173     }
2174 
2175     int rowCount(const QModelIndex &parent) const
2176     {
2177         return Base::size(this->childRange(parent));
2178     }
2179 
2180     int columnCount(const QModelIndex &) const
2181     {
2182         // all levels of a tree have to have the same, static, column count
2183         if constexpr (Base::one_dimensional_range)
2184             return 1;
2185         else
2186             return Base::static_column_count; // if static_column_count is -1, static assert fires
2187     }
2188 
2189     static constexpr Qt::ItemFlags defaultFlags()
2190     {
2191         return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
2192     }
2193 
2194     static constexpr bool canInsertRowsImpl()
2195     {
2196         // We must not insert rows if we cannot adjust the parents of the
2197         // children of the following rows. We don't have to do that if the
2198         // range operates on pointers.
2199         return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2200              && Base::dynamicRows() && range_features::has_insert;
2201     }
2202 
2203     static constexpr bool canRemoveRowsImpl()
2204     {
2205         // We must not remove rows if we cannot adjust the parents of the
2206         // children of the following rows. We don't have to do that if the
2207         // range operates on pointers.
2208         return (rows_are_any_refs_or_pointers || tree_traits::has_setParentRow)
2209              && Base::dynamicRows() && range_features::has_erase;
2210     }
2211 
2212     static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
2213     {
2214         return true;
2215     }
2216 
2217     static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
2218     {
2219         return true;
2220     }
2221 
2222     bool moveRowsAcross(const QModelIndex &sourceParent, int sourceRow, int count,
2223                         const QModelIndex &destParent, int destRow)
2224     {
2225         // If rows are pointers, then reference to the parent row don't
2226         // change, so we can move them around freely. Otherwise we need to
2227         // be able to explicitly update the parent pointer.
2228         if constexpr (!rows_are_any_refs_or_pointers && !tree_traits::has_setParentRow) {
2229             return false;
2230         } else if constexpr (!(range_features::has_insert && range_features::has_erase)) {
2231             return false;
2232         } else if (!this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1,
2233                                         destParent, destRow)) {
2234             return false;
2235         }
2236 
2237         range_type *source = this->childRange(sourceParent);
2238         range_type *destination = this->childRange(destParent);
2239 
2240         // If we can insert data from another range into, then
2241         // use that to move the old data over.
2242         const auto destStart = QRangeModelDetails::pos(destination, destRow);
2243         if constexpr (range_features::has_insert_range) {
2244             const auto sourceStart = QRangeModelDetails::pos(*source, sourceRow);
2245             const auto sourceEnd = std::next(sourceStart, count);
2246 
2247             destination->insert(destStart, std::move_iterator(sourceStart),
2248                                            std::move_iterator(sourceEnd));
2249         } else if constexpr (std::is_copy_constructible_v<row_type>) {
2250             // otherwise we have to make space first, and copy later.
2251             destination->insert(destStart, count, row_type{});
2252         }
2253 
2254         row_ptr parentRow = destParent.isValid()
2255                           ? QRangeModelDetails::pointerTo(this->rowData(destParent))
2256                           : nullptr;
2257 
2258         // if the source's parent was already inside the new parent row,
2259         // then the source row might have become invalid, so reset it.
2260         if (parentRow == static_cast<row_ptr>(sourceParent.internalPointer())) {
2261             if (sourceParent.row() < destRow) {
2262                 source = this->childRange(sourceParent);
2263             } else {
2264                 // the source parent moved down within destination
2265                 source = this->childRange(this->createIndex(sourceParent.row() + count, 0,
2266                                                             sourceParent.internalPointer()));
2267             }
2268         }
2269 
2270         // move the data over and update the parent pointer
2271         {
2272             const auto writeStart = QRangeModelDetails::pos(destination, destRow);
2273             const auto writeEnd = std::next(writeStart, count);
2274             const auto sourceStart = QRangeModelDetails::pos(source, sourceRow);
2275             const auto sourceEnd = std::next(sourceStart, count);
2276 
2277             for (auto write = writeStart, read = sourceStart; write != writeEnd; ++write, ++read) {
2278                 // move data over if not already done, otherwise
2279                 // only fix the parent pointer
2280                 if constexpr (!range_features::has_insert_range)
2281                     *write = std::move(*read);
2282                 this->protocol().setParentRow(QRangeModelDetails::refTo(*write), parentRow);
2283             }
2284             // remove the old rows from the source parent
2285             source->erase(sourceStart, sourceEnd);
2286         }
2287 
2288         // Fix the parent pointers in children of both source and destination
2289         // ranges, as the references to the entries might have become invalid.
2290         // We don't have to do that if the rows are pointers, as in that case
2291         // the references to the entries are stable.
2292         resetParentInChildren(destination);
2293         resetParentInChildren(source);
2294 
2295         this->endMoveRows();
2296         return true;
2297     }
2298 
2299     auto makeEmptyRow(const QModelIndex &parent)
2300     {
2301         // tree traversal protocol: if we are here, then it must be possible
2302         // to change the parent of a row.
2303         static_assert(tree_traits::has_setParentRow);
2304         row_type empty_row = this->protocol().newRow();
2305         if (QRangeModelDetails::isValid(empty_row) && parent.isValid()) {
2306             this->protocol().setParentRow(QRangeModelDetails::refTo(empty_row),
2307                                         QRangeModelDetails::pointerTo(this->rowData(parent)));
2308         }
2309         return empty_row;
2310     }
2311 
2312     template <typename It, typename Sentinel>
2313     void deleteRemovedRows(It &&begin, Sentinel &&end)
2314     {
2315         if constexpr (tree_traits::has_deleteRow) {
2316             for (auto it = begin; it != end; ++it) {
2317                 if constexpr (Base::isMutable()) {
2318                     decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(*it));
2319                     if (QRangeModelDetails::isValid(children)) {
2320                         deleteRemovedRows(QRangeModelDetails::begin(children),
2321                                           QRangeModelDetails::end(children));
2322                         QRangeModelDetails::refTo(children) = range_type{ };
2323                     }
2324                 }
2325 
2326                 this->protocol().deleteRow(std::move(*it));
2327             }
2328         }
2329     }
2330 
2331     void resetParentInChildren(range_type *children)
2332     {
2333         if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) {
2334             const auto begin = QRangeModelDetails::begin(*children);
2335             const auto end = QRangeModelDetails::end(*children);
2336             for (auto it = begin; it != end; ++it) {
2337                 decltype(auto) maybeChildren = this->protocol().childRows(*it);
2338                 if (QRangeModelDetails::isValid(maybeChildren)) {
2339                     auto &childrenRef = QRangeModelDetails::refTo(maybeChildren);
2340                     QModelIndexList fromIndexes;
2341                     QModelIndexList toIndexes;
2342                     fromIndexes.reserve(Base::size(childrenRef));
2343                     toIndexes.reserve(Base::size(childrenRef));
2344                     auto *parentRow = QRangeModelDetails::pointerTo(*it);
2345 
2346                     int row = 0;
2347                     for (auto &child : childrenRef) {
2348                         const_row_ptr oldParent = this->protocol().parentRow(child);
2349                         if (oldParent != parentRow) {
2350                             fromIndexes.append(this->createIndex(row, 0, oldParent));
2351                             toIndexes.append(this->createIndex(row, 0, parentRow));
2352                             this->protocol().setParentRow(child, parentRow);
2353                         }
2354                         ++row;
2355                     }
2356                     this->changePersistentIndexList(fromIndexes, toIndexes);
2357                     resetParentInChildren(&childrenRef);
2358                 }
2359             }
2360         }
2361     }
2362 
2363     decltype(auto) rowDataImpl(const QModelIndex &index) const
2364     {
2365         const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer());
2366         const range_type &siblings = childrenOf(parentRow);
2367         Q_ASSERT(index.row() < int(Base::size(siblings)));
2368         return *QRangeModelDetails::pos(siblings, index.row());
2369     }
2370 
2371     decltype(auto) rowDataImpl(const QModelIndex &index)
2372     {
2373         row_ptr parentRow = static_cast<row_ptr>(index.internalPointer());
2374         range_type &siblings = childrenOf(parentRow);
2375         Q_ASSERT(index.row() < int(Base::size(siblings)));
2376         return *QRangeModelDetails::pos(siblings, index.row());
2377     }
2378 
2379     const range_type *childRangeImpl(const QModelIndex &index) const
2380     {
2381         const auto &row = this->rowData(index);
2382         if (!QRangeModelDetails::isValid(row))
2383             return static_cast<const range_type *>(nullptr);
2384 
2385         decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(row));
2386         return QRangeModelDetails::pointerTo(std::forward<decltype(children)>(children));
2387     }
2388 
2389     range_type *childRangeImpl(const QModelIndex &index)
2390     {
2391         auto &row = this->rowData(index);
2392         if (!QRangeModelDetails::isValid(row))
2393             return static_cast<range_type *>(nullptr);
2394 
2395         decltype(auto) children = this->protocol().childRows(QRangeModelDetails::refTo(row));
2396         using Children = std::remove_reference_t<decltype(children)>;
2397 
2398         if constexpr (QRangeModelDetails::is_any_of<Children, std::optional>())
2399             if constexpr (std::is_default_constructible<typename Children::value_type>()) {
2400                 if (!children)
2401                     children.emplace(range_type{});
2402             }
2403 
2404         return QRangeModelDetails::pointerTo(std::forward<decltype(children)>(children));
2405     }
2406 
2407     const range_type &childrenOf(const_row_ptr row) const
2408     {
2409         return row ? QRangeModelDetails::refTo(this->protocol().childRows(*row))
2410                    : *this->m_data.model();
2411     }
2412 
2413 private:
2414     range_type &childrenOf(row_ptr row)
2415     {
2416         return row ? QRangeModelDetails::refTo(this->protocol().childRows(*row))
2417                    : *this->m_data.model();
2418     }
2419 };
2420 
2421 // specialization for flat models without protocol
2422 template <typename Range>
2423 class QGenericTableItemModelImpl
2424     : public QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>
2425 {
2426     using Base = QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>;
2427     friend class QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>;
2428 
2429     using range_type = typename Base::range_type;
2430     using range_features = typename Base::range_features;
2431     using row_type = typename Base::row_type;
2432     using const_row_ptr = typename Base::const_row_ptr;
2433     using row_traits = typename Base::row_traits;
2434     using row_features = typename Base::row_features;
2435 
2436     static constexpr bool is_mutable_impl = true;
2437 
2438 public:
2439     explicit QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel)
2440         : Base(std::forward<Range>(model), {}, itemModel)
2441     {}
2442 
2443 protected:
2444     QModelIndex indexImpl(int row, int column, const QModelIndex &) const
2445     {
2446         if constexpr (Base::dynamicColumns()) {
2447             if (column < int(Base::size(*QRangeModelDetails::pos(*this->m_data.model(), row))))
2448                 return this->createIndex(row, column);
2449 #ifndef QT_NO_DEBUG
2450             // if we got here, then column < columnCount(), but this row is too short
2451             qCritical("QRangeModel: Column-range at row %d is not large enough!", row);
2452 #endif
2453             return {};
2454         } else {
2455             return this->createIndex(row, column);
2456         }
2457     }
2458 
2459     QModelIndex parent(const QModelIndex &) const
2460     {
2461         return {};
2462     }
2463 
2464     int rowCount(const QModelIndex &parent) const
2465     {
2466         if (parent.isValid())
2467             return 0;
2468         return int(Base::size(*this->m_data.model()));
2469     }
2470 
2471     int columnCount(const QModelIndex &parent) const
2472     {
2473         if (parent.isValid())
2474             return 0;
2475 
2476         // in a table, all rows have the same number of columns (as the first row)
2477         if constexpr (Base::dynamicColumns()) {
2478             return int(Base::size(*this->m_data.model()) == 0
2479                        ? 0
2480                        : Base::size(*QRangeModelDetails::begin(*this->m_data.model())));
2481         } else if constexpr (Base::one_dimensional_range) {
2482             return row_traits::fixed_size();
2483         } else {
2484             return Base::static_column_count;
2485         }
2486     }
2487 
2488     static constexpr Qt::ItemFlags defaultFlags()
2489     {
2490         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren;
2491     }
2492 
2493     static constexpr bool canInsertRowsImpl()
2494     {
2495         return Base::dynamicRows() && range_features::has_insert;
2496     }
2497 
2498     static constexpr bool canRemoveRowsImpl()
2499     {
2500         return Base::dynamicRows() && range_features::has_erase;
2501     }
2502 
2503     static constexpr bool canMoveColumns(const QModelIndex &source, const QModelIndex &destination)
2504     {
2505         return !source.isValid() && !destination.isValid();
2506     }
2507 
2508     static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
2509     {
2510         return !source.isValid() && !destination.isValid();
2511     }
2512 
2513     constexpr bool moveRowsAcross(const QModelIndex &, int , int,
2514                                   const QModelIndex &, int) noexcept
2515     {
2516         // table/flat model: can't move rows between different parents
2517         return false;
2518     }
2519 
2520     auto makeEmptyRow(const QModelIndex &)
2521     {
2522         row_type empty_row = this->protocol().newRow();
2523 
2524         // dynamically sized rows all have to have the same column count
2525         if constexpr (Base::dynamicColumns() && row_features::has_resize) {
2526             if (QRangeModelDetails::isValid(empty_row))
2527                 QRangeModelDetails::refTo(empty_row).resize(this->itemModel().columnCount());
2528         }
2529 
2530         return empty_row;
2531     }
2532 
2533     template <typename It, typename Sentinel>
2534     void deleteRemovedRows(It &&begin, Sentinel &&end)
2535     {
2536         if constexpr (Base::protocol_traits::has_deleteRow) {
2537             for (auto it = begin; it != end; ++it)
2538                 this->protocol().deleteRow(std::move(*it));
2539         }
2540     }
2541 
2542     decltype(auto) rowDataImpl(const QModelIndex &index) const
2543     {
2544         Q_ASSERT(q20::cmp_less(index.row(), Base::size(*this->m_data.model())));
2545         return *QRangeModelDetails::pos(*this->m_data.model(), index.row());
2546     }
2547 
2548     decltype(auto) rowDataImpl(const QModelIndex &index)
2549     {
2550         Q_ASSERT(q20::cmp_less(index.row(), Base::size(*this->m_data.model())));
2551         return *QRangeModelDetails::pos(*this->m_data.model(), index.row());
2552     }
2553 
2554     const range_type *childRangeImpl(const QModelIndex &) const
2555     {
2556         return nullptr;
2557     }
2558 
2559     range_type *childRangeImpl(const QModelIndex &)
2560     {
2561         return nullptr;
2562     }
2563 
2564     const range_type &childrenOf(const_row_ptr row) const
2565     {
2566         Q_ASSERT(!row);
2567         return *this->m_data.model();
2568     }
2569 
2570     void resetParentInChildren(range_type *)
2571     {
2572     }
2573 };
2574 
2575 QT_END_NAMESPACE
2576 
2577 #endif // Q_QDOC
2578 
2579 #endif // QRANGEMODEL_IMPL_H