summaryrefslogtreecommitdiffstats
path: root/src/rtphashtable.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtphashtable.h')
-rw-r--r--src/rtphashtable.h337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/rtphashtable.h b/src/rtphashtable.h
new file mode 100644
index 0000000..aa482c0
--- /dev/null
+++ b/src/rtphashtable.h
@@ -0,0 +1,337 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPHASHTABLE_H
+
+#define RTPHASHTABLE_H
+
+/**
+ * \file rtphashtable.h
+ */
+
+#include "rtperrors.h"
+#include "rtpmemoryobject.h"
+
+#ifdef RTPDEBUG
+#include <iostream>
+#endif // RTPDEBUG
+
+//template<class Element,int GetIndex(const Element &k),int hashsize>
+template<class Element,class GetIndex,int hashsize>
+class RTPHashTable : public RTPMemoryObject
+{
+public:
+ RTPHashTable(RTPMemoryManager *mgr = 0, int memtype = RTPMEM_TYPE_OTHER);
+ ~RTPHashTable() { Clear(); }
+
+ void GotoFirstElement() { curhashelem = firsthashelem; }
+ void GotoLastElement() { curhashelem = lasthashelem; }
+ bool HasCurrentElement() { return (curhashelem == 0)?false:true; }
+ int DeleteCurrentElement();
+ Element &GetCurrentElement() { return curhashelem->GetElement(); }
+ int GotoElement(const Element &e);
+ bool HasElement(const Element &e);
+ void GotoNextElement();
+ void GotoPreviousElement();
+ void Clear();
+
+ int AddElement(const Element &elem);
+ int DeleteElement(const Element &elem);
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ class HashElement
+ {
+ public:
+ HashElement(const Element &e,int index):element(e) { hashprev = 0; hashnext = 0; listnext = 0; listprev = 0; hashindex = index; }
+ int GetHashIndex() { return hashindex; }
+ Element &GetElement() { return element; }
+#ifdef RTPDEBUG
+ void Dump() { std::cout << "\tHash index " << hashindex << " | Element " << element << std::endl; }
+#endif // RTPDEBUG
+ private:
+ int hashindex;
+ Element element;
+ public:
+ HashElement *hashprev,*hashnext;
+ HashElement *listprev,*listnext;
+ };
+
+ HashElement *table[hashsize];
+ HashElement *firsthashelem,*lasthashelem;
+ HashElement *curhashelem;
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ int memorytype;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+};
+
+template<class Element,class GetIndex,int hashsize>
+inline RTPHashTable<Element,GetIndex,hashsize>::RTPHashTable(RTPMemoryManager *mgr,int memtype) : RTPMemoryObject(mgr)
+{
+ for (int i = 0 ; i < hashsize ; i++)
+ table[i] = 0;
+ firsthashelem = 0;
+ lasthashelem = 0;
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ memorytype = memtype;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::DeleteCurrentElement()
+{
+ if (curhashelem)
+ {
+ HashElement *tmp1,*tmp2;
+ int index;
+
+ // First, relink elements in current hash bucket
+
+ index = curhashelem->GetHashIndex();
+ tmp1 = curhashelem->hashprev;
+ tmp2 = curhashelem->hashnext;
+ if (tmp1 == 0) // no previous element in hash bucket
+ {
+ table[index] = tmp2;
+ if (tmp2 != 0)
+ tmp2->hashprev = 0;
+ }
+ else // there is a previous element in the hash bucket
+ {
+ tmp1->hashnext = tmp2;
+ if (tmp2 != 0)
+ tmp2->hashprev = tmp1;
+ }
+
+ // Relink elements in list
+
+ tmp1 = curhashelem->listprev;
+ tmp2 = curhashelem->listnext;
+ if (tmp1 == 0) // curhashelem is first in list
+ {
+ firsthashelem = tmp2;
+ if (tmp2 != 0)
+ tmp2->listprev = 0;
+ else // curhashelem is also last in list
+ lasthashelem = 0;
+ }
+ else
+ {
+ tmp1->listnext = tmp2;
+ if (tmp2 != 0)
+ tmp2->listprev = tmp1;
+ else // curhashelem is last in list
+ lasthashelem = tmp1;
+ }
+
+ // finally, with everything being relinked, we can delete curhashelem
+ RTPDelete(curhashelem,GetMemoryManager());
+ curhashelem = tmp2; // Set to next element in the list
+ }
+ else
+ return ERR_RTP_HASHTABLE_NOCURRENTELEMENT;
+ return 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::GotoElement(const Element &e)
+{
+ int index;
+ bool found;
+
+ index = GetIndex::GetIndex(e);
+ if (index >= hashsize)
+ return ERR_RTP_HASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
+
+ curhashelem = table[index];
+ found = false;
+ while(!found && curhashelem != 0)
+ {
+ if (curhashelem->GetElement() == e)
+ found = true;
+ else
+ curhashelem = curhashelem->hashnext;
+ }
+ if (!found)
+ return ERR_RTP_HASHTABLE_ELEMENTNOTFOUND;
+ return 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline bool RTPHashTable<Element,GetIndex,hashsize>::HasElement(const Element &e)
+{
+ int index;
+ bool found;
+ HashElement *tmp;
+
+ index = GetIndex::GetIndex(e);
+ if (index >= hashsize)
+ return false;
+
+ tmp = table[index];
+ found = false;
+ while(!found && tmp != 0)
+ {
+ if (tmp->GetElement() == e)
+ found = true;
+ else
+ tmp = tmp->hashnext;
+ }
+ return found;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::GotoNextElement()
+{
+ if (curhashelem)
+ curhashelem = curhashelem->listnext;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::GotoPreviousElement()
+{
+ if (curhashelem)
+ curhashelem = curhashelem->listprev;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::Clear()
+{
+ HashElement *tmp1,*tmp2;
+
+ for (int i = 0 ; i < hashsize ; i++)
+ table[i] = 0;
+
+ tmp1 = firsthashelem;
+ while (tmp1 != 0)
+ {
+ tmp2 = tmp1->listnext;
+ RTPDelete(tmp1,GetMemoryManager());
+ tmp1 = tmp2;
+ }
+ firsthashelem = 0;
+ lasthashelem = 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::AddElement(const Element &elem)
+{
+ int index;
+ bool found;
+ HashElement *e,*newelem;
+
+ index = GetIndex::GetIndex(elem);
+ if (index >= hashsize)
+ return ERR_RTP_HASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
+
+ e = table[index];
+ found = false;
+ while(!found && e != 0)
+ {
+ if (e->GetElement() == elem)
+ found = true;
+ else
+ e = e->hashnext;
+ }
+ if (found)
+ return ERR_RTP_HASHTABLE_ELEMENTALREADYEXISTS;
+
+ // Okay, the key doesn't exist, so we can add the new element in the hash table
+
+ newelem = RTPNew(GetMemoryManager(),memorytype) HashElement(elem,index);
+ if (newelem == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ e = table[index];
+ table[index] = newelem;
+ newelem->hashnext = e;
+ if (e != 0)
+ e->hashprev = newelem;
+
+ // Now, we still got to add it to the linked list
+
+ if (firsthashelem == 0)
+ {
+ firsthashelem = newelem;
+ lasthashelem = newelem;
+ }
+ else // there already are some elements in the list
+ {
+ lasthashelem->listnext = newelem;
+ newelem->listprev = lasthashelem;
+ lasthashelem = newelem;
+ }
+ return 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::DeleteElement(const Element &elem)
+{
+ int status;
+
+ status = GotoElement(elem);
+ if (status < 0)
+ return status;
+ return DeleteCurrentElement();
+}
+
+#ifdef RTPDEBUG
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::Dump()
+{
+ HashElement *e;
+
+ std::cout << "DUMPING TABLE CONTENTS:" << std::endl;
+ for (int i = 0 ; i < hashsize ; i++)
+ {
+ e = table[i];
+ while (e != 0)
+ {
+ e->Dump();
+ e = e->hashnext;
+ }
+ }
+
+ std::cout << "DUMPING LIST CONTENTS:" << std::endl;
+ e = firsthashelem;
+ while (e != 0)
+ {
+ e->Dump();
+ e = e->listnext;
+ }
+}
+#endif // RTPDEBUG
+
+#endif // RTPHASHTABLE_H
+