qvarlengtharray.h

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (qt-info@nokia.com)
00006 **
00007 ** This file is part of the QtCore module of the Qt Toolkit.
00008 **
00009 ** $QT_BEGIN_LICENSE:LGPL$
00010 ** Commercial Usage
00011 ** Licensees holding valid Qt Commercial licenses may use this file in
00012 ** accordance with the Qt Commercial License Agreement provided with the
00013 ** Software or, alternatively, in accordance with the terms contained in
00014 ** a written agreement between you and Nokia.
00015 **
00016 ** GNU Lesser General Public License Usage
00017 ** Alternatively, this file may be used under the terms of the GNU Lesser
00018 ** General Public License version 2.1 as published by the Free Software
00019 ** Foundation and appearing in the file LICENSE.LGPL included in the
00020 ** packaging of this file.  Please review the following information to
00021 ** ensure the GNU Lesser General Public License version 2.1 requirements
00022 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
00023 **
00024 ** In addition, as a special exception, Nokia gives you certain additional
00025 ** rights.  These rights are described in the Nokia Qt LGPL Exception
00026 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this module.
00027 **
00028 ** GNU General Public License Usage
00029 ** Alternatively, this file may be used under the terms of the GNU
00030 ** General Public License version 3.0 as published by the Free Software
00031 ** Foundation and appearing in the file LICENSE.GPL included in the
00032 ** packaging of this file.  Please review the following information to
00033 ** ensure the GNU General Public License version 3.0 requirements will be
00034 ** met: http://www.gnu.org/copyleft/gpl.html.
00035 **
00036 ** If you have questions regarding the use of this file, please contact
00037 ** Nokia at qt-info@nokia.com.
00038 ** $QT_END_LICENSE$
00039 **
00040 ****************************************************************************/
00041 
00042 #ifndef QVARLENGTHARRAY_H
00043 #define QVARLENGTHARRAY_H
00044 
00045 #include <QtCore/qcontainerfwd.h>
00046 #include <QtCore/qglobal.h>
00047 #include <new>
00048 
00049 QT_BEGIN_HEADER
00050 
00051 QT_BEGIN_NAMESPACE
00052 
00053 QT_MODULE(Core)
00054 
00055 template<class T, int Prealloc>
00056 class QPodList;
00057 
00058 // Prealloc = 256 by default, specified in qcontainerfwd.h
00059 template<class T, int Prealloc>
00060 class QVarLengthArray
00061 {
00062 public:
00063     inline explicit QVarLengthArray(int size = 0);
00064 
00065     inline QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
00066         : a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
00067     {
00068         append(other.constData(), other.size());
00069     }
00070 
00071     inline ~QVarLengthArray() {
00072         if (QTypeInfo<T>::isComplex) {
00073             T *i = ptr + s;
00074             while (i-- != ptr)
00075                 i->~T();
00076         }
00077         if (ptr != reinterpret_cast<T *>(array))
00078             qFree(ptr);
00079     }
00080     inline QVarLengthArray<T, Prealloc> &operator=(const QVarLengthArray<T, Prealloc> &other)
00081     {
00082         if (this != &other) {
00083             clear();
00084             append(other.constData(), other.size());
00085         }
00086         return *this;
00087     }
00088 
00089     inline void removeLast() {
00090         Q_ASSERT(s > 0);
00091         realloc(s - 1, a);
00092     }
00093     inline int size() const { return s; }
00094     inline int count() const { return s; }
00095     inline bool isEmpty() const { return (s == 0); }
00096     inline void resize(int size);
00097     inline void clear() { resize(0); }
00098 
00099     inline int capacity() const { return a; }
00100     inline void reserve(int size);
00101 
00102     inline T &operator[](int idx) {
00103         Q_ASSERT(idx >= 0 && idx < s);
00104         return ptr[idx];
00105     }
00106     inline const T &operator[](int idx) const {
00107         Q_ASSERT(idx >= 0 && idx < s);
00108         return ptr[idx];
00109     }
00110     inline const T &at(int idx) const { return operator[](idx); }
00111 
00112     T value(int i) const;
00113     T value(int i, const T &defaultValue) const;
00114 
00115     inline void append(const T &t) {
00116         if (s == a)   // i.e. s != 0
00117             realloc(s, s<<1);
00118         const int idx = s++;
00119         if (QTypeInfo<T>::isComplex) {
00120             new (ptr + idx) T(t);
00121         } else {
00122             ptr[idx] = t;
00123         }
00124     }
00125     void append(const T *buf, int size);
00126 
00127     inline T *data() { return ptr; }
00128     inline const T *data() const { return ptr; }
00129     inline const T * constData() const { return ptr; }
00130     typedef int size_type;
00131     typedef T value_type;
00132     typedef value_type *pointer;
00133     typedef const value_type *const_pointer;
00134     typedef value_type &reference;
00135     typedef const value_type &const_reference;
00136     typedef qptrdiff difference_type;
00137 
00138 private:
00139     friend class QPodList<T, Prealloc>;
00140     void realloc(int size, int alloc);
00141 
00142     int a;      // capacity
00143     int s;      // size
00144     T *ptr;     // data
00145     union {
00146         // ### Qt 5: Use 'Prealloc * sizeof(T)' as array size
00147         char array[sizeof(qint64) * (((Prealloc * sizeof(T)) / sizeof(qint64)) + 1)];
00148         qint64 q_for_alignment_1;
00149         double q_for_alignment_2;
00150     };
00151 };
00152 
00153 template <class T, int Prealloc>
00154 Q_INLINE_TEMPLATE QVarLengthArray<T, Prealloc>::QVarLengthArray(int asize)
00155     : s(asize) {
00156     if (s > Prealloc) {
00157         ptr = reinterpret_cast<T *>(qMalloc(s * sizeof(T)));
00158         Q_CHECK_PTR(ptr);
00159         a = s;
00160     } else {
00161         ptr = reinterpret_cast<T *>(array);
00162         a = Prealloc;
00163     }
00164     if (QTypeInfo<T>::isComplex) {
00165         T *i = ptr + s;
00166         while (i != ptr)
00167             new (--i) T;
00168     }
00169 }
00170 
00171 template <class T, int Prealloc>
00172 Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::resize(int asize)
00173 { realloc(asize, qMax(asize, a)); }
00174 
00175 template <class T, int Prealloc>
00176 Q_INLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::reserve(int asize)
00177 { if (asize > a) realloc(s, asize); }
00178 
00179 template <class T, int Prealloc>
00180 Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int increment)
00181 {
00182     Q_ASSERT(abuf);
00183     if (increment <= 0)
00184         return;
00185 
00186     const int asize = s + increment;
00187 
00188     if (asize >= a)
00189         realloc(s, qMax(s*2, asize));
00190 
00191     if (QTypeInfo<T>::isComplex) {
00192         // call constructor for new objects (which can throw)
00193         while (s < asize)
00194             new (ptr+(s++)) T(*abuf++);
00195     } else {
00196         qMemCopy(&ptr[s], abuf, increment * sizeof(T));
00197         s = asize;
00198     }
00199 }
00200 
00201 template <class T, int Prealloc>
00202 Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int aalloc)
00203 {
00204     Q_ASSERT(aalloc >= asize);
00205     T *oldPtr = ptr;
00206     int osize = s;
00207 
00208     const int copySize = qMin(asize, osize);
00209     if (aalloc != a) {
00210         ptr = reinterpret_cast<T *>(qMalloc(aalloc * sizeof(T)));
00211         Q_CHECK_PTR(ptr);
00212         if (ptr) {
00213             s = 0;
00214             a = aalloc;
00215 
00216             if (QTypeInfo<T>::isStatic) {
00217                 QT_TRY {
00218                     // copy all the old elements
00219                     while (s < copySize) {
00220                         new (ptr+s) T(*(oldPtr+s));
00221                         (oldPtr+s)->~T();
00222                         s++;
00223                     }
00224                 } QT_CATCH(...) {
00225                     // clean up all the old objects and then free the old ptr
00226                     int sClean = s;
00227                     while (sClean < osize)
00228                         (oldPtr+(sClean++))->~T();
00229                     if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
00230                         qFree(oldPtr);
00231                     QT_RETHROW;
00232                 }
00233             } else {
00234                 qMemCopy(ptr, oldPtr, copySize * sizeof(T));
00235             }
00236         } else {
00237             ptr = oldPtr;
00238             return;
00239         }
00240     }
00241     s = copySize;
00242 
00243     if (QTypeInfo<T>::isComplex) {
00244         // destroy remaining old objects
00245         while (osize > asize)
00246             (oldPtr+(--osize))->~T();
00247     }
00248 
00249     if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
00250         qFree(oldPtr);
00251 
00252     if (QTypeInfo<T>::isComplex) {
00253         // call default constructor for new objects (which can throw)
00254         while (s < asize)
00255             new (ptr+(s++)) T;
00256     } else {
00257         s = asize;
00258     }
00259 }
00260 
00261 template <class T, int Prealloc>
00262 Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i) const
00263 {
00264     if (i < 0 || i >= size()) {
00265         return T();
00266     }
00267     return at(i);
00268 }
00269 template <class T, int Prealloc>
00270 Q_OUTOFLINE_TEMPLATE T QVarLengthArray<T, Prealloc>::value(int i, const T &defaultValue) const
00271 {
00272     return (i < 0 || i >= size()) ? defaultValue : at(i);
00273 }
00274 
00275 
00276 QT_END_NAMESPACE
00277 
00278 QT_END_HEADER
00279 
00280 #endif // QVARLENGTHARRAY_H