Hashtable.h

00001 /* This file is Copyright 2000-2008 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */
00002 
00003 #ifndef MuscleHashtable_h
00004 #define MuscleHashtable_h
00005 
00006 #include "support/MuscleSupport.h"
00007 
00008 #ifdef _MSC_VER
00009 # pragma warning(disable: 4786)
00010 #endif
00011 
00012 #ifndef MUSCLE_HASHTABLE_DEFAULT_CAPACITY
00013 # define MUSCLE_HASHTABLE_DEFAULT_CAPACITY 7
00014 #endif
00015 
00016 BEGIN_NAMESPACE(muscle);
00017 
00018 // implementation detail; please ignore this!
00019 static const uint32 MUSCLE_HASHTABLE_INVALID_HASH_CODE = (uint32)-1;
00020 
00026 template <class T> class HashFunctor
00027 {
00028 public:
00030    uint32 operator()(const T x) const {return (uint32)((unsigned long)x);}  // double-cast for AMD64
00031 };
00032 
00033 template <class KeyType, class ValueType, class HashFunctorType> class Hashtable;  // forward declaration
00034 
00038 enum {
00039    HTIT_FLAG_BACKWARDS  = (1<<0), // iterate backwards.  Conveniently equal to ((bool)true), for backwards compatibility with old code
00040    HTIT_FLAG_NOREGISTER = (1<<1), // don't register with Hashtable object, for thread-safety (at the expense of modification-safety)
00041    NUM_HTIT_FLAGS = 2             // number of HTIT_FLAG_* constants that have been defined
00042 };
00043 
00080 template <class KeyType, class ValueType, class HashFunctorType = HashFunctor<KeyType> > class HashtableIterator
00081 {
00082 public:
00089    HashtableIterator();
00090 
00092    HashtableIterator(const HashtableIterator<KeyType, ValueType, HashFunctorType> & rhs);
00093 
00098    HashtableIterator(const Hashtable<KeyType, ValueType, HashFunctorType> & table, uint32 flags = 0);
00099 
00106    HashtableIterator(const Hashtable<KeyType, ValueType, HashFunctorType> & table, const KeyType & startAt, uint32 flags);
00107 
00109    ~HashtableIterator();
00110 
00112    HashtableIterator<KeyType, ValueType, HashFunctorType> & operator=(const HashtableIterator<KeyType, ValueType, HashFunctorType> & rhs);
00113 
00115    void operator++(int) {(void) GetNextKey(); (void) GetNextValue();}
00116 
00118    void operator--(int) {bool b = IsBackwards(); SetBackwards(!b); (void) GetNextKey(); (void) GetNextValue(); SetBackwards(b);}
00119 
00121    bool HasMoreKeys() const {return ((_nextKeyCookie != NULL)||((_owner)&&(_owner->HasItems())&&(_flags&HTIT_INTERNAL_FLAG_RESTARTKEY)));}
00122 
00131    const KeyType & GetKey() const {return *PeekNextKey();}
00132 
00141    ValueType & GetValue() const {return *PeekNextValue();}
00142 
00148    status_t GetNextKey(KeyType & setNextKey);
00149 
00155    status_t GetNextKey(const KeyType * & setNextKeyPtr);
00156 
00162    const KeyType * GetNextKey();
00163 
00169    status_t PeekNextKey(KeyType & setKey) const;
00170 
00176    status_t PeekNextKey(const KeyType * & setKey) const;
00177 
00183    const KeyType * PeekNextKey() const;
00184 
00186    bool HasMoreValues() const {return ((_nextValueCookie != NULL)||((_owner)&&(_owner->HasItems())&&(_flags & HTIT_INTERNAL_FLAG_RESTARTVALUE)));}
00187 
00193    status_t GetNextValue(ValueType & setNextValue);
00194 
00200    status_t GetNextValue(ValueType * & setValuePtr);
00201 
00207    status_t GetNextValue(const ValueType * & setValuePtr);
00208 
00214    ValueType * GetNextValue();
00215 
00221    status_t PeekNextValue(ValueType & setValue) const;
00222 
00228    status_t PeekNextValue(const ValueType * & setValue) const;
00229 
00235    status_t PeekNextValue(ValueType * & setValue) const;
00236 
00242    ValueType * PeekNextValue() const;
00243 
00249    status_t GetNextKeyAndValue(KeyType & setKey, ValueType & setValue);
00250 
00256    status_t GetNextKeyAndValue(KeyType & setKey, ValueType * & setValuePtr);
00257 
00263    status_t GetNextKeyAndValue(KeyType & setKey, const ValueType * & setValuePtr);
00264 
00270    status_t GetNextKeyAndValue(const KeyType * & setKeyPtr, ValueType & setValue);
00271 
00277    status_t GetNextKeyAndValue(const KeyType * & setKeyPtr, ValueType * & setValuePtr);
00278 
00284    status_t GetNextKeyAndValue(const KeyType * & setKeyPtr, const ValueType * & setValuePtr);
00285 
00287    uint32 GetFlags() const {return _flags;}
00288 
00293    void SetBackwards(bool backwards) {if (backwards) _flags |= HTIT_FLAG_BACKWARDS; else _flags &= ~HTIT_FLAG_BACKWARDS;}
00294 
00298    bool IsBackwards() const {return ((_flags & HTIT_FLAG_BACKWARDS) != 0);}
00299 
00300 private:
00301    enum {
00302       HTIT_INTERNAL_FLAG_RESTARTKEY   = (1<<31), // tells GetNextKey() not to iterate on the next iteration
00303       HTIT_INTERNAL_FLAG_RESTARTVALUE = (1<<30)  // tells GetNextValue() not to iterate on the next iteration
00304    };
00305 
00307    friend class Hashtable<KeyType, ValueType, HashFunctorType>;
00308 
00309    void * _scratchSpace[2];   // ignore this; it's temp scratch space used by EnsureSize().
00310 
00311    void * _nextKeyCookie;
00312    void * _nextValueCookie;
00313    uint32 _flags;
00314 
00315    HashtableIterator<KeyType, ValueType, HashFunctorType> * _prevIter;  // for the doubly linked list so that the table can notify us if it is modified
00316    HashtableIterator<KeyType, ValueType, HashFunctorType> * _nextIter;  // for the doubly linked list so that the table can notify us if it is modified
00317    const Hashtable<KeyType, ValueType, HashFunctorType>   * _owner;     // table that we are associated with
00318 };
00319 
00334 template <class KeyType, class ValueType, class HashFunctorType = HashFunctor<KeyType> > class Hashtable
00335 {
00336 public:
00346    typedef int (*KeyCompareFunc)(const KeyType& key1, const KeyType& key2, void * cookie);
00347 
00357    typedef int (*ValueCompareFunc)(const ValueType& key1, const ValueType& key2, void * cookie);
00358 
00360    enum {
00361       AUTOSORT_DISABLED = 0,  
00362       AUTOSORT_BY_KEY,        
00363       AUTOSORT_BY_VALUE       
00364    };
00365 
00367    Hashtable();
00368 
00373    explicit Hashtable(uint32 initialCapacity);
00374 
00376    Hashtable(const Hashtable<KeyType,ValueType,HashFunctorType> & rhs);
00377 
00379    ~Hashtable();
00380 
00384    Hashtable<KeyType,ValueType,HashFunctorType> & operator= (const Hashtable<KeyType,ValueType,HashFunctorType> & rhs);
00385 
00389    bool operator== (const Hashtable<KeyType,ValueType,HashFunctorType> & rhs) const;
00390 
00392    bool operator!= (const Hashtable<KeyType,ValueType,HashFunctorType> & rhs) const {return !(*this == rhs);}
00393 
00399    status_t CopyFrom(const Hashtable<KeyType,ValueType,HashFunctorType> & rhs);
00400 
00402    uint32 GetNumItems() const {return _count;}
00403 
00405    bool IsEmpty() const {return (_count == 0);}
00406 
00408    bool HasItems() const {return (_count > 0);}
00409 
00411    bool ContainsKey(const KeyType& key) const {return (GetEntry(ComputeHash(key), key) != NULL);}
00412 
00414    bool ContainsValue(const ValueType& value) const;
00415 
00417    int32 IndexOfKey(const KeyType& key) const;
00418 
00427    int32 IndexOfValue(const ValueType& value, bool searchBackwards = false) const;
00428 
00434    status_t GetValue(const KeyType& key, ValueType& setValue) const; 
00435 
00442    ValueType * GetValue(const KeyType & key) const;
00443 
00451    status_t GetKey(const KeyType & lookupKey, KeyType & setKey) const;
00452 
00460    const KeyType * GetKey(const KeyType & lookupKey) const;
00461 
00467    HashtableIterator<KeyType,ValueType,HashFunctorType> GetIterator(uint32 flags = 0) const 
00468    {
00469       return HashtableIterator<KeyType,ValueType,HashFunctorType>(*this, flags); 
00470    }
00471 
00478    HashtableIterator<KeyType,ValueType,HashFunctorType> GetIteratorAt(const KeyType & startAt, uint32 flags = 0) const 
00479    {
00480       return HashtableIterator<KeyType,ValueType,HashFunctorType>(*this, startAt, flags);
00481    }
00482 
00489    const KeyType * GetKeyAt(uint32 index) const;
00490 
00498    status_t GetKeyAt(uint32 index, KeyType & retKey) const;
00499 
00509    status_t Put(const KeyType& key, const ValueType& value, ValueType & setPreviousValue, bool * optSetReplaced = NULL) {return (PutAux(ComputeHash(key), key, value, &setPreviousValue, optSetReplaced) != NULL) ? B_NO_ERROR : B_ERROR;}
00510 
00518    status_t Put(const KeyType& key, const ValueType& value) {return (PutAux(ComputeHash(key), key, value, NULL, NULL) != NULL) ? B_NO_ERROR : B_ERROR;}
00519 
00526    status_t Put(const Hashtable<KeyType, ValueType, HashFunctorType> & pairs);
00527 
00532    status_t Remove(const KeyType& key) {return RemoveAux(key, NULL);}
00533 
00539    status_t Remove(const KeyType& key, ValueType & setRemovedValue) {return RemoveAux(key, &setRemovedValue);}
00540 
00545    uint32 Remove(const Hashtable<KeyType, ValueType, HashFunctorType> & pairs);
00546 
00550    status_t RemoveFirst() {return _iterHead ? RemoveEntry(_iterHead, NULL) : B_ERROR;}
00551 
00557    status_t RemoveFirst(KeyType & setRemovedKey) 
00558    {
00559       if (_iterHead == NULL) return B_ERROR;
00560       setRemovedKey = _iterHead->_key;
00561       return RemoveEntry(_iterHead, NULL);
00562    }
00563 
00570    status_t RemoveFirst(KeyType & setRemovedKey, ValueType & setRemovedValue) 
00571    {
00572       if (_iterHead == NULL) return B_ERROR;
00573       setRemovedKey = _iterHead->_key;
00574       return RemoveEntry(_iterHead, &setRemovedValue);
00575    }
00576 
00580    status_t RemoveLast() {return _iterTail ? RemoveEntry(_iterTail, NULL) : B_ERROR;}
00581 
00587    status_t RemoveLast(KeyType & setRemovedKey) 
00588    {
00589       if (_iterTail == NULL) return B_ERROR;
00590       setRemovedKey = _iterTail->_key;
00591       return RemoveEntry(_iterTail, NULL);
00592    }
00593 
00600    status_t RemoveLast(KeyType & setRemovedKey, ValueType & setRemovedValue) 
00601    {
00602       if (_iterTail == NULL) return B_ERROR;
00603       setRemovedKey = _iterTail->_key;
00604       return RemoveEntry(_iterTail, &setRemovedValue);
00605    }
00606 
00611    void Clear(bool releaseCachedData = false);
00612 
00625    status_t Reposition(const KeyType & key);
00626 
00639    void SetAutoSortMode(int mode, bool sortNow = true) {_autoSortMode = mode; if (sortNow) (void) Sort();}
00640 
00642    int GetAutoSortMode() const {return _autoSortMode;}
00643 
00649    void SetCompareCookie(void * cookie) {_compareCookie = cookie;}
00650 
00652    void * GetCompareCookie() const {return _compareCookie;}
00653 
00661    void SetKeyCompareFunction(KeyCompareFunc func) {_userKeyCompareFunc = func;}
00662 
00664    KeyCompareFunc GetKeyCompareFunction() const {return _userKeyCompareFunc;}
00665 
00671    void SetValueCompareFunction(ValueCompareFunc func) {_userValueCompareFunc = func;}
00672 
00674    ValueCompareFunc GetValueCompareFunction() const {return _userValueCompareFunc;}
00675 
00682    void SwapContents(Hashtable<KeyType,ValueType,HashFunctorType> & swapMe);
00683 
00691    status_t MoveToFront(const KeyType & moveMe);
00692 
00700    status_t MoveToBack(const KeyType & moveMe);
00701 
00712    status_t MoveToBefore(const KeyType & moveMe, const KeyType & toBeforeMe);
00713 
00724    status_t MoveToBehind(const KeyType & moveMe, const KeyType & toBehindMe);
00725 
00733    status_t MoveToTable(const KeyType & moveMe, Hashtable<KeyType, ValueType> & toTable);
00734 
00742    status_t CopyToTable(const KeyType & copyMe, Hashtable<KeyType, ValueType> & toTable) const;
00743 
00755    status_t Sort() {return SortByAux((_autoSortMode != AUTOSORT_BY_VALUE) ? _userKeyCompareFunc : NULL, (_autoSortMode != AUTOSORT_BY_KEY) ? _userValueCompareFunc : NULL, _compareCookie);}
00756 
00762    void SortByKey(KeyCompareFunc func, void * optCompareCookie = NULL) {(void) SortByAux(func, NULL, optCompareCookie);}
00763 
00769    void SortByValue(ValueCompareFunc func, void * optCompareCookie = NULL) {(void) SortByAux(NULL, func, optCompareCookie);}
00770 
00772    status_t Get(const KeyType& key, ValueType& setValue) const {return GetValue(key, setValue);}
00773 
00775    ValueType * Get(const KeyType & key) const {return GetValue(key);}
00776 
00785    ValueType * GetOrPut(const KeyType & key, const ValueType & defValue)
00786    {
00787       uint32 hash = ComputeHash(key);
00788       HashtableEntry * e = GetEntry(hash, key);
00789       if (e == NULL) e = PutAux(hash, key, defValue, NULL, NULL);
00790       return e ? &e->_value : NULL;
00791    }
00792 
00801    ValueType * GetOrPut(const KeyType & key)
00802    {
00803       uint32 hash = ComputeHash(key);
00804       HashtableEntry * e = GetEntry(hash, key);
00805       if (e == NULL) e = PutAux(hash, key, ValueType(), NULL, NULL);
00806       return e ? &e->_value : NULL;
00807    }
00808 
00815    ValueType GetWithDefault(const KeyType & key) const
00816    {
00817       const ValueType * v = Get(key);
00818       return v ? *v : ValueType();
00819    }
00820 
00831    ValueType GetWithDefault(const KeyType & key, const ValueType & defaultValue) const
00832    {
00833       const ValueType * v = Get(key);
00834       return v ? *v : defaultValue;
00835    }
00836 
00845    ValueType * PutAndGet(const KeyType & key, const ValueType & value = ValueType()) 
00846    { 
00847        HashtableEntry * e = PutAux(ComputeHash(key), key, value, NULL, NULL);
00848        return e ? &e->_value : NULL;
00849    }
00850 
00859    ValueType * PutIfNotAlreadyPresent(const KeyType & key, const ValueType & value) 
00860    {
00861        uint32 hash = ComputeHash(key);
00862        HashtableEntry * e = GetEntry(hash, key);
00863        if (e) return NULL;
00864        else
00865        {
00866           e = PutAux(hash, key, value, NULL, NULL);
00867           return e ? &e->_value : NULL;
00868        }
00869    }
00870 
00879    ValueType * PutIfNotAlreadyPresent(const KeyType & key) 
00880    {
00881        uint32 hash = ComputeHash(key);
00882        HashtableEntry * e = GetEntry(hash, key);
00883        if (e) return NULL;
00884        else
00885        {
00886           e = PutAux(hash, key, ValueType(), NULL, NULL);
00887           return e ? &e->_value : NULL;
00888        }
00889    }
00890 
00892    const KeyType * GetFirstKey() const {return _iterHead ? &_iterHead->_key : NULL;}
00893 
00895    const KeyType * GetLastKey() const {return _iterTail ? &_iterTail->_key : NULL;}
00896 
00898    ValueType * GetFirstValue() const {return _iterHead ? &_iterHead->_value : NULL;}
00899 
00901    ValueType * GetLastValue() const {return _iterTail ? &_iterTail->_value : NULL;}
00902 
00912    status_t EnsureSize(uint32 newTableSize);
00913 
00918    uint32 GetNumAllocatedSlots() const {return _tableSize;}
00919 
00920 private:
00922    friend class HashtableIterator<KeyType, ValueType, HashFunctorType>;
00923 
00924    void InitializeIterator(HashtableIterator<KeyType,ValueType,HashFunctorType> & iter) const
00925    {
00926       RegisterIterator(&iter);
00927       iter._nextKeyCookie = iter._nextValueCookie = (iter._flags & HTIT_FLAG_BACKWARDS) ? _iterTail : _iterHead;
00928    }
00929 
00930    void InitializeIteratorAt(HashtableIterator<KeyType,ValueType,HashFunctorType> & iter, const KeyType & startAt) const
00931    {
00932       RegisterIterator(&iter);
00933       iter._nextKeyCookie = iter._nextValueCookie = GetEntry(ComputeHash(startAt), startAt);
00934    }
00935 
00936    class HashtableEntry
00937    {
00938    public:
00939       // Note:  _bucketPrev and _bucketNext are intentionally not set here
00940       HashtableEntry() : _hash(MUSCLE_HASHTABLE_INVALID_HASH_CODE), _iterPrev(NULL), _iterNext(NULL)
00941 #ifndef _MSC_VER
00942                          , _mapTo(this), _mappedFrom(this)  // this is slightly more efficient...
00943 #endif
00944       {
00945 #ifdef _MSC_VER
00946          _mapTo      = this;  // ... but VC++ complains if (this) is in the init list, so for VC++ we do it here
00947          _mappedFrom = this;
00948 #endif
00949       }
00950 
00951       ~HashtableEntry() {/* empty */}
00952 
00953       // Frees up our memory and returns us to the free-list.
00954       void ReturnToFreeList(const KeyType & defaultKey, const ValueType & defaultValue, HashtableEntry ** freeHead)
00955       {
00956          _hash  = MUSCLE_HASHTABLE_INVALID_HASH_CODE;
00957          _key   = defaultKey;
00958          _value = defaultValue;
00959 
00960          _iterPrev = _iterNext = _bucketPrev = NULL;
00961          _bucketNext = *freeHead; 
00962          if (_bucketNext) _bucketNext->_bucketPrev = this;
00963          *freeHead = this;
00964       }
00965 
00970       HashtableEntry * RemoveFromFreeList(HashtableEntry * freeHead) 
00971       {
00972          if (_bucketNext) _bucketNext->_bucketPrev = _bucketPrev;
00973          if (_bucketPrev) _bucketPrev->_bucketNext = _bucketNext;
00974          HashtableEntry * ret = (freeHead == this) ? _bucketNext : freeHead;
00975          _bucketPrev = _bucketNext = NULL;
00976          return ret;
00977       }
00978 
00979       void SwapMaps(HashtableEntry * e)
00980       {
00981          muscleSwap(e->_mapTo, _mapTo);
00982          _mapTo->_mappedFrom = this;
00983          e->_mapTo->_mappedFrom = e;
00984       }
00985 
00986       inline HashtableEntry * GetMapTo() const {return _mapTo;}
00987       inline HashtableEntry * GetMappedFrom() const {return _mappedFrom;}
00988 
00989       static HashtableEntry * CreateEntriesArray(uint32 size)
00990       {
00991          HashtableEntry * ret = newnothrow_array(HashtableEntry,size);
00992          if (ret)
00993          {
00994             HashtableEntry * prev = NULL;
00995             for (uint32 i=0; i<size; i++) 
00996             {
00997                HashtableEntry * cur = &ret[i];
00998                cur->_bucketPrev = prev;
00999                if (prev) prev->_bucketNext = cur;
01000                prev = cur;
01001             }
01002             ret[size-1]._bucketNext = NULL;
01003          }
01004          else WARN_OUT_OF_MEMORY;
01005          return ret;
01006       }
01007   
01008       uint32 _hash;                // precalculated for efficiency
01009       KeyType _key;                // used for '==' checking
01010       ValueType _value;            // payload
01011       HashtableEntry* _bucketPrev; // for making linked lists in our bucket
01012       HashtableEntry* _bucketNext; // for making linked lists in our bucket
01013       HashtableEntry* _iterPrev;   // for user's table iteration
01014       HashtableEntry* _iterNext;   // for user's table iteration
01015 
01016    private:
01017       HashtableEntry* _mapTo;
01018       HashtableEntry* _mappedFrom;
01019    };
01020 
01021 private:
01022    // Auxilliary methods
01023    HashtableEntry * PutAux(uint32 hash, const KeyType& key, const ValueType& value, ValueType * optSetPreviousValue, bool * optReplacedFlag);
01024    status_t RemoveAux(uint32 hash, const KeyType& key, ValueType * optSetValue)
01025    {
01026       HashtableEntry * e = GetEntry(hash, key);
01027       return e ? RemoveEntry(e, optSetValue) : B_ERROR;
01028    }
01029    status_t RemoveAux(const KeyType& key, ValueType * optSetValue)
01030    {
01031       HashtableEntry * e = GetEntry(ComputeHash(key), key);
01032       return e ? RemoveEntry(e, optSetValue) : B_ERROR;
01033    }
01034    status_t RemoveEntry(HashtableEntry * e, ValueType * optSetValue);
01035 
01036    status_t SortByAux(KeyCompareFunc optKeyFunc, ValueCompareFunc optValueFunc, void * cookie);
01037    void RepositionAux(HashtableEntry * e);
01038 
01039    inline uint32 ComputeHash(const KeyType & key) const
01040    {
01041       uint32 ret = _functor(key);
01042       if (ret == MUSCLE_HASHTABLE_INVALID_HASH_CODE) ret++;  // avoid using the guard value as a hash code (unlikely but possible)
01043       return ret;
01044    }
01045 
01046    // Linked list maintainence
01047    void InsertSortedIterationEntry(HashtableEntry * e, KeyCompareFunc optKeyFunc, ValueCompareFunc optValueCompareFunc, void * cookie);
01048    void InsertIterationEntry(HashtableEntry * e, HashtableEntry * optBehindThisOne);
01049    void RemoveIterationEntry(HashtableEntry * e);
01050    HashtableEntry * GetEntry(uint32 hash, const KeyType& key) const;
01051    HashtableEntry * GetEntryAt(uint32 idx) const;
01052    bool IsBucketHead(const HashtableEntry * e) const {return ((e->_hash != MUSCLE_HASHTABLE_INVALID_HASH_CODE)&&(_table[e->_hash%_tableSize].GetMapTo() == e));}
01053 
01054    int CompareEntries(const HashtableEntry & left, const HashtableEntry & right, KeyCompareFunc optKeyFunc, ValueCompareFunc optValueFunc, void * cookie) const;
01055 
01056    // HashtableIterator's private API
01057    void RegisterIterator(HashtableIterator<KeyType,ValueType,HashFunctorType> * iter) const
01058    {
01059       if (iter->_flags & HTIT_FLAG_NOREGISTER) iter->_prevIter = iter->_nextIter = NULL;
01060       else
01061       {
01062          // add him to the head of our linked list of iterators
01063          iter->_prevIter = NULL;
01064          iter->_nextIter = _iterList;  
01065          if (_iterList) _iterList->_prevIter = iter;
01066          _iterList = iter;
01067       }
01068    }
01069 
01070    void UnregisterIterator(HashtableIterator<KeyType,ValueType,HashFunctorType> * iter) const
01071    {
01072       if (iter->_flags & HTIT_FLAG_NOREGISTER) iter->_prevIter = iter->_nextIter = NULL;
01073       else
01074       {
01075          if (iter->_prevIter) iter->_prevIter->_nextIter = iter->_nextIter;
01076          if (iter->_nextIter) iter->_nextIter->_prevIter = iter->_prevIter;
01077          if (iter == _iterList) _iterList = iter->_nextIter;
01078          iter->_prevIter = iter->_nextIter = NULL;
01079       }
01080    }
01081 
01082    KeyType * GetKeyFromCookie(void * c) const {return c ? &(((HashtableEntry *)c)->_key) : NULL;}
01083    ValueType * GetValueFromCookie(void * c) const  {return c ? &(((HashtableEntry *)c)->_value) : NULL;}
01084 
01085    HashtableEntry * GetInitialEntry(uint32 flags) const {return (flags & HTIT_FLAG_BACKWARDS) ? _iterTail : _iterHead;}
01086    HashtableEntry * GetSubsequentEntry(void * entryPtr, uint32 flags) const 
01087    {
01088       HashtableEntry * ep = static_cast<HashtableEntry *>(entryPtr);
01089       return ep ? ((flags & HTIT_FLAG_BACKWARDS) ? ep->_iterPrev : ep->_iterNext) : NULL;
01090    }
01091 
01092    void MoveToBackAux(HashtableEntry * moveMe)
01093    {
01094       if (moveMe->_iterNext)
01095       {
01096          RemoveIterationEntry(moveMe);
01097          InsertIterationEntry(moveMe, _iterTail);
01098       }
01099    }
01100 
01101    void MoveToFrontAux(HashtableEntry * moveMe)
01102    {
01103       if (moveMe->_iterPrev)
01104       {
01105          RemoveIterationEntry(moveMe);
01106          InsertIterationEntry(moveMe, NULL);
01107       }
01108    }
01109 
01110    void MoveToBeforeAux(HashtableEntry * moveMe, HashtableEntry * toBeforeMe)
01111    {
01112       if (moveMe->_iterNext != toBeforeMe)
01113       {
01114          RemoveIterationEntry(moveMe);
01115          InsertIterationEntry(moveMe, toBeforeMe->_iterPrev);
01116       }
01117    }
01118 
01119    void MoveToBehindAux(HashtableEntry * moveMe, HashtableEntry * toBehindMe)
01120    {
01121       if (moveMe->_iterPrev != toBehindMe)
01122       {
01123          RemoveIterationEntry(moveMe);
01124          InsertIterationEntry(moveMe, toBehindMe);
01125       }
01126    }
01127 
01128    uint32 NextPrime(uint32 start) const;
01129 
01130    const uint32 _initialCapacity;
01131    uint32 _count;       // the number of valid elements in the hashtable
01132    uint32 _tableSize;   // the number of entries in _table (or the number to allocate if _table is NULL)
01133 
01134    HashtableEntry * _table;       // our array of table entries
01135    HashtableEntry * _iterHead;    // start of linked list to iterate through
01136    HashtableEntry * _iterTail;    // end of linked list to iterate through
01137 
01138    HashtableEntry * _freeHead;    // head of the list of unused HashtableEntries in our _table array
01139 
01140    KeyCompareFunc _userKeyCompareFunc;       // (optional) used to compare two Keys
01141    ValueCompareFunc _userValueCompareFunc;   // (optional) used to compare two Values
01142    int _autoSortMode;                        // one of the AUTOSORT_BY_* tokens
01143    void * _compareCookie;                    // (optional) passed to the CompareFuncs
01144 
01145    HashFunctorType _functor;  // used to compute hash codes for key objects
01146 
01147    mutable HashtableIterator<KeyType, ValueType, HashFunctorType> * _iterList;  // list of existing iterators for this table
01148 };
01149 
01150 //===============================================================
01151 // Implementation of Hashtable
01152 // Necessary location for appropriate template instantiation.
01153 //===============================================================
01154 
01155 template <class KeyType, class ValueType, class HashFunctorType>
01156 Hashtable<KeyType,ValueType,HashFunctorType>::Hashtable()
01157    : _initialCapacity(MUSCLE_HASHTABLE_DEFAULT_CAPACITY), _count(0), _tableSize(MUSCLE_HASHTABLE_DEFAULT_CAPACITY), _table(NULL), _iterHead(NULL), _iterTail(NULL), _freeHead(NULL), _userKeyCompareFunc(NULL), _userValueCompareFunc(NULL), _autoSortMode(AUTOSORT_DISABLED), _compareCookie(NULL), _iterList(NULL)
01158 {
01159    // empty
01160 }
01161 
01162 template <class KeyType, class ValueType, class HashFunctorType>
01163 Hashtable<KeyType,ValueType,HashFunctorType>::Hashtable(uint32 initialCapacity)
01164    : _initialCapacity(initialCapacity), _count(0), _tableSize(initialCapacity), _table(NULL), _iterHead(NULL), _iterTail(NULL), _freeHead(NULL), _userKeyCompareFunc(NULL), _userValueCompareFunc(NULL), _autoSortMode(AUTOSORT_DISABLED), _compareCookie(NULL), _iterList(NULL)
01165 {
01166    // empty
01167 }
01168 
01169 template <class KeyType, class ValueType, class HashFunctorType>
01170 Hashtable<KeyType,ValueType,HashFunctorType>::
01171 Hashtable(const Hashtable<KeyType,ValueType,HashFunctorType> & rhs)
01172    : _initialCapacity(rhs._initialCapacity), _count(0), _tableSize(rhs._tableSize), _table(NULL), _iterHead(NULL), _iterTail(NULL), _freeHead(NULL), _userKeyCompareFunc(rhs._userKeyCompareFunc), _userValueCompareFunc(rhs._userValueCompareFunc), _autoSortMode(rhs._autoSortMode), _compareCookie(rhs._compareCookie), _iterList(NULL)
01173 {
01174    *this = rhs;
01175 }
01176 
01177 template <class KeyType, class ValueType, class HashFunctorType>
01178 Hashtable<KeyType, ValueType, HashFunctorType> &
01179 Hashtable<KeyType, ValueType, HashFunctorType> ::
01180 operator=(const Hashtable<KeyType, ValueType, HashFunctorType> & rhs)
01181 {
01182    if (this != &rhs)
01183    {
01184       Clear();
01185       if (EnsureSize(rhs.GetNumItems()) == B_NO_ERROR)
01186       {
01187          const HashtableEntry * e = rhs._iterHead;    // start of linked list to iterate through
01188          while(e)
01189          {
01190             (void) PutAux(e->_hash, e->_key, e->_value, NULL, NULL);
01191             e = e->_iterNext;
01192          }
01193       }
01194    }
01195    return *this;
01196 }
01197 
01198 template <class KeyType, class ValueType, class HashFunctorType>
01199 status_t
01200 Hashtable<KeyType, ValueType, HashFunctorType> ::
01201 CopyFrom(const Hashtable<KeyType, ValueType, HashFunctorType> & rhs)
01202 {
01203    if (this == &rhs) return B_NO_ERROR;
01204 
01205    Clear();
01206    if (EnsureSize(rhs.GetNumItems()) != B_NO_ERROR) return B_ERROR;
01207 
01208    const HashtableEntry * e = rhs._iterHead;    // start of linked list to iterate through
01209    while(e)
01210    {
01211       (void) PutAux(e->_hash, e->_key, e->_value, NULL, NULL);
01212       e = e->_iterNext;
01213    }
01214    return B_NO_ERROR;
01215 }
01216 
01217 template <class KeyType, class ValueType, class HashFunctorType>
01218 bool
01219 Hashtable<KeyType, ValueType, HashFunctorType> ::
01220 operator==(const Hashtable<KeyType, ValueType, HashFunctorType> & rhs) const
01221 {
01222    if (this == &rhs) return true;
01223    if (GetNumItems() != rhs.GetNumItems()) return false;
01224 
01225    const HashtableEntry * e = _iterHead;
01226    while(e)
01227    {
01228       const HashtableEntry * hisE = rhs.GetEntry(e->_hash, e->_key);
01229       if ((hisE == NULL)||(hisE->_value != e->_value)) return false;
01230       e = e->_iterNext;
01231    }
01232    return true;
01233 }
01234 
01235 template <class KeyType, class ValueType, class HashFunctorType>
01236 Hashtable<KeyType,ValueType,HashFunctorType>::~Hashtable()
01237 {
01238    Clear(true);
01239 }
01240 
01241 template <class KeyType, class ValueType, class HashFunctorType>
01242 bool
01243 Hashtable<KeyType,ValueType,HashFunctorType>::ContainsValue(const ValueType & value) const
01244 {
01245    const HashtableEntry * e = _iterHead;
01246    while(e)
01247    {
01248       if (e->_value == value) return true;
01249       e = e->_iterNext;
01250    }
01251    return false;
01252 }
01253 
01254 template <class KeyType, class ValueType, class HashFunctorType>
01255 int32
01256 Hashtable<KeyType,ValueType,HashFunctorType>::IndexOfKey(const KeyType& key) const
01257 {
01258    const HashtableEntry * entry = GetEntry(ComputeHash(key), key);
01259    int32 count = -1;
01260    if (entry)
01261    {
01262       if (entry == _iterTail) count = GetNumItems()-1;
01263       else
01264       {
01265          while(entry)
01266          {
01267             entry = entry->_iterPrev; 
01268             count++;
01269          }
01270       }
01271    }
01272    return count;
01273 }
01274 
01275 template <class KeyType, class ValueType, class HashFunctorType>
01276 int32
01277 Hashtable<KeyType,ValueType,HashFunctorType>::IndexOfValue(const ValueType& value, bool searchBackwards) const
01278 {
01279    if (searchBackwards)
01280    {
01281       int32 idx = GetNumItems();
01282       const HashtableEntry * entry = _iterTail;
01283       while(entry)
01284       {
01285          --idx;
01286          if (entry->_value == value) return idx;
01287          entry = entry->_iterPrev;
01288       }
01289    }
01290    else
01291    {
01292       int32 idx = 0;
01293       const HashtableEntry * entry = _iterHead;
01294       while(entry)
01295       {
01296          if (entry->_value == value) return idx;
01297          entry = entry->_iterNext;
01298          idx++;
01299       }
01300    }
01301    return -1;
01302 }
01303 
01304 template <class KeyType, class ValueType, class HashFunctorType>
01305 const KeyType * 
01306 Hashtable<KeyType,ValueType,HashFunctorType>::GetKeyAt(uint32 index) const
01307 {
01308    HashtableEntry * e = GetEntryAt(index);
01309    return e ? &e->_key : NULL;
01310 }
01311 
01312 template <class KeyType, class ValueType, class HashFunctorType>
01313 status_t 
01314 Hashtable<KeyType,ValueType,HashFunctorType>::GetKeyAt(uint32 index, KeyType & retKey) const
01315 {
01316    HashtableEntry * e = GetEntryAt(index);
01317    if (e)
01318    {
01319       retKey = e->_key;
01320       return B_NO_ERROR;
01321    }
01322    return B_ERROR;
01323 }
01324 
01325 template <class KeyType, class ValueType, class HashFunctorType>
01326 status_t
01327 Hashtable<KeyType,ValueType,HashFunctorType>::GetValue(const KeyType& key, ValueType & setValue) const
01328 {
01329    ValueType * ptr = GetValue(key);
01330    if (ptr)
01331    {
01332       setValue = *ptr;
01333       return B_NO_ERROR;
01334    }
01335    else return B_ERROR;
01336 }
01337 
01338 template <class KeyType, class ValueType, class HashFunctorType>
01339 ValueType *
01340 Hashtable<KeyType,ValueType,HashFunctorType>::GetValue(const KeyType& key) const
01341 {
01342    HashtableEntry * e = GetEntry(ComputeHash(key), key);
01343    return e ? &e->_value : NULL;
01344 }
01345 
01346 template <class KeyType, class ValueType, class HashFunctorType>
01347 const KeyType * 
01348 Hashtable<KeyType,ValueType,HashFunctorType>::GetKey(const KeyType& lookupKey) const
01349 {
01350    HashtableEntry * e = GetEntry(ComputeHash(lookupKey), lookupKey);
01351    return e ? &e->_key : NULL;
01352 }
01353 
01354 template <class KeyType, class ValueType, class HashFunctorType>
01355 status_t
01356 Hashtable<KeyType,ValueType,HashFunctorType>::GetKey(const KeyType& lookupKey, KeyType & setKey) const
01357 {
01358    const KeyType * ptr = GetKey(lookupKey);
01359    if (ptr)
01360    {
01361       setKey = *ptr;
01362       return B_NO_ERROR;
01363    }
01364    else return B_ERROR;
01365 }
01366 
01367 template <class KeyType, class ValueType, class HashFunctorType>
01368 typename Hashtable<KeyType,ValueType,HashFunctorType>::HashtableEntry *
01369 Hashtable<KeyType,ValueType,HashFunctorType>::GetEntry(uint32 hash, const KeyType& key) const
01370 {
01371    if (HasItems()) 
01372    {
01373       HashtableEntry * e = _table[hash%_tableSize].GetMapTo();
01374       if (IsBucketHead(e))  // if the e isn't the start of a bucket, then we know our entry doesn't exist
01375       {
01376          // While loops separated out for efficiency (one less if statement) --jaf
01377          if (_userKeyCompareFunc)
01378          {
01379             while(e)
01380             {
01381                if ((e->_hash == hash)&&(_userKeyCompareFunc(e->_key, key, _compareCookie) == 0)) return e;
01382                e = e->_bucketNext; 
01383             }
01384          }
01385          else
01386          {
01387             while(e)
01388             {
01389                if ((e->_hash == hash)&&(e->_key == key)) return e;
01390                e = e->_bucketNext; 
01391             }
01392          }
01393       }
01394    }
01395    return NULL;
01396 }
01397 
01398 template <class KeyType, class ValueType, class HashFunctorType>
01399 typename Hashtable<KeyType,ValueType,HashFunctorType>::HashtableEntry *
01400 Hashtable<KeyType,ValueType,HashFunctorType>::GetEntryAt(uint32 idx) const
01401 {
01402    HashtableEntry * e = NULL;
01403    if (idx < _count)
01404    {
01405       if (idx < _count/2)
01406       {
01407          e = _iterHead;
01408          while((e)&&(idx--)) e = e->_iterNext;
01409       }
01410       else
01411       {
01412          idx = _count-(idx+1);
01413          e = _iterTail;
01414          while((e)&&(idx--)) e = e->_iterPrev;
01415       }
01416    }
01417    return e;
01418 }
01419 
01420 template <class KeyType, class ValueType, class HashFunctorType>
01421 int
01422 Hashtable<KeyType,ValueType,HashFunctorType>::CompareEntries(const HashtableEntry & left, const HashtableEntry & right, KeyCompareFunc optKeyFunc, ValueCompareFunc optValueFunc, void * cookie) const
01423 {
01424    return optValueFunc ? optValueFunc(left._value, right._value, cookie) : (optKeyFunc ? optKeyFunc(left._key, right._key, cookie) : 0);
01425 }
01426 
01427 // Linked-list MergeSort adapted from Simon Tatham's C code at http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c
01428 template <class KeyType, class ValueType, class HashFunctorType>
01429 status_t 
01430 Hashtable<KeyType,ValueType,HashFunctorType>::SortByAux(KeyCompareFunc optKeyFunc, ValueCompareFunc optValueFunc, void * cookie)
01431 {
01432    if ((optKeyFunc)||(optValueFunc))
01433    {
01434       if (_iterHead)
01435       {
01436          for (uint32 mergeSize = 1; /* empty */; mergeSize *= 2)
01437          {
01438             HashtableEntry * p = _iterHead;
01439             _iterHead = _iterTail = NULL;
01440 
01441             uint32 numMerges = 0;  /* count number of merges we do in this pass */
01442             while(p) 
01443             {
01444                numMerges++;  /* there exists a merge to be done */
01445 
01446                /* step `mergeSize' places along from p */
01447                HashtableEntry * q = p;
01448                uint32 psize = 0;
01449                for (uint32 i=0; i<mergeSize; i++) 
01450                {
01451                    psize++;
01452                    q = q->_iterNext;
01453                    if (!q) break;
01454                }
01455 
01456                /* now we have two lists; merge them */
01457                for (uint32 qsize=mergeSize; ((psize > 0)||((qsize > 0)&&(q))); /* empty */) 
01458                {
01459                   HashtableEntry * e;
01460 
01461                   /* decide whether next element of the merge comes from p or q */
01462                        if (psize == 0)                                                {e = q; q = q->_iterNext; qsize--;}
01463                   else if ((qsize == 0)||(!q))                                        {e = p; p = p->_iterNext; psize--;}
01464                   else if (CompareEntries(*p,*q,optKeyFunc,optValueFunc,cookie) <= 0) {e = p; p = p->_iterNext; psize--;}
01465                   else                                                                {e = q; q = q->_iterNext; qsize--;}
01466 
01467                   /* append to our new more-sorted list */
01468                   if (_iterTail) _iterTail->_iterNext = e;
01469                             else _iterHead = e;
01470                   e->_iterPrev = _iterTail;
01471                   _iterTail = e;
01472                }
01473 
01474                p = q; /* now p has stepped `mergeSize' places along, and q has too */
01475             }
01476             _iterTail->_iterNext = NULL;
01477             if (numMerges <= 1) return B_NO_ERROR;
01478          }
01479       }
01480       return B_NO_ERROR;  // it's easy to sort an empty list :^)
01481    }
01482    return B_ERROR;
01483 }
01484 
01485 template <class KeyType, class ValueType, class HashFunctorType>
01486 status_t
01487 Hashtable<KeyType,ValueType,HashFunctorType>::EnsureSize(uint32 requestedSize)
01488 {
01489    if (_tableSize >= requestedSize) return B_NO_ERROR;  // no need to do anything if we're already big enough!
01490 
01491    // 1. Initialize the scratch space for our active iterators.
01492    {
01493       HashtableIterator<KeyType,ValueType,HashFunctorType> * nextIter = _iterList;
01494       while(nextIter)
01495       {
01496          nextIter->_scratchSpace[0] = nextIter->_scratchSpace[1] = NULL;  // these will hold our switch-to-on-success values
01497          nextIter = nextIter->_nextIter;
01498       }
01499    }
01500     
01501    // 2. Create a new, bigger table, and fill it with a copy of all of our data.
01502    Hashtable<KeyType,ValueType,HashFunctorType> biggerTable(NextPrime(muscleMax(_count, requestedSize)));
01503    biggerTable.SetKeyCompareFunction(_userKeyCompareFunc);
01504    biggerTable.SetValueCompareFunction(_userValueCompareFunc);
01505    biggerTable.SetCompareCookie(_compareCookie);
01506    biggerTable.SetAutoSortMode(_autoSortMode);
01507    {
01508       HashtableEntry * next = _iterHead;
01509       while(next)
01510       {
01511          HashtableEntry * hisClone = biggerTable.PutAux(next->_hash, next->_key, next->_value, NULL, NULL);
01512          if (hisClone)
01513          {
01514             // Mark any iterators that will need to be redirected to point to the new nodes.
01515             HashtableIterator<KeyType,ValueType,HashFunctorType> * nextIter = _iterList;
01516             while(nextIter)
01517             {
01518                if (nextIter->_nextKeyCookie   == next) nextIter->_scratchSpace[0] = hisClone;
01519                if (nextIter->_nextValueCookie == next) nextIter->_scratchSpace[1] = hisClone;
01520                nextIter = nextIter->_nextIter;
01521             }
01522          }
01523          else return B_ERROR;  // oops, out of mem, too bad.  
01524 
01525          next = next->_iterNext;
01526       }
01527    }
01528 
01529    // 3. Swap contents with the bigger table, but don't swap iterator lists (we want to keep ours!)
01530    {
01531       HashtableIterator<KeyType,ValueType,HashFunctorType> * temp = _iterList;
01532       _iterList = NULL;
01533       SwapContents(biggerTable);
01534       _iterList = temp;
01535    }
01536 
01537    // 4. Lastly, fix up our iterators to point to their new entries.
01538    {
01539       HashtableIterator<KeyType,ValueType,HashFunctorType> * nextIter = _iterList;
01540       while(nextIter)
01541       {
01542          nextIter->_nextKeyCookie   = nextIter->_scratchSpace[0];
01543          nextIter->_nextValueCookie = nextIter->_scratchSpace[1];
01544          nextIter = nextIter->_nextIter;
01545       }
01546    }
01547 
01548    return B_NO_ERROR;
01549 }
01550 
01551 template <class KeyType, class ValueType, class HashFunctorType>
01552 void
01553 Hashtable<KeyType,ValueType,HashFunctorType>::SwapContents(Hashtable<KeyType,ValueType,HashFunctorType> & swapMe)
01554 {
01555    muscleSwap(_count,                swapMe._count);
01556    muscleSwap(_tableSize,            swapMe._tableSize);
01557    muscleSwap(_table,                swapMe._table);
01558    muscleSwap(_iterHead,             swapMe._iterHead);
01559    muscleSwap(_iterTail,             swapMe._iterTail);
01560    muscleSwap(_freeHead,             swapMe._freeHead);
01561    muscleSwap(_userKeyCompareFunc,   swapMe._userKeyCompareFunc);
01562    muscleSwap(_userValueCompareFunc, swapMe._userValueCompareFunc);
01563    muscleSwap(_autoSortMode,         swapMe._autoSortMode);
01564    muscleSwap(_compareCookie,        swapMe._compareCookie);
01565    muscleSwap(_iterList,             swapMe._iterList);
01566 
01567    // Lastly, swap the owners of all iterators, so that they will unregister from the correct table when they die
01568    {
01569       HashtableIterator<KeyType,ValueType,HashFunctorType> * next = _iterList;
01570       while(next)
01571       {
01572          next->_owner = &swapMe;
01573          next = next->_nextIter;
01574       }
01575    }
01576    {
01577       HashtableIterator<KeyType,ValueType,HashFunctorType> * next = swapMe._iterList;
01578       while(next)
01579       {
01580          next->_owner = this;
01581          next = next->_nextIter;
01582       }
01583    }
01584 }
01585 
01586 template <class KeyType, class ValueType, class HashFunctorType>
01587 status_t 
01588 Hashtable<KeyType,ValueType,HashFunctorType>::CopyToTable(const KeyType & copyMe, Hashtable<KeyType, ValueType> & toTable) const
01589 {
01590    uint32 hash = ComputeHash(copyMe);
01591    const HashtableEntry * e = GetEntry(hash, copyMe);
01592    if (e)
01593    { 
01594       if (this == &toTable) return B_NO_ERROR;  // it's already here!
01595       if (toTable.PutAux(hash, copyMe, e->_value, NULL, NULL) != NULL) return B_NO_ERROR;
01596    }
01597    return B_ERROR;
01598 }
01599 
01600 template <class KeyType, class ValueType, class HashFunctorType>
01601 status_t 
01602 Hashtable<KeyType,ValueType,HashFunctorType>::MoveToTable(const KeyType & moveMe, Hashtable<KeyType, ValueType> & toTable)
01603 {
01604    uint32 hash = ComputeHash(moveMe);
01605    const HashtableEntry * e = GetEntry(hash, moveMe);
01606    if (e)
01607    {
01608       if (this == &toTable) return B_NO_ERROR;  // it's already here!
01609       if (toTable.PutAux(hash, moveMe, e->_value, NULL, NULL) != NULL) return RemoveAux(e->_hash, moveMe, NULL);
01610    }
01611    return B_ERROR;
01612 }
01613 
01614 template <class KeyType, class ValueType, class HashFunctorType>
01615 status_t 
01616 Hashtable<KeyType,ValueType,HashFunctorType>::MoveToFront(const KeyType & moveMe)
01617 {
01618    HashtableEntry * e = GetEntry(ComputeHash(moveMe), moveMe);
01619    if (e == NULL) return B_ERROR;
01620    MoveToFrontAux(e);
01621    return B_NO_ERROR;
01622 }
01623 
01624 template <class KeyType, class ValueType, class HashFunctorType>
01625 status_t 
01626 Hashtable<KeyType,ValueType,HashFunctorType>::MoveToBack(const KeyType & moveMe)
01627 {
01628    HashtableEntry * e = GetEntry(ComputeHash(moveMe), moveMe);
01629    if (e == NULL) return B_ERROR;
01630    MoveToBackAux(e);
01631    return B_NO_ERROR;
01632 }
01633 
01634 template <class KeyType, class ValueType, class HashFunctorType>
01635 status_t 
01636 Hashtable<KeyType,ValueType,HashFunctorType>::MoveToBefore(const KeyType & moveMe, const KeyType & toBeforeMe)
01637 {
01638    if (HasItems())
01639    {
01640       HashtableEntry * e = GetEntry(ComputeHash(moveMe),     moveMe);
01641       HashtableEntry * f = GetEntry(ComputeHash(toBeforeMe), toBeforeMe);
01642       if ((e == NULL)||(f == NULL)||(e == f)) return B_ERROR;
01643       MoveToBeforeAux(e, f);
01644       return B_NO_ERROR;
01645    }
01646    else return B_ERROR;
01647 }
01648 
01649 template <class KeyType, class ValueType, class HashFunctorType>
01650 status_t 
01651 Hashtable<KeyType,ValueType,HashFunctorType>::MoveToBehind(const KeyType & moveMe, const KeyType & toBehindMe)
01652 {
01653    if (HasItems())
01654    {
01655       HashtableEntry * d = GetEntry(ComputeHash(toBehindMe), toBehindMe);
01656       HashtableEntry * e = GetEntry(ComputeHash(moveMe),     moveMe);
01657       if ((d == NULL)||(e == NULL)||(d == e)) return B_ERROR;
01658       MoveToBehindAux(e, d);
01659       return B_NO_ERROR;
01660    }
01661    else return B_ERROR;
01662 }
01663 
01664 // Adds (e) to the end of our iteration linked list, or to an appropriate location to maintain sorting, if a sorting function is specified.
01665 template <class KeyType, class ValueType, class HashFunctorType>
01666 void
01667 Hashtable<KeyType,ValueType,HashFunctorType>::InsertSortedIterationEntry(HashtableEntry * e, KeyCompareFunc optKeyFunc, ValueCompareFunc optValueFunc, void * cookie)
01668 {
01669    HashtableEntry * insertAfter = _iterTail;  // default to appending to the end of the list
01670    if ((_iterHead)&&((optKeyFunc)||(optValueFunc)))
01671    {
01672       // We're in sorted mode, so we'll try to place this guy in the correct position.
01673            if (CompareEntries(*e, *_iterHead, optKeyFunc, optValueFunc, cookie) < 0) insertAfter = NULL;  // easy; append to the head of the list
01674       else if (CompareEntries(*e, *_iterTail, optKeyFunc, optValueFunc, cookie) < 0)  // only iterate through if we're before the tail, otherwise the tail is fine
01675       {
01676          HashtableEntry * prev = _iterHead;
01677          HashtableEntry * next = _iterHead->_iterNext;  // more difficult;  find where to insert into the middle
01678          while(next)
01679          {
01680             if (CompareEntries(*e, *next, optKeyFunc, optValueFunc, cookie) < 0)
01681             {
01682                insertAfter = prev;
01683                break;
01684             }
01685             else 
01686             {
01687                prev = next;
01688                next = next->_iterNext;
01689             }
01690          }   
01691       }
01692    }
01693    InsertIterationEntry(e, insertAfter);
01694 }
01695 
01696 // Adds (e) to the our iteration linked list, behind (optBehindThis), or at the head if (optBehindThis) is NULL.
01697 template <class KeyType, class ValueType, class HashFunctorType>
01698 void
01699 Hashtable<KeyType,ValueType,HashFunctorType>::InsertIterationEntry(HashtableEntry * e, HashtableEntry * optBehindThis)
01700 {
01701    e->_iterPrev = optBehindThis;
01702    e->_iterNext = optBehindThis ? optBehindThis->_iterNext : _iterHead;
01703    if (e->_iterPrev) e->_iterPrev->_iterNext = e;
01704                 else _iterHead = e;
01705    if (e->_iterNext) e->_iterNext->_iterPrev = e;
01706                 else _iterTail = e;
01707 }
01708 
01709 // Remove (e) from our iteration linked list
01710 template <class KeyType, class ValueType, class HashFunctorType>
01711 void 
01712 Hashtable<KeyType,ValueType,HashFunctorType>::RemoveIterationEntry(HashtableEntry * e)
01713 {
01714    // Update any iterators that were pointing at (e), so that they now point to the entry after e.
01715    HashtableIterator<KeyTyp