mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
8.5 KiB
426 lines
8.5 KiB
/*++
|
|
|
|
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__
|