File indexing completed on 2026-10-04 09:19:32
0001
0002
0003
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
0080
0081
0082
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