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