258 lines
4.7 KiB
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;
|
||
|
}
|