ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

generictable.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.