Windows-Server-2003/net/rras/rtmv2/pattrie.c

258 lines
4.7 KiB
C

/*++
Copyright (c) 1997 - 98, Microsoft Corporation
Module Name:
avltrie.c
Abstract:
Contains routines for a best matching
prefix lookup using an PATRICIA trie.
Author:
Chaitanya Kodeboyina (chaitk) 24-Jun-1998
Revision History:
--*/
#include "pattrie.h"
DWORD
WINAPI
CreateTable(
IN USHORT MaxBytes,
OUT HANDLE *Table
)
{
PPAT_TRIE NewTrie;
ASSERT(sizeof(PAT_CONTEXT) <= sizeof(LOOKUP_CONTEXT));
ASSERT(sizeof(PAT_LINKAGE) <= sizeof(DATA_ENTRY));
if (MaxBytes)
{
if (NewTrie = AllocNZeroMemory(sizeof(PAT_TRIE)))
{
NewTrie->MaxKeyBytes = (MaxBytes + sizeof(ULONG) - 1) / sizeof(ULONG);
#if _PROF_
NewTrie->MemoryInUse = sizeof(PAT_TRIE);
#endif
*Table = NewTrie;
return NO_ERROR;
}
else // if (NewTrie == NULL)
{
*Table = NULL;
return ERROR_NOT_ENOUGH_MEMORY;
}
}
else // (if MaxBytes == 0)
{
return ERROR_INVALID_PARAMETER;
}
}
DWORD
WINAPI
SearchInTable(
IN HANDLE Table,
IN USHORT NumBits,
IN PUCHAR KeyBits,
OUT PLOOKUP_CONTEXT Context OPTIONAL,
OUT PDATA_ENTRY *Data
)
{
PPAT_TRIE Trie;
PPAT_NODE PrevNode;
PPAT_NODE CurrNode;
PPAT_NODE BestNode;
PAT_CHILD NextChild;
ULONG Key;
#if _PROF_
UINT NumTravs1;
UINT NumTravs2;
#endif
Trie = Table;
#if DBG
if (NumBits > Trie->MaxKeyBytes * BITS_IN_BYTE)
{
*Data = NULL;
return ERROR_INVALID_PARAMETER;
}
#endif
#if _PROF_
NumTravs1 = 0;
NumTravs2 = 0;
#endif
//
// Go down the search trie matching the
// next set of bits in key as u do so
//
Key = RtlUlongByteSwap(KeyBits);
CurrNode = Trie->TrieRoot;
PrevNode = NULL;
NextChild = LCHILD;
BestNode = NULL;
while (CurrNode)
{
#if _PROF_
NumTravs1++;
if (CurrNode->Data)
{
NumTravs2++;
}
#endif
}
return NO_ERROR;
}
DWORD
WINAPI
BestMatchInTable(
IN HANDLE Table,
IN PUCHAR KeyBits,
OUT PDATA_ENTRY *BestData
)
{
PPAT_TRIE Trie;
PPAT_NODE CurrNode;
PAT_CHILD NextChild;
UINT BitsLeft;
ULONG Key;
ULONG CurrMask;
ULONG CurrBits;
#if _PROF_
UINT NumTravs1;
UINT NumTravs2;
#endif
*BestData = NULL;
Trie = Table;
BytesLeft = Trie->MaxKeyBytes;
#if _PROF_
NumTravs1 = 0;
NumTravs2 = 0;
#endif
//
// Go down trie after trie until all bits done
//
while (BytesLeft)
{
//
// Get the key for the next trie search
//
Key = RtlUlongByteSwap(*(ULONG *)KeyBits);
KeyBits += sizeof(ULONG);
BytesLeft -= sizeof(ULONG);
//
// Go down the current search trie
//
CurrNode = Trie->TrieRoot;
BitsLeft = sizeof(ULONG) * BITS_IN_BYTE;
Data = NULL;
while (CurrNode)
{
#if _PROF_
NumTravs1++;
if (CurrNode->Data)
{
NumTravs2++;
}
#endif
CurrMask = MaskBits(CurrNode->NumBits);
CurrBits = CurrNode->KeyBits;
//
// Try to match bits in the current node
//
if ((Key & CurrMask) != CurrBits)
{
// Failed to match this node
break;
}
//
// Update node with best data so far
//
if (CurrNode->Data)
{
Data = CurrNode->Data;
}
//
// Go down for more specific match
//
BitsLeft -= CurrNode->NumBits;
Key <<= CurrNode->NumBits;
NextChild = PickMostSigNBits(Key, 1);
CurrNode = CurrNode->Child[NextChild];
}
//
// Do we do a full match in this sub-trie
// & do we have more sub-trees to work on
//
if (BitsLeft || (!IS_SUB_TRIE(Data)))
{
*BestData = Data;
break;
}
Trie = GET_SUB_TRIE(*BestData);
}
#if _PROF_
Print("Num Travs 1 = %5d, Travs 2 = %5d\n",
NumTravs1,
NumTravs2);
#endif
return BitsLeft ? ERROR_NOT_FOUND : NO_ERROR;
}