source: trunk/src/corelib/tools/qcontiguouscache.h@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 13.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QCONTIGUOUSCACHE_H
43#define QCONTIGUOUSCACHE_H
44
45#include <QtCore/qatomic.h>
46#include <limits.h>
47#include <new>
48
49QT_BEGIN_HEADER
50
51QT_BEGIN_NAMESPACE
52
53#undef QT_QCONTIGUOUSCACHE_DEBUG
54QT_MODULE(Core)
55
56
57struct Q_CORE_EXPORT QContiguousCacheData
58{
59 QBasicAtomicInt ref;
60 int alloc;
61 int count;
62 int start;
63 int offset;
64 uint sharable : 1;
65 uint reserved : 31;
66
67 // total is 24 bytes (HP-UX aCC: 40 bytes)
68 // the next entry is already aligned to 8 bytes
69 // there will be an 8 byte gap here if T requires 16-byte alignment
70 // (such as long double on 64-bit platforms, __int128, __float128)
71
72 static QContiguousCacheData *allocate(int size, int alignment);
73 static void free(QContiguousCacheData *data);
74
75#ifdef QT_QCONTIGUOUSCACHE_DEBUG
76 void dump() const;
77#endif
78};
79
80template <typename T>
81struct QContiguousCacheTypedData: private QContiguousCacheData
82{
83 // private inheritance to avoid aliasing warningss
84 T array[1];
85
86 static inline void free(QContiguousCacheTypedData *data) { QContiguousCacheData::free(data); }
87};
88
89template<typename T>
90class QContiguousCache {
91 typedef QContiguousCacheTypedData<T> Data;
92 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; };
93public:
94 // STL compatibility
95 typedef T value_type;
96 typedef value_type* pointer;
97 typedef const value_type* const_pointer;
98 typedef value_type& reference;
99 typedef const value_type& const_reference;
100 typedef ptrdiff_t difference_type;
101 typedef int size_type;
102
103 explicit QContiguousCache(int capacity = 0);
104 QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
105
106 inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(p); }
107
108 inline void detach() { if (d->ref != 1) detach_helper(); }
109 inline bool isDetached() const { return d->ref == 1; }
110 inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; }
111
112 QContiguousCache<T> &operator=(const QContiguousCache<T> &other);
113 bool operator==(const QContiguousCache<T> &other) const;
114 inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); }
115
116 inline int capacity() const {return d->alloc; }
117 inline int count() const { return d->count; }
118 inline int size() const { return d->count; }
119
120 inline bool isEmpty() const { return d->count == 0; }
121 inline bool isFull() const { return d->count == d->alloc; }
122 inline int available() const { return d->alloc - d->count; }
123
124 void clear();
125 void setCapacity(int size);
126
127 const T &at(int pos) const;
128 T &operator[](int i);
129 const T &operator[](int i) const;
130
131 void append(const T &value);
132 void prepend(const T &value);
133 void insert(int pos, const T &value);
134
135 inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; }
136 inline int firstIndex() const { return d->offset; }
137 inline int lastIndex() const { return d->offset + d->count - 1; }
138
139 inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; }
140 inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; }
141 inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; }
142 inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; }
143
144 void removeFirst();
145 T takeFirst();
146 void removeLast();
147 T takeLast();
148
149 inline bool areIndexesValid() const
150 { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; }
151
152 inline void normalizeIndexes() { d->offset = d->start; }
153
154#ifdef QT_QCONTIGUOUSCACHE_DEBUG
155 void dump() const { p->dump(); }
156#endif
157private:
158 void detach_helper();
159
160 QContiguousCacheData *malloc(int aalloc);
161 void free(Data *x);
162 int sizeOfTypedData() {
163 // this is more or less the same as sizeof(Data), except that it doesn't
164 // count the padding at the end
165 return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this);
166 }
167 int alignOfTypedData() const
168 {
169#ifdef Q_ALIGNOF
170 return qMax<int>(sizeof(void*), Q_ALIGNOF(Data));
171#else
172 return 0;
173#endif
174 }
175};
176
177template <typename T>
178void QContiguousCache<T>::detach_helper()
179{
180 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
181
182 x.d = malloc(d->alloc);
183 x.d->ref = 1;
184 x.d->count = d->count;
185 x.d->start = d->start;
186 x.d->offset = d->offset;
187 x.d->alloc = d->alloc;
188 x.d->sharable = true;
189 x.d->reserved = 0;
190
191 T *dest = x.p->array + x.d->start;
192 T *src = p->array + d->start;
193 int oldcount = x.d->count;
194 while (oldcount--) {
195 if (QTypeInfo<T>::isComplex) {
196 new (dest) T(*src);
197 } else {
198 *dest = *src;
199 }
200 dest++;
201 if (dest == x.p->array + x.d->alloc)
202 dest = x.p->array;
203 src++;
204 if (src == p->array + d->alloc)
205 src = p->array;
206 }
207
208 if (!d->ref.deref())
209 free(p);
210 d = x.d;
211}
212
213template <typename T>
214void QContiguousCache<T>::setCapacity(int asize)
215{
216 if (asize == d->alloc)
217 return;
218 detach();
219 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
220 x.d = malloc(asize);
221 x.d->alloc = asize;
222 x.d->count = qMin(d->count, asize);
223 x.d->offset = d->offset + d->count - x.d->count;
224 x.d->start = x.d->offset % x.d->alloc;
225 T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc;
226 T *src = p->array + (d->start + d->count-1) % d->alloc;
227 int oldcount = x.d->count;
228 while (oldcount--) {
229 if (QTypeInfo<T>::isComplex) {
230 new (dest) T(*src);
231 } else {
232 *dest = *src;
233 }
234 if (dest == x.p->array)
235 dest = x.p->array + x.d->alloc;
236 dest--;
237 if (src == p->array)
238 src = p->array + d->alloc;
239 src--;
240 }
241 /* free old */
242 free(p);
243 d = x.d;
244}
245
246template <typename T>
247void QContiguousCache<T>::clear()
248{
249 if (d->ref == 1) {
250 if (QTypeInfo<T>::isComplex) {
251 int oldcount = d->count;
252 T * i = p->array + d->start;
253 T * e = p->array + d->alloc;
254 while (oldcount--) {
255 i->~T();
256 i++;
257 if (i == e)
258 i = p->array;
259 }
260 }
261 d->count = d->start = d->offset = 0;
262 } else {
263 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
264 x.d = malloc(d->alloc);
265 x.d->ref = 1;
266 x.d->alloc = d->alloc;
267 x.d->count = x.d->start = x.d->offset = 0;
268 x.d->sharable = true;
269 if (!d->ref.deref()) free(p);
270 d = x.d;
271 }
272}
273
274template <typename T>
275inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc)
276{
277 return QContiguousCacheData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData());
278}
279
280template <typename T>
281QContiguousCache<T>::QContiguousCache(int cap)
282{
283 d = malloc(cap);
284 d->ref = 1;
285 d->alloc = cap;
286 d->count = d->start = d->offset = 0;
287 d->sharable = true;
288}
289
290template <typename T>
291QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other)
292{
293 other.d->ref.ref();
294 if (!d->ref.deref())
295 free(d);
296 d = other.d;
297 if (!d->sharable)
298 detach_helper();
299 return *this;
300}
301
302template <typename T>
303bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const
304{
305 if (other.d == d)
306 return true;
307 if (other.d->start != d->start
308 || other.d->count != d->count
309 || other.d->offset != d->offset
310 || other.d->alloc != d->alloc)
311 return false;
312 for (int i = firstIndex(); i <= lastIndex(); ++i)
313 if (!(at(i) == other.at(i)))
314 return false;
315 return true;
316}
317
318template <typename T>
319void QContiguousCache<T>::free(Data *x)
320{
321 if (QTypeInfo<T>::isComplex) {
322 int oldcount = d->count;
323 T * i = p->array + d->start;
324 T * e = p->array + d->alloc;
325 while (oldcount--) {
326 i->~T();
327 i++;
328 if (i == e)
329 i = p->array;
330 }
331 }
332 x->free(x);
333}
334template <typename T>
335void QContiguousCache<T>::append(const T &value)
336{
337 detach();
338 if (QTypeInfo<T>::isComplex) {
339 if (d->count == d->alloc)
340 (p->array + (d->start+d->count) % d->alloc)->~T();
341 new (p->array + (d->start+d->count) % d->alloc) T(value);
342 } else {
343 p->array[(d->start+d->count) % d->alloc] = value;
344 }
345
346 if (d->count == d->alloc) {
347 d->start++;
348 d->start %= d->alloc;
349 d->offset++;
350 } else {
351 d->count++;
352 }
353}
354
355template<typename T>
356void QContiguousCache<T>::prepend(const T &value)
357{
358 detach();
359 if (d->start)
360 d->start--;
361 else
362 d->start = d->alloc-1;
363 d->offset--;
364
365 if (d->count != d->alloc)
366 d->count++;
367 else
368 if (d->count == d->alloc)
369 (p->array + d->start)->~T();
370
371 if (QTypeInfo<T>::isComplex)
372 new (p->array + d->start) T(value);
373 else
374 p->array[d->start] = value;
375}
376
377template<typename T>
378void QContiguousCache<T>::insert(int pos, const T &value)
379{
380 Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range");
381 detach();
382 if (containsIndex(pos)) {
383 if(QTypeInfo<T>::isComplex)
384 new (p->array + pos % d->alloc) T(value);
385 else
386 p->array[pos % d->alloc] = value;
387 } else if (pos == d->offset-1)
388 prepend(value);
389 else if (pos == d->offset+d->count)
390 append(value);
391 else {
392 // we don't leave gaps.
393 clear();
394 d->offset = pos;
395 d->start = pos % d->alloc;
396 d->count = 1;
397 if (QTypeInfo<T>::isComplex)
398 new (p->array + d->start) T(value);
399 else
400 p->array[d->start] = value;
401 }
402}
403
404template <typename T>
405inline const T &QContiguousCache<T>::at(int pos) const
406{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
407template <typename T>
408inline const T &QContiguousCache<T>::operator[](int pos) const
409{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
410
411template <typename T>
412inline T &QContiguousCache<T>::operator[](int pos)
413{
414 detach();
415 if (!containsIndex(pos))
416 insert(pos, T());
417 return p->array[pos % d->alloc];
418}
419
420template <typename T>
421inline void QContiguousCache<T>::removeFirst()
422{
423 Q_ASSERT(d->count > 0);
424 detach();
425 d->count--;
426 if (QTypeInfo<T>::isComplex)
427 (p->array + d->start)->~T();
428 d->start = (d->start + 1) % d->alloc;
429 d->offset++;
430}
431
432template <typename T>
433inline void QContiguousCache<T>::removeLast()
434{
435 Q_ASSERT(d->count > 0);
436 detach();
437 d->count--;
438 if (QTypeInfo<T>::isComplex)
439 (p->array + (d->start + d->count) % d->alloc)->~T();
440}
441
442template <typename T>
443inline T QContiguousCache<T>::takeFirst()
444{ T t = first(); removeFirst(); return t; }
445
446template <typename T>
447inline T QContiguousCache<T>::takeLast()
448{ T t = last(); removeLast(); return t; }
449
450QT_END_NAMESPACE
451
452QT_END_HEADER
453
454#endif
Note: See TracBrowser for help on using the repository browser.