Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qrangemodeladapter_impl.h
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QRANGEMODELADAPTER_IMPL_H
6#define QRANGEMODELADAPTER_IMPL_H
7
8#ifndef Q_QDOC
9
10#ifndef QRANGEMODELADAPTER_H
11#error Do not include qrangemodeladapter_impl.h directly
12#endif
13
14#if 0
15#pragma qt_sync_skip_header_check
16#pragma qt_sync_stop_processing
17#endif
18
19#include <QtCore/qrangemodel.h>
20#include <QtCore/qspan.h>
21#include <set>
22#include <memory>
23
24QT_BEGIN_NAMESPACE
25
26namespace QRangeModelDetails
27{
28template <typename Range, typename Protocol>
33 >,
35 >;
36
37template <typename ...Args>
38using construct_rangeModel_test = decltype(QRangeModel(std::declval<Args &&>()...));
39
40template <typename ...Args>
42 Args...>;
43
44template <typename ...Args>
46
47template <typename Output, typename Input>
48decltype(auto) forwardOrConvert(Input&& input)
49{
50 if constexpr (std::is_same_v<q20::remove_cvref<Output>, q20::remove_cvref<Input>>)
51 return std::forward<Input>(input);
52 else
53 return Output(std::forward<Input>(input));
54}
55
56// we can't use wrapped_t, we only want to unpack smart pointers, and maintain
57// the pointer nature of the type.
58template <typename T, typename = void>
59struct data_type { using type = T; };
60template <>
61struct data_type<void> { using type = QVariant; };
62
63// pointer types of iterators use QtPrivate::ArrowProxy if the type does not
64// provide operator->() (or is a pointer).
65template <typename T, typename = void> struct test_pointerAccess : std::false_type {};
66template <typename T> struct test_pointerAccess<T *> : std::true_type {};
67template <typename T>
68struct test_pointerAccess<T, std::void_t<decltype(std::declval<T>().operator->())>>
69 : std::true_type
70{};
71
72template <typename T>
75
76// Helpers to make a type const "in depth", taking into account raw pointers
77// and wrapping types, like smart pointers and std::reference_wrapper.
78
79// We need to return data by value, not by reference, as we might only have
80// temporary values (i.e. a QVariant returned by QAIM::data).
81template <typename T, typename = void> struct AsConstData { using type = T; };
82template <typename T> struct AsConstData<const T &> { using type = T; };
83template <typename T> struct AsConstData<T *> { using type = const T *; };
84template <template <typename> typename U, typename T>
86{ using type = U<const T>; };
87template <typename T> struct AsConstData<std::reference_wrapper<T>>
88{ using type = std::reference_wrapper<const T>; };
89
90template <typename T> using asConst_t = typename AsConstData<T>::type;
91
92// Rows get wrapped into a "view", as a begin/end iterator/sentinel pair.
93// The iterator dereferences to the const version of the value returned by
94// the underlying iterator.
95// Could be replaced with std::views::sub_range in C++ 20.
96template <typename const_row_type, typename Iterator, typename Sentinel>
97struct RowView
98{
99 // this is similar to C++23's std::basic_const_iterator, but we don't want
100 // to convert to the underlying const_iterator.
101 struct iterator
102 {
104 using difference_type = typename Iterator::difference_type;
108 using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
109
110 template <typename I, typename Category>
111 static constexpr bool is_atLeast = std::is_base_of_v<Category,
113 template <typename I, typename Category>
115
116 reference operator*() const { return *m_it; }
117 pointer operator->() const { return operator*(); }
118
119 // QRM requires at least forward_iterator, so we provide both post- and
120 // prefix increment unconditionally
121 friend constexpr iterator &operator++(iterator &it)
122 noexcept(noexcept(++std::declval<Iterator&>()))
123 {
124 ++it.m_it;
125 return it;
126 }
127 friend constexpr iterator operator++(iterator &it, int)
128 noexcept(noexcept(std::declval<Iterator&>()++))
129 {
130 iterator copy = it;
131 ++copy.m_it;
132 return copy;
133 }
134
135 template <typename I = Iterator, if_atLeast<I, std::bidirectional_iterator_tag> = true>
136 friend constexpr iterator &operator--(iterator &it)
137 noexcept(noexcept(--std::declval<I&>()))
138 {
139 --it.m_it;
140 return it;
141 }
142 template <typename I = Iterator, if_atLeast<I, std::bidirectional_iterator_tag> = true>
143 friend constexpr iterator operator--(iterator &it, int)
144 noexcept(noexcept(std::declval<I&>()--))
145 {
146 iterator copy = it;
147 --it.m_it;
148 return copy;
149 }
150
151 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
152 friend constexpr iterator &operator+=(iterator &it, difference_type n)
153 noexcept(noexcept(std::declval<I&>() += 1))
154 {
155 it.m_it += n;
156 return it;
157 }
158 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
159 friend constexpr iterator &operator-=(iterator &it, difference_type n)
160 noexcept(noexcept(std::declval<I&>() -= 1))
161 {
162 it.m_it -= n;
163 return it;
164 }
165
166 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
167 friend constexpr iterator operator+(const iterator &it, difference_type n)
168 noexcept(noexcept(std::declval<I&>() + 1))
169 {
170 iterator copy = it;
171 copy.m_it += n;
172 return copy;
173 }
174 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
175 friend constexpr iterator operator+(difference_type n, const iterator &it)
176 noexcept(noexcept(1 + std::declval<I&>()))
177 {
178 return it + n;
179 }
180 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
181 friend constexpr iterator operator-(const iterator &it, difference_type n)
182 noexcept(noexcept(std::declval<I&>() - 1))
183 {
184 iterator copy = it;
185 copy.m_it = it.m_it - n;
186 return copy;
187 }
188
189 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
190 constexpr reference operator[](difference_type n) const
191 noexcept(noexcept(I::operator[]()))
192 {
193 return m_it[n];
194 }
195
196 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
197 friend constexpr difference_type operator-(const iterator &lhs, const iterator &rhs)
198 noexcept(noexcept(std::declval<I&>() - std::declval<I&>()))
199 {
200 return lhs.m_it - rhs.m_it;
201 }
202
203 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
204 friend constexpr bool operator<(const iterator &lhs, const iterator &rhs)
205 noexcept(noexcept(std::declval<I&>() < std::declval<I&>()))
206 {
207 return lhs.m_it < rhs.m_it;
208 }
209 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
210 friend constexpr bool operator<=(const iterator &lhs, const iterator &rhs)
211 noexcept(noexcept(std::declval<I&>() <= std::declval<I&>()))
212 {
213 return lhs.m_it <= rhs.m_it;
214 }
215
216 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
217 friend constexpr bool operator>(const iterator &lhs, const iterator &rhs)
218 noexcept(noexcept(std::declval<I&>() > std::declval<I&>()))
219 {
220 return lhs.m_it > rhs.m_it;
221 }
222 template <typename I = Iterator, if_atLeast<I, std::random_access_iterator_tag> = true>
223 friend constexpr bool operator>=(const iterator &lhs, const iterator &rhs)
224 noexcept(noexcept(std::declval<I&>() >= std::declval<I&>()))
225 {
226 return lhs.m_it >= rhs.m_it;
227 }
228
229 // This would implement the P2836R1 fix from std::basic_const_iterator,
230 // but a const_iterator on a range<pointer> would again allow us to
231 // mutate the pointed-to object, which is exactly what we want to
232 // prevent.
233 /*
234 template <typename CI, std::enable_if_t<std::is_convertible_v<const Iterator &, CI>, bool> = true>
235 operator CI() const
236 {
237 return CI{m_it};
238 }
239
240 template <typename CI, std::enable_if_t<std::is_convertible_v<Iterator, CI>, bool> = true>
241 operator CI() &&
242 {
243 return CI{std::move(m_it)};
244 }
245 */
246
247 friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
248 {
249 return lhs.m_it == rhs.m_it;
250 }
252
254 };
255
256 using value_type = typename iterator::value_type;
258
259 friend bool comparesEqual(const RowView &lhs, const RowView &rhs) noexcept
260 {
261 return lhs.m_begin == rhs.m_begin;
262 }
264
265 template <typename RHS>
266 bool operator==(const RHS &rhs) const noexcept
267 {
269 }
270 template <typename RHS>
271 bool operator!=(const RHS &rhs) const noexcept
272 {
273 return !operator==(rhs);
274 }
275
277
278 iterator begin() const { return iterator{m_begin}; }
279 iterator end() const { return iterator{m_end}; }
280
282 Sentinel m_end;
283};
284
285// Const-in-depth mapping for row types. We do store row types, and they might
286// be move-only, so we return them by const reference.
287template <typename T, typename = void> struct AsConstRow { using type = const T &; };
288// Otherwise the mapping for basic row types is the same as for data.
289template <typename T> struct AsConstRow<T *> : AsConstData<T *> {};
290template <template <typename> typename U, typename T>
292template <typename T> struct AsConstRow<std::reference_wrapper<T>>
294
295template <typename T> using if_range = std::enable_if_t<is_range_v<T>, bool>;
296// If the row type is a range, then we assume that the first type is the
297// element type.
298template <template <typename, typename ...> typename R, typename T, typename ...Args>
299struct AsConstRow<R<T, Args...>, if_range<R<T, Args...>>>
300{
301 using type = const R<T, Args...> &;
302};
303
304// specialize for range of pointers and smart pointers
305template <template <typename, typename ...> typename R, typename T, typename ...Args>
313
314template <template <typename, typename ...> typename R, typename T, typename ...Args>
324
325template <typename T>
326using asConstRow_t = typename AsConstRow<T>::type;
327
328Q_CORE_EXPORT QVariant qVariantAtIndex(const QModelIndex &index);
329
330template <typename Type>
331static inline Type dataAtIndex(const QModelIndex &index)
332{
333 Q_ASSERT_X(index.isValid(), "QRangeModelAdapter::dataAtIndex", "Index at position is invalid");
334 QVariant variant = qVariantAtIndex(index);
335
336 if constexpr (std::is_same_v<QVariant, Type>)
337 return variant;
338 else
339 return variant.value<Type>();
340}
341
342template <typename Type>
343static inline Type dataAtIndex(const QModelIndex &index, int role)
344{
345 Q_ASSERT_X(index.isValid(), "QRangeModelAdapter::dataAtIndex", "Index at position is invalid");
346 QVariant variant = index.data(role);
347
348 if constexpr (std::is_same_v<QVariant, Type>)
349 return variant;
350 else
351 return variant.value<Type>();
352}
353
354template <bool isTree = false>
356{
357 ParentIndex(const QModelIndex &dummy = {}) { Q_ASSERT(!dummy.isValid()); }
358 QModelIndex root() const { return {}; }
359};
360
361template <>
362struct ParentIndex<true>
363{
365 QModelIndex root() const { return m_rootIndex; }
366};
367
368template <typename Model, typename Impl>
369struct AdapterStorage : ParentIndex<Impl::protocol_traits::is_tree>
370{
371 // If it is, then we can shortcut the model and operate on the container.
372 // Otherwise we have to go through the model's vtable. For now, this is always
373 // the case.
374 static constexpr bool isRangeModel = std::is_same_v<Model, QRangeModel>;
375 static_assert(isRangeModel, "The model must be a QRangeModel (not a subclass).");
377
378 template <typename I = Impl, std::enable_if_t<I::protocol_traits::is_tree, bool> = true>
379 explicit AdapterStorage(const std::shared_ptr<QRangeModel> &model, const QModelIndex &root)
380 : ParentIndex<Impl::protocol_traits::is_tree>{root}, m_model(model)
381 {
382 }
383
384 explicit AdapterStorage(Model *model)
385 : m_model{model}
386 {}
387
388 const Impl *implementation() const
389 {
390 return static_cast<const Impl *>(QRangeModelImplBase::getImplementation(m_model.get()));
391 }
392
394 {
395 return static_cast<Impl *>(QRangeModelImplBase::getImplementation(m_model.get()));
396 }
397
398 auto *operator->()
399 {
400 if constexpr (isRangeModel)
401 return implementation();
402 else
403 return m_model.get();
404 }
405
406 const auto *operator->() const
407 {
408 if constexpr (isRangeModel)
409 return implementation();
410 else
411 return m_model.get();
412 }
413};
414
415} // QRangeModelDetails
416
417QT_END_NAMESPACE
418
419#endif // Q_QDOC
420
421#endif // QRANGEMODELADAPTER_IMPL_H
static Type dataAtIndex(const QModelIndex &index, int role)
static Type dataAtIndex(const QModelIndex &index)
decltype(auto) forwardOrConvert(Input &&input)
static constexpr bool can_construct_rangeModel
decltype(QRangeModel(std::declval< Args && >()...)) construct_rangeModel_test
std::shared_ptr< QRangeModel > m_model
AdapterStorage(const std::shared_ptr< QRangeModel > &model, const QModelIndex &root)
ParentIndex(const QModelIndex &dummy={})
friend constexpr iterator & operator-=(iterator &it, difference_type n) noexcept(noexcept(std::declval< I & >() -=1))
friend constexpr iterator operator+(const iterator &it, difference_type n) noexcept(noexcept(std::declval< I & >()+1))
friend constexpr iterator & operator+=(iterator &it, difference_type n) noexcept(noexcept(std::declval< I & >()+=1))
friend constexpr iterator operator-(const iterator &it, difference_type n) noexcept(noexcept(std::declval< I & >() - 1))
friend constexpr iterator operator+(difference_type n, const iterator &it) noexcept(noexcept(1+std::declval< I & >()))
friend constexpr difference_type operator-(const iterator &lhs, const iterator &rhs) noexcept(noexcept(std::declval< I & >() - std::declval< I & >()))
friend constexpr bool operator<=(const iterator &lhs, const iterator &rhs) noexcept(noexcept(std::declval< I & >()<=std::declval< I & >()))
friend constexpr bool operator>(const iterator &lhs, const iterator &rhs) noexcept(noexcept(std::declval< I & >() > std::declval< I & >()))
friend constexpr iterator & operator++(iterator &it) noexcept(noexcept(++std::declval< Iterator & >()))
friend constexpr bool operator<(const iterator &lhs, const iterator &rhs) noexcept(noexcept(std::declval< I & >()< std::declval< I & >()))
typename std::iterator_traits< Iterator >::iterator_category iterator_category
friend constexpr iterator operator++(iterator &it, int) noexcept(noexcept(std::declval< Iterator & >()++))
friend constexpr iterator & operator--(iterator &it) noexcept(noexcept(--std::declval< I & >()))
friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
typename Iterator::difference_type difference_type
friend constexpr bool operator>=(const iterator &lhs, const iterator &rhs) noexcept(noexcept(std::declval< I & >() >=std::declval< I & >()))
friend constexpr iterator operator--(iterator &it, int) noexcept(noexcept(std::declval< I & >() --))
constexpr reference operator[](difference_type n) const noexcept(noexcept(I::operator[]()))
typename iterator::difference_type difference_type
typename iterator::value_type value_type
friend bool comparesEqual(const RowView &lhs, const RowView &rhs) noexcept