Go to the
documentation of this file.
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #ifndef QCONTIGUOUSCACHE_H
00043 #define QCONTIGUOUSCACHE_H
00044
00045 #include <QtCore/qatomic.h>
00046 #include <limits.h>
00047 #include <new>
00048
00049 QT_BEGIN_HEADER
00050
00051 QT_BEGIN_NAMESPACE
00052
00053 #undef QT_QCONTIGUOUSCACHE_DEBUG
00054 QT_MODULE(Core)
00055
00056
00057 struct Q_CORE_EXPORT QContiguousCacheData
00058 {
00059 QBasicAtomicInt ref;
00060 int alloc;
00061 int count;
00062 int start;
00063 int offset;
00064 uint sharable : 1;
00065 uint reserved : 31;
00066
00067
00068
00069
00070
00071
00072 static QContiguousCacheData *allocate(int size, int alignment);
00073 static void free(QContiguousCacheData *data);
00074
00075 #ifdef QT_QCONTIGUOUSCACHE_DEBUG
00076 void dump() const;
00077 #endif
00078 };
00079
00080 template <typename T>
00081 struct QContiguousCacheTypedData: private QContiguousCacheData
00082 {
00083
00084 T array[1];
00085
00086 static inline void free(QContiguousCacheTypedData *data) { QContiguousCacheData::free(data); }
00087 };
00088
00089 template<typename T>
00090 class QContiguousCache {
00091 typedef QContiguousCacheTypedData<T> Data;
00092 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; };
00093 public:
00094
00095 typedef T value_type;
00096 typedef value_type* pointer;
00097 typedef const value_type* const_pointer;
00098 typedef value_type& reference;
00099 typedef const value_type& const_reference;
00100 typedef qptrdiff difference_type;
00101 typedef int size_type;
00102
00103 explicit QContiguousCache(int capacity = 0);
00104 QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
00105
00106 inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(p); }
00107
00108 inline void detach() { if (d->ref != 1) detach_helper(); }
00109 inline bool isDetached() const { return d->ref == 1; }
00110 inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
00111
00112 QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
00113 bool operator==(const QContiguousCache<T> &other) const;
00114 inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); }
00115
00116 inline int capacity() const {return d->alloc; }
00117 inline int count() const { return d->count; }
00118 inline int size() const { return d->count; }
00119
00120 inline bool isEmpty() const { return d->count == 0; }
00121 inline bool isFull() const { return d->count == d->alloc; }
00122 inline int available() const { return d->alloc - d->count; }
00123
00124 void clear();
00125 void setCapacity(int size);
00126
00127 const T &at(int pos) const;
00128 T &operator[](int i);
00129 const T &operator[](int i) const;
00130
00131 void append(const T &value);
00132 void prepend(const T &value);
00133 void insert(int pos, const T &value);
00134
00135 inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; }
00136 inline int firstIndex() const { return d->offset; }
00137 inline int lastIndex() const { return d->offset + d->count - 1; }
00138
00139 inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; }
00140 inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; }
00141 inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; }
00142 inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; }
00143
00144 void removeFirst();
00145 T takeFirst();
00146 void removeLast();
00147 T takeLast();
00148
00149 inline bool areIndexesValid() const
00150 { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; }
00151
00152 inline void normalizeIndexes() { d->offset = d->start; }
00153
00154 #ifdef QT_QCONTIGUOUSCACHE_DEBUG
00155 void dump() const { p->dump(); }
00156 #endif
00157 private:
00158 void detach_helper();
00159
00160 QContiguousCacheData *malloc(int aalloc);
00161 void free(Data *x);
00162 int sizeOfTypedData() {
00163
00164
00165 return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this);
00166 }
00167 int alignOfTypedData() const
00168 {
00169 #ifdef Q_ALIGNOF
00170 return qMax<int>(sizeof(void*), Q_ALIGNOF(Data));
00171 #else
00172 return 0;
00173 #endif
00174 }
00175 };
00176
00177 template <typename T>
00178 void QContiguousCache<T>::detach_helper()
00179 {
00180 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
00181
00182 x.d = malloc(d->alloc);
00183 x.d->ref = 1;
00184 x.d->count = d->count;
00185 x.d->start = d->start;
00186 x.d->offset = d->offset;
00187 x.d->alloc = d->alloc;
00188 x.d->sharable = true;
00189 x.d->reserved = 0;
00190
00191 T *dest = x.p->array + x.d->start;
00192 T *src = p->array + d->start;
00193 int oldcount = x.d->count;
00194 while (oldcount--) {
00195 if (QTypeInfo<T>::isComplex) {
00196 new (dest) T(*src);
00197 } else {
00198 *dest = *src;
00199 }
00200 dest++;
00201 if (dest == x.p->array + x.d->alloc)
00202 dest = x.p->array;
00203 src++;
00204 if (src == p->array + d->alloc)
00205 src = p->array;
00206 }
00207
00208 if (!d->ref.deref())
00209 free(p);
00210 d = x.d;
00211 }
00212
00213 template <typename T>
00214 void QContiguousCache<T>::setCapacity(int asize)
00215 {
00216 if (asize == d->alloc)
00217 return;
00218 detach();
00219 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
00220 x.d = malloc(asize);
00221 x.d->alloc = asize;
00222 x.d->count = qMin(d->count, asize);
00223 x.d->offset = d->offset + d->count - x.d->count;
00224 if(asize)
00225 x.d->start = x.d->offset % x.d->alloc;
00226 else
00227 x.d->start = 0;
00228
00229 int oldcount = x.d->count;
00230 if(oldcount)
00231 {
00232 T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc;
00233 T *src = p->array + (d->start + d->count-1) % d->alloc;
00234 while (oldcount--) {
00235 if (QTypeInfo<T>::isComplex) {
00236 new (dest) T(*src);
00237 } else {
00238 *dest = *src;
00239 }
00240 if (dest == x.p->array)
00241 dest = x.p->array + x.d->alloc;
00242 dest--;
00243 if (src == p->array)
00244 src = p->array + d->alloc;
00245 src--;
00246 }
00247 }
00248
00249 free(p);
00250 d = x.d;
00251 }
00252
00253 template <typename T>
00254 void QContiguousCache<T>::clear()
00255 {
00256 if (d->ref == 1) {
00257 if (QTypeInfo<T>::isComplex) {
00258 int oldcount = d->count;
00259 T * i = p->array + d->start;
00260 T * e = p->array + d->alloc;
00261 while (oldcount--) {
00262 i->~T();
00263 i++;
00264 if (i == e)
00265 i = p->array;
00266 }
00267 }
00268 d->count = d->start = d->offset = 0;
00269 } else {
00270 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
00271 x.d = malloc(d->alloc);
00272 x.d->ref = 1;
00273 x.d->alloc = d->alloc;
00274 x.d->count = x.d->start = x.d->offset = 0;
00275 x.d->sharable = true;
00276 if (!d->ref.deref()) free(p);
00277 d = x.d;
00278 }
00279 }
00280
00281 template <typename T>
00282 inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc)
00283 {
00284 return QContiguousCacheData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData());
00285 }
00286
00287 template <typename T>
00288 QContiguousCache<T>::QContiguousCache(int cap)
00289 {
00290 d = malloc(cap);
00291 d->ref = 1;
00292 d->alloc = cap;
00293 d->count = d->start = d->offset = 0;
00294 d->sharable = true;
00295 }
00296
00297 template <typename T>
00298 QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other)
00299 {
00300 other.d->ref.ref();
00301 if (!d->ref.deref())
00302 free(d);
00303 d = other.d;
00304 if (!d->sharable)
00305 detach_helper();
00306 return *this;
00307 }
00308
00309 template <typename T>
00310 bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const
00311 {
00312 if (other.d == d)
00313 return true;
00314 if (other.d->start != d->start
00315 || other.d->count != d->count
00316 || other.d->offset != d->offset
00317 || other.d->alloc != d->alloc)
00318 return false;
00319 for (int i = firstIndex(); i <= lastIndex(); ++i)
00320 if (!(at(i) == other.at(i)))
00321 return false;
00322 return true;
00323 }
00324
00325 template <typename T>
00326 void QContiguousCache<T>::free(Data *x)
00327 {
00328 if (QTypeInfo<T>::isComplex) {
00329 int oldcount = d->count;
00330 T * i = p->array + d->start;
00331 T * e = p->array + d->alloc;
00332 while (oldcount--) {
00333 i->~T();
00334 i++;
00335 if (i == e)
00336 i = p->array;
00337 }
00338 }
00339 x->free(x);
00340 }
00341 template <typename T>
00342 void QContiguousCache<T>::append(const T &value)
00343 {
00344 detach();
00345 if (QTypeInfo<T>::isComplex) {
00346 if (d->count == d->alloc)
00347 (p->array + (d->start+d->count) % d->alloc)->~T();
00348 new (p->array + (d->start+d->count) % d->alloc) T(value);
00349 } else {
00350 p->array[(d->start+d->count) % d->alloc] = value;
00351 }
00352
00353 if (d->count == d->alloc) {
00354 d->start++;
00355 d->start %= d->alloc;
00356 d->offset++;
00357 } else {
00358 d->count++;
00359 }
00360 }
00361
00362 template<typename T>
00363 void QContiguousCache<T>::prepend(const T &value)
00364 {
00365 detach();
00366 if (d->start)
00367 d->start--;
00368 else
00369 d->start = d->alloc-1;
00370 d->offset--;
00371
00372 if (d->count != d->alloc)
00373 d->count++;
00374 else
00375 if (d->count == d->alloc)
00376 (p->array + d->start)->~T();
00377
00378 if (QTypeInfo<T>::isComplex)
00379 new (p->array + d->start) T(value);
00380 else
00381 p->array[d->start] = value;
00382 }
00383
00384 template<typename T>
00385 void QContiguousCache<T>::insert(int pos, const T &value)
00386 {
00387 Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range");
00388 detach();
00389 if (containsIndex(pos)) {
00390 if(QTypeInfo<T>::isComplex)
00391 new (p->array + pos % d->alloc) T(value);
00392 else
00393 p->array[pos % d->alloc] = value;
00394 } else if (pos == d->offset-1)
00395 prepend(value);
00396 else if (pos == d->offset+d->count)
00397 append(value);
00398 else {
00399
00400 clear();
00401 d->offset = pos;
00402 d->start = pos % d->alloc;
00403 d->count = 1;
00404 if (QTypeInfo<T>::isComplex)
00405 new (p->array + d->start) T(value);
00406 else
00407 p->array[d->start] = value;
00408 }
00409 }
00410
00411 template <typename T>
00412 inline const T &QContiguousCache<T>::at(int pos) const
00413 { Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
00414 template <typename T>
00415 inline const T &QContiguousCache<T>::operator[](int pos) const
00416 { Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
00417
00418 template <typename T>
00419 inline T &QContiguousCache<T>::operator[](int pos)
00420 {
00421 detach();
00422 if (!containsIndex(pos))
00423 insert(pos, T());
00424 return p->array[pos % d->alloc];
00425 }
00426
00427 template <typename T>
00428 inline void QContiguousCache<T>::removeFirst()
00429 {
00430 Q_ASSERT(d->count > 0);
00431 detach();
00432 d->count--;
00433 if (QTypeInfo<T>::isComplex)
00434 (p->array + d->start)->~T();
00435 d->start = (d->start + 1) % d->alloc;
00436 d->offset++;
00437 }
00438
00439 template <typename T>
00440 inline void QContiguousCache<T>::removeLast()
00441 {
00442 Q_ASSERT(d->count > 0);
00443 detach();
00444 d->count--;
00445 if (QTypeInfo<T>::isComplex)
00446 (p->array + (d->start + d->count) % d->alloc)->~T();
00447 }
00448
00449 template <typename T>
00450 inline T QContiguousCache<T>::takeFirst()
00451 { T t = first(); removeFirst(); return t; }
00452
00453 template <typename T>
00454 inline T QContiguousCache<T>::takeLast()
00455 { T t = last(); removeLast(); return t; }
00456
00457 QT_END_NAMESPACE
00458
00459 QT_END_HEADER
00460
00461 #endif