summaryrefslogtreecommitdiff
path: root/qmake/tools/qgarray.cpp
Unidiff
Diffstat (limited to 'qmake/tools/qgarray.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/tools/qgarray.cpp754
1 files changed, 754 insertions, 0 deletions
diff --git a/qmake/tools/qgarray.cpp b/qmake/tools/qgarray.cpp
new file mode 100644
index 0000000..45c45ce
--- a/dev/null
+++ b/qmake/tools/qgarray.cpp
@@ -0,0 +1,754 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QGArray class
5**
6** Created : 930906
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the tools module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38 #include "qglobal.h" // needed to define Q_WS_WIN
39#ifdef Q_WS_WIN
40 #include "qt_windows.h" // needed for bsearch on some platforms
41#endif
42
43 #define QGARRAY_CPP
44#include "qgarray.h"
45#include <stdlib.h>
46#include <string.h>
47
48#ifdef QT_THREAD_SUPPORT
49# include <private/qmutexpool_p.h>
50#endif // QT_THREAD_SUPPORT
51
52 #define USE_MALLOC // comment to use new/delete
53
54#undef NEW
55#undef DELETE
56
57#if defined(USE_MALLOC)
58 #define NEW(type,size)((type*)malloc(size*sizeof(type)))
59 #define DELETE(array)(free((char*)array))
60#else
61 #define NEW(type,size)(new type[size])
62 #define DELETE(array)(delete[] array)
63 #define DONT_USE_REALLOC // comment to use realloc()
64#endif
65
66/*!
67 \class QShared qshared.h
68 \reentrant
69 \ingroup shared
70 \brief The QShared class is used internally for implementing shared classes.
71
72 \internal
73
74 It only contains a reference count and member functions to increment and
75 decrement it.
76
77 Shared classes normally have internal classes that inherit QShared and
78 add the shared data.
79
80 \sa \link shclass.html Shared Classes\endlink
81*/
82
83/*!
84 \class QGArray qgarray.h
85 \reentrant
86 \ingroup shared
87 \ingroup collection
88 \brief The QGArray class is an internal class for implementing the QMemArray class.
89
90 \internal
91
92 QGArray 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
103QGArray::QGArray()
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
116QGArray::QGArray( int, int )
117{
118}
119
120/*!
121 Constructs an array with room for \a size bytes.
122*/
123
124QGArray::QGArray( int size )
125{
126 if ( size < 0 ) {
127#if defined(QT_CHECK_RANGE)
128 qWarning( "QGArray: 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 = size;
139}
140
141/*!
142 Constructs a shallow copy of \a a.
143*/
144
145QGArray::QGArray( const QGArray &a )
146{
147 shd = a.shd;
148 shd->ref();
149}
150
151/*!
152 Dereferences the array data and deletes it if this was the last
153 reference.
154*/
155
156QGArray::~QGArray()
157{
158 if ( shd && shd->deref() ) { // delete when last reference
159 if ( shd->data ) // is lost
160 DELETE(shd->data);
161 deleteData( shd );
162 shd = 0;
163 }
164}
165
166
167/*!
168 \fn QGArray &QGArray::operator=( const QGArray &a )
169
170 Assigns a shallow copy of \a a to this array and returns a reference to
171 this array. Equivalent to assign().
172*/
173
174/*!
175 \fn void QGArray::detach()
176
177 Detaches this array from shared array data.
178*/
179
180/*!
181 \fn char *QGArray::data() const
182
183 Returns a pointer to the actual array data.
184*/
185
186/*!
187 \fn uint QGArray::nrefs() const
188
189 Returns the reference count.
190*/
191
192/*!
193 \fn uint QGArray::size() const
194
195 Returns the size of the array, in bytes.
196*/
197
198
199/*!
200 Returns TRUE if this array is equal to \a a, otherwise FALSE.
201 The comparison is bitwise, of course.
202*/
203
204bool QGArray::isEqual( const QGArray &a ) const
205{
206 if ( size() != a.size() ) // different size
207 return FALSE;
208 if ( data() == a.data() ) // has same data
209 return TRUE;
210 return (size() ? memcmp( data(), a.data(), size() ) : 0) == 0;
211}
212
213
214/*!
215 Resizes the array to \a newsize bytes.
216*/
217
218bool QGArray::resize( uint newsize )
219{
220 if ( newsize == shd->len ) // nothing to do
221 return TRUE;
222 if ( newsize == 0 ) { // remove array
223 duplicate( 0, 0 );
224 return TRUE;
225 }
226 if ( shd->data ) { // existing data
227#if defined(DONT_USE_REALLOC)
228 char *newdata = NEW(char,newsize);// manual realloc
229 memcpy( newdata, shd->data, QMIN(shd->len,newsize) );
230 DELETE(shd->data);
231 shd->data = newdata;
232#else
233 shd->data = (char *)realloc( shd->data, newsize );
234#endif
235 } else {
236 shd->data = NEW(char,newsize);
237 }
238 if ( !shd->data ) // no memory
239 return FALSE;
240 shd->len = newsize;
241 return TRUE;
242}
243
244/*!
245 Fills the array with the repeated occurrences of \a d, which is
246 \a sz bytes long.
247 If \a len is specified as different from -1, then the array will be
248 resized to \a len*sz before it is filled.
249
250 Returns TRUE if successful, or FALSE if the memory cannot be allocated
251 (only when \a len != -1).
252
253 \sa resize()
254*/
255
256bool QGArray::fill( const char *d, int len, uint sz )
257{
258 if ( len < 0 )
259 len = shd->len/sz; // default: use array length
260 else if ( !resize( len*sz ) )
261 return FALSE;
262 if ( sz == 1 ) // 8 bit elements
263 memset( data(), *d, len );
264 else if ( sz == 4 ) { // 32 bit elements
265 register Q_INT32 *x = (Q_INT32*)data();
266 Q_INT32 v = *((Q_INT32*)d);
267 while ( len-- )
268 *x++ = v;
269 } else if ( sz == 2 ) { // 16 bit elements
270 register Q_INT16 *x = (Q_INT16*)data();
271 Q_INT16 v = *((Q_INT16*)d);
272 while ( len-- )
273 *x++ = v;
274 } else { // any other size elements
275 register char *x = data();
276 while ( len-- ) { // more complicated
277 memcpy( x, d, sz );
278 x += sz;
279 }
280 }
281 return TRUE;
282}
283
284/*!
285 \overload
286 Shallow copy. Dereference the current array and references the data
287 contained in \a a instead. Returns a reference to this array.
288 \sa operator=()
289*/
290
291QGArray &QGArray::assign( const QGArray &a )
292{
293 a.shd->ref(); // avoid 'a = a'
294 if ( shd->deref() ) { // delete when last reference
295 if ( shd->data ) // is lost
296 DELETE(shd->data);
297 deleteData( shd );
298 }
299 shd = a.shd;
300 return *this;
301}
302
303/*!
304 Shallow copy. Dereference the current array and references the
305 array data \a d, which contains \a len bytes.
306 Returns a reference to this array.
307
308 Do not delete \a d later, because QGArray takes care of that.
309*/
310
311QGArray &QGArray::assign( const char *d, uint len )
312{
313 if ( shd->count > 1 ) { // disconnect this
314 shd->count--;
315 shd = newData();
316 Q_CHECK_PTR( shd );
317 } else {
318 if ( shd->data )
319 DELETE(shd->data);
320 }
321 shd->data = (char *)d;
322 shd->len = len;
323 return *this;
324}
325
326/*!
327 Deep copy. Dereference the current array and obtains a copy of the data
328 contained in \a a instead. Returns a reference to this array.
329 \sa assign(), operator=()
330*/
331
332QGArray &QGArray::duplicate( const QGArray &a )
333{
334 if ( a.shd == shd ) { // a.duplicate(a) !
335 if ( shd->count > 1 ) {
336 shd->count--;
337 register array_data *n = newData();
338 Q_CHECK_PTR( n );
339 if ( (n->len=shd->len) ) {
340 n->data = NEW(char,n->len);
341 Q_CHECK_PTR( n->data );
342 if ( n->data )
343 memcpy( n->data, shd->data, n->len );
344 } else {
345 n->data = 0;
346 }
347 shd = n;
348 }
349 return *this;
350 }
351 char *oldptr = 0;
352 if ( shd->count > 1 ) { // disconnect this
353 shd->count--;
354 shd = newData();
355 Q_CHECK_PTR( shd );
356 } else { // delete after copy was made
357 oldptr = shd->data;
358 }
359 if ( a.shd->len ) { // duplicate data
360 shd->data = NEW(char,a.shd->len);
361 Q_CHECK_PTR( shd->data );
362 if ( shd->data )
363 memcpy( shd->data, a.shd->data, a.shd->len );
364 } else {
365 shd->data = 0;
366 }
367 shd->len = a.shd->len;
368 if ( oldptr )
369 DELETE(oldptr);
370 return *this;
371}
372
373/*!
374 \overload
375 Deep copy. Dereferences the current array and obtains a copy of
376 \a len characters from array data \a d instead. Returns a reference
377 to this array.
378 \sa assign(), operator=()
379*/
380
381QGArray &QGArray::duplicate( const char *d, uint len )
382{
383 char *data;
384 if ( d == 0 || len == 0 ) {
385 data = 0;
386 len = 0;
387 } else {
388 if ( shd->count == 1 && shd->len == len ) {
389 memcpy( shd->data, d, len );// use same buffer
390 return *this;
391 }
392 data = NEW(char,len);
393 Q_CHECK_PTR( data );
394 memcpy( data, d, len );
395 }
396 if ( shd->count > 1 ) { // detach
397 shd->count--;
398 shd = newData();
399 Q_CHECK_PTR( shd );
400 } else { // just a single reference
401 if ( shd->data )
402 DELETE(shd->data);
403 }
404 shd->data = data;
405 shd->len = len;
406 return *this;
407}
408
409/*!
410 Resizes this array to \a len bytes and copies the \a len bytes at
411 address \a d into it.
412
413 \warning This function disregards the reference count mechanism. If
414 other QGArrays reference the same data as this, all will be updated.
415*/
416
417void QGArray::store( const char *d, uint len )
418 { // store, but not deref
419 resize( len );
420 memcpy( shd->data, d, len );
421}
422
423
424/*!
425 \fn array_data *QGArray::sharedBlock() const
426
427 Returns a pointer to the shared array block.
428
429 \warning
430
431 Do not use this function. Using it is begging for trouble. We dare
432 not remove it, for fear of breaking code, but we \e strongly
433 discourage new use of it.
434*/
435
436/*!
437 \fn void QGArray::setSharedBlock( array_data *p )
438
439 Sets the shared array block to \a p.
440
441 \warning
442
443 Do not use this function. Using it is begging for trouble. We dare
444 not remove it, for fear of breaking code, but we \e strongly
445 discourage new use of it.
446*/
447
448
449/*!
450 Sets raw data and returns a reference to the array.
451
452 Dereferences the current array and sets the new array data to \a d and
453 the new array size to \a len. Do not attempt to resize or re-assign the
454 array data when raw data has been set.
455 Call resetRawData(d,len) to reset the array.
456
457 Setting raw data is useful because it sets QMemArray data without
458 allocating memory or copying data.
459
460 Example of intended use:
461 \code
462 static uchar bindata[] = { 231, 1, 44, ... };
463 QByteArraya;
464 a.setRawData( bindata, sizeof(bindata) );// a points to bindata
465 QDataStream s( a, IO_ReadOnly ); // open on a's data
466 s >> <something>; // read raw bindata
467 s.close();
468 a.resetRawData( bindata, sizeof(bindata) ); // finished
469 \endcode
470
471 Example of misuse (do not do this):
472 \code
473 static uchar bindata[] = { 231, 1, 44, ... };
474 QByteArraya, b;
475 a.setRawData( bindata, sizeof(bindata) );// a points to bindata
476 a.resize( 8 ); // will crash
477 b = a; // will crash
478 a[2] = 123; // might crash
479 // forget to resetRawData - will crash
480 \endcode
481
482 \warning If you do not call resetRawData(), QGArray will attempt to
483 deallocate or reallocate the raw data, which might not be too good.
484 Be careful.
485*/
486
487QGArray &QGArray::setRawData( const char *d, uint len )
488{
489 duplicate( 0, 0 ); // set null data
490 shd->data = (char *)d;
491 shd->len = len;
492 return *this;
493}
494
495/*!
496 Resets raw data.
497
498 The arguments must be the data, \a d, and length \a len, that were
499 passed to setRawData(). This is for consistency checking.
500*/
501
502void QGArray::resetRawData( const char *d, uint len )
503{
504 if ( d != shd->data || len != shd->len ) {
505#if defined(QT_CHECK_STATE)
506 qWarning( "QGArray::resetRawData: Inconsistent arguments" );
507#endif
508 return;
509 }
510 shd->data = 0;
511 shd->len = 0;
512}
513
514
515/*!
516 Finds the first occurrence of \a d in the array from position \a index,
517 where \a sz is the size of the \a d element.
518
519 Note that \a index is given in units of \a sz, not bytes.
520
521 This function only compares whole cells, not bytes.
522*/
523
524int QGArray::find( const char *d, uint index, uint sz ) const
525{
526 index *= sz;
527 if ( index >= shd->len ) {
528#if defined(QT_CHECK_RANGE)
529 qWarning( "QGArray::find: Index %d out of range", index/sz );
530#endif
531 return -1;
532 }
533 register uint i;
534 uint ii;
535 switch ( sz ) {
536 case 1: { // 8 bit elements
537 register char *x = data() + index;
538 char v = *d;
539 for ( i=index; i<shd->len; i++ ) {
540 if ( *x++ == v )
541 break;
542 }
543 ii = i;
544 }
545 break;
546 case 2: { // 16 bit elements
547 register Q_INT16 *x = (Q_INT16*)(data() + index);
548 Q_INT16 v = *((Q_INT16*)d);
549 for ( i=index; i<shd->len; i+=2 ) {
550 if ( *x++ == v )
551 break;
552 }
553 ii = i/2;
554 }
555 break;
556 case 4: { // 32 bit elements
557 register Q_INT32 *x = (Q_INT32*)(data() + index);
558 Q_INT32 v = *((Q_INT32*)d);
559 for ( i=index; i<shd->len; i+=4 ) {
560 if ( *x++ == v )
561 break;
562 }
563 ii = i/4;
564 }
565 break;
566 default: { // any size elements
567 for ( i=index; i<shd->len; i+=sz ) {
568 if ( memcmp( d, &shd->data[i], sz ) == 0 )
569 break;
570 }
571 ii = i/sz;
572 }
573 break;
574 }
575 return i<shd->len ? (int)ii : -1;
576}
577
578/*!
579 Returns the number of occurrences of \a d in the array, where \a sz is
580 the size of the \a d element.
581
582 This function only compares whole cells, not bytes.
583*/
584
585int QGArray::contains( const char *d, uint sz ) const
586{
587 register uint i = shd->len;
588 int count = 0;
589 switch ( sz ) {
590 case 1: { // 8 bit elements
591 register char *x = data();
592 char v = *d;
593 while ( i-- ) {
594 if ( *x++ == v )
595 count++;
596 }
597 }
598 break;
599 case 2: { // 16 bit elements
600 register Q_INT16 *x = (Q_INT16*)data();
601 Q_INT16 v = *((Q_INT16*)d);
602 i /= 2;
603 while ( i-- ) {
604 if ( *x++ == v )
605 count++;
606 }
607 }
608 break;
609 case 4: { // 32 bit elements
610 register Q_INT32 *x = (Q_INT32*)data();
611 Q_INT32 v = *((Q_INT32*)d);
612 i /= 4;
613 while ( i-- ) {
614 if ( *x++ == v )
615 count++;
616 }
617 }
618 break;
619 default: { // any size elements
620 for ( i=0; i<shd->len; i+=sz ) {
621 if ( memcmp(d, &shd->data[i], sz) == 0 )
622 count++;
623 }
624 }
625 break;
626 }
627 return count;
628}
629
630static int cmp_item_size = 0;
631
632#if defined(Q_C_CALLBACKS)
633extern "C" {
634#endif
635
636#ifdef Q_OS_TEMP
637static int __cdecl cmp_arr( const void *n1, const void *n2 )
638#else
639static int cmp_arr( const void *n1, const void *n2 )
640#endif
641{
642 return ( n1 && n2 ) ? memcmp( n1, n2, cmp_item_size )
643 : ( n1 ? 1 : ( n2 ? -1 : 0 ) );
644 // ### Qt 3.0: Add a virtual compareItems() method and call that instead
645}
646
647#if defined(Q_C_CALLBACKS)
648}
649#endif
650
651/*!
652 Sorts the first \a sz items of the array.
653*/
654
655void QGArray::sort( uint sz )
656{
657 int numItems = size() / sz;
658 if ( numItems < 2 )
659 return;
660
661#ifdef QT_THREAD_SUPPORT
662 QMutexLocker locker( qt_global_mutexpool->get( &cmp_item_size ) );
663#endif // QT_THREAD_SUPPORT
664
665 cmp_item_size = sz;
666 qsort( shd->data, numItems, sz, cmp_arr );
667}
668
669/*!
670 Binary search; assumes that \a d is a sorted array of size \a sz.
671*/
672
673int QGArray::bsearch( const char *d, uint sz ) const
674{
675 int numItems = size() / sz;
676 if ( !numItems )
677 return -1;
678
679#ifdef QT_THREAD_SUPPORT
680 QMutexLocker locker( qt_global_mutexpool->get( &cmp_item_size ) );
681#endif // QT_THREAD_SUPPORT
682
683 cmp_item_size = sz;
684 char* r = (char*)::bsearch( d, shd->data, numItems, sz, cmp_arr );
685 if ( !r )
686 return -1;
687 while( (r >= shd->data + sz) && (cmp_arr( r - sz, d ) == 0) )
688 r -= sz;// search to first of equal elements; bsearch is undef
689 return (int)(( r - shd->data ) / sz);
690}
691
692
693/*!
694 \fn char *QGArray::at( uint index ) const
695
696 Returns a pointer to the byte at offset \a index in the array.
697*/
698
699/*!
700 Expand the array if necessary, and copies (the first part of) its
701 contents from the \a index * \a sz bytes at \a d.
702
703 Returns TRUE if the operation succeeds, FALSE if it runs out of
704 memory.
705
706 \warning This function disregards the reference count mechanism. If
707 other QGArrays reference the same data as this, all will be changed.
708*/
709
710bool QGArray::setExpand( uint index, const char *d, uint sz )
711{
712 index *= sz;
713 if ( index >= shd->len ) {
714 if ( !resize( index+sz ) ) // no memory
715 return FALSE;
716 }
717 memcpy( data() + index, d, sz );
718 return TRUE;
719}
720
721
722/*!
723 Prints a warning message if at() or [] is given a bad index.
724*/
725
726void QGArray::msg_index( uint index )
727{
728#if defined(QT_CHECK_RANGE)
729 qWarning( "QGArray::at: Absolute index %d out of range", index );
730#else
731 Q_UNUSED( index )
732#endif
733}
734
735
736/*!
737 Returns a new shared array block.
738*/
739
740QGArray::array_data * QGArray::newData()
741{
742 return new array_data;
743}
744
745
746/*!
747 Deletes the shared array block, \a p.
748*/
749
750void QGArray::deleteData( array_data *p )
751{
752 delete p;
753 p = 0;
754}