// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLLISTCOMPOSITOR_P_H #define QQMLLISTCOMPOSITOR_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include QT_BEGIN_NAMESPACE class Q_AUTOTEST_EXPORT QQmlListCompositor { public: enum { MinimumGroupCount = 3, MaximumGroupCount = 11 }; enum Group { Cache = 0, Default = 1, Persisted = 2 }; enum Flag { CacheFlag = 1 << Cache, DefaultFlag = 1 << Default, PersistedFlag = 1 << Persisted, PrependFlag = 0x10000000, AppendFlag = 0x20000000, UnresolvedFlag = 0x40000000, MovedFlag = 0x80000000, GroupMask = ~(PrependFlag | AppendFlag | UnresolvedFlag | MovedFlag | CacheFlag) }; class Range { public: Range() : next(this), previous(this) {} Range(Range *next, void *list, int index, int count, uint flags) : next(next), previous(next->previous), list(list), index(index), count(count), flags(flags) { next->previous = this; previous->next = this; } Range *next; Range *previous; void *list = nullptr; int index = 0; int count = 0; uint flags = 0; inline int start() const { return index; } inline int end() const { return index + count; } inline int groups() const { return flags & GroupMask; } inline bool inGroup() const { return flags & GroupMask; } inline bool inCache() const { return flags & CacheFlag; } inline bool inGroup(int group) const { return flags & (1 << group); } inline bool isUnresolved() const { return flags & UnresolvedFlag; } inline bool prepend() const { return flags & PrependFlag; } inline bool append() const { return flags & AppendFlag; } }; class Q_AUTOTEST_EXPORT iterator { public: inline iterator() = default; inline iterator(Range *range, int offset, Group group, int groupCount); bool operator ==(const iterator &it) const { return range == it.range && offset == it.offset; } bool operator !=(const iterator &it) const { return range != it.range || offset != it.offset; } bool operator ==(Group group) const { return range->flags & (1 << group); } bool operator !=(Group group) const { return !(range->flags & (1 << group)); } Range *&operator *() { return range; } Range * const &operator *() const { return range; } Range *operator ->() { return range; } const Range *operator ->() const { return range; } iterator &operator +=(int difference); template T *list() const { return static_cast(range->list); } int modelIndex() const { return range->index + offset; } void incrementIndexes(int difference) { incrementIndexes(difference, range->flags); } void decrementIndexes(int difference) { decrementIndexes(difference, range->flags); } inline void incrementIndexes(int difference, uint flags); inline void decrementIndexes(int difference, uint flags); void setGroup(Group g) { group = g; groupFlag = 1 << g; } Range *range = nullptr; int offset = 0; Group group = Default; int groupFlag = 0; int groupCount = 0; int index[MaximumGroupCount] = { 0 }; int cacheIndex() const { return index[Cache]; } void setCacheIndex(int cacheIndex) { index[Cache] = cacheIndex; } }; class Q_AUTOTEST_EXPORT insert_iterator : public iterator { public: inline insert_iterator() {} inline insert_iterator(const iterator &it) : iterator(it) {} inline insert_iterator(Range *, int, Group, int); inline ~insert_iterator() {} insert_iterator &operator +=(int difference); }; struct Change { inline Change() = default; inline Change(const iterator &it, int count, uint flags, int moveId = -1); int count = 0; uint flags = 0; int moveId = 0; int index[MaximumGroupCount] = { 0 }; int cacheIndex() const { return index[Cache]; } void setCacheIndex(int cacheIndex) { index[Cache] = cacheIndex; } inline bool isMove() const { return moveId >= 0; } inline bool inCache() const { return flags & CacheFlag; } inline bool inGroup() const { return flags & GroupMask; } inline bool inGroup(int group) const { return flags & (CacheFlag << group); } inline int groups() const { return flags & GroupMask; } }; struct Insert : public Change { Insert() {} Insert(const iterator &it, int count, uint flags, int moveId = -1) : Change(it, count, flags, moveId) {} }; struct Remove : public Change { Remove() {} Remove(const iterator &it, int count, uint flags, int moveId = -1) : Change(it, count, flags, moveId) {} }; QQmlListCompositor(); ~QQmlListCompositor(); int defaultGroups() const { return m_defaultFlags & ~PrependFlag; } void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; } void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); } void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); } void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; } void setGroupCount(int count); int count(Group group) const; iterator find(Group group, int index); iterator find(Group group, int index) const; insert_iterator findInsertPosition(Group group, int index); const iterator &end() { return m_end; } void append(void *list, int index, int count, uint flags, QVector *inserts = nullptr); void insert(Group group, int before, void *list, int index, int count, uint flags, QVector *inserts = nullptr); iterator insert(iterator before, void *list, int index, int count, uint flags, QVector *inserts = nullptr); void setFlags(Group fromGroup, int from, int count, Group group, int flags, QVector *inserts = nullptr); void setFlags(iterator from, int count, Group group, uint flags, QVector *inserts = nullptr); void setFlags(Group fromGroup, int from, int count, uint flags, QVector *inserts = nullptr) { setFlags(fromGroup, from, count, fromGroup, flags, inserts); } void setFlags(const iterator from, int count, uint flags, QVector *inserts = nullptr) { setFlags(from, count, from.group, flags, inserts); } void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector *removals = nullptr); void clearFlags(iterator from, int count, Group group, uint flags, QVector *removals = nullptr); void clearFlags(Group fromGroup, int from, int count, uint flags, QVector *removals = nullptr) { clearFlags(fromGroup, from, count, fromGroup, flags, removals); } void clearFlags(const iterator &from, int count, uint flags, QVector *removals = nullptr) { clearFlags(from, count, from.group, flags, removals); } bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count, Group group) const; void move( Group fromGroup, int from, Group toGroup, int to, int count, Group group, QVector *removals = nullptr, QVector *inserts = nullptr); void clear(); void listItemsInserted(void *list, int index, int count, QVector *inserts); void listItemsRemoved(void *list, int index, int count, QVector *removals); void listItemsMoved(void *list, int from, int to, int count, QVector *removals, QVector *inserts); void listItemsChanged(void *list, int index, int count, QVector *changes); void transition( Group from, Group to, QVector *removes, QVector *inserts); private: Range m_ranges; iterator m_end; iterator m_cacheIt; int m_groupCount; int m_defaultFlags; int m_removeFlags; int m_moveId; inline Range *insert(Range *before, void *list, int index, int count, uint flags); inline Range *erase(Range *range); struct MovedFlags { MovedFlags() {} MovedFlags(int moveId, uint flags) : moveId(moveId), flags(flags) {} int moveId; uint flags; }; void listItemsRemoved( QVector *translatedRemovals, void *list, QVector *removals, QVector *insertions = nullptr, QVector *movedFlags = nullptr); void listItemsInserted( QVector *translatedInsertions, void *list, const QVector &insertions, const QVector *movedFlags = nullptr); void listItemsChanged( QVector *translatedChanges, void *list, const QVector &changes); friend Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list); }; Q_DECLARE_TYPEINFO(QQmlListCompositor::Change, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QQmlListCompositor::Remove, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE); QT_WARNING_PUSH // GCC isn't wrong, as groupCount is public in iterator, but we tried Q_ASSUME(), // right in front of the loops, and it didn't help, so we disable the warning: QT_WARNING_DISABLE_GCC("-Warray-bounds") inline QQmlListCompositor::iterator::iterator( Range *range, int offset, Group group, int groupCount) : range(range) , offset(offset) , group(group) , groupFlag(1 << group) , groupCount(groupCount) { for (int i = 0; i < groupCount; ++i) index[i] = 0; } inline void QQmlListCompositor::iterator::incrementIndexes(int difference, uint flags) { for (int i = 0; i < groupCount; ++i) { if (flags & (1 << i)) index[i] += difference; } } inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint flags) { for (int i = 0; i < groupCount; ++i) { if (flags & (1 << i)) index[i] -= difference; } } QT_WARNING_POP // -Warray-bounds inline QQmlListCompositor::insert_iterator::insert_iterator( Range *range, int offset, Group group, int groupCount) : iterator(range, offset, group, groupCount) {} inline QQmlListCompositor::Change::Change(const iterator &it, int count, uint flags, int moveId) : count(count), flags(flags), moveId(moveId) { for (int i = 0; i < MaximumGroupCount; ++i) index[i] = it.index[i]; } Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group); Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range); Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it); Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change); Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove); Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert); Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list); QT_END_NAMESPACE #endif