1 /****************************************************************************
2 **
3 ** DQt - D bindings for the Qt Toolkit
4 **
5 ** GNU Lesser General Public License Usage
6 ** This file may be used under the terms of the GNU Lesser
7 ** General Public License version 3 as published by the Free Software
8 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
9 ** packaging of this file. Please review the following information to
10 ** ensure the GNU Lesser General Public License version 3 requirements
11 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
12 **
13 ****************************************************************************/
14 module qt.core.arraydata;
15 extern(C++):
16 
17 import qt.config;
18 import qt.core.flags;
19 import qt.core.global;
20 import qt.core.refcount;
21 import qt.helpers;
22 
23 struct /+ Q_CORE_EXPORT +/ QArrayData
24 {
25     /+ QtPrivate:: +/qt.core.refcount.RefCount ref_;
26     int size;
27     /+ uint alloc : 31; +/
28     uint bitfieldData_alloc;
29     final uint alloc() const
30     {
31         return (bitfieldData_alloc >> 0) & 0x7fffffff;
32     }
33     final uint alloc(uint value)
34     {
35         bitfieldData_alloc = (bitfieldData_alloc & ~0x7fffffff) | ((value & 0x7fffffff) << 0);
36         return value;
37     }
38     /+ uint capacityReserved : 1; +/
39     final uint capacityReserved() const
40     {
41         return (bitfieldData_alloc >> 31) & 0x1;
42     }
43     final uint capacityReserved(uint value)
44     {
45         bitfieldData_alloc = (bitfieldData_alloc & ~0x80000000) | ((value & 0x1) << 31);
46         return value;
47     }
48 
49     qptrdiff offset; // in bytes from beginning of header
50 
51     void* data()
52     {
53         (mixin(Q_ASSERT(q{QArrayData.size == 0
54                     || QArrayData.offset < 0 || size_t(QArrayData.offset) >= QArrayData.sizeof})));
55         return reinterpret_cast!(char*)(&this) + offset;
56     }
57 
58     const(void)* data() const
59     {
60         (mixin(Q_ASSERT(q{QArrayData.size == 0
61                     || QArrayData.offset < 0 || size_t(QArrayData.offset) >= QArrayData.sizeof})));
62         return reinterpret_cast!(const(char)*)(&this) + offset;
63     }
64 
65     // This refers to array data mutability, not "header data" represented by
66     // data members in QArrayData. Shared data (array and header) must still
67     // follow COW principles.
68     bool isMutable() const
69     {
70         return alloc != 0;
71     }
72 
73     mixin("enum AllocationOption {"
74         ~ q{
75             CapacityReserved    = 0x1,
76         }
77         ~ (!versionIsSet!("QT_NO_UNSHARABLE_CONTAINERS") ? q{
78     /+ #if !defined(QT_NO_UNSHARABLE_CONTAINERS) +/
79             Unsharable          = 0x2,
80         }:"")
81         ~ q{
82     /+ #endif +/
83             RawData             = 0x4,
84             Grow                = 0x8,
85 
86             Default = 0
87         }
88         ~ "}"
89     );
90 
91     /+ Q_DECLARE_FLAGS(AllocationOptions, AllocationOption) +/
92 alias AllocationOptions = QFlags!(AllocationOption);
93     size_t detachCapacity(size_t newSize) const
94     {
95         if (capacityReserved && newSize < alloc)
96             return alloc;
97         return newSize;
98     }
99 
100     AllocationOptions detachFlags() const
101     {
102         AllocationOptions result;
103         if (capacityReserved)
104             result |= AllocationOption.CapacityReserved;
105         return result;
106     }
107 
108     AllocationOptions cloneFlags() const
109     {
110         AllocationOptions result;
111         if (capacityReserved)
112             result |= AllocationOption.CapacityReserved;
113         return result;
114     }
115 
116     /+ Q_REQUIRED_RESULT +/ static QArrayData* allocate(size_t objectSize, size_t alignment,
117                 size_t capacity, AllocationOptions options = AllocationOptions.Default)/+ noexcept+/;
118     /+ Q_REQUIRED_RESULT +/ static QArrayData* reallocateUnaligned(QArrayData* data, size_t objectSize,
119                 size_t newCapacity, AllocationOptions newOptions = AllocationOption.Default)/+ noexcept+/;
120     static void deallocate(QArrayData* data, size_t objectSize,
121                 size_t alignment)/+ noexcept+/;
122 
123     mixin(mangleWindows("?shared_null@QArrayData@@2QBU1@B", exportOnWindows ~ q{
124     extern static __gshared const(const(QArrayData)[2]) shared_null;
125     }));
126     static QArrayData* sharedNull()/+ noexcept+/ { return const_cast!(QArrayData*)(shared_null.ptr); }
127 }
128 /+pragma(inline, true) QFlags!(QArrayData.AllocationOptions.enum_type) operator |(QArrayData.AllocationOptions.enum_type f1, QArrayData.AllocationOptions.enum_type f2)/+noexcept+/{return QFlags!(QArrayData.AllocationOptions.enum_type)(f1)|f2;}+/
129 /+pragma(inline, true) QFlags!(QArrayData.AllocationOptions.enum_type) operator |(QArrayData.AllocationOptions.enum_type f1, QFlags!(QArrayData.AllocationOptions.enum_type) f2)/+noexcept+/{return f2|f1;}+/
130 /+pragma(inline, true) QIncompatibleFlag operator |(QArrayData.AllocationOptions.enum_type f1, int f2)/+noexcept+/{return QIncompatibleFlag(int(f1)|f2);}+/
131 
132 /+ Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocationOptions) +/
133 struct QTypedArrayData(T)
134 
135 {
136     QArrayData base0;
137     alias base0 this;
138     alias AllocationOption = QArrayData.AllocationOption;
139     alias AllocationOptions = QArrayData.AllocationOptions;
140 
141 /+ #ifdef QT_STRICT_ITERATORS
142     class iterator {
143     public:
144         T *i;
145         typedef std::random_access_iterator_tag  iterator_category;
146         typedef int difference_type;
147         typedef T value_type;
148         typedef T *pointer;
149         typedef T &reference;
150 
151         inline iterator() : i(nullptr) {}
152         inline iterator(T *n) : i(n) {}
153         inline iterator(const iterator &o): i(o.i){} // #### Qt 6: remove, the implicit version is fine
154         inline T &operator*() const { return *i; }
155         inline T *operator->() const { return i; }
156         inline T &operator[](int j) const { return *(i + j); }
157         inline bool operator==(const iterator &o) const { return i == o.i; }
158         inline bool operator!=(const iterator &o) const { return i != o.i; }
159         inline bool operator<(const iterator& other) const { return i < other.i; }
160         inline bool operator<=(const iterator& other) const { return i <= other.i; }
161         inline bool operator>(const iterator& other) const { return i > other.i; }
162         inline bool operator>=(const iterator& other) const { return i >= other.i; }
163         inline iterator &operator++() { ++i; return *this; }
164         inline iterator operator++(int) { T *n = i; ++i; return n; }
165         inline iterator &operator--() { i--; return *this; }
166         inline iterator operator--(int) { T *n = i; i--; return n; }
167         inline iterator &operator+=(int j) { i+=j; return *this; }
168         inline iterator &operator-=(int j) { i-=j; return *this; }
169         inline iterator operator+(int j) const { return iterator(i+j); }
170         inline iterator operator-(int j) const { return iterator(i-j); }
171         friend inline iterator operator+(int j, iterator k) { return k + j; }
172         inline int operator-(iterator j) const { return i - j.i; }
173         inline operator T*() const { return i; }
174     };
175     friend class iterator;
176 
177     class const_iterator {
178     public:
179         const T *i;
180         typedef std::random_access_iterator_tag  iterator_category;
181         typedef int difference_type;
182         typedef T value_type;
183         typedef const T *pointer;
184         typedef const T &reference;
185 
186         inline const_iterator() : i(nullptr) {}
187         inline const_iterator(const T *n) : i(n) {}
188         inline const_iterator(const const_iterator &o): i(o.i) {} // #### Qt 6: remove, the default version is fine
189         inline explicit const_iterator(const iterator &o): i(o.i) {}
190         inline const T &operator*() const { return *i; }
191         inline const T *operator->() const { return i; }
192         inline const T &operator[](int j) const { return *(i + j); }
193         inline bool operator==(const const_iterator &o) const { return i == o.i; }
194         inline bool operator!=(const const_iterator &o) const { return i != o.i; }
195         inline bool operator<(const const_iterator& other) const { return i < other.i; }
196         inline bool operator<=(const const_iterator& other) const { return i <= other.i; }
197         inline bool operator>(const const_iterator& other) const { return i > other.i; }
198         inline bool operator>=(const const_iterator& other) const { return i >= other.i; }
199         inline const_iterator &operator++() { ++i; return *this; }
200         inline const_iterator operator++(int) { const T *n = i; ++i; return n; }
201         inline const_iterator &operator--() { i--; return *this; }
202         inline const_iterator operator--(int) { const T *n = i; i--; return n; }
203         inline const_iterator &operator+=(int j) { i+=j; return *this; }
204         inline const_iterator &operator-=(int j) { i-=j; return *this; }
205         inline const_iterator operator+(int j) const { return const_iterator(i+j); }
206         inline const_iterator operator-(int j) const { return const_iterator(i-j); }
207         friend inline const_iterator operator+(int j, const_iterator k) { return k + j; }
208         inline int operator-(const_iterator j) const { return i - j.i; }
209         inline operator const T*() const { return i; }
210     };
211     friend class const_iterator;
212 #else +/
213     alias iterator = T*;
214     alias const_iterator = const(T)*;
215 /+ #endif +/
216 
217     T* data() { return static_cast!(T*)(base0.data()); }
218     const(T)* data() const { return static_cast!(const(T)*)(base0.data()); }
219 
220     iterator begin(/+iterator  = iterator() +/) { return data(); }
221     iterator end(/+iterator  = iterator() +/) { return data() + size; }
222     const_iterator begin(/+const_iterator  = const_iterator() +/) const { return data(); }
223     const_iterator end(/+const_iterator  = const_iterator() +/) const { return data() + size; }
224     const_iterator constBegin(/+const_iterator  = const_iterator() +/) const { return data(); }
225     const_iterator constEnd(/+ const_iterator = const_iterator() +/) const { return data() + size; }
226 
227     extern(C++, class) struct AlignmentDummy {
228     private:
229  QArrayData header; T data; }
230 
231     /+ Q_REQUIRED_RESULT +/ static QTypedArrayData* allocate(size_t capacity,
232                 AllocationOptions options = AllocationOptions.Default)
233     {
234         mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
235         return static_cast!(QTypedArrayData*)(QArrayData.allocate(T.sizeof,
236                     /+ Q_ALIGNOF +/AlignmentDummy.alignof, capacity, options));
237     }
238 
239     static QTypedArrayData* reallocateUnaligned(QTypedArrayData* data, size_t capacity,
240                 AllocationOptions options = AllocationOptions.Default)
241     {
242         mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
243         return static_cast!(QTypedArrayData*)(QArrayData.reallocateUnaligned(&data.base0, T.sizeof,
244                     capacity, options));
245     }
246 
247     static void deallocate(QArrayData* data)
248     {
249         mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
250         QArrayData.deallocate(data, T.sizeof, /+ Q_ALIGNOF +/AlignmentDummy.alignof);
251     }
252 
253     static void deallocate(QTypedArrayData * data)
254     {
255         deallocate(&data.base0);
256     }
257 
258     static QTypedArrayData* fromRawData(const(T)* data, size_t n,
259                 AllocationOptions options = AllocationOption.Default)
260     {
261         mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
262         QTypedArrayData* result = allocate(0, options | AllocationOption.RawData);
263         if (result) {
264             (mixin(Q_ASSERT(q{!result.ref_.isShared()}))); // No shared empty, please!
265 
266             result.offset = reinterpret_cast!(const(char)*)(data)
267                 - reinterpret_cast!(const(char)*)(result);
268             result.size = cast(int)(n);
269         }
270         return result;
271     }
272 
273     static QTypedArrayData* sharedNull()/+ noexcept+/
274     {
275         mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
276         return static_cast!(QTypedArrayData*)(QArrayData.sharedNull());
277     }
278 
279     static QTypedArrayData* sharedEmpty()
280     {
281         mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
282         return allocate(/* capacity */ 0);
283     }
284 
285     version(QT_NO_UNSHARABLE_CONTAINERS){}else
286     {
287         static QTypedArrayData* unsharableEmpty()
288         {
289             mixin(Q_STATIC_ASSERT(q{QTypedArrayData.sizeof == QArrayData.sizeof}));
290             return allocate(/* capacity */ 0, AllocationOptions.Unsharable);
291         }
292     }
293 }
294 
295 struct QStaticArrayData(T, size_t N)
296 {
297     QArrayData header;
298     T[N] data;
299 }
300 
301 // Support for returning QArrayDataPointer<T> from functions
302 struct QArrayDataPointerRef(T)
303 {
304     QTypedArrayData!(T)* ptr;
305 }
306 
307 /+ #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
308     { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
309     /**/
310 
311 #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) \
312     Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size,\
313         ((sizeof(QArrayData) + (Q_ALIGNOF(type) - 1)) & ~(Q_ALIGNOF(type) - 1) )) \
314     /**/
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 //  Q_ARRAY_LITERAL
318 
319 // The idea here is to place a (read-only) copy of header and array data in an
320 // mmappable portion of the executable (typically, .rodata section). This is
321 // accomplished by hiding a static const instance of QStaticArrayData, which is
322 // POD.
323 
324 // Hide array inside a lambda
325 #define Q_ARRAY_LITERAL(Type, ...)                                              \
326     ([]() -> QArrayDataPointerRef<Type> {                                       \
327             /* MSVC 2010 Doesn't support static variables in a lambda, but */   \
328             /* happily accepts them in a static function of a lambda-local */   \
329             /* struct :-) */                                                    \
330             struct StaticWrapper {                                              \
331                 static QArrayDataPointerRef<Type> get()                         \
332                 {                                                               \
333                     Q_ARRAY_LITERAL_IMPL(Type, __VA_ARGS__)                     \
334                     return ref;                                                 \
335                 }                                                               \
336             };                                                                  \
337             return StaticWrapper::get();                                        \
338         }())                                                                    \
339     /**/
340 
341 #ifdef Q_COMPILER_CONSTEXPR
342 #define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) Q_STATIC_ASSERT(std::is_literal_type<Type>::value)
343 #else
344 #define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) do {} while (0)
345 #endif
346 
347 #define Q_ARRAY_LITERAL_IMPL(Type, ...)                                         \
348     Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type);                                   \
349                                                                                 \
350     /* Portable compile-time array size computation */                          \
351     Q_CONSTEXPR Type data[] = { __VA_ARGS__ }; Q_UNUSED(data);                  \
352     enum { Size = sizeof(data) / sizeof(data[0]) };                             \
353                                                                                 \
354     static const QStaticArrayData<Type, Size> literal = {                       \
355         Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } };  \
356                                                                                 \
357     QArrayDataPointerRef<Type> ref =                                            \
358         { static_cast<QTypedArrayData<Type> *>(                                 \
359             const_cast<QArrayData *>(&literal.header)) };                       \
360     /**/ +/
361 
362 extern(C++, "QtPrivate") {
363 struct /+ Q_CORE_EXPORT +/ QContainerImplHelper
364 {
365     enum CutResult { Null, Empty, Full, Subset }
366     static CutResult mid(int originalLength, int* position, int* length);
367 }
368 }
369