/*- * Copyright 2005 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #ifndef holH #define holH //--------------------------------------------------------------------------- namespace ksys { //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- template< typename T> class HashedObjectListKey { public: ~HashedObjectListKey(); HashedObjectListKey(); HashedObjectListKey(const T & key); HashedObjectListKey(const HashedObjectListKey< T> & key); HashedObjectListKey< T> & operator =(const T & key); HashedObjectListKey< T> & operator =(const HashedObjectListKey< T> & key); bool hashKeyEqu(const HashedObjectListKey< T> & key, bool) const; uintptr_t hash(bool) const; protected: private: T key_; }; //--------------------------------------------------------------------------- template< typename T> inline HashedObjectListKey< T>::~HashedObjectListKey() { } //--------------------------------------------------------------------------- template< typename T> inline HashedObjectListKey< T>::HashedObjectListKey() { } //--------------------------------------------------------------------------- template< typename T> inline HashedObjectListKey< T>::HashedObjectListKey(const T & key) : key_(key) { } //--------------------------------------------------------------------------- template< typename T> inline HashedObjectListKey< T>::HashedObjectListKey(const HashedObjectListKey< T> & key) : key_(key.key_) { } //--------------------------------------------------------------------------- template< typename T> inline HashedObjectListKey< T> & HashedObjectListKey::operator =(const T & key) { key_ = key; return *this; } //--------------------------------------------------------------------------- template< typename T> inline HashedObjectListKey< T> & HashedObjectListKey::operator =(const HashedObjectListKey< T> & key) { key_ = key.key_; return *this; } //--------------------------------------------------------------------------- template< typename T> inline bool HashedObjectListKey< T>::hashKeyEqu(const HashedObjectListKey< T> & key, bool) const { return memcmp(&key_, &key.key_, sizeof(key_)) == 0; } //--------------------------------------------------------------------------- template< typename T> inline uintptr_t HashedObjectListKey< T>::hash(bool) const { return HF::hash((void *) &key_, sizeof(key_), 0); } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- enum HashChainType { hctKey, hctObject, hctIndex }; //--------------------------------------------------------------------------- template< class TKey,class TObj> class HashedObjectListItem { public: ~HashedObjectListItem(); HashedObjectListItem() {} HashedObjectListItem(const TKey & key, TObj * object, uintptr_t index); HashedObjectListItem< TKey,TObj> ** next() const; TKey & key() const; HashedObjectListItem< TKey,TObj> *& keyNext() const; HashedObjectListItem< TKey,TObj> & keyNext(HashedObjectListItem< TKey,TObj> * keyNextA); HashedObjectListItem< TKey,TObj> *& objectNext() const; HashedObjectListItem< TKey,TObj> & objectNext(HashedObjectListItem< TKey,TObj> * objectNextA); HashedObjectListItem< TKey,TObj> *& indexNext() const; HashedObjectListItem< TKey,TObj> & indexNext(HashedObjectListItem< TKey,TObj> * indexNextA); HashedObjectListItem< TKey,TObj> & key(const TKey & keyA); TObj *& object() const; HashedObjectListItem< TKey,TObj> & object(TObj * objectA); const uintptr_t & index() const; HashedObjectListItem< TKey,TObj> & index(uintptr_t indexA); protected: private: HashedObjectListItem(const HashedObjectListItem< TKey,TObj> &){} void operator =(const HashedObjectListItem< TKey,TObj> &){} #if _MSC_VER #pragma warning(push,3) #endif union { mutable HashedObjectListItem< TKey,TObj> * next_[3]; struct { mutable HashedObjectListItem< TKey,TObj> * keyNext_; mutable HashedObjectListItem< TKey,TObj> * objectNext_; mutable HashedObjectListItem< TKey,TObj> * indexNext_; }; }; #if _MSVC_VER #pragma warning(pop) #endif mutable TKey key_; mutable TObj * object_; mutable uintptr_t index_; }; //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj>::~HashedObjectListItem() { } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj>::HashedObjectListItem(const TKey & key, TObj * object, uintptr_t index) : keyNext_(NULL), objectNext_(NULL), indexNext_(NULL), key_(key), object_(object), index_(index) { } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> ** HashedObjectListItem< TKey,TObj>::next() const { return next_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> *& HashedObjectListItem< TKey,TObj>::keyNext() const { return keyNext_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> & HashedObjectListItem< TKey,TObj>::keyNext(HashedObjectListItem< TKey,TObj> * keyNextA) { keyNext_ = keyNextA; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> *& HashedObjectListItem< TKey,TObj>::objectNext() const { return objectNext_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> & HashedObjectListItem< TKey,TObj>::objectNext(HashedObjectListItem< TKey,TObj> * objectNextA) { objectNext_ = objectNextA; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> *& HashedObjectListItem< TKey,TObj>::indexNext() const { return indexNext_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> & HashedObjectListItem< TKey,TObj>::indexNext(HashedObjectListItem< TKey,TObj> * indexNextA) { indexNext_ = indexNextA; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TKey & HashedObjectListItem< TKey,TObj>::key() const { return key_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> & HashedObjectListItem< TKey,TObj>::key(const TKey & keyA) { key_ = keyA; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj *& HashedObjectListItem< TKey,TObj>::object() const { return object_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> & HashedObjectListItem< TKey,TObj>::object(TObj * objectA) { object_ = objectA; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline const uintptr_t & HashedObjectListItem< TKey,TObj>::index() const { return index_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> & HashedObjectListItem< TKey,TObj>::index(uintptr_t indexA) { index_ = indexA; return *this; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- template< class TKey,class TObj> class HashedObjectListHash { public: ~HashedObjectListHash(); HashedObjectListHash(uintptr_t slotCount = 1); HashedObjectListItem< TKey,TObj> ** find(const TKey & key, bool caseSensitive) const; HashedObjectListItem< TKey,TObj> ** find(const TObj * object) const; HashedObjectListItem< TKey,TObj> ** find(const uintptr_t index) const; uintptr_t maxChainLength(HashChainType chain) const; uintptr_t minChainLength(HashChainType chain) const; uintptr_t avgChainLength(HashChainType chain) const; HashedObjectListHash< TKey,TObj> & resize(uintptr_t slotCount); HashedObjectListItem< TKey,TObj> ** const & slots() const; HashedObjectListHash< TKey,TObj> & slots(HashedObjectListItem< TKey,TObj> ** slotsA); const uintptr_t & slotCount() const; HashedObjectListHash< TKey,TObj> & slotCount(uintptr_t slotCountA); protected: private: HashedObjectListHash(const HashedObjectListHash< TKey,TObj> &){} void operator =(const HashedObjectListHash< TKey,TObj> &){} HashedObjectListItem< TKey,TObj> ** slots_; uintptr_t slotCount_; }; //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListHash< TKey,TObj>::~HashedObjectListHash() { xfree(slots_); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListHash< TKey,TObj>::HashedObjectListHash(uintptr_t slotCount) : slots_(NULL), slotCount_(0) { resize(slotCount); } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif uintptr_t HashedObjectListHash< TKey,TObj>::maxChainLength(HashChainType chain) const { uintptr_t max = 0, m ; for( intptr_t i = slotCount_ - 1; i >= 0; i-- ){ HashedObjectListItem< TKey,TObj> ** p; for( m = 0, p = slots_ + i; *p != NULL; p = &(*p)->next()[chain], m++ ); if( m > max ) max = m; } return max; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif uintptr_t HashedObjectListHash< TKey,TObj>::minChainLength(HashChainType chain) const { uintptr_t min = ~(uintptr_t) 0, m ; for( intptr_t i = slotCount_ - 1; i >= 0; i-- ){ HashedObjectListItem< TKey,TObj> ** p; for( m = 0, p = slots_ + i; *p != NULL; p = &(*p)->next()[chain], m++ ); if( m < min ) min = m; } return min; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif uintptr_t HashedObjectListHash< TKey,TObj>::avgChainLength(HashChainType chain) const { uintptr_t avg = 0, m ; for( intptr_t i = slotCount_ - 1; i >= 0; i-- ){ HashedObjectListItem< TKey,TObj> ** p; for( m = 0, p = slots_ + i; *p != NULL; p = &(*p)->next()[chain], m++ ); avg += m; } return slotCount_ > 0 ? avg / slotCount_ : 0; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectListHash< TKey,TObj> & HashedObjectListHash< TKey,TObj>::resize(uintptr_t slotCount) { xrealloc(slots_, sizeof(HashedObjectListItem< TKey,TObj>) * slotCount); while( slotCount_ < slotCount ) slots_[slotCount_++] = NULL; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectListItem< TKey,TObj> ** HashedObjectListHash< TKey,TObj>::find(const TKey & key, bool caseSensitive) const { HashedObjectListItem< TKey,TObj> ** pItem; pItem = slots_ + (key.hash(caseSensitive) & (slotCount_ - 1)); while( *pItem != NULL ){ if( key.hashKeyEqu((*pItem)->key(), caseSensitive) ) break; pItem = &(*pItem)->keyNext(); } return pItem; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectListItem< TKey,TObj> ** HashedObjectListHash< TKey,TObj>::find(const TObj * object) const { HashedObjectListItem< TKey,TObj> ** pItem = slots_ + (HF::hash(uintptr_t(object)) & (slotCount_ - 1)); while( *pItem != NULL ){ if( object == (*pItem)->object() ) break; pItem = &(*pItem)->objectNext(); } return pItem; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectListItem< TKey,TObj> ** HashedObjectListHash< TKey,TObj>::find(const uintptr_t index) const { HashedObjectListItem< TKey,TObj> ** pItem = slots_ + (HF::hash(index) & (slotCount_ - 1)); while( *pItem != NULL ){ if( index == (*pItem)->index() ) break; pItem = &(*pItem)->indexNext(); } return pItem; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> ** const & HashedObjectListHash< TKey,TObj>::slots() const { return slots_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListHash< TKey,TObj> & HashedObjectListHash< TKey,TObj>::slots(HashedObjectListItem< TKey,TObj> ** slotsA) { slots_ = slotsA; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline const uintptr_t & HashedObjectListHash< TKey,TObj>::slotCount() const { return slotCount_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListHash< TKey,TObj> & HashedObjectListHash< TKey,TObj>::slotCount(uintptr_t slotCountA) { slotCount_ = slotCountA; return *this; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- template< class TKey,class TObj> class HashedObjectList { public: ~HashedObjectList(); HashedObjectList(); TObj * operator[](intptr_t i) const; TObj * operator[](uintptr_t i) const; HashedObjectList< TKey,TObj> & clear(); HashedObjectList< TKey,TObj> & assign(const HashedObjectList< TKey,TObj> & source); HashedObjectList< TKey,TObj> & transplant(HashedObjectList< TKey,TObj> & donor); uintptr_t add(TObj * object, const TKey & key, HashedObjectListItem< TKey,TObj> ** pItem = NULL,bool throwIfExist = true); HashedObjectList< TKey,TObj> & removeByKey(const TKey & key); HashedObjectList< TKey,TObj> & removeByObject(TObj * object); HashedObjectList< TKey,TObj> & removeByIndex(uintptr_t index); TObj * extractByKey(const TKey & key); TObj * extractByObject(TObj * object); TObj * extractByIndex(uintptr_t index); uintptr_t indexOfObject(TObj * object) const; uintptr_t indexOfKey(const TKey & key) const; TKey keyOfObject(TObj * object) const; TKey keyOfIndex(uintptr_t Index) const; TObj * objectOfKey(const TKey & key) const; TObj * objectOfIndex(uintptr_t index) const; HashedObjectListItem< TKey,TObj> * itemOfKey(const TKey & key) const; HashedObjectListItem< TKey,TObj> * itemOfObject(TObj * key) const; HashedObjectListItem< TKey,TObj> * itemOfIndex(uintptr_t index) const; HashedObjectList< TKey,TObj> & changeKey(const TKey & oldKey, const TKey & newKey); HashedObjectList< TKey,TObj> & changeObject(TObj * oldObject, TObj * newObject); HashedObjectList< TKey,TObj> & changeIndex(uintptr_t oldIndex, uintptr_t newIndex); HashedObjectList< TKey,TObj> & transplantByKey(HashedObjectList< TKey,TObj> & donor, const TKey & key); HashedObjectList< TKey,TObj> & transplantByObject(HashedObjectList< TKey,TObj> & donor, TObj * object); HashedObjectList< TKey,TObj> & transplantByIndex(HashedObjectList< TKey,TObj> & donor, uintptr_t index); const bool & ownsObjects() const; HashedObjectList< TKey,TObj> & ownsObjects(bool ownsObjects); const bool & caseSensitive() const; HashedObjectList< TKey,TObj> & caseSensitive(bool caseSensitive); const uintptr_t & count() const; uintptr_t maxChainLength(HashChainType chain) const; uintptr_t minChainLength(HashChainType chain) const; uintptr_t avgChainLength(HashChainType chain) const; protected: HashedObjectListHash< TKey,TObj> keyHash_; HashedObjectListHash< TKey,TObj> objectHash_; HashedObjectListHash< TKey,TObj> indexHash_; uintptr_t count_; bool ownsObjects_; bool caseSensitive_; void clearHash(); void reHash(uintptr_t slotCount); void renumeration(uintptr_t index); uintptr_t addHelper(HashedObjectListItem< TKey,TObj> * & item,bool throwIfExists); private: HashedObjectList(const HashedObjectList< TKey,TObj> &){} void operator =(const HashedObjectList< TKey,TObj> &){} }; //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj>::~HashedObjectList() { clear(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectList< TKey,TObj>::HashedObjectList() : count_(0), ownsObjects_(true), caseSensitive_(true) { } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList::operator[](intptr_t i) const { assert((uintptr_t) i < count_); return objectOfIndex(i); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList::operator[](uintptr_t i) const { assert(i < count_); return objectOfIndex(i); } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif void HashedObjectList< TKey,TObj>::clearHash() { for( intptr_t i = keyHash_.slotCount() - 1; i >= 0; i-- ){ keyHash_.slots()[i] = NULL; objectHash_.slots()[i] = NULL; indexHash_.slots()[i] = NULL; } } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif void HashedObjectList< TKey,TObj>::reHash(uintptr_t slotCount) { if( slotCount > 0 ){ HashedObjectListItem< TKey,TObj> ** ppItem0 = keyHash_.slots(), ** ppItem1 = ppItem0 + keyHash_.slotCount(); HashedObjectListItem< TKey,TObj> * head = NULL, * pItem; while( ppItem0 < ppItem1 ){ pItem = *ppItem0; while( pItem != NULL ){ pItem->indexNext(head); head = pItem; pItem = pItem->keyNext(); } ppItem0++; } clearHash(); uintptr_t oldSlotCount = keyHash_.slotCount(); Exception * esp = NULL; try{ keyHash_.resize(slotCount); try { objectHash_.resize(slotCount); try { indexHash_.resize(slotCount); } catch( ... ){ objectHash_.slotCount(oldSlotCount); throw; } } catch( ... ){ keyHash_.slotCount(oldSlotCount); throw; } } catch( ExceptionSP & e ){ esp = e.ptr(); esp->addRef(); } catch( ... ){ assert(0); } HashedObjectListItem< TKey,TObj> ** pKeyItem, ** pIndexItem, ** pObjectItem; while( head != NULL ){ pItem = head->indexNext(); pKeyItem = keyHash_.find(head->key(), caseSensitive_); pObjectItem = objectHash_.find(head->object()); pIndexItem = indexHash_.find(head->index()); head->keyNext() = NULL; head->objectNext() = NULL; head->indexNext() = NULL; *pKeyItem = head; *pObjectItem = head; *pIndexItem = head; head = pItem; } if( esp != NULL ) esp->throwSP(); } } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::caseSensitive(bool caseSensitive) { if( caseSensitive != caseSensitive_ ){ if( caseSensitive && !caseSensitive_ && count_ > 0 ) newObjectV1C2(EINVAL,__PRETTY_FUNCTION__)->throwSP(); caseSensitive_ = caseSensitive; } return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::clear() { if( count_ > 0 ){ HashedObjectListItem< TKey,TObj> ** ppItem0 = keyHash_.slots(), ** ppItem1 = ppItem0 + keyHash_.slotCount(); while( ppItem0 < ppItem1 ){ HashedObjectListItem< TKey,TObj> * pItem = *ppItem0; while( pItem != NULL ){ if( ownsObjects_ ) deleteObject(pItem->object()); HashedObjectListItem< TKey,TObj> * pItem1 = pItem->keyNext(); deleteObject(pItem); pItem = pItem1; } ppItem0++; } clearHash(); count_ = 0; } return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::assign(const HashedObjectList & source) { clear(); ownsObjects_ = false; HashedObjectListItem< TKey,TObj> ** ppItem0 = source.keyHash_.slots(); HashedObjectListItem< TKey,TObj> ** ppItem1 = ppItem0 + source.keyHash_.slotCount(); while( ppItem0 < ppItem1 ){ HashedObjectListItem< TKey,TObj> * pItem = *ppItem0; while( pItem != NULL ){ addHelper(newObject >(*pItem)); pItem = pItem->keyNext(); } ppItem0++; } return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::transplant(HashedObjectList & donor) { HashedObjectListItem< TKey,TObj> ** ppItem0 = donor.keyHash_.slots(); HashedObjectListItem< TKey,TObj> ** ppItem1 = ppItem0 + donor.keyHash_.slotCount(); while( ppItem0 < ppItem1 ){ HashedObjectListItem< TKey,TObj> * pItem = *ppItem0; while( pItem != NULL ){ HashedObjectListItem< TKey,TObj> ** ppKey0, ** ppObject0, ** ppIndex0; pItem->index() = count_++; ppKey0 = keyHash_.find(pItem->key(), caseSensitive_); ppObject0 = objectHash_.find(pItem->object()); ppIndex0 = indexHash_.find(pItem->index()); HashedObjectListItem< TKey,TObj> * pItemNext = pItem->keyNext(); pItem->keyNext() = NULL; pItem->objectNext() = NULL; pItem->indexNext() = NULL; *ppKey0 = pItem; *ppObject0 = pItem; *ppIndex0 = pItem; pItem = pItemNext; } ppItem0++; } donor.clearHash(); donor.count_ = 0; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList< TKey,TObj>::addHelper(HashedObjectListItem * & item,bool throwIfExists) { HashedObjectListItem ** pKeyItem, ** pObjectItem, ** pIndexItem; pKeyItem = keyHash_.find(item->key(),caseSensitive_); pObjectItem = objectHash_.find(item->object()); pIndexItem = indexHash_.find(item->index()); if( *pKeyItem != NULL || *pObjectItem != NULL || *pIndexItem != NULL ){ if( throwIfExists ) newObjectV1C2(EEXIST, __PRETTY_FUNCTION__)->throwSP(); item = *pKeyItem; return item->index(); } *pKeyItem = item; *pObjectItem = item; *pIndexItem = item; count_++; uintptr_t count = keyHash_.slotCount() << 4; if( count_ > count + (((count << 2) + count) >> 3) ) reHash(keyHash_.slotCount() << 1); return count_ - 1; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::changeKey(const TKey & oldKey, const TKey & newKey) { HashedObjectListItem< TKey,TObj> ** ppOldKeyItem, * pOldKeyItem; ppOldKeyItem = keyHash_.find(oldKey, caseSensitive_); if( *ppOldKeyItem == NULL ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); *ppOldKeyItem = (pOldKeyItem = *ppOldKeyItem)->keyNext(); HashedObjectListItem< TKey,TObj> ** ppNewKeyItem; ppNewKeyItem = keyHash_.find(newKey, caseSensitive_); if( *ppNewKeyItem != NULL ){ *ppOldKeyItem = pOldKeyItem; newObjectV1C2(EEXIST, __PRETTY_FUNCTION__)->throwSP(); } pOldKeyItem->key() = newKey; *ppNewKeyItem = pOldKeyItem; pOldKeyItem->keyNext() = NULL; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::changeObject(TObj * oldObject, TObj * newObject) { HashedObjectListItem< TKey,TObj> ** ppOldObjectItem, * pOldObjectItem; ppOldObjectItem = objectHash_.find(oldObject); if( *ppOldObjectItem == NULL ) newObjectV1C2(ENOENT,__PRETTY_FUNCTION__)->throwSP(); *ppOldObjectItem = (pOldObjectItem = *ppOldObjectItem)->objectNext(); HashedObjectListItem< TKey,TObj> ** ppNewObjectItem; ppNewObjectItem = objectHash_.find(newObject); if( *ppNewObjectItem != NULL ){ *ppOldObjectItem = pOldObjectItem; newObjectV1C2(ENOENT,__PRETTY_FUNCTION__)->throwSP(); } if( ownsObjects_ ) deleteObject(pOldObjectItem->object()); pOldObjectItem->object() = newObject; *ppNewObjectItem = pOldObjectItem; pOldObjectItem->objectNext() = NULL; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::changeIndex(uintptr_t oldIndex, uintptr_t newIndex) { HashedObjectListItem< TKey,TObj> ** ppOldItem, ** ppNewItem; ppOldItem = indexHash_.find(oldIndex); ppNewItem = indexHash_.find(newIndex); assert(*ppOldItem != NULL && *ppNewItem != NULL); if( oldIndex != newIndex ){ HashedObjectListItem< TKey,TObj> * pOldItem, * pNewItem; *ppOldItem = (pOldItem = *ppOldItem)->indexNext(); *ppNewItem = (pNewItem = *ppNewItem)->indexNext(); pOldItem->indexNext(NULL); pNewItem->indexNext(NULL); pOldItem->index(newIndex); ppOldItem = indexHash_.find(pOldItem->index()); assert(*ppOldItem == NULL); *ppOldItem = pOldItem; pNewItem->index(oldIndex); ppNewItem = indexHash_.find(pNewItem->index()); assert(*ppNewItem == NULL); *ppNewItem = pNewItem; } return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList::add(TObj * object,const TKey & key,HashedObjectListItem ** pItem,bool throwIfExist) { AutoPtr > item( newObjectC1V2V3 >(key,object,count_) ); HashedObjectListItem * p = item.ptr(); uintptr_t i = addHelper(p,throwIfExist); if( pItem != NULL ) *pItem = p; if( p == item.ptr() ) item.ptr(NULL); return i; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::removeByKey(const TKey & key) { TObj * object = extractByKey(key); if( ownsObjects_ ) deleteObject(object); return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::removeByObject(TObj * object) { object = extractByObject(object); if( ownsObjects_ ) deleteObject(object); return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::removeByIndex(uintptr_t index) { TObj * object = extractByIndex(index); if( ownsObjects_ ) deleteObject(object); return *this; } //--------------------------------------------------------------------------- #ifdef __BCPLUSPLUS__ #pragma option push -w-8013 #endif //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList< TKey,TObj>::extractByKey(const TKey & key) { HashedObjectListItem< TKey,TObj> ** pKeyItem, ** pObjectItem, ** pIndexItem; pKeyItem = keyHash_.find(key, caseSensitive_); pObjectItem = objectHash_.find((*pKeyItem)->object()); pIndexItem = indexHash_.find((*pKeyItem)->index()); if( *pKeyItem == NULL || *pObjectItem == NULL || *pIndexItem == NULL ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); HashedObjectListItem< TKey,TObj> * pItem = *pKeyItem; *pKeyItem = (*pKeyItem)->keyNext(); *pObjectItem = (*pObjectItem)->objectNext(); *pIndexItem = (*pIndexItem)->indexNext(); uintptr_t index = pItem->index(); TObj * object = pItem->object(); deleteObject(pItem); renumeration(index); count_--; uintptr_t count = keyHash_.slotCount() << 4; if( count_ < count - (((count << 2) + count) >> 3) ) reHash(keyHash_.slotCount() >> 1); return object; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList< TKey,TObj>::extractByObject(TObj * object) { if( object != NULL ){ HashedObjectListItem< TKey,TObj> ** pKeyItem, ** pObjectItem, ** pIndexItem; pObjectItem = objectHash_.find(object); pKeyItem = keyHash_.find((*pObjectItem)->key(), caseSensitive_); pIndexItem = indexHash_.find((*pObjectItem)->index()); if( *pObjectItem == NULL || *pKeyItem == NULL || *pIndexItem == NULL ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); HashedObjectListItem< TKey,TObj> * pItem = *pKeyItem; *pKeyItem = (*pKeyItem)->keyNext(); *pObjectItem = (*pObjectItem)->objectNext(); *pIndexItem = (*pIndexItem)->indexNext(); uintptr_t index = pItem->index(); deleteObject(pItem); renumeration(index); count_--; uintptr_t count = keyHash_.slotCount() << 4; if( count_ < count - (((count << 2) + count) >> 3) ) reHash(keyHash_.slotCount() >> 1); } return object; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList< TKey,TObj>::extractByIndex(uintptr_t index) { HashedObjectListItem< TKey,TObj> ** pKeyItem, ** pObjectItem, ** pIndexItem; pIndexItem = indexHash_.find(index); pObjectItem = objectHash_.find((*pIndexItem)->object()); pKeyItem = keyHash_.find((*pIndexItem)->key(), caseSensitive_); if( *pIndexItem == NULL || *pObjectItem == NULL || *pKeyItem == NULL ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); HashedObjectListItem< TKey,TObj> * pItem = *pKeyItem; *pKeyItem = (*pKeyItem)->keyNext(); *pObjectItem = (*pObjectItem)->objectNext(); *pIndexItem = (*pIndexItem)->indexNext(); TObj * object = pItem->object(); deleteObject(pItem); renumeration(index); count_--; uintptr_t count = keyHash_.slotCount() << 4; if( count_ < count - (((count << 2) + count) >> 3) ) reHash(keyHash_.slotCount() >> 1); return object; } //--------------------------------------------------------------------------- #ifdef __BCPLUSPLUS__ #pragma option pop #endif //--------------------------------------------------------------------------- template< class TKey,class TObj> inline void HashedObjectList< TKey,TObj>::renumeration(uintptr_t index) { if( index < count_ - 1 ){ HashedObjectListItem< TKey,TObj> ** pIndexItem, * pItem; pIndexItem = indexHash_.find(count_ - 1); pItem = *pIndexItem; assert(pItem != NULL); *pIndexItem = pItem->indexNext(); pItem->indexNext(NULL); pItem->index(index); pIndexItem = indexHash_.find(index); *pIndexItem = pItem; } } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList< TKey,TObj>::indexOfObject(TObj * object) const { HashedObjectListItem< TKey,TObj> ** pItem = objectHash_.find(object); return *pItem == NULL ? -1 : (*pItem)->index(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList< TKey,TObj>::indexOfKey(const TKey & key) const { HashedObjectListItem< TKey,TObj> ** pItem = keyHash_.find(key, caseSensitive_); return *pItem == NULL ? -1 : (*pItem)->index(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TKey HashedObjectList< TKey,TObj>::keyOfObject(TObj * object) const { HashedObjectListItem< TKey,TObj> ** pItem = objectHash_.find(object); return *pItem == NULL ? TKey() : (*pItem)->key(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> #ifndef __BCPLUSPLUS__ inline #endif TKey HashedObjectList< TKey,TObj>::keyOfIndex(uintptr_t index) const { HashedObjectListItem< TKey,TObj> ** pItem = indexHash_.find(index); return *pItem == NULL ? TKey() : (*pItem)->key(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList< TKey,TObj>::objectOfKey(const TKey & key) const { HashedObjectListItem< TKey,TObj> ** pItem = keyHash_.find(key, caseSensitive_); return *pItem == NULL ? NULL : (*pItem)->object(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline TObj * HashedObjectList< TKey,TObj>::objectOfIndex(uintptr_t index) const { HashedObjectListItem< TKey,TObj> ** pItem = indexHash_.find(index); return *pItem == NULL ? NULL : (*pItem)->object(); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> * HashedObjectList< TKey,TObj>::itemOfKey(const TKey & key) const { return *keyHash_.find(key, caseSensitive_); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> * HashedObjectList< TKey,TObj>::itemOfObject(TObj * object) const { return *objectHash_.find(object); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectListItem< TKey,TObj> * HashedObjectList< TKey,TObj>::itemOfIndex(uintptr_t index) const { return *indexHash_.find(index); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::transplantByKey(HashedObjectList & donor, const TKey & key) { HashedObjectListItem< TKey,TObj> ** ppKeyItem0, ** ppObjectItem0, ** ppIndexItem0; HashedObjectListItem< TKey,TObj> ** ppKeyItem1, ** ppObjectItem1, ** ppIndexItem1; ppKeyItem0 = donor.keyHash_.find(key, donor.caseSensitive_); ppObjectItem0 = donor.objectHash_.find((*ppKeyItem0)->object()); ppIndexItem0 = donor.indexHash_.find((*ppKeyItem0)->index()); if( *ppKeyItem0 == NULL || *ppObjectItem0 == NULL || *ppIndexItem0 == NULL || *ppKeyItem0 != *ppObjectItem0 || *ppKeyItem0 != *ppIndexItem0 ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); ppKeyItem1 = keyHash_.find(key, caseSensitive_); ppObjectItem1 = objectHash_.find((*ppKeyItem0)->object()); if( *ppKeyItem1 != NULL || *ppObjectItem1 != NULL ) newObjectV1C2(EEXIST, __PRETTY_FUNCTION__)->throwSP(); HashedObjectListItem< TKey,TObj> * pItem = *ppKeyItem0; *ppKeyItem0 = pItem->keyNext(); *ppObjectItem0 = pItem->objectNext(); *ppIndexItem0 = pItem->indexNext(); donor.renumeration(pItem->index()); donor.count_--; pItem->keyNext() = NULL; pItem->objectNext() = NULL; pItem->indexNext() = NULL; pItem->index() = count_; ppIndexItem1 = indexHash_.find(pItem->index()); *ppKeyItem1 = pItem; *ppObjectItem1 = pItem; *ppIndexItem1 = pItem; count_++; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::transplantByObject(HashedObjectList & donor, TObj * object) { HashedObjectListItem< TKey,TObj> ** ppKeyItem0, ** ppObjectItem0, ** ppIndexItem0; HashedObjectListItem< TKey,TObj> ** ppKeyItem1, ** ppObjectItem1, ** ppIndexItem1; ppObjectItem0 = donor.objectHash_.find(object); ppKeyItem0 = donor.keyHash_.find((*ppObjectItem0)->key(), donor.caseSensitive_); ppIndexItem0 = donor.indexHash_.find((*ppObjectItem0)->index()); if( *ppObjectItem0 == NULL || *ppKeyItem0 == NULL || *ppIndexItem0 == NULL || *ppObjectItem0 != *ppKeyItem0 || *ppObjectItem0 != *ppIndexItem0 ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); ppKeyItem1 = keyHash_.find((*ppKeyItem0)->key(), caseSensitive_); ppObjectItem1 = objectHash_.find((*ppKeyItem0)->object()); if( *ppKeyItem1 != NULL || *ppObjectItem1 != NULL ) newObjectV1C2(EEXIST, __PRETTY_FUNCTION__)->throwSP(); HashedObjectListItem< TKey,TObj> * pItem = *ppKeyItem0; *ppKeyItem0 = pItem->keyNext(); *ppObjectItem0 = pItem->objectNext(); *ppIndexItem0 = pItem->indexNext(); donor.renumeration(pItem->index()); donor.count_--; pItem->keyNext() = NULL; pItem->objectNext() = NULL; pItem->indexNext() = NULL; pItem->index() = count_; ppIndexItem1 = indexHash_.find(pItem->index()); *ppKeyItem1 = pItem; *ppObjectItem1 = pItem; *ppIndexItem1 = pItem; count_++; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::transplantByIndex(HashedObjectList & donor, uintptr_t index) { HashedObjectListItem< TKey,TObj> ** ppKeyItem0, ** ppObjectItem0, ** ppIndexItem0; HashedObjectListItem< TKey,TObj> ** ppKeyItem1, ** ppObjectItem1, ** ppIndexItem1; ppIndexItem0 = donor.indexHash_.find(index); ppObjectItem0 = donor.objectHash_.find((*ppIndexItem0)->object()); ppKeyItem0 = donor.keyHash_.find((*ppIndexItem0)->key(), donor.caseSensitive_); if( *ppIndexItem0 == NULL || *ppObjectItem0 == NULL || *ppKeyItem0 == NULL || *ppIndexItem0 != *ppObjectItem0 || *ppIndexItem0 != *ppKeyItem0 ) newObjectV1C2(ENOENT, __PRETTY_FUNCTION__)->throwSP(); ppKeyItem1 = keyHash_.find((*ppKeyItem0)->key(), caseSensitive_); ppObjectItem1 = objectHash_.find((*ppKeyItem0)->object()); if( *ppKeyItem1 != NULL || *ppObjectItem1 != NULL ) newObjectV1C2(EEXIST, __PRETTY_FUNCTION__)->throwSP(); HashedObjectListItem< TKey,TObj> * pItem = *ppKeyItem0; *ppKeyItem0 = pItem->keyNext(); *ppObjectItem0 = pItem->objectNext(); *ppIndexItem0 = pItem->indexNext(); donor.renumeration(pItem->index()); donor.count_--; pItem->keyNext() = NULL; pItem->objectNext() = NULL; pItem->indexNext() = NULL; pItem->index() = count_; ppIndexItem1 = indexHash_.find(pItem->index()); *ppKeyItem1 = pItem; *ppObjectItem1 = pItem; *ppIndexItem1 = pItem; count_++; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline const bool & HashedObjectList< TKey,TObj>::ownsObjects() const { return ownsObjects_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline HashedObjectList< TKey,TObj> & HashedObjectList< TKey,TObj>::ownsObjects(bool owns) { ownsObjects_ = owns; return *this; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline const bool & HashedObjectList< TKey,TObj>::caseSensitive() const { return caseSensitive_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline const uintptr_t & HashedObjectList< TKey,TObj>::count() const { return count_; } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList< TKey,TObj>::maxChainLength(HashChainType chain) const { return (&keyHash_ + chain)->maxChainLength(chain); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList< TKey,TObj>::minChainLength(HashChainType chain) const { return (&keyHash_ + chain)->minChainLength(chain); } //--------------------------------------------------------------------------- template< class TKey,class TObj> inline uintptr_t HashedObjectList< TKey,TObj>::avgChainLength(HashChainType chain) const { return (&keyHash_ + chain)->avgChainLength(chain); } //--------------------------------------------------------------------------- } // namespace ksys //--------------------------------------------------------------------------- #endif //---------------------------------------------------------------------------