Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-04 09:19:32

0001 // Copyright (C) 2020 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 QTAGGEDPOINTER_H
0006 #define QTAGGEDPOINTER_H
0007 
0008 #include <QtCore/qglobal.h>
0009 #include <QtCore/qalgorithms.h>
0010 #include <QtCore/qmath.h>
0011 #include <QtCore/qtypeinfo.h>
0012 
0013 QT_BEGIN_NAMESPACE
0014 
0015 namespace QtPrivate {
0016     constexpr quint8 nextByteSize(quint8 bits) { return quint8((bits + 7) / 8); }
0017 
0018     template <typename T>
0019     struct TagInfo
0020     {
0021         static constexpr size_t alignment = alignof(T);
0022         static_assert((alignment & (alignment - 1)) == 0,
0023             "Alignment of template parameter must be power of two");
0024 
0025         static constexpr quint8 tagBits = quint8(qCountTrailingZeroBits(alignment));
0026         static_assert(tagBits > 0,
0027             "Alignment of template parameter does not allow any tags");
0028 
0029         static constexpr size_t tagSize = qNextPowerOfTwo(nextByteSize(tagBits));
0030         static_assert(tagSize < sizeof(quintptr),
0031             "Alignment of template parameter allows tags masking away pointer");
0032 
0033         using TagType = typename QIntegerForSize<tagSize>::Unsigned;
0034     };
0035 }
0036 
0037 template <typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
0038 class QTaggedPointer
0039 {
0040 public:
0041     using Type = T;
0042     using TagType = Tag;
0043 
0044     static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
0045     static constexpr quintptr pointerMask() { return ~tagMask(); }
0046 
0047     Q_NODISCARD_CTOR constexpr QTaggedPointer() noexcept : d(0) {}
0048     Q_NODISCARD_CTOR constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
0049 
0050     Q_NODISCARD_CTOR explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
0051         : d(quintptr(pointer) | quintptr(tag))
0052     {
0053         static_assert(sizeof(Type*) == sizeof(QTaggedPointer));
0054 
0055         Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0, "QTaggedPointer<T, Tag>", "Pointer is not aligned");
0056         Q_ASSERT_X((static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & pointerMask()) == 0,
0057             "QTaggedPointer<T, Tag>::setTag", "Tag is larger than allowed by number of available tag bits");
0058     }
0059 
0060     Type &operator*() const noexcept
0061     {
0062         Q_ASSERT(data());
0063         return *data();
0064     }
0065 
0066     Type *operator->() const noexcept
0067     {
0068         return data();
0069     }
0070 
0071     explicit operator bool() const noexcept
0072     {
0073         return !isNull();
0074     }
0075 
0076 #ifdef Q_QDOC
0077     QTaggedPointer &operator=(T *other) noexcept;
0078 #else
0079     // Disables the usage of `ptr = {}`, which would go through this operator
0080     // (rather than using the implicitly-generated assignment operator).
0081     // The operators have different semantics: the ones here leave the tag intact,
0082     // the implicitly-generated one overwrites it.
0083     template <typename U,
0084               std::enable_if_t<std::is_convertible_v<U *, T *>, bool> = false>
0085     QTaggedPointer &operator=(U *other) noexcept
0086     {
0087         T *otherT = other;
0088         d = reinterpret_cast<quintptr>(otherT) | (d & tagMask());
0089         return *this;
0090     }
0091 
0092     template <typename U,
0093               std::enable_if_t<std::is_null_pointer_v<U>, bool> = false>
0094     QTaggedPointer &operator=(U) noexcept
0095     {
0096         d = reinterpret_cast<quintptr>(static_cast<T *>(nullptr)) | (d & tagMask());
0097         return *this;
0098     }
0099 #endif
0100 
0101     static constexpr Tag maximumTag() noexcept
0102     {
0103         return TagType(typename QtPrivate::TagInfo<T>::TagType(tagMask()));
0104     }
0105 
0106     void setTag(Tag tag)
0107     {
0108         Q_ASSERT_X(
0109                 (static_cast<quintptr>(tag) & pointerMask()) == 0,
0110                 "QTaggedPointer<T, Tag>::setTag",
0111                 "Tag is larger than allowed by number of available tag bits");
0112 
0113         d = (d & pointerMask()) | static_cast<quintptr>(tag);
0114     }
0115 
0116     Tag tag() const noexcept
0117     {
0118         return TagType(typename QtPrivate::TagInfo<T>::TagType(d & tagMask()));
0119     }
0120 
0121     T* data() const noexcept
0122     {
0123         return reinterpret_cast<T*>(d & pointerMask());
0124     }
0125 
0126     bool isNull() const noexcept
0127     {
0128         return !data();
0129     }
0130 
0131     void swap(QTaggedPointer &other) noexcept
0132     {
0133         std::swap(d, other.d);
0134     }
0135 
0136     friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
0137     {
0138         return lhs.data() == rhs.data();
0139     }
0140 
0141     friend inline bool operator!=(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
0142     {
0143         return lhs.data() != rhs.data();
0144     }
0145 
0146     friend inline bool operator==(QTaggedPointer lhs, std::nullptr_t) noexcept
0147     {
0148         return lhs.isNull();
0149     }
0150 
0151     friend inline bool operator==(std::nullptr_t, QTaggedPointer rhs) noexcept
0152     {
0153         return rhs.isNull();
0154     }
0155 
0156     friend inline bool operator!=(QTaggedPointer lhs, std::nullptr_t) noexcept
0157     {
0158         return !lhs.isNull();
0159     }
0160 
0161     friend inline bool operator!=(std::nullptr_t, QTaggedPointer rhs) noexcept
0162     {
0163         return !rhs.isNull();
0164     }
0165 
0166     friend inline bool operator!(QTaggedPointer ptr) noexcept
0167     {
0168         return !ptr.data();
0169     }
0170 
0171     friend inline void swap(QTaggedPointer &p1, QTaggedPointer &p2) noexcept
0172     {
0173         p1.swap(p2);
0174     }
0175 
0176 protected:
0177     quintptr d;
0178 };
0179 
0180 template <typename T, typename Tag>
0181 constexpr inline std::size_t qHash(QTaggedPointer<T, Tag> p, std::size_t seed = 0) noexcept
0182 { return qHash(p.data(), seed); }
0183 
0184 template <typename T, typename Tag>
0185 class QTypeInfo<QTaggedPointer<T, Tag>>
0186     : public QTypeInfoMerger<QTaggedPointer<T, Tag>, quintptr> {};
0187 
0188 QT_END_NAMESPACE
0189 
0190 #endif // QTAGGEDPOINTER_H