讀QT5.7原始碼(一)QArrayData QTypedArrayData
阿新 • • 發佈:2019-02-07
QArrayData QTypedArrayData這兩個類是配套的,後者是以前者為基礎的類模板,以方便對不同型別的陣列提供抽象管理。
他們被定義下同一個頭檔案和原始檔中,分別是QarraryData.h 和 QarraryData.cpp 位於qtcode資料夾中
QArrayData定義如下
struct Q_CORE_EXPORT QArrayData { QtPrivate::RefCount ref;//引用計數 int size; //大小 uint alloc : 31; //分配的個數 uint capacityReserved : 1;//適應模式 qptrdiff offset; // in bytes from beginning of header 定位指標 void *data() { Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); return reinterpret_cast<char *>(this) + offset; } const void *data() const { Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); return reinterpret_cast<const char *>(this) + offset; } // This refers to array data mutability, not "header data" represented by // data members in QArrayData. Shared data (array and header) must still // follow COW principles. bool isMutable() const { return alloc != 0; } enum AllocationOption { //5種模式 分配模式 使用shared_null[0] 使用shared_null[1] 可以增長 預設 CapacityReserved = 0x1, #if !defined(QT_NO_UNSHARABLE_CONTAINERS) Unsharable = 0x2, #endif RawData = 0x4, Grow = 0x8, Default = 0 }; Q_DECLARE_FLAGS(AllocationOptions, AllocationOption) size_t detachCapacity(size_t newSize) const { if (capacityReserved && newSize < alloc) return alloc; return newSize; } AllocationOptions detachFlags() const { AllocationOptions result; if (capacityReserved) result |= CapacityReserved; return result; } AllocationOptions cloneFlags() const { AllocationOptions result; if (capacityReserved) result |= CapacityReserved; return result; } static QArrayData *allocate(size_t objectSize, size_t alignment, //分配記憶體返回一個適配的 QArrayData指標 size_t capacity, AllocationOptions options = Default) Q_DECL_NOTHROW Q_REQUIRED_RESULT; static void deallocate(QArrayData *data, size_t objectSize, //釋放記憶體 size_t alignment) Q_DECL_NOTHROW; static const QArrayData shared_null[2]; 靜態的全域性物件兩個,在分配記憶體時可以使用Unsharable 和 RawData來指定使用這個兩個物件來管理分配的記憶體 static QArrayData *sharedNull() Q_DECL_NOTHROW { return const_cast<QArrayData*>(shared_null); } };
分配和釋放的實現
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, size_t capacity, AllocationOptions options) Q_DECL_NOTHROW { // Alignment is a power of two Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData) && !(alignment & (alignment - 1))); // Don't allocate empty headers if (!(options & RawData) && !capacity) { #if !defined(QT_NO_UNSHARABLE_CONTAINERS) if (options & Unsharable) return const_cast<QArrayData *>(&qt_array_unsharable_empty); #endif return const_cast<QArrayData *>(&qt_array_empty); } size_t headerSize = sizeof(QArrayData); // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we // can properly align the data array. This assumes malloc is able to // provide appropriate alignment for the header -- as it should! // Padding is skipped when allocating a header for RawData. if (!(options & RawData)) headerSize += (alignment - Q_ALIGNOF(QArrayData)); // Allocate additional space if array is growing if (options & Grow) { // Guard against integer overflow when multiplying. if (capacity > std::numeric_limits<size_t>::max() / objectSize) return 0; size_t alloc; if (mul_overflow(objectSize, capacity, &alloc)) return 0; // Make sure qAllocMore won't overflow qAllocMore. if (headerSize > size_t(MaxAllocSize) || alloc > size_t(MaxAllocSize) - headerSize) return 0; capacity = qAllocMore(int(alloc), int(headerSize)) / int(objectSize); } size_t allocSize; if (mul_overflow(objectSize, capacity, &allocSize)) return 0; if (add_overflow(allocSize, headerSize, &allocSize)) return 0; QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); if (header) { quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1); #if !defined(QT_NO_UNSHARABLE_CONTAINERS) header->ref.atomic.store(bool(!(options & Unsharable))); #else header->ref.atomic.store(1); #endif header->size = 0; header->alloc = capacity; header->capacityReserved = bool(options & CapacityReserved); header->offset = data - quintptr(header); } return header; } void QArrayData::deallocate(QArrayData *data, size_t objectSize, size_t alignment) Q_DECL_NOTHROW { // Alignment is a power of two Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData) && !(alignment & (alignment - 1))); Q_UNUSED(objectSize) Q_UNUSED(alignment) #if !defined(QT_NO_UNSHARABLE_CONTAINERS) if (data == &qt_array_unsharable_empty) return; #endif Q_ASSERT_X(data == 0 || !data->ref.isStatic(), "QArrayData::deallocate", "Static data can not be deleted"); ::free(data); }
QTypedArrayData
以模板來泛化 QArrayData,提供了迭代器
template <class T> struct QTypedArrayData : QArrayData { #ifdef QT_STRICT_ITERATORS class iterator { public: T *i; typedef std::random_access_iterator_tag iterator_category; typedef int difference_type; typedef T value_type; typedef T *pointer; typedef T &reference; inline iterator() : i(Q_NULLPTR) {} inline iterator(T *n) : i(n) {} inline iterator(const iterator &o): i(o.i){} // #### Qt 6: remove, the implicit version is fine inline T &operator*() const { return *i; } inline T *operator->() const { return i; } inline T &operator[](int j) const { return *(i + j); } inline bool operator==(const iterator &o) const { return i == o.i; } inline bool operator!=(const iterator &o) const { return i != o.i; } inline bool operator<(const iterator& other) const { return i < other.i; } inline bool operator<=(const iterator& other) const { return i <= other.i; } inline bool operator>(const iterator& other) const { return i > other.i; } inline bool operator>=(const iterator& other) const { return i >= other.i; } inline iterator &operator++() { ++i; return *this; } inline iterator operator++(int) { T *n = i; ++i; return n; } inline iterator &operator--() { i--; return *this; } inline iterator operator--(int) { T *n = i; i--; return n; } inline iterator &operator+=(int j) { i+=j; return *this; } inline iterator &operator-=(int j) { i-=j; return *this; } inline iterator operator+(int j) const { return iterator(i+j); } inline iterator operator-(int j) const { return iterator(i-j); } inline int operator-(iterator j) const { return i - j.i; } inline operator T*() const { return i; } }; friend class iterator; class const_iterator { public: const T *i; typedef std::random_access_iterator_tag iterator_category; typedef int difference_type; typedef T value_type; typedef const T *pointer; typedef const T &reference; inline const_iterator() : i(Q_NULLPTR) {} inline const_iterator(const T *n) : i(n) {} inline const_iterator(const const_iterator &o): i(o.i) {} // #### Qt 6: remove, the default version is fine inline explicit const_iterator(const iterator &o): i(o.i) {} inline const T &operator*() const { return *i; } inline const T *operator->() const { return i; } inline const T &operator[](int j) const { return *(i + j); } inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline bool operator<(const const_iterator& other) const { return i < other.i; } inline bool operator<=(const const_iterator& other) const { return i <= other.i; } inline bool operator>(const const_iterator& other) const { return i > other.i; } inline bool operator>=(const const_iterator& other) const { return i >= other.i; } inline const_iterator &operator++() { ++i; return *this; } inline const_iterator operator++(int) { const T *n = i; ++i; return n; } inline const_iterator &operator--() { i--; return *this; } inline const_iterator operator--(int) { const T *n = i; i--; return n; } inline const_iterator &operator+=(int j) { i+=j; return *this; } inline const_iterator &operator-=(int j) { i-=j; return *this; } inline const_iterator operator+(int j) const { return const_iterator(i+j); } inline const_iterator operator-(int j) const { return const_iterator(i-j); } inline int operator-(const_iterator j) const { return i - j.i; } inline operator const T*() const { return i; } }; friend class const_iterator; #else typedef T* iterator; typedef const T* const_iterator; #endif T *data() { return static_cast<T *>(QArrayData::data()); } const T *data() const { return static_cast<const T *>(QArrayData::data()); } iterator begin(iterator = iterator()) { return data(); } iterator end(iterator = iterator()) { return data() + size; } const_iterator begin(const_iterator = const_iterator()) const { return data(); } const_iterator end(const_iterator = const_iterator()) const { return data() + size; } const_iterator constBegin(const_iterator = const_iterator()) const { return data(); } const_iterator constEnd(const_iterator = const_iterator()) const { return data() + size; } class AlignmentDummy { QArrayData header; T data; }; static QTypedArrayData *allocate(size_t capacity, AllocationOptions options = Default) Q_REQUIRED_RESULT { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T), Q_ALIGNOF(AlignmentDummy), capacity, options)); } static void deallocate(QArrayData *data) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy)); } static QTypedArrayData *fromRawData(const T *data, size_t n, AllocationOptions options = Default) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QTypedArrayData *result = allocate(0, options | RawData); if (result) { Q_ASSERT(!result->ref.isShared()); // No shared empty, please! result->offset = reinterpret_cast<const char *>(data) - reinterpret_cast<const char *>(result); result->size = int(n); } return result; } static QTypedArrayData *sharedNull() Q_DECL_NOTHROW { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return static_cast<QTypedArrayData *>(QArrayData::sharedNull()); } static QTypedArrayData *sharedEmpty() { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return allocate(/* capacity */ 0); } #if !defined(QT_NO_UNSHARABLE_CONTAINERS) static QTypedArrayData *unsharableEmpty() { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return allocate(/* capacity */ 0, Unsharable); } #endif };
QStaticArrayData和QArrayDataPointerRef
template <class T, size_t N>
struct QStaticArrayData
{
QArrayData header;
T data[N];
};
// Support for returning QArrayDataPointer<T> from functions
template <class T>
struct QArrayDataPointerRef
{
QTypedArrayData<T> *ptr;
};