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