Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtaggedpointer.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QTAGGEDPOINTER_H
6#define QTAGGEDPOINTER_H
7
8#include <QtCore/qglobal.h>
9#include <QtCore/qalgorithms.h>
10#include <QtCore/qmath.h>
11#include <QtCore/qtypeinfo.h>
12
13QT_BEGIN_NAMESPACE
14
15namespace QtPrivate {
16 constexpr quint8 nextByteSize(quint8 bits) { return quint8((bits + 7) / 8); }
17
18 template <typename T>
19 struct TagInfo
20 {
21 static constexpr size_t alignment = alignof(T);
22 static_assert((alignment & (alignment - 1)) == 0,
23 "Alignment of template parameter must be power of two");
24
25 static constexpr quint8 tagBits = quint8(qCountTrailingZeroBits(alignment));
26 static_assert(tagBits > 0,
27 "Alignment of template parameter does not allow any tags");
28
29 static constexpr size_t tagSize = qNextPowerOfTwo(nextByteSize(tagBits));
30 static_assert(tagSize < sizeof(quintptr),
31 "Alignment of template parameter allows tags masking away pointer");
32
34 };
35}
36
37template <typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
39{
40public:
41 using Type = T;
42 using TagType = Tag;
43
44 static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
45 static constexpr quintptr pointerMask() { return ~tagMask(); }
46
47 Q_NODISCARD_CTOR constexpr QTaggedPointer() noexcept : d(0) {}
49
52 {
53 static_assert(sizeof(Type*) == sizeof(QTaggedPointer));
54
55 Q_ASSERT_X((quintptr(pointer) & tagMask()) == 0, "QTaggedPointer<T, Tag>", "Pointer is not aligned");
56 Q_ASSERT_X((static_cast<typename QtPrivate::TagInfo<T>::TagType>(tag) & pointerMask()) == 0,
57 "QTaggedPointer<T, Tag>::setTag", "Tag is larger than allowed by number of available tag bits");
58 }
59
60 Type &operator*() const noexcept
61 {
62 Q_ASSERT(data());
63 return *data();
64 }
65
66 Type *operator->() const noexcept
67 {
68 return data();
69 }
70
71 explicit operator bool() const noexcept
72 {
73 return !isNull();
74 }
75
76#ifdef Q_QDOC
77 QTaggedPointer &operator=(T *other) noexcept;
78#else
79 // Disables the usage of `ptr = {}`, which would go through this operator
80 // (rather than using the implicitly-generated assignment operator).
81 // The operators have different semantics: the ones here leave the tag intact,
82 // the implicitly-generated one overwrites it.
83 template <typename U,
84 std::enable_if_t<std::is_convertible_v<U *, T *>, bool> = false>
86 {
87 T *otherT = other;
88 d = reinterpret_cast<quintptr>(otherT) | (d & tagMask());
89 return *this;
90 }
91
92 template <typename U,
93 std::enable_if_t<std::is_null_pointer_v<U>, bool> = false>
95 {
96 d = reinterpret_cast<quintptr>(static_cast<T *>(nullptr)) | (d & tagMask());
97 return *this;
98 }
99#endif
100
101 static constexpr Tag maximumTag() noexcept
102 {
103 return TagType(typename QtPrivate::TagInfo<T>::TagType(tagMask()));
104 }
105
107 {
109 (static_cast<quintptr>(tag) & pointerMask()) == 0,
110 "QTaggedPointer<T, Tag>::setTag",
111 "Tag is larger than allowed by number of available tag bits");
112
113 d = (d & pointerMask()) | static_cast<quintptr>(tag);
114 }
115
116 Tag tag() const noexcept
117 {
118 return TagType(typename QtPrivate::TagInfo<T>::TagType(d & tagMask()));
119 }
120
121 T* data() const noexcept
122 {
123 return reinterpret_cast<T*>(d & pointerMask());
124 }
125
126 bool isNull() const noexcept
127 {
128 return !data();
129 }
130
131 void swap(QTaggedPointer &other) noexcept
132 {
133 std::swap(d, other.d);
134 }
135
136 friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
137 {
138 return lhs.data() == rhs.data();
139 }
140
141 friend inline bool operator!=(QTaggedPointer lhs, QTaggedPointer rhs) noexcept
142 {
143 return lhs.data() != rhs.data();
144 }
145
146 friend inline bool operator==(QTaggedPointer lhs, std::nullptr_t) noexcept
147 {
148 return lhs.isNull();
149 }
150
151 friend inline bool operator==(std::nullptr_t, QTaggedPointer rhs) noexcept
152 {
153 return rhs.isNull();
154 }
155
156 friend inline bool operator!=(QTaggedPointer lhs, std::nullptr_t) noexcept
157 {
158 return !lhs.isNull();
159 }
160
161 friend inline bool operator!=(std::nullptr_t, QTaggedPointer rhs) noexcept
162 {
163 return !rhs.isNull();
164 }
165
166 friend inline bool operator!(QTaggedPointer ptr) noexcept
167 {
168 return !ptr.data();
169 }
170
171 friend inline void swap(QTaggedPointer &p1, QTaggedPointer &p2) noexcept
172 {
173 p1.swap(p2);
174 }
175
176protected:
178};
179
180template <typename T, typename Tag>
181constexpr inline std::size_t qHash(QTaggedPointer<T, Tag> p, std::size_t seed = 0) noexcept
182{ return qHash(p.data(), seed); }
183
184template <typename T, typename Tag>
187
188QT_END_NAMESPACE
189
190#endif // QTAGGEDPOINTER_H
Type * operator->() const noexcept
static constexpr quintptr pointerMask()
static constexpr quintptr tagMask()
operator bool() const noexcept
Type & operator*() const noexcept
constexpr quint8 nextByteSize(quint8 bits)
constexpr std::size_t qHash(QTaggedPointer< T, Tag > p, std::size_t seed=0) noexcept
static constexpr size_t tagSize
static constexpr size_t alignment
static constexpr quint8 tagBits