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