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

list.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  List                                                                                */
00003 /*                                                                                      */
00004 /*  Author: Charles Bloom                                                               */
00005 /*  Description: List/Link/Node Primitives                                              */
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 
00023 //#define SAFE_HASH_DEBUG
00024 
00025 /*****
00026 
00027 List_Ram can still be as high as 30% of the time!
00028 
00029 *******/
00030 
00031 // #define DO_TIMER
00032 
00033 #include <assert.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include "list.h"
00037 #include "mempool.h"
00038 #include "ram.h"
00039 #include "crc32.h"
00040 
00041 /**********************************/
00042 // Timer Stuff
00043 
00044 #ifdef DO_TIMER
00045 #include "timer.h"
00046 
00047 TIMER_VARS(List_Ram);
00048 TIMER_VARS(List_RadixWalk);
00049 TIMER_VARS(List_RadixInit);
00050 
00051 #else
00052 
00053 #define TIMER_P(x)
00054 #define TIMER_Q(X)
00055 
00056 #endif // DO_TIMER
00057 
00058 #ifdef _DEBUG
00059 #define Debug(func)     func;
00060 #define DebugAlert()    do { __asm { int 03h } } while(0)
00061 #else
00062 #define Debug(func)
00063 #define DebugAlert()
00064 #endif
00065 
00066 #define MemAlloc(size)  geRam_AllocateClear(size)
00067 #define MemFree(mem)    geRam_Free(mem)
00068 
00069 #ifdef DO_TIMER // {
00070 #undef new
00071 #define new(type)               mymalloc(sizeof(type))
00072 #undef destroy
00073 #define destroy(mem)    if ( mem ) myfree(mem)
00074 
00075 void * mymalloc(int size)
00076 {
00077 void *ret;
00078 TIMER_P(List_Ram);
00079 ret = MemAlloc(size);
00080 TIMER_Q(List_Ram);
00081 return ret;
00082 }
00083 void myfree(void *mem)
00084 {
00085 TIMER_P(List_Ram);
00086 MemFree(mem);
00087 TIMER_Q(List_Ram);
00088 }
00089 
00090 #undef MemAlloc
00091 #define MemAlloc mymalloc
00092 #undef MemFree
00093 #define MemFree myfree
00094 
00095 #else // }{ DO_TIMER
00096 
00097 #undef  new
00098 #define new(type)               MemAlloc(sizeof(type))
00099 #undef  destroy
00100 #define destroy(mem)    if ( mem ) MemFree(mem)
00101 
00102 #endif // } DO_TIMER
00103 
00104 /**********************************/
00105 
00106 static MemPool *ListPool_g = NULL, *LinkPool_g = NULL, *HashNodePool_g = NULL;
00107 static int UsageCount = 0;
00108 
00109 /**********************************/
00110 
00111 int LN_ListLen(LinkNode *pList)
00112 {
00113 LinkNode *pNode;
00114 int Len=0;
00115         if ( ! pList )
00116                 return 0;
00117         LN_Walk(pNode,pList) {
00118                 Len++;
00119         }
00120 return Len;
00121 }
00122 
00123 LinkNode *      LISTCALL LN_CutHead(LinkNode *pList)
00124 {
00125 LinkNode * LN;
00126         assert(pList);
00127         LN = pList->Next;
00128         if ( LN == pList ) return NULL;
00129         LN_Cut(LN);
00130 return LN;
00131 }
00132 
00133 LinkNode *      LISTCALL LN_CutTail(LinkNode *pList)
00134 {
00135 LinkNode * LN;
00136         assert(pList);
00137         LN = pList->Prev;
00138         if ( LN == pList ) return NULL;
00139         LN_Cut(LN);
00140 return LN;
00141 }
00142 
00143 /**********************************/
00144 
00145 struct List
00146 {
00147         List *Next,*Prev;
00148         void * Data;
00149 };
00150 
00151 void    LISTCALL List_Destroy(List * pList)
00152 {
00153 List * pNode;
00154         assert(pList);
00155         pNode = pList->Next;
00156         while( pNode != pList )
00157         {
00158         List *Next;
00159                 Next = pNode->Next;
00160                 MemPool_FreeHunk(ListPool_g,pNode);
00161                 pNode = Next;
00162         }
00163         MemPool_FreeHunk(ListPool_g,pList);
00164 }
00165 
00166 List *  LISTCALL List_Create(void)
00167 {
00168 List * pNew;
00169 
00170         pNew = MemPool_GetHunk(ListPool_g);
00171         assert(pNew);
00172         pNew->Data = NULL;
00173         pNew->Next = pNew->Prev = pNew;
00174 return pNew;
00175 }
00176 
00177 List *  LISTCALL List_AddTail(List *pList,void * Data)
00178 {
00179 List * pNew;
00180 
00181         pNew = MemPool_GetHunk(ListPool_g);
00182         assert(pNew);
00183 
00184         pNew->Next = pList;
00185         pNew->Prev = pList->Prev;
00186         pNew->Next->Prev = pNew;
00187         pNew->Prev->Next = pNew;
00188         
00189         pNew->Data= Data;
00190 return pNew;
00191 }
00192 
00193 List *  LISTCALL List_AddHead(List *pList,void * Data)
00194 {
00195 List * pNew;
00196 
00197         pNew = MemPool_GetHunk(ListPool_g);
00198         assert(pNew);
00199         pNew->Data= Data;
00200 
00201         pNew->Prev = pList;
00202         pNew->Next = pList->Next;
00203         pNew->Next->Prev = pNew;
00204         pNew->Prev->Next = pNew;
00205 return pNew;
00206 }
00207 
00208 void *  LISTCALL List_CutHead(List *pList)
00209 {
00210 List * pNode;
00211 void * pData;
00212         pNode = pList->Next;
00213         if ( pNode == pList ) return NULL;
00214         pData = pNode->Data;
00215 
00216         pList->Next = pNode->Next;
00217         pList->Next->Prev = pList;
00218 
00219         MemPool_FreeHunk(ListPool_g,pNode);
00220 
00221 return pData;
00222 }
00223 
00224 void *  LISTCALL List_CutTail(List *pList)
00225 {
00226 List * pNode;
00227 void * pData;
00228         pNode = pList->Prev;
00229         if ( pNode == pList ) return NULL;
00230         pData = pNode->Data;
00231 
00232         pList->Prev = pNode->Prev;
00233         pList->Prev->Next = pList;
00234 
00235         MemPool_FreeHunk(ListPool_g,pNode);
00236 
00237 return pData;
00238 }
00239 
00240 
00241 void *  LISTCALL List_PeekHead(List *pList)
00242 {
00243 List * pNode;
00244         pNode = pList->Next;
00245         if ( pNode == pList ) return NULL;
00246 return pNode->Data;
00247 }
00248 
00249 void *  LISTCALL List_PeekTail(List *pList)
00250 {
00251 List * pNode;
00252         pNode = pList->Prev;
00253         if ( pNode == pList ) return NULL;
00254 return pNode->Data;
00255 }
00256 
00257 void    LISTCALL List_CutNode(List *pNode)
00258 {
00259         pNode->Prev->Next = pNode->Next;
00260         pNode->Next->Prev = pNode->Prev;
00261 
00262         pNode->Next = pNode->Prev = pNode;
00263 }
00264 
00265 void    LISTCALL List_DeleteNode(List *pNode)
00266 {
00267         List_CutNode(pNode);
00268         List_FreeNode(pNode);
00269 }
00270 
00271 void    LISTCALL List_FreeNode(List *pNode)
00272 {
00273         assert(pNode);
00274         MemPool_FreeHunk(ListPool_g,pNode);
00275 }
00276 
00277 void *  LISTCALL List_NodeData(List *pNode)
00278 {
00279         assert(pNode);
00280         return pNode->Data;
00281 }
00282 
00283 List *  LISTCALL List_Next(List *pNode)
00284 {
00285         return pNode->Next;
00286 }
00287 List *  LISTCALL List_Prev(List *pNode)
00288 {
00289         return pNode->Prev;
00290 }
00291 
00292 List *  List_Find(List *pList,void *Data)
00293 {
00294 List *pNode;
00295         assert(pList);
00296         for(pNode = pList->Next; pNode != pList; pNode = pNode->Next )
00297         {
00298                 if ( pNode->Data == Data )
00299                         return pNode;
00300         }
00301         return NULL;
00302 }
00303 
00304 /***********************************************************/
00305 // Stack by linked list
00306 
00307 struct Link
00308 {
00309         Link * Next;
00310         void * Data;
00311 };
00312 
00313 void    LISTCALL Link_Destroy(Link * pLink)
00314 {
00315         while( pLink )
00316         {
00317         Link *Next;
00318                 Next = pLink->Next;
00319                 MemPool_FreeHunk(LinkPool_g,pLink);
00320                 pLink = Next;
00321         }
00322 }
00323 
00324 Link *  LISTCALL Link_Create(void)
00325 {
00326 Link * pLink;
00327         pLink = MemPool_GetHunk(LinkPool_g);
00328         assert(pLink);
00329         pLink->Next = NULL;
00330         pLink->Data = NULL;
00331 return pLink;
00332 }
00333 
00334 void    LISTCALL Link_Push(Link *pLink,void * Data)
00335 {
00336 Link * pNode;
00337         assert(pLink);
00338         pNode = MemPool_GetHunk(LinkPool_g);
00339         assert(pNode);
00340 //      DebugWarn(geRam_IsValidPtr(pLink));
00341 //      DebugWarn(geRam_IsValidPtr(pNode));
00342         pNode->Data = Data;
00343 
00344         pNode->Next = pLink->Next;
00345         pLink->Next = pNode;
00346 }
00347 
00348 void *  LISTCALL Link_Pop(Link *pLink)
00349 {
00350 void *pData;
00351 Link * pNode;
00352         if ( ! pLink ) return NULL;
00353 //      DebugWarn(geRam_IsValidPtr(pLink));
00354         pNode = pLink->Next;
00355         if ( ! pNode ) return NULL;
00356 //      DebugWarn(geRam_IsValidPtr(pNode));
00357         pData = pNode->Data;
00358         pLink->Next = pNode->Next;
00359         MemPool_FreeHunk(LinkPool_g,pNode);
00360 return pData;
00361 }
00362 
00363 void *  LISTCALL Link_Peek(Link *pLink)
00364 {
00365 void *pData;
00366 Link * pNode;
00367         if ( ! pLink ) return NULL;
00368 //      DebugWarn(geRam_IsValidPtr(pLink));
00369         pNode = pLink->Next;
00370         if ( ! pNode ) return NULL;
00371 //      DebugWarn(geRam_IsValidPtr(pNode));
00372         pData = pNode->Data;
00373 return pData;
00374 }
00375 
00376 /*************************************************************/
00377 
00378 #ifdef _DEBUG   // else it's in list.h
00379 struct Stack
00380 {
00381         void ** Buffer, **End;
00382         void ** Head;
00383         int members;
00384 };
00385 #endif
00386 
00387 void    LISTCALL Stack_Destroy(Stack * pStack)
00388 {
00389         if ( pStack )
00390         {
00391                 destroy(pStack->Buffer);
00392                 destroy(pStack);
00393         }
00394 }
00395 
00396 Stack * LISTCALL Stack_Create(void)
00397 {
00398 Stack * pStack;
00399         pStack = new(Stack);
00400         assert(pStack);
00401         pStack->members = 4096;
00402         pStack->Buffer = MemAlloc(sizeof(void *)*(pStack->members));
00403         assert(pStack->Buffer);
00404         pStack->End = pStack->Buffer + (pStack->members);
00405         pStack->Head = pStack->Buffer;
00406 return pStack;
00407 }
00408 
00409 int     LISTCALL Stack_Extend(Stack *pStack)
00410 {
00411 void ** NewBuffer;
00412 int newmembers;
00413         // realloc
00414         newmembers = pStack->members + 4096;
00415         NewBuffer = MemAlloc(sizeof(void *)*newmembers);
00416         assert(NewBuffer);
00417         memcpy(NewBuffer,pStack->Buffer, sizeof(void *)*(pStack->members));
00418         pStack->Head = NewBuffer + pStack->members;
00419         pStack->members = newmembers;
00420         MemFree(pStack->Buffer);
00421         pStack->Buffer = NewBuffer;
00422 
00423         pStack->End = pStack->Buffer + (pStack->members);
00424 return newmembers;
00425 }
00426 
00427 void    LISTCALL Stack_Push_Func(Stack *pStack,void * Data)
00428 {
00429         assert(pStack);
00430         *(pStack->Head)++ = Data;
00431         if ( pStack->Head == pStack->End )
00432                 Stack_Extend(pStack);
00433 }
00434 
00435 void *  LISTCALL Stack_Pop_Func(Stack *pStack)
00436 {
00437         assert(pStack);
00438         if ( pStack->Head == pStack->Buffer )
00439                 return NULL;
00440         pStack->Head --;
00441 return *(pStack->Head);
00442 }
00443 
00444 /*************************************************************/
00445 
00446 struct RadixList
00447 {
00448         int NumLists;
00449         int Min,Max;
00450         List ** Lists;
00451 };
00452 
00453 RadixList * RadixList_Create(int RadixListMax)
00454 {
00455 RadixList * pRadixList;
00456 int r;
00457         pRadixList = new(RadixList);
00458         assert(pRadixList);
00459         pRadixList->NumLists = RadixListMax+1;
00460         pRadixList->Lists = MemAlloc(sizeof(List *)*(pRadixList->NumLists));
00461         assert(pRadixList->Lists);
00462         for(r=0;r<(pRadixList->NumLists);r++)
00463         {
00464                 pRadixList->Lists[r] = List_Create();
00465                 assert(pRadixList->Lists[r]);
00466         }
00467         pRadixList->Min = pRadixList->NumLists;
00468         pRadixList->Max = - 1;
00469 return pRadixList;
00470 }
00471 
00472 void RadixList_Destroy(RadixList * pRadixList)
00473 {
00474 int r;
00475         assert(pRadixList);
00476         for(r=0;r<(pRadixList->NumLists);r++)
00477         {
00478                 List_Destroy(pRadixList->Lists[r]);
00479         }
00480         MemFree(pRadixList->Lists);
00481         MemFree(pRadixList);
00482 }
00483 
00484 List * RadixList_Add(RadixList *pRadixList,void * Data,int Key)
00485 {
00486 List * l;
00487         assert(pRadixList);
00488         assert( Key < pRadixList->NumLists && Key >= 0 );
00489         l = List_AddTail(pRadixList->Lists[Key],Data);
00490         if ( Key < pRadixList->Min ) pRadixList->Min = Key;
00491         if ( Key > pRadixList->Max ) pRadixList->Max = Key;
00492 return l;
00493 }
00494 
00495 void * RadixList_CutMax(RadixList *pRadixList,int *pKey)
00496 {
00497         assert(pRadixList);
00498 
00499         while ( pRadixList->Max >= 0 )
00500         {
00501         void * Data;
00502 
00503                 if ( Data = List_CutHead(pRadixList->Lists[pRadixList->Max]) )
00504                 {
00505                         if ( pKey ) *pKey = pRadixList->Max;
00506                         return Data;    
00507                 }
00508                 pRadixList->Max --;
00509 
00510         }
00511 
00512 return NULL;
00513 }
00514 
00515 void * RadixList_CutMin(RadixList *pRadixList,int *pKey)
00516 {
00517         assert(pRadixList);
00518 
00519         while ( pRadixList->Min < pRadixList->NumLists )
00520         {
00521         void * Data;
00522 
00523                 if ( Data = List_CutHead(pRadixList->Lists[pRadixList->Min]) )
00524                 {
00525                         if ( pKey ) *pKey = pRadixList->Min;
00526                         return Data;    
00527                 }
00528                 pRadixList->Min ++;
00529 
00530         }
00531 
00532 return NULL;
00533 }
00534 
00535 void * RadixList_CutKey(RadixList *pRadixList,int Key)
00536 {
00537         assert(pRadixList);
00538 return List_CutHead(pRadixList->Lists[Key]);
00539 }
00540 
00541 /*************************************************/
00542 
00543 struct RadixLN
00544 {
00545         int NumLNs;
00546         int Min,Max;
00547         LinkNode * LNs;
00548 };
00549 
00550 RadixLN * RadixLN_Create(int RadixLNMax)
00551 {
00552 RadixLN * pRadixLN;
00553 LinkNode * LNs;
00554 int r;
00555         pRadixLN = new(RadixLN);
00556         assert(pRadixLN);
00557         pRadixLN->NumLNs = RadixLNMax+1;
00558         pRadixLN->LNs = MemAlloc(sizeof(LinkNode)*(pRadixLN->NumLNs));
00559         assert(pRadixLN->LNs);
00560 
00561 TIMER_P(List_RadixInit); // not counting the allocs, tracking in List_Ram
00562 
00563         LNs = pRadixLN->LNs;
00564         for(r=(pRadixLN->NumLNs);r--;LNs++)
00565         {
00566                 // LN_InitList( LNs );
00567                 LNs->Next = LNs->Prev = LNs;
00568         }
00569         pRadixLN->Min = RadixLNMax;
00570         pRadixLN->Max = 0;
00571         
00572 TIMER_Q(List_RadixInit);
00573 
00574 return pRadixLN;
00575 }
00576 
00577 void RadixLN_Destroy(RadixLN * pRadixLN)
00578 {
00579         assert(pRadixLN);
00580         MemFree(pRadixLN->LNs);
00581         MemFree(pRadixLN);
00582 }
00583 
00584 void RadixLN_AddHead(RadixLN *pRadixLN,LinkNode *LN,int Key)
00585 {
00586         assert(pRadixLN);
00587         assert( Key < pRadixLN->NumLNs && Key >= 0 );
00588         LN_AddHead(&(pRadixLN->LNs[Key]),LN);
00589         if ( Key < pRadixLN->Min ) pRadixLN->Min = Key;
00590         if ( Key > pRadixLN->Max ) pRadixLN->Max = Key;
00591 }
00592 
00593 void RadixLN_AddTail(RadixLN *pRadixLN,LinkNode *LN,int Key)
00594 {
00595         assert(pRadixLN);
00596         assert( Key < pRadixLN->NumLNs && Key >= 0 );
00597         LN_AddTail(&(pRadixLN->LNs[Key]),LN);
00598         if ( Key < pRadixLN->Min ) pRadixLN->Min = Key;
00599         if ( Key > pRadixLN->Max ) pRadixLN->Max = Key;
00600 }
00601 
00602 LinkNode * RadixLN_CutMax(RadixLN *pRadixLN,int *pKey)
00603 {
00604         assert(pRadixLN);
00605 
00606 TIMER_P(List_RadixWalk);
00607         while ( pRadixLN->Max >= 0 )
00608         {
00609         LinkNode * LN;
00610 
00611                 if ( LN = LN_CutHead(&(pRadixLN->LNs[pRadixLN->Max])) )
00612                 {
00613                         if ( pKey ) *pKey = pRadixLN->Max;
00614 TIMER_Q(List_RadixWalk);
00615                         return LN;
00616                 }
00617                 pRadixLN->Max --;
00618         }
00619 TIMER_Q(List_RadixWalk);
00620 
00621 return NULL;
00622 }
00623 
00624 LinkNode * RadixLN_CutMin(RadixLN *pRadixLN,int *pKey)
00625 {
00626         assert(pRadixLN);
00627 
00628 TIMER_P(List_RadixWalk);
00629         while ( pRadixLN->Min < pRadixLN->NumLNs )
00630         {
00631         LinkNode * LN;
00632 
00633                 if ( LN = LN_CutHead(&(pRadixLN->LNs[pRadixLN->Min])) )
00634                 {
00635                         if ( pKey ) *pKey = pRadixLN->Max;
00636 TIMER_Q(List_RadixWalk);
00637                         return LN;
00638                 }
00639                 pRadixLN->Min ++;
00640         }
00641 TIMER_Q(List_RadixWalk);
00642 
00643 return NULL;
00644 }
00645 
00646 LinkNode * RadixLN_CutKey(RadixLN *pRadixLN,int Key)
00647 {
00648         assert(pRadixLN);
00649 return LN_CutHead(&(pRadixLN->LNs[Key]));
00650 }
00651 
00652 
00653 LinkNode * RadixLN_PeekMax(RadixLN *pRadixLN,int *pKey)
00654 {
00655 LinkNode * LNs;
00656         assert(pRadixLN);
00657 
00658 TIMER_P(List_RadixWalk);
00659         LNs = & pRadixLN->LNs[pRadixLN->Max];
00660         while ( pRadixLN->Max >= 0 )
00661         {
00662         LinkNode * LN;
00663 
00664                 LN = LNs->Next;
00665                 if ( LN != LNs )
00666                 {
00667                         if ( pKey ) *pKey = pRadixLN->Max;
00668 TIMER_Q(List_RadixWalk);
00669                         return LN;
00670                 }
00671                 pRadixLN->Max --;
00672                 LNs --;
00673         }
00674 TIMER_Q(List_RadixWalk);
00675 
00676 return NULL;
00677 }
00678 
00679 LinkNode * RadixLN_PeekMin(RadixLN *pRadixLN,int *pKey)
00680 {
00681 LinkNode * LNlist;
00682         assert(pRadixLN);
00683 
00684 TIMER_P(List_RadixWalk);
00685         LNlist = & pRadixLN->LNs[pRadixLN->Min];
00686         while ( pRadixLN->Min < pRadixLN->NumLNs )
00687         {
00688         LinkNode * LN;
00689 
00690                 LN = LNlist->Next;
00691                 if ( LN != LNlist )
00692                 {
00693                         if ( pKey ) *pKey = pRadixLN->Min;
00694 TIMER_Q(List_RadixWalk);
00695                         return LN;
00696                 }
00697                 pRadixLN->Min ++;
00698                 LNlist ++;
00699         }
00700 TIMER_Q(List_RadixWalk);
00701 
00702 return NULL;
00703 }
00704 
00705 /*************************************************/
00706 
00707 struct RadixLink
00708 {
00709         int NumLinks;
00710         int Min,Max;
00711         Link * Links;
00712 };
00713 
00714 RadixLink * RadixLink_Create(int RadixLinkMax)
00715 {
00716 RadixLink * pRadixLink;
00717         pRadixLink = new(RadixLink);
00718         assert(pRadixLink);
00719         pRadixLink->NumLinks = RadixLinkMax+1;
00720         pRadixLink->Links = MemAlloc(sizeof(Link)*(pRadixLink->NumLinks));
00721         assert(pRadixLink->Links);
00722         //memset(pRadixLink->Links,0,(sizeof(Link)*(pRadixLink->NumLinks)));
00723         pRadixLink->Min = pRadixLink->NumLinks;
00724         pRadixLink->Max = - 1;
00725 return pRadixLink;
00726 }
00727 
00728 void RadixLink_Grow(RadixLink *pRadixLink,int NewMax)
00729 {
00730 Link * OldLinks;
00731 int OldNumLinks;
00732 
00733         OldNumLinks = pRadixLink->NumLinks;
00734         OldLinks = pRadixLink->Links;
00735 
00736         pRadixLink->NumLinks = NewMax + 1;
00737         pRadixLink->Links = MemAlloc(sizeof(Link)*(pRadixLink->NumLinks));
00738 
00739         assert(pRadixLink->Links);
00740 
00741         memcpy(pRadixLink->Links, OldLinks, (sizeof(Link)*OldNumLinks));
00742         //memset(pRadixLink->Links + OldNumLinks,0,(sizeof(Link)*(pRadixLink->NumLinks - OldNumLinks)));
00743 
00744         MemFree(OldLinks);
00745 }
00746 
00747 void RadixLink_Destroy(RadixLink * pRadixLink)
00748 {
00749 int r;
00750         assert(pRadixLink);
00751         for(r=0;r<(pRadixLink->NumLinks);r++)
00752         {
00753                 if ( pRadixLink->Links[r].Next )
00754                         Link_Destroy(pRadixLink->Links[r].Next);
00755         }
00756         MemFree(pRadixLink->Links);
00757         MemFree(pRadixLink);
00758 }
00759 
00760 void RadixLink_Add(RadixLink *pRadixLink,void * Data,int Key)
00761 {
00762         assert(pRadixLink);
00763         assert( Key >= 0 );
00764 
00765         if ( Key >= pRadixLink->NumLinks )
00766                 RadixLink_Grow(pRadixLink, Key + (Key>>2) );
00767 
00768         Link_Push(&(pRadixLink->Links[Key]),Data);
00769 
00770         if ( Key < pRadixLink->Min ) pRadixLink->Min = Key;
00771         if ( Key > pRadixLink->Max ) pRadixLink->Max = Key;
00772 }
00773 
00774 void * RadixLink_CutMax(RadixLink *pRadixLink,int *pKey)
00775 {
00776 Link * pLink;
00777         pLink = (pRadixLink->Links) + (pRadixLink->Max);
00778         while ( pRadixLink->Max >= 0 )
00779         {
00780                 if ( pLink->Next )
00781                 {
00782                         if ( pKey ) *pKey = pRadixLink->Max;
00783                         return Link_Pop(pLink);
00784                 }
00785                 pRadixLink->Max --;
00786                 pLink --;
00787         }
00788 return NULL;
00789 }
00790 
00791 void * RadixLink_CutMin(RadixLink *pRadixLink,int *pKey)
00792 {
00793 Link * pLink;
00794         pLink = (pRadixLink->Links) + (pRadixLink->Min);
00795         while ( pRadixLink->Min < pRadixLink->NumLinks )
00796         {
00797                 if ( pLink->Next )
00798                 {
00799                         if ( pKey ) *pKey = pRadixLink->Min;
00800                         return Link_Pop(pLink);
00801                 }
00802                 pRadixLink->Min ++;
00803                 pLink ++;
00804         }
00805 return NULL;
00806 }
00807 
00808 void * RadixLink_CutKey(RadixLink *pRadixLink,int Key)
00809 {
00810         assert(pRadixLink);
00811 return Link_Pop(&(pRadixLink->Links[Key]));
00812 }
00813 
00814 
00815 /***** debug only : **********************/
00816 
00817 void List_TimerReport(void)
00818 {
00819 #ifdef DO_TIMER
00820         TIMER_REPORT(List_Ram);
00821         TIMER_REPORT(List_RadixWalk);
00822         TIMER_REPORT(List_RadixInit);
00823 #endif
00824 }
00825 
00826 /*************************************************/
00827 
00828 /**************************************************
00829 
00830 Hash has separate Keys & Data
00831 
00832 We use a single Circular list of all the nodes.  We have
00833 cappers of Hash = 0 and HASH_SIZE at the head and tail.
00834 So a general hash looks like : (with HASH_SIZE == 7)
00835 
00836 
00837 (Head)-->A--x->C--x->E--x-->(Tail)
00838 [0]             [1][2][3][4][5][6]
00839 
00840 the brackets are hash buckets; little x's mean that hash bucket
00841 has seen no nodes of its own hash, so it points to the next
00842 larger hash's list.
00843 
00844 to do a Get :
00845         simply look at your current pointer and walk while hash == my hash
00846         example : Get(Hash == 3)
00847                 we get node C : ok, test it
00848                 next is node E : not my hash, so I'm done
00849 
00850 to do a delete :
00851         simply cut your node, and point yourself to the next node.
00852         example : Delete( Node C )
00853 
00854 (Head)-->A--x--x--x->E--x-->(Tail)
00855 [0]             [1][2][3][4][5][6]
00856 
00857                 now hash bucket 3 points to node E
00858 
00859 to do an add :
00860 
00861         first you must take your current pointer and walk backwards until
00862         the preceding node has a lower hash than you (see example later).
00863 
00864         then simply add the new node before the current one and make yourself
00865         point to the new one.
00866 
00867         Example 1: Add an A:
00868                 bucket 1 already is in the right place
00869                 add before the old node :
00870 
00871        +-A1
00872        | |
00873 (Head)-+ A2-x--x--x->E--x-->(Tail)
00874 [0]             [1][2][3][4][5][6]
00875 
00876                 now make the hash point to the new add:
00877 
00878          A2-+
00879          |  |
00880 (Head)---A1 x--x--x->E--x-->(Tail)
00881 [0]             [1][2][3][4][5][6]
00882 
00883         Example 2 : we need the extra seek in each _Add()
00884                 add a node C at hash 3
00885 
00886 
00887          A--+--+
00888          |     |
00889 (Head)---A (E) C--x->E--x-->(Tail)
00890 [0]             [1][2][3][4][5][6]
00891 
00892                 the funny notation is to indicate that bucket 2 still
00893                 points to node E.
00894 
00895                 now add a node B at hash 2
00896                 we currently point to node (E)
00897                 the previous node is (C), which is greater than B, so
00898                 we step back; now the current is (C) and the previous is (A) :
00899 
00900          A--+
00901          |  |   
00902 (Head)---A  +->C--x->E--x-->(Tail)
00903 [0]             [1][2][3][4][5][6]
00904 
00905                 which is a good list, so we do the normal add:
00906 
00907          A--+
00908          |  |   
00909 (Head)---A  B->C--x->E--x-->(Tail)
00910 [0]             [1][2][3][4][5][6]
00911 
00912 **************
00913 
00914 the whole goal of this system is that the WalkNext() function is
00915 blazing fast.  The only thing that hurts in the _Add function, but
00916 the cost of adding N nodes to hash of size M is only O(N + M*M)
00917 (because the first M adds are O(M) and the later adds are O(1))
00918 
00919 *****************************/
00920 
00921 #ifdef SAFE_HASH_DEBUG //{
00922 
00923 #pragma message("using safe debug hash implementation")
00924 
00925 struct Hash
00926 {
00927         HashNode ** NodeArray;
00928         int                     NodeArrayLen;
00929         int                     NodeCount;
00930 };
00931 
00932 
00933 struct HashNode
00934 {
00935         uint32  Key;
00936         uint32  Data;
00937 };
00938 
00939 Hash *  Hash_Create(void)
00940 {
00941 Hash * H;
00942         H = new(Hash);
00943         assert(H);
00944         //memset(H,0,sizeof(*H));
00945 return H;
00946 }
00947 
00948 void Hash_Destroy(Hash *H)
00949 {
00950         assert(H);
00951         if ( H->NodeArray )
00952         {
00953         int n;
00954                 for(n=0;n<H->NodeCount;n++)
00955                 {
00956                         MemPool_FreeHunk(HashNodePool_g,H->NodeArray[n]);
00957                 }
00958                 destroy(H->NodeArray);
00959         }
00960 
00961         destroy(H);
00962 }       
00963 
00964 HashNode *      LISTCALL Hash_Add(Hash *H,uint32 Key,uint32 Data)
00965 {
00966 HashNode * hn;
00967         hn = MemPool_GetHunk(HashNodePool_g);
00968         assert(hn);
00969         hn->Key = Key;
00970         hn->Data = Data;
00971 
00972         if ( H->NodeCount == H->NodeArrayLen )
00973         {
00974                 H->NodeArrayLen = H->NodeCount + 100;
00975                 if ( H->NodeArray )
00976                 {
00977                         H->NodeArray = geRam_Realloc(H->NodeArray,H->NodeArrayLen*sizeof(HashNode *));
00978                 }
00979                 else
00980                 {
00981                         H->NodeArray = geRam_Allocate(H->NodeArrayLen*sizeof(HashNode *));
00982                 }
00983                 assert(H->NodeArray);
00984         }
00985 
00986         H->NodeArray[H->NodeCount] = hn;
00987         H->NodeCount ++;
00988 
00989 return hn;
00990 }
00991 
00992 void            LISTCALL Hash_DeleteNode(Hash *pHash,HashNode *pNode)
00993 {
00994 int n;
00995 
00996         n = 0;
00997         while( pHash->NodeArray[n] != pNode )
00998         {
00999                 n++;
01000                 assert( n < pHash->NodeCount );
01001         }
01002 
01003         pHash->NodeArray[n] = pHash->NodeArray[ pHash->NodeCount - 1];
01004         assert(pHash->NodeArray[n]);
01005         pHash->NodeArray[ pHash->NodeCount - 1] = NULL;
01006         pHash->NodeCount --;
01007 
01008         MemPool_FreeHunk(HashNodePool_g,pNode);
01009 }
01010 
01011 HashNode *      LISTCALL Hash_Get(Hash *pHash,uint32 Key,uint32 *pData)
01012 {
01013 int n;
01014         for(n=0;n<pHash->NodeCount;n++)
01015         {
01016                 if ( pHash->NodeArray[n]->Key == Key )
01017                 {
01018                         if ( pData )
01019                                 *pData = pHash->NodeArray[n]->Data;
01020                         return pHash->NodeArray[n];
01021                 }
01022         }
01023         return NULL;
01024 }
01025 
01026 HashNode *      LISTCALL Hash_WalkNext(Hash *pHash,HashNode *pCur)
01027 {
01028 int n;
01029 
01030         if ( pCur )
01031         {
01032                 n = 0;
01033                 while( pHash->NodeArray[n] != pCur )
01034                 {
01035                         n++;
01036                         assert( n < pHash->NodeCount );
01037                 }
01038                 n ++;
01039         }
01040         else
01041         {
01042                 n = 0;
01043         }
01044         if ( n == pHash->NodeCount )
01045                 return NULL;
01046         else
01047                 return pHash->NodeArray[n];
01048 }
01049 
01050 uint32          LISTCALL Hash_NumMembers(Hash *pHash)
01051 {
01052         return pHash->NodeCount;
01053 }
01054 
01055 
01056 #else //}{ the real thing
01057 
01058 #define HASH_MOD        (1009) // or 1013  , a nice prime
01059 #define HASH_SIZE       (HASH_MOD + 1) 
01060 #define HASH(Key)       ((( ((Key)>>15) ^ (Key) )%HASH_MOD)+1)
01061 
01062 struct Hash
01063 {
01064 
01065         Debug(Hash * MySelf1)
01066 
01067         HashNode *      HashTable[HASH_SIZE];
01068         HashNode *      NodeList;
01069 
01070         Debug(int       Members)
01071         Debug(Hash * MySelf2)
01072 };
01073 
01074 struct HashNode
01075 {
01076         LinkNode LN;
01077         uint32  Key;
01078         uint32  Data;
01079         uint32  Hash;
01080 };
01081 
01082 Hash * Hash_Create(void)
01083 {
01084 Hash * pHash;
01085 HashNode *pHead,*pTail;
01086 
01087         pHash = new(Hash);
01088         if ( ! pHash ) 
01089                 return NULL;
01090         
01091         //memset(pHash,0,sizeof(Hash));
01092 
01093         Debug( pHash->MySelf1 = pHash )
01094         Debug( pHash->MySelf2 = pHash )
01095 
01096         pTail = MemPool_GetHunk(HashNodePool_g);
01097         assert(pTail);
01098         LN_Null(pTail);
01099         pTail->Key = pTail->Data = 0;
01100         pTail->Hash = HASH_SIZE;
01101 
01102         pHead = MemPool_GetHunk(HashNodePool_g);
01103         assert(pHead);
01104         LN_Null(pHead);
01105         pHead->Key = pHead->Data = 0;
01106         pHead->Hash = 0;
01107 
01108         LN_AddBefore(pHead,pTail);
01109 
01110         pHash->NodeList = pHead;
01111 
01112         Debug(pHash->Members = 0)
01113 
01114 return pHash;
01115 }
01116 
01117 void Hash_Destroy(Hash *pHash)
01118 {
01119         if ( pHash )
01120         {
01121         HashNode *pList,*pNode,*pNext;
01122         
01123                 assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash );
01124 
01125                 Debug(pHash->Members += 2) // count Head & Tail
01126 
01127                 pList = pHash->NodeList;
01128                 LN_Walk_Editting(pNode,pList,pNext) {
01129                         MemPool_FreeHunk(HashNodePool_g,pNode);
01130                         assert(pHash->Members > 1);
01131                         Debug(pHash->Members --)
01132                 }
01133                 assert(pHash->Members == 1);
01134                 MemPool_FreeHunk(HashNodePool_g,pList);
01135                 destroy(pHash);
01136         }
01137 }
01138 
01139 #ifdef _DEBUG
01140 int Hash_ListLen(Hash *pHash,uint32 H)
01141 {
01142 HashNode *hn;
01143 int Len = 0;
01144         hn = pHash->HashTable[H];
01145         if ( ! hn )
01146                 return 0;
01147         while( hn->Hash == H )
01148         {
01149                 Len ++;
01150                 assert(pHash->Members >= Len);
01151                 hn = LN_Next(hn);
01152         }
01153 return Len;
01154 }
01155 #endif
01156 
01157 HashNode * LISTCALL Hash_Add(Hash *pHash,uint32 Key,uint32 Data)
01158 {
01159 uint32 H;
01160 HashNode *hn,**pTable,*Node,*Prev;
01161 Debug( int ListLen1; int ListLen2; int HashLen1; int HashLen2; int WalkLen)
01162 
01163         assert(pHash);
01164         assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash );
01165 
01166         hn = MemPool_GetHunk(HashNodePool_g);
01167         assert(hn);
01168         Debug( LN_Null(hn) )
01169 
01170         hn->Key = Key;
01171         hn->Data = Data;
01172         hn->Hash = H = HASH(Key);
01173 
01174         pTable = &(pHash->HashTable[H]);
01175         Node = *pTable;
01176 
01177         assert( H > 0 );
01178         assert( pHash->NodeList->Hash == 0 );
01179         assert( ((HashNode *)LN_Prev(pHash->NodeList))->Hash == HASH_SIZE );
01180 
01181         Debug(HashLen1 = Hash_NumMembers(pHash))
01182         Debug(ListLen1 = Hash_ListLen(pHash,H))
01183 
01184         if ( ! Node )
01185         {
01186                 Prev = pHash->NodeList;
01187                 Node = LN_Next(Prev);
01188 
01189                 Debug(WalkLen = 0)
01190 
01191                 assert(Prev->Hash < H);
01192                 while( Node->Hash < H )
01193                 {
01194                         Prev = Node;
01195                         Node = LN_Next(Prev);
01196                 
01197                         assert(WalkLen < pHash->Members );
01198                         Debug( WalkLen ++)
01199                         
01200                         assert(Prev->Hash <= Node->Hash);
01201                         assert(Prev->Hash < HASH_SIZE );
01202                 }
01203 
01204                 assert(Prev->Hash < H);
01205                 assert(Node->Hash >= H);
01206         }
01207 
01208         LN_AddBefore(hn,Node);
01209         *pTable = hn;
01210 
01211         Debug(pHash->Members ++)
01212 
01213         Debug(ListLen2 = Hash_ListLen(pHash,H))
01214         assert( ListLen2 == (ListLen1 + 1) );
01215         Debug(HashLen2 = Hash_NumMembers(pHash))
01216         assert( HashLen2 == (HashLen1 + 1) );
01217 
01218 return hn;
01219 }
01220 
01221 void LISTCALL Hash_DeleteNode(Hash *pHash,HashNode *pNode)
01222 {
01223 HashNode ** pHead;
01224 uint32 H;
01225 Debug( int ListLen1; int ListLen2;int HashLen1; int HashLen2)
01226 
01227         assert(pNode );
01228         assert( pHash );
01229         assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash );
01230 
01231         assert( pNode->Hash > 0 && pNode->Hash < HASH_SIZE );
01232 
01233         H = pNode->Hash;
01234         pHead = & ( pHash->HashTable[H] );
01235 
01236         Debug( HashLen1 = Hash_NumMembers(pHash) )
01237         Debug( ListLen1 = Hash_ListLen(pHash,H) )
01238         assert(pHash->Members > 0);
01239         Debug(pHash->Members --)
01240 
01241         if ( *pHead == pNode )
01242         {
01243                 *pHead = LN_Next(pNode);
01244                 if ( (*pHead)->Hash != H )
01245                 {
01246                         // pNode was the head of the list
01247                         assert( ((HashNode *)LN_Prev(pNode))->Hash < H );
01248                         *pHead = NULL;
01249                 }
01250         }
01251         assert( *pHead == NULL || (*pHead)->Hash == H );
01252 
01253         LN_Cut(pNode);
01254 
01255         MemPool_FreeHunk(HashNodePool_g,pNode);
01256         
01257         Debug( HashLen2 = Hash_NumMembers(pHash) )
01258         Debug( ListLen2 = Hash_ListLen(pHash,H) )
01259         assert( HashLen2 == (HashLen1 - 1) );
01260 
01261 }
01262 
01263 HashNode * LISTCALL Hash_Get(Hash *pHash,uint32 Key,uint32 *pData)
01264 {
01265 uint32 H;
01266 HashNode *pNode;
01267 
01268         assert(pHash );
01269         assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash );
01270 
01271         H = HASH(Key);
01272         assert( H > 0 && H < HASH_SIZE );
01273 
01274         pNode = pHash->HashTable[H];
01275         if ( ! pNode )
01276                 return NULL;
01277 
01278         assert( pNode->Hash == H );
01279 
01280         while( pNode->Hash == H )
01281         {
01282                 if ( pNode->Key == Key )
01283                 {
01284                         if ( pData )
01285                                 *pData = pNode->Data;
01286                         return pNode;
01287                 }
01288                 pNode = LN_Next(pNode);
01289         }
01290 
01291 return NULL;
01292 }
01293 
01294 HashNode * LISTCALL Hash_WalkNext(Hash *pHash,HashNode *pNode)
01295 {
01296 HashNode *pNext;
01297 
01298         assert(pHash);
01299         assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash );
01300 
01301         if ( ! pNode )
01302         {
01303                 pNode = pHash->NodeList;
01304                 assert( pNode->Hash == 0 );
01305         }
01306 
01307         pNext = LN_Next(pNode);
01308         assert( pNext->Hash > 0 );
01309         assert( pNext->Hash >= pNode->Hash );
01310 
01311         assert( pNext != pNode );
01312         assert( LN_Prev(pNext) == pNode );
01313 
01314         if ( pNext->Hash == HASH_SIZE )
01315         {
01316                 assert( ((HashNode *)LN_Next(pNext)) == pHash->NodeList );
01317                 return NULL;
01318         }
01319 
01320         assert(pNext->Hash < HASH_SIZE);
01321 
01322 return pNext;
01323 }
01324 
01325 uint32          LISTCALL Hash_NumMembers(Hash *pHash)
01326 {
01327 uint32 N;
01328 HashNode *pNode;
01329 
01330         assert(pHash);
01331         assert( pHash->MySelf1 == pHash && pHash->MySelf2 == pHash );
01332 
01333         pNode = pHash->NodeList;
01334         assert( pNode->Hash == 0 );
01335         pNode = LN_Next(pNode);
01336         assert( pNode->Hash > 0 );
01337 
01338         N = 0;
01339         while( pNode->Hash < HASH_SIZE )
01340         {
01341                 assert( N < (uint32)pHash->Members );
01342                 pNode = LN_Next(pNode);
01343                 N ++;
01344         }
01345 
01346         assert( N == (uint32)pHash->Members );
01347 
01348 return N;
01349 }
01350 
01351 #endif //}{ hashes
01352 
01353 uint32  Hash_StringToKey(const char * String)
01354 {
01355 return CRC32_Array(String,strlen(String));
01356 }
01357 
01358 void    HashNode_SetData(HashNode *pNode,uint32 Data)
01359 {
01360         assert(pNode);
01361         pNode->Data = Data;
01362 }
01363 
01364 void    HashNode_GetData(HashNode *pNode,uint32 *pKey,uint32 *pData)
01365 {
01366         assert(pNode);
01367         *pKey   = pNode->Key;
01368         *pData  = pNode->Data;
01369 }
01370 
01371 uint32  HashNode_Data(HashNode *pNode)
01372 {
01373         assert(pNode);
01374 return pNode->Data;
01375 }
01376 
01377 uint32  HashNode_Key(HashNode *pNode)
01378 {
01379         assert(pNode);
01380 return pNode->Key;
01381 }
01382 
01383 /***************************/
01384 
01385 geBoolean List_Start(void)
01386 {
01387         assert(UsageCount >= 0 );
01388         if ( UsageCount == 0 )
01389         {
01390                 assert(ListPool_g == NULL && LinkPool_g == NULL);
01391                 if ( ! (ListPool_g = MemPool_Create(sizeof(List),1024,1024) ) )
01392                         return GE_FALSE;
01393                 if ( ! (LinkPool_g = MemPool_Create(sizeof(Link),128,128) ) )
01394                         return GE_FALSE;
01395                 if ( ! (HashNodePool_g = MemPool_Create(sizeof(HashNode),128,128) ) )
01396                         return GE_FALSE;
01397                 // could latch ListFuncs_Stop() on atexit() , but no need, really..
01398         }
01399         UsageCount ++;
01400         return GE_TRUE;
01401 }
01402 
01403 geBoolean List_Stop(void)
01404 {
01405         assert(UsageCount > 0 );
01406         UsageCount --;
01407         if ( UsageCount == 0 )
01408         {
01409                 assert(ListPool_g && LinkPool_g );
01410                 MemPool_Destroy(&ListPool_g); ListPool_g = NULL;
01411                 MemPool_Destroy(&LinkPool_g); LinkPool_g = NULL;
01412                 MemPool_Destroy(&HashNodePool_g); HashNodePool_g = NULL;
01413         }
01414         return GE_TRUE;
01415 }

Generated on Tue Sep 30 12:35:58 2003 for GTestAndEngine by doxygen 1.3.2