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

Last change on this file since 497 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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