/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QITERABLE_H #define QITERABLE_H #include #include #include #include QT_BEGIN_NAMESPACE namespace QtPrivate { template class QConstPreservingPointer { enum Tag : bool { Const, Mutable }; QTaggedPointer m_pointer; public: QConstPreservingPointer(std::nullptr_t) : m_pointer(nullptr, Const) {} QConstPreservingPointer(const void *pointer, qsizetype alignment) : m_pointer(reinterpret_cast(const_cast(pointer)), Const) { Q_UNUSED(alignment); Q_ASSERT(alignment > qsizetype(alignof(Storage))); } QConstPreservingPointer(void *pointer, qsizetype alignment) : m_pointer(reinterpret_cast(pointer), Mutable) { Q_UNUSED(alignment); Q_ASSERT(alignment > qsizetype(alignof(Storage))); } template QConstPreservingPointer(const InputType *pointer) : m_pointer(reinterpret_cast(const_cast(pointer)), Const) { static_assert(alignof(InputType) >= alignof(Storage)); } template QConstPreservingPointer(InputType *pointer) : m_pointer(reinterpret_cast(pointer), Mutable) { static_assert(alignof(InputType) >= alignof(Storage)); } QConstPreservingPointer() = default; const Type *constPointer() const { return reinterpret_cast(m_pointer.data()); } Type *mutablePointer() const { return m_pointer.tag() == Mutable ? reinterpret_cast(m_pointer.data()) : nullptr; } }; } template class QTaggedIterator : public Iterator { public: using iterator_category = IteratorCategory; QTaggedIterator(Iterator &&it) : Iterator(std::move(it)) { const QMetaContainer metaContainer = this->metaContainer(); if (std::is_base_of_v && !metaContainer.hasRandomAccessIterator()) { qFatal("You cannot use this iterator as a random access iterator"); this->clearIterator(); } if (std::is_base_of_v && !metaContainer.hasBidirectionalIterator()) { qFatal("You cannot use this iterator as a bidirectional iterator"); this->clearIterator(); } if (std::is_base_of_v && !metaContainer.hasForwardIterator()) { qFatal("You cannot use this iterator as a forward iterator"); this->clearIterator(); } if (std::is_base_of_v && !metaContainer.hasInputIterator()) { qFatal("You cannot use this iterator as an input iterator"); this->clearIterator(); } } bool operator==(const QTaggedIterator &o) const { return Iterator::operator==(o); } bool operator!=(const QTaggedIterator &o) const { return Iterator::operator!=(o); } QTaggedIterator &operator++() { Iterator::operator++(); return *this; } QTaggedIterator operator++(int x) { return QTaggedIterator(Iterator::operator++(x)); }; QTaggedIterator &operator--() { Iterator::operator--(); return *this; } QTaggedIterator operator--(int x) { return QTaggedIterator(Iterator::operator--(x)); }; QTaggedIterator &operator+=(qsizetype j) { Iterator::operator+=(j); return *this; } QTaggedIterator &operator-=(qsizetype j) { Iterator::operator-=(j); return *this; } QTaggedIterator operator+(qsizetype j) const { return QTaggedIterator(Iterator::operator+(j)); } QTaggedIterator operator-(qsizetype j) const { return QTaggedIterator(Iterator::operator-(j)); } qsizetype operator-(const QTaggedIterator &j) const { return Iterator::operator-(j); } bool operator<(const QTaggedIterator &j) { return operator-(j) < 0; } bool operator>=(const QTaggedIterator &j) { return !operator<(j); } bool operator>(const QTaggedIterator &j) { return operator-(j) > 0; } bool operator<=(const QTaggedIterator &j) { return !operator>(j); } friend inline QTaggedIterator operator+(qsizetype j, const QTaggedIterator &k) { return k + j; } }; template class QIterable; template class QBaseIterator { private: QtPrivate::QConstPreservingPointer> m_iterable; void *m_iterator = nullptr; protected: QBaseIterator() = default; QBaseIterator(const QIterable *iterable, void *iterator) : m_iterable(iterable), m_iterator(iterator) {} QBaseIterator(QIterable *iterable, void *iterator) : m_iterable(iterable), m_iterator(iterator) {} QBaseIterator(QBaseIterator &&other) : m_iterable(std::move(other.m_iterable)), m_iterator(std::move(other.m_iterator)) { other.m_iterator = nullptr; } QBaseIterator(const QBaseIterator &other) : m_iterable(other.m_iterable) { initIterator(other.m_iterator); } ~QBaseIterator() { clearIterator(); } QBaseIterator &operator=(QBaseIterator &&other) { if (this != &other) { clearIterator(); m_iterable = std::move(other.m_iterable); m_iterator = std::move(other.m_iterator); other.m_iterator = nullptr; } return *this; } QBaseIterator &operator=(const QBaseIterator &other) { if (this != &other) { clearIterator(); m_iterable = other.m_iterable; initIterator(other.m_iterator); } return *this; } QIterable *mutableIterable() const { return m_iterable.mutablePointer(); } const QIterable *constIterable() const { return m_iterable.constPointer(); } void initIterator(const void *copy) { if (!copy) return; if (auto *mutableIt = mutableIterable()) { m_iterator = metaContainer().begin(mutableIt->mutableIterable()); metaContainer().copyIterator(m_iterator, copy); } else if (auto *constIt = constIterable()) { m_iterator = metaContainer().constBegin(constIt->constIterable()); metaContainer().copyConstIterator(m_iterator, copy); } } void clearIterator() { if (!m_iterator) return; if (mutableIterable()) metaContainer().destroyIterator(m_iterator); else metaContainer().destroyConstIterator(m_iterator); } public: void *mutableIterator() { return m_iterator; } const void *constIterator() const { return m_iterator; } Container metaContainer() const { return constIterable()->m_metaContainer; } }; template struct QIterator : public QBaseIterator { public: using difference_type = qsizetype; explicit QIterator(QIterable *iterable, void *iterator) : QBaseIterator(iterable, iterator) { Q_ASSERT(iterable != nullptr); } bool operator==(const QIterator &o) const { return this->metaContainer().compareIterator(this->constIterator(), o.constIterator()); } bool operator!=(const QIterator &o) const { return !this->metaContainer().compareIterator(this->constIterator(), o.constIterator()); } QIterator &operator++() { this->metaContainer().advanceIterator(this->mutableIterator(), 1); return *this; } QIterator operator++(int) { QIterable *iterable = this->mutableIterable(); const Container metaContainer = this->metaContainer(); QIterator result(iterable, metaContainer.begin(iterable->mutableIterable())); metaContainer.copyIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceIterator(this->mutableIterator(), 1); return result; } QIterator &operator--() { this->metaContainer().advanceIterator(this->mutableIterator(), -1); return *this; } QIterator operator--(int) { QIterable *iterable = this->mutableIterable(); const Container metaContainer = this->metaContainer(); QIterator result(iterable, metaContainer.begin(iterable->mutableIterable())); metaContainer.copyIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceIterator(this->mutableIterator(), -1); return result; } QIterator &operator+=(qsizetype j) { this->metaContainer().advanceIterator(this->mutableIterator(), j); return *this; } QIterator &operator-=(qsizetype j) { this->metaContainer().advanceIterator(this->mutableIterator(), -j); return *this; } QIterator operator+(qsizetype j) const { QIterable *iterable = this->mutableIterable(); const Container metaContainer = this->metaContainer(); QIterator result(iterable, metaContainer.begin(iterable->mutableIterable())); metaContainer.copyIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceIterator(result.mutableIterator(), j); return result; } QIterator operator-(qsizetype j) const { QIterable *iterable = this->mutableIterable(); const Container metaContainer = this->metaContainer(); QIterator result(iterable, metaContainer.begin(iterable->mutableIterable())); metaContainer.copyIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceIterator(result.mutableIterator(), -j); return result; } qsizetype operator-(const QIterator &j) const { return this->metaContainer().diffIterator(this->constIterator(), j.constIterator()); } friend inline QIterator operator+(qsizetype j, const QIterator &k) { return k + j; } }; template struct QConstIterator : public QBaseIterator { public: using difference_type = qsizetype; explicit QConstIterator(const QIterable *iterable, void *iterator) : QBaseIterator(iterable, iterator) { } bool operator==(const QConstIterator &o) const { return this->metaContainer().compareConstIterator( this->constIterator(), o.constIterator()); } bool operator!=(const QConstIterator &o) const { return !this->metaContainer().compareConstIterator( this->constIterator(), o.constIterator()); } QConstIterator &operator++() { this->metaContainer().advanceConstIterator(this->mutableIterator(), 1); return *this; } QConstIterator operator++(int) { const Container metaContainer = this->metaContainer(); QConstIterator result(this->constIterable(), metaContainer.constBegin( this->constIterable()->constIterable())); metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceConstIterator(this->mutableIterator(), 1); return result; } QConstIterator &operator--() { this->metaContainer().advanceConstIterator(this->mutableIterator(), -1); return *this; } QConstIterator operator--(int) { const Container metaContainer = this->metaContainer(); QConstIterator result(this->constIterable(), metaContainer.constBegin( this->constIterable()->constIterable())); metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceConstIterator(this->mutableIterator(), -1); return result; } QConstIterator &operator+=(qsizetype j) { this->metaContainer().advanceConstIterator(this->mutableIterator(), j); return *this; } QConstIterator &operator-=(qsizetype j) { this->metaContainer().advanceConstIterator(this->mutableIterator(), -j); return *this; } QConstIterator operator+(qsizetype j) const { const Container metaContainer = this->metaContainer(); QConstIterator result( this->constIterable(), metaContainer.constBegin(this->constIterable()->constIterable())); metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceConstIterator(result.mutableIterator(), j); return result; } QConstIterator operator-(qsizetype j) const { const Container metaContainer = this->metaContainer(); QConstIterator result(this->constIterable(), metaContainer.constBegin( this->constIterable()->constIterable())); metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator()); metaContainer.advanceConstIterator(result.mutableIterator(), -j); return result; } qsizetype operator-(const QConstIterator &j) const { return this->metaContainer().diffIterator(this->constIterator(), j.constIterator()); } friend inline QConstIterator operator+(qsizetype j, const QConstIterator &k) { return k + j; } }; template class QIterable { friend class QBaseIterator; protected: uint m_revision = 0; QtPrivate::QConstPreservingPointer m_iterable; Container m_metaContainer; public: template QIterable(const Container &metaContainer, const T *p) : m_iterable(p), m_metaContainer(metaContainer) { } template QIterable(const Container &metaContainer, T *p) : m_iterable(p), m_metaContainer(metaContainer) { } template QIterable(const Container &metaContainer, Pointer iterable) : m_iterable(iterable), m_metaContainer(metaContainer) { } QIterable(const Container &metaContainer, qsizetype alignment, const void *p) : m_iterable(p, alignment), m_metaContainer(metaContainer) { } QIterable(const Container &metaContainer, qsizetype alignment, void *p) : m_iterable(p, alignment), m_metaContainer(metaContainer) { } bool canInputIterate() const { return m_metaContainer.hasInputIterator(); } bool canForwardIterate() const { return m_metaContainer.hasForwardIterator(); } bool canReverseIterate() const { return m_metaContainer.hasBidirectionalIterator(); } bool canRandomAccessIterate() const { return m_metaContainer.hasRandomAccessIterator(); } const void *constIterable() const { return m_iterable.constPointer(); } void *mutableIterable() { return m_iterable.mutablePointer(); } QConstIterator constBegin() const { return QConstIterator(this, m_metaContainer.constBegin(constIterable())); } QConstIterator constEnd() const { return QConstIterator(this, m_metaContainer.constEnd(constIterable())); } QIterator mutableBegin() { return QIterator(this, m_metaContainer.begin(mutableIterable())); } QIterator mutableEnd() { return QIterator(this, m_metaContainer.end(mutableIterable())); } qsizetype size() const { const void *container = constIterable(); if (m_metaContainer.hasSize()) return m_metaContainer.size(container); if (!m_metaContainer.hasConstIterator()) return -1; const void *begin = m_metaContainer.constBegin(container); const void *end = m_metaContainer.constEnd(container); const qsizetype size = m_metaContainer.diffConstIterator(end, begin); m_metaContainer.destroyConstIterator(begin); m_metaContainer.destroyConstIterator(end); return size; } Container metaContainer() const { return m_metaContainer; }; }; QT_END_NAMESPACE #endif // QITERABLE_H