/////////////////////////////////////////////////////////////////////////////// // // 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 #include 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 // // DESCRIPTION // // Provides a type safe wrapper around HashTableBase. // /////////////////////////////////////////////////////////////////////////////// template 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 find(const K& key) throw () { return ObjectPointer(narrow(HashTableBase::find(&key)), false); } bool insert( T& entry, bool checkForDuplicates = true ) throw () { return HashTableBase::insert(entry, checkForDuplicates); } ObjectPointer remove(const K& key) throw () { return ObjectPointer(narrow(HashTableBase::remove(&key)), false); } protected: static T* narrow(HashTableBase::Entry* entry) throw () { return entry ? static_cast(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 // // DESCRIPTION // // Provides a type safe wrapper around CacheBase. // /////////////////////////////////////////////////////////////////////////////// template 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 find(const K& key) throw () { return ObjectPointer(narrow(CacheBase::find(&key)), false); } bool insert( T& entry, bool checkForDuplicates = true ) throw () { return CacheBase::insert(entry, checkForDuplicates); } ObjectPointer remove(const K& key) throw () { return ObjectPointer(narrow(CacheBase::remove(&key)), false); } protected: static T* narrow(CacheBase::Entry* entry) throw () { return entry ? static_cast(entry) : NULL; } }; #endif // IASCACHE_H