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

Last change on this file since 901 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 13.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 qptrdiff 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 if(asize)
225 x.d->start = x.d->offset % x.d->alloc;
226 else
227 x.d->start = 0;
228
229 int oldcount = x.d->count;
230 if(oldcount)
231 {
232 T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc;
233 T *src = p->array + (d->start + d->count-1) % d->alloc;
234 while (oldcount--) {
235 if (QTypeInfo<T>::isComplex) {
236 new (dest) T(*src);
237 } else {
238 *dest = *src;
239 }
240 if (dest == x.p->array)
241 dest = x.p->array + x.d->alloc;
242 dest--;
243 if (src == p->array)
244 src = p->array + d->alloc;
245 src--;
246 }
247 }
248 /* free old */
249 free(p);
250 d = x.d;
251}
252
253template <typename T>
254void QContiguousCache<T>::clear()
255{
256 if (d->ref == 1) {
257 if (QTypeInfo<T>::isComplex) {
258 int oldcount = d->count;
259 T * i = p->array + d->start;
260 T * e = p->array + d->alloc;
261 while (oldcount--) {
262 i->~T();
263 i++;
264 if (i == e)
265 i = p->array;
266 }
267 }
268 d->count = d->start = d->offset = 0;
269 } else {
270 union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
271 x.d = malloc(d->alloc);
272 x.d->ref = 1;
273 x.d->alloc = d->alloc;
274 x.d->count = x.d->start = x.d->offset = 0;
275 x.d->sharable = true;
276 if (!d->ref.deref()) free(p);
277 d = x.d;
278 }
279}
280
281template <typename T>
282inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc)
283{
284 return QContiguousCacheData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData());
285}
286
287template <typename T>
288QContiguousCache<T>::QContiguousCache(int cap)
289{
290 d = malloc(cap);
291 d->ref = 1;
292 d->alloc = cap;
293 d->count = d->start = d->offset = 0;
294 d->sharable = true;
295}
296
297template <typename T>
298QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other)
299{
300 other.d->ref.ref();
301 if (!d->ref.deref())
302 free(d);
303 d = other.d;
304 if (!d->sharable)
305 detach_helper();
306 return *this;
307}
308
309template <typename T>
310bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const
311{
312 if (other.d == d)
313 return true;
314 if (other.d->start != d->start
315 || other.d->count != d->count
316 || other.d->offset != d->offset
317 || other.d->alloc != d->alloc)
318 return false;
319 for (int i = firstIndex(); i <= lastIndex(); ++i)
320 if (!(at(i) == other.at(i)))
321 return false;
322 return true;
323}
324
325template <typename T>
326void QContiguousCache<T>::free(Data *x)
327{
328 if (QTypeInfo<T>::isComplex) {
329 int oldcount = d->count;
330 T * i = p->array + d->start;
331 T * e = p->array + d->alloc;
332 while (oldcount--) {
333 i->~T();
334 i++;
335 if (i == e)
336 i = p->array;
337 }
338 }
339 x->free(x);
340}
341template <typename T>
342void QContiguousCache<T>::append(const T &value)
343{
344 detach();
345 if (QTypeInfo<T>::isComplex) {
346 if (d->count == d->alloc)
347 (p->array + (d->start+d->count) % d->alloc)->~T();
348 new (p->array + (d->start+d->count) % d->alloc) T(value);
349 } else {
350 p->array[(d->start+d->count) % d->alloc] = value;
351 }
352
353 if (d->count == d->alloc) {
354 d->start++;
355 d->start %= d->alloc;
356 d->offset++;
357 } else {
358 d->count++;
359 }
360}
361
362template<typename T>
363void QContiguousCache<T>::prepend(const T &value)
364{
365 detach();
366 if (d->start)
367 d->start--;
368 else
369 d->start = d->alloc-1;
370 d->offset--;
371
372 if (d->count != d->alloc)
373 d->count++;
374 else
375 if (d->count == d->alloc)
376 (p->array + d->start)->~T();
377
378 if (QTypeInfo<T>::isComplex)
379 new (p->array + d->start) T(value);
380 else
381 p->array[d->start] = value;
382}
383
384template<typename T>
385void QContiguousCache<T>::insert(int pos, const T &value)
386{
387 Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range");
388 detach();
389 if (containsIndex(pos)) {
390 if(QTypeInfo<T>::isComplex)
391 new (p->array + pos % d->alloc) T(value);
392 else
393 p->array[pos % d->alloc] = value;
394 } else if (pos == d->offset-1)
395 prepend(value);
396 else if (pos == d->offset+d->count)
397 append(value);
398 else {
399 // we don't leave gaps.
400 clear();
401 d->offset = pos;
402 d->start = pos % d->alloc;
403 d->count = 1;
404 if (QTypeInfo<T>::isComplex)
405 new (p->array + d->start) T(value);
406 else
407 p->array[d->start] = value;
408 }
409}
410
411template <typename T>
412inline const T &QContiguousCache<T>::at(int pos) const
413{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
414template <typename T>
415inline const T &QContiguousCache<T>::operator[](int pos) const
416{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; }
417
418template <typename T>
419inline T &QContiguousCache<T>::operator[](int pos)
420{
421 detach();
422 if (!containsIndex(pos))
423 insert(pos, T());
424 return p->array[pos % d->alloc];
425}
426
427template <typename T>
428inline void QContiguousCache<T>::removeFirst()
429{
430 Q_ASSERT(d->count > 0);
431 detach();
432 d->count--;
433 if (QTypeInfo<T>::isComplex)
434 (p->array + d->start)->~T();
435 d->start = (d->start + 1) % d->alloc;
436 d->offset++;
437}
438
439template <typename T>
440inline void QContiguousCache<T>::removeLast()
441{
442 Q_ASSERT(d->count > 0);
443 detach();
444 d->count--;
445 if (QTypeInfo<T>::isComplex)
446 (p->array + (d->start + d->count) % d->alloc)->~T();
447}
448
449template <typename T>
450inline T QContiguousCache<T>::takeFirst()
451{ T t = first(); removeFirst(); return t; }
452
453template <typename T>
454inline T QContiguousCache<T>::takeLast()
455{ T t = last(); removeLast(); return t; }
456
457QT_END_NAMESPACE
458
459QT_END_HEADER
460
461#endif
Note: See TracBrowser for help on using the repository browser.