src/qt3support/tools/q3garray.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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
       
    63 QT_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 
       
   103 Q3GArray::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 
       
   116 Q3GArray::Q3GArray(int, int)
       
   117     : shd(0)
       
   118 {
       
   119 }
       
   120 
       
   121 /*!
       
   122   Constructs an array with room for \a size bytes.
       
   123 */
       
   124 
       
   125 Q3GArray::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 
       
   150 Q3GArray::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 
       
   161 Q3GArray::~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 
       
   209 bool 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 */
       
   223 bool 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 */
       
   284 bool 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 
       
   302 bool 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 
       
   337 Q3GArray &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 
       
   357 Q3GArray &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 
       
   382 Q3GArray &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 
       
   435 Q3GArray &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 
       
   476 void 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 
       
   530 Q3GArray &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 
       
   545 void 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 
       
   567 int 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 
       
   628 int 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 
       
   673 static int cmp_item_size = 0;
       
   674 
       
   675 #if defined(Q_C_CALLBACKS)
       
   676 extern "C" {
       
   677 #endif
       
   678 
       
   679 #ifdef Q_OS_WINCE
       
   680 static int __cdecl cmp_arr(const void *n1, const void *n2)
       
   681 #else
       
   682 static 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 
       
   698 void 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 
       
   716 int 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 
       
   753 bool 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 
       
   769 void 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 
       
   783 Q3GArray::array_data * Q3GArray::newData()
       
   784 {
       
   785     return new array_data;
       
   786 }
       
   787 
       
   788 
       
   789 /*!
       
   790   Deletes the shared array block \a p.
       
   791 */
       
   792 
       
   793 void Q3GArray::deleteData(array_data *p)
       
   794 {
       
   795     delete p;
       
   796 }
       
   797 
       
   798 QT_END_NAMESPACE