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.
 
 
 
 
 
 

595 lines
18 KiB

#ifndef _UNIQUE_HPP_
#define _UNIQUE_HPP_
// Ruler
// 1 2 3 4 5 6 7 8
//345678901234567890123456789012345678901234567890123456789012345678901234567890
/********************************************************************/
/* */
/* The standard layout. */
/* */
/* The standard layout for 'hpp' files for this code is as */
/* follows: */
/* */
/* 1. Include files. */
/* 2. Constants exported from the class. */
/* 3. Data structures exported from the class. */
/* 4. Forward references to other data structures. */
/* 5. Class specifications (including inline functions). */
/* 6. Additional large inline functions. */
/* */
/* Any portion that is not required is simply omitted. */
/* */
/********************************************************************/
#include "Global.hpp"
#include "Hash.hpp"
#include "List.hpp"
#include "Pool.hpp"
/********************************************************************/
/* */
/* Constants exported from the class. */
/* */
/* The constants supplied here control how unique strings */
/* are constructed. */
/* */
/********************************************************************/
CONST SBIT32 MinDetails = 16;
/********************************************************************/
/* */
/* Class forward references. */
/* */
/* We need to refer to the following classes before they are */
/* fully specified so here we list them as forward references. */
/* */
/********************************************************************/
template <class LOCK> class UNIQUE;
/********************************************************************/
/* */
/* A string description. */
/* */
/* All unique strings have a string drescription which is */
/* into either the active or free list. */
/* */
/********************************************************************/
class DETAIL : public LIST
{
private:
//
// Friend classes.
//
friend class UNIQUE<NO_LOCK>;
friend class UNIQUE<PARTIAL_LOCK>;
friend class UNIQUE<FULL_LOCK>;
//
// Private data.
//
BOOLEAN Active;
SBIT32 Size;
CHAR *Text;
SBIT32 Uses;
};
/********************************************************************/
/* */
/* A unique string. */
/* */
/* Almost all the other classes in the library offer valuable */
/* free-standing functionality. However, this class is really */
/* just a support class for the variable length string class. */
/* */
/********************************************************************/
template <class LOCK=PARTIAL_LOCK> class UNIQUE : public HASH<SBIT32,POINTER>
{
//
// Private data.
//
LIST Active;
LIST Free;
DETAIL *Default;
POOL<DETAIL> Details;
LOCK Sharelock;
public:
//
// Public functions.
//
UNIQUE( VOID );
DETAIL *CreateString( CHAR *String,SBIT32 Size );
SBIT32 CompareStrings( DETAIL *Detail1,DETAIL *Detail2 );
DETAIL *CopyString( DETAIL *Detail1,DETAIL *Detail2 );
VOID DeleteString( DETAIL *Detail );
~UNIQUE( VOID );
//
// Public inline functions.
//
INLINE DETAIL *DefaultString( VOID )
{ return Default; }
INLINE SBIT32 Size( DETAIL *Detail )
{ return Detail -> Size; }
INLINE CHAR *Value( DETAIL *Detail )
{ return Detail -> Text; }
private:
//
// Private functions.
//
VIRTUAL SBIT32 ComputeHashKey
(
CONST SBIT32 & Key
);
VIRTUAL BOOLEAN MatchingKeys
(
CONST SBIT32 & Key1,
CONST SBIT32 & Key2
);
//
// Disabled operations.
//
UNIQUE( CONST UNIQUE & Copy );
VOID operator=( CONST UNIQUE & Copy );
};
/********************************************************************/
/* */
/* Class constructor. */
/* */
/* Create a new unique string table. This call is not thread */
/* safe and should only be made in a single thread environment. */
/* */
/********************************************************************/
template <class LOCK> UNIQUE<LOCK>::UNIQUE( VOID )
{
//
// Create the default string.
//
Default = CreateString( "",0 );
}
/********************************************************************/
/* */
/* Create a new unique string. */
/* */
/* When we are handed a new string we need to find out whether */
/* it is unique (and needs to be added to the table) or just a */
/* duplicate of an existing string. */
/* */
/********************************************************************/
template <class LOCK> DETAIL *UNIQUE<LOCK>::CreateString
(
CHAR *String,
SBIT32 Size
)
{
AUTO DETAIL *Detail1;
AUTO DETAIL *Detail2;
//
// Claim an exclusive lock (if enabled).
//
Sharelock.ClaimExclusiveLock();
//
// Let us assume that the string is unique and
// build an entry to for it. If we later find
// it is not then we just back out the changes.
//
if ( Free.EndOfList() )
{
REGISTER SBIT32 Count;
//
// Create a several new string descriptions
// and link them into the free list.
//
for ( Count=0;Count < MinDetails;Count ++ )
{
//
// Create a new description and add it
// to the free list.
//
Detail1 = new DETAIL;
Detail1 -> Active = False;
Detail1 -> Insert( & Free );
}
}
//
// We know that the free list must contain
// least one element (if not we would have
// just made some). We extract the oldest
// here.
//
if ( (Detail1 = ((DETAIL*) Free.Last())) -> Active )
{
//
// Delete any existing value when we
// recycle an old and unused string
// description. Remember to remove
// it from the hash before deleting
// the string as the hash uses the
// string.
//
RemoveFromHash( ((SBIT32) Detail1) );
delete [] Detail1 -> Text;
Detail1 -> Active = False;
}
//
// We now setup the string description for the
// new string.
//
Detail1 -> Size = Size;
Detail1 -> Text = String;
Detail1 -> Uses = 1;
//
// We are now ready to search the hash table for
// a matching string. We do this by overloading
// the hash table key comparision (see later).
//
if ( ! FindInHash( ((SBIT32) Detail1),((POINTER*) & Detail2) ) )
{
//
// We have found a new string so we need to
// make the string description active and
// insert it in the active list.
//
(Detail2 = Detail1) -> Active = True;
Detail1 -> Delete( & Free );
Detail1 -> Insert( & Active );
//
// Add the new unique string the the hash
// table so we can find it later.
//
AddToHash( ((SBIT32) Detail1),((POINTER) Detail1) );
//
// We know the string is unique so lets
// allocate some space for it and copy it
// into the new area.
//
Detail1 -> Text =
(
strncpy
(
new CHAR [ (Size + 1) ],
String,
Size
)
);
Detail1 -> Text[ Size ] = '\0';
}
else
{
//
// Increment the use count for an existing
// string.
//
if ( Detail2 != Default )
{
//
// We may be lucky and find an unused
// string. If so we need to add it to
// the active list again.
//
if ( (Detail2 -> Uses ++) == 0 )
{
//
// Add an unused string back to the
// active list again.
//
Detail1 -> Delete( & Free );
Detail1 -> Insert( & Active );
}
}
}
//
// Release any lock we got earlier.
//
Sharelock.ReleaseExclusiveLock();
return Detail2;
}
/********************************************************************/
/* */
/* Compare two strings. */
/* */
/* Compare two strings and find the relationship between them. */
/* */
/********************************************************************/
template <class LOCK> SBIT32 UNIQUE<LOCK>::CompareStrings
(
DETAIL *Detail1,
DETAIL *Detail2
)
{
//
// We know that all strings are unique so if the
// string pointers match then they must be the
// the same string.
//
if ( Detail1 != Detail2 )
{
REGISTER SBIT32 Result =
(
strncmp
(
Detail1 -> Text,
Detail2 -> Text,
(Detail1 -> Size < Detail2 -> Size)
? Detail1 -> Size
: Detail2 -> Size
)
);
//
// If the strings match pick the longest.
//
if ( Result == 0 )
{ Result = ((Detail1 -> Size < Detail2 -> Size) ? -1 : 1); }
return Result;
}
else
{ return 0; }
}
/********************************************************************/
/* */
/* Compute a hash key. */
/* */
/* Compute a hash key for the supplied key. This hash key */
/* is used to select the hash chain to search. */
/* */
/********************************************************************/
template <class LOCK> SBIT32 UNIQUE<LOCK>::ComputeHashKey
(
CONST SBIT32 & Key
)
{
REGISTER SBIT32 Count;
REGISTER DETAIL *Detail = ((DETAIL*) Key);
REGISTER SBIT32 HashKey = 2964557531;
for ( Count=0;Count < Detail -> Size;Count ++ )
{
REGISTER SBIT32 Value = ((SBIT32) Detail -> Text[ Count ]);
HashKey = ((HashKey * Value) + Value);
}
return (HashKey & 0x3fffffff);
}
/********************************************************************/
/* */
/* Copy a string. */
/* */
/* All strings are unique so there is no need to copy a string. */
/* Nonetheless, we still have to update the use counts. */
/* */
/********************************************************************/
template <class LOCK> DETAIL *UNIQUE<LOCK>::CopyString
(
DETAIL *Detail1,
DETAIL *Detail2
)
{
//
// Claim an exclusive lock (if enabled).
//
Sharelock.ClaimExclusiveLock();
//
// Decrement the use count for old string.
//
if ( Detail1 != Default )
{ Detail1 -> Uses --; }
//
// Increment the use count for new string.
//
if ( Detail2 != Default )
{ Detail2 -> Uses ++; }
//
// Release any lock we got earlier.
//
Sharelock.ReleaseExclusiveLock();
return Detail2;
}
/********************************************************************/
/* */
/* Compare two hash keys. */
/* */
/* Compare two hash keys to see if they match. */
/* */
/********************************************************************/
template <class LOCK> BOOLEAN UNIQUE<LOCK>::MatchingKeys
(
CONST SBIT32 & Key1,
CONST SBIT32 & Key2
)
{
REGISTER DETAIL *Detail1 = ((DETAIL*) Key1);
REGISTER DETAIL *Detail2 = ((DETAIL*) Key2);
return
(
(Detail1 -> Size == Detail2 -> Size)
&&
(strncmp( Detail1 -> Text,Detail2 -> Text,Detail1 -> Size ) == 0)
);
}
/********************************************************************/
/* */
/* Delete a string. */
/* */
/* Delete a text string. */
/* */
/********************************************************************/
template <class LOCK> VOID UNIQUE<LOCK>::DeleteString( DETAIL *Detail )
{
//
// Claim an exclusive lock (if enabled).
//
Sharelock.ClaimExclusiveLock();
//
// Decrement the use count for the string.
//
if ( Detail != Default )
{
//
// Decrement the use count and ensure that
// this is not the last use of the string.
//
if ( (-- Detail -> Uses) == 0 )
{
//
// When we delete the last use of
// a string we add it to the free
// list. The string can be reclaimed
// if it is recreated before it is
// deleted.
//
Detail -> Delete( & Active );
Detail -> Insert( & Free );
}
}
//
// Release any lock we got earlier.
//
Sharelock.ReleaseExclusiveLock();
}
/********************************************************************/
/* */
/* Class destructor. */
/* */
/* Destory the unique string table. This call is not thread */
/* safe and should only be made in a single thread environment. */
/* */
/********************************************************************/
template <class LOCK> UNIQUE<LOCK>::~UNIQUE( VOID )
{
//
// Delete all active strings.
//
while ( ! Active.EndOfList() )
{
REGISTER DETAIL *Detail = ((DETAIL*) Active.First());
//
// Delete from the list and add to the free
// pool just to be tidy.
//
Detail -> Delete( & Active );
//
// The string description may be contain an
// previous value and require some cleanup.
//
if ( Detail -> Active )
{
//
// Delete any existing value. Remember
// to remove it from the hash before
// deleting the string as the hash uses
// the string.
//
RemoveFromHash( ((SBIT32) Detail) );
delete [] Detail -> Text;
Detail -> Active = False;
}
//
// Push back into the pool.
//
Details.PushPool( Detail );
}
//
// Delete all free strings.
//
while ( ! Free.EndOfList() )
{
REGISTER DETAIL *Detail = ((DETAIL*) Free.First());
//
// Delete from the list and add to the free
// pool just to be tidy.
//
Detail -> Delete( & Free );
//
// The string description may be contain an
// previous value and require some cleanup.
//
if ( Detail -> Active )
{
//
// Delete any existing value. Remember
// to remove it from the hash before
// deleting the string as the hash uses
// the string.
//
RemoveFromHash( ((SBIT32) Detail) );
delete [] Detail -> Text;
Detail -> Active = False;
}
//
// Push back into the pool.
//
Details.PushPool( Detail );
}
}
#endif