|
|
///////////////////////////////////////////////////////////////////////////////
//
// 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
|