Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

tkarray.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  TKARRAY.C                                                                                                                                                   */
00003 /*                                                                                      */
00004 /*  Author: Mike Sandige                                                                    */
00005 /*  Description: Time-keyed array implementation.                                                                               */
00006 /*                                                                                      */
00007 /*  The contents of this file are subject to the Genesis3D Public License               */
00008 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00009 /*  compliance with the License. You may obtain a copy of the License at                */
00010 /*  http://www.genesis3d.com                                                            */
00011 /*                                                                                      */
00012 /*  Software distributed under the License is distributed on an "AS IS"                 */
00013 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00014 /*  the License for the specific language governing rights and limitations              */
00015 /*  under the License.                                                                  */
00016 /*                                                                                      */
00017 /*  The Original Code is Genesis3D, released March 25, 1999.                            */
00018 /*Genesis3D Version 1.1 released November 15, 1999                            */
00019 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
00020 /*                                                                                      */
00021 /****************************************************************************************/
00022 /*TKArray
00023         (Time-Keyed-Array)
00024         This module is designed primarily to support path.c
00025 
00026         The idea is that there are these packed arrays of elements,
00027         sorted by a geTKArray_TimeType key.  The key is assumed to be the 
00028         first field in each element.
00029 
00030         the geTKArray functions operate on this very specific array type.
00031 
00032         Error conditions are reported to errorlog
00033 */
00034 #include <assert.h>
00035 #include <stddef.h>
00036 #include <string.h>
00037 
00038 #include "TKArray.h"
00039 #include "ErrorLog.h"
00040 #include "ram.h"
00041 
00042 typedef struct geTKArray
00043 {
00044         int32 NumElements;              // number of elements in use
00045         int32 ElementSize;              // size of each element
00046         char Elements[1];               // array elements.  This list will be expanded by changing
00047                                                         // the allocated size of the entire geTKArray object
00048 }       geTKArray;
00049 
00050 typedef struct 
00051 {
00052         int32 NumElements;              // number of elements in use
00053         int32 ElementSize;              // size of each element
00054 } geTKArray_BinaryFileHeader;
00055 
00056 
00057 #define TK_MAX_ARRAY_LENGTH (0x7FFFFFFF)  // NumElements is (signed) 32 bit int
00058 
00059 
00060 #define TK_ARRAYSIZE (offsetof(geTKArray, Elements))    // gets rid of the extra element char in the def.
00061 
00062 // General validity test.
00063 // Use TK_ASSERT_VALID to test array for reasonable data.
00064 #ifdef _DEBUG
00065 
00066 #define TK_ASSERT_VALID(A) geTKArray_Asserts(A)
00067 
00068 // Do not call this function directly.  Use TK_ASSERT_VALID
00069 static void GENESISCC geTKArray_Asserts(const geTKArray* A)
00070 {
00071         assert( (A) != NULL );
00072         assert( ((A)->NumElements == 0) ||
00073                         (((A)->NumElements > 0) && ((A)->Elements != NULL)) );
00074         assert( (A)->NumElements >= 0 );
00075         assert( (A)->NumElements <= TK_MAX_ARRAY_LENGTH );
00076         assert( (A)->ElementSize > 0 );
00077 }
00078 
00079 #else // !_DEBUG
00080 
00081 #define TK_ASSERT_VALID(A) ((void)0)
00082 
00083 #endif // _DEBUG
00084 
00085 
00086 geTKArray *GENESISCC geTKArray_Create(                          
00087         int ElementSize)                                // element size
00088         // Creates new array with given attributes.  The first field of the element
00089         // is assumed to be the geTKArray_TimeType key.
00090 {
00091         geTKArray *A;
00092 
00093         // first item in each element must be the time key
00094         assert( ElementSize >= sizeof(geTKArray_TimeType) );
00095 
00096         A = geRam_Allocate(TK_ARRAYSIZE);
00097         if ( A == NULL)
00098         {
00099                 geErrorLog_Add(ERR_TKARRAY_CREATE, NULL);
00100                 return NULL;
00101         }
00102 
00103         A->ElementSize = ElementSize;
00104         A->NumElements = 0;
00105 
00106         TK_ASSERT_VALID(A);
00107 
00108         return A;       
00109 }
00110 
00111 geTKArray *GENESISCC geTKArray_CreateEmpty(                             
00112         int ElementSize,int ElementCount)                               // element size
00113         // Creates new array with given size and count.  The first field of the element
00114         // is assumed to be the geTKArray_TimeType key.
00115 {
00116         geTKArray *A;
00117         int32 size = TK_ARRAYSIZE + ElementCount * ElementSize;
00118         A = (geTKArray*)geRam_Allocate(size);
00119         if( A == NULL )
00120         {
00121                 geErrorLog_AddString(-1,"Failure to allocate empty TKArray", NULL);
00122                 return NULL;
00123         }
00124         A->ElementSize = ElementSize;
00125         A->NumElements = ElementCount;
00126 
00127         TK_ASSERT_VALID(A);
00128 
00129         return A;       
00130 }
00131 
00132 geTKArray* GENESISCC geTKArray_CreateFromBinaryFile(
00133         geVFile* pFile)                                 // stream positioned at array data
00134         // Creates a new array from the given stream.
00135 {
00136         int32 size;
00137         geTKArray* A;
00138         geTKArray_BinaryFileHeader Header;
00139 
00140         if (geVFile_Read(pFile, &Header, sizeof(geTKArray_BinaryFileHeader)) == GE_FALSE)
00141         {
00142                 geErrorLog_AddString(-1,"Failure to binary read TKArray header", NULL);
00143                 return NULL;
00144         }
00145 
00146         size = TK_ARRAYSIZE + Header.NumElements * Header.ElementSize;
00147         A = (geTKArray*)geRam_Allocate(size);
00148         if( A == NULL )
00149         {
00150                 geErrorLog_AddString(-1,"Failure to allocate TKArray during binary read", NULL);
00151                 return NULL;
00152         }
00153 
00154 
00155         if(geVFile_Read(pFile, A->Elements, size - sizeof(geTKArray_BinaryFileHeader)) == GE_FALSE)
00156                 {
00157                         geRam_Free(A);
00158                         geErrorLog_AddString(-1,"Failure to binary read TKArray body", NULL);
00159                         return NULL;
00160                 }
00161 
00162         A->NumElements = Header.NumElements;
00163         A->ElementSize = Header.ElementSize;
00164 
00165         return A;
00166 }
00167 
00168 
00169 geBoolean GENESISCC geTKArray_SamplesAreTimeLinear(const geTKArray *Array,geFloat Tolerance)
00170 {
00171         int i;
00172 
00173         geTKArray_TimeType Delta,Nth,LastNth,NthDelta;
00174                         
00175         if (Array->NumElements < 2)
00176                 return GE_TRUE;
00177 
00178         LastNth = geTKArray_ElementTime(Array, 0);
00179         Nth     = geTKArray_ElementTime(Array, 1);
00180         Delta   =  Nth - LastNth;
00181         LastNth = Nth;
00182         
00183         for (i=2; i< Array->NumElements; i++)
00184                 {
00185                         Nth = geTKArray_ElementTime(Array, i);
00186                         NthDelta = (Nth-LastNth)-Delta;
00187                         if (NthDelta<0.0f) NthDelta = -NthDelta;
00188                         if (NthDelta>Tolerance)
00189                                 {
00190                                         return GE_FALSE;
00191                                 }
00192                         LastNth = Nth;
00193                 }
00194         return GE_TRUE;
00195 }
00196 
00197 geBoolean GENESISCC geTKArray_WriteToBinaryFile(
00198         const geTKArray* Array,                 // sorted array to write
00199         geVFile* pFile)                                 // stream positioned for writing
00200         // Writes the array to the given stream.
00201 {
00202         int size;
00203         
00204         size = TK_ARRAYSIZE + Array->NumElements * Array->ElementSize;
00205         if(geVFile_Write(pFile, Array, size) == GE_FALSE)
00206         {
00207                 geErrorLog_AddString(-1,"Failure to write binary TKArray data", NULL);
00208                 return GE_FALSE;
00209         }
00210         return GE_TRUE;
00211 }
00212 
00213 void GENESISCC geTKArray_Destroy(geTKArray **PA)
00214         // destroys array
00215 {
00216         assert( PA  != NULL );
00217         TK_ASSERT_VALID(*PA);
00218 
00219         geRam_Free(*PA);
00220         *PA = NULL;
00221 }
00222 
00223 
00224 int GENESISCC geTKArray_BSearch(
00225         const geTKArray *A,                             // sorted array to search
00226         geTKArray_TimeType Key)                 // searching for this key
00227         // Searches for key in the Array.   A is assumed to be sorted
00228         // if key is found (within +-tolarance), the index to that element is returned.
00229         // if key is not found, the index to the key just smaller than the 
00230         // given key is returned.  (-1 if the key is smaller than the first element)
00231 {
00232         int low,hi,mid;
00233         int ElementSize;
00234         const char *Array;
00235         geTKArray_TimeType test;
00236 
00237         TK_ASSERT_VALID(A);
00238         
00239         low = 0;
00240         hi = A->NumElements - 1;
00241         Array = A->Elements;
00242         ElementSize = A->ElementSize;
00243         
00244         while ( low<=hi )
00245                 {
00246                         mid = (low+hi)/2;
00247                         test = *(geTKArray_TimeType *)(Array + mid*ElementSize);
00248                         if ( Key > test )
00249                                 {
00250                                         low = mid+1;
00251                                 }
00252                         else
00253                                 {
00254                                         if ( Key < test )
00255                                                 {
00256                                                         hi = mid-1;
00257                                                 }
00258                                         else
00259                                                 {
00260                                                         return mid;
00261                                                 }
00262                                 }
00263                 }
00264         return hi;
00265 }
00266 
00267 
00268 geBoolean GENESISCC geTKArray_Insert(
00269         geTKArray **PtrA,                               // sorted array to insert into
00270         geTKArray_TimeType Key,                 // key to insert
00271         int *Index)                                             // new element index
00272         // inserts a new element into Array.
00273         // sets only the key for the new element - the rest is junk
00274         // returns GE_TRUE if the insertion was successful.
00275         // returns GE_FALSE if the insertion failed. 
00276         // if Array is empty (no elements, NULL pointer) it is allocated and filled 
00277         // with the one Key element
00278         // Index is the index of the new element 
00279 {
00280         int n;
00281         geTKArray *ChangedA;
00282         geTKArray *A;
00283         geTKArray_TimeType Found;
00284 
00285         assert( PtrA );
00286         A = *PtrA;
00287         TK_ASSERT_VALID(A);
00288 
00289         n = geTKArray_BSearch(A,Key);
00290         // n is the element just prior to the location of the new element
00291 
00292         if(Index)
00293                 *Index = n+1;
00294 
00295         if (n >= 0)
00296         {
00297                 Found =  *(geTKArray_TimeType *)(A->Elements + (n * (A->ElementSize)) );
00298                 // Found <= Key  (within +-GE_TKA_TIME_TOLERANCE)
00299                 if (Found > Key - GE_TKA_TIME_TOLERANCE)
00300                 {       // if Found==Key, bail.  Can't have two identical keys.
00301                         geErrorLog_Add(ERR_TKARRAY_INSERT_IDENTICAL, NULL);
00302                         return GE_FALSE;
00303                 }
00304         }
00305 
00306         if (A->NumElements >= TK_MAX_ARRAY_LENGTH)
00307         {
00308                 geErrorLog_Add(ERR_TKARRAY_TOO_BIG, NULL);
00309                 return GE_FALSE;
00310         }
00311 
00312         ChangedA = (geTKArray *)geRam_Realloc(A, 
00313                                 TK_ARRAYSIZE + (A->NumElements + 1) * A->ElementSize);
00314 
00315         if ( ChangedA == NULL )
00316         {       
00317                 geErrorLog_Add(ERR_TKARRAY_INSERT_ENOMEM, NULL);
00318                 return GE_FALSE;
00319         }
00320         A = ChangedA;
00321 
00322         // advance n to new element's position
00323         n++;
00324         
00325         // move elements as necessary
00326         if(n < A->NumElements)
00327         {
00328                 memmove( A->Elements + (n + 1) * A->ElementSize,        // dest
00329                                  A->Elements + n * A->ElementSize,                      // src
00330                                  (A->NumElements - n) * A->ElementSize);        // count
00331         }
00332 
00333         *(geTKArray_TimeType *)((A->Elements) + ((n) * (A->ElementSize)) ) = Key;
00334         A->NumElements++;
00335         *PtrA = A;
00336 
00337         return GE_TRUE;
00338 }
00339 
00340 
00341 geBoolean GENESISCC geTKArray_DeleteElement(
00342         geTKArray **PtrA,                               // sorted array to delete from
00343         int N)                                                  // element to delete
00344         // deletes an element from Array.
00345         // returns GE_TRUE if the deletion was successful. 
00346         // returns GE_FALSE if the deletion failed. (key not found or realloc failed)
00347 {
00348         geTKArray *A;
00349         geTKArray *ChangedA;
00350         
00351         assert( PtrA != NULL);
00352         A = *PtrA;
00353         TK_ASSERT_VALID(A);
00354         assert(N >= 0);
00355         assert(N < A->NumElements);
00356         
00357         memmove( (A->Elements) + (N) * (A->ElementSize),  //dest
00358                          (A->Elements) + (N+1) * (A->ElementSize),  //src
00359                          ((A->NumElements) - (N+1))* (A->ElementSize) );
00360 
00361         A->NumElements--;
00362         ChangedA = (geTKArray *)geRam_Realloc(A, 
00363                                 TK_ARRAYSIZE + A->NumElements * A->ElementSize);
00364         if ( ChangedA != NULL ) 
00365         {       
00366                 // if realloc fails to shrink block. no real error.
00367                 A = ChangedA;
00368         }
00369 
00370         *PtrA = A;
00371 
00372         return GE_TRUE;
00373 }
00374 
00375 
00376 void *GENESISCC geTKArray_Element(const geTKArray *A, int N)
00377         // returns the Nth element 
00378 {
00379         TK_ASSERT_VALID(A);
00380         assert(N >= 0);
00381         assert(N < A->NumElements);
00382 
00383         return (void *)( (A->Elements) + (N * (A->ElementSize)) );
00384 }
00385 
00386 
00387 geTKArray_TimeType GENESISCC geTKArray_ElementTime(const geTKArray *A, int N)
00388         // returns the time key for the Nth element 
00389 {
00390         TK_ASSERT_VALID(A);
00391         assert(N >= 0);
00392         assert(N < A->NumElements);
00393         
00394         return *(geTKArray_TimeType *)((A->Elements) + (N * (A->ElementSize)) );
00395 }
00396 
00397 
00398 int GENESISCC geTKArray_NumElements(const geTKArray *A)
00399         // returns the number of elements in the array
00400 {
00401         TK_ASSERT_VALID(A);
00402         return A->NumElements;
00403 }
00404 
00405 
00406 int GENESISCC geTKArray_ElementSize(const geTKArray *A)
00407         // returns the size of each element in the array
00408 {
00409         TK_ASSERT_VALID(A);
00410         return A->ElementSize;
00411 }

Generated on Tue Sep 30 12:36:31 2003 for GTestAndEngine by doxygen 1.3.2