mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			336 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 
 | |
|  This file is a part of JRTPLIB
 | |
|  Copyright (c) 1999-2017 Jori Liesenborgs
 | |
| 
 | |
|  Contact: jori.liesenborgs@gmail.com
 | |
| 
 | |
|  This library was developed at the Expertise Centre for Digital 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.
 | |
| 
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * \file rtpkeyhashtable.h
 | |
|  */
 | |
| 
 | |
| #ifndef RTPKEYHASHTABLE_H
 | |
| 
 | |
| #define RTPKEYHASHTABLE_H
 | |
| 
 | |
| #include "rtperrors.h"
 | |
| 
 | |
| namespace qrtplib
 | |
| {
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| class RTPKeyHashTable
 | |
| {
 | |
| public:
 | |
|     RTPKeyHashTable();
 | |
|     ~RTPKeyHashTable()
 | |
|     {
 | |
|         Clear();
 | |
|     }
 | |
| 
 | |
|     void GotoFirstElement()
 | |
|     {
 | |
|         curhashelem = firsthashelem;
 | |
|     }
 | |
|     void GotoLastElement()
 | |
|     {
 | |
|         curhashelem = lasthashelem;
 | |
|     }
 | |
|     bool HasCurrentElement()
 | |
|     {
 | |
|         return (curhashelem == 0) ? false : true;
 | |
|     }
 | |
|     int DeleteCurrentElement();
 | |
|     Element &GetCurrentElement()
 | |
|     {
 | |
|         return curhashelem->GetElement();
 | |
|     }
 | |
|     Key &GetCurrentKey()
 | |
|     {
 | |
|         return curhashelem->GetKey();
 | |
|     }
 | |
|     int GotoElement(const Key &k);
 | |
|     bool HasElement(const Key &k);
 | |
|     void GotoNextElement();
 | |
|     void GotoPreviousElement();
 | |
|     void Clear();
 | |
| 
 | |
|     int AddElement(const Key &k, const Element &elem);
 | |
|     int DeleteElement(const Key &k);
 | |
| 
 | |
| private:
 | |
|     class HashElement
 | |
|     {
 | |
|     public:
 | |
|         HashElement(const Key &k, const Element &e, int index) :
 | |
|                 key(k), element(e)
 | |
|         {
 | |
|             hashprev = 0;
 | |
|             hashnext = 0;
 | |
|             listnext = 0;
 | |
|             listprev = 0;
 | |
|             hashindex = index;
 | |
|         }
 | |
|         int GetHashIndex()
 | |
|         {
 | |
|             return hashindex;
 | |
|         }
 | |
|         Key &GetKey()
 | |
|         {
 | |
|             return key;
 | |
|         }
 | |
|         Element &GetElement()
 | |
|         {
 | |
|             return element;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         int hashindex;
 | |
|         Key key;
 | |
|         Element element;
 | |
|     public:
 | |
|         HashElement *hashprev, *hashnext;
 | |
|         HashElement *listprev, *listnext;
 | |
|     };
 | |
| 
 | |
|     HashElement *table[hashsize];
 | |
|     HashElement *firsthashelem, *lasthashelem;
 | |
|     HashElement *curhashelem;
 | |
| };
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline RTPKeyHashTable<Key, Element, GetIndex, hashsize>::RTPKeyHashTable()
 | |
| {
 | |
|     for (int i = 0; i < hashsize; i++)
 | |
|         table[i] = 0;
 | |
|     firsthashelem = 0;
 | |
|     lasthashelem = 0;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline int RTPKeyHashTable<Key, 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
 | |
|         delete curhashelem;
 | |
|         curhashelem = tmp2; // Set to next element in list
 | |
|     }
 | |
|     else
 | |
|         return ERR_RTP_KEYHASHTABLE_NOCURRENTELEMENT;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline int RTPKeyHashTable<Key, Element, GetIndex, hashsize>::GotoElement(const Key &k)
 | |
| {
 | |
|     int index;
 | |
|     bool found;
 | |
| 
 | |
|     index = GetIndex::GetIndex(k);
 | |
|     if (index >= hashsize)
 | |
|         return ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
 | |
| 
 | |
|     curhashelem = table[index];
 | |
|     found = false;
 | |
|     while (!found && curhashelem != 0)
 | |
|     {
 | |
|         if (curhashelem->GetKey() == k)
 | |
|             found = true;
 | |
|         else
 | |
|             curhashelem = curhashelem->hashnext;
 | |
|     }
 | |
|     if (!found)
 | |
|         return ERR_RTP_KEYHASHTABLE_KEYNOTFOUND;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline bool RTPKeyHashTable<Key, Element, GetIndex, hashsize>::HasElement(const Key &k)
 | |
| {
 | |
|     int index;
 | |
|     bool found;
 | |
|     HashElement *tmp;
 | |
| 
 | |
|     index = GetIndex::GetIndex(k);
 | |
|     if (index >= hashsize)
 | |
|         return false;
 | |
| 
 | |
|     tmp = table[index];
 | |
|     found = false;
 | |
|     while (!found && tmp != 0)
 | |
|     {
 | |
|         if (tmp->GetKey() == k)
 | |
|             found = true;
 | |
|         else
 | |
|             tmp = tmp->hashnext;
 | |
|     }
 | |
|     return found;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline void RTPKeyHashTable<Key, Element, GetIndex, hashsize>::GotoNextElement()
 | |
| {
 | |
|     if (curhashelem)
 | |
|         curhashelem = curhashelem->listnext;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline void RTPKeyHashTable<Key, Element, GetIndex, hashsize>::GotoPreviousElement()
 | |
| {
 | |
|     if (curhashelem)
 | |
|         curhashelem = curhashelem->listprev;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline void RTPKeyHashTable<Key, 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;
 | |
|         delete tmp1;
 | |
|         tmp1 = tmp2;
 | |
|     }
 | |
|     firsthashelem = 0;
 | |
|     lasthashelem = 0;
 | |
| }
 | |
| 
 | |
| template<class Key, class Element, class GetIndex, int hashsize>
 | |
| inline int RTPKeyHashTable<Key, Element, GetIndex, hashsize>::AddElement(const Key &k, const Element &elem)
 | |
| {
 | |
|     int index;
 | |
|     bool found;
 | |
|     HashElement *e, *newelem;
 | |
| 
 | |
|     index = GetIndex::GetIndex(k);
 | |
|     if (index >= hashsize)
 | |
|         return ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
 | |
| 
 | |
|     e = table[index];
 | |
|     found = false;
 | |
|     while (!found && e != 0)
 | |
|     {
 | |
|         if (e->GetKey() == k)
 | |
|             found = true;
 | |
|         else
 | |
|             e = e->hashnext;
 | |
|     }
 | |
|     if (found)
 | |
|         return ERR_RTP_KEYHASHTABLE_KEYALREADYEXISTS;
 | |
| 
 | |
|     // Okay, the key doesn't exist, so we can add the new element in the hash table
 | |
| 
 | |
|     newelem = new HashElement(k, elem, index);
 | |
| 
 | |
|     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 Key, class Element, class GetIndex, int hashsize>
 | |
| inline int RTPKeyHashTable<Key, Element, GetIndex, hashsize>::DeleteElement(const Key &k)
 | |
| {
 | |
|     int status;
 | |
| 
 | |
|     status = GotoElement(k);
 | |
|     if (status < 0)
 | |
|         return status;
 | |
|     return DeleteCurrentElement();
 | |
| }
 | |
| 
 | |
| } // end namespace
 | |
| 
 | |
| #endif // RTPKEYHASHTABLE_H
 |