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.arraydata;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.basicatomic;
17 import qt.core.flags;
18 import qt.core.global;
19 import qt.core.pair;
20 import qt.helpers;
21 
22 
23 struct QArrayData
24 {
25     enum AllocationOption {
26         Grow,
27         KeepSize
28     }
29 
30     enum GrowthPosition {
31         GrowsAtEnd,
32         GrowsAtBeginning
33     }
34 
35    enum ArrayOption {
36         ArrayOptionDefault = 0,
37         CapacityReserved     = 0x1  //!< the capacity was reserved by the user, try to keep it
38     }
39     /+ Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) +/
40 alias ArrayOptions = QFlags!(ArrayOption);
41     QBasicAtomicInt ref__;
42     ArrayOptions flags;
43     qsizetype alloc;
44 
45     qsizetype allocatedCapacity()/+ noexcept+/
46     {
47         return alloc;
48     }
49 
50     qsizetype constAllocatedCapacity() const/+ noexcept+/
51     {
52         return alloc;
53     }
54 
55     /// Returns true if sharing took place
56     bool ref_()/+ noexcept+/
57     {
58         ref__.ref_();
59         return true;
60     }
61 
62     /// Returns false if deallocation is necessary
63     bool deref()/+ noexcept+/
64     {
65         return ref__.deref();
66     }
67 
68     bool isShared() const/+ noexcept+/
69     {
70         return ref__.loadRelaxed() != 1;
71     }
72 
73     // Returns true if a detach is necessary before modifying the data
74     // This method is intentionally not const: if you want to know whether
75     // detaching is necessary, you should be in a non-const function already
76     bool needsDetach() const/+ noexcept+/
77     {
78         return ref__.loadRelaxed() > 1;
79     }
80 
81     qsizetype detachCapacity(qsizetype newSize) const/+ noexcept+/
82     {
83         if (flags & ArrayOption.CapacityReserved && newSize < constAllocatedCapacity())
84             return constAllocatedCapacity();
85         return newSize;
86     }
87 
88     /+ [[nodiscard]] +/
89     /+ #if defined(Q_CC_GNU) +/
90         /+ __attribute__((__malloc__)) +/
91     /+ #endif +/
92         /+ Q_CORE_EXPORT +/ static void* allocate(QArrayData** pdata, qsizetype objectSize, qsizetype alignment,
93                 qsizetype capacity, AllocationOption option = AllocationOption.KeepSize)/+ noexcept+/;
94     /+ [[nodiscard]] +/ /+ Q_CORE_EXPORT +/ static qt.core.pair.QPair!(QArrayData*, void*) reallocateUnaligned(QArrayData* data, void* dataPointer,
95                 qsizetype objectSize, qsizetype newCapacity, AllocationOption option)/+ noexcept+/;
96     /+ Q_CORE_EXPORT +/ static void deallocate(QArrayData* data, qsizetype objectSize,
97                 qsizetype alignment)/+ noexcept+/;
98 }
99 /+pragma(inline, true) QFlags!(QArrayData.ArrayOptions.enum_type) operator |(QArrayData.ArrayOptions.enum_type f1, QArrayData.ArrayOptions.enum_type f2)/+noexcept+/{return QFlags!(QArrayData.ArrayOptions.enum_type)(f1)|f2;}+/
100 /+pragma(inline, true) QFlags!(QArrayData.ArrayOptions.enum_type) operator |(QArrayData.ArrayOptions.enum_type f1, QFlags!(QArrayData.ArrayOptions.enum_type) f2)/+noexcept+/{return f2|f1;}+/
101 /+pragma(inline, true) QFlags!(QArrayData.ArrayOptions.enum_type) operator &(QArrayData.ArrayOptions.enum_type f1, QArrayData.ArrayOptions.enum_type f2)/+noexcept+/{return QFlags!(QArrayData.ArrayOptions.enum_type)(f1)&f2;}+/
102 /+pragma(inline, true) QFlags!(QArrayData.ArrayOptions.enum_type) operator &(QArrayData.ArrayOptions.enum_type f1, QFlags!(QArrayData.ArrayOptions.enum_type) f2)/+noexcept+/{return f2&f1;}+/
103 /+pragma(inline, true) void operator +(QArrayData.ArrayOptions.enum_type f1, QArrayData.ArrayOptions.enum_type f2)/+noexcept+/;+/
104 /+pragma(inline, true) void operator +(QArrayData.ArrayOptions.enum_type f1, QFlags!(QArrayData.ArrayOptions.enum_type) f2)/+noexcept+/;+/
105 /+pragma(inline, true) void operator +(int f1, QFlags!(QArrayData.ArrayOptions.enum_type) f2)/+noexcept+/;+/
106 /+pragma(inline, true) void operator -(QArrayData.ArrayOptions.enum_type f1, QArrayData.ArrayOptions.enum_type f2)/+noexcept+/;+/
107 /+pragma(inline, true) void operator -(QArrayData.ArrayOptions.enum_type f1, QFlags!(QArrayData.ArrayOptions.enum_type) f2)/+noexcept+/;+/
108 /+pragma(inline, true) void operator -(int f1, QFlags!(QArrayData.ArrayOptions.enum_type) f2)/+noexcept+/;+/
109 /+pragma(inline, true) QIncompatibleFlag operator |(QArrayData.ArrayOptions.enum_type f1, int f2)/+noexcept+/{return QIncompatibleFlag(int(f1)|f2);}+/
110 /+pragma(inline, true) void operator +(int f1, QArrayData.ArrayOptions.enum_type f2)/+noexcept+/;+/
111 /+pragma(inline, true) void operator +(QArrayData.ArrayOptions.enum_type f1, int f2)/+noexcept+/;+/
112 /+pragma(inline, true) void operator -(int f1, QArrayData.ArrayOptions.enum_type f2)/+noexcept+/;+/
113 /+pragma(inline, true) void operator -(QArrayData.ArrayOptions.enum_type f1, int f2)/+noexcept+/;+/
114 
115 /+ Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions) +/
116 struct QTypedArrayData(T)
117 {
118     QArrayData base0;
119     alias base0 this;
120     alias AllocationOption = QArrayData.AllocationOption;
121     struct AlignmentDummy { QArrayData header; T data; }
122 
123     /+ [[nodiscard]] +/ static qt.core.pair.QPair!(QTypedArrayData*, T*) allocate(qsizetype capacity, AllocationOption option = QArrayData.AllocationOption.KeepSize)
124     {
125         static assert(QTypedArrayData.sizeof == QArrayData.sizeof);
126         QArrayData* d;
127         void* result = QArrayData.allocate(&d, T.sizeof, AlignmentDummy.alignof, capacity, option);
128         static if((configValue!"__has_builtin___builtin_assume_aligned" && defined!"__has_builtin___builtin_assume_aligned"))
129         {
130             result = __builtin_assume_aligned(result, /+ Q_ALIGNOF +/AlignmentDummy.alignof);
131         }
132         return qMakePair(static_cast!(QTypedArrayData*)(d), static_cast!(T*)(result));
133     }
134 
135     static qt.core.pair.QPair!(QTypedArrayData*, T*)
136         reallocateUnaligned(QTypedArrayData* data, T* dataPointer, qsizetype capacity, AllocationOption option)
137     {
138         static assert(QTypedArrayData.sizeof == QArrayData.sizeof);
139         qt.core.pair.QPair!(QArrayData*, void*) pair =
140                 QArrayData.reallocateUnaligned(cast(QArrayData*)data, dataPointer, T.sizeof, capacity, option);
141         return qMakePair(static_cast!(QTypedArrayData*)(pair.first), static_cast!(T*)(pair.second));
142     }
143 
144     static void deallocate(QArrayData* data)/+ noexcept+/
145     {
146         static assert(QTypedArrayData.sizeof == QArrayData.sizeof);
147         QArrayData.deallocate(data, T.sizeof, AlignmentDummy.alignof);
148     }
149 
150     static T* dataStart(QArrayData* data, qsizetype alignment)/+ noexcept+/
151     {
152         // Alignment is a power of two
153         (mixin(Q_ASSERT(q{alignment >= qsizetype(QArrayData.alignof) && !(alignment & (alignment - 1))})));
154         void* start =  reinterpret_cast!(void*)(
155             (cast(quintptr)(data) + QArrayData.sizeof + alignment - 1) & ~(alignment - 1));
156         return static_cast!(T*)(start);
157     }
158 }
159 
160 extern(C++, "QtPrivate") {
161 struct /+ Q_CORE_EXPORT +/ QContainerImplHelper
162 {
163     enum CutResult { Null, Empty, Full, Subset }
164     /+ static CutResult mid(qsizetype originalLength, qsizetype* _position, qsizetype* _length)
165     {
166         ref qsizetype position = *_position;
167         ref qsizetype length = *_length;
168         if (position > originalLength) {
169             position = 0;
170             length = 0;
171             return CutResult.Null;
172         }
173 
174         if (position < 0) {
175             if (length < 0 || length + position >= originalLength) {
176                 position = 0;
177                 length = originalLength;
178                 return CutResult.Full;
179             }
180             if (length + position <= 0) {
181                 position = length = 0;
182                 return CutResult.Null;
183             }
184             length += position;
185             position = 0;
186         } else if (size_t(length) > size_t(originalLength - position)) {
187             length = originalLength - position;
188         }
189 
190         if (position == 0 && length == originalLength)
191             return CutResult.Full;
192 
193         return length > 0 ? CutResult.Subset : CutResult.Empty;
194     } +/
195 }
196 }
197