|
|
/*++
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__
|