Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qgarray.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** $Id: qgarray.cpp,v 1.2 2003/07/10 02:40:11 llornkcor Exp $
00003 **
00004 ** Implementation of QGArray class
00005 **
00006 ** Created : 930906
00007 **
00008 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
00009 **
00010 ** This file is part of the tools module of the Qt GUI Toolkit.
00011 **
00012 ** This file may be distributed under the terms of the Q Public License
00013 ** as defined by Trolltech AS of Norway and appearing in the file
00014 ** LICENSE.QPL included in the packaging of this file.
00015 **
00016 ** This file may be distributed and/or modified under the terms of the
00017 ** GNU General Public License version 2 as published by the Free Software
00018 ** Foundation and appearing in the file LICENSE.GPL included in the
00019 ** packaging of this file.
00020 **
00021 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
00022 ** licenses may use this file in accordance with the Qt Commercial License
00023 ** Agreement provided with the Software.
00024 **
00025 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00026 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00027 **
00028 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00029 **   information about Qt Commercial License Agreements.
00030 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00031 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00032 **
00033 ** Contact info@trolltech.com if any conditions of this licensing are
00034 ** not clear to you.
00035 **
00036 **********************************************************************/
00037 
00038 #include "qglobal.h"
00039 #if defined(Q_CC_BOR)
00040     // needed for qsort() because of a std namespace problem on Borland
00041 #   include "qplatformdefs.h"
00042 #elif defined(Q_WS_WIN)
00043     // needed for bsearch on some platforms
00044 #   include "qt_windows.h"
00045 #endif
00046 
00047 #define  QGARRAY_CPP
00048 #include "qgarray.h"
00049 #include <stdlib.h>
00050 #include <string.h>
00051 
00052 #ifdef QT_THREAD_SUPPORT
00053 #  include <private/qmutexpool_p.h>
00054 #endif // QT_THREAD_SUPPORT
00055 
00056 /*
00057   If USE_MALLOC isn't defined, we use new[] and delete[] to allocate
00058   memory. The documentation for QMemArray<T>::assign() explicitly
00059   mentions that the array is freed using free(), so don't mess around
00060   with USE_MALLOC unless you know what you're doing.
00061 */
00062 #define USE_MALLOC
00063 
00064 #undef NEW
00065 #undef DELETE
00066 
00067 #if defined(USE_MALLOC)
00068 #define NEW(type,size)  ((type*)malloc(size*sizeof(type)))
00069 #define DELETE(array)   (free((char*)array))
00070 #else
00071 #define NEW(type,size)  (new type[size])
00072 #define DELETE(array)   (delete[] array)
00073 #define DONT_USE_REALLOC                        // comment to use realloc()
00074 #endif
00075 
00113 QGArray::QGArray()
00114 {
00115     shd = newData();
00116     Q_CHECK_PTR( shd );
00117 }
00118 
00126 QGArray::QGArray( int, int )
00127 {
00128 }
00129 
00134 QGArray::QGArray( int size )
00135 {
00136     if ( size < 0 ) {
00137 #if defined(QT_CHECK_RANGE)
00138         qWarning( "QGArray: Cannot allocate array with negative length" );
00139 #endif
00140         size = 0;
00141     }
00142     shd = newData();
00143     Q_CHECK_PTR( shd );
00144     if ( size == 0 )                            // zero length
00145         return;
00146     shd->data = NEW(char,size);
00147     Q_CHECK_PTR( shd->data );
00148     shd->len =
00149 #ifdef QT_QGARRAY_SPEED_OPTIM
00150         shd->maxl =
00151 #endif
00152         size;
00153 }
00154 
00159 QGArray::QGArray( const QGArray &a )
00160 {
00161     shd = a.shd;
00162     shd->ref();
00163 }
00164 
00170 QGArray::~QGArray()
00171 {
00172     if ( shd && shd->deref() ) {                // delete when last reference
00173         if ( shd->data )                        // is lost
00174             DELETE(shd->data);
00175         deleteData( shd );
00176         shd = 0;
00177     }
00178 }
00179 
00180 
00218 bool QGArray::isEqual( const QGArray &a ) const
00219 {
00220     if ( size() != a.size() )                   // different size
00221         return FALSE;
00222     if ( data() == a.data() )                   // has same data
00223         return TRUE;
00224     return (size() ? memcmp( data(), a.data(), size() ) : 0) == 0;
00225 }
00226 
00227 
00232 bool QGArray::resize( uint newsize, Optimization optim )
00233 {
00234 #ifndef QT_QGARRAY_SPEED_OPTIM
00235     Q_UNUSED(optim);
00236 #endif
00237 
00238     if ( newsize == shd->len
00239 #ifdef QT_QGARRAY_SPEED_OPTIM
00240          && newsize == shd->maxl
00241 #endif
00242         ) // nothing to do
00243         return TRUE;
00244     if ( newsize == 0 ) {                       // remove array
00245         duplicate( 0, 0 );
00246         return TRUE;
00247     }
00248 
00249     uint newmaxl = newsize;
00250 #ifdef QT_QGARRAY_SPEED_OPTIM
00251     if ( optim == SpeedOptim ) {
00252         if ( newsize <= shd->maxl &&
00253              ( newsize * 4 > shd->maxl || shd->maxl <= 4 ) ) {
00254             shd->len = newsize;
00255             return TRUE;
00256         }
00257         newmaxl = 4;
00258         while ( newmaxl < newsize )
00259             newmaxl *= 2;
00260         // try to spare some memory
00261         if ( newmaxl >= 1024 * 1024 && newsize <= newmaxl - (newmaxl >> 2) )
00262             newmaxl -= newmaxl >> 2;
00263     }
00264     shd->maxl = newmaxl;
00265 #endif
00266 
00267     if ( shd->data ) {                          // existing data
00268 #if defined(DONT_USE_REALLOC)
00269         char *newdata = NEW(char,newsize);      // manual realloc
00270         memcpy( newdata, shd->data, QMIN(shd->len,newmaxl) );
00271         DELETE(shd->data);
00272         shd->data = newdata;
00273 #else
00274         shd->data = (char *)realloc( shd->data, newmaxl );
00275 #endif
00276     } else {
00277         shd->data = NEW(char,newmaxl);
00278     }
00279     if ( !shd->data )                           // no memory
00280         return FALSE;
00281     shd->len = newsize;
00282     return TRUE;
00283 }
00284 
00287 bool QGArray::resize( uint newsize )
00288 {
00289     return resize( newsize, MemOptim );
00290 }
00291 
00292 
00305 bool QGArray::fill( const char *d, int len, uint sz )
00306 {
00307     if ( len < 0 )
00308         len = shd->len/sz;                      // default: use array length
00309     else if ( !resize( len*sz ) )
00310         return FALSE;
00311     if ( sz == 1 )                              // 8 bit elements
00312         memset( data(), *d, len );
00313     else if ( sz == 4 ) {                       // 32 bit elements
00314         register Q_INT32 *x = (Q_INT32*)data();
00315         Q_INT32 v = *((Q_INT32*)d);
00316         while ( len-- )
00317             *x++ = v;
00318     } else if ( sz == 2 ) {                     // 16 bit elements
00319         register Q_INT16 *x = (Q_INT16*)data();
00320         Q_INT16 v = *((Q_INT16*)d);
00321         while ( len-- )
00322             *x++ = v;
00323     } else {                                    // any other size elements
00324         register char *x = data();
00325         while ( len-- ) {                       // more complicated
00326             memcpy( x, d, sz );
00327             x += sz;
00328         }
00329     }
00330     return TRUE;
00331 }
00332 
00340 QGArray &QGArray::assign( const QGArray &a )
00341 {
00342     a.shd->ref();                               // avoid 'a = a'
00343     if ( shd->deref() ) {                       // delete when last reference
00344         if ( shd->data )                        // is lost
00345             DELETE(shd->data);
00346         deleteData( shd );
00347     }
00348     shd = a.shd;
00349     return *this;
00350 }
00351 
00360 QGArray &QGArray::assign( const char *d, uint len )
00361 {
00362     if ( shd->count > 1 ) {                     // disconnect this
00363         shd->count--;
00364         shd = newData();
00365         Q_CHECK_PTR( shd );
00366     } else {
00367         if ( shd->data )
00368             DELETE(shd->data);
00369     }
00370     shd->data = (char *)d;
00371     shd->len =
00372 #ifdef QT_QGARRAY_SPEED_OPTIM
00373         shd->maxl =
00374 #endif
00375         len;
00376     return *this;
00377 }
00378 
00385 QGArray &QGArray::duplicate( const QGArray &a )
00386 {
00387     if ( a.shd == shd ) {                       // a.duplicate(a) !
00388         if ( shd->count > 1 ) {
00389             shd->count--;
00390             register array_data *n = newData();
00391             Q_CHECK_PTR( n );
00392             if ( (n->len=shd->len) ) {
00393                 n->data = NEW(char,n->len);
00394                 Q_CHECK_PTR( n->data );
00395                 if ( n->data )
00396                     memcpy( n->data, shd->data, n->len );
00397             } else {
00398                 n->data = 0;
00399             }
00400             shd = n;
00401         }
00402         return *this;
00403     }
00404     char *oldptr = 0;
00405     if ( shd->count > 1 ) {                     // disconnect this
00406         shd->count--;
00407         shd = newData();
00408         Q_CHECK_PTR( shd );
00409     } else {                                    // delete after copy was made
00410         oldptr = shd->data;
00411     }
00412     if ( a.shd->len ) {                         // duplicate data
00413         shd->data = NEW(char,a.shd->len);
00414         Q_CHECK_PTR( shd->data );
00415         if ( shd->data )
00416             memcpy( shd->data, a.shd->data, a.shd->len );
00417     } else {
00418         shd->data = 0;
00419     }
00420     shd->len =
00421 #ifdef QT_QGARRAY_SPEED_OPTIM
00422         shd->maxl =
00423 #endif
00424         a.shd->len;
00425     if ( oldptr )
00426         DELETE(oldptr);
00427     return *this;
00428 }
00429 
00438 QGArray &QGArray::duplicate( const char *d, uint len )
00439 {
00440     char *data;
00441     if ( d == 0 || len == 0 ) {
00442         data = 0;
00443         len  = 0;
00444     } else {
00445         if ( shd->count == 1 && shd->len == len ) {
00446             memcpy( shd->data, d, len );        // use same buffer
00447             return *this;
00448         }
00449         data = NEW(char,len);
00450         Q_CHECK_PTR( data );
00451         memcpy( data, d, len );
00452     }
00453     if ( shd->count > 1 ) {                     // detach
00454         shd->count--;
00455         shd = newData();
00456         Q_CHECK_PTR( shd );
00457     } else {                                    // just a single reference
00458         if ( shd->data )
00459             DELETE(shd->data);
00460     }
00461     shd->data = data;
00462     shd->len =
00463 #ifdef QT_QGARRAY_SPEED_OPTIM
00464         shd->maxl =
00465 #endif
00466         len;
00467     return *this;
00468 }
00469 
00478 void QGArray::store( const char *d, uint len )
00479 {                                               // store, but not deref
00480     resize( len );
00481     memcpy( shd->data, d, len );
00482 }
00483 
00484 
00548 QGArray &QGArray::setRawData( const char *d, uint len )
00549 {
00550     duplicate( 0, 0 );                          // set null data
00551     shd->data = (char *)d;
00552     shd->len  = len;
00553     return *this;
00554 }
00555 
00563 void QGArray::resetRawData( const char *d, uint len )
00564 {
00565     if ( d != shd->data || len != shd->len ) {
00566 #if defined(QT_CHECK_STATE)
00567         qWarning( "QGArray::resetRawData: Inconsistent arguments" );
00568 #endif
00569         return;
00570     }
00571     shd->data = 0;
00572     shd->len  = 0;
00573 }
00574 
00575 
00585 int QGArray::find( const char *d, uint index, uint sz ) const
00586 {
00587     index *= sz;
00588     if ( index >= shd->len ) {
00589 #if defined(QT_CHECK_RANGE)
00590         qWarning( "QGArray::find: Index %d out of range", index/sz );
00591 #endif
00592         return -1;
00593     }
00594     register uint i;
00595     uint ii;
00596     switch ( sz ) {
00597         case 1: {                               // 8 bit elements
00598             register char *x = data() + index;
00599             char v = *d;
00600             for ( i=index; i<shd->len; i++ ) {
00601                 if ( *x++ == v )
00602                     break;
00603             }
00604             ii = i;
00605             }
00606             break;
00607         case 2: {                               // 16 bit elements
00608             register Q_INT16 *x = (Q_INT16*)(data() + index);
00609             Q_INT16 v = *((Q_INT16*)d);
00610             for ( i=index; i<shd->len; i+=2 ) {
00611                 if ( *x++ == v )
00612                     break;
00613             }
00614             ii = i/2;
00615             }
00616             break;
00617         case 4: {                               // 32 bit elements
00618             register Q_INT32 *x = (Q_INT32*)(data() + index);
00619             Q_INT32 v = *((Q_INT32*)d);
00620             for ( i=index; i<shd->len; i+=4 ) {
00621                 if ( *x++ == v )
00622                     break;
00623             }
00624             ii = i/4;
00625             }
00626             break;
00627         default: {                              // any size elements
00628             for ( i=index; i<shd->len; i+=sz ) {
00629                 if ( memcmp( d, &shd->data[i], sz ) == 0 )
00630                     break;
00631             }
00632             ii = i/sz;
00633             }
00634             break;
00635     }
00636     return i<shd->len ? (int)ii : -1;
00637 }
00638 
00646 int QGArray::contains( const char *d, uint sz ) const
00647 {
00648     register uint i = shd->len;
00649     int count = 0;
00650     switch ( sz ) {
00651         case 1: {                               // 8 bit elements
00652             register char *x = data();
00653             char v = *d;
00654             while ( i-- ) {
00655                 if ( *x++ == v )
00656                     count++;
00657             }
00658             }
00659             break;
00660         case 2: {                               // 16 bit elements
00661             register Q_INT16 *x = (Q_INT16*)data();
00662             Q_INT16 v = *((Q_INT16*)d);
00663             i /= 2;
00664             while ( i-- ) {
00665                 if ( *x++ == v )
00666                     count++;
00667             }
00668             }
00669             break;
00670         case 4: {                               // 32 bit elements
00671             register Q_INT32 *x = (Q_INT32*)data();
00672             Q_INT32 v = *((Q_INT32*)d);
00673             i /= 4;
00674             while ( i-- ) {
00675                 if ( *x++ == v )
00676                     count++;
00677             }
00678             }
00679             break;
00680         default: {                              // any size elements
00681             for ( i=0; i<shd->len; i+=sz ) {
00682                 if ( memcmp(d, &shd->data[i], sz) == 0 )
00683                     count++;
00684             }
00685             }
00686             break;
00687     }
00688     return count;
00689 }
00690 
00691 static int cmp_item_size = 0;
00692 
00693 #if defined(Q_C_CALLBACKS)
00694 extern "C" {
00695 #endif
00696 
00697 #ifdef Q_OS_TEMP
00698 static int __cdecl cmp_arr( const void *n1, const void *n2 )
00699 #else
00700 static int cmp_arr( const void *n1, const void *n2 )
00701 #endif
00702 {
00703     return ( n1 && n2 ) ? memcmp( n1, n2, cmp_item_size )
00704                         : ( n1 ? 1 : ( n2 ? -1 : 0 ) );
00705     // ### Qt 3.0: Add a virtual compareItems() method and call that instead
00706 }
00707 
00708 #if defined(Q_C_CALLBACKS)
00709 }
00710 #endif
00711 
00716 void QGArray::sort( uint sz )
00717 {
00718     int numItems = size() / sz;
00719     if ( numItems < 2 )
00720         return;
00721 
00722 #ifdef QT_THREAD_SUPPORT
00723     QMutexLocker locker( qt_global_mutexpool ?
00724                          qt_global_mutexpool->get( &cmp_item_size ) : 0 );
00725 #endif // QT_THREAD_SUPPORT
00726 
00727     cmp_item_size = sz;
00728     qsort( shd->data, numItems, sz, cmp_arr );
00729 }
00730 
00735 int QGArray::bsearch( const char *d, uint sz ) const
00736 {
00737     int numItems = size() / sz;
00738     if ( !numItems )
00739         return -1;
00740 
00741 #ifdef QT_THREAD_SUPPORT
00742     QMutexLocker locker( qt_global_mutexpool ?
00743                          qt_global_mutexpool->get( &cmp_item_size ) : 0 );
00744 #endif // QT_THREAD_SUPPORT
00745 
00746     cmp_item_size = sz;
00747     char* r = (char*)::bsearch( d, shd->data, numItems, sz, cmp_arr );
00748     if ( !r )
00749         return -1;
00750     while( (r >= shd->data + sz) && (cmp_arr( r - sz, d ) == 0) )
00751         r -= sz;        // search to first of equal elements; bsearch is undef
00752     return (int)(( r - shd->data ) / sz);
00753 }
00754 
00755 
00773 bool QGArray::setExpand( uint index, const char *d, uint sz )
00774 {
00775     index *= sz;
00776     if ( index >= shd->len ) {
00777         if ( !resize( index+sz ) )              // no memory
00778             return FALSE;
00779     }
00780     memcpy( data() + index, d, sz );
00781     return TRUE;
00782 }
00783 
00784 
00789 void QGArray::msg_index( uint index )
00790 {
00791 #if defined(QT_CHECK_RANGE)
00792     qWarning( "QGArray::at: Absolute index %d out of range", index );
00793 #else
00794     Q_UNUSED( index )
00795 #endif
00796 }
00797 
00798 
00803 QGArray::array_data * QGArray::newData()
00804 {
00805     return new array_data;
00806 }
00807 
00808 
00813 void QGArray::deleteData( array_data *p )
00814 {
00815     delete p;
00816     p = 0;
00817 }

Generated on Sat Nov 5 16:18:30 2005 for OPIE by  doxygen 1.4.2