/*++ Copyright (c) 1997 - 98, Microsoft Corporation Module Name: avltrie.h Abstract: Contains interface for a best matching prefix lookup using an AVL trie. Author: Chaitanya Kodeboyina (chaitk) 24-Jun-1998 Revision History: --*/ #ifndef __ROUTING_AVLLOOKUP_H__ #define __ROUTING_AVLLOOKUP_H__ #include "lookup.h" #define Print printf #define BITS_IN_BYTE (UINT) 8 // // Balance factor at an AVL node // #define LEFT -1 #define EVEN 0 #define RIGHT +1 #define INVALID 100 typedef INT AVL_BALANCE, *PAVL_BALANCE; // // A node in the AVL trie // typedef struct _AVL_NODE *PAVL_NODE; // Disable warnings for unnamed structs #pragma warning(disable : 4201) typedef struct _AVL_NODE { PAVL_NODE Prefix; // Node with the next best prefix PAVL_NODE Parent; // Parent of this AVL trie node struct { PAVL_NODE LChild; union { PAVL_NODE Child[1]; // Child[-1] = Left, Child[1] = Right PVOID Data; // Opaque Pointer to data in the node }; PAVL_NODE RChild; }; AVL_BALANCE Balance; // Balance factor at this node USHORT NumBits; // Actual number of bits in key UCHAR KeyBits[1]; // Value of key bits to compare } AVL_NODE; #pragma warning(default : 4201) // // AVL trie with prefix matching // typedef struct _AVL_TRIE { PAVL_NODE TrieRoot; // Pointer to the AVL trie UINT MaxKeyBytes; // Max num of bytes in key UINT NumNodes; // Number of nodes in trie #if PROF ULONG MemoryInUse; // Total memory in use now UINT NumAllocs; // Num of total allocations UINT NumFrees; // Num of total free allocs UINT NumInsertions; // Num of total insertions UINT NumDeletions; // Num of total deletions UINT NumSingleRots; // Num of single rotations UINT NumDoubleRots; // Num of double rotations #endif } AVL_TRIE, *PAVL_TRIE; // // Lookup context for an AVL trie // typedef struct _AVL_CONTEXT { PVOID BestNode; // Node with best the matching prefix PVOID InsPoint; // Node to which new node is attached AVL_BALANCE InsChild; // Node should attached as this child } AVL_CONTEXT, *PAVL_CONTEXT; // // Linkage Info Kept in Data // typedef struct _AVL_LINKAGE { PAVL_NODE NodePtr; // Back pointer to the owning node } AVL_LINKAGE, *PAVL_LINKAGE; #define SET_NODEPTR_INTO_DATA(Data, Node) ((PAVL_LINKAGE)Data)->NodePtr = Node #define GET_NODEPTR_FROM_DATA(Data) ((PAVL_LINKAGE)Data)->NodePtr // // Key Compare/Copy inlines // INT __inline CompareFullKeys( IN PUCHAR Key1, IN PUCHAR Key2, IN UINT NumBytes ) { UINT Count; #if _OPT_ ULONG Temp1; ULONG Temp2; if (NumBytes == sizeof(ULONG)) { Temp1 = RtlUlongByteSwap(*(ULONG *)Key1); Temp2 = RtlUlongByteSwap(*(ULONG *)Key2); if (Temp1 > Temp2) { return +1; } if (Temp1 < Temp2) { return -1; } return 0; } #endif Count = NumBytes; if (!Count) { return 0; } Count--; while (Count && (*Key1 == *Key2)) { Key1++; Key2++; Count--; } return *Key1 - *Key2; } INT __inline ComparePartialKeys( IN PUCHAR Key1, IN PUCHAR Key2, IN USHORT NumBits ) { UINT Count; #if _OPT_ ULONG Temp1; ULONG Temp2; if (NumBits <= sizeof(ULONG) * BITS_IN_BYTE) { Count = sizeof(ULONG) * BITS_IN_BYTE - NumBits; Temp1 = RtlUlongByteSwap(*(ULONG *)Key1) >> Count; Temp2 = RtlUlongByteSwap(*(ULONG *)Key2) >> Count; if (Temp1 > Temp2) { return +1; } if (Temp1 < Temp2) { return -1; } return 0; } #endif Count = NumBits / BITS_IN_BYTE; while (Count && *Key1 == *Key2) { Key1++; Key2++; Count--; } if (Count) { return (*Key1 - *Key2); } Count = NumBits % BITS_IN_BYTE; if (Count) { Count = BITS_IN_BYTE - Count; return (*Key1 >> Count) - (*Key2 >> Count); } return 0; } VOID __inline CopyFullKeys( OUT PUCHAR KeyDst, IN PUCHAR KeySrc, IN UINT NumBytes ) { UINT Count = NumBytes; while (Count--) { *KeyDst++ = *KeySrc++; } return; } VOID __inline CopyPartialKeys( OUT PUCHAR KeyDst, IN PUCHAR KeySrc, IN USHORT NumBits ) { UINT Count = (NumBits + BITS_IN_BYTE - 1) / BITS_IN_BYTE; while (Count--) { *KeyDst++ = *KeySrc++; } return; } // // Node Creation and Deletion inlines // PAVL_NODE __inline CreateTrieNode( IN PAVL_TRIE Trie, IN USHORT NumBits, IN PUCHAR KeyBits, IN PAVL_NODE Prefix, IN PLOOKUP_LINKAGE Data ) { PAVL_NODE NewNode; UINT NumBytes; NumBytes = FIELD_OFFSET(AVL_NODE, KeyBits) + Trie->MaxKeyBytes; NewNode = AllocNZeroMemory(NumBytes); if (NewNode) { NewNode->Prefix = Prefix; NewNode->Data = Data; SET_NODEPTR_INTO_DATA(Data, NewNode); NewNode->Balance = EVEN; NewNode->NumBits = NumBits; CopyPartialKeys(NewNode->KeyBits, KeyBits, NumBits); Trie->NumNodes++; #if PROF Trie->NumAllocs++; Trie->MemoryInUse += NumBytes; #endif } return NewNode; } VOID __inline DestroyTrieNode( IN PAVL_TRIE Trie, IN PAVL_NODE Node ) { UINT NumBytes; SET_NODEPTR_INTO_DATA(Node->Data, NULL); NumBytes = FIELD_OFFSET(AVL_NODE, KeyBits) + Trie->MaxKeyBytes; Trie->NumNodes--; #if PROF Trie->NumFrees++; Trie->MemoryInUse -= NumBytes; #endif FreeMemory(Node); } // // Helper Prototypes // VOID BalanceAfterInsert( IN PAVL_TRIE Trie, IN PAVL_NODE Node, IN AVL_BALANCE Longer ); VOID BalanceAfterDelete( IN PAVL_TRIE Trie, IN PAVL_NODE Node, IN AVL_BALANCE Shorter ); VOID SingleRotate( IN PAVL_TRIE Trie, IN PAVL_NODE UnbalNode, IN AVL_BALANCE Direction, OUT PAVL_NODE *BalancedNode ); VOID DoubleRotate( IN PAVL_TRIE Trie, IN PAVL_NODE UnbalNode, IN AVL_BALANCE Direction, OUT PAVL_NODE *BalancedNode ); VOID SwapWithSuccessor( IN PAVL_TRIE Trie, IN OUT PAVL_CONTEXT Context ); VOID AdjustPrefixes( IN PAVL_TRIE Trie, IN PAVL_NODE OldNode, IN PAVL_NODE NewNode, IN PAVL_NODE TheNode, IN PLOOKUP_CONTEXT Context ); DWORD CheckSubTrie( IN PAVL_NODE Node, OUT PUSHORT Depth ); DWORD CheckTrieNode( IN PAVL_NODE Node, IN USHORT LDepth, IN USHORT RDepth ); VOID DumpSubTrie( IN PAVL_NODE Node ); VOID DumpTrieNode( IN PAVL_NODE Node ); #endif //__ROUTING_AVLLOOKUP_H__