mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 14:53:40 +00:00
Create a branch for header work.
svn path=/branches/header-work/; revision=45691
This commit is contained in:
parent
14fe274b1c
commit
9ea495ba33
19538 changed files with 0 additions and 1063950 deletions
768
lib/rtl/generictable.c
Normal file
768
lib/rtl/generictable.c
Normal file
|
@ -0,0 +1,768 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/rtl/generictable.c
|
||||
* PURPOSE: Splay Tree and AVL Tree Generic Table Implementation
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
* Art Yerks (ayerkes@speakeasy.net)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <rtl.h>
|
||||
#include "austin/avl.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* Internal header for table entries */
|
||||
typedef struct _TABLE_ENTRY_HEADER
|
||||
{
|
||||
RTL_SPLAY_LINKS SplayLinks;
|
||||
LIST_ENTRY ListEntry;
|
||||
LONGLONG UserData;
|
||||
} TABLE_ENTRY_HEADER, *PTABLE_ENTRY_HEADER;
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
TABLE_SEARCH_RESULT
|
||||
NTAPI
|
||||
RtlpFindGenericTableNodeOrParent(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
OUT PRTL_SPLAY_LINKS *NodeOrParent)
|
||||
{
|
||||
PRTL_SPLAY_LINKS CurrentNode, ChildNode;
|
||||
RTL_GENERIC_COMPARE_RESULTS Result;
|
||||
|
||||
/* Quick check to see if the table is empty */
|
||||
if (RtlIsGenericTableEmpty(Table))
|
||||
{
|
||||
*NodeOrParent = NULL;
|
||||
return TableEmptyTree;
|
||||
}
|
||||
|
||||
/* Set the current node */
|
||||
CurrentNode = Table->TableRoot;
|
||||
|
||||
/* Start compare loop */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Do the compare */
|
||||
Result = Table->CompareRoutine(Table,
|
||||
Buffer,
|
||||
&((PTABLE_ENTRY_HEADER)CurrentNode)->
|
||||
UserData);
|
||||
if (Result == GenericLessThan)
|
||||
{
|
||||
/* We're less, check if this is the left child */
|
||||
if ((ChildNode = RtlLeftChild(CurrentNode)))
|
||||
{
|
||||
/* Continue searching from this node */
|
||||
CurrentNode = ChildNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, the element isn't in this tree */
|
||||
*NodeOrParent = CurrentNode;
|
||||
return TableInsertAsLeft;
|
||||
}
|
||||
}
|
||||
else if (Result == GenericGreaterThan)
|
||||
{
|
||||
/* We're more, check if this is the right child */
|
||||
if ((ChildNode = RtlRightChild(CurrentNode)))
|
||||
{
|
||||
/* Continue searching from this node */
|
||||
CurrentNode = ChildNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, the element isn't in this tree */
|
||||
*NodeOrParent = CurrentNode;
|
||||
return TableInsertAsRight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We should've found the node */
|
||||
ASSERT(Result == GenericEqual);
|
||||
|
||||
/* Return node found */
|
||||
*NodeOrParent = CurrentNode;
|
||||
return TableFoundNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SPLAY FUNCTIONS ***********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
RtlInitializeGenericTable(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine,
|
||||
IN PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine,
|
||||
IN PRTL_GENERIC_FREE_ROUTINE FreeRoutine,
|
||||
IN PVOID TableContext)
|
||||
{
|
||||
/* Initialize the table to default and passed values */
|
||||
InitializeListHead(&Table->InsertOrderList);
|
||||
Table->TableRoot = NULL;
|
||||
Table->NumberGenericTableElements = 0;
|
||||
Table->WhichOrderedElement = 0;
|
||||
Table->OrderedPointer = &Table->InsertOrderList;
|
||||
Table->CompareRoutine = CompareRoutine;
|
||||
Table->AllocateRoutine = AllocateRoutine;
|
||||
Table->FreeRoutine = FreeRoutine;
|
||||
Table->TableContext = TableContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlInsertElementGenericTable(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PBOOLEAN NewElement OPTIONAL)
|
||||
{
|
||||
PRTL_SPLAY_LINKS NodeOrParent;
|
||||
TABLE_SEARCH_RESULT Result;
|
||||
|
||||
/* Get the splay links and table search result immediately */
|
||||
Result = RtlpFindGenericTableNodeOrParent(Table, Buffer, &NodeOrParent);
|
||||
|
||||
/* Now call the routine to do the full insert */
|
||||
return RtlInsertElementGenericTableFull(Table,
|
||||
Buffer,
|
||||
BufferSize,
|
||||
NewElement,
|
||||
NodeOrParent,
|
||||
Result);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlInsertElementGenericTableFull(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PBOOLEAN NewElement OPTIONAL,
|
||||
IN PVOID NodeOrParent,
|
||||
IN TABLE_SEARCH_RESULT SearchResult)
|
||||
{
|
||||
PRTL_SPLAY_LINKS NewNode;
|
||||
|
||||
/* Check if the entry wasn't already found */
|
||||
if (SearchResult != TableFoundNode)
|
||||
{
|
||||
/* We're doing an allocation, sanity check */
|
||||
ASSERT(Table->NumberGenericTableElements != (MAXULONG - 1));
|
||||
|
||||
/* Allocate a node */
|
||||
NewNode = Table->AllocateRoutine(Table,
|
||||
BufferSize +
|
||||
FIELD_OFFSET(TABLE_ENTRY_HEADER,
|
||||
UserData));
|
||||
if (!NewNode)
|
||||
{
|
||||
/* No memory or other allocation error, fail */
|
||||
if (NewElement) *NewElement = FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the new inserted element */
|
||||
RtlInitializeSplayLinks(NewNode);
|
||||
InsertTailList(&Table->InsertOrderList,
|
||||
&((PTABLE_ENTRY_HEADER)NewNode)->ListEntry);
|
||||
|
||||
/* Increase element count */
|
||||
Table->NumberGenericTableElements++;
|
||||
|
||||
/* Check where we should insert the entry */
|
||||
if (SearchResult == TableEmptyTree)
|
||||
{
|
||||
/* This is the new root node */
|
||||
Table->TableRoot = NewNode;
|
||||
}
|
||||
else if (SearchResult == TableInsertAsLeft)
|
||||
{
|
||||
/* Insert it left */
|
||||
RtlInsertAsLeftChild(NodeOrParent, NewNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right node */
|
||||
RtlInsertAsRightChild(NodeOrParent, NewNode);
|
||||
}
|
||||
|
||||
/* Copy user buffer */
|
||||
RtlCopyMemory(&((PTABLE_ENTRY_HEADER)NewNode)->UserData,
|
||||
Buffer,
|
||||
BufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return the node we already found */
|
||||
NewNode = NodeOrParent;
|
||||
}
|
||||
|
||||
/* Splay the tree */
|
||||
Table->TableRoot = RtlSplay(NewNode);
|
||||
|
||||
/* Return status */
|
||||
if (NewElement) *NewElement = (SearchResult == TableFoundNode);
|
||||
|
||||
/* Return pointer to user data */
|
||||
return &((PTABLE_ENTRY_HEADER)NewNode)->UserData;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
RtlIsGenericTableEmpty(IN PRTL_GENERIC_TABLE Table)
|
||||
{
|
||||
/* Check if the table root is empty */
|
||||
return (Table->TableRoot) ? FALSE: TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlNumberGenericTableElements(IN PRTL_GENERIC_TABLE Table)
|
||||
{
|
||||
/* Return the number of elements */
|
||||
return Table->NumberGenericTableElements;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlLookupElementGenericTable(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PRTL_SPLAY_LINKS NodeOrParent;
|
||||
TABLE_SEARCH_RESULT Result;
|
||||
|
||||
/* Call the full version */
|
||||
return RtlLookupElementGenericTableFull(Table,
|
||||
Buffer,
|
||||
(PVOID)&NodeOrParent,
|
||||
&Result);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlLookupElementGenericTableFull(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
OUT PVOID *NodeOrParent,
|
||||
OUT TABLE_SEARCH_RESULT *SearchResult)
|
||||
{
|
||||
/* Do the initial lookup */
|
||||
*SearchResult = RtlpFindGenericTableNodeOrParent(Table,
|
||||
Buffer,
|
||||
(PRTL_SPLAY_LINKS *)
|
||||
NodeOrParent);
|
||||
|
||||
/* Check if we found anything */
|
||||
if ((*SearchResult == TableEmptyTree) || (*SearchResult != TableFoundNode))
|
||||
{
|
||||
/* Nothing found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, splay the tree and return this entry */
|
||||
Table->TableRoot = RtlSplay(*NodeOrParent);
|
||||
return &((PTABLE_ENTRY_HEADER)*NodeOrParent)->UserData;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
RtlDeleteElementGenericTable(IN PRTL_GENERIC_TABLE Table,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PRTL_SPLAY_LINKS NodeOrParent;
|
||||
TABLE_SEARCH_RESULT Result;
|
||||
|
||||
/* Get the splay links and table search result immediately */
|
||||
Result = RtlpFindGenericTableNodeOrParent(Table, Buffer, &NodeOrParent);
|
||||
if ((Result == TableEmptyTree) || (Result != TableFoundNode))
|
||||
{
|
||||
/* Nothing to delete */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Delete the entry */
|
||||
Table->TableRoot = RtlDelete(NodeOrParent);
|
||||
RemoveEntryList(&((PTABLE_ENTRY_HEADER)NodeOrParent)->ListEntry);
|
||||
|
||||
/* Update accounting data */
|
||||
Table->NumberGenericTableElements--;
|
||||
Table->WhichOrderedElement = 0;
|
||||
Table->OrderedPointer = &Table->InsertOrderList;
|
||||
|
||||
/* Free the entry */
|
||||
Table->FreeRoutine(Table, NodeOrParent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlEnumerateGenericTable(IN PRTL_GENERIC_TABLE Table,
|
||||
IN BOOLEAN Restart)
|
||||
{
|
||||
PRTL_SPLAY_LINKS FoundNode;
|
||||
|
||||
/* Check if the table is empty */
|
||||
if (RtlIsGenericTableEmpty(Table)) return NULL;
|
||||
|
||||
/* Check if we have to restart */
|
||||
if (Restart)
|
||||
{
|
||||
/* Then find the leftmost element */
|
||||
FoundNode = Table->TableRoot;
|
||||
do
|
||||
{
|
||||
/* Get the left child */
|
||||
FoundNode = RtlLeftChild(FoundNode);
|
||||
} while(RtlLeftChild(FoundNode));
|
||||
|
||||
/* Splay it */
|
||||
Table->TableRoot = RtlSplay(FoundNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, try using the real successor */
|
||||
FoundNode = RtlRealSuccessor(Table->TableRoot);
|
||||
if (FoundNode) Table->TableRoot = RtlSplay(FoundNode);
|
||||
}
|
||||
|
||||
/* Check if we found the node and return it */
|
||||
return FoundNode ? &((PTABLE_ENTRY_HEADER)FoundNode)->UserData : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlEnumerateGenericTableWithoutSplaying(IN PRTL_GENERIC_TABLE Table,
|
||||
IN OUT PVOID *RestartKey)
|
||||
{
|
||||
PRTL_SPLAY_LINKS FoundNode;
|
||||
|
||||
/* Check if the table is empty */
|
||||
if (RtlIsGenericTableEmpty(Table)) return NULL;
|
||||
|
||||
/* Check if we have to restart */
|
||||
if (!(*RestartKey))
|
||||
{
|
||||
/* Then find the leftmost element */
|
||||
FoundNode = Table->TableRoot;
|
||||
do
|
||||
{
|
||||
/* Get the left child */
|
||||
FoundNode = RtlLeftChild(FoundNode);
|
||||
} while(RtlLeftChild(FoundNode));
|
||||
|
||||
/* Splay it */
|
||||
*RestartKey = FoundNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, try using the real successor */
|
||||
FoundNode = RtlRealSuccessor(*RestartKey);
|
||||
if (FoundNode) *RestartKey = FoundNode;
|
||||
}
|
||||
|
||||
/* Check if we found the node and return it */
|
||||
return FoundNode ? &((PTABLE_ENTRY_HEADER)FoundNode)->UserData : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlEnumerateGenericTableLikeADirectory(IN PRTL_AVL_TABLE Table,
|
||||
IN PRTL_AVL_MATCH_FUNCTION MatchFunction,
|
||||
IN PVOID MatchData,
|
||||
IN ULONG NextFlag,
|
||||
IN OUT PVOID *RestartKey,
|
||||
IN OUT PULONG DeleteCount,
|
||||
IN OUT PVOID Buffer)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlGetElementGenericTable(IN PRTL_GENERIC_TABLE Table,
|
||||
IN ULONG I)
|
||||
{
|
||||
ULONG OrderedElement, ElementCount;
|
||||
PLIST_ENTRY OrderedNode;
|
||||
ULONG DeltaUp, DeltaDown;
|
||||
ULONG NextI = I + 1;
|
||||
|
||||
/* Setup current accounting data */
|
||||
OrderedNode = Table->OrderedPointer;
|
||||
OrderedElement = Table->WhichOrderedElement;
|
||||
ElementCount = Table->NumberGenericTableElements;
|
||||
|
||||
/* Sanity checks */
|
||||
if ((I == MAXULONG) || (NextI > ElementCount)) return NULL;
|
||||
|
||||
/* Check if we already found the entry */
|
||||
if (NextI == OrderedElement)
|
||||
{
|
||||
/* Return it */
|
||||
return &((PTABLE_ENTRY_HEADER)CONTAINING_RECORD(OrderedNode,
|
||||
TABLE_ENTRY_HEADER,
|
||||
ListEntry))->UserData;
|
||||
}
|
||||
|
||||
/* Now check if we're farther behind */
|
||||
if (OrderedElement > NextI)
|
||||
{
|
||||
/* Find out if the distance is more then the half-way point */
|
||||
if (NextI > (OrderedElement / 2))
|
||||
{
|
||||
/* Do the search backwards, since this takes less iterations */
|
||||
DeltaDown = OrderedElement - NextI;
|
||||
do
|
||||
{
|
||||
/* Get next node */
|
||||
OrderedNode = OrderedNode->Blink;
|
||||
} while (--DeltaDown);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Follow the list directly instead */
|
||||
OrderedNode = &Table->InsertOrderList;
|
||||
do
|
||||
{
|
||||
/* Get next node */
|
||||
OrderedNode = OrderedNode->Flink;
|
||||
} while (--NextI);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are farther ahead, calculate distances */
|
||||
DeltaUp = NextI - OrderedElement;
|
||||
DeltaDown = (ElementCount - NextI) + 1;
|
||||
|
||||
/* Check if the up distance is smaller then the down distance */
|
||||
if (DeltaUp <= DeltaDown)
|
||||
{
|
||||
/* Do the search forwards, since this takes less iterations */
|
||||
do
|
||||
{
|
||||
/* Get next node */
|
||||
OrderedNode = OrderedNode->Blink;
|
||||
} while (--DeltaUp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do the search downwards, since this takes less iterations */
|
||||
OrderedNode = &Table->InsertOrderList;
|
||||
do
|
||||
{
|
||||
/* Get next node */
|
||||
OrderedNode = OrderedNode->Blink;
|
||||
} while (--DeltaDown);
|
||||
}
|
||||
}
|
||||
|
||||
/* Got the element, save it */
|
||||
Table->OrderedPointer = OrderedNode;
|
||||
Table->WhichOrderedElement = NextI;
|
||||
|
||||
/* Return the element */
|
||||
return &((PTABLE_ENTRY_HEADER)CONTAINING_RECORD(OrderedNode,
|
||||
TABLE_ENTRY_HEADER,
|
||||
ListEntry))->UserData;
|
||||
}
|
||||
|
||||
/* AVL FUNCTIONS *************************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlLookupElementGenericTableFullAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
IN OUT PVOID *NodeOrParent,
|
||||
IN OUT TABLE_SEARCH_RESULT *SearchResult)
|
||||
{
|
||||
PRTL_BALANCED_LINKS OurNodeOrParent;
|
||||
TABLE_SEARCH_RESULT OurSearchResult;
|
||||
|
||||
if( !Table->NumberGenericTableElements )
|
||||
{
|
||||
*SearchResult = TableEmptyTree;
|
||||
*NodeOrParent = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OurSearchResult = avl_search
|
||||
(Table, Buffer,
|
||||
Table->BalancedRoot.LeftChild, &OurNodeOrParent);
|
||||
|
||||
if(SearchResult) *SearchResult = OurSearchResult;
|
||||
if(NodeOrParent) *NodeOrParent = OurNodeOrParent;
|
||||
|
||||
if(OurSearchResult == TableFoundNode)
|
||||
return avl_data(OurNodeOrParent);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlLookupElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
PRTL_BALANCED_LINKS OurNodeOrParent;
|
||||
TABLE_SEARCH_RESULT OurSearchResult;
|
||||
return RtlLookupElementGenericTableFullAvl
|
||||
(Table, Buffer, (PVOID *)&OurNodeOrParent, &OurSearchResult);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
RtlDeleteElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
TABLE_SEARCH_RESULT Result;
|
||||
PRTL_BALANCED_LINKS Node;
|
||||
|
||||
RtlLookupElementGenericTableFullAvl
|
||||
( Table, Buffer, (PVOID *)&Node, &Result );
|
||||
|
||||
if( Result == TableFoundNode )
|
||||
{
|
||||
avl_delete_node(Table, Node);
|
||||
Table->FreeRoutine(Table, Node);
|
||||
if( Table->NumberGenericTableElements == 0 )
|
||||
avl_deinit(Table);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlEnumerateGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN BOOLEAN Restart)
|
||||
{
|
||||
if( Table->NumberGenericTableElements == 0 )
|
||||
return NULL;
|
||||
|
||||
if( Restart )
|
||||
{
|
||||
Table->RestartKey = avl_first(Table);
|
||||
}
|
||||
else
|
||||
{
|
||||
Table->RestartKey = avl_next(Table, Table->RestartKey);
|
||||
}
|
||||
if( !Table->RestartKey )
|
||||
return NULL;
|
||||
else
|
||||
return avl_data(Table->RestartKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlEnumerateGenericTableWithoutSplayingAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN OUT PVOID *RestartKey)
|
||||
{
|
||||
/* FIXME! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlGetElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN ULONG I)
|
||||
{
|
||||
PRTL_BALANCED_LINKS Node;
|
||||
|
||||
if( I >= Table->NumberGenericTableElements ) return NULL;
|
||||
else
|
||||
{
|
||||
Node = avl_first(Table);
|
||||
while(I--) Node = avl_next(Table, Node);
|
||||
return avl_data(Node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
RtlInitializeGenericTableAvl(IN OUT PRTL_AVL_TABLE Table,
|
||||
IN PRTL_AVL_COMPARE_ROUTINE CompareRoutine,
|
||||
IN PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine,
|
||||
IN PRTL_AVL_FREE_ROUTINE FreeRoutine,
|
||||
IN PVOID TableContext)
|
||||
{
|
||||
RtlZeroMemory(Table, sizeof(RTL_AVL_TABLE));
|
||||
Table->BalancedRoot.Parent = &Table->BalancedRoot;
|
||||
Table->CompareRoutine = CompareRoutine;
|
||||
Table->AllocateRoutine = AllocateRoutine;
|
||||
Table->FreeRoutine = FreeRoutine;
|
||||
Table->TableContext = TableContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlInsertElementGenericTableFullAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PBOOLEAN NewElement OPTIONAL,
|
||||
IN OUT PVOID *NodeOrParent,
|
||||
IN OUT TABLE_SEARCH_RESULT *SearchResult)
|
||||
{
|
||||
PRTL_BALANCED_LINKS OurNodeOrParent;
|
||||
TABLE_SEARCH_RESULT OurSearchResult;
|
||||
|
||||
if(Table->NumberGenericTableElements == 0) {
|
||||
avl_init(Table);
|
||||
}
|
||||
|
||||
if(NewElement)
|
||||
*NewElement = FALSE;
|
||||
|
||||
OurSearchResult = avl_search
|
||||
(Table, Buffer,
|
||||
Table->BalancedRoot.LeftChild, &OurNodeOrParent);
|
||||
|
||||
if(NodeOrParent) *NodeOrParent = OurNodeOrParent;
|
||||
if(SearchResult) *SearchResult = OurSearchResult;
|
||||
|
||||
if(OurSearchResult == TableFoundNode)
|
||||
{
|
||||
RtlDeleteElementGenericTableAvl(Table, Buffer);
|
||||
return RtlInsertElementGenericTableFullAvl
|
||||
(Table, Buffer, BufferSize,
|
||||
NewElement, NodeOrParent, SearchResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRTL_BALANCED_LINKS NewNode =
|
||||
Table->AllocateRoutine
|
||||
(Table,
|
||||
BufferSize + sizeof(RTL_BALANCED_LINKS) + BufferSize);
|
||||
|
||||
if( !NewNode ) return NULL;
|
||||
|
||||
NewNode->Balance = 0;
|
||||
RtlCopyMemory(avl_data(NewNode), Buffer, BufferSize);
|
||||
|
||||
OurNodeOrParent = NewNode;
|
||||
|
||||
avl_insert_node(Table, NewNode);
|
||||
return avl_data(NewNode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlInsertElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PBOOLEAN NewElement OPTIONAL)
|
||||
{
|
||||
PVOID NodeOrParent;
|
||||
TABLE_SEARCH_RESULT SearchResult;
|
||||
|
||||
return RtlInsertElementGenericTableFullAvl
|
||||
(Table, Buffer, BufferSize, NewElement, &NodeOrParent, &SearchResult);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
RtlIsGenericTableEmptyAvl(PRTL_AVL_TABLE Table)
|
||||
{
|
||||
return Table->NumberGenericTableElements == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlNumberGenericTableElementsAvl(IN PRTL_AVL_TABLE Table)
|
||||
{
|
||||
return Table->NumberGenericTableElements;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
PVOID
|
||||
NTAPI
|
||||
RtlLookupFirstMatchingElementGenericTableAvl(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
OUT PVOID *RestartKey)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue