1 /* 2 * DQt - D bindings for the Qt Toolkit 3 * 4 * GNU Lesser General Public License Usage 5 * This file may be used under the terms of the GNU Lesser 6 * General Public License version 3 as published by the Free Software 7 * Foundation and appearing in the file LICENSE.LGPL3 included in the 8 * packaging of this file. Please review the following information to 9 * ensure the GNU Lesser General Public License version 3 requirements 10 * will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 11 */ 12 module qt.core.taggedpointer; 13 extern(C++): 14 15 import qt.config; 16 import qt.core.algorithms; 17 import qt.core.global; 18 import qt.core.math; 19 import qt.helpers; 20 21 extern(C++, "QtPrivate") { 22 quint8 nextByteSize(quint8 bits) { return cast(quint8)((bits + 7) / 8); } 23 24 struct TagInfo(T) 25 { 26 extern(D) static immutable size_t alignment = T.alignof; 27 static assert((alignment & (alignment - 1)) == 0, 28 "Alignment of template parameter must be power of two"); 29 30 extern(D) static immutable quint8 tagBits = /+ QtPrivate:: +/qt.core.algorithms.qConstexprCountTrailingZeroBits(alignment); 31 static assert(tagBits > 0, 32 "Alignment of template parameter does not allow any tags"); 33 34 extern(D) static immutable size_t tagSize = /+ QtPrivate:: +/qt.core.math.qConstexprNextPowerOfTwo(cast(uint)nextByteSize(tagBits)); 35 static assert(tagSize < quintptr.sizeof, 36 "Alignment of template parameter allows tags masking away pointer"); 37 38 alias TagType = QIntegerForSize!(tagSize).Unsigned; 39 } 40 } 41 42 extern(C++, class) struct QTaggedPointer(T, Tag) 43 { 44 public: 45 alias Type = T; 46 alias TagType = Tag; 47 48 static quintptr tagMask() { return TagInfo!(T).alignment - 1; } 49 static quintptr pointerMask() { return ~tagMask(); } 50 51 @disable this(); 52 /+this()/+ noexcept+/ 53 { 54 this.d = 0; 55 }+/ 56 this(typeof(null))/+ noexcept+/ 57 { 58 } 59 60 /+ explicit +/this(T* pointer, Tag tag = Tag())/+ noexcept+/ 61 { 62 this.d = cast(quintptr)(pointer) | quintptr(tag); 63 64 static assert((Type*).sizeof == QTaggedPointer.sizeof); 65 66 (mixin(Q_ASSERT_X(q{(cast(quintptr)(pointer) & QTaggedPointer.tagMask()) == 0},q{ "QTaggedPointer<T, Tag>"},q{ "Pointer is not aligned"}))); 67 (mixin(Q_ASSERT_X(q{(static_cast!(/+ QtPrivate:: +/TagInfo!(T).TagType)(tag) & QTaggedPointer.pointerMask()) == 0},q{ 68 "QTaggedPointer<T, Tag>::setTag"},q{ "Tag is larger than allowed by number of available tag bits"}))); 69 } 70 71 ref Type opUnary(string op)() const/+ noexcept+/ if(op == "*") 72 { 73 (mixin(Q_ASSERT(q{data()}))); 74 return *data(); 75 } 76 77 /+Type* operator ->() const/+ noexcept+/ 78 { 79 return data(); 80 }+/ 81 82 /+/+ explicit +/ auto opCast(T : bool)() const/+ noexcept+/ 83 { 84 return !isNull(); 85 }+/ 86 87 /+ref QTaggedPointer operator =(T* other)/+ noexcept+/ 88 { 89 d = reinterpret_cast!(quintptr)(other) | (d & tagMask()); 90 return this; 91 }+/ 92 93 static Tag maximumTag()/+ noexcept+/ 94 { 95 return cast(TagType)(cast(/+ typename +/ /+ QtPrivate:: +/TagInfo!(T).TagType)(tagMask())); 96 } 97 98 void setTag(Tag tag) 99 { 100 (mixin(Q_ASSERT_X(q{(static_cast!(/+ QtPrivate:: +/TagInfo!(T).TagType)(tag) & QTaggedPointer.pointerMask()) == 0},q{ 101 "QTaggedPointer<T, Tag>::setTag"},q{ "Tag is larger than allowed by number of available tag bits"}))); 102 103 d = (d & pointerMask()) | static_cast!(quintptr)(tag); 104 } 105 106 Tag tag() const/+ noexcept+/ 107 { 108 return cast(TagType)(cast(/+ typename +/ /+ QtPrivate:: +/TagInfo!(T).TagType)(d & tagMask())); 109 } 110 111 T* data() const/+ noexcept+/ 112 { 113 return reinterpret_cast!(T*)(d & pointerMask()); 114 } 115 116 bool isNull() const/+ noexcept+/ 117 { 118 return !data(); 119 } 120 121 /+ void swap(QTaggedPointer &other) noexcept 122 { 123 qSwap(d, other.d); 124 } +/ 125 126 /+ friend inline bool operator==(QTaggedPointer lhs, QTaggedPointer rhs) noexcept 127 { 128 return lhs.data() == rhs.data(); 129 } +/ 130 131 /+ friend inline bool operator!=(QTaggedPointer lhs, QTaggedPointer rhs) noexcept 132 { 133 return lhs.data() != rhs.data(); 134 } +/ 135 136 /+ friend inline bool operator==(QTaggedPointer lhs, std::nullptr_t) noexcept 137 { 138 return lhs.isNull(); 139 } +/ 140 141 /+ friend inline bool operator==(std::nullptr_t, QTaggedPointer rhs) noexcept 142 { 143 return rhs.isNull(); 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 ptr) noexcept 157 { 158 return !ptr.data(); 159 } +/ 160 161 /+ friend inline void swap(QTaggedPointer &p1, QTaggedPointer &p2) noexcept 162 { 163 p1.swap(p2); 164 } +/ 165 166 protected: 167 quintptr d = 0; 168 } 169 170 /+ template <typename T, typename Tag> 171 constexpr inline std::size_t qHash(QTaggedPointer<T, Tag> p, std::size_t seed = 0) noexcept 172 { return qHash(p.data(), seed); } 173 174 template <typename T, typename Tag> 175 class QTypeInfo<QTaggedPointer<T, Tag>> 176 : public QTypeInfoMerger<QTaggedPointer<T, Tag>, quintptr> {}; +/ 177