Leaked source code of windows server 2003
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.
 
 
 
 
 
 

612 lines
14 KiB

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
dict.c
Abstract:
This module implements a dictionary package. A dictionary is a
generic mapping of an arbitrary domain to an arbitrary range.
This implementation uses a hash-table to give constant time insert
and delete access to the elements in the table, assuming the table is
relativly close in size to the number of elements in the table.
Author:
Matthew D Hendel (math) 9-Feb-2001
Revision History:
--*/
#include "precomp.h"
#define DICT_TAG ('tciD')
#ifdef ExAllocatePool
#undef ExAllocatePool
#define ExAllocatePool(Type, Size) ExAllocatePoolWithTag(Type, Size, DICT_TAG)
#endif
#ifdef ExFreePool
#undef ExFreePool
#define ExFreePool(Type) ExFreePoolWithTag (Type, DICT_TAG)
#endif
NTSTATUS
StorCreateDictionary(
IN PSTOR_DICTIONARY Dictionary,
IN ULONG EntryCount,
IN POOL_TYPE PoolType,
IN STOR_DICTIONARY_GET_KEY_ROUTINE GetKeyRoutine,
IN STOR_DICTIONARY_COMPARE_KEY_ROUTINE CompareKeyRoutine, OPTIONAL
IN STOR_DICTIONARY_HASH_KEY_ROUTINE HashKeyRoutine OPTIONAL
)
/*++
Routine Description:
Initialize a dictionary object.
Arguments:
Dictionary - Supplies the dictionary object to initialize.
EntryCount - Supplies the initial number of empty slots in the dictioanry
table. This number can increase via a call to StorSetElementCount.
PoolType - Pool type of memory to be used.
GetKeyRoutine - User-supplied routine to get a key from a specific
element.
CompareKeyRoutine - User-supplied routine to compare the keys of
two elements. If this routine is not supplied, the default
comparison will be used which assumes the values of the keys
are ULONGs.
HashKeyRoutine - User-supplied routine to has the key to a ULONG.
If this routine is not supplied, the default has routine
merely returns the value of the key as a ULONG.
Return Value:
NTSTATUS code.
--*/
{
ULONG i;
PLIST_ENTRY Entries;
Dictionary->MaxEntryCount = EntryCount;
Dictionary->EntryCount = 0;
Dictionary->PoolType = PoolType;
Dictionary->GetKeyRoutine = GetKeyRoutine;
if (CompareKeyRoutine != NULL) {
Dictionary->CompareKeyRoutine = CompareKeyRoutine;
} else {
Dictionary->CompareKeyRoutine = StorCompareUlongKey;
}
if (HashKeyRoutine != NULL) {
Dictionary->HashKeyRoutine = HashKeyRoutine;
} else {
Dictionary->HashKeyRoutine = StorHashUlongKey;
}
Entries = ExAllocatePool (PoolType,
EntryCount * sizeof (LIST_ENTRY));
if (Entries == NULL) {
return STATUS_NO_MEMORY;
}
//
// Initialize the table of lists.
//
for (i = 0; i < EntryCount; i++) {
InitializeListHead (&Entries[i]);
}
Dictionary->Entries = Entries;
return STATUS_SUCCESS;
}
NTSTATUS
StorDeleteDictionary(
IN PSTOR_DICTIONARY Dictionary
)
/*++
Routine Description:
Delete the dictionary and all resources held by the dictionary.
NB: This routine does not delete all of the individual elements from
the dictionary -- it can't. You should delete the elements from the
dictionary before calling this routine.
Arguments:
Dictionary - Supplies the dictinoary to delete.
Return Value:
NTSTATUS code.
--*/
{
if (Dictionary->EntryCount != 0) {
ASSERT (FALSE);
//
//NB: should we define a new NTSTATUS value for
//STATUS_NOT_EMPTY condition?
//
return STATUS_DIRECTORY_NOT_EMPTY;
}
ASSERT (Dictionary->Entries != NULL);
ExFreePool (Dictionary->Entries);
return STATUS_SUCCESS;
}
NTSTATUS
StorInsertDictionary(
IN PSTOR_DICTIONARY Dictionary,
IN PSTOR_DICTIONARY_ENTRY Entry
)
/*++
Routine Description:
Insert an entry into the dictionary.
Arguments:
Dictionary - Supplies the dictionary to insert into.
Entry - Supplies the entry to insert.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
ULONG Index;
PLIST_ENTRY NextEntry;
PLIST_ENTRY ListHead;
LONG Comparison;
STOR_DICTIONARY_GET_KEY_ROUTINE GetKeyRoutine;
STOR_DICTIONARY_COMPARE_KEY_ROUTINE CompareRoutine;
STOR_DICTIONARY_HASH_KEY_ROUTINE HashRoutine;
GetKeyRoutine = Dictionary->GetKeyRoutine;
CompareRoutine = Dictionary->CompareKeyRoutine;
HashRoutine = Dictionary->HashKeyRoutine;
Index = (HashRoutine (GetKeyRoutine (Entry)) % Dictionary->MaxEntryCount);
ListHead = &Dictionary->Entries[Index];
//
// Otherwise, walk the list searching for the place to insert the entry.
//
for (NextEntry = ListHead->Flink;
NextEntry != ListHead;
NextEntry = NextEntry->Flink) {
Comparison = CompareRoutine (GetKeyRoutine (NextEntry),
GetKeyRoutine (Entry));
if (Comparison == 0) {
return STATUS_DUPLICATE_OBJECTID;
} else if (Comparison < 0) {
//
// Insert the entry directly before this entry.
Entry->Flink = NextEntry;
Entry->Blink = NextEntry->Blink;
Entry->Flink->Blink = Entry;
Entry->Blink->Flink = Entry;
ASSERT (Entry->Flink->Blink == Entry);
ASSERT (Entry->Blink->Flink == Entry);
#if DBG
for (NextEntry = ListHead->Flink;
NextEntry != ListHead;
NextEntry = NextEntry->Flink) {
NOTHING;
}
#endif
Dictionary->EntryCount++;
return STATUS_SUCCESS;
} else {
//
// Continue searching
//
ASSERT (Comparison > 0);
}
}
//
// We'll only exit the loop if there isn't a entry less than the
// one we're inserting. The list is either empty, or all of the
// entries in the list are less than the one we're inserting.
// In either case, the correct action is to add and entry to the
// end of the list.
//
Dictionary->EntryCount++;
InsertTailList (ListHead, Entry);
return STATUS_SUCCESS;
}
NTSTATUS
StorFindDictionary(
IN PSTOR_DICTIONARY Dictionary,
IN PVOID Key,
OUT PSTOR_DICTIONARY_ENTRY* EntryBuffer OPTIONAL
)
/*++
Routine Description:
Find an entry in the dictionary and, optionally, retun the found
entry.
Arguments:
Dictionary - Supplies the dictionary to search through.
Key - Supplies the key of the entry to search for.
EntryBuffer - Supplies an optional buffer where the entry will be copied
if found.
Return Value:
STATUS_NOT_FOUND - If the entry could not be found.
STATUS_SUCCESS - If the entry was successfully found.
Other NTSTATUS code - For other errors.
--*/
{
NTSTATUS Status;
LONG Comparison;
ULONG Index;
PLIST_ENTRY ListHead;
PLIST_ENTRY NextEntry;
STOR_DICTIONARY_GET_KEY_ROUTINE GetKeyRoutine;
STOR_DICTIONARY_COMPARE_KEY_ROUTINE CompareRoutine;
STOR_DICTIONARY_HASH_KEY_ROUTINE HashRoutine;
GetKeyRoutine = Dictionary->GetKeyRoutine;
CompareRoutine = Dictionary->CompareKeyRoutine;
HashRoutine = Dictionary->HashKeyRoutine;
Index = HashRoutine (Key) % Dictionary->MaxEntryCount;
ListHead = &Dictionary->Entries[Index];
Status = STATUS_NOT_FOUND;
for (NextEntry = ListHead->Flink;
NextEntry != ListHead;
NextEntry = NextEntry->Flink) {
Comparison = CompareRoutine (GetKeyRoutine (NextEntry), Key);
if (Comparison == 0) {
//
// Found it.
//
Status = STATUS_SUCCESS;
if (EntryBuffer) {
*EntryBuffer = NextEntry;
}
break;
} else if (Comparison < 0) {
//
// Done searching
//
Status = STATUS_NOT_FOUND;
if (EntryBuffer) {
*EntryBuffer = NULL;
}
break;
} else {
//
// Continue searching
//
ASSERT (Comparison > 0);
}
}
return Status;
}
NTSTATUS
StorRemoveDictionary(
IN PSTOR_DICTIONARY Dictionary,
IN PVOID Key,
OUT PSTOR_DICTIONARY_ENTRY* EntryBuffer OPTIONAL
)
/*++
Routine Description:
Remove an entry from the dictionary.
Arguments:
Dictioanry - Supplies the dictionary to remove the entry from.
Key - Supplies the key used to identify the entry.
EntryBuffer - Optional parameter that supplies a buffer to copy the
removed entry into.
Return Value:
STATUS_NOT_FOUND - If the entry was not found.
STATUS_SUCCESS - If the entry was successfully removed.
Other NTSTATUS code - other error condition.
--*/
{
NTSTATUS Status;
PSTOR_DICTIONARY_ENTRY Entry;
Entry = NULL;
Status = StorFindDictionary (Dictionary, Key, &Entry);
if (NT_SUCCESS (Status)) {
RemoveEntryList (Entry);
Dictionary->EntryCount--;
}
if (EntryBuffer) {
*EntryBuffer = Entry;
}
return Status;
}
NTSTATUS
StorAdjustDictionarySize(
IN PSTOR_DICTIONARY Dictionary,
IN ULONG MaxEntryCount
)
/*++
Routine Description:
Adjust the number of bins in the underlying hash table. Having the
number of bins relativly large compared to the number of entries in
the table gives much better performance.
Adjusting the size of the dictionary is an expensive operation. It
takes about the same amount of time to adjust the dictionary size as
it does to delete the dictionary and create a new one.
Arguments:
Dictionary - Supplies the dictionary whose size is to be adjusted.
MaxEntryCount - Supplies the new maximum entry count. This can be
greater or less than the current entry count. (It can
actually be the same as the current entry count, but
doing so merely wastes time.)
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS Status;
ULONG i;
ULONG OldMaxEntryCount;
PLIST_ENTRY OldEntries;
PLIST_ENTRY Entries;
PLIST_ENTRY Head;
PLIST_ENTRY Entry;
OldEntries = Dictionary->Entries;
OldMaxEntryCount = Dictionary->MaxEntryCount;
Entries = ExAllocatePool (Dictionary->PoolType,
sizeof (LIST_ENTRY) * MaxEntryCount);
if (Entries == NULL) {
return STATUS_NO_MEMORY;
}
for (i = 0; i < MaxEntryCount; i++) {
InitializeListHead (&Entries[i]);
}
//
// Save the old dictionary
//
OldEntries = Dictionary->Entries;
OldMaxEntryCount = Dictionary->MaxEntryCount;
//
// Replace it with the new, empty one
//
Dictionary->Entries = Entries;
Dictionary->MaxEntryCount = MaxEntryCount;
//
// Remove all the old entries, placing them in the new dictioanry
//
for (i = 0; i < OldMaxEntryCount; i++) {
Head = &OldEntries[i];
while (!IsListEmpty (Head)) {
Entry = RemoveHeadList (Head);
Status = StorInsertDictionary (Dictionary, Entry);
ASSERT (NT_SUCCESS (Status));
}
}
ExFreePool (Entries);
return STATUS_SUCCESS;
}
VOID
StorEnumerateDictionary(
IN PSTOR_DICTIONARY Dictionary,
IN PSTOR_DICTIONARY_ENUMERATOR Enumerator
)
/*++
Routine Description:
Enumerate the entries in the dictionary.
Arguments:
Dictionary - Supplies the dictionary to enumerate.
Enumerator - Supplies an enumerator used to enumerate the dictionary.
To halt the enumeration, the enumerator should return FALSE.
Caveats:
The entries are listed in ARBITRARY ORDER. This is not an ordered
enumeration.
Multiple enumerations of the list can happen at the same time. But
the list CANNOT BE MODIFIED while it is being enumerated.
Return Value:
None.
--*/
{
ULONG i;
PLIST_ENTRY NextEntry;
PLIST_ENTRY ListHead;
BOOLEAN Continue;
REVIEW();
for (i = 0; i < Dictionary->MaxEntryCount; i++) {
ListHead = &Dictionary->Entries[i];
for (NextEntry = ListHead->Flink;
NextEntry != ListHead;
NextEntry = NextEntry->Flink) {
Continue = Enumerator->EnumerateEntry (Enumerator, NextEntry);
if (!Continue) {
return ;
}
}
}
}
LONG
StorCompareUlongKey(
IN PVOID Key1,
IN PVOID Key2
)
/*++
Routine Description:
Compare key routine for ULONG keys.
Arguments:
Key1 - First key to compare.
Key2 - Second key to compare.
Return Value:
-1 - if Key1 < Key2
0 - if Key1 == Key2
1 - if Key1 > Key2
--*/
{
if (Key1 < Key2) {
return -1;
} else if (Key1 == Key2) {
return 0;
} else {
return 1;
}
}
ULONG
StorHashUlongKey(
IN PVOID Key
)
/*++
Routine Description:
Hash routine for ULONG keys.
Arguments:
Key - Supplies the key to hash.
Return Value:
Hash code for the key.
--*/
{
return (ULONG)(ULONG_PTR)Key;
}