/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QRAWVECTOR_H #define QRAWVECTOR_H #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE struct QVectorData { QtPrivate::RefCount ref; int size; uint alloc : 31; uint capacityReserved : 1; qptrdiff offset; void* data() { return reinterpret_cast(this) + this->offset; } static const QVectorData shared_null; static QVectorData *allocate(int size, int alignment); static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment); static void free(QVectorData *data, int alignment); static int grow(int sizeOfHeader, int size, int sizeOfT); }; template struct QVectorTypedData : QVectorData { T* begin() { return reinterpret_cast(this->data()); } T* end() { return begin() + this->size; } static QVectorTypedData *sharedNull() { return static_cast(const_cast(&QVectorData::shared_null)); } }; template class QRawVector { typedef QVectorTypedData Data; T *m_begin; int m_size; int m_alloc; public: static Data *toBase(T *begin) { return (Data*)((char*)begin - offsetOfTypedData()); } static T *fromBase(void *d) { return (T*)((char*)d + offsetOfTypedData()); } inline QRawVector() { m_begin = fromBase(0); m_alloc = m_size = 0; realloc(m_size, m_alloc, true); } explicit QRawVector(int size); QRawVector(int size, const T &t); inline QRawVector(const QRawVector &v) { m_begin = v.m_begin; m_alloc = v.m_alloc; m_size = v.m_size; realloc(m_size, m_alloc, true); } inline ~QRawVector() { free(m_begin, m_size); } QRawVector &operator=(const QRawVector &v); bool operator==(const QRawVector &v) const; inline bool operator!=(const QRawVector &v) const { return !(*this == v); } inline int size() const { return m_size; } inline bool isEmpty() const { return m_size == 0; } void resize(int size); inline int capacity() const { return m_alloc; } void reserve(int size); inline void squeeze() { realloc(m_size, m_size, false); } inline T *data() { return m_begin; } inline const T *data() const { return m_begin; } inline const T *constData() const { return m_begin; } void clear(); const T &at(int i) const; T &operator[](int i); const T &operator[](int i) const; void append(const T &t); void prepend(const T &t); void insert(int i, const T &t); void insert(int i, int n, const T &t); void replace(int i, const T &t); void remove(int i); void remove(int i, int n); QRawVector &fill(const T &t, int size = -1); int indexOf(const T &t, int from = 0) const; int lastIndexOf(const T &t, int from = -1) const; bool contains(const T &t) const; int count(const T &t) const; #ifdef QT_STRICT_ITERATORS class iterator { public: T *i; typedef std::random_access_iterator_tag iterator_category; typedef ptrdiff_t difference_type; typedef T value_type; typedef T *pointer; typedef T &reference; inline iterator() : i(0) {} inline iterator(T *n) : i(n) {} inline iterator(const iterator &o): i(o.i){} 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; } }; friend class iterator; class const_iterator { public: T *i; typedef std::random_access_iterator_tag iterator_category; typedef ptrdiff_t difference_type; typedef T value_type; typedef const T *pointer; typedef const T &reference; inline const_iterator() : i(0) {} inline const_iterator(T *n) : i(n) {} inline const_iterator(const const_iterator &o): i(o.i) {} 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) { T *n = i; ++i; return n; } inline const_iterator &operator--() { i--; return *this; } inline const_iterator operator--(int) { 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; } }; friend class const_iterator; #else // STL-style typedef T *iterator; typedef const T *const_iterator; #endif inline iterator begin() { return m_begin; } inline const_iterator begin() const { return m_begin; } inline const_iterator constBegin() const { return m_begin; } inline iterator end() { return m_begin + m_size; } inline const_iterator end() const { return m_begin + m_size; } inline const_iterator constEnd() const { return m_begin + m_size; } iterator insert(iterator before, int n, const T &x); inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); } iterator erase(iterator begin, iterator end); inline iterator erase(iterator pos) { return erase(pos, pos+1); } // more Qt inline int count() const { return m_size; } inline T& first() { Q_ASSERT(!isEmpty()); return *begin(); } inline const T &first() const { Q_ASSERT(!isEmpty()); return *begin(); } inline T& last() { Q_ASSERT(!isEmpty()); return *(end()-1); } inline const T &last() const { Q_ASSERT(!isEmpty()); return *(end()-1); } inline bool startsWith(const T &t) const { return !isEmpty() && first() == t; } inline bool endsWith(const T &t) const { return !isEmpty() && last() == t; } QRawVector mid(int pos, int length = -1) const; T value(int i) const; T value(int i, const T &defaultValue) const; // STL compatibility typedef T value_type; typedef value_type *pointer; typedef const value_type *const_pointer; typedef value_type &reference; typedef const value_type &const_reference; typedef ptrdiff_t difference_type; typedef iterator Iterator; typedef const_iterator ConstIterator; typedef int size_type; inline void push_back(const T &t) { append(t); } inline void push_front(const T &t) { prepend(t); } void pop_back() { Q_ASSERT(!isEmpty()); erase(end()-1); } void pop_front() { Q_ASSERT(!isEmpty()); erase(begin()); } inline bool empty() const { return m_size == 0; } inline T &front() { return first(); } inline const_reference front() const { return first(); } inline reference back() { return last(); } inline const_reference back() const { return last(); } // comfort QRawVector &operator+=(const QRawVector &l); inline QRawVector operator+(const QRawVector &l) const { QRawVector n = *this; n += l; return n; } inline QRawVector &operator+=(const T &t) { append(t); return *this; } inline QRawVector &operator<< (const T &t) { append(t); return *this; } inline QRawVector &operator<<(const QRawVector &l) { *this += l; return *this; } QList toList() const; //static QRawVector fromList(const QList &list); static inline QRawVector fromStdVector(const std::vector &vector) { QRawVector tmp; qCopy(vector.begin(), vector.end(), std::back_inserter(tmp)); return tmp; } inline std::vector toStdVector() const { std::vector tmp; qCopy(constBegin(), constEnd(), std::back_inserter(tmp)); return tmp; } private: T *allocate(int alloc); void realloc(int size, int alloc, bool ref); void free(T *begin, int size); class AlignmentDummy { QVectorData header; T array[1]; }; static Q_DECL_CONSTEXPR int offsetOfTypedData() { // (non-POD)-safe offsetof(AlignmentDummy, array) return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1); } static Q_DECL_CONSTEXPR int alignOfTypedData() { #ifdef Q_ALIGNOF return Q_ALIGNOF(AlignmentDummy); #else return sizeof(void *); #endif } public: QVector mutateToVector() { Data *d = toBase(m_begin); d->ref.initializeOwned(); d->alloc = m_alloc; d->size = m_size; d->capacityReserved = 0; d->offset = offsetOfTypedData(); QVector v; *reinterpret_cast(&v) = d; m_begin = fromBase(0); m_size = m_alloc = 0; return v; } }; template void QRawVector::reserve(int asize) { if (asize > m_alloc) realloc(m_size, asize, false); } template void QRawVector::resize(int asize) { realloc(asize, (asize > m_alloc || (asize < m_size && asize < (m_alloc >> 1))) ? QVectorData::grow(offsetOfTypedData(), asize, sizeof(T)) : m_alloc, false); } template inline void QRawVector::clear() { *this = QRawVector(); } template inline const T &QRawVector::at(int i) const { Q_ASSERT_X(i >= 0 && i < m_size, "QRawVector::at", "index out of range"); return m_begin[i]; } template inline const T &QRawVector::operator[](int i) const { Q_ASSERT_X(i >= 0 && i < m_size, "QRawVector::operator[]", "index out of range"); return m_begin[i]; } template inline T &QRawVector::operator[](int i) { Q_ASSERT_X(i >= 0 && i < m_size, "QRawVector::operator[]", "index out of range"); return data()[i]; } template inline void QRawVector::insert(int i, const T &t) { Q_ASSERT_X(i >= 0 && i <= m_size, "QRawVector::insert", "index out of range"); insert(begin() + i, 1, t); } template inline void QRawVector::insert(int i, int n, const T &t) { Q_ASSERT_X(i >= 0 && i <= m_size, "QRawVector::insert", "index out of range"); insert(begin() + i, n, t); } template inline void QRawVector::remove(int i, int n) { Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= m_size, "QRawVector::remove", "index out of range"); erase(begin() + i, begin() + i + n); } template inline void QRawVector::remove(int i) { Q_ASSERT_X(i >= 0 && i < m_size, "QRawVector::remove", "index out of range"); erase(begin() + i, begin() + i + 1); } template inline void QRawVector::prepend(const T &t) { insert(begin(), 1, t); } template inline void QRawVector::replace(int i, const T &t) { Q_ASSERT_X(i >= 0 && i < m_size, "QRawVector::replace", "index out of range"); const T copy(t); data()[i] = copy; } template QRawVector &QRawVector::operator=(const QRawVector &v) { if (this != &v) { free(m_begin, m_size); m_alloc = v.m_alloc; m_size = v.m_size; m_begin = v.m_begin; realloc(m_size, m_alloc, true); } return *this; } template inline T *QRawVector::allocate(int aalloc) { QVectorData *d = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData()); Q_CHECK_PTR(d); return fromBase(d); } template QRawVector::QRawVector(int asize) { m_size = m_alloc = asize; m_begin = allocate(asize); if (QTypeInfo::isComplex) { T *b = m_begin; T *i = m_begin + m_size; while (i != b) new (--i) T; } else { memset(m_begin, 0, asize * sizeof(T)); } } template QRawVector::QRawVector(int asize, const T &t) { m_size = m_alloc = asize; m_begin = allocate(asize); T *i = m_begin + m_size; while (i != m_begin) new (--i) T(t); } template void QRawVector::free(T *begin, int size) { if (QTypeInfo::isComplex) { T *i = begin + size; while (i-- != begin) i->~T(); } Data *x = toBase(begin); x->free(x, alignOfTypedData()); } template void QRawVector::realloc(int asize, int aalloc, bool ref) { if (QTypeInfo::isComplex && asize < m_size && !ref) { // call the destructor on all objects that need to be // destroyed when shrinking T *pOld = m_begin + m_size; while (asize < m_size) { (--pOld)->~T(); --m_size; } } int xalloc = m_alloc; int xsize = m_size; bool changed = false; T *xbegin = m_begin; if (aalloc != xalloc || ref) { // (re)allocate memory if (QTypeInfo::isStatic) { xbegin = allocate(aalloc); xsize = 0; changed = true; } else if (ref) { xbegin = allocate(aalloc); if (QTypeInfo::isComplex) { xsize = 0; } else { ::memcpy(xbegin, m_begin, qMin(aalloc, xalloc) * sizeof(T)); xsize = m_size; } changed = true; } else { QT_TRY { QVectorData *mem = QVectorData::reallocate(toBase(m_begin), offsetOfTypedData() + aalloc * sizeof(T), offsetOfTypedData() + xalloc * sizeof(T), alignOfTypedData()); Q_CHECK_PTR(mem); xbegin = fromBase(mem); xsize = m_size; } QT_CATCH (const std::bad_alloc &) { if (aalloc > xalloc) // ignore the error in case we are just shrinking. QT_RETHROW; } } xalloc = aalloc; } if (QTypeInfo::isComplex) { QT_TRY { T *pOld = m_begin + xsize; T *pNew = xbegin + xsize; // copy objects from the old array into the new array while (xsize < qMin(asize, m_size)) { new (pNew++) T(*pOld++); ++xsize; } // construct all new objects when growing while (xsize < asize) { new (pNew++) T; ++xsize; } } QT_CATCH (...) { free(xbegin, xsize); QT_RETHROW; } } else if (asize > xsize) { // initialize newly allocated memory to 0 memset(xbegin + xsize, 0, (asize - xsize) * sizeof(T)); } xsize = asize; if (changed) { if (!ref) free(m_begin, m_size); } m_alloc = xalloc; m_size = xsize; m_begin = xbegin; } template Q_OUTOFLINE_TEMPLATE T QRawVector::value(int i) const { return (i < 0 || i >= m_size) ? T() : m_begin[i]; } template Q_OUTOFLINE_TEMPLATE T QRawVector::value(int i, const T &defaultValue) const { return (i < 0 || i >= m_size) ? defaultValue : m_begin[i]; } template void QRawVector::append(const T &t) { if (m_size + 1 > m_alloc) { const T copy(t); realloc(m_size, QVectorData::grow(offsetOfTypedData(), m_size + 1, sizeof(T)), false); if (QTypeInfo::isComplex) new (m_begin + m_size) T(copy); else m_begin[m_size] = copy; } else { if (QTypeInfo::isComplex) new (m_begin + m_size) T(t); else m_begin[m_size] = t; } ++m_size; } template typename QRawVector::iterator QRawVector::insert(iterator before, size_type n, const T &t) { int offset = int(before - m_begin); if (n != 0) { const T copy(t); if (m_size + n > m_alloc) realloc(m_size, QVectorData::grow(offsetOfTypedData(), m_size + n, sizeof(T)), false); if (QTypeInfo::isStatic) { T *b = m_begin + m_size; T *i = m_begin + m_size + n; while (i != b) new (--i) T; i = m_begin + m_size; T *j = i + n; b = m_begin + offset; while (i != b) *--j = *--i; i = b+n; while (i != b) *--i = copy; } else { T *b = m_begin + offset; T *i = b + n; memmove(i, b, (m_size - offset) * sizeof(T)); while (i != b) new (--i) T(copy); } m_size += n; } return m_begin + offset; } template typename QRawVector::iterator QRawVector::erase(iterator abegin, iterator aend) { int f = int(abegin - m_begin); int l = int(aend - m_begin); int n = l - f; if (QTypeInfo::isComplex) { qCopy(m_begin + l, m_begin + m_size, m_begin + f); T *i = m_begin + m_size; T *b = m_begin + m_size - n; while (i != b) { --i; i->~T(); } } else { memmove(m_begin + f, m_begin + l, (m_size - l) * sizeof(T)); } m_size -= n; return m_begin + f; } template bool QRawVector::operator==(const QRawVector &v) const { if (m_size != v.m_size) return false; T* b = m_begin; T* i = b + m_size; T* j = v.m_begin + m_size; while (i != b) if (!(*--i == *--j)) return false; return true; } template QRawVector &QRawVector::fill(const T &from, int asize) { const T copy(from); resize(asize < 0 ? m_size : asize); if (m_size) { T *i = m_begin + m_size; T *b = m_begin; while (i != b) *--i = copy; } return *this; } template QRawVector &QRawVector::operator+=(const QRawVector &l) { int newSize = m_size + l.m_size; realloc(m_size, newSize, false); T *w = m_begin + newSize; T *i = l.m_begin + l.m_size; T *b = l.m_begin; while (i != b) { if (QTypeInfo::isComplex) new (--w) T(*--i); else *--w = *--i; } m_size = newSize; return *this; } template int QRawVector::indexOf(const T &t, int from) const { if (from < 0) from = qMax(from + m_size, 0); if (from < m_size) { T* n = m_begin + from - 1; T* e = m_begin + m_size; while (++n != e) if (*n == t) return n - m_begin; } return -1; } template int QRawVector::lastIndexOf(const T &t, int from) const { if (from < 0) from += m_size; else if (from >= m_size) from = m_size-1; if (from >= 0) { T* b = m_begin; T* n = m_begin + from + 1; while (n != b) { if (*--n == t) return n - b; } } return -1; } template bool QRawVector::contains(const T &t) const { T* b = m_begin; T* i = m_begin + m_size; while (i != b) if (*--i == t) return true; return false; } template int QRawVector::count(const T &t) const { int c = 0; T* b = m_begin; T* i = m_begin + m_size; while (i != b) if (*--i == t) ++c; return c; } template Q_OUTOFLINE_TEMPLATE QRawVector QRawVector::mid(int pos, int length) const { if (length < 0) length = size() - pos; if (pos == 0 && length == size()) return *this; QRawVector copy; if (pos + length > size()) length = size() - pos; for (int i = pos; i < pos + length; ++i) copy += at(i); return copy; } template Q_OUTOFLINE_TEMPLATE QList QRawVector::toList() const { QList result; for (int i = 0; i < size(); ++i) result.append(at(i)); return result; } /*template Q_OUTOFLINE_TEMPLATE QRawVector QList::toVector() const { QRawVector result(size()); for (int i = 0; i < size(); ++i) result[i] = at(i); return result; } template QRawVector QRawVector::fromList(const QList &list) { return list.toVector(); } template QList QList::fromVector(const QRawVector &vector) { return vector.toList(); } */ Q_DECLARE_SEQUENTIAL_ITERATOR(RawVector) Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR(RawVector) QT_END_NAMESPACE #endif // QRAWVECTOR_H