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.
 
 
 
 
 
 

389 lines
11 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000, Microsoft Corp. All rights reserved.
//
// FILE
//
// iascache.h
//
// SYNOPSIS
//
// Declares the classes for creating hash tables and caches.
//
// MODIFICATION HISTORY
//
// 02/07/2000 Original version.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef IASCACHE_H
#define IASCACHE_H
#if _MSC_VER >= 1000
#pragma once
#endif
#include <iasobj.h>
#include <iaswin32.h>
class HashTableBase;
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// HashTableEntry
//
// DESCRIPTION
//
// Abstract base class for objects that will be stored in a hash table.
//
///////////////////////////////////////////////////////////////////////////////
class HashTableEntry
{
public:
virtual void AddRef() throw () = 0;
virtual void Release() throw () = 0;
virtual const void* getKey() const throw () = 0;
virtual bool matches(const void* key) const throw () = 0;
friend class HashTableBase;
protected:
HashTableEntry* next;
virtual ~HashTableEntry() throw ();
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// HashTableBase
//
// DESCRIPTION
//
// Implements a simple hash table.
//
///////////////////////////////////////////////////////////////////////////////
class HashTableBase
{
public:
// Entry type.
typedef HashTableEntry Entry;
typedef ULONG (WINAPI *HashKey)(const void*) throw ();
HashTableBase(
HashKey hashFunction,
ULONG initialSize
);
~HashTableBase() throw ();
// Erases all entries from the table.
void clear() throw ();
// Removes and releases the entry matching key. Returns true if successful.
bool erase(const void* key) throw ();
// Returns the entry with the given key or null if no such entry exists. The
// caller is responsible for releasing the returned entry.
HashTableEntry* find(const void* key) throw ();
// Insert a new entry in the cache. Returns 'true' if the entry was
// successfully inserted. Note: this operation can only fail if
// checkForDuplicates is true and the entry already exists.
bool insert(
HashTableEntry& entry,
bool checkForDuplicates = true
) throw ();
// Removes and returns the entry with the given key or null if no such entry
// exists. The caller is responsible for releasing the returned entry.
HashTableEntry* remove(const void* key) throw ();
// Resize the hash table to have newSize buckets. Returns true if
// successful.
bool resize(ULONG newSize) throw ();
protected:
void lock() throw ()
{ monitor.lock(); }
void unlock() throw ()
{ monitor.unlock(); }
HashTableEntry* bucketAsEntry(size_t bucket) throw ()
{ return (HashTableEntry*)(table + bucket); }
typedef HashTableEntry* Bucket;
HashKey hash; // Hash function for hashing keys.
Bucket* table; // Hash table of entries.
ULONG buckets; // Number of buckets in the table.
ULONG entries; // Number of entries in the table.
CriticalSection monitor; // Synchronizes access to the table.
// Not implemented.
HashTableBase(const HashTableBase&) throw ();
HashTableBase& operator=(const HashTableBase&) throw ();
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// HashTable<T>
//
// DESCRIPTION
//
// Provides a type safe wrapper around HashTableBase.
//
///////////////////////////////////////////////////////////////////////////////
template <class K, class T>
class HashTable : public HashTableBase
{
public:
HashTable(
HashKey hashFunction,
ULONG initialSize
) throw ()
: HashTableBase(hashFunction, initialSize)
{ }
bool erase(const K& key) throw ()
{ return HashTableBase::erase(&key); }
bool erase(const T& value) throw ()
{ return HashTableBase::erase(value.getKey()); }
ObjectPointer<T> find(const K& key) throw ()
{ return ObjectPointer<T>(narrow(HashTableBase::find(&key)), false); }
bool insert(
T& entry,
bool checkForDuplicates = true
) throw ()
{ return HashTableBase::insert(entry, checkForDuplicates); }
ObjectPointer<T> remove(const K& key) throw ()
{ return ObjectPointer<T>(narrow(HashTableBase::remove(&key)), false); }
protected:
static T* narrow(HashTableBase::Entry* entry) throw ()
{ return entry ? static_cast<T*>(entry) : NULL; }
};
class CacheBase;
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// CacheEntry
//
// DESCRIPTION
//
// Abstract base class for objects that will be stored in a cache.
//
///////////////////////////////////////////////////////////////////////////////
class CacheEntry : public HashTableEntry
{
public:
// Methods for traversing the doubly-linked list.
CacheEntry* prevInList() const throw ();
CacheEntry* nextInList() const throw ();
protected:
friend class CacheBase;
// Removes the node from the list.
void removeFromList() throw ();
// Methods for manipulating the expiration time.
bool isExpired(const ULONG64& now) const throw ();
bool isExpired() const throw ();
void setExpiry(ULONG64 ttl) throw ();
CacheEntry* flink; // Allows this to be an entry in a doubly-linked list.
CacheEntry* blink;
ULONG64 expiry; // Expiration time.
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// CacheBase
//
// DESCRIPTION
//
// Extends HashTableBase to add support for LRU and TTL based eviction.
//
///////////////////////////////////////////////////////////////////////////////
class CacheBase : protected HashTableBase
{
public:
// Entry type
typedef CacheEntry Entry;
CacheBase(
HashKey hashFunction,
ULONG initialSize,
ULONG maxCapacity,
ULONG timeToLive,
bool updateExpiryOnFind
);
~CacheBase() throw ();
// Erases all entries from the cache.
void clear() throw ();
// Removes and releases the entry matching key. Returns true if successful.
bool erase(const void* key) throw ();
// Evict any eligible entries. Returns the number of entries evicted.
ULONG evict() throw ();
// Returns the entry with the given key or null if no such entry exists. The
// caller is responsible for releasing the returned entry.
CacheEntry* find(const void* key) throw ();
// Insert a new entry in the cache. Returns 'true' if the entry was
// successfully inserted. Note: this operation can only fail if
// checkForDuplicates is true and the entry already exists.
bool insert(
CacheEntry& entry,
bool checkForDuplicates = true
) throw ();
// Removes and returns the entry with the given key or null if no such entry
// exists. The caller is responsible for releasing the returned entry.
CacheEntry* remove(const void* key) throw ();
//////////
// iterator for traversing the cache entries.
//////////
class iterator
{
public:
iterator() throw () {}
iterator(CacheEntry* entry) throw () : p(entry) { }
CacheEntry& operator*() const throw ()
{ return *p; }
CacheEntry* operator->() const throw ()
{ return p; }
iterator& operator++() throw ()
{ p = p->nextInList(); return *this; }
iterator operator++(int) throw ()
{ iterator tmp = *this; ++*this; return tmp; }
iterator& operator--() throw ()
{ p = p->prevInList(); return *this; }
iterator operator--(int) throw ()
{ iterator tmp = *this; --*this; return tmp; }
bool operator==(const iterator& i) const throw ()
{ return p == i.p; }
bool operator!=(const iterator& i) const throw ()
{ return p != i.p; }
protected:
CacheEntry* p;
};
// Iterators for traversing the cache from most to least recently used.
iterator begin() const throw ()
{ return flink; }
iterator end() const throw ()
{ return listAsEntry(); }
protected:
CacheEntry* flink; // Doubly-linked list of entries.
CacheEntry* blink;
ULONG64 ttl; // Time-to-live of cache entries.
ULONG maxEntries; // Max number of entries in the cache.
bool autoUpdate; // true if TTL should be updated in find.
// Evict an eligible entries without grabbing the lock.
void unsafe_evict() throw ();
// Remove an entry without grabbing the lock.
CacheEntry* unsafe_remove(const void* key) throw ();
// Returns the list as if it were a CacheEntry.
CacheEntry* listAsEntry() const throw ()
{
return (CacheEntry*)
((ULONG_PTR)&flink - FIELD_OFFSET(CacheEntry, flink));
}
// Add an entry to the front of the LRU list (i.e., it is the most recently
// used entry.
void push_front(CacheEntry* entry) throw ();
};
///////////////////////////////////////////////////////////////////////////////
//
// CLASS
//
// Cache<T>
//
// DESCRIPTION
//
// Provides a type safe wrapper around CacheBase.
//
///////////////////////////////////////////////////////////////////////////////
template <class K, class T>
class Cache : public CacheBase
{
public:
Cache(
HashKey hashFunction,
ULONG initialSize,
ULONG maxCapacity,
ULONG timeToLive,
bool updateExpiryOnFind
) throw ()
: CacheBase(
hashFunction,
initialSize,
maxCapacity,
timeToLive,
updateExpiryOnFind
)
{ }
bool erase(const K& key) throw ()
{ return CacheBase::erase(&key); }
bool erase(const T& value) throw ()
{ return CacheBase::erase(value.getKey()); }
ObjectPointer<T> find(const K& key) throw ()
{ return ObjectPointer<T>(narrow(CacheBase::find(&key)), false); }
bool insert(
T& entry,
bool checkForDuplicates = true
) throw ()
{ return CacheBase::insert(entry, checkForDuplicates); }
ObjectPointer<T> remove(const K& key) throw ()
{ return ObjectPointer<T>(narrow(CacheBase::remove(&key)), false); }
protected:
static T* narrow(CacheBase::Entry* entry) throw ()
{ return entry ? static_cast<T*>(entry) : NULL; }
};
#endif // IASCACHE_H