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