JRTPLIB  3.11.2 (development version)
rtpkeyhashtable.h
Go to the documentation of this file.
1 /*
2 
3  This file is a part of JRTPLIB
4  Copyright (c) 1999-2017 Jori Liesenborgs
5 
6  Contact: jori.liesenborgs@gmail.com
7 
8  This library was developed at the Expertise Centre for Digital Media
9  (http://www.edm.uhasselt.be), a research center of the Hasselt University
10  (http://www.uhasselt.be). The library is based upon work done for
11  my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
12 
13  Permission is hereby granted, free of charge, to any person obtaining a
14  copy of this software and associated documentation files (the "Software"),
15  to deal in the Software without restriction, including without limitation
16  the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  and/or sell copies of the Software, and to permit persons to whom the
18  Software is furnished to do so, subject to the following conditions:
19 
20  The above copyright notice and this permission notice shall be included
21  in all copies or substantial portions of the Software.
22 
23  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29  IN THE SOFTWARE.
30 
31 */
32 
37 #ifndef RTPKEYHASHTABLE_H
38 
39 #define RTPKEYHASHTABLE_H
40 
41 #include "rtpconfig.h"
42 #include "rtperrors.h"
43 #include "rtpmemoryobject.h"
44 
45 #ifdef RTPDEBUG
46 #include <iostream>
47 #endif // RTPDEBUG
48 
49 namespace jrtplib
50 {
51 
52 template<class Key,class Element,class GetIndex,int hashsize>
53 class RTPKeyHashTable : public RTPMemoryObject
54 {
55  JRTPLIB_NO_COPY(RTPKeyHashTable)
56 public:
57  RTPKeyHashTable(RTPMemoryManager *mgr = 0,int memtype = RTPMEM_TYPE_OTHER);
58  ~RTPKeyHashTable() { Clear(); }
59 
60  void GotoFirstElement() { curhashelem = firsthashelem; }
61  void GotoLastElement() { curhashelem = lasthashelem; }
62  bool HasCurrentElement() { return (curhashelem == 0)?false:true; }
63  int DeleteCurrentElement();
64  Element &GetCurrentElement() { return curhashelem->GetElement(); }
65  Key &GetCurrentKey() { return curhashelem->GetKey(); }
66  int GotoElement(const Key &k);
67  bool HasElement(const Key &k);
68  void GotoNextElement();
69  void GotoPreviousElement();
70  void Clear();
71 
72  int AddElement(const Key &k,const Element &elem);
73  int DeleteElement(const Key &k);
74 
75 #ifdef RTPDEBUG
76  void Dump();
77 #endif // RTPDEBUG
78 private:
79  class HashElement
80  {
81  public:
82  HashElement(const Key &k,const Element &e,int index):key(k),element(e) { hashprev = 0; hashnext = 0; listnext = 0; listprev = 0; hashindex = index; }
83  int GetHashIndex() { return hashindex; }
84  Key &GetKey() { return key; }
85  Element &GetElement() { return element; }
86 #ifdef RTPDEBUG
87  void Dump() { std::cout << "\tHash index " << hashindex << " | Key " << key << " | Element " << element << std::endl; }
88 #endif // RTPDEBUG
89  private:
90  int hashindex;
91  Key key;
92  Element element;
93  public:
94  HashElement *hashprev,*hashnext;
95  HashElement *listprev,*listnext;
96  };
97 
98  HashElement *table[hashsize];
99  HashElement *firsthashelem,*lasthashelem;
100  HashElement *curhashelem;
101 #ifdef RTP_SUPPORT_MEMORYMANAGEMENT
102  int memorytype;
103 #endif // RTP_SUPPORT_MEMORYMANAGEMENT
104 };
105 
106 template<class Key,class Element,class GetIndex,int hashsize>
107 inline RTPKeyHashTable<Key,Element,GetIndex,hashsize>::RTPKeyHashTable(RTPMemoryManager *mgr,int memtype) : RTPMemoryObject(mgr)
108 {
109  JRTPLIB_UNUSED(memtype); // possibly unused
110 
111  for (int i = 0 ; i < hashsize ; i++)
112  table[i] = 0;
113  firsthashelem = 0;
114  lasthashelem = 0;
115 #ifdef RTP_SUPPORT_MEMORYMANAGEMENT
116  memorytype = memtype;
117 #endif // RTP_SUPPORT_MEMORYMANAGEMENT
118 }
119 
120 template<class Key,class Element,class GetIndex,int hashsize>
121 inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::DeleteCurrentElement()
122 {
123  if (curhashelem)
124  {
125  HashElement *tmp1,*tmp2;
126  int index;
127 
128  // First, relink elements in current hash bucket
129 
130  index = curhashelem->GetHashIndex();
131  tmp1 = curhashelem->hashprev;
132  tmp2 = curhashelem->hashnext;
133  if (tmp1 == 0) // no previous element in hash bucket
134  {
135  table[index] = tmp2;
136  if (tmp2 != 0)
137  tmp2->hashprev = 0;
138  }
139  else // there is a previous element in the hash bucket
140  {
141  tmp1->hashnext = tmp2;
142  if (tmp2 != 0)
143  tmp2->hashprev = tmp1;
144  }
145 
146  // Relink elements in list
147 
148  tmp1 = curhashelem->listprev;
149  tmp2 = curhashelem->listnext;
150  if (tmp1 == 0) // curhashelem is first in list
151  {
152  firsthashelem = tmp2;
153  if (tmp2 != 0)
154  tmp2->listprev = 0;
155  else // curhashelem is also last in list
156  lasthashelem = 0;
157  }
158  else
159  {
160  tmp1->listnext = tmp2;
161  if (tmp2 != 0)
162  tmp2->listprev = tmp1;
163  else // curhashelem is last in list
164  lasthashelem = tmp1;
165  }
166 
167  // finally, with everything being relinked, we can delete curhashelem
168  RTPDelete(curhashelem,GetMemoryManager());
169  curhashelem = tmp2; // Set to next element in list
170  }
171  else
172  return ERR_RTP_KEYHASHTABLE_NOCURRENTELEMENT;
173  return 0;
174 }
175 
176 template<class Key,class Element,class GetIndex,int hashsize>
177 inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::GotoElement(const Key &k)
178 {
179  int index;
180  bool found;
181 
182  index = GetIndex::GetIndex(k);
183  if (index >= hashsize)
184  return ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
185 
186  curhashelem = table[index];
187  found = false;
188  while(!found && curhashelem != 0)
189  {
190  if (curhashelem->GetKey() == k)
191  found = true;
192  else
193  curhashelem = curhashelem->hashnext;
194  }
195  if (!found)
196  return ERR_RTP_KEYHASHTABLE_KEYNOTFOUND;
197  return 0;
198 }
199 
200 template<class Key,class Element,class GetIndex,int hashsize>
201 inline bool RTPKeyHashTable<Key,Element,GetIndex,hashsize>::HasElement(const Key &k)
202 {
203  int index;
204  bool found;
205  HashElement *tmp;
206 
207  index = GetIndex::GetIndex(k);
208  if (index >= hashsize)
209  return false;
210 
211  tmp = table[index];
212  found = false;
213  while(!found && tmp != 0)
214  {
215  if (tmp->GetKey() == k)
216  found = true;
217  else
218  tmp = tmp->hashnext;
219  }
220  return found;
221 }
222 
223 template<class Key,class Element,class GetIndex,int hashsize>
224 inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::GotoNextElement()
225 {
226  if (curhashelem)
227  curhashelem = curhashelem->listnext;
228 }
229 
230 template<class Key,class Element,class GetIndex,int hashsize>
231 inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::GotoPreviousElement()
232 {
233  if (curhashelem)
234  curhashelem = curhashelem->listprev;
235 }
236 
237 template<class Key,class Element,class GetIndex,int hashsize>
238 inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::Clear()
239 {
240  HashElement *tmp1,*tmp2;
241 
242  for (int i = 0 ; i < hashsize ; i++)
243  table[i] = 0;
244 
245  tmp1 = firsthashelem;
246  while (tmp1 != 0)
247  {
248  tmp2 = tmp1->listnext;
249  RTPDelete(tmp1,GetMemoryManager());
250  tmp1 = tmp2;
251  }
252  firsthashelem = 0;
253  lasthashelem = 0;
254 }
255 
256 template<class Key,class Element,class GetIndex,int hashsize>
257 inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::AddElement(const Key &k,const Element &elem)
258 {
259  int index;
260  bool found;
261  HashElement *e,*newelem;
262 
263  index = GetIndex::GetIndex(k);
264  if (index >= hashsize)
265  return ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
266 
267  e = table[index];
268  found = false;
269  while(!found && e != 0)
270  {
271  if (e->GetKey() == k)
272  found = true;
273  else
274  e = e->hashnext;
275  }
276  if (found)
277  return ERR_RTP_KEYHASHTABLE_KEYALREADYEXISTS;
278 
279  // Okay, the key doesn't exist, so we can add the new element in the hash table
280 
281  newelem = RTPNew(GetMemoryManager(),memorytype) HashElement(k,elem,index);
282  if (newelem == 0)
283  return ERR_RTP_OUTOFMEM;
284 
285  e = table[index];
286  table[index] = newelem;
287  newelem->hashnext = e;
288  if (e != 0)
289  e->hashprev = newelem;
290 
291  // Now, we still got to add it to the linked list
292 
293  if (firsthashelem == 0)
294  {
295  firsthashelem = newelem;
296  lasthashelem = newelem;
297  }
298  else // there already are some elements in the list
299  {
300  lasthashelem->listnext = newelem;
301  newelem->listprev = lasthashelem;
302  lasthashelem = newelem;
303  }
304  return 0;
305 }
306 
307 template<class Key,class Element,class GetIndex,int hashsize>
308 inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::DeleteElement(const Key &k)
309 {
310  int status;
311 
312  status = GotoElement(k);
313  if (status < 0)
314  return status;
315  return DeleteCurrentElement();
316 }
317 
318 #ifdef RTPDEBUG
319 template<class Key,class Element,class GetIndex,int hashsize>
320 inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::Dump()
321 {
322  HashElement *e;
323 
324  std::cout << "DUMPING TABLE CONTENTS:" << std::endl;
325  for (int i = 0 ; i < hashsize ; i++)
326  {
327  e = table[i];
328  while (e != 0)
329  {
330  e->Dump();
331  e = e->hashnext;
332  }
333  }
334 
335  std::cout << "DUMPING LIST CONTENTS:" << std::endl;
336  e = firsthashelem;
337  while (e != 0)
338  {
339  e->Dump();
340  e = e->listnext;
341  }
342 }
343 #endif // RTPDEBUG
344 
345 } // end namespace
346 
347 #endif // RTPKEYHASHTABLE_H
#define RTPMEM_TYPE_OTHER
Used to indicate a general kind of memory block.
Definition: rtpmemorymanager.h:45