QtBase  v6.3.1
qcontiguouscache.h
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QCONTIGUOUSCACHE_H
41 #define QCONTIGUOUSCACHE_H
42 
43 #include <QtCore/qatomic.h>
44 #include <limits.h>
45 #include <new>
46 
48 
49 #undef QT_QCONTIGUOUSCACHE_DEBUG
50 
51 
52 struct Q_CORE_EXPORT QContiguousCacheData
53 {
59 
60  static QContiguousCacheData *allocateData(qsizetype size, qsizetype alignment);
61  static void freeData(QContiguousCacheData *data);
62 
63 #ifdef QT_QCONTIGUOUSCACHE_DEBUG
64  void dump() const;
65 #endif
66 };
67 
68 template <typename T>
70 {
71  T array[1];
72 };
73 
74 template<typename T>
76  static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
77 
79  Data *d;
80 public:
81  // STL compatibility
82  typedef T value_type;
83  typedef value_type* pointer;
84  typedef const value_type* const_pointer;
86  typedef const value_type& const_reference;
89 
91  QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); }
92 
93  inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(d); }
94 
95  inline void detach() { if (d->ref.loadRelaxed() != 1) detach_helper(); }
96  inline bool isDetached() const { return d->ref.loadRelaxed() == 1; }
97 
100  void swap(QContiguousCache &other) noexcept { qt_ptr_swap(d, other.d); }
101 
102 #ifndef Q_CLANG_QDOC
103  template <typename U = T>
105  {
106  if (other.d == d)
107  return true;
108  if (other.d->start != d->start
109  || other.d->count != d->count
110  || other.d->offset != d->offset
111  || other.d->alloc != d->alloc)
112  return false;
113  for (qsizetype i = firstIndex(); i <= lastIndex(); ++i)
114  if (!(at(i) == other.at(i)))
115  return false;
116  return true;
117  }
118  template <typename U = T>
120  { return !(*this == other); }
121 #else
122  bool operator==(const QContiguousCache &other) const;
123  bool operator!=(const QContiguousCache &other) const;
124 #endif // Q_CLANG_QDOC
125 
126  inline qsizetype capacity() const {return d->alloc; }
127  inline qsizetype count() const { return d->count; }
128  inline qsizetype size() const { return d->count; }
129 
130  inline bool isEmpty() const { return d->count == 0; }
131  inline bool isFull() const { return d->count == d->alloc; }
132  inline qsizetype available() const { return d->alloc - d->count; }
133 
134  void clear();
136 
137  const T &at(qsizetype pos) const;
139  const T &operator[](qsizetype i) const;
140 
141  void append(T &&value);
142  void append(const T &value);
143  void prepend(T &&value);
144  void prepend(const T &value);
146  void insert(qsizetype pos, const T &value);
147 
148 
149  inline bool containsIndex(qsizetype pos) const { return pos >= d->offset && pos - d->offset < d->count; }
150  inline qsizetype firstIndex() const { return d->offset; }
151  inline qsizetype lastIndex() const { return d->offset + d->count - 1; }
152 
153  inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; }
154  inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; }
155  inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; }
156  inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; }
157 
158  void removeFirst();
160  void removeLast();
162 
163  // Use extra parentheses around max to avoid expanding it if it is a macro.
164  inline bool areIndexesValid() const
165  { return d->offset >= 0 && d->offset < (std::numeric_limits<qsizetype>::max)() - d->count && (d->offset % d->alloc) == d->start; }
166 
167  inline void normalizeIndexes() { d->offset = d->start; }
168 
169 #ifdef QT_QCONTIGUOUSCACHE_DEBUG
170  void dump() const { d->dump(); }
171 #endif
172 private:
173  void detach_helper();
174 
175  Data *allocateData(qsizetype aalloc);
176  void freeData(Data *x);
177 };
178 
179 template <typename T>
181 {
182  Data *x = allocateData(d->alloc);
183  x->ref.storeRelaxed(1);
184  x->count = d->count;
185  x->start = d->start;
186  x->offset = d->offset;
187  x->alloc = d->alloc;
188 
189  T *dest = x->array + x->start;
190  T *src = d->array + d->start;
191  qsizetype oldcount = x->count;
192  while (oldcount--) {
193  new (dest) T(*src);
194  dest++;
195  if (dest == x->array + x->alloc)
196  dest = x->array;
197  src++;
198  if (src == d->array + d->alloc)
199  src = d->array;
200  }
201 
202  if (!d->ref.deref())
203  freeData(d);
204  d = x;
205 }
206 
207 template <typename T>
209 {
210  Q_ASSERT(asize >= 0);
211  if (asize == d->alloc)
212  return;
213  detach();
214  Data *x = allocateData(asize);
215  x->ref.storeRelaxed(1);
216  x->alloc = asize;
217  x->count = qMin(d->count, asize);
218  x->offset = d->offset + d->count - x->count;
219  if (asize)
220  x->start = x->offset % x->alloc;
221  else
222  x->start = 0;
223 
224  qsizetype oldcount = x->count;
225  if (oldcount)
226  {
227  T *dest = x->array + (x->start + x->count-1) % x->alloc;
228  T *src = d->array + (d->start + d->count-1) % d->alloc;
229  while (oldcount--) {
230  new (dest) T(*src);
231  if (dest == x->array)
232  dest = x->array + x->alloc;
233  dest--;
234  if (src == d->array)
235  src = d->array + d->alloc;
236  src--;
237  }
238  }
239  /* free old */
240  freeData(d);
241  d = x;
242 }
243 
244 template <typename T>
246 {
247  if (d->ref.loadRelaxed() == 1) {
249  qsizetype oldcount = d->count;
250  T * i = d->array + d->start;
251  T * e = d->array + d->alloc;
252  while (oldcount--) {
253  i->~T();
254  i++;
255  if (i == e)
256  i = d->array;
257  }
258  }
259  d->count = d->start = d->offset = 0;
260  } else {
261  Data *x = allocateData(d->alloc);
262  x->ref.storeRelaxed(1);
263  x->alloc = d->alloc;
264  x->count = x->start = x->offset = 0;
265  if (!d->ref.deref())
266  freeData(d);
267  d = x;
268  }
269 }
270 
271 template <typename T>
273 {
274  return static_cast<Data *>(QContiguousCacheData::allocateData(sizeof(Data) + (aalloc - 1) * sizeof(T), alignof(Data)));
275 }
276 
277 template <typename T>
279 {
280  Q_ASSERT(cap >= 0);
281  d = allocateData(cap);
282  d->ref.storeRelaxed(1);
283  d->alloc = cap;
284  d->count = d->start = d->offset = 0;
285 }
286 
287 template <typename T>
289 {
290  other.d->ref.ref();
291  if (!d->ref.deref())
292  freeData(d);
293  d = other.d;
294  return *this;
295 }
296 
297 template <typename T>
299 {
301  qsizetype oldcount = d->count;
302  T * i = d->array + d->start;
303  T * e = d->array + d->alloc;
304  while (oldcount--) {
305  i->~T();
306  i++;
307  if (i == e)
308  i = d->array;
309  }
310  }
311  Data::freeData(x);
312 }
313 template <typename T>
315 {
316  if (!d->alloc)
317  return; // zero capacity
318  detach();
319  if (d->count == d->alloc)
320  (d->array + (d->start+d->count) % d->alloc)->~T();
321  new (d->array + (d->start+d->count) % d->alloc) T(std::move(value));
322 
323  if (d->count == d->alloc) {
324  d->start++;
325  d->start %= d->alloc;
326  d->offset++;
327  } else {
328  d->count++;
329  }
330 }
331 
332 template <typename T>
334 {
335  if (!d->alloc)
336  return; // zero capacity
337  detach();
338  if (d->count == d->alloc)
339  (d->array + (d->start+d->count) % d->alloc)->~T();
340  new (d->array + (d->start+d->count) % d->alloc) T(value);
341 
342  if (d->count == d->alloc) {
343  d->start++;
344  d->start %= d->alloc;
345  d->offset++;
346  } else {
347  d->count++;
348  }
349 }
350 
351 template<typename T>
353 {
354  if (!d->alloc)
355  return; // zero capacity
356  detach();
357  if (d->start)
358  d->start--;
359  else
360  d->start = d->alloc-1;
361  d->offset--;
362 
363  if (d->count != d->alloc)
364  d->count++;
365  else
366  (d->array + d->start)->~T();
367 
368  new (d->array + d->start) T(std::move(value));
369 }
370 
371 template<typename T>
373 {
374  if (!d->alloc)
375  return; // zero capacity
376  detach();
377  if (d->start)
378  d->start--;
379  else
380  d->start = d->alloc-1;
381  d->offset--;
382 
383  if (d->count != d->alloc)
384  d->count++;
385  else
386  (d->array + d->start)->~T();
387 
388  new (d->array + d->start) T(value);
389 }
390 
391 template<typename T>
393 {
394  Q_ASSERT_X(pos >= 0, "QContiguousCache<T>::insert", "index out of range");
395  if (!d->alloc)
396  return; // zero capacity
397  detach();
398  if (containsIndex(pos)) {
399  d->array[pos % d->alloc] = std::move(value);
400  } else if (pos == d->offset-1)
401  prepend(value);
402  else if (pos == d->offset+d->count)
403  append(value);
404  else {
405  // we don't leave gaps.
406  clear();
407  d->offset = pos;
408  d->start = pos % d->alloc;
409  d->count = 1;
410  new (d->array + d->start) T(std::move(value));
411  }
412 }
413 
414 template<typename T>
416 {
417  return insert(pos, T(value));
418 }
419 template <typename T>
421 { Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; }
422 template <typename T>
424 { return at(pos); }
425 
426 template <typename T>
428 {
429  detach();
430  if (!containsIndex(pos))
431  insert(pos, T());
432  return d->array[pos % d->alloc];
433 }
434 
435 template <typename T>
437 {
438  Q_ASSERT(d->count > 0);
439  detach();
440  d->count--;
442  (d->array + d->start)->~T();
443  d->start = (d->start + 1) % d->alloc;
444  d->offset++;
445 }
446 
447 template <typename T>
449 {
450  Q_ASSERT(d->count > 0);
451  detach();
452  d->count--;
454  (d->array + (d->start + d->count) % d->alloc)->~T();
455 }
456 
457 template <typename T>
459 { T t = std::move(first()); removeFirst(); return t; }
460 
461 template <typename T>
463 { T t = std::move(last()); removeLast(); return t; }
464 
466 
467 #endif
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
The QContiguousCache class is a template class that provides a contiguous cache.\reentrant.
const value_type * const_pointer
qsizetype firstIndex() const
qsizetype available() const
void setCapacity(qsizetype size)
qsizetype lastIndex() const
const T & at(qsizetype pos) const
value_type & reference
void insert(qsizetype pos, T &&value)
void prepend(T &&value)
void append(const T &value)
bool isDetached() const
QTypeTraits::compare_eq_result< U > operator!=(const QContiguousCache< T > &other) const
bool containsIndex(qsizetype pos) const
qptrdiff difference_type
const T & operator[](qsizetype i) const
qsizetype capacity() const
void prepend(const T &value)
qsizetype count() const
bool isEmpty() const
QContiguousCache(qsizetype capacity=0)
qsizetype size() const
QContiguousCache< T > & operator=(const QContiguousCache< T > &other)
bool isFull() const
bool areIndexesValid() const
void insert(qsizetype pos, const T &value)
const value_type & const_reference
T & operator[](qsizetype i)
const T & last() const
QContiguousCache(const QContiguousCache< T > &v)
void append(T &&value)
const T & first() const
void swap(QContiguousCache &other) noexcept
QTypeTraits::compare_eq_result< U > operator==(const QContiguousCache< T > &other) const
value_type * pointer
#define T(x)
Definition: main.cpp:42
map insert("Paris", "France")
b clear()
list append(new Employee("Blackpool", "Stephen"))
double e
uint alignment
std::enable_if_t< std::conjunction_v< QTypeTraits::has_operator_equal< T >... >, bool > compare_eq_result
Definition: qtypeinfo.h:344
void
Definition: png.h:1080
EGLOutputLayerEXT EGLint EGLAttrib value
ptrdiff_t qptrdiff
Definition: qglobal.h:307
ptrdiff_t qsizetype
Definition: qglobal.h:308
#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Class)
Definition: qglobal.h:563
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum src
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint first
GLenum array
Definition: qopenglext.h:7028
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLenum cap
Definition: qopenglext.h:8893
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
list prepend("one")
QSharedPointer< T > other(t)
[5]
QAction * at
QBasicAtomicInt ref
static QContiguousCacheData * allocateData(qsizetype size, qsizetype alignment)
Definition: main.cpp:38
void dump(QAbstractItemModel *model, QString const &indent=" - ", QModelIndex const &parent={})