#ifndef N_KEYARRAY_H #define N_KEYARRAY_H //------------------------------------------------------------------------------ /** @brief Implements growable array of key-pointer pairs. The array is kept sorted for fast bsearch() by key @author - RadonLabs GmbH @since - 2005.6.30 @remarks - Áö¿Ï Ãß°¡ */ #include "../ProgramCommon/Macro.h" #include "../ProgramCommon/Define.h" #include "Narray.h" //------------------------------------------------------------------------------ template class nKeyArray { public: /// constructor for non-growable array nKeyArray(int num); /// constructor for growable array nKeyArray(int num, int grow); /// destructor ~nKeyArray(); /// add key/element pair to array void Add(int key, const TYPE& e); /// find element associated with given key bool Find(int key, TYPE& e); /// find pointer to element associated with key bool FindPtr(int key, TYPE*& e); /// remove element defined by key void Rem(int key); /// remove element defined by key index void RemByIndex(int index); /// return number of elements int Size() const; /// get element at index TYPE& GetElementAt(int index) const; /// get key at index int GetKeyAt(int index) const; /// clear the array without deallocating memory! void Clear(); private: struct nKAElement { int key; TYPE elm; }; /// allocate array void alloc(int num); /// grow array void grow(); /// binary search nKAElement* bsearch(int key); int numElms; int maxElms; int growElms; nKAElement* curElm; nKAElement* elmArray; }; //------------------------------------------------------------------------------ /** */ template void nKeyArray::alloc(int num) { ASSERT(0 == this->elmArray); ASSERT(0 == this->curElm); this->elmArray = n_new nKAElement[num]; this->maxElms = num; } //------------------------------------------------------------------------------ /** */ template void nKeyArray::grow() { ASSERT(this->elmArray); ASSERT(this->growElms > 0); int newNum = this->maxElms + this->growElms; nKAElement* newArray = n_new nKAElement[newNum]; memcpy(newArray, this->elmArray, this->numElms * sizeof(nKAElement)); n_delete[] this->elmArray; this->elmArray = newArray; this->maxElms = newNum; this->curElm = 0; } //------------------------------------------------------------------------------ /** */ template typename nKeyArray::nKAElement* nKeyArray::bsearch(int key) { ASSERT(this->numElms > 0); int num = this->numElms; int half; nKAElement* lo = &(this->elmArray[0]); nKAElement* hi = &(this->elmArray[num-1]); nKAElement* mid; while (lo <= hi) { if ((half = num/2)) { mid = lo + ((num & 1) ? half : (half - 1)); int diff = key - mid->key; if (diff < 0) { hi = mid - 1; num = num & 1 ? half : half-1; } else if (diff > 0) { lo = mid + 1; num = half; } else { return mid; } } else if (num) { int diff = key - lo->key; if (diff) { return 0; } else { return lo; } } else { break; } } return NULL; } //------------------------------------------------------------------------------ /** */ template nKeyArray::nKeyArray(int num) : numElms(0), maxElms(0), growElms(0), curElm(0), elmArray(0) { this->alloc(num); } //------------------------------------------------------------------------------ /** */ template nKeyArray::nKeyArray(int num, int grow) : numElms(0), maxElms(0), growElms(grow), curElm(0), elmArray(0) { this->alloc(num); } //------------------------------------------------------------------------------ /** */ template nKeyArray::~nKeyArray() { if (this->elmArray) { n_delete[] this->elmArray; } } //------------------------------------------------------------------------------ /** */ template void nKeyArray::Add(int key, const TYPE& e) { // need to grow array? if (this->numElms == this->maxElms) { ASSERT(this->growElms > 0); this->grow(); } // insert key into array, keep array sorted by key int i; for (i = 0; i < this->numElms; i++) { nKAElement* kae = &(this->elmArray[i]); if (key < kae->key) { // insert in front of 'e' nKAElement* kaeSucc = kae + 1; int numMove = this->numElms - i; if (numMove > 0) { memmove(kaeSucc, kae, numMove * sizeof(nKAElement)); } kae->key = key; kae->elm = e; this->numElms++; this->curElm = 0; return; } } // fallthrough: add element to end of array this->elmArray[this->numElms].key = key; this->elmArray[this->numElms].elm = e; this->numElms++; } //------------------------------------------------------------------------------ /** */ template bool nKeyArray::Find(int key, TYPE& e) { if (this->numElms == 0) { return false; } if (this->curElm && (this->curElm->key == key)) { e = this->curElm->elm; return true; } else { nKAElement* p = this->bsearch(key); if (p) { this->curElm = p; e = this->curElm->elm; return true; } else { return false; } } } //------------------------------------------------------------------------------ /** */ template bool nKeyArray::FindPtr(int key, TYPE*& e) { if (this->numElms == 0) { return false; } if (this->curElm && (this->curElm->key == key)) { e = &(this->curElm->elm); return true; } else { nKAElement* p = this->bsearch(key); if (p) { this->curElm = p; e = &(this->curElm->elm); return true; } else { return false; } } } //------------------------------------------------------------------------------ /** */ template void nKeyArray::Rem(int key) { nKAElement* e = this->bsearch(key); if (e) { this->curElm = NULL; this->numElms--; nKAElement* eSucc = e + 1; int i = e - this->elmArray; int numMove = this->numElms - i; if (numMove > 0) { memmove(e, eSucc, numMove * sizeof(nKAElement)); } } } //------------------------------------------------------------------------------ /** */ template void nKeyArray::RemByIndex(int index) { ASSERT((index >= 0) && (index < this->numElms)); nKAElement* e = &(this->elmArray[index]); nKAElement* eSucc = e + 1; this->curElm = 0; this->numElms--; int numMove = this->numElms - index; if (numMove > 0) { memmove(e, eSucc, numMove * sizeof(nKAElement)); } } //------------------------------------------------------------------------------ /** */ template int nKeyArray::Size() const { return this->numElms; } //------------------------------------------------------------------------------ /** */ template TYPE& nKeyArray::GetElementAt(int index) const { ASSERT((index >= 0) && (index < this->numElms)); return this->elmArray[index].elm; } //------------------------------------------------------------------------------ /** */ template int nKeyArray::GetKeyAt(int index) const { ASSERT((index >= 0) && (index < this->numElms)); return this->elmArray[index].key; } //------------------------------------------------------------------------------ /** */ template void nKeyArray::Clear() { this->numElms = 0; this->curElm = 0; } //------------------------------------------------------------------------------ #endif