Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengenerictable.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Runtime Library 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: lib/rtl/generictable.c 00005 * PURPOSE: Splay Tree Generic Table Implementation 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <rtl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* Internal header for table entries */ 00016 typedef struct _TABLE_ENTRY_HEADER 00017 { 00018 RTL_SPLAY_LINKS SplayLinks; 00019 LIST_ENTRY ListEntry; 00020 LONGLONG UserData; 00021 } TABLE_ENTRY_HEADER, *PTABLE_ENTRY_HEADER; 00022 00023 /* PRIVATE FUNCTIONS *********************************************************/ 00024 00025 TABLE_SEARCH_RESULT 00026 NTAPI 00027 RtlpFindGenericTableNodeOrParent(IN PRTL_GENERIC_TABLE Table, 00028 IN PVOID Buffer, 00029 OUT PRTL_SPLAY_LINKS *NodeOrParent) 00030 { 00031 PRTL_SPLAY_LINKS CurrentNode, ChildNode; 00032 RTL_GENERIC_COMPARE_RESULTS Result; 00033 00034 /* Quick check to see if the table is empty */ 00035 if (RtlIsGenericTableEmpty(Table)) 00036 { 00037 *NodeOrParent = NULL; 00038 return TableEmptyTree; 00039 } 00040 00041 /* Set the current node */ 00042 CurrentNode = Table->TableRoot; 00043 00044 /* Start compare loop */ 00045 while (TRUE) 00046 { 00047 /* Do the compare */ 00048 Result = Table->CompareRoutine(Table, 00049 Buffer, 00050 &((PTABLE_ENTRY_HEADER)CurrentNode)-> 00051 UserData); 00052 if (Result == GenericLessThan) 00053 { 00054 /* We're less, check if this is the left child */ 00055 if ((ChildNode = RtlLeftChild(CurrentNode))) 00056 { 00057 /* Continue searching from this node */ 00058 CurrentNode = ChildNode; 00059 } 00060 else 00061 { 00062 /* Otherwise, the element isn't in this tree */ 00063 *NodeOrParent = CurrentNode; 00064 return TableInsertAsLeft; 00065 } 00066 } 00067 else if (Result == GenericGreaterThan) 00068 { 00069 /* We're more, check if this is the right child */ 00070 if ((ChildNode = RtlRightChild(CurrentNode))) 00071 { 00072 /* Continue searching from this node */ 00073 CurrentNode = ChildNode; 00074 } 00075 else 00076 { 00077 /* Otherwise, the element isn't in this tree */ 00078 *NodeOrParent = CurrentNode; 00079 return TableInsertAsRight; 00080 } 00081 } 00082 else 00083 { 00084 /* We should've found the node */ 00085 ASSERT(Result == GenericEqual); 00086 00087 /* Return node found */ 00088 *NodeOrParent = CurrentNode; 00089 return TableFoundNode; 00090 } 00091 } 00092 } 00093 00094 /* SPLAY FUNCTIONS ***********************************************************/ 00095 00096 /* 00097 * @implemented 00098 */ 00099 VOID 00100 NTAPI 00101 RtlInitializeGenericTable(IN PRTL_GENERIC_TABLE Table, 00102 IN PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine, 00103 IN PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine, 00104 IN PRTL_GENERIC_FREE_ROUTINE FreeRoutine, 00105 IN PVOID TableContext) 00106 { 00107 /* Initialize the table to default and passed values */ 00108 InitializeListHead(&Table->InsertOrderList); 00109 Table->TableRoot = NULL; 00110 Table->NumberGenericTableElements = 0; 00111 Table->WhichOrderedElement = 0; 00112 Table->OrderedPointer = &Table->InsertOrderList; 00113 Table->CompareRoutine = CompareRoutine; 00114 Table->AllocateRoutine = AllocateRoutine; 00115 Table->FreeRoutine = FreeRoutine; 00116 Table->TableContext = TableContext; 00117 } 00118 00119 /* 00120 * @implemented 00121 */ 00122 PVOID 00123 NTAPI 00124 RtlInsertElementGenericTable(IN PRTL_GENERIC_TABLE Table, 00125 IN PVOID Buffer, 00126 IN ULONG BufferSize, 00127 OUT PBOOLEAN NewElement OPTIONAL) 00128 { 00129 PRTL_SPLAY_LINKS NodeOrParent; 00130 TABLE_SEARCH_RESULT Result; 00131 00132 /* Get the splay links and table search result immediately */ 00133 Result = RtlpFindGenericTableNodeOrParent(Table, Buffer, &NodeOrParent); 00134 00135 /* Now call the routine to do the full insert */ 00136 return RtlInsertElementGenericTableFull(Table, 00137 Buffer, 00138 BufferSize, 00139 NewElement, 00140 NodeOrParent, 00141 Result); 00142 } 00143 00144 /* 00145 * @implemented 00146 */ 00147 PVOID 00148 NTAPI 00149 RtlInsertElementGenericTableFull(IN PRTL_GENERIC_TABLE Table, 00150 IN PVOID Buffer, 00151 IN ULONG BufferSize, 00152 OUT PBOOLEAN NewElement OPTIONAL, 00153 IN PVOID NodeOrParent, 00154 IN TABLE_SEARCH_RESULT SearchResult) 00155 { 00156 PRTL_SPLAY_LINKS NewNode; 00157 00158 /* Check if the entry wasn't already found */ 00159 if (SearchResult != TableFoundNode) 00160 { 00161 /* We're doing an allocation, sanity check */ 00162 ASSERT(Table->NumberGenericTableElements != (MAXULONG - 1)); 00163 00164 /* Allocate a node */ 00165 NewNode = Table->AllocateRoutine(Table, 00166 BufferSize + 00167 FIELD_OFFSET(TABLE_ENTRY_HEADER, 00168 UserData)); 00169 if (!NewNode) 00170 { 00171 /* No memory or other allocation error, fail */ 00172 if (NewElement) *NewElement = FALSE; 00173 return NULL; 00174 } 00175 00176 /* Initialize the new inserted element */ 00177 RtlInitializeSplayLinks(NewNode); 00178 InsertTailList(&Table->InsertOrderList, 00179 &((PTABLE_ENTRY_HEADER)NewNode)->ListEntry); 00180 00181 /* Increase element count */ 00182 Table->NumberGenericTableElements++; 00183 00184 /* Check where we should insert the entry */ 00185 if (SearchResult == TableEmptyTree) 00186 { 00187 /* This is the new root node */ 00188 Table->TableRoot = NewNode; 00189 } 00190 else if (SearchResult == TableInsertAsLeft) 00191 { 00192 /* Insert it left */ 00193 RtlInsertAsLeftChild(NodeOrParent, NewNode); 00194 } 00195 else 00196 { 00197 /* Right node */ 00198 RtlInsertAsRightChild(NodeOrParent, NewNode); 00199 } 00200 00201 /* Copy user buffer */ 00202 RtlCopyMemory(&((PTABLE_ENTRY_HEADER)NewNode)->UserData, 00203 Buffer, 00204 BufferSize); 00205 } 00206 else 00207 { 00208 /* Return the node we already found */ 00209 NewNode = NodeOrParent; 00210 } 00211 00212 /* Splay the tree */ 00213 Table->TableRoot = RtlSplay(NewNode); 00214 00215 /* Return status */ 00216 if (NewElement) *NewElement = (SearchResult != TableFoundNode); 00217 00218 /* Return pointer to user data */ 00219 return &((PTABLE_ENTRY_HEADER)NewNode)->UserData; 00220 } 00221 00222 /* 00223 * @implemented 00224 */ 00225 BOOLEAN 00226 NTAPI 00227 RtlIsGenericTableEmpty(IN PRTL_GENERIC_TABLE Table) 00228 { 00229 /* Check if the table root is empty */ 00230 return (Table->TableRoot) ? FALSE: TRUE; 00231 } 00232 00233 /* 00234 * @implemented 00235 */ 00236 ULONG 00237 NTAPI 00238 RtlNumberGenericTableElements(IN PRTL_GENERIC_TABLE Table) 00239 { 00240 /* Return the number of elements */ 00241 return Table->NumberGenericTableElements; 00242 } 00243 00244 /* 00245 * @implemented 00246 */ 00247 PVOID 00248 NTAPI 00249 RtlLookupElementGenericTable(IN PRTL_GENERIC_TABLE Table, 00250 IN PVOID Buffer) 00251 { 00252 PRTL_SPLAY_LINKS NodeOrParent; 00253 TABLE_SEARCH_RESULT Result; 00254 00255 /* Call the full version */ 00256 return RtlLookupElementGenericTableFull(Table, 00257 Buffer, 00258 (PVOID)&NodeOrParent, 00259 &Result); 00260 } 00261 00262 /* 00263 * @implemented 00264 */ 00265 PVOID 00266 NTAPI 00267 RtlLookupElementGenericTableFull(IN PRTL_GENERIC_TABLE Table, 00268 IN PVOID Buffer, 00269 OUT PVOID *NodeOrParent, 00270 OUT TABLE_SEARCH_RESULT *SearchResult) 00271 { 00272 /* Do the initial lookup */ 00273 *SearchResult = RtlpFindGenericTableNodeOrParent(Table, 00274 Buffer, 00275 (PRTL_SPLAY_LINKS *) 00276 NodeOrParent); 00277 00278 /* Check if we found anything */ 00279 if ((*SearchResult == TableEmptyTree) || (*SearchResult != TableFoundNode)) 00280 { 00281 /* Nothing found */ 00282 return NULL; 00283 } 00284 00285 /* Otherwise, splay the tree and return this entry */ 00286 Table->TableRoot = RtlSplay(*NodeOrParent); 00287 return &((PTABLE_ENTRY_HEADER)*NodeOrParent)->UserData; 00288 } 00289 00290 /* 00291 * @implemented 00292 */ 00293 BOOLEAN 00294 NTAPI 00295 RtlDeleteElementGenericTable(IN PRTL_GENERIC_TABLE Table, 00296 IN PVOID Buffer) 00297 { 00298 PRTL_SPLAY_LINKS NodeOrParent; 00299 TABLE_SEARCH_RESULT Result; 00300 00301 /* Get the splay links and table search result immediately */ 00302 Result = RtlpFindGenericTableNodeOrParent(Table, Buffer, &NodeOrParent); 00303 if (Result != TableFoundNode) 00304 { 00305 /* Nothing to delete */ 00306 return FALSE; 00307 } 00308 00309 /* Delete the entry */ 00310 Table->TableRoot = RtlDelete(NodeOrParent); 00311 RemoveEntryList(&((PTABLE_ENTRY_HEADER)NodeOrParent)->ListEntry); 00312 00313 /* Update accounting data */ 00314 Table->NumberGenericTableElements--; 00315 Table->WhichOrderedElement = 0; 00316 Table->OrderedPointer = &Table->InsertOrderList; 00317 00318 /* Free the entry */ 00319 Table->FreeRoutine(Table, NodeOrParent); 00320 return TRUE; 00321 } 00322 00323 /* 00324 * @implemented 00325 */ 00326 PVOID 00327 NTAPI 00328 RtlEnumerateGenericTable(IN PRTL_GENERIC_TABLE Table, 00329 IN BOOLEAN Restart) 00330 { 00331 PRTL_SPLAY_LINKS FoundNode; 00332 00333 /* Check if the table is empty */ 00334 if (RtlIsGenericTableEmpty(Table)) return NULL; 00335 00336 /* Check if we have to restart */ 00337 if (Restart) 00338 { 00339 /* Then find the leftmost element */ 00340 FoundNode = Table->TableRoot; 00341 do 00342 { 00343 /* Get the left child */ 00344 FoundNode = RtlLeftChild(FoundNode); 00345 } while(RtlLeftChild(FoundNode)); 00346 00347 /* Splay it */ 00348 Table->TableRoot = RtlSplay(FoundNode); 00349 } 00350 else 00351 { 00352 /* Otherwise, try using the real successor */ 00353 FoundNode = RtlRealSuccessor(Table->TableRoot); 00354 if (FoundNode) Table->TableRoot = RtlSplay(FoundNode); 00355 } 00356 00357 /* Check if we found the node and return it */ 00358 return FoundNode ? &((PTABLE_ENTRY_HEADER)FoundNode)->UserData : NULL; 00359 } 00360 00361 /* 00362 * @implemented 00363 */ 00364 PVOID 00365 NTAPI 00366 RtlEnumerateGenericTableWithoutSplaying(IN PRTL_GENERIC_TABLE Table, 00367 IN OUT PVOID *RestartKey) 00368 { 00369 PRTL_SPLAY_LINKS FoundNode; 00370 00371 /* Check if the table is empty */ 00372 if (RtlIsGenericTableEmpty(Table)) return NULL; 00373 00374 /* Check if we have to restart */ 00375 if (!(*RestartKey)) 00376 { 00377 /* Then find the leftmost element */ 00378 FoundNode = Table->TableRoot; 00379 do 00380 { 00381 /* Get the left child */ 00382 FoundNode = RtlLeftChild(FoundNode); 00383 } while(RtlLeftChild(FoundNode)); 00384 00385 /* Splay it */ 00386 *RestartKey = FoundNode; 00387 } 00388 else 00389 { 00390 /* Otherwise, try using the real successor */ 00391 FoundNode = RtlRealSuccessor(*RestartKey); 00392 if (FoundNode) *RestartKey = FoundNode; 00393 } 00394 00395 /* Check if we found the node and return it */ 00396 return FoundNode ? &((PTABLE_ENTRY_HEADER)FoundNode)->UserData : NULL; 00397 } 00398 00399 /* 00400 * @unimplemented 00401 */ 00402 PVOID 00403 NTAPI 00404 RtlEnumerateGenericTableLikeADirectory(IN PRTL_AVL_TABLE Table, 00405 IN PRTL_AVL_MATCH_FUNCTION MatchFunction, 00406 IN PVOID MatchData, 00407 IN ULONG NextFlag, 00408 IN OUT PVOID *RestartKey, 00409 IN OUT PULONG DeleteCount, 00410 IN OUT PVOID Buffer) 00411 { 00412 UNIMPLEMENTED; 00413 return 0; 00414 } 00415 00416 /* 00417 * @implemented 00418 */ 00419 PVOID 00420 NTAPI 00421 RtlGetElementGenericTable(IN PRTL_GENERIC_TABLE Table, 00422 IN ULONG I) 00423 { 00424 ULONG OrderedElement, ElementCount; 00425 PLIST_ENTRY OrderedNode; 00426 ULONG DeltaUp, DeltaDown; 00427 ULONG NextI = I + 1; 00428 00429 /* Setup current accounting data */ 00430 OrderedNode = Table->OrderedPointer; 00431 OrderedElement = Table->WhichOrderedElement; 00432 ElementCount = Table->NumberGenericTableElements; 00433 00434 /* Sanity checks */ 00435 if ((I == MAXULONG) || (NextI > ElementCount)) return NULL; 00436 00437 /* Check if we already found the entry */ 00438 if (NextI == OrderedElement) 00439 { 00440 /* Return it */ 00441 return &((PTABLE_ENTRY_HEADER)CONTAINING_RECORD(OrderedNode, 00442 TABLE_ENTRY_HEADER, 00443 ListEntry))->UserData; 00444 } 00445 00446 /* Now check if we're farther behind */ 00447 if (OrderedElement > NextI) 00448 { 00449 /* Find out if the distance is more then the half-way point */ 00450 if (NextI > (OrderedElement / 2)) 00451 { 00452 /* Do the search backwards, since this takes less iterations */ 00453 DeltaDown = OrderedElement - NextI; 00454 do 00455 { 00456 /* Get next node */ 00457 OrderedNode = OrderedNode->Blink; 00458 } while (--DeltaDown); 00459 } 00460 else 00461 { 00462 /* Follow the list directly instead */ 00463 OrderedNode = &Table->InsertOrderList; 00464 do 00465 { 00466 /* Get next node */ 00467 OrderedNode = OrderedNode->Flink; 00468 } while (--NextI); 00469 } 00470 } 00471 else 00472 { 00473 /* We are farther ahead, calculate distances */ 00474 DeltaUp = NextI - OrderedElement; 00475 DeltaDown = (ElementCount - NextI) + 1; 00476 00477 /* Check if the up distance is smaller then the down distance */ 00478 if (DeltaUp <= DeltaDown) 00479 { 00480 /* Do the search forwards, since this takes less iterations */ 00481 do 00482 { 00483 /* Get next node */ 00484 OrderedNode = OrderedNode->Blink; 00485 } while (--DeltaUp); 00486 } 00487 else 00488 { 00489 /* Do the search downwards, since this takes less iterations */ 00490 OrderedNode = &Table->InsertOrderList; 00491 do 00492 { 00493 /* Get next node */ 00494 OrderedNode = OrderedNode->Blink; 00495 } while (--DeltaDown); 00496 } 00497 } 00498 00499 /* Got the element, save it */ 00500 Table->OrderedPointer = OrderedNode; 00501 Table->WhichOrderedElement = NextI; 00502 00503 /* Return the element */ 00504 return &((PTABLE_ENTRY_HEADER)CONTAINING_RECORD(OrderedNode, 00505 TABLE_ENTRY_HEADER, 00506 ListEntry))->UserData; 00507 } 00508 00509 /* EOF */ Generated on Sun May 27 2012 04:36:21 for ReactOS by
1.7.6.1
|