Revision control

++ // Copyright (C) 2020 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
++ // Qt-Security score:significant reason:default
++
++ #ifndef QITERABLE_H
++ #define QITERABLE_H
++
++ #include <QtCore/qglobal.h>
++ #include <QtCore/qtypeinfo.h>
++ #include <QtCore/qtaggedpointer.h>
++
++ QT_BEGIN_NAMESPACE
++
++ namespace QtPrivate {
++ template<typename Type, typename Storage = Type>
++ class QConstPreservingPointer
++ {
++ enum Tag : bool { Const, Mutable };
++ QTaggedPointer<Storage, Tag> m_pointer;
++
++ public:
++ Q_NODISCARD_CTOR QConstPreservingPointer(std::nullptr_t) : m_pointer(nullptr, Const) {}
++
++ Q_NODISCARD_CTOR QConstPreservingPointer(const void *pointer, qsizetype alignment)
++ : m_pointer(reinterpret_cast<Storage *>(const_cast<void *>(pointer)), Const)
++ {
++ Q_UNUSED(alignment);
++ Q_ASSERT(alignment > qsizetype(alignof(Storage)));
++ }
++
++ Q_NODISCARD_CTOR QConstPreservingPointer(void *pointer, qsizetype alignment)
++ : m_pointer(reinterpret_cast<Storage *>(pointer), Mutable)
++ {
++ Q_UNUSED(alignment);
++ Q_ASSERT(alignment > qsizetype(alignof(Storage)));
++ }
++
++ template<typename InputType>
++ Q_NODISCARD_CTOR QConstPreservingPointer(const InputType *pointer)
++ : m_pointer(reinterpret_cast<Storage *>(const_cast<InputType *>(pointer)), Const)
++ {
++ static_assert(alignof(InputType) >= alignof(Storage));
++ }
++
++ template<typename InputType>
++ Q_NODISCARD_CTOR QConstPreservingPointer(InputType *pointer)
++ : m_pointer(reinterpret_cast<Storage *>(pointer), Mutable)
++ {
++ static_assert(alignof(InputType) >= alignof(Storage));
++ }
++
++ Q_NODISCARD_CTOR QConstPreservingPointer() = default;
++
++ const Type *constPointer() const
++ {
++ return reinterpret_cast<const Type *>(m_pointer.data());
++ }
++
++ Type *mutablePointer() const
++ {
++ return m_pointer.tag() == Mutable ? reinterpret_cast<Type *>(m_pointer.data()) : nullptr;
++ }
++ };
++
++ enum class SynthesizedAccessFunction: quint8
++ {
++ IterableSize,
++ SequenceAt
++ };
++
++ Q_CORE_EXPORT void warnSynthesizedIterableAccess(SynthesizedAccessFunction function);
++ }
++
++ template<class Iterator, typename IteratorCategory>
++ class QTaggedIterator : public Iterator
++ {
++ public:
++ using iterator_category = IteratorCategory;
++ QTaggedIterator(Iterator &&it) : Iterator(std::move(it))
++ {
++ [[maybe_unused]] const auto metaContainer = this->metaContainer();
++ if constexpr (std::is_base_of_v<std::random_access_iterator_tag, IteratorCategory>) {
++ if (!metaContainer.hasRandomAccessIterator()) {
++ qFatal("You cannot use this iterator as a random access iterator");
++ this->clearIterator();
++ }
++ }
++
++ if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag, IteratorCategory>) {
++ if (!metaContainer.hasBidirectionalIterator()) {
++ qFatal("You cannot use this iterator as a bidirectional iterator");
++ this->clearIterator();
++ }
++ }
++
++ if constexpr (std::is_base_of_v<std::forward_iterator_tag, IteratorCategory>) {
++ if (!metaContainer.hasForwardIterator()) {
++ qFatal("You cannot use this iterator as a forward iterator");
++ this->clearIterator();
++ }
++ }
++
++ if constexpr (std::is_base_of_v<std::input_iterator_tag, IteratorCategory>) {
++ if (!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 Container>
++ class QIterable;
++
++ template<class Container>
++ class QBaseIterator
++ {
++ private:
++ QtPrivate::QConstPreservingPointer<QIterable<Container>> m_iterable;
++ void *m_iterator = nullptr;
++
++ protected:
++ QBaseIterator() = default;
++ QBaseIterator(const QIterable<Container> *iterable, void *iterator)
++ : m_iterable(iterable), m_iterator(iterator)
++ {}
++
++ QBaseIterator(QIterable<Container> *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<Container> *mutableIterable() const
++ {
++ return m_iterable.mutablePointer();
++ }
++
++ const QIterable<Container> *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<class Container>
++ struct QIterator : public QBaseIterator<Container>
++ {
++ public:
++ using difference_type = qsizetype;
++
++ explicit QIterator(QIterable<Container> *iterable, void *iterator)
++ : QBaseIterator<Container>(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<Container> *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<Container> *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<Container> *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<Container> *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<class Container>
++ struct QConstIterator : public QBaseIterator<Container>
++ {
++ public:
++ using difference_type = qsizetype;
++
++ explicit QConstIterator(const QIterable<Container> *iterable, void *iterator)
++ : QBaseIterator<Container>(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 Container>
++ class QIterable
++ {
++ friend class QBaseIterator<Container>;
++
++ protected:
++ uint m_revision = 0;
++ QtPrivate::QConstPreservingPointer<void, quint16> m_iterable;
++ Container m_metaContainer;
++
++ public:
++ template<class T>
++ QIterable(const Container &metaContainer, const T *p)
++ : m_iterable(p), m_metaContainer(metaContainer)
++ {
++ }
++
++ template<class T>
++ QIterable(const Container &metaContainer, T *p)
++ : m_iterable(p), m_metaContainer(metaContainer)
++ {
++ }
++
++ template<typename Pointer>
++ 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<Container> constBegin() const
++ {
++ return QConstIterator(this, m_metaContainer.constBegin(constIterable()));
++ }
++
++ QConstIterator<Container> constEnd() const
++ {
++ return QConstIterator(this, m_metaContainer.constEnd(constIterable()));
++ }
++
++ QIterator<Container> mutableBegin()
++ {
++ return QIterator(this, m_metaContainer.begin(mutableIterable()));
++ }
++
++ QIterator<Container> 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 QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
++ // We shouldn't second-guess the underlying container, so we're not synthesizing a size.
++ return -1;
++ #else
++ QtPrivate::warnSynthesizedIterableAccess(
++ QtPrivate::SynthesizedAccessFunction::IterableSize);
++
++ 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;
++ #endif
++ }
++
++ void clear()
++ {
++ m_metaContainer.clear(mutableIterable());
++ }
++
++ Container metaContainer() const
++ {
++ return m_metaContainer;
++ }
++ };
++
++ QT_END_NAMESPACE
++
++ #endif // QITERABLE_H