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