Qt 4.8
qlist.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <new>
43 #include "qlist.h"
44 #include "qtools_p.h"
45 #include <string.h>
46 
48 
49 /*
50  QList as an array-list combines the easy-of-use of a random
51  access interface with fast list operations and the low memory
52  management overhead of an array. Accessing elements by index,
53  appending, prepending, and removing elements from both the front
54  and the back all happen in constant time O(1). Inserting or
55  removing elements at random index positions \ai happens in linear
56  time, or more precisly in O(min{i,n-i}) <= O(n/2), with n being
57  the number of elements in the list.
58 */
59 
61 
62 static int grow(int size)
63 {
64  // dear compiler: don't optimize me out.
65  volatile int x = qAllocMore(size * sizeof(void *), QListData::DataHeaderSize) / sizeof(void *);
66  return x;
67 }
68 
80 {
81  Data *x = d;
82  int l = x->end - x->begin;
83  int nl = l + num;
84  int alloc = grow(nl);
85  Data* t = static_cast<Data *>(qMalloc(DataHeaderSize + alloc * sizeof(void *)));
86  Q_CHECK_PTR(t);
87 
88  t->ref = 1;
89  t->sharable = true;
90  t->alloc = alloc;
91  // The space reservation algorithm's optimization is biased towards appending:
92  // Something which looks like an append will put the data at the beginning,
93  // while something which looks like a prepend will put it in the middle
94  // instead of at the end. That's based on the assumption that prepending
95  // is uncommon and even an initial prepend will eventually be followed by
96  // at least some appends.
97  int bg;
98  if (*idx < 0) {
99  *idx = 0;
100  bg = (alloc - nl) >> 1;
101  } else if (*idx > l) {
102  *idx = l;
103  bg = 0;
104  } else if (*idx < (l >> 1)) {
105  bg = (alloc - nl) >> 1;
106  } else {
107  bg = 0;
108  }
109  t->begin = bg;
110  t->end = bg + nl;
111  d = t;
112 
113  return x;
114 }
115 
116 #if QT_VERSION >= 0x050000
117 # error "Remove QListData::detach(), it is only required for binary compatibility for 4.0.x to 4.2.x"
118 #endif
120 {
121  Data *x = static_cast<Data *>(qMalloc(DataHeaderSize + d->alloc * sizeof(void *)));
122  Q_CHECK_PTR(x);
123 
124  x->ref = 1;
125  x->sharable = true;
126  x->alloc = d->alloc;
127  if (!x->alloc) {
128  x->begin = 0;
129  x->end = 0;
130  } else {
131  x->begin = d->begin;
132  x->end = d->end;
133  }
134 
135  qSwap(d, x);
136  if (!x->ref.deref())
137  return x;
138  return 0;
139 }
140 
148 #if QT_VERSION >= 0x050000
149 # error "Remove QListData::detach2(), it is only required for binary compatibility for 4.3.x to 4.5.x"
150 #endif
152 {
153  Data *x = d;
154  Data* t = static_cast<Data *>(qMalloc(DataHeaderSize + x->alloc * sizeof(void *)));
155  Q_CHECK_PTR(t);
156 
157  ::memcpy(t, d, DataHeaderSize + d->alloc * sizeof(void *));
158 
159  t->ref = 1;
160  t->sharable = true;
161  t->alloc = x->alloc;
162  if (!t->alloc) {
163  t->begin = 0;
164  t->end = 0;
165  } else {
166  t->begin = x->begin;
167  t->end = x->end;
168  }
169  d = t;
170 
171  return x;
172 }
173 
183 {
184  Data *x = d;
185  Data* t = static_cast<Data *>(qMalloc(DataHeaderSize + alloc * sizeof(void *)));
186  Q_CHECK_PTR(t);
187 
188  t->ref = 1;
189  t->sharable = true;
190  t->alloc = alloc;
191  if (!alloc) {
192  t->begin = 0;
193  t->end = 0;
194  } else {
195  t->begin = x->begin;
196  t->end = x->end;
197  }
198  d = t;
199 
200  return x;
201 }
202 
210 #if QT_VERSION >= 0x050000
211 # error "Remove QListData::detach3(), it is only required for binary compatibility for 4.5.x to 4.6.x"
212 #endif
214 {
215  return detach(d->alloc);
216 }
217 
218 void QListData::realloc(int alloc)
219 {
220  Q_ASSERT(d->ref == 1);
221  Data *x = static_cast<Data *>(qRealloc(d, DataHeaderSize + alloc * sizeof(void *)));
222  Q_CHECK_PTR(x);
223 
224  d = x;
225  d->alloc = alloc;
226  if (!alloc)
227  d->begin = d->end = 0;
228 }
229 
230 // ensures that enough space is available to append n elements
231 void **QListData::append(int n)
232 {
233  Q_ASSERT(d->ref == 1);
234  int e = d->end;
235  if (e + n > d->alloc) {
236  int b = d->begin;
237  if (b - n >= 2 * d->alloc / 3) {
238  // we have enough space. Just not at the end -> move it.
239  e -= b;
240  ::memmove(d->array, d->array + b, e * sizeof(void *));
241  d->begin = 0;
242  } else {
243  realloc(grow(d->alloc + n));
244  }
245  }
246  d->end = e + n;
247  return d->array + e;
248 }
249 
250 // ensures that enough space is available to append one element
252 {
253  return append(1);
254 }
255 
256 // ensures that enough space is available to append the list
257 #if QT_VERSION >= 0x050000
258 # error "Remove QListData::append(), it is only required for binary compatibility up to 4.5.x"
259 #endif
261 {
262  Q_ASSERT(d->ref == 1);
263  int e = d->end;
264  int n = l.d->end - l.d->begin;
265  if (n) {
266  if (e + n > d->alloc)
267  realloc(grow(e + n));
268  ::memcpy(d->array + d->end, l.d->array + l.d->begin, n*sizeof(void*));
269  d->end += n;
270  }
271  return d->array + e;
272 }
273 
274 // ensures that enough space is available to append the list
276 {
277  return append(l.d->end - l.d->begin);
278 }
279 
281 {
282  Q_ASSERT(d->ref == 1);
283  if (d->begin == 0) {
284  if (d->end >= d->alloc / 3)
285  realloc(grow(d->alloc + 1));
286 
287  if (d->end < d->alloc / 3)
288  d->begin = d->alloc - 2 * d->end;
289  else
290  d->begin = d->alloc - d->end;
291 
292  ::memmove(d->array + d->begin, d->array, d->end * sizeof(void *));
293  d->end += d->begin;
294  }
295  return d->array + --d->begin;
296 }
297 
298 void **QListData::insert(int i)
299 {
300  Q_ASSERT(d->ref == 1);
301  if (i <= 0)
302  return prepend();
303  int size = d->end - d->begin;
304  if (i >= size)
305  return append();
306 
307  bool leftward = false;
308 
309  if (d->begin == 0) {
310  if (d->end == d->alloc) {
311  // If the array is full, we expand it and move some items rightward
312  realloc(grow(d->alloc + 1));
313  } else {
314  // If there is free space at the end of the array, we move some items rightward
315  }
316  } else {
317  if (d->end == d->alloc) {
318  // If there is free space at the beginning of the array, we move some items leftward
319  leftward = true;
320  } else {
321  // If there is free space at both ends, we move as few items as possible
322  leftward = (i < size - i);
323  }
324  }
325 
326  if (leftward) {
327  --d->begin;
328  ::memmove(d->array + d->begin, d->array + d->begin + 1, i * sizeof(void *));
329  } else {
330  ::memmove(d->array + d->begin + i + 1, d->array + d->begin + i,
331  (size - i) * sizeof(void *));
332  ++d->end;
333  }
334  return d->array + d->begin + i;
335 }
336 
337 void QListData::remove(int i)
338 {
339  Q_ASSERT(d->ref == 1);
340  i += d->begin;
341  if (i - d->begin < d->end - i) {
342  if (int offset = i - d->begin)
343  ::memmove(d->array + d->begin + 1, d->array + d->begin, offset * sizeof(void *));
344  d->begin++;
345  } else {
346  if (int offset = d->end - i - 1)
347  ::memmove(d->array + i, d->array + i + 1, offset * sizeof(void *));
348  d->end--;
349  }
350 }
351 
352 void QListData::remove(int i, int n)
353 {
354  Q_ASSERT(d->ref == 1);
355  i += d->begin;
356  int middle = i + n/2;
357  if (middle - d->begin < d->end - middle) {
358  ::memmove(d->array + d->begin + n, d->array + d->begin,
359  (i - d->begin) * sizeof(void*));
360  d->begin += n;
361  } else {
362  ::memmove(d->array + i, d->array + i + n,
363  (d->end - i - n) * sizeof(void*));
364  d->end -= n;
365  }
366 }
367 
368 void QListData::move(int from, int to)
369 {
370  Q_ASSERT(d->ref == 1);
371  if (from == to)
372  return;
373 
374  from += d->begin;
375  to += d->begin;
376  void *t = d->array[from];
377 
378  if (from < to) {
379  if (d->end == d->alloc || 3 * (to - from) < 2 * (d->end - d->begin)) {
380  ::memmove(d->array + from, d->array + from + 1, (to - from) * sizeof(void *));
381  } else {
382  // optimization
383  if (int offset = from - d->begin)
384  ::memmove(d->array + d->begin + 1, d->array + d->begin, offset * sizeof(void *));
385  if (int offset = d->end - (to + 1))
386  ::memmove(d->array + to + 2, d->array + to + 1, offset * sizeof(void *));
387  ++d->begin;
388  ++d->end;
389  ++to;
390  }
391  } else {
392  if (d->begin == 0 || 3 * (from - to) < 2 * (d->end - d->begin)) {
393  ::memmove(d->array + to + 1, d->array + to, (from - to) * sizeof(void *));
394  } else {
395  // optimization
396  if (int offset = to - d->begin)
397  ::memmove(d->array + d->begin - 1, d->array + d->begin, offset * sizeof(void *));
398  if (int offset = d->end - (from + 1))
399  ::memmove(d->array + from, d->array + from + 1, offset * sizeof(void *));
400  --d->begin;
401  --d->end;
402  --to;
403  }
404  }
405  d->array[to] = t;
406 }
407 
408 void **QListData::erase(void **xi)
409 {
410  Q_ASSERT(d->ref == 1);
411  int i = xi - (d->array + d->begin);
412  remove(i);
413  return d->array + d->begin + i;
414 }
415 
Data * detach()
Definition: qlist.cpp:119
void ** erase(void **xi)
Definition: qlist.cpp:408
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
Q_CORE_EXPORT void * qMalloc(size_t size)
Definition: qmalloc.cpp:53
Q_CORE_EXPORT void * qRealloc(void *ptr, size_t size)
Definition: qmalloc.cpp:63
void ** append()
Definition: qlist.cpp:251
void * array[1]
Definition: qlist.h:76
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Definition: qbasicatomic.h:218
Data * detach3()
Detaches the QListData by reallocating new memory.
Definition: qlist.cpp:213
void remove(int i)
Definition: qlist.cpp:337
void ** prepend()
Definition: qlist.cpp:280
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
int qAllocMore(int alloc, int extra)
Definition: qbytearray.cpp:70
uint sharable
Definition: qlist.h:75
void ** append2(const QListData &l)
Definition: qlist.cpp:275
int size() const
Definition: qlist.h:98
Data * detach2()
Detaches the QListData by reallocating new memory.
Definition: qlist.cpp:151
Data * detach_grow(int *i, int n)
Detaches the QListData by allocating new memory for a list which will be bigger than the copied one a...
Definition: qlist.cpp:79
void realloc(int alloc)
Definition: qlist.cpp:218
void qSwap(T &value1, T &value2)
Definition: qglobal.h:2181
static Data shared_null
Definition: qlist.h:86
#define Q_CHECK_PTR(p)
Definition: qglobal.h:1853
QBasicAtomicInt ref
Definition: qlist.h:73
Data * d
Definition: qlist.h:87
QFactoryLoader * l
static int grow(int size)
Definition: qlist.cpp:62
void ** insert(int i)
Definition: qlist.cpp:298
void move(int from, int to)
Definition: qlist.cpp:368