source: trunk/src/qt3support/tools/q3garray.cpp@ 792

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

trunk: Merged in qt 4.6.2 sources.

File size: 17.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 Qt3Support 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#include "qglobal.h"
43#if defined(Q_CC_BOR)
44 // needed for qsort() because of a std namespace problem on Borland
45# include "qplatformdefs.h"
46#elif defined(Q_WS_WIN)
47 // needed for bsearch on some platforms
48# include "qt_windows.h"
49#endif
50
51#define Q3GARRAY_CPP
52#include "q3garray.h"
53#include <stdlib.h>
54#include <string.h>
55
56#ifndef QT_NO_THREAD
57# include "private/qmutexpool_p.h"
58#endif
59
60#if defined(Q_OS_WINCE)
61# include "qfunctions_wince.h"
62#endif
63QT_BEGIN_NAMESPACE
64
65/*
66 If USE_MALLOC isn't defined, we use new[] and delete[] to allocate
67 memory. The documentation for QMemArray<T>::assign() explicitly
68 mentions that the array is freed using free(), so don't mess around
69 with USE_MALLOC unless you know what you're doing.
70*/
71#define USE_MALLOC
72
73#undef NEW
74#undef DELETE
75
76#if defined(USE_MALLOC)
77#define NEW(type,size) ((type*)malloc(size*sizeof(type)))
78#define DELETE(array) (free((char*)array))
79#else
80#define NEW(type,size) (new type[size])
81#define DELETE(array) (delete[] array)
82#define DONT_USE_REALLOC // comment to use realloc()
83#endif
84
85/*!
86 \class Q3GArray
87 \reentrant
88 \brief The Q3GArray class is an internal class for implementing the QMemArray class.
89
90 \internal
91
92 Q3GArray is a strictly internal class that acts as base class for the
93 QMemArray template array.
94
95 It contains an array of bytes and has no notion of an array element.
96*/
97
98
99/*!
100 Constructs a null array.
101*/
102
103Q3GArray::Q3GArray()
104{
105 shd = newData();
106 Q_CHECK_PTR(shd);
107}
108
109/*!
110 Dummy constructor; does not allocate any data.
111
112 This constructor does not initialize any array data so subclasses
113 must do it. The intention is to make the code more efficient.
114*/
115
116Q3GArray::Q3GArray(int, int)
117 : shd(0)
118{
119}
120
121/*!
122 Constructs an array with room for \a size bytes.
123*/
124
125Q3GArray::Q3GArray(int size)
126{
127 if (size < 0) {
128#if defined(QT_CHECK_RANGE)
129 qWarning("Q3GArray: Cannot allocate array with negative length");
130#endif
131 size = 0;
132 }
133 shd = newData();
134 Q_CHECK_PTR(shd);
135 if (size == 0) // zero length
136 return;
137 shd->data = NEW(char,size);
138 Q_CHECK_PTR(shd->data);
139 shd->len =
140#ifdef QT_Q3GARRAY_SPEED_OPTIM
141 shd->maxl =
142#endif
143 size;
144}
145
146/*!
147 Constructs a shallow copy of \a a.
148*/
149
150Q3GArray::Q3GArray(const Q3GArray &a)
151{
152 shd = a.shd;
153 shd->ref();
154}
155
156/*!
157 Dereferences the array data and deletes it if this was the last
158 reference.
159*/
160
161Q3GArray::~Q3GArray()
162{
163 if (shd && shd->deref()) { // delete when last reference
164 if (shd->data) // is lost
165 DELETE(shd->data);
166 deleteData(shd);
167 shd = 0;
168 }
169}
170
171
172/*!
173 \fn Q3GArray &Q3GArray::operator=(const Q3GArray &a)
174
175 Assigns a shallow copy of \a a to this array and returns a reference to
176 this array. Equivalent to assign().
177*/
178
179/*!
180 \fn void Q3GArray::detach()
181
182 Detaches this array from shared array data.
183*/
184
185/*!
186 \fn char *Q3GArray::data() const
187
188 Returns a pointer to the actual array data.
189*/
190
191/*!
192 \fn uint Q3GArray::nrefs() const
193
194 Returns the reference count.
195*/
196
197/*!
198 \fn uint Q3GArray::size() const
199
200 Returns the size of the array, in bytes.
201*/
202
203
204/*!
205 Returns true if this array is equal to \a a, otherwise false.
206 The comparison is bitwise, of course.
207*/
208
209bool Q3GArray::isEqual(const Q3GArray &a) const
210{
211 if (size() != a.size()) // different size
212 return false;
213 if (data() == a.data()) // has same data
214 return true;
215 return (size() ? memcmp(data(), a.data(), size()) : 0) == 0;
216}
217
218
219/*!
220 Resizes the array to \a newsize bytes. \a optim is either
221 MemOptim (the default) or SpeedOptim.
222*/
223bool Q3GArray::resize(uint newsize, Optimization optim)
224{
225#ifndef QT_Q3GARRAY_SPEED_OPTIM
226 Q_UNUSED(optim);
227#endif
228
229 if (newsize == shd->len
230#ifdef QT_Q3GARRAY_SPEED_OPTIM
231 && newsize == shd->maxl
232#endif
233 ) // nothing to do
234 return true;
235 if (newsize == 0) { // remove array
236 if (shd->data)
237 DELETE(shd->data);
238 shd->data = 0;
239 shd->len = 0;
240#ifdef QT_Q3GARRAY_SPEED_OPTIM
241 shd->maxl = 0;
242#endif
243 return true;
244 }
245
246 uint newmaxl = newsize;
247#ifdef QT_Q3GARRAY_SPEED_OPTIM
248 if (optim == SpeedOptim) {
249 if (newsize <= shd->maxl &&
250 (newsize * 4 > shd->maxl || shd->maxl <= 4)) {
251 shd->len = newsize;
252 return true;
253 }
254 newmaxl = 4;
255 while (newmaxl < newsize)
256 newmaxl *= 2;
257 // try to spare some memory
258 if (newmaxl >= 1024 * 1024 && newsize <= newmaxl - (newmaxl >> 2))
259 newmaxl -= newmaxl >> 2;
260 }
261 shd->maxl = newmaxl;
262#endif
263
264 if (shd->data) { // existing data
265#if defined(DONT_USE_REALLOC)
266 char *newdata = NEW(char,newsize); // manual realloc
267 memcpy(newdata, shd->data, QMIN(shd->len,newmaxl));
268 DELETE(shd->data);
269 shd->data = newdata;
270#else
271 shd->data = (char *)realloc(shd->data, newmaxl);
272#endif
273 } else {
274 shd->data = NEW(char,newmaxl);
275 }
276 if (!shd->data) // no memory
277 return false;
278 shd->len = newsize;
279 return true;
280}
281
282/*!\overload
283*/
284bool Q3GArray::resize(uint newsize)
285{
286 return resize(newsize, MemOptim);
287}
288
289
290/*!
291 Fills the array with the repeated occurrences of \a d, which is
292 \a sz bytes long.
293 If \a len is specified as different from -1, then the array will be
294 resized to \a len*sz before it is filled.
295
296 Returns true if successful, or false if the memory cannot be allocated
297 (only when \a len != -1).
298
299 \sa resize()
300*/
301
302bool Q3GArray::fill(const char *d, int len, uint sz)
303{
304 if (len < 0)
305 len = shd->len/sz; // default: use array length
306 else if (!resize(len*sz))
307 return false;
308 if (sz == 1) // 8 bit elements
309 memset(data(), *d, len);
310 else if (sz == 4) { // 32 bit elements
311 register Q_INT32 *x = (Q_INT32*)data();
312 Q_INT32 v = *((Q_INT32*)d);
313 while (len--)
314 *x++ = v;
315 } else if (sz == 2) { // 16 bit elements
316 register Q_INT16 *x = (Q_INT16*)data();
317 Q_INT16 v = *((Q_INT16*)d);
318 while (len--)
319 *x++ = v;
320 } else { // any other size elements
321 register char *x = data();
322 while (len--) { // more complicated
323 memcpy(x, d, sz);
324 x += sz;
325 }
326 }
327 return true;
328}
329
330/*!
331 \overload
332 Shallow copy. Dereference the current array and references the data
333 contained in \a a instead. Returns a reference to this array.
334 \sa operator=()
335*/
336
337Q3GArray &Q3GArray::assign(const Q3GArray &a)
338{
339 a.shd->ref(); // avoid 'a = a'
340 if (shd->deref()) { // delete when last reference
341 if (shd->data) // is lost
342 DELETE(shd->data);
343 deleteData(shd);
344 }
345 shd = a.shd;
346 return *this;
347}
348
349/*!
350 Shallow copy. Dereference the current array and references the
351 array data \a d, which contains \a len bytes.
352 Returns a reference to this array.
353
354 Do not delete \a d later, because Q3GArray takes care of that.
355*/
356
357Q3GArray &Q3GArray::assign(const char *d, uint len)
358{
359 if (shd->count > 1) { // disconnect this
360 shd->count--;
361 shd = newData();
362 Q_CHECK_PTR(shd);
363 } else {
364 if (shd->data)
365 DELETE(shd->data);
366 }
367 shd->data = (char *)d;
368 shd->len =
369#ifdef QT_Q3GARRAY_SPEED_OPTIM
370 shd->maxl =
371#endif
372 len;
373 return *this;
374}
375
376/*!
377 Deep copy. Dereference the current array and obtains a copy of the data
378 contained in \a a instead. Returns a reference to this array.
379 \sa assign(), operator=()
380*/
381
382Q3GArray &Q3GArray::duplicate(const Q3GArray &a)
383{
384 if (a.shd == shd) { // a.duplicate(a) !
385 if (shd->count > 1) {
386 shd->count--;
387 register array_data *n = newData();
388 Q_CHECK_PTR(n);
389 if ((n->len=shd->len)) {
390 n->data = NEW(char,n->len);
391 Q_CHECK_PTR(n->data);
392 if (n->data)
393 memcpy(n->data, shd->data, n->len);
394 } else {
395 n->data = 0;
396 }
397 shd = n;
398 }
399 return *this;
400 }
401 char *oldptr = 0;
402 if (shd->count > 1) { // disconnect this
403 shd->count--;
404 shd = newData();
405 Q_CHECK_PTR(shd);
406 } else { // delete after copy was made
407 oldptr = shd->data;
408 }
409 if (a.shd->len) { // duplicate data
410 shd->data = NEW(char,a.shd->len);
411 Q_CHECK_PTR(shd->data);
412 if (shd->data)
413 memcpy(shd->data, a.shd->data, a.shd->len);
414 } else {
415 shd->data = 0;
416 }
417 shd->len =
418#ifdef QT_Q3GARRAY_SPEED_OPTIM
419 shd->maxl =
420#endif
421 a.shd->len;
422 if (oldptr)
423 DELETE(oldptr);
424 return *this;
425}
426
427/*!
428 \overload
429 Deep copy. Dereferences the current array and obtains a copy of
430 \a len characters from array data \a d instead. Returns a reference
431 to this array.
432 \sa assign(), operator=()
433*/
434
435Q3GArray &Q3GArray::duplicate(const char *d, uint len)
436{
437 char *data;
438 if (d == 0 || len == 0) {
439 data = 0;
440 len = 0;
441 } else {
442 if (shd->count == 1 && shd->len == len) {
443 if (shd->data != d) // avoid self-assignment
444 memcpy(shd->data, d, len); // use same buffer
445 return *this;
446 }
447 data = NEW(char,len);
448 Q_CHECK_PTR(data);
449 memcpy(data, d, len);
450 }
451 if (shd->count > 1) { // detach
452 shd->count--;
453 shd = newData();
454 Q_CHECK_PTR(shd);
455 } else { // just a single reference
456 if (shd->data)
457 DELETE(shd->data);
458 }
459 shd->data = data;
460 shd->len =
461#ifdef QT_Q3GARRAY_SPEED_OPTIM
462 shd->maxl =
463#endif
464 len;
465 return *this;
466}
467
468/*!
469 Resizes this array to \a len bytes and copies the \a len bytes at
470 address \a d into it.
471
472 \warning This function disregards the reference count mechanism. If
473 other Q3GArrays reference the same data as this, all will be updated.
474*/
475
476void Q3GArray::store(const char *d, uint len)
477{ // store, but not deref
478 resize(len);
479 memcpy(shd->data, d, len);
480}
481
482
483/*!
484 \fn array_data *Q3GArray::sharedBlock() const
485
486 Returns a pointer to the shared array block.
487
488 \warning
489
490 Do not use this function. Using it is begging for trouble. We dare
491 not remove it, for fear of breaking code, but we \e strongly
492 discourage new use of it.
493*/
494
495/*!
496 \fn void Q3GArray::setSharedBlock(array_data *p)
497
498 Sets the shared array block to \a p.
499
500 \warning
501
502 Do not use this function. Using it is begging for trouble. We dare
503 not remove it, for fear of breaking code, but we \e strongly
504 discourage new use of it.
505*/
506
507
508/*!
509 Sets raw data and returns a reference to the array.
510
511 Dereferences the current array and sets the new array data to \a d and
512 the new array size to \a len. Do not attempt to resize or re-assign the
513 array data when raw data has been set.
514 Call resetRawData(d,len) to reset the array.
515
516 Setting raw data is useful because it sets QMemArray data without
517 allocating memory or copying data.
518
519 Example of intended use:
520 \snippet doc/src/snippets/code/src_qt3support_tools_q3garray.cpp 0
521
522 Example of misuse (do not do this):
523 \snippet doc/src/snippets/code/src_qt3support_tools_q3garray.cpp 1
524
525 \warning If you do not call resetRawData(), Q3GArray will attempt to
526 deallocate or reallocate the raw data, which might not be too good.
527 Be careful.
528*/
529
530Q3GArray &Q3GArray::setRawData(const char *d, uint len)
531{
532 duplicate(0, 0); // set null data
533 shd->data = (char *)d;
534 shd->len = len;
535 return *this;
536}
537
538/*!
539 Resets raw data.
540
541 The arguments must be the data, \a d, and length \a len, that were
542 passed to setRawData(). This is for consistency checking.
543*/
544
545void Q3GArray::resetRawData(const char *d, uint len)
546{
547 if (d != shd->data || len != shd->len) {
548#if defined(QT_CHECK_STATE)
549 qWarning("Q3GArray::resetRawData: Inconsistent arguments");
550#endif
551 return;
552 }
553 shd->data = 0;
554 shd->len = 0;
555}
556
557
558/*!
559 Finds the first occurrence of \a d in the array from position \a index,
560 where \a sz is the size of the \a d element.
561
562 Note that \a index is given in units of \a sz, not bytes.
563
564 This function only compares whole cells, not bytes.
565*/
566
567int Q3GArray::find(const char *d, uint index, uint sz) const
568{
569 index *= sz;
570 if (index >= shd->len) {
571#if defined(QT_CHECK_RANGE)
572 qWarning("Q3GArray::find: Index %d out of range", index/sz);
573#endif
574 return -1;
575 }
576 register uint i;
577 uint ii;
578 switch (sz) {
579 case 1: { // 8 bit elements
580 register char *x = data() + index;
581 char v = *d;
582 for (i=index; i<shd->len; i++) {
583 if (*x++ == v)
584 break;
585 }
586 ii = i;
587 }
588 break;
589 case 2: { // 16 bit elements
590 register Q_INT16 *x = (Q_INT16*)(data() + index);
591 Q_INT16 v = *((Q_INT16*)d);
592 for (i=index; i<shd->len; i+=2) {
593 if (*x++ == v)
594 break;
595 }
596 ii = i/2;
597 }
598 break;
599 case 4: { // 32 bit elements
600 register Q_INT32 *x = (Q_INT32*)(data() + index);
601 Q_INT32 v = *((Q_INT32*)d);
602 for (i=index; i<shd->len; i+=4) {
603 if (*x++ == v)
604 break;
605 }
606 ii = i/4;
607 }
608 break;
609 default: { // any size elements
610 for (i=index; i<shd->len; i+=sz) {
611 if (memcmp(d, &shd->data[i], sz) == 0)
612 break;
613 }
614 ii = i/sz;
615 }
616 break;
617 }
618 return i<shd->len ? (int)ii : -1;
619}
620
621/*!
622 Returns the number of occurrences of \a d in the array, where \a sz is
623 the size of the \a d element.
624
625 This function only compares whole cells, not bytes.
626*/
627
628int Q3GArray::contains(const char *d, uint sz) const
629{
630 register uint i = shd->len;
631 int count = 0;
632 switch (sz) {
633 case 1: { // 8 bit elements
634 register char *x = data();
635 char v = *d;
636 while (i--) {
637 if (*x++ == v)
638 count++;
639 }
640 }
641 break;
642 case 2: { // 16 bit elements
643 register Q_INT16 *x = (Q_INT16*)data();
644 Q_INT16 v = *((Q_INT16*)d);
645 i /= 2;
646 while (i--) {
647 if (*x++ == v)
648 count++;
649 }
650 }
651 break;
652 case 4: { // 32 bit elements
653 register Q_INT32 *x = (Q_INT32*)data();
654 Q_INT32 v = *((Q_INT32*)d);
655 i /= 4;
656 while (i--) {
657 if (*x++ == v)
658 count++;
659 }
660 }
661 break;
662 default: { // any size elements
663 for (i=0; i<shd->len; i+=sz) {
664 if (memcmp(d, &shd->data[i], sz) == 0)
665 count++;
666 }
667 }
668 break;
669 }
670 return count;
671}
672
673static int cmp_item_size = 0;
674
675#if defined(Q_C_CALLBACKS)
676extern "C" {
677#endif
678
679#ifdef Q_OS_WINCE
680static int __cdecl cmp_arr(const void *n1, const void *n2)
681#else
682static int cmp_arr(const void *n1, const void *n2)
683#endif
684{
685 return (n1 && n2) ? memcmp(n1, n2, cmp_item_size)
686 : (n1 ? 1 : (n2 ? -1 : 0));
687 // ### Qt 3.0: Add a virtual compareItems() method and call that instead
688}
689
690#if defined(Q_C_CALLBACKS)
691}
692#endif
693
694/*!
695 Sorts the first \a sz items of the array.
696*/
697
698void Q3GArray::sort(uint sz)
699{
700 int numItems = size() / sz;
701 if (numItems < 2)
702 return;
703
704#ifndef QT_NO_THREAD
705 QMutexLocker locker(QMutexPool::globalInstanceGet(&cmp_item_size));
706#endif
707
708 cmp_item_size = sz;
709 qsort(shd->data, numItems, sz, cmp_arr);
710}
711
712/*!
713 Binary search; assumes that \a d is a sorted array of size \a sz.
714*/
715
716int Q3GArray::bsearch(const char *d, uint sz) const
717{
718 int numItems = size() / sz;
719 if (!numItems)
720 return -1;
721
722#ifndef QT_NO_THREAD
723 QMutexLocker locker(QMutexPool::globalInstanceGet(&cmp_item_size));
724#endif
725
726 cmp_item_size = sz;
727 char* r = (char*)::bsearch(d, shd->data, numItems, sz, cmp_arr);
728 if (!r)
729 return -1;
730 while((r >= shd->data + sz) && (cmp_arr(r - sz, d) == 0))
731 r -= sz; // search to first of equal elements; bsearch is undef
732 return (int)((r - shd->data) / sz);
733}
734
735
736/*!
737 \fn char *Q3GArray::at(uint index) const
738
739 Returns a pointer to the byte at offset \a index in the array.
740*/
741
742/*!
743 Expand the array if necessary, and copies (the first part of) its
744 contents from the \a index * \a sz bytes at \a d.
745
746 Returns true if the operation succeeds, false if it runs out of
747 memory.
748
749 \warning This function disregards the reference count mechanism. If
750 other Q3GArrays reference the same data as this, all will be changed.
751*/
752
753bool Q3GArray::setExpand(uint index, const char *d, uint sz)
754{
755 index *= sz;
756 if (index >= shd->len) {
757 if (!resize(index+sz)) // no memory
758 return false;
759 }
760 memcpy(data() + index, d, sz);
761 return true;
762}
763
764
765/*!
766 Prints a warning message if at() or [] is given a bad index.
767*/
768
769void Q3GArray::msg_index(uint index)
770{
771#if defined(QT_CHECK_RANGE)
772 qWarning("Q3GArray::at: Absolute index %d out of range", index);
773#else
774 Q_UNUSED(index)
775#endif
776}
777
778
779/*!
780 Returns a new shared array block.
781*/
782
783Q3GArray::array_data * Q3GArray::newData()
784{
785 return new array_data;
786}
787
788
789/*!
790 Deletes the shared array block \a p.
791*/
792
793void Q3GArray::deleteData(array_data *p)
794{
795 delete p;
796}
797
798QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.