Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-02 09:27:24

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 QRANGEMODELADAPTER_IMPL_H
0006 #define QRANGEMODELADAPTER_IMPL_H
0007 
0008 #ifndef Q_QDOC
0009 
0010 #ifndef QRANGEMODELADAPTER_H
0011 #error Do not include qrangemodeladapter_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/qrangemodel.h>
0020 #include <QtCore/qspan.h>
0021 #include <set>
0022 #include <memory>
0023 
0024 QT_BEGIN_NAMESPACE
0025 
0026 namespace QRangeModelDetails
0027 {
0028 template <typename Range, typename Protocol>
0029 using RangeImplementation = std::conditional_t<std::is_void_v<Protocol>,
0030                                 std::conditional_t<is_tree_range<Range>::value,
0031                                     QGenericTreeItemModelImpl<Range, DefaultTreeProtocol<Range>>,
0032                                     QGenericTableItemModelImpl<Range>
0033                                 >,
0034                                 QGenericTreeItemModelImpl<Range, Protocol>
0035                             >;
0036 
0037 template <typename ...Args>
0038 using construct_rangeModel_test = decltype(QRangeModel(std::declval<Args &&>()...));
0039 
0040 template <typename ...Args>
0041 static constexpr bool can_construct_rangeModel = qxp::is_detected_v<construct_rangeModel_test,
0042                                                                     Args...>;
0043 
0044 template <typename ...Args>
0045 using if_can_construct = std::enable_if_t<can_construct_rangeModel<Args...>, bool>;
0046 
0047 template <typename Output, typename Input>
0048 decltype(auto) forwardOrConvert(Input&& input)
0049 {
0050     if constexpr (std::is_same_v<q20::remove_cvref<Output>, q20::remove_cvref<Input>>)
0051         return std::forward<Input>(input);
0052     else
0053         return Output(std::forward<Input>(input));
0054 }
0055 
0056 // we can't use wrapped_t, we only want to unpack smart pointers, and maintain
0057 // the pointer nature of the type.
0058 template <typename T, typename = void>
0059 struct data_type { using type = T; };
0060 template <>
0061 struct data_type<void> { using type = QVariant; };
0062 
0063 // pointer types of iterators use QtPrivate::ArrowProxy if the type does not
0064 // provide operator->() (or is a pointer).
0065 template <typename T, typename = void> struct test_pointerAccess : std::false_type {};
0066 template <typename T> struct test_pointerAccess<T *> : std::true_type {};
0067 template <typename T>
0068 struct test_pointerAccess<T, std::void_t<decltype(std::declval<T>().operator->())>>
0069     : std::true_type
0070 {};
0071 
0072 template <typename T>
0073 using data_pointer_t = std::conditional_t<test_pointerAccess<T>::value,
0074                                           T, QtPrivate::ArrowProxy<T>>;
0075 
0076 // Helpers to make a type const "in depth", taking into account raw pointers
0077 // and wrapping types, like smart pointers and std::reference_wrapper.
0078 
0079 // We need to return data by value, not by reference, as we might only have
0080 // temporary values (i.e. a QVariant returned by QAIM::data).
0081 template <typename T, typename = void> struct AsConstData { using type = T; };
0082 template <typename T> struct AsConstData<const T &> { using type = T; };
0083 template <typename T> struct AsConstData<T *> { using type = const T *; };
0084 template <template <typename> typename U, typename T>
0085 struct AsConstData<U<T>, std::enable_if_t<is_any_shared_ptr<U<T>>::value>>
0086 { using type = U<const T>; };
0087 template <typename T> struct AsConstData<std::reference_wrapper<T>>
0088 { using type = std::reference_wrapper<const T>; };
0089 
0090 template <typename T> using asConst_t = typename AsConstData<T>::type;
0091 
0092 // Rows get wrapped into a "view", as a begin/end iterator/sentinel pair.
0093 // The iterator dereferences to the const version of the value returned by
0094 // the underlying iterator.
0095 // Could be replaced with std::views::sub_range in C++ 20.
0096 template <typename const_row_type, typename Iterator, typename Sentinel>
0097 struct RowView
0098 {
0099     // this is similar to C++23's std::basic_const_iterator, but we don't want
0100     // to convert to the underlying const_iterator.
0101     struct iterator
0102     {
0103         using value_type = asConst_t<typename Iterator::value_type>;
0104         using difference_type = typename Iterator::difference_type;
0105         using pointer = QRangeModelDetails::data_pointer_t<value_type>;
0106         using reference = value_type;
0107         using const_reference = value_type;
0108         using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
0109 
0110         template <typename I, typename Category>
0111         static constexpr bool is_atLeast = std::is_base_of_v<Category,
0112                                                typename std::iterator_traits<I>::iterator_category>;
0113         template <typename I, typename Category>
0114         using if_atLeast = std::enable_if_t<is_atLeast<I, Category>, bool>;
0115 
0116         reference operator*() const { return *m_it; }
0117         pointer operator->() const { return operator*(); }
0118 
0119         // QRM requires at least forward_iterator, so we provide both post- and
0120         // prefix increment unconditionally
0121         friend constexpr iterator &operator++(iterator &it)
0122             noexcept(noexcept(++std::declval<Iterator&>()))
0123         {
0124             ++it.m_it;
0125             return it;
0126         }
0127         friend constexpr iterator operator++(iterator &it, int)
0128             noexcept(noexcept(std::declval<Iterator&>()++))
0129         {
0130             iterator copy = it;
0131             ++copy.m_it;
0132             return copy;
0133         }
0134 
0135         template <typename I = Iterator, if_atLeast<I, std::bidirectional_iterator_tag> = true>
0136         friend constexpr iterator &operator--(iterator &it)
0137             noexcept(noexcept(--std::declval<I&>()))
0138         {
0139             --it.m_it;
0140             return it;
0141         }
0142         template <typename I = Iterator, if_atLeast<I, std::bidirectional_iterator_tag> = true>
0143         friend constexpr iterator operator--(iterator &it, int)
0144             noexcept(noexcept(std::declval<I&>()--))
0145         {
0146             iterator copy = it;
0147             --it.m_it;
0148             return copy;
0149         }
0150 
0151         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0152         friend constexpr iterator &operator+=(iterator &it, difference_type n)
0153             noexcept(noexcept(std::declval<I&>() += 1))
0154         {
0155             it.m_it += n;
0156             return it;
0157         }
0158         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0159         friend constexpr iterator &operator-=(iterator &it, difference_type n)
0160             noexcept(noexcept(std::declval<I&>() -= 1))
0161         {
0162             it.m_it -= n;
0163             return it;
0164         }
0165 
0166         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0167         friend constexpr iterator operator+(const iterator &it, difference_type n)
0168             noexcept(noexcept(std::declval<I&>() + 1))
0169         {
0170             iterator copy = it;
0171             copy.m_it += n;
0172             return copy;
0173         }
0174         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0175         friend constexpr iterator operator+(difference_type n, const iterator &it)
0176             noexcept(noexcept(1 + std::declval<I&>()))
0177         {
0178             return it + n;
0179         }
0180         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0181         friend constexpr iterator operator-(const iterator &it, difference_type n)
0182             noexcept(noexcept(std::declval<I&>() - 1))
0183         {
0184             iterator copy = it;
0185             copy.m_it = it.m_it - n;
0186             return copy;
0187         }
0188 
0189         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0190         constexpr reference operator[](difference_type n) const
0191             noexcept(noexcept(I::operator[]()))
0192         {
0193             return m_it[n];
0194         }
0195 
0196         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0197         friend constexpr difference_type operator-(const iterator &lhs, const iterator &rhs)
0198             noexcept(noexcept(std::declval<I&>() - std::declval<I&>()))
0199         {
0200             return lhs.m_it - rhs.m_it;
0201         }
0202 
0203         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0204         friend constexpr bool operator<(const iterator &lhs, const iterator &rhs)
0205             noexcept(noexcept(std::declval<I&>() < std::declval<I&>()))
0206         {
0207             return lhs.m_it < rhs.m_it;
0208         }
0209         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0210         friend constexpr bool operator<=(const iterator &lhs, const iterator &rhs)
0211             noexcept(noexcept(std::declval<I&>() <= std::declval<I&>()))
0212         {
0213             return lhs.m_it <= rhs.m_it;
0214         }
0215 
0216         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0217         friend constexpr bool operator>(const iterator &lhs, const iterator &rhs)
0218             noexcept(noexcept(std::declval<I&>() > std::declval<I&>()))
0219         {
0220             return lhs.m_it > rhs.m_it;
0221         }
0222         template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
0223         friend constexpr bool operator>=(const iterator &lhs, const iterator &rhs)
0224             noexcept(noexcept(std::declval<I&>() >= std::declval<I&>()))
0225         {
0226             return lhs.m_it >= rhs.m_it;
0227         }
0228 
0229         // This would implement the P2836R1 fix from std::basic_const_iterator,
0230         // but a const_iterator on a range<pointer> would again allow us to
0231         // mutate the pointed-to object, which is exactly what we want to
0232         // prevent.
0233         /*
0234         template <typename CI, std::enable_if_t<std::is_convertible_v<const Iterator &, CI>, bool> = true>
0235         operator CI() const
0236         {
0237             return CI{m_it};
0238         }
0239 
0240         template <typename CI, std::enable_if_t<std::is_convertible_v<Iterator, CI>, bool> = true>
0241         operator CI() &&
0242         {
0243             return CI{std::move(m_it)};
0244         }
0245         */
0246 
0247         friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
0248         {
0249             return lhs.m_it == rhs.m_it;
0250         }
0251         Q_DECLARE_EQUALITY_COMPARABLE(iterator)
0252 
0253         Iterator m_it;
0254     };
0255 
0256     using value_type = typename iterator::value_type;
0257     using difference_type = typename iterator::difference_type;
0258 
0259     friend bool comparesEqual(const RowView &lhs, const RowView &rhs) noexcept
0260     {
0261         return lhs.m_begin == rhs.m_begin;
0262     }
0263     Q_DECLARE_EQUALITY_COMPARABLE(RowView)
0264 
0265     template <typename RHS>
0266     bool operator==(const RHS &rhs) const noexcept
0267     {
0268         return m_begin == QRangeModelDetails::begin(rhs);
0269     }
0270     template <typename RHS>
0271     bool operator!=(const RHS &rhs) const noexcept
0272     {
0273         return !operator==(rhs);
0274     }
0275 
0276     value_type at(difference_type n) const { return *std::next(m_begin, n); }
0277 
0278     iterator begin() const { return iterator{m_begin}; }
0279     iterator end() const { return iterator{m_end}; }
0280 
0281     Iterator m_begin;
0282     Sentinel m_end;
0283 };
0284 
0285 // Const-in-depth mapping for row types. We do store row types, and they might
0286 // be move-only, so we return them by const reference.
0287 template <typename T, typename = void> struct AsConstRow { using type = const T &; };
0288 // Otherwise the mapping for basic row types is the same as for data.
0289 template <typename T> struct AsConstRow<T *> : AsConstData<T *> {};
0290 template <template <typename> typename U, typename T>
0291 struct AsConstRow<U<T>, std::enable_if_t<is_any_shared_ptr<U<T>>::value>> : AsConstData<U<T>> {};
0292 template <typename T> struct AsConstRow<std::reference_wrapper<T>>
0293     : AsConstData<std::reference_wrapper<T>> {};
0294 
0295 template <typename T> using if_range = std::enable_if_t<is_range_v<T>, bool>;
0296 // If the row type is a range, then we assume that the first type is the
0297 // element type.
0298 template <template <typename, typename ...> typename R, typename T, typename ...Args>
0299 struct AsConstRow<R<T, Args...>, if_range<R<T, Args...>>>
0300 {
0301     using type = const R<T, Args...> &;
0302 };
0303 
0304 // specialize for range of pointers and smart pointers
0305 template <template <typename, typename ...> typename R, typename T, typename ...Args>
0306 struct AsConstRow<R<T *, Args...>, if_range<R<T *, Args...>>>
0307 {
0308     using row_type = R<T, Args...>;
0309     using const_iterator = typename row_type::const_iterator;
0310     using const_row_type = R<asConst_t<T>>;
0311     using type = RowView<const_row_type, const_iterator, const_iterator>;
0312 };
0313 
0314 template <template <typename, typename ...> typename R, typename T, typename ...Args>
0315 struct AsConstRow<R<T, Args...>,
0316     std::enable_if_t<std::conjunction_v<is_range<R<T, Args...>>, is_any_shared_ptr<T>>>
0317 >
0318 {
0319     using row_type = R<T, Args...>;
0320     using const_iterator = typename row_type::const_iterator;
0321     using const_row_type = R<asConst_t<T>>;
0322     using type = RowView<const_row_type, const_iterator, const_iterator>;
0323 };
0324 
0325 template <typename T>
0326 using asConstRow_t = typename AsConstRow<T>::type;
0327 
0328 Q_CORE_EXPORT QVariant qVariantAtIndex(const QModelIndex &index);
0329 
0330 template <typename Type>
0331 static inline Type dataAtIndex(const QModelIndex &index)
0332 {
0333     Q_ASSERT_X(index.isValid(), "QRangeModelAdapter::dataAtIndex", "Index at position is invalid");
0334     QVariant variant = qVariantAtIndex(index);
0335 
0336     if constexpr (std::is_same_v<QVariant, Type>)
0337         return variant;
0338     else
0339         return variant.value<Type>();
0340 }
0341 
0342 template <typename Type>
0343 static inline Type dataAtIndex(const QModelIndex &index, int role)
0344 {
0345     Q_ASSERT_X(index.isValid(), "QRangeModelAdapter::dataAtIndex", "Index at position is invalid");
0346     QVariant variant = index.data(role);
0347 
0348     if constexpr (std::is_same_v<QVariant, Type>)
0349         return variant;
0350     else
0351         return variant.value<Type>();
0352 }
0353 
0354 template <bool isTree = false>
0355 struct ParentIndex
0356 {
0357     ParentIndex(const QModelIndex &dummy = {}) { Q_ASSERT(!dummy.isValid()); }
0358     QModelIndex root() const { return {}; }
0359 };
0360 
0361 template <>
0362 struct ParentIndex<true>
0363 {
0364     QModelIndex m_rootIndex;
0365     QModelIndex root() const { return m_rootIndex; }
0366 };
0367 
0368 template <typename Model, typename Impl>
0369 struct AdapterStorage : ParentIndex<Impl::protocol_traits::is_tree>
0370 {
0371     // If it is, then we can shortcut the model and operate on the container.
0372     // Otherwise we have to go through the model's vtable. For now, this is always
0373     // the case.
0374     static constexpr bool isRangeModel = std::is_same_v<Model, QRangeModel>;
0375     static_assert(isRangeModel, "The model must be a QRangeModel (not a subclass).");
0376     std::shared_ptr<QRangeModel> m_model;
0377 
0378     template <typename I = Impl, std::enable_if_t<I::protocol_traits::is_tree, bool> = true>
0379     explicit AdapterStorage(const std::shared_ptr<QRangeModel> &model, const QModelIndex &root)
0380         : ParentIndex<Impl::protocol_traits::is_tree>{root}, m_model(model)
0381     {
0382     }
0383 
0384     explicit AdapterStorage(Model *model)
0385         : m_model{model}
0386     {}
0387 
0388     const Impl *implementation() const
0389     {
0390         return static_cast<const Impl *>(QRangeModelImplBase::getImplementation(m_model.get()));
0391     }
0392 
0393     Impl *implementation()
0394     {
0395         return static_cast<Impl *>(QRangeModelImplBase::getImplementation(m_model.get()));
0396     }
0397 
0398     auto *operator->()
0399     {
0400         if constexpr (isRangeModel)
0401             return implementation();
0402         else
0403             return m_model.get();
0404     }
0405 
0406     const auto *operator->() const
0407     {
0408         if constexpr (isRangeModel)
0409             return implementation();
0410         else
0411             return m_model.get();
0412     }
0413 };
0414 
0415 } // QRangeModelDetails
0416 
0417 QT_END_NAMESPACE
0418 
0419 #endif // Q_QDOC
0420 
0421 #endif // QRANGEMODELADAPTER_IMPL_H