source: trunk/src/tools/qgvector.cpp@ 97

Last change on this file since 97 was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 14.1 KB
Line 
1/****************************************************************************
2** $Id: qgvector.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QGVector class
5**
6** Created : 930907
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"
39#if defined(Q_CC_BOR)
40// needed for qsort() because of a std namespace problem on Borland
41#include "qplatformdefs.h"
42#endif
43
44#define QGVECTOR_CPP
45#include "qgvector.h"
46#include "qglist.h"
47#include "qstring.h"
48#include "qdatastream.h"
49#include <stdlib.h>
50
51#ifdef QT_THREAD_SUPPORT
52# include <private/qmutexpool_p.h>
53#endif // QT_THREAD_SUPPORT
54
55#define USE_MALLOC // comment to use new/delete
56
57#undef NEW
58#undef DELETE
59
60#if defined(USE_MALLOC)
61#define NEW(type,size) ((type*)malloc(size*sizeof(type)))
62#define DELETE(array) (free((char*)array))
63#else
64#define NEW(type,size) (new type[size])
65#define DELETE(array) (delete[] array)
66#define DONT_USE_REALLOC // comment to use realloc()
67#endif
68
69/*!
70 \class QGVector
71 \reentrant
72 \ingroup collection
73
74 \brief The QGVector class is an internal class for implementing Qt
75 collection classes.
76
77 \internal
78
79 QGVector is an internal class that acts as a base class for the
80 QPtrVector collection class.
81
82 QGVector has some virtual functions that may be reimplemented in
83 subclasses to customize behavior.
84
85 \list
86 \i compareItems() compares two collection/vector items.
87 \i read() reads a collection/vector item from a QDataStream.
88 \i write() writes a collection/vector item to a QDataStream.
89 \endlist
90*/
91
92/*****************************************************************************
93 Default implementation of virtual functions
94 *****************************************************************************/
95
96/*!
97 This virtual function compares two list items.
98
99 Returns:
100 <ul>
101 <li> 0 if \a d1 == \a d2
102 <li> non-zero if \a d1 != \a d2
103 </ul>
104
105 This function returns \e int rather than \e bool so that
106 reimplementations can return one of three values and use it to sort
107 by:
108 <ul>
109 <li> 0 if \a d1 == \a d2
110 <li> \> 0 (positive integer) if \a d1 \> \a d2
111 <li> \< 0 (negative integer) if \a d1 \< \a d2
112 </ul>
113
114 The QPtrVector::sort() and QPtrVector::bsearch() functions require that
115 compareItems() is implemented as described here.
116
117 This function should not modify the vector because some const
118 functions call compareItems().
119*/
120
121int QGVector::compareItems( Item d1, Item d2 )
122{
123 return d1 != d2; // compare pointers
124}
125
126#ifndef QT_NO_DATASTREAM
127/*!
128 Reads a collection/vector item from the stream \a s and returns a reference
129 to the stream.
130
131 The default implementation sets \a d to 0.
132
133 \sa write()
134*/
135
136QDataStream &QGVector::read( QDataStream &s, Item &d )
137{ // read item from stream
138 d = 0;
139 return s;
140}
141
142/*!
143 Writes a collection/vector item to the stream \a s and returns a reference
144 to the stream.
145
146 The default implementation does nothing.
147
148 \sa read()
149*/
150
151QDataStream &QGVector::write( QDataStream &s, Item ) const
152{ // write item to stream
153 return s;
154}
155#endif // QT_NO_DATASTREAM
156
157/*****************************************************************************
158 QGVector member functions
159 *****************************************************************************/
160
161QGVector::QGVector() // create empty vector
162{
163 vec = 0;
164 len = numItems = 0;
165}
166
167QGVector::QGVector( uint size ) // create vectors with nullptrs
168{
169 len = size;
170 numItems = 0;
171 if ( len == 0 ) { // zero length
172 vec = 0;
173 return;
174 }
175 vec = NEW(Item,len);
176 Q_CHECK_PTR( vec );
177 memset( (void*)vec, 0, len*sizeof(Item) ); // fill with nulls
178}
179
180QGVector::QGVector( const QGVector &a ) // make copy of other vector
181 : QPtrCollection( a )
182{
183 len = a.len;
184 numItems = a.numItems;
185 if ( len == 0 ) {
186 vec = 0;
187 return;
188 }
189 vec = NEW( Item, len );
190 Q_CHECK_PTR( vec );
191 for ( uint i = 0; i < len; i++ ) {
192 if ( a.vec[i] ) {
193 vec[i] = newItem( a.vec[i] );
194 Q_CHECK_PTR( vec[i] );
195 } else {
196 vec[i] = 0;
197 }
198 }
199}
200
201QGVector::~QGVector()
202{
203 clear();
204}
205
206QGVector& QGVector::operator=( const QGVector &v )
207{
208 if ( &v == this )
209 return *this;
210
211 clear();
212 len = v.len;
213 numItems = v.numItems;
214 if ( len == 0 ) {
215 vec = 0;
216 return *this;
217 }
218 vec = NEW( Item, len );
219 Q_CHECK_PTR( vec );
220 for ( uint i = 0; i < len; i++ ) {
221 if ( v.vec[i] ) {
222 vec[i] = newItem( v.vec[i] );
223 Q_CHECK_PTR( vec[i] );
224 } else {
225 vec[i] = 0;
226 }
227 }
228 return *this;
229}
230
231
232bool QGVector::insert( uint index, Item d ) // insert item at index
233{
234#if defined(QT_CHECK_RANGE)
235 if ( index >= len ) { // range error
236 qWarning( "QGVector::insert: Index %d out of range", index );
237 return FALSE;
238 }
239#endif
240 if ( vec[index] ) { // remove old item
241 deleteItem( vec[index] );
242 numItems--;
243 }
244 if ( d ) {
245 vec[index] = newItem( d );
246 Q_CHECK_PTR( vec[index] );
247 numItems++;
248 return vec[index] != 0;
249 } else {
250 vec[index] = 0; // reset item
251 }
252 return TRUE;
253}
254
255bool QGVector::remove( uint index ) // remove item at index
256{
257#if defined(QT_CHECK_RANGE)
258 if ( index >= len ) { // range error
259 qWarning( "QGVector::remove: Index %d out of range", index );
260 return FALSE;
261 }
262#endif
263 if ( vec[index] ) { // valid item
264 deleteItem( vec[index] ); // delete it
265 vec[index] = 0; // reset pointer
266 numItems--;
267 }
268 return TRUE;
269}
270
271QPtrCollection::Item QGVector::take( uint index ) // take out item
272{
273#if defined(QT_CHECK_RANGE)
274 if ( index >= len ) { // range error
275 qWarning( "QGVector::take: Index %d out of range", index );
276 return 0;
277 }
278#endif
279 Item d = vec[index]; // don't delete item
280 if ( d )
281 numItems--;
282 vec[index] = 0;
283 return d;
284}
285
286void QGVector::clear() // clear vector
287{
288 if ( vec ) {
289 for ( uint i=0; i<len; i++ ) { // delete each item
290 if ( vec[i] )
291 deleteItem( vec[i] );
292 }
293 DELETE(vec);
294 vec = 0;
295 len = numItems = 0;
296 }
297}
298
299bool QGVector::resize( uint newsize ) // resize array
300{
301 if ( newsize == len ) // nothing to do
302 return TRUE;
303 if ( vec ) { // existing data
304 if ( newsize < len ) { // shrink vector
305 uint i = newsize;
306 while ( i < len ) { // delete lost items
307 if ( vec[i] ) {
308 deleteItem( vec[i] );
309 numItems--;
310 }
311 i++;
312 }
313 }
314 if ( newsize == 0 ) { // vector becomes empty
315 DELETE(vec);
316 vec = 0;
317 len = numItems = 0;
318 return TRUE;
319 }
320#if defined(DONT_USE_REALLOC)
321 if ( newsize == 0 ) {
322 DELETE(vec);
323 vec = 0;
324 return FALSE;
325 }
326 Item *newvec = NEW(Item,newsize); // manual realloc
327 memcpy( newvec, vec, (len < newsize ? len : newsize)*sizeof(Item) );
328 DELETE(vec);
329 vec = newvec;
330#else
331 vec = (Item*)realloc( (char *)vec, newsize*sizeof(Item) );
332#endif
333 } else { // create new vector
334 vec = NEW(Item,newsize);
335 len = numItems = 0;
336 }
337 Q_CHECK_PTR( vec );
338 if ( !vec ) // no memory
339 return FALSE;
340 if ( newsize > len ) // init extra space added
341 memset( (void*)&vec[len], 0, (newsize-len)*sizeof(Item) );
342 len = newsize;
343 return TRUE;
344}
345
346
347bool QGVector::fill( Item d, int flen ) // resize and fill vector
348{
349 if ( flen < 0 )
350 flen = len; // default: use vector length
351 else if ( !resize( flen ) )
352 return FALSE;
353 for ( uint i=0; i<(uint)flen; i++ ) // insert d at every index
354 insert( i, d );
355 return TRUE;
356}
357
358
359static QGVector *sort_vec=0; // current sort vector
360
361
362#if defined(Q_C_CALLBACKS)
363extern "C" {
364#endif
365
366#ifdef Q_OS_TEMP
367static int _cdecl cmp_vec( const void *n1, const void *n2 )
368#else
369static int cmp_vec( const void *n1, const void *n2 )
370#endif
371{
372 return sort_vec->compareItems( *((QPtrCollection::Item*)n1), *((QPtrCollection::Item*)n2) );
373}
374
375#if defined(Q_C_CALLBACKS)
376}
377#endif
378
379
380void QGVector::sort() // sort vector
381{
382 if ( count() == 0 ) // no elements
383 return;
384 register Item *start = &vec[0];
385 register Item *end = &vec[len-1];
386 Item tmp;
387 for (;;) { // put all zero elements behind
388 while ( start < end && *start != 0 )
389 start++;
390 while ( end > start && *end == 0 )
391 end--;
392 if ( start < end ) {
393 tmp = *start;
394 *start = *end;
395 *end = tmp;
396 } else {
397 break;
398 }
399 }
400
401#ifdef QT_THREAD_SUPPORT
402 QMutexLocker locker( qt_global_mutexpool ?
403 qt_global_mutexpool->get( &sort_vec ) : 0 );
404#endif // QT_THREAD_SUPPORT
405
406 sort_vec = (QGVector*)this;
407 qsort( vec, count(), sizeof(Item), cmp_vec );
408 sort_vec = 0;
409}
410
411int QGVector::bsearch( Item d ) const // binary search; when sorted
412{
413 if ( !len )
414 return -1;
415 if ( !d ) {
416#if defined(QT_CHECK_NULL)
417 qWarning( "QGVector::bsearch: Cannot search for null object" );
418#endif
419 return -1;
420 }
421 int n1 = 0;
422 int n2 = len - 1;
423 int mid = 0;
424 bool found = FALSE;
425 while ( n1 <= n2 ) {
426 int res;
427 mid = (n1 + n2)/2;
428 if ( vec[mid] == 0 ) // null item greater
429 res = -1;
430 else
431 res = ((QGVector*)this)->compareItems( d, vec[mid] );
432 if ( res < 0 )
433 n2 = mid - 1;
434 else if ( res > 0 )
435 n1 = mid + 1;
436 else { // found it
437 found = TRUE;
438 break;
439 }
440 }
441 if ( !found )
442 return -1;
443 // search to first of equal items
444 while ( (mid - 1 >= 0) && !((QGVector*)this)->compareItems(d, vec[mid-1]) )
445 mid--;
446 return mid;
447}
448
449int QGVector::findRef( Item d, uint index) const // find exact item in vector
450{
451#if defined(QT_CHECK_RANGE)
452 if ( index > len ) { // range error
453 qWarning( "QGVector::findRef: Index %d out of range", index );
454 return -1;
455 }
456#endif
457 for ( uint i=index; i<len; i++ ) {
458 if ( vec[i] == d )
459 return i;
460 }
461 return -1;
462}
463
464int QGVector::find( Item d, uint index ) const // find equal item in vector
465{
466#if defined(QT_CHECK_RANGE)
467 if ( index >= len ) { // range error
468 qWarning( "QGVector::find: Index %d out of range", index );
469 return -1;
470 }
471#endif
472 for ( uint i=index; i<len; i++ ) {
473 if ( vec[i] == 0 && d == 0 ) // found null item
474 return i;
475 if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 )
476 return i;
477 }
478 return -1;
479}
480
481uint QGVector::containsRef( Item d ) const // get number of exact matches
482{
483 uint count = 0;
484 for ( uint i=0; i<len; i++ ) {
485 if ( vec[i] == d )
486 count++;
487 }
488 return count;
489}
490
491uint QGVector::contains( Item d ) const // get number of equal matches
492{
493 uint count = 0;
494 for ( uint i=0; i<len; i++ ) {
495 if ( vec[i] == 0 && d == 0 ) // count null items
496 count++;
497 if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 )
498 count++;
499 }
500 return count;
501}
502
503bool QGVector::insertExpand( uint index, Item d )// insert and grow if necessary
504{
505 if ( index >= len ) {
506 if ( !resize( index+1 ) ) // no memory
507 return FALSE;
508 }
509 insert( index, d );
510 return TRUE;
511}
512
513void QGVector::toList( QGList *list ) const // store items in list
514{
515 list->clear();
516 for ( uint i=0; i<len; i++ ) {
517 if ( vec[i] )
518 list->append( vec[i] );
519 }
520}
521
522
523void QGVector::warningIndexRange( uint i )
524{
525#if defined(QT_CHECK_RANGE)
526 qWarning( "QGVector::operator[]: Index %d out of range", i );
527#else
528 Q_UNUSED( i )
529#endif
530}
531
532
533/*****************************************************************************
534 QGVector stream functions
535 *****************************************************************************/
536#ifndef QT_NO_DATASTREAM
537QDataStream &operator>>( QDataStream &s, QGVector &vec )
538{ // read vector
539 return vec.read( s );
540}
541
542QDataStream &operator<<( QDataStream &s, const QGVector &vec )
543{ // write vector
544 return vec.write( s );
545}
546
547QDataStream &QGVector::read( QDataStream &s ) // read vector from stream
548{
549 uint num;
550 s >> num; // read number of items
551 clear(); // clear vector
552 resize( num );
553 for (uint i=0; i<num; i++) { // read all items
554 Item d;
555 read( s, d );
556 Q_CHECK_PTR( d );
557 if ( !d ) // no memory
558 break;
559 vec[i] = d;
560 }
561 return s;
562}
563
564QDataStream &QGVector::write( QDataStream &s ) const
565{ // write vector to stream
566 uint num = count();
567 s << num; // number of items to write
568 num = size();
569 for (uint i=0; i<num; i++) { // write non-null items
570 if ( vec[i] )
571 write( s, vec[i] );
572 }
573 return s;
574}
575
576/* Returns whether v equals this vector or not */
577
578bool QGVector::operator==( const QGVector &v ) const
579{
580 if ( size() != v.size() )
581 return FALSE;
582 if ( count() != v.count() )
583 return FALSE;
584 for ( int i = 0; i < (int)size(); ++i ) {
585 if ( ( (QGVector*)this )->compareItems( at( i ), v.at( i ) ) != 0 )
586 return FALSE;
587 }
588 return TRUE;
589}
590
591#endif // QT_NO_DATASTREAM
Note: See TracBrowser for help on using the repository browser.