/* Copyright (C) 1997, 1998, 1999, 2000 by Alex Pfaffe (Digital Dawn Graphics Inc) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _ddgCache_Class_ #define _ddgCache_Class_ #include "util/ddgerror.h" typedef unsigned short ddgCacheIndex; class WEXP ddgCacheNode { friend class ddgCache; ddgCacheIndex _next; public: ddgCacheNode(void) : _next(0) {} inline ddgCacheIndex next(void) { return _next; } inline void next(ddgCacheIndex ci) { _next = ci; } }; class WEXP ddgCache { ddgCacheNode * _nList; ddgCacheIndex _fList; unsigned int _cacheSize; unsigned int _size; unsigned int _nodeSize; unsigned int _maxSize; public: ddgCache(void ); ~ddgCache(void); bool init( unsigned int cacheSize, unsigned int nodeSize ); ddgCacheIndex allocNode(void); void freeNode(ddgCacheIndex n); inline unsigned int size(void) { return _size; } void reset(void); inline ddgCacheNode *get(ddgCacheIndex i) { ddgAsserts(i >= 0 && i < _cacheSize,"Invalid cache index"); return &(_nList[i*_nodeSize]); } }; class WEXP ddgLNode : public ddgCacheNode { friend class ddgLCache; private: ddgCacheIndex _prev; public: void prev(ddgCacheIndex ci ) { _prev = ci; } ddgCacheIndex prev(void) { return _prev; } }; class WEXP ddgLCache : public ddgCache { typedef ddgCache super; public: inline ddgLNode* get(ddgCacheIndex n) { return (ddgLNode*) super::get(n); } inline ddgCacheIndex insert(ddgCacheIndex nextNode) { ddgCacheIndex ci = allocNode(); // Initialize the new node. ddgLNode *n = get(ci); // Insert at head of the list. n->next(nextNode); if (nextNode) { n->prev(get(nextNode)->prev()); // Update the neighbours. if (n->prev()) get(n->prev())->next(ci); get(n->next())->prev(ci); } else n->prev(0); ddgAssert(ci); return ci; } inline void remove(ddgCacheIndex ci) { ddgAssert(ci); ddgLNode *n = get(ci); if (n->prev()) { get(n->prev())->next(n->next()); } if (n->next()) { get(n->next())->prev(n->prev()); } freeNode(ci); } inline ddgCacheIndex insertHead(ddgCacheIndex nextNode) { ddgCacheIndex ci = allocNode(); // Initialize the new node. ddgLNode *n = get(ci); // Insert at head of the list. n->next(nextNode); if (nextNode) { get(n->next())->prev(ci); } n->prev(0); ddgAssert(ci); return ci; } inline ddgCacheIndex insertTail(ddgCacheIndex prevNode) { ddgCacheIndex ci = allocNode(); // Initialize the new node. ddgLNode *n = get(ci); // Insert at head of the list. n->prev(prevNode); if (prevNode) { get(n->prev())->next(ci); } n->next(0); ddgAssert(ci); return ci; } }; class WEXP ddgSNode : public ddgLNode { friend class ddgSCache; private: short _bucket; public: inline short bucket(void) { return _bucket; } inline void bucket(short b) { _bucket = b; } }; class WEXP ddgSCache : public ddgLCache { typedef ddgLCache super; ddgCacheIndex *_bucket; ddgCacheIndex _head; ddgCacheIndex _tail; short _bucketNo; bool _reverse; public: ddgSCache(void) { _bucket = 0; _bucketNo = 0; _head = 0; _tail = 0; } ~ddgSCache(void) { delete[] _bucket; _head = 0; _tail = 0; _bucket = 0; } inline void reset(void) { ddgCache::reset(); _head = 0; _tail = 0; unsigned int i = _bucketNo; while (i) _bucket[--i] = 0; } void init (unsigned int size, unsigned int nodeSize, unsigned int bn, bool r = false ) { ddgAssert(bn < 0xFFFF); _bucketNo = bn; _reverse = r; super::init(size,nodeSize); _bucket = new ddgCacheIndex[_bucketNo]; ddgAsserts(_bucket, "Failed to allocate memory."); ddgMemorySet(ddgCacheIndex,_bucketNo); reset(); } inline ddgSNode* get(unsigned short index) { return (ddgSNode*) ddgCache::get(index); } inline short bucketNo(void) { return _bucketNo; } inline short convert( short b ) { return _reverse ? _bucketNo - b - 1 : b; } inline ddgCacheIndex insert(short b) { ddgAsserts(b >= 0 && b < _bucketNo,"Bucket key is out of range!"); ddgAsserts(_bucket, "Failed to allocate memory."); if (_reverse) b = _bucketNo - b - 1; ddgCacheIndex ci = super::insert(_bucket[b]); // Initialize the new node. ddgSNode *n = get(ci); n->bucket(b); // We are now the head of the list. _bucket[b] = ci; // Reset the head and tail of the queue if need be. if (_head < ddgCacheIndex(b)) _head = b; else if (_tail > ddgCacheIndex(b)) _tail = b; ddgAssert(ci); return ci; } inline void remove(ddgCacheIndex ci) { ddgAssert(ci); ddgSNode *n = get(ci); short b = n->bucket(); ddgAssert(b >= 0 && b < _bucketNo); ddgAsserts(_bucket, "Failed to allocate memory."); // If the deleted node was the head of the queue update the head. if (_bucket[b] == ci) { _bucket[b] = n->next(); } // Remove the actual item and free it. super::remove(ci); } inline ddgCacheIndex head(void) { while (!_bucket[_head] && _head > 0 ) _head--; return _bucket[_head]; } inline ddgCacheIndex tail(void) { while (!_bucket[_tail] && _tail < _bucketNo-1 ) _tail++; return _bucket[_tail]; } inline ddgCacheIndex next(ddgCacheIndex ci) { ddgAssert(ci); ddgSNode *n = get(ci); short b = n->bucket(); const short blim = (short)_tail; if (n->next()) return n->next(); // Find next bucket with something in it. while (--b > blim && !_bucket[b] ){} return b < 0 ? 0 : _bucket[b]; } }; #endif