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_H
0006 #define QRANGEMODELADAPTER_H
0007 
0008 #include <QtCore/qrangemodeladapter_impl.h>
0009 
0010 #include <QtCore/q26numeric.h>
0011 
0012 QT_BEGIN_NAMESPACE
0013 
0014 template <typename Range, typename Protocol = void, typename Model = QRangeModel>
0015 class QT_TECH_PREVIEW_API QRangeModelAdapter
0016 {
0017     using Impl = QRangeModelDetails::RangeImplementation<Range, Protocol>;
0018     using Storage = QRangeModelDetails::AdapterStorage<Model, Impl>;
0019 
0020     Storage storage;
0021 
0022 #ifdef Q_QDOC
0023     using range_type = Range;
0024 #else
0025     using range_type = QRangeModelDetails::wrapped_t<Range>;
0026 #endif
0027     using const_row_reference = typename Impl::const_row_reference;
0028     using row_reference = typename Impl::row_reference;
0029     using range_features = typename QRangeModelDetails::range_traits<range_type>;
0030     using row_type = std::remove_reference_t<row_reference>;
0031     using row_features = QRangeModelDetails::range_traits<typename Impl::wrapped_row_type>;
0032     using row_ptr = typename Impl::wrapped_row_type *;
0033     using row_traits = typename Impl::row_traits;
0034     using item_type = std::remove_reference_t<typename row_traits::item_type>;
0035     using data_type = typename QRangeModelDetails::data_type<item_type>::type;
0036     using const_data_type = QRangeModelDetails::asConst_t<data_type>;
0037     using protocol_traits = typename Impl::protocol_traits;
0038 
0039     template <typename I> static constexpr bool is_list = I::protocol_traits::is_list;
0040     template <typename I> static constexpr bool is_table = I::protocol_traits::is_table;
0041     template <typename I> static constexpr bool is_tree = I::protocol_traits::is_tree;
0042     template <typename I> static constexpr bool canInsertColumns = I::dynamicColumns()
0043                                                                  && I::isMutable()
0044                                                                  && row_features::has_insert;
0045     template <typename I> static constexpr bool canRemoveColumns = I::dynamicColumns()
0046                                                                  && I::isMutable()
0047                                                                  && row_features::has_erase;
0048 
0049     template <typename I> using if_writable = std::enable_if_t<I::isMutable(), bool>;
0050     template <typename I> using if_list = std::enable_if_t<is_list<I>, bool>;
0051     template <typename I> using unless_list = std::enable_if_t<!is_list<I>, bool>;
0052     template <typename I> using if_table = std::enable_if_t<is_table<I>, bool>;
0053     template <typename I> using if_tree = std::enable_if_t<is_tree<I>, bool>;
0054     template <typename I> using unless_tree = std::enable_if_t<!is_tree<I>, bool>;
0055     template <typename I> using if_flat = std::enable_if_t<is_list<I> || is_table<I>, bool>;
0056 
0057     template <typename I>
0058     using if_canInsertRows = std::enable_if_t<I::canInsertRows(), bool>;
0059     template <typename I>
0060     using if_canRemoveRows = std::enable_if_t<I::canRemoveRows(), bool>;
0061     template <typename F>
0062     using if_canMoveItems = std::enable_if_t<F::has_rotate || F::has_splice, bool>;
0063 
0064     template <typename I>
0065     using if_canInsertColumns = std::enable_if_t<canInsertColumns<I>, bool>;
0066     template <typename I>
0067     using if_canRemoveColumns = std::enable_if_t<canRemoveColumns<I>, bool>;
0068 
0069     template <typename Row>
0070     static constexpr bool is_compatible_row = std::is_convertible_v<Row, const_row_reference>;
0071     template <typename Row>
0072     using if_compatible_row = std::enable_if_t<is_compatible_row<Row>, bool>;
0073 
0074     template <typename C>
0075     static constexpr bool is_compatible_row_range = is_compatible_row<
0076                                                           decltype(*std::begin(std::declval<C&>()))
0077                                                     >;
0078     template <typename C>
0079     using if_compatible_row_range = std::enable_if_t<is_compatible_row_range<C>, bool>;
0080     template <typename Data>
0081     static constexpr bool is_compatible_data = std::is_convertible_v<Data, data_type>;
0082     template <typename Data>
0083     using if_compatible_data = std::enable_if_t<is_compatible_data<Data>, bool>;
0084     template <typename C>
0085     static constexpr bool is_compatible_data_range = is_compatible_data<
0086                                                 typename QRangeModelDetails::data_type<
0087                                                     typename QRangeModelDetails::row_traits<
0088                                                         decltype(*std::begin(std::declval<C&>()))
0089                                                     >::item_type
0090                                                 >::type
0091                                             >;
0092     template <typename C>
0093     using if_compatible_column_data = std::enable_if_t<is_compatible_data<C>
0094                                                     || is_compatible_data_range<C>, bool>;
0095     template <typename C>
0096     using if_compatible_column_range = std::enable_if_t<is_compatible_data_range<C>, bool>;
0097 
0098     template <typename R>
0099     using if_assignable_range = std::enable_if_t<std::is_assignable_v<range_type, R>, bool>;
0100 
0101     friend class QRangeModel;
0102     template <typename T>
0103     static constexpr bool is_adapter = QRangeModelDetails::is_any_of<q20::remove_cvref_t<T>,
0104                                                                      QRangeModelAdapter>::value;
0105     template <typename T>
0106     using unless_adapter = std::enable_if_t<!is_adapter<T>, bool>;
0107 
0108     template <typename R, typename P>
0109     using if_compatible_model_params =
0110         std::enable_if_t<
0111            std::conjunction_v<
0112                 std::disjunction<
0113                     std::is_convertible<R &&, Range>,
0114                     std::is_convertible<R &&, Range &&> // for C-arrays
0115                 >,
0116                 std::is_convertible<P, Protocol> // note, only void is expected to be convertible to void
0117          >, bool>;
0118 
0119 #if !defined(Q_OS_VXWORKS) && !defined(Q_OS_INTEGRITY)
0120     // An adapter on a mutable range can make itself an adapter on a const
0121     // version of that same range. To make the constructor for a sub-range
0122     // accessible, befriend the mutable version. We can use more
0123     // generic pattern matching here, as we only use as input what asConst
0124     // might produce as output.
0125     template <typename T> static constexpr T asMutable(const T &);
0126     template <typename T> static constexpr T *asMutable(const T *);
0127     template <template <typename, typename...> typename U, typename T, typename ...Args>
0128     static constexpr U<T, Args...> asMutable(const U<const T, Args...> &);
0129 
0130     template <typename T>
0131     using asMutable_t = decltype(asMutable(std::declval<T>()));
0132     friend class QRangeModelAdapter<asMutable_t<Range>, Protocol, Model>;
0133 #else
0134     template <typename R, typename P, typename M>
0135     friend class QRangeModelAdapter;
0136 #endif
0137 
0138     explicit QRangeModelAdapter(const std::shared_ptr<QRangeModel> &model, const QModelIndex &root,
0139                                 std::in_place_t) // disambiguate from range/protocol c'tor
0140         : storage{model, root}
0141     {}
0142 
0143     explicit QRangeModelAdapter(QRangeModel *model)
0144         : storage(model)
0145     {}
0146 
0147 public:
0148     struct DataReference
0149     {
0150 #ifdef Q_QDOC
0151         using value_type = int;
0152         using const_value_type = const int;
0153         using pointer = void *;
0154 #else
0155         using value_type = data_type;
0156         using const_value_type = const_data_type;
0157         using pointer = QRangeModelDetails::data_pointer_t<const_value_type>;
0158 #endif
0159 
0160         explicit DataReference(const QModelIndex &index) noexcept
0161             : m_index(index)
0162         {}
0163 
0164         DataReference(const DataReference &other) = default;
0165         DataReference(DataReference &&other) = default;
0166 
0167         // reference (not std::reference_wrapper) semantics
0168         DataReference &operator=(const DataReference &other)
0169         {
0170             *this = other.get();
0171             return *this;
0172         }
0173 
0174         DataReference &operator=(DataReference &&other)
0175         {
0176             *this = other.get();
0177             return *this;
0178         }
0179 
0180         ~DataReference() = default;
0181 
0182         DataReference &operator=(const value_type &value)
0183         {
0184             assign(value);
0185             return *this;
0186         }
0187 
0188         DataReference &operator=(value_type &&value)
0189         {
0190             assign(std::move(value));
0191             return *this;
0192         }
0193 
0194         const_value_type get() const
0195         {
0196             Q_ASSERT_X(m_index.isValid(), "QRangeModelAdapter::at", "Index at position is invalid");
0197             return QRangeModelDetails::dataAtIndex<q20::remove_cvref_t<value_type>>(m_index);
0198         }
0199 
0200         operator const_value_type() const
0201         {
0202             return get();
0203         }
0204 
0205         pointer operator->() const
0206         {
0207             return {get()};
0208         }
0209 
0210         bool isValid() const { return m_index.isValid(); }
0211 
0212     private:
0213         QModelIndex m_index;
0214 
0215         template <typename Value>
0216         void assign(Value &&value)
0217         {
0218             constexpr Qt::ItemDataRole dataRole = Qt::RangeModelAdapterRole;
0219 
0220             if (m_index.isValid()) {
0221                 auto model = const_cast<QAbstractItemModel *>(m_index.model());
0222                 [[maybe_unused]] bool couldWrite = false;
0223                 if constexpr (std::is_same_v<q20::remove_cvref_t<Value>, QVariant>) {
0224                     couldWrite = model->setData(m_index, value, dataRole);
0225                 } else {
0226                     couldWrite = model->setData(m_index,
0227                                                 QVariant::fromValue(std::forward<Value>(value)),
0228                                                 dataRole);
0229                 }
0230 #ifndef QT_NO_DEBUG
0231                 if (!couldWrite) {
0232                     qWarning() << "Writing value of type"
0233                                << QMetaType::fromType<q20::remove_cvref_t<Value>>().name()
0234                                << "to role" << dataRole << "at index" << m_index << "failed";
0235                 }
0236             } else {
0237                 qCritical("Data reference for invalid index, can't write to model");
0238 #endif
0239             }
0240         }
0241 
0242         friend inline bool comparesEqual(const DataReference &lhs, const DataReference &rhs)
0243         {
0244             return lhs.m_index == rhs.m_index
0245                 || lhs.get() == rhs.get();
0246         }
0247         Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(DataReference);
0248 
0249         friend inline bool comparesEqual(const DataReference &lhs, const value_type &rhs)
0250         {
0251             return lhs.get() == rhs;
0252         }
0253         Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(DataReference, value_type);
0254 
0255         friend inline void swap(DataReference lhs, DataReference rhs)
0256         {
0257             const value_type lhsValue = lhs.get();
0258             lhs = rhs;
0259             rhs = lhsValue; // no point in moving, we have to go through QVariant anyway
0260         }
0261 
0262 #ifndef QT_NO_DEBUG_STREAM
0263         friend inline QDebug operator<<(QDebug dbg, const DataReference &ref)
0264         {
0265             return dbg << ref.get();
0266         }
0267 #endif
0268 #ifndef QT_NO_DATASTREAM
0269         friend inline QDataStream &operator<<(QDataStream &ds, const DataReference &ref)
0270         {
0271             return ds << ref.get();
0272         }
0273         friend inline QDataStream &operator>>(QDataStream &ds, DataReference &ref)
0274         {
0275             value_type value;
0276             ds >> value;
0277             ref = std::move(value);
0278             return ds;
0279         }
0280 #endif
0281     };
0282     template <typename Iterator, typename Adapter>
0283     struct ColumnIteratorBase
0284     {
0285         using iterator_category = std::random_access_iterator_tag;
0286         using difference_type = int;
0287 
0288         ColumnIteratorBase() = default;
0289         ColumnIteratorBase(const ColumnIteratorBase &other) = default;
0290         ColumnIteratorBase(ColumnIteratorBase &&other) = default;
0291         ColumnIteratorBase &operator=(const ColumnIteratorBase &other) = default;
0292         ColumnIteratorBase &operator=(ColumnIteratorBase &&other) = default;
0293 
0294         ColumnIteratorBase(const QModelIndex &rowIndex, int column, Adapter *adapter) noexcept
0295             : m_rowIndex(rowIndex), m_column(column), m_adapter(adapter)
0296         {
0297         }
0298 
0299         void swap(ColumnIteratorBase &other) noexcept
0300         {
0301             std::swap(m_rowIndex, other.m_rowIndex);
0302             std::swap(m_column, other.m_column);
0303             q_ptr_swap(m_adapter, other.m_adapter);
0304         }
0305 
0306         friend Iterator &operator++(Iterator &that)
0307         {
0308             ++that.m_column;
0309             return that;
0310         }
0311         friend Iterator operator++(Iterator &that, int)
0312         {
0313             auto copy = that;
0314             ++that;
0315             return copy;
0316         }
0317         friend Iterator operator+(const Iterator &that, difference_type n)
0318         {
0319             return {that.m_rowIndex, that.m_column + n, that.m_adapter};
0320         }
0321         friend Iterator operator+(difference_type n, const Iterator &that)
0322         {
0323             return that + n;
0324         }
0325         friend Iterator &operator+=(Iterator &that, difference_type n)
0326         {
0327             that.m_column += n;
0328             return that;
0329         }
0330 
0331         friend Iterator &operator--(Iterator &that)
0332         {
0333             --that.m_column;
0334             return that;
0335         }
0336         friend Iterator operator--(Iterator &that, int)
0337         {
0338             auto copy = that;
0339             --that;
0340             return copy;
0341         }
0342         friend Iterator operator-(const Iterator &that, difference_type n)
0343         {
0344             return {that.m_rowIndex, that.m_column - n, that.m_adapter};
0345         }
0346         friend Iterator operator-(difference_type n, const Iterator &that)
0347         {
0348             return that - n;
0349         }
0350         friend Iterator &operator-=(Iterator &that, difference_type n)
0351         {
0352             that.m_column -= n;
0353             return that;
0354         }
0355 
0356         friend difference_type operator-(const Iterator &lhs, const Iterator &rhs)
0357         {
0358             Q_PRE(lhs.m_rowIndex == rhs.m_rowIndex);
0359             Q_PRE(lhs.m_adapter == rhs.m_adapter);
0360             return lhs.m_column - rhs.m_column;
0361         }
0362 
0363     protected:
0364         ~ColumnIteratorBase() = default;
0365         QModelIndex m_rowIndex;
0366         int m_column = -1;
0367         Adapter *m_adapter = nullptr;
0368 
0369     private:
0370         friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs)
0371         {
0372             Q_ASSERT(lhs.m_rowIndex == rhs.m_rowIndex);
0373             return lhs.m_column == rhs.m_column;
0374         }
0375         friend Qt::strong_ordering compareThreeWay(const Iterator &lhs, const Iterator &rhs)
0376         {
0377             Q_ASSERT(lhs.m_rowIndex == rhs.m_rowIndex);
0378             return qCompareThreeWay(lhs.m_column, rhs.m_column);
0379         }
0380 
0381         Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(Iterator)
0382 
0383 #ifndef QT_NO_DEBUG_STREAM
0384         friend inline QDebug operator<<(QDebug dbg, const Iterator &it)
0385         {
0386             QDebugStateSaver saver(dbg);
0387             dbg.nospace();
0388             return dbg << "ColumnIterator(" << it.m_rowIndex.siblingAtColumn(it.m_column) << ")";
0389         }
0390 #endif
0391     };
0392 
0393     struct ConstColumnIterator : ColumnIteratorBase<ConstColumnIterator, const QRangeModelAdapter>
0394     {
0395     private:
0396         using Base = ColumnIteratorBase<ConstColumnIterator, const QRangeModelAdapter>;
0397     public:
0398         using difference_type = typename Base::difference_type;
0399         using value_type = data_type;
0400         using reference = const_data_type;
0401         using pointer = QRangeModelDetails::data_pointer_t<value_type>;
0402 
0403         using Base::Base;
0404         using Base::operator=;
0405         ~ConstColumnIterator() = default;
0406 
0407         pointer operator->() const
0408         {
0409             return pointer{operator*()};
0410         }
0411 
0412         reference operator*() const
0413         {
0414             return std::as_const(this->m_adapter)->at(this->m_rowIndex.row(), this->m_column);
0415         }
0416 
0417         reference operator[](difference_type n) const
0418         {
0419             return *(*this + n);
0420         }
0421     };
0422 
0423     struct ColumnIterator : ColumnIteratorBase<ColumnIterator, QRangeModelAdapter>
0424     {
0425     private:
0426         using Base = ColumnIteratorBase<ColumnIterator, QRangeModelAdapter>;
0427     public:
0428         using difference_type = typename Base::difference_type;
0429         using value_type = DataReference;
0430         using reference = DataReference;
0431         using pointer = reference;
0432 
0433         using Base::Base;
0434         using Base::operator=;
0435         ~ColumnIterator() = default;
0436 
0437         operator ConstColumnIterator() const
0438         {
0439             return ConstColumnIterator{this->m_rowIndex, this->m_column, this->m_adapter};
0440         }
0441 
0442         pointer operator->() const
0443         {
0444             return operator*();
0445         }
0446 
0447         reference operator*() const
0448         {
0449             return reference{this->m_rowIndex.siblingAtColumn(this->m_column)};
0450         }
0451 
0452         reference operator[](difference_type n) const
0453         {
0454             return *(*this + n);
0455         }
0456     };
0457 
0458     template <typename Reference, typename const_row_type, typename = void>
0459     struct RowGetter
0460     {
0461         const_row_type get() const
0462         {
0463             const Reference *that = static_cast<const Reference *>(this);
0464             const auto *impl = that->m_adapter->storage.implementation();
0465             auto *childRange = impl->childRange(that->m_index.parent());
0466             if constexpr (std::is_convertible_v<const row_type &, const_row_type>) {
0467                 return *std::next(QRangeModelDetails::adl_begin(childRange), that->m_index.row());
0468             } else {
0469                 const auto &row = *std::next(QRangeModelDetails::adl_begin(childRange),
0470                                              that->m_index.row());
0471                 return const_row_type{QRangeModelDetails::adl_begin(row),
0472                                       QRangeModelDetails::adl_end(row)};
0473             }
0474         }
0475 
0476         const_row_type operator->() const
0477         {
0478             return {get()};
0479         }
0480 
0481         operator const_row_type() const
0482         {
0483             return get();
0484         }
0485     };
0486 
0487     template <typename Reference, typename const_row_type>
0488     struct RowGetter<Reference, const_row_type,
0489                      std::enable_if_t<std::is_reference_v<const_row_type>>>
0490     {
0491         const_row_type get() const
0492         {
0493             const Reference *that = static_cast<const Reference *>(this);
0494             const auto *impl = that->m_adapter->storage.implementation();
0495             return *std::next(QRangeModelDetails::begin(
0496                                 QRangeModelDetails::refTo(impl->childRange(that->m_index.parent()))),
0497                               that->m_index.row());
0498         }
0499 
0500         auto operator->() const
0501         {
0502             return std::addressof(get());
0503         }
0504 
0505         operator const_row_type() const
0506         {
0507             return get();
0508         }
0509     };
0510 
0511     template <typename Reference, typename const_row_type>
0512     struct RowGetter<Reference, const_row_type,
0513                      std::enable_if_t<std::is_pointer_v<const_row_type>>>
0514     {
0515         const_row_type get() const
0516         {
0517             const Reference *that = static_cast<const Reference *>(this);
0518             const auto *impl = that->m_adapter->storage.implementation();
0519             return *std::next(QRangeModelDetails::begin(
0520                                 QRangeModelDetails::refTo(impl->childRange(that->m_index.parent()))),
0521                               that->m_index.row());
0522         }
0523 
0524         const_row_type operator->() const
0525         {
0526             return get();
0527         }
0528 
0529         operator const_row_type() const
0530         {
0531             return get();
0532         }
0533     };
0534 
0535     template <typename Reference, typename Adapter>
0536     struct RowReferenceBase : RowGetter<Reference, QRangeModelDetails::asConstRow_t<row_type>>
0537     {
0538         using const_iterator = ConstColumnIterator;
0539         using size_type = int;
0540         using difference_type = int;
0541         using const_row_type = QRangeModelDetails::asConstRow_t<row_type>;
0542 
0543         RowReferenceBase(const QModelIndex &index, Adapter *adapter) noexcept
0544             : m_index(index), m_adapter(adapter)
0545         {}
0546 
0547         template <typename I = Impl, if_tree<I> = true>
0548         bool hasChildren() const
0549         {
0550             return m_adapter->model()->hasChildren(m_index);
0551         }
0552 
0553         template <typename I = Impl, if_tree<I> = true>
0554         auto children() const
0555         {
0556             using ConstRange = QRangeModelDetails::asConst_t<Range>;
0557             return QRangeModelAdapter<ConstRange, Protocol, Model>(m_adapter->storage.m_model,
0558                                                                    m_index, std::in_place);
0559         }
0560 
0561         ConstColumnIterator cbegin() const
0562         {
0563             return ConstColumnIterator{m_index, 0, m_adapter};
0564         }
0565         ConstColumnIterator cend() const
0566         {
0567             return ConstColumnIterator{m_index, m_adapter->columnCount(), m_adapter};
0568         }
0569 
0570         ConstColumnIterator begin() const { return cbegin(); }
0571         ConstColumnIterator end() const { return cend(); }
0572 
0573         size_type size() const
0574         {
0575             return m_adapter->columnCount();
0576         }
0577 
0578         auto at(int column) const
0579         {
0580             Q_ASSERT(column >= 0 && column < m_adapter->columnCount());
0581             return *ConstColumnIterator{m_index, column, m_adapter};
0582         }
0583 
0584         auto operator[](int column) const
0585         {
0586             return at(column);
0587         }
0588 
0589     protected:
0590         friend struct RowGetter<Reference, const_row_type>;
0591         ~RowReferenceBase() = default;
0592         QModelIndex m_index;
0593         Adapter *m_adapter;
0594 
0595     private:
0596         friend bool comparesEqual(const Reference &lhs, const Reference &rhs)
0597         {
0598             Q_ASSERT(lhs.m_adapter == rhs.m_adapter);
0599             return lhs.m_index == rhs.m_index;
0600         }
0601         friend Qt::strong_ordering compareThreeWay(const Reference &lhs, const Reference &rhs)
0602         {
0603             Q_ASSERT(lhs.m_adapter == rhs.m_adapter);
0604             return qCompareThreeWay(lhs.m_index, rhs.m_index);
0605         }
0606 
0607         Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(Reference)
0608 
0609         friend bool comparesEqual(const Reference &lhs, const row_type &rhs)
0610         {
0611             return lhs.get() == rhs;
0612         }
0613         Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(Reference, row_type)
0614 
0615 #ifndef QT_NO_DEBUG_STREAM
0616         friend inline QDebug operator<<(QDebug dbg, const Reference &ref)
0617         {
0618             QDebugStateSaver saver(dbg);
0619             dbg.nospace();
0620             return dbg << "RowReference(" << ref.m_index << ")";
0621         }
0622 #endif
0623 #ifndef QT_NO_DATASTREAM
0624         friend inline QDataStream &operator<<(QDataStream &ds, const Reference &ref)
0625         {
0626             return ds << ref.get();
0627         }
0628 #endif
0629     };
0630 
0631     struct ConstRowReference : RowReferenceBase<ConstRowReference, const QRangeModelAdapter>
0632     {
0633     private:
0634         using Base = RowReferenceBase<ConstRowReference, const QRangeModelAdapter>;
0635     public:
0636         using Base::Base;
0637 
0638         ConstRowReference() = default;
0639         ConstRowReference(const ConstRowReference &) = default;
0640         ConstRowReference(ConstRowReference &&) = default;
0641         ConstRowReference &operator=(const ConstRowReference &) = default;
0642         ConstRowReference &operator=(ConstRowReference &&) = default;
0643         ~ConstRowReference() = default;
0644     };
0645 
0646     struct RowReference : RowReferenceBase<RowReference, QRangeModelAdapter>
0647     {
0648     private:
0649         using Base = RowReferenceBase<RowReference, QRangeModelAdapter>;
0650     public:
0651         using iterator = ColumnIterator;
0652         using const_iterator = typename Base::const_iterator;
0653         using size_type = typename Base::size_type;
0654         using difference_type = typename Base::difference_type;
0655 #ifdef Q_QDOC
0656         using row_type = int;
0657 #endif
0658         using const_row_type = typename Base::const_row_type;
0659 
0660         using Base::Base;
0661         RowReference() = delete;
0662         ~RowReference() = default;
0663         RowReference(const RowReference &other) = default;
0664         RowReference(RowReference &&other) = default;
0665 
0666         // assignment has reference (std::reference_wrapper) semantics
0667         RowReference &operator=(const ConstRowReference &other)
0668         {
0669             *this = other.get();
0670             return *this;
0671         }
0672 
0673         RowReference &operator=(const RowReference &other)
0674         {
0675             *this = other.get();
0676             return *this;
0677         }
0678 
0679         RowReference &operator=(const row_type &other)
0680         {
0681             assign(other);
0682             return *this;
0683         }
0684 
0685         RowReference &operator=(row_type &&other)
0686         {
0687             assign(std::move(other));
0688             return *this;
0689         }
0690 
0691         operator ConstRowReference() const
0692         {
0693             return ConstRowReference{this->m_index, this->m_adapter};
0694         }
0695 
0696         template <typename ConstRowType = const_row_type,
0697                   std::enable_if_t<!std::is_same_v<ConstRowType, const row_type &>, bool> = true>
0698         RowReference &operator=(const ConstRowType &other)
0699         {
0700             assign(other);
0701             return *this;
0702         }
0703 
0704         template <typename T, typename It, typename Sentinel>
0705         RowReference &operator=(const QRangeModelDetails::RowView<T, It, Sentinel> &other)
0706         {
0707             *this = row_type{other.begin(), other.end()};
0708             return *this;
0709         }
0710 
0711         friend inline void swap(RowReference lhs, RowReference rhs)
0712         {
0713             auto lhsRow = lhs.get();
0714             lhs = rhs.get();
0715             rhs = std::move(lhsRow);
0716         }
0717 
0718         template <typename I = Impl, if_tree<I> = true>
0719         auto children()
0720         {
0721             return QRangeModelAdapter(this->m_adapter->storage.m_model, this->m_index,
0722                                       std::in_place);
0723         }
0724 
0725         using Base::begin;
0726         ColumnIterator begin()
0727         {
0728             return ColumnIterator{this->m_index, 0, this->m_adapter};
0729         }
0730 
0731         using Base::end;
0732         ColumnIterator end()
0733         {
0734             return ColumnIterator{this->m_index, this->m_adapter->columnCount(), this->m_adapter};
0735         }
0736 
0737         using Base::at;
0738         auto at(int column)
0739         {
0740             Q_ASSERT(column >= 0 && column < this->m_adapter->columnCount());
0741             return *ColumnIterator{this->m_index, column, this->m_adapter};
0742         }
0743 
0744         using Base::operator[];
0745         auto operator[](int column)
0746         {
0747             return at(column);
0748         }
0749 
0750     private:
0751         template <typename RHS>
0752         void verifyRows(const row_type &oldRow, const RHS &newRow)
0753         {
0754             if constexpr (QRangeModelDetails::test_size<row_type>::value) {
0755                 // prevent that tables get populated with wrongly sized rows
0756                 Q_ASSERT_X(Impl::size(newRow) == Impl::size(oldRow),
0757                            "RowReference::operator=()",
0758                            "The new row has the wrong size!");
0759             }
0760 
0761             if constexpr (is_tree<Impl>) {
0762                 // we cannot hook invalid rows up to the tree hierarchy
0763                 Q_ASSERT_X(QRangeModelDetails::isValid(newRow),
0764                            "RowReference::operator=()",
0765                            "An invalid row can not inserted into a tree!");
0766             }
0767         }
0768 
0769         template <typename R>
0770         void assign(R &&other)
0771         {
0772             auto *impl = this->m_adapter->storage.implementation();
0773             decltype(auto) oldRow = impl->rowData(this->m_index);
0774 
0775             verifyRows(oldRow, other);
0776 
0777             if constexpr (is_tree<Impl>) {
0778                 auto &protocol = impl->protocol();
0779                 auto *oldParent = protocol.parentRow(QRangeModelDetails::refTo(oldRow));
0780 
0781                 // the old children will be removed; we don't try to overwrite
0782                 // them with the new children, we replace them completely
0783                 if (decltype(auto) oldChildren = protocol.childRows(QRangeModelDetails::refTo(oldRow));
0784                     QRangeModelDetails::isValid(oldChildren)) {
0785                     if (int oldChildCount = this->m_adapter->model()->rowCount(this->m_index)) {
0786                         impl->beginRemoveRows(this->m_index, 0, oldChildCount - 1);
0787                         impl->deleteRemovedRows(QRangeModelDetails::refTo(oldChildren));
0788                         // make sure the list is empty before we emit rowsRemoved
0789                         QRangeModelDetails::refTo(oldChildren) = range_type{};
0790                         impl->endRemoveRows();
0791                     }
0792                 }
0793 
0794                 if constexpr (protocol_traits::has_deleteRow)
0795                     protocol.deleteRow(oldRow);
0796                 oldRow = std::forward<R>(other);
0797                 if constexpr (protocol_traits::has_setParentRow) {
0798                     protocol.setParentRow(QRangeModelDetails::refTo(oldRow),
0799                                           QRangeModelDetails::pointerTo(oldParent));
0800                     if (decltype(auto) newChildren = protocol.childRows(QRangeModelDetails::refTo(oldRow));
0801                         QRangeModelDetails::isValid(newChildren)) {
0802                         impl->beginInsertRows(this->m_index, 0,
0803                                               Impl::size(QRangeModelDetails::refTo(newChildren)) - 1);
0804                         impl->setParentRow(QRangeModelDetails::refTo(newChildren),
0805                                            QRangeModelDetails::pointerTo(oldRow));
0806                         impl->endInsertRows();
0807                     }
0808                 }
0809             } else {
0810                 oldRow = std::forward<R>(other);
0811             }
0812             this->m_adapter->emitDataChanged(this->m_index,
0813                                              this->m_index.siblingAtColumn(this->m_adapter->columnCount() - 1));
0814             if constexpr (Impl::itemsAreQObjects) {
0815                 if (this->m_adapter->model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
0816                     impl->autoConnectPropertiesInRow(oldRow, this->m_index.row(), this->m_index.parent());
0817                     if constexpr (is_tree<Impl>)
0818                         impl->autoConnectProperties(this->m_index);
0819                 }
0820 
0821             }
0822         }
0823 
0824 #ifndef QT_NO_DATASTREAM
0825         friend inline QDataStream &operator>>(QDataStream &ds, RowReference &ref)
0826         {
0827             row_type value;
0828             ds >> value;
0829             ref = value;
0830             return ds;
0831         }
0832 #endif
0833     };
0834 
0835     template <typename Iterator, typename Adapter>
0836     struct RowIteratorBase : QRangeModelDetails::ParentIndex<is_tree<Impl>>
0837     {
0838         using iterator_category = std::random_access_iterator_tag;
0839         using difference_type = int;
0840 
0841         RowIteratorBase() = default;
0842         RowIteratorBase(const RowIteratorBase &) = default;
0843         RowIteratorBase(RowIteratorBase &&) = default;
0844         RowIteratorBase &operator=(const RowIteratorBase &) = default;
0845         RowIteratorBase &operator=(RowIteratorBase &&) = default;
0846 
0847         RowIteratorBase(int row, const QModelIndex &parent, Adapter *adapter)
0848             : QRangeModelDetails::ParentIndex<is_tree<Impl>>{parent}
0849             , m_row(row), m_adapter(adapter)
0850         {}
0851 
0852         void swap(RowIteratorBase &other) noexcept
0853         {
0854             qSwap(m_row, other.m_row);
0855             qSwap(this->m_rootIndex, other.m_rootIndex);
0856             q_ptr_swap(m_adapter, other.m_adapter);
0857         }
0858 
0859         friend Iterator &operator++(Iterator &that)
0860         {
0861             ++that.m_row;
0862             return that;
0863         }
0864         friend Iterator operator++(Iterator &that, int)
0865         {
0866             auto copy = that;
0867             ++that;
0868             return copy;
0869         }
0870         friend Iterator operator+(const Iterator &that, difference_type n)
0871         {
0872             return {that.m_row + n, that.root(), that.m_adapter};
0873         }
0874         friend Iterator operator+(difference_type n, const Iterator &that)
0875         {
0876             return that + n;
0877         }
0878         friend Iterator &operator+=(Iterator &that, difference_type n)
0879         {
0880             that.m_row += n;
0881             return that;
0882         }
0883 
0884         friend Iterator &operator--(Iterator &that)
0885         {
0886             --that.m_row;
0887             return that;
0888         }
0889         friend Iterator operator--(Iterator &that, int)
0890         {
0891             auto copy = that;
0892             --that;
0893             return copy;
0894         }
0895         friend Iterator operator-(const Iterator &that, difference_type n)
0896         {
0897             return {that.m_row - n, that.root(), that.m_adapter};
0898         }
0899         friend Iterator operator-(difference_type n, const Iterator &that)
0900         {
0901             return that - n;
0902         }
0903         friend Iterator &operator-=(Iterator &that, difference_type n)
0904         {
0905             that.m_row -= n;
0906             return that;
0907         }
0908 
0909         friend difference_type operator-(const Iterator &lhs, const Iterator &rhs)
0910         {
0911             return lhs.m_row - rhs.m_row;
0912         }
0913 
0914     protected:
0915         ~RowIteratorBase() = default;
0916         int m_row = -1;
0917         Adapter *m_adapter = nullptr;
0918 
0919     private:
0920         friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
0921         {
0922             return lhs.m_row == rhs.m_row && lhs.root() == rhs.root();
0923         }
0924         friend Qt::strong_ordering compareThreeWay(const Iterator &lhs, const Iterator &rhs) noexcept
0925         {
0926             if (lhs.root() == rhs.root())
0927                 return qCompareThreeWay(lhs.m_row, rhs.m_row);
0928             return qCompareThreeWay(lhs.root(), rhs.root());
0929         }
0930 
0931         Q_DECLARE_STRONGLY_ORDERED(Iterator)
0932 
0933 #ifndef QT_NO_DEBUG_STREAM
0934         friend inline QDebug operator<<(QDebug dbg, const Iterator &it)
0935         {
0936             QDebugStateSaver saver(dbg);
0937             dbg.nospace();
0938             return dbg << "RowIterator(" << it.m_row << it.root() << ")";
0939         }
0940 #endif
0941     };
0942 
0943 public:
0944     struct ConstRowIterator : public RowIteratorBase<ConstRowIterator, const QRangeModelAdapter>
0945     {
0946     private:
0947         using Base = RowIteratorBase<ConstRowIterator, const QRangeModelAdapter>;
0948     public:
0949         using Base::Base;
0950 
0951         using difference_type = typename Base::difference_type;
0952         using value_type = std::conditional_t<is_list<Impl>,
0953                                               const_data_type,
0954                                               ConstRowReference>;
0955         using reference = std::conditional_t<is_list<Impl>,
0956                                              const_data_type,
0957                                              ConstRowReference>;
0958         using pointer = std::conditional_t<is_list<Impl>,
0959                                            QRangeModelDetails::data_pointer_t<const_data_type>,
0960                                            ConstRowReference>;
0961 
0962         ConstRowIterator(const ConstRowIterator &other) = default;
0963         ConstRowIterator(ConstRowIterator &&other) = default;
0964         ConstRowIterator &operator=(const ConstRowIterator &other) = default;
0965         ConstRowIterator &operator=(ConstRowIterator &&other) = default;
0966         ~ConstRowIterator() = default;
0967 
0968         pointer operator->() const
0969         {
0970             return pointer{operator*()};
0971         }
0972 
0973         reference operator*() const
0974         {
0975             if constexpr (is_list<Impl>) {
0976                 return this->m_adapter->at(this->m_row);
0977             } else {
0978                 const QModelIndex index = this->m_adapter->model()->index(this->m_row, 0,
0979                                                                           this->root());
0980                 return ConstRowReference{index, this->m_adapter};
0981             }
0982         }
0983 
0984         reference operator[](difference_type n) const
0985         {
0986             return *(*this + n);
0987         }
0988     };
0989 
0990     struct RowIterator : public RowIteratorBase<RowIterator, QRangeModelAdapter>
0991     {
0992     private:
0993         using Base = RowIteratorBase<RowIterator, QRangeModelAdapter>;
0994     public:
0995         using Base::Base;
0996 
0997         using difference_type = typename Base::difference_type;
0998         using value_type = std::conditional_t<is_list<Impl>,
0999                                               DataReference,
1000                                               RowReference>;
1001         using reference = std::conditional_t<is_list<Impl>,
1002                                              DataReference,
1003                                              RowReference>;
1004         using pointer = std::conditional_t<is_list<Impl>,
1005                                            DataReference,
1006                                            RowReference>;
1007 
1008         RowIterator(const RowIterator &other) = default;
1009         RowIterator(RowIterator &&other) = default;
1010         RowIterator &operator=(const RowIterator &other) = default;
1011         RowIterator &operator=(RowIterator &&other) = default;
1012         ~RowIterator() = default;
1013 
1014         operator ConstRowIterator() const
1015         {
1016             return ConstRowIterator{this->m_row, this->root(), this->m_adapter};
1017         }
1018 
1019         pointer operator->() const
1020         {
1021             return pointer{operator*()};
1022         }
1023 
1024         reference operator*() const
1025         {
1026             const QModelIndex index = this->m_adapter->model()->index(this->m_row, 0, this->root());
1027             if constexpr (is_list<Impl>) {
1028                 return reference{index};
1029             } else {
1030                 return reference{index, this->m_adapter};
1031             }
1032         }
1033 
1034         reference operator[](difference_type n) const
1035         {
1036             return *(*this + n);
1037         }
1038     };
1039 
1040     using const_iterator = ConstRowIterator;
1041     using iterator = RowIterator;
1042 
1043     template <typename R,
1044               typename P,
1045               if_compatible_model_params<R, P> = true>
1046     explicit QRangeModelAdapter(R &&range, P &&protocol)
1047         : QRangeModelAdapter(new Model(QRangeModelDetails::forwardOrConvert<Range>(std::forward<R>(range)),
1048                                        QRangeModelDetails::forwardOrConvert<Protocol>(std::forward<P>(protocol))))
1049     {}
1050 
1051     template <typename R,
1052               typename P = void, // to enable the ctr for void protocols only
1053               if_compatible_model_params<R, P> = true,
1054               unless_adapter<R> = true>
1055     explicit QRangeModelAdapter(R &&range)
1056         : QRangeModelAdapter(new Model(QRangeModelDetails::forwardOrConvert<Range>(std::forward<R>(range))))
1057     {}
1058 
1059     // compiler-generated copy/move SMF are fine!
1060 
1061     Model *model() const
1062     {
1063         return storage.m_model.get();
1064     }
1065 
1066     const range_type &range() const
1067     {
1068         return QRangeModelDetails::refTo(storage.implementation()->childRange(storage.root()));
1069     }
1070 
1071     template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
1072     void assign(NewRange &&newRange)
1073     {
1074         assignImpl(qsizetype(Impl::size(QRangeModelDetails::refTo(newRange))),
1075             [&newRange](auto &oldRange) {
1076             oldRange = std::forward<NewRange>(newRange);
1077         });
1078     }
1079 
1080     template <typename NewRange = range_type, if_assignable_range<NewRange> = true,
1081               unless_adapter<NewRange> = true>
1082     QRangeModelAdapter &operator=(NewRange &&newRange)
1083     {
1084         assign(std::forward<NewRange>(newRange));
1085         return *this;
1086     }
1087 
1088     template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
1089     void assign(std::initializer_list<Row> newRange)
1090     {
1091         assignImpl(newRange.size(), [&newRange](auto &oldRange) {
1092             oldRange = newRange;
1093         });
1094     }
1095 
1096     template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
1097     QRangeModelAdapter &operator=(std::initializer_list<Row> newRange)
1098     {
1099         assign(newRange);
1100         return *this;
1101     }
1102 
1103     template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
1104     void assign(InputIterator first, Sentinel last)
1105     {
1106         assignImpl(size_t(std::distance(first, last)), [first, last](auto &oldRange) {
1107             oldRange.assign(first, last);
1108         });
1109     }
1110 
1111     // iterator API
1112     ConstRowIterator cbegin() const
1113     {
1114         return ConstRowIterator{ 0, storage.root(), this };
1115     }
1116     ConstRowIterator begin() const { return cbegin(); }
1117 
1118     ConstRowIterator cend() const
1119     {
1120         return ConstRowIterator{ rowCount(), storage.root(), this };
1121     }
1122     ConstRowIterator end() const { return cend(); }
1123 
1124     template <typename I = Impl, if_writable<I> = true>
1125     RowIterator begin()
1126     {
1127         return RowIterator{ 0, storage.root(), this };
1128     }
1129 
1130     template <typename I = Impl, if_writable<I> = true>
1131     RowIterator end()
1132     {
1133         return RowIterator{ rowCount(), storage.root(), this };
1134     }
1135 
1136     int size() const
1137     {
1138         return rowCount();
1139     }
1140 
1141     template <typename I = Impl, if_list<I> = true>
1142     QModelIndex index(int row) const
1143     {
1144         return storage->index(row, 0, storage.root());
1145     }
1146 
1147     template <typename I = Impl, unless_list<I> = true>
1148     QModelIndex index(int row, int column) const
1149     {
1150         return storage->index(row, column, storage.root());
1151     }
1152 
1153     template <typename I = Impl, if_tree<I> = true>
1154     QModelIndex index(QSpan<const int> path, int col) const
1155     {
1156         QModelIndex result = storage.root();
1157         auto count = path.size();
1158         for (const int r : path) {
1159             if (--count)
1160                 result = storage->index(r, 0, result);
1161             else
1162                 result = storage->index(r, col, result);
1163         }
1164         return result;
1165     }
1166 
1167     int columnCount() const
1168     {
1169         // all rows and tree branches have the same column count
1170         return storage->columnCount({});
1171     }
1172 
1173     int rowCount() const
1174     {
1175         return storage->rowCount(storage.root());
1176     }
1177 
1178     template <typename I = Impl, if_tree<I> = true>
1179     int rowCount(int row) const
1180     {
1181         return storage->rowCount(index(row, 0));
1182     }
1183 
1184     template <typename I = Impl, if_tree<I> = true>
1185     int rowCount(QSpan<const int> path) const
1186     {
1187         return storage->rowCount(index(path, 0));
1188     }
1189 
1190     template <typename I = Impl, if_tree<I> = true>
1191     constexpr bool hasChildren(int row) const
1192     {
1193         return storage.m_model->hasChildren(index(row, 0));
1194     }
1195 
1196     template <typename I = Impl, if_tree<I> = true>
1197     constexpr bool hasChildren(QSpan<const int> path) const
1198     {
1199         return storage.m_model->hasChildren(index(path, 0));
1200     }
1201 
1202     template <typename I = Impl, if_list<I> = true>
1203     QVariant data(int row) const
1204     {
1205         return QRangeModelDetails::dataAtIndex<QVariant>(index(row));
1206     }
1207 
1208     template <typename I = Impl, if_list<I> = true>
1209     QVariant data(int row, int role) const
1210     {
1211         return QRangeModelDetails::dataAtIndex<QVariant>(index(row), role);
1212     }
1213 
1214     template <typename I = Impl, if_list<I> = true, if_writable<I> = true>
1215     bool setData(int row, const QVariant &value, int role = Qt::EditRole)
1216     {
1217         return storage->setData(index(row), value, role);
1218     }
1219 
1220     template <typename I = Impl, unless_list<I> = true>
1221     QVariant data(int row, int column) const
1222     {
1223         return QRangeModelDetails::dataAtIndex<QVariant>(index(row, column));
1224     }
1225 
1226     template <typename I = Impl, unless_list<I> = true>
1227     QVariant data(int row, int column, int role) const
1228     {
1229         return QRangeModelDetails::dataAtIndex<QVariant>(index(row, column), role);
1230     }
1231 
1232     template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1233     bool setData(int row, int column, const QVariant &value, int role = Qt::EditRole)
1234     {
1235         return storage->setData(index(row, column), value, role);
1236     }
1237 
1238     template <typename I = Impl, if_tree<I> = true>
1239     QVariant data(QSpan<const int> path, int column) const
1240     {
1241         return QRangeModelDetails::dataAtIndex<QVariant>(index(path, column));
1242     }
1243 
1244     template <typename I = Impl, if_tree<I> = true>
1245     QVariant data(QSpan<const int> path, int column, int role) const
1246     {
1247         return QRangeModelDetails::dataAtIndex<QVariant>(index(path, column), role);
1248     }
1249 
1250     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1251     bool setData(QSpan<const int> path, int column, const QVariant &value, int role = Qt::EditRole)
1252     {
1253         return storage->setData(index(path, column), value, role);
1254     }
1255 
1256     // at/operator[int] for list: returns value at row
1257     // if multi-role value: return the entire object
1258     template <typename I= Impl, if_list<I> = true>
1259     const_data_type at(int row) const
1260     {
1261         return QRangeModelDetails::dataAtIndex<data_type>(index(row));
1262     }
1263     template <typename I = Impl, if_list<I> = true>
1264     const_data_type operator[](int row) const { return at(row); }
1265 
1266     template <typename I= Impl, if_list<I> = true, if_writable<I> = true>
1267     auto at(int row) {
1268         const QModelIndex idx = this->index(row);
1269         Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at row is invalid");
1270         return DataReference{idx};
1271     }
1272     template <typename I = Impl, if_list<I> = true, if_writable<I> = true>
1273     auto operator[](int row) {
1274         const QModelIndex idx = this->index(row);
1275         Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at row is invalid");
1276         return DataReference{idx};
1277     }
1278 
1279     // at/operator[int] for table or tree: a reference or view of the row
1280     template <typename I = Impl, unless_list<I> = true>
1281     decltype(auto) at(int row) const
1282     {
1283         return ConstRowReference{index(row, 0), this}.get();
1284     }
1285     template <typename I = Impl, unless_list<I> = true>
1286     decltype(auto) operator[](int row) const { return at(row); }
1287 
1288     template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
1289     auto at(int row)
1290     {
1291         return RowReference{index(row, 0), this};
1292     }
1293     template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
1294     auto operator[](int row) { return at(row); }
1295 
1296     // at/operator[int, int] for table: returns value at row/column
1297     template <typename I = Impl, unless_list<I> = true>
1298     const_data_type at(int row, int column) const
1299     {
1300         return QRangeModelDetails::dataAtIndex<data_type>(index(row, column));
1301     }
1302 
1303 #ifdef __cpp_multidimensional_subscript
1304     template <typename I = Impl, unless_list<I> = true>
1305     const_data_type operator[](int row, int column) const { return at(row, column); }
1306 #endif
1307 
1308     template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1309     auto at(int row, int column)
1310     {
1311         const QModelIndex idx = this->index(row, column);
1312         Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at cell is invalid");
1313         return DataReference{idx};
1314     }
1315 #ifdef __cpp_multidimensional_subscript
1316     template <typename I = Impl, unless_list<I> = true, if_writable<I> = true>
1317     auto operator[](int row, int column)
1318     {
1319         const QModelIndex idx = this->index(row, column);
1320         Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at cell is invalid");
1321         return DataReference{idx};
1322     }
1323 #endif
1324 
1325     // at/operator[int] for tree: return a wrapper that maintains reference to
1326     // parent.
1327     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1328     auto at(int row)
1329     {
1330         return RowReference{index(row, 0), this};
1331     }
1332     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1333     auto operator[](int row) { return at(row); }
1334 
1335     // at/operator[path] for tree: a reference or view of the row
1336     template <typename I = Impl, if_tree<I> = true>
1337     decltype(auto) at(QSpan<const int> path) const
1338     {
1339         return ConstRowReference{index(path, 0), this}.get();
1340     }
1341     template <typename I = Impl, if_tree<I> = true>
1342     decltype(auto) operator[](QSpan<const int> path) const { return at(path); }
1343 
1344     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1345     auto at(QSpan<const int> path)
1346     {
1347         return RowReference{index(path, 0), this};
1348     }
1349     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1350     auto operator[](QSpan<const int> path) { return at(path); }
1351 
1352     // at/operator[path, column] for tree: return value
1353     template <typename I = Impl, if_tree<I> = true>
1354     const_data_type at(QSpan<const int> path, int column) const
1355     {
1356         Q_PRE(path.size());
1357         return QRangeModelDetails::dataAtIndex<data_type>(index(path, column));
1358     }
1359 
1360 #ifdef __cpp_multidimensional_subscript
1361     template <typename I = Impl, if_tree<I> = true>
1362     const_data_type operator[](QSpan<const int> path, int column) const { return at(path, column); }
1363 #endif
1364 
1365     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1366     auto at(QSpan<const int> path, int column)
1367     {
1368         Q_PRE(path.size());
1369         const QModelIndex idx = this->index(path, column);
1370         Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::at", "Index at path is invalid");
1371         return DataReference{idx};
1372     }
1373 #ifdef __cpp_multidimensional_subscript
1374     template <typename I = Impl, if_tree<I> = true, if_writable<I> = true>
1375     auto operator[](QSpan<const int> path, int column)
1376     {
1377         const QModelIndex idx = this->index(path, column);
1378         Q_ASSERT_X(idx.isValid(), "QRangeModelAdapter::operator[]", "Index at path is invalid");
1379         return DataReference{idx};
1380     }
1381 #endif
1382 
1383     template <typename I = Impl, if_canInsertRows<I> = true>
1384     bool insertRow(int before)
1385     {
1386         return storage.m_model->insertRow(before);
1387     }
1388 
1389     template <typename I = Impl, if_canInsertRows<I> = true, if_tree<I> = true>
1390     bool insertRow(QSpan<const int> before)
1391     {
1392         Q_PRE(before.size());
1393         return storage.m_model->insertRow(before.back(), this->index(before.first(before.size() - 1), 0));
1394     }
1395 
1396     template <typename D = row_type, typename I = Impl,
1397               if_canInsertRows<I> = true, if_compatible_row<D> = true>
1398     bool insertRow(int before, D &&data)
1399     {
1400         return insertRowImpl(before, storage.root(), std::forward<D>(data));
1401     }
1402 
1403     template <typename D = row_type, typename I = Impl,
1404               if_canInsertRows<I> = true, if_compatible_row<D> = true, if_tree<I> = true>
1405     bool insertRow(QSpan<const int> before, D &&data)
1406     {
1407         return insertRowImpl(before.back(), this->index(before.sliced(0, before.size() - 1), 0),
1408                              std::forward<D>(data));
1409     }
1410 
1411     template <typename C, typename I = Impl,
1412               if_canInsertRows<I> = true, if_compatible_row_range<C> = true>
1413     bool insertRows(int before, C &&data)
1414     {
1415         return insertRowsImpl(before, storage.root(), std::forward<C>(data));
1416     }
1417 
1418     template <typename C, typename I = Impl,
1419               if_canInsertRows<I> = true, if_compatible_row_range<C> = true, if_tree<I> = true>
1420     bool insertRows(QSpan<const int> before, C &&data)
1421     {
1422         return insertRowsImpl(before.back(), this->index(before.sliced(0, before.size() - 1), 0),
1423                               std::forward<C>(data));
1424     }
1425 
1426     template <typename I = Impl, if_canRemoveRows<I> = true>
1427     bool removeRow(int row)
1428     {
1429         return removeRows(row, 1);
1430     }
1431 
1432     template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1433     bool removeRow(QSpan<const int> path)
1434     {
1435         return removeRows(path, 1);
1436     }
1437 
1438     template <typename I = Impl, if_canRemoveRows<I> = true>
1439     bool removeRows(int row, int count)
1440     {
1441         return storage->removeRows(row, count, storage.root());
1442     }
1443 
1444     template <typename I = Impl, if_canRemoveRows<I> = true, if_tree<I> = true>
1445     bool removeRows(QSpan<const int> path, int count)
1446     {
1447         return storage->removeRows(path.back(), count,
1448                                    this->index(path.first(path.size() - 1), 0));
1449     }
1450 
1451     template <typename F = range_features, if_canMoveItems<F> = true>
1452     bool moveRow(int source, int destination)
1453     {
1454         return moveRows(source, 1, destination);
1455     }
1456 
1457     template <typename F = range_features, if_canMoveItems<F> = true>
1458     bool moveRows(int source, int count, int destination)
1459     {
1460         return storage->moveRows(storage.root(), source, count, storage.root(), destination);
1461     }
1462 
1463     template <typename I = Impl, typename F = range_features,
1464               if_canMoveItems<F> = true, if_tree<I> = true>
1465     bool moveRow(QSpan<const int> source, QSpan<const int> destination)
1466     {
1467         return moveRows(source, 1, destination);
1468     }
1469 
1470     template <typename I = Impl, typename F = range_features,
1471               if_canMoveItems<F> = true, if_tree<I> = true>
1472     bool moveRows(QSpan<const int> source, int count, QSpan<const int> destination)
1473     {
1474         return storage->moveRows(this->index(source.first(source.size() - 1), 0),
1475                                  source.back(),
1476                                  count,
1477                                  this->index(destination.first(destination.size() - 1), 0),
1478                                  destination.back());
1479     }
1480 
1481     template <typename I = Impl, if_canInsertColumns<I> = true>
1482     bool insertColumn(int before)
1483     {
1484         return storage.m_model->insertColumn(before);
1485     }
1486 
1487     template <typename D, typename I = Impl,
1488               if_canInsertColumns<I> = true, if_compatible_column_data<D> = true>
1489     bool insertColumn(int before, D &&data)
1490     {
1491         return insertColumnImpl(before, storage.root(), std::forward<D>(data));
1492     }
1493 
1494     template <typename C, typename I = Impl,
1495               if_canInsertColumns<I> = true, if_compatible_column_range<C> = true>
1496     bool insertColumns(int before, C &&data)
1497     {
1498         return insertColumnsImpl(before, storage.root(), std::forward<C>(data));
1499     }
1500 
1501     template <typename I = Impl, if_canRemoveColumns<I> = true>
1502     bool removeColumn(int column)
1503     {
1504         return storage.m_model->removeColumn(column);
1505     }
1506 
1507     template <typename I = Impl, if_canRemoveColumns<I> = true>
1508     bool removeColumns(int column, int count)
1509     {
1510         return storage->removeColumns(column, count, {});
1511     }
1512 
1513     template <typename F = row_features, if_canMoveItems<F> = true>
1514     bool moveColumn(int from, int to)
1515     {
1516         return moveColumns(from, 1, to);
1517     }
1518 
1519     template <typename F = row_features, if_canMoveItems<F> = true>
1520     bool moveColumns(int from, int count, int to)
1521     {
1522         return storage->moveColumns(storage.root(), from, count, storage.root(), to);
1523     }
1524 
1525     template <typename I = Impl, typename F = row_features,
1526               if_canMoveItems<F> = true, if_tree<I> = true>
1527     bool moveColumn(QSpan<const int> source, int to)
1528     {
1529         const QModelIndex parent = this->index(source.first(source.size() - 1), 0);
1530         return storage->moveColumns(parent, source.back(), 1, parent, to);
1531     }
1532 
1533     template <typename I = Impl, typename F = row_features,
1534               if_canMoveItems<F> = true, if_tree<I> = true>
1535     bool moveColumns(QSpan<const int> source, int count, int destination)
1536     {
1537         const QModelIndex parent = this->index(source.first(source.size() - 1), 0);
1538         return storage->moveColumns(parent, source.back(), count, parent, destination);
1539     }
1540 
1541 private:
1542     friend inline
1543     bool comparesEqual(const QRangeModelAdapter &lhs, const QRangeModelAdapter &rhs) noexcept
1544     {
1545         return lhs.storage.m_model == rhs.storage.m_model;
1546     }
1547     Q_DECLARE_EQUALITY_COMPARABLE(QRangeModelAdapter)
1548 
1549     friend inline
1550     bool comparesEqual(const QRangeModelAdapter &lhs, const range_type &rhs)
1551     {
1552         return lhs.range() == rhs;
1553     }
1554     Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(QRangeModelAdapter, range_type)
1555 
1556 
1557     void emitDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
1558     {
1559         Q_EMIT storage.implementation()->dataChanged(topLeft, bottomRight, {});
1560     }
1561 
1562     void beginAssignImpl(Impl *impl, range_type *oldRange, int newLastRow)
1563     {
1564         const QModelIndex root = storage.root();
1565         const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
1566 
1567         if (!root.isValid()) {
1568             impl->beginResetModel();
1569             impl->deleteOwnedRows();
1570         } else if constexpr (is_tree<Impl>) {
1571             if (oldLastRow >= 0) {
1572                 impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
1573                 impl->deleteRemovedRows(QRangeModelDetails::refTo(oldRange));
1574                 impl->endRemoveRows();
1575             }
1576             if (newLastRow >= 0)
1577                 impl->beginInsertRows(root, 0, newLastRow);
1578         } else {
1579             Q_ASSERT_X(false, "QRangeModelAdapter::assign",
1580                        "Internal error: The root index in a table or list must be invalid.");
1581         }
1582     }
1583 
1584     void endAssignImpl(Impl *impl, int newLastRow)
1585     {
1586         const QModelIndex root = storage.root();
1587         if (!root.isValid()) {
1588             impl->endResetModel();
1589         } else if constexpr (is_tree<Impl>) {
1590             if (newLastRow >= 0) {
1591                 Q_ASSERT(model()->hasChildren(root));
1592                 // if it was moved, then newRange is now likely to be empty. Get
1593                 // the inserted row.
1594                 impl->setParentRow(QRangeModelDetails::refTo(impl->childRange(root)),
1595                                    QRangeModelDetails::pointerTo(impl->rowData(root)));
1596                 impl->endInsertRows();
1597             }
1598         }
1599     }
1600 
1601     template <typename Assigner>
1602     void assignImpl(std::size_t newSize, Assigner &&assigner)
1603     {
1604         const auto sz = q26::saturating_cast<int>(newSize);
1605         Q_ASSERT_X(q20::cmp_equal(sz, newSize),
1606                    "QRangeModelAdapter::assign", "New range is too large");
1607         const int newLastRow = sz - 1;
1608 
1609         auto *impl = storage.implementation();
1610         auto *oldRange = impl->childRange(storage.root());
1611         beginAssignImpl(impl, oldRange, newLastRow);
1612         assigner(QRangeModelDetails::refTo(oldRange));
1613         endAssignImpl(impl, newLastRow);
1614 
1615         if constexpr (Impl::itemsAreQObjects) {
1616             if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
1617                 const auto begin = QRangeModelDetails::begin(QRangeModelDetails::refTo(oldRange));
1618                 const auto end = QRangeModelDetails::end(QRangeModelDetails::refTo(oldRange));
1619                 int rowIndex = 0;
1620                 for (auto it = begin; it != end; ++it, ++rowIndex)
1621                     impl->autoConnectPropertiesInRow(*it, rowIndex, storage.root());
1622             }
1623         }
1624     }
1625 
1626 
1627     template <typename P, typename Row>
1628     static auto setParentRow(P &protocol, Row &newRow, row_ptr parentRow)
1629         -> decltype(protocol.setParentRow(newRow, parentRow))
1630     {
1631         return protocol.setParentRow(newRow, parentRow);
1632     }
1633     template <typename ...Args> static constexpr void setParentRow(Args &&...)
1634     {
1635         static_assert(!protocol_traits::has_setParentRow,
1636                       "Internal error, wrong setParentRow overload called");
1637     }
1638 
1639     template <typename D>
1640     bool insertRowImpl(int before, const QModelIndex &parent, D &&data)
1641     {
1642         return storage.implementation()->doInsertRows(before, 1, parent, [&data, this]
1643                                         (range_type &range, auto *parentRow, int row, int count) {
1644             Q_UNUSED(this);
1645             const auto oldSize = range.size();
1646             auto newRow = range.emplace(QRangeModelDetails::pos(range, row), std::forward<D>(data));
1647             setParentRow(storage->protocol(), QRangeModelDetails::refTo(*newRow),
1648                                               QRangeModelDetails::pointerTo(parentRow));
1649             return range.size() == oldSize + count;
1650         });
1651     }
1652 
1653     template <typename LHS>
1654     static auto selfInsertion(LHS *lhs, LHS *rhs) -> decltype(lhs == rhs)
1655     {
1656         if (lhs == rhs) {
1657 #ifndef QT_NO_DEBUG
1658             qCritical("Inserting data into itself is not supported");
1659 #endif
1660             return true;
1661         }
1662         return false;
1663     }
1664     template <typename LHS, typename RHS>
1665     static constexpr bool selfInsertion(LHS *, RHS *) { return false; }
1666 
1667     template <typename C>
1668     bool insertRowsImpl(int before, const QModelIndex &parent, C &&data)
1669     {
1670         bool result = false;
1671         result = storage->doInsertRows(before, int(std::size(data)), parent, [&data, this]
1672                                         (range_type &range, auto *parentRow, int row, int count){
1673             Q_UNUSED(parentRow);
1674             Q_UNUSED(this);
1675             const auto pos = QRangeModelDetails::pos(range, row);
1676             const auto oldSize = range.size();
1677 
1678             auto dataRange = [&data]{
1679                 if constexpr (std::is_rvalue_reference_v<C&&>) {
1680                     return std::make_pair(
1681                         std::move_iterator(std::begin(data)),
1682                         std::move_iterator(std::end(data))
1683                     );
1684                 } else {
1685                     return std::make_pair(std::begin(data), std::end(data));
1686                 }
1687             }();
1688 
1689             if constexpr (range_features::has_insert_range) {
1690                 if (selfInsertion(&range, &data))
1691                     return false;
1692                 auto start = range.insert(pos, dataRange.first, dataRange.second);
1693                 if constexpr (protocol_traits::has_setParentRow) {
1694                     while (count) {
1695                         setParentRow(storage->protocol(), QRangeModelDetails::refTo(*start),
1696                                                           QRangeModelDetails::pointerTo(parentRow));
1697                         ++start;
1698                         --count;
1699                     }
1700                 } else {
1701                     Q_UNUSED(start);
1702                 }
1703             } else {
1704                 auto newRow = range.insert(pos, count, row_type{});
1705                 while (dataRange.first != dataRange.second) {
1706                     *newRow = *dataRange.first;
1707                     setParentRow(storage->protocol(), QRangeModelDetails::refTo(*newRow),
1708                                                       QRangeModelDetails::pointerTo(parentRow));
1709                     ++dataRange.first;
1710                     ++newRow;
1711                 }
1712             }
1713             return range.size() == oldSize + count;
1714         });
1715         return result;
1716     }
1717 
1718     template <typename D, typename = void>
1719     struct DataFromList {
1720         static constexpr auto first(D &data) { return &data; }
1721         static constexpr auto next(D &, D *entry) { return entry; }
1722     };
1723 
1724     template <typename D>
1725     struct DataFromList<D, std::enable_if_t<QRangeModelDetails::range_traits<D>::value>>
1726     {
1727         static constexpr auto first(D &data) { return std::begin(data); }
1728         static constexpr auto next(D &data, typename D::iterator entry)
1729         {
1730             ++entry;
1731             if (entry == std::end(data))
1732                 entry = first(data);
1733             return entry;
1734         }
1735     };
1736 
1737     template <typename D, typename = void> struct RowFromTable
1738     {
1739         static constexpr auto first(D &data) { return &data; }
1740         static constexpr auto next(D &, D *entry) { return entry; }
1741     };
1742 
1743     template <typename D>
1744     struct RowFromTable<D, std::enable_if_t<std::conjunction_v<
1745                                             QRangeModelDetails::range_traits<D>,
1746                                             QRangeModelDetails::range_traits<typename D::value_type>
1747                                            >>
1748                         > : DataFromList<D>
1749     {};
1750 
1751     template <typename D>
1752     bool insertColumnImpl(int before, const QModelIndex &parent, D data)
1753     {
1754         auto entry = DataFromList<D>::first(data);
1755 
1756         return storage->doInsertColumns(before, 1, parent, [&entry, &data]
1757                                         (auto &range, auto pos, int count) {
1758             const auto oldSize = range.size();
1759             range.insert(pos, *entry);
1760             entry = DataFromList<D>::next(data, entry);
1761             return range.size() == oldSize + count;
1762         });
1763     }
1764 
1765     template <typename C>
1766     bool insertColumnsImpl(int before, const QModelIndex &parent, C data)
1767     {
1768         bool result = false;
1769         auto entries = RowFromTable<C>::first(data);
1770         auto begin = std::begin(*entries);
1771         auto end = std::end(*entries);
1772         result = storage->doInsertColumns(before, int(std::size(*entries)), parent,
1773                             [&begin, &end, &entries, &data](auto &range, auto pos, int count) {
1774             const auto oldSize = range.size();
1775             if constexpr (row_features::has_insert_range) {
1776                 range.insert(pos, begin, end);
1777             } else {
1778                 auto start = range.insert(pos, count, {});
1779                 std::copy(begin, end, start);
1780             }
1781             entries = RowFromTable<C>::next(data, entries);
1782             begin = std::begin(*entries);
1783             end = std::end(*entries);
1784             return range.size() == oldSize + count;
1785         });
1786         return result;
1787     }
1788 };
1789 
1790 // Deduction guides are needed to correctly map single-parameter construction
1791 // to the void-protocol case, and to disable construction from incompatible
1792 // ranges.
1793 template <typename Range, typename Protocol,
1794           QRangeModelDetails::if_can_construct<Range, Protocol> = true>
1795 QRangeModelAdapter(Range &&, Protocol &&) -> QRangeModelAdapter<Range, Protocol>;
1796 
1797 template <typename Range,
1798           QRangeModelDetails::if_can_construct<Range> = true>
1799 QRangeModelAdapter(Range &&) -> QRangeModelAdapter<Range, void>;
1800 
1801 QT_END_NAMESPACE
1802 
1803 #endif // QRANGEMODELADAPTER_H