1 #ifndef GIM_HASH_TABLE_H_INCLUDED
2 #define GIM_HASH_TABLE_H_INCLUDED
3 /*! \file gim_trimesh_data.h
4 \author Francisco Leon Najera
5 */
6 /*
7 -----------------------------------------------------------------------------
8 This source file is part of GIMPACT Library.
9
10 For the latest info, see http://gimpact.sourceforge.net/
11
12 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
13 email: projectileman@yahoo.com
14
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of EITHER:
17 (1) The GNU Lesser General Public License as published by the Free
18 Software Foundation; either version 2.1 of the License, or (at
19 your option) any later version. The text of the GNU Lesser
20 General Public License is included with this library in the
21 file GIMPACT-LICENSE-LGPL.TXT.
22 (2) The BSD-style license that is included with this library in
23 the file GIMPACT-LICENSE-BSD.TXT.
24 (3) The zlib/libpng license that is included with this library in
25 the file GIMPACT-LICENSE-ZLIB.TXT.
26
27 This library is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
30 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
31
32 -----------------------------------------------------------------------------
33 */
34
35 #include "gim_radixsort.h"
36
37 #define GIM_INVALID_HASH 0xffffffff //!< A very very high value
38 #define GIM_DEFAULT_HASH_TABLE_SIZE 380
39 #define GIM_DEFAULT_HASH_TABLE_NODE_SIZE 4
40 #define GIM_HASH_TABLE_GROW_FACTOR 2
41
42 #define GIM_MIN_RADIX_SORT_SIZE 860 //!< calibrated on a PIII
43
44 template <typename T>
45 struct GIM_HASH_TABLE_NODE
46 {
47 GUINT m_key;
48 T m_data;
GIM_HASH_TABLE_NODEGIM_HASH_TABLE_NODE49 GIM_HASH_TABLE_NODE()
50 {
51 }
52
GIM_HASH_TABLE_NODEGIM_HASH_TABLE_NODE53 GIM_HASH_TABLE_NODE(const GIM_HASH_TABLE_NODE& value)
54 {
55 m_key = value.m_key;
56 m_data = value.m_data;
57 }
58
GIM_HASH_TABLE_NODEGIM_HASH_TABLE_NODE59 GIM_HASH_TABLE_NODE(GUINT key, const T& data)
60 {
61 m_key = key;
62 m_data = data;
63 }
64
65 bool operator<(const GIM_HASH_TABLE_NODE<T>& other) const
66 {
67 ///inverse order, further objects are first
68 if (m_key < other.m_key) return true;
69 return false;
70 }
71
72 bool operator>(const GIM_HASH_TABLE_NODE<T>& other) const
73 {
74 ///inverse order, further objects are first
75 if (m_key > other.m_key) return true;
76 return false;
77 }
78
79 bool operator==(const GIM_HASH_TABLE_NODE<T>& other) const
80 {
81 ///inverse order, further objects are first
82 if (m_key == other.m_key) return true;
83 return false;
84 }
85 };
86
87 ///Macro for getting the key
88 class GIM_HASH_NODE_GET_KEY
89 {
90 public:
91 template <class T>
operator()92 inline GUINT operator()(const T& a)
93 {
94 return a.m_key;
95 }
96 };
97
98 ///Macro for comparing the key and the element
99 class GIM_HASH_NODE_CMP_KEY_MACRO
100 {
101 public:
102 template <class T>
operator()103 inline int operator()(const T& a, GUINT key)
104 {
105 return ((int)(a.m_key - key));
106 }
107 };
108
109 ///Macro for comparing Hash nodes
110 class GIM_HASH_NODE_CMP_MACRO
111 {
112 public:
113 template <class T>
operator()114 inline int operator()(const T& a, const T& b)
115 {
116 return ((int)(a.m_key - b.m_key));
117 }
118 };
119
120 //! Sorting for hash table
121 /*!
122 switch automatically between quicksort and radixsort
123 */
124 template <typename T>
gim_sort_hash_node_array(T * array,GUINT array_count)125 void gim_sort_hash_node_array(T* array, GUINT array_count)
126 {
127 if (array_count < GIM_MIN_RADIX_SORT_SIZE)
128 {
129 gim_heap_sort(array, array_count, GIM_HASH_NODE_CMP_MACRO());
130 }
131 else
132 {
133 memcopy_elements_func cmpfunc;
134 gim_radix_sort(array, array_count, GIM_HASH_NODE_GET_KEY(), cmpfunc);
135 }
136 }
137
138 // Note: assumes long is at least 32 bits.
139 #define GIM_NUM_PRIME 28
140
141 static const GUINT gim_prime_list[GIM_NUM_PRIME] =
142 {
143 53ul, 97ul, 193ul, 389ul, 769ul,
144 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
145 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
146 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
147 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
148 1610612741ul, 3221225473ul, 4294967291ul};
149
gim_next_prime(GUINT number)150 inline GUINT gim_next_prime(GUINT number)
151 {
152 //Find nearest upper prime
153 GUINT result_ind = 0;
154 gim_binary_search(gim_prime_list, 0, (GIM_NUM_PRIME - 2), number, result_ind);
155
156 // inv: result_ind < 28
157 return gim_prime_list[result_ind];
158 }
159
160 //! A compact hash table implementation
161 /*!
162 A memory aligned compact hash table that coud be treated as an array.
163 It could be a simple sorted array without the overhead of the hash key bucked, or could
164 be a formely hash table with an array of keys.
165 You can use switch_to_hashtable() and switch_to_sorted_array for saving space or increase speed.
166 </br>
167
168 <ul>
169 <li> if node_size = 0, then this container becomes a simple sorted array allocator. reserve_size is used for reserve memory in m_nodes.
170 When the array size reaches the size equivalent to 'min_hash_table_size', then it becomes a hash table by calling check_for_switching_to_hashtable.
171 <li> If node_size != 0, then this container becomes a hash table for ever
172 </ul>
173
174 */
175 template <class T>
176 class gim_hash_table
177 {
178 protected:
179 typedef GIM_HASH_TABLE_NODE<T> _node_type;
180
181 //!The nodes
182 //array< _node_type, SuperAllocator<_node_type> > m_nodes;
183 gim_array<_node_type> m_nodes;
184 //SuperBufferedArray< _node_type > m_nodes;
185 bool m_sorted;
186
187 ///Hash table data management. The hash table has the indices to the corresponding m_nodes array
188 GUINT* m_hash_table; //!<
189 GUINT m_table_size; //!<
190 GUINT m_node_size; //!<
191 GUINT m_min_hash_table_size;
192
193 //! Returns the cell index
_find_cell(GUINT hashkey)194 inline GUINT _find_cell(GUINT hashkey)
195 {
196 _node_type* nodesptr = m_nodes.pointer();
197 GUINT start_index = (hashkey % m_table_size) * m_node_size;
198 GUINT end_index = start_index + m_node_size;
199
200 while (start_index < end_index)
201 {
202 GUINT value = m_hash_table[start_index];
203 if (value != GIM_INVALID_HASH)
204 {
205 if (nodesptr[value].m_key == hashkey) return start_index;
206 }
207 start_index++;
208 }
209 return GIM_INVALID_HASH;
210 }
211
212 //! Find the avaliable cell for the hashkey, and return an existing cell if it has the same hash key
_find_avaliable_cell(GUINT hashkey)213 inline GUINT _find_avaliable_cell(GUINT hashkey)
214 {
215 _node_type* nodesptr = m_nodes.pointer();
216 GUINT avaliable_index = GIM_INVALID_HASH;
217 GUINT start_index = (hashkey % m_table_size) * m_node_size;
218 GUINT end_index = start_index + m_node_size;
219
220 while (start_index < end_index)
221 {
222 GUINT value = m_hash_table[start_index];
223 if (value == GIM_INVALID_HASH)
224 {
225 if (avaliable_index == GIM_INVALID_HASH)
226 {
227 avaliable_index = start_index;
228 }
229 }
230 else if (nodesptr[value].m_key == hashkey)
231 {
232 return start_index;
233 }
234 start_index++;
235 }
236 return avaliable_index;
237 }
238
239 //! reserves the memory for the hash table.
240 /*!
241 \pre hash table must be empty
242 \post reserves the memory for the hash table, an initializes all elements to GIM_INVALID_HASH.
243 */
_reserve_table_memory(GUINT newtablesize)244 inline void _reserve_table_memory(GUINT newtablesize)
245 {
246 if (newtablesize == 0) return;
247 if (m_node_size == 0) return;
248
249 //Get a Prime size
250
251 m_table_size = gim_next_prime(newtablesize);
252
253 GUINT datasize = m_table_size * m_node_size;
254 //Alloc the data buffer
255 m_hash_table = (GUINT*)gim_alloc(datasize * sizeof(GUINT));
256 }
257
_invalidate_keys()258 inline void _invalidate_keys()
259 {
260 GUINT datasize = m_table_size * m_node_size;
261 for (GUINT i = 0; i < datasize; i++)
262 {
263 m_hash_table[i] = GIM_INVALID_HASH; // invalidate keys
264 }
265 }
266
267 //! Clear all memory for the hash table
_clear_table_memory()268 inline void _clear_table_memory()
269 {
270 if (m_hash_table == NULL) return;
271 gim_free(m_hash_table);
272 m_hash_table = NULL;
273 m_table_size = 0;
274 }
275
276 //! Invalidates the keys (Assigning GIM_INVALID_HASH to all) Reorders the hash keys
_rehash()277 inline void _rehash()
278 {
279 _invalidate_keys();
280
281 _node_type* nodesptr = m_nodes.pointer();
282 for (GUINT i = 0; i < (GUINT)m_nodes.size(); i++)
283 {
284 GUINT nodekey = nodesptr[i].m_key;
285 if (nodekey != GIM_INVALID_HASH)
286 {
287 //Search for the avaliable cell in buffer
288 GUINT index = _find_avaliable_cell(nodekey);
289
290 if (m_hash_table[index] != GIM_INVALID_HASH)
291 { //The new index is alreade used... discard this new incomming object, repeated key
292 btAssert(m_hash_table[index] == nodekey);
293 nodesptr[i].m_key = GIM_INVALID_HASH;
294 }
295 else
296 {
297 //;
298 //Assign the value for alloc
299 m_hash_table[index] = i;
300 }
301 }
302 }
303 }
304
305 //! Resize hash table indices
_resize_table(GUINT newsize)306 inline void _resize_table(GUINT newsize)
307 {
308 //Clear memory
309 _clear_table_memory();
310 //Alloc the data
311 _reserve_table_memory(newsize);
312 //Invalidate keys and rehash
313 _rehash();
314 }
315
316 //! Destroy hash table memory
_destroy()317 inline void _destroy()
318 {
319 if (m_hash_table == NULL) return;
320 _clear_table_memory();
321 }
322
323 //! Finds an avaliable hash table cell, and resizes the table if there isn't space
_assign_hash_table_cell(GUINT hashkey)324 inline GUINT _assign_hash_table_cell(GUINT hashkey)
325 {
326 GUINT cell_index = _find_avaliable_cell(hashkey);
327
328 if (cell_index == GIM_INVALID_HASH)
329 {
330 //rehashing
331 _resize_table(m_table_size + 1);
332 GUINT cell_index = _find_avaliable_cell(hashkey);
333 btAssert(cell_index != GIM_INVALID_HASH);
334 }
335 return cell_index;
336 }
337
338 //! erase by index in hash table
_erase_by_index_hash_table(GUINT index)339 inline bool _erase_by_index_hash_table(GUINT index)
340 {
341 if (index >= m_nodes.size()) return false;
342 if (m_nodes[index].m_key != GIM_INVALID_HASH)
343 {
344 //Search for the avaliable cell in buffer
345 GUINT cell_index = _find_cell(m_nodes[index].m_key);
346
347 btAssert(cell_index != GIM_INVALID_HASH);
348 btAssert(m_hash_table[cell_index] == index);
349
350 m_hash_table[cell_index] = GIM_INVALID_HASH;
351 }
352
353 return this->_erase_unsorted(index);
354 }
355
356 //! erase by key in hash table
_erase_hash_table(GUINT hashkey)357 inline bool _erase_hash_table(GUINT hashkey)
358 {
359 if (hashkey == GIM_INVALID_HASH) return false;
360
361 //Search for the avaliable cell in buffer
362 GUINT cell_index = _find_cell(hashkey);
363 if (cell_index == GIM_INVALID_HASH) return false;
364
365 GUINT index = m_hash_table[cell_index];
366 m_hash_table[cell_index] = GIM_INVALID_HASH;
367
368 return this->_erase_unsorted(index);
369 }
370
371 //! insert an element in hash table
372 /*!
373 If the element exists, this won't insert the element
374 \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted
375 If so, the element has been inserted at the last position of the array.
376 */
_insert_hash_table(GUINT hashkey,const T & value)377 inline GUINT _insert_hash_table(GUINT hashkey, const T& value)
378 {
379 if (hashkey == GIM_INVALID_HASH)
380 {
381 //Insert anyway
382 _insert_unsorted(hashkey, value);
383 return GIM_INVALID_HASH;
384 }
385
386 GUINT cell_index = _assign_hash_table_cell(hashkey);
387
388 GUINT value_key = m_hash_table[cell_index];
389
390 if (value_key != GIM_INVALID_HASH) return value_key; // Not overrited
391
392 m_hash_table[cell_index] = m_nodes.size();
393
394 _insert_unsorted(hashkey, value);
395 return GIM_INVALID_HASH;
396 }
397
398 //! insert an element in hash table.
399 /*!
400 If the element exists, this replaces the element.
401 \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted
402 If so, the element has been inserted at the last position of the array.
403 */
_insert_hash_table_replace(GUINT hashkey,const T & value)404 inline GUINT _insert_hash_table_replace(GUINT hashkey, const T& value)
405 {
406 if (hashkey == GIM_INVALID_HASH)
407 {
408 //Insert anyway
409 _insert_unsorted(hashkey, value);
410 return GIM_INVALID_HASH;
411 }
412
413 GUINT cell_index = _assign_hash_table_cell(hashkey);
414
415 GUINT value_key = m_hash_table[cell_index];
416
417 if (value_key != GIM_INVALID_HASH)
418 { //replaces the existing
419 m_nodes[value_key] = _node_type(hashkey, value);
420 return value_key; // index of the replaced element
421 }
422
423 m_hash_table[cell_index] = m_nodes.size();
424
425 _insert_unsorted(hashkey, value);
426 return GIM_INVALID_HASH;
427 }
428
429 ///Sorted array data management. The hash table has the indices to the corresponding m_nodes array
_erase_sorted(GUINT index)430 inline bool _erase_sorted(GUINT index)
431 {
432 if (index >= (GUINT)m_nodes.size()) return false;
433 m_nodes.erase_sorted(index);
434 if (m_nodes.size() < 2) m_sorted = false;
435 return true;
436 }
437
438 //! faster, but unsorted
_erase_unsorted(GUINT index)439 inline bool _erase_unsorted(GUINT index)
440 {
441 if (index >= m_nodes.size()) return false;
442
443 GUINT lastindex = m_nodes.size() - 1;
444 if (index < lastindex && m_hash_table != 0)
445 {
446 GUINT hashkey = m_nodes[lastindex].m_key;
447 if (hashkey != GIM_INVALID_HASH)
448 {
449 //update the new position of the last element
450 GUINT cell_index = _find_cell(hashkey);
451 btAssert(cell_index != GIM_INVALID_HASH);
452 //new position of the last element which will be swaped
453 m_hash_table[cell_index] = index;
454 }
455 }
456 m_nodes.erase(index);
457 m_sorted = false;
458 return true;
459 }
460
461 //! Insert in position ordered
462 /*!
463 Also checks if it is needed to transform this container to a hash table, by calling check_for_switching_to_hashtable
464 */
_insert_in_pos(GUINT hashkey,const T & value,GUINT pos)465 inline void _insert_in_pos(GUINT hashkey, const T& value, GUINT pos)
466 {
467 m_nodes.insert(_node_type(hashkey, value), pos);
468 this->check_for_switching_to_hashtable();
469 }
470
471 //! Insert an element in an ordered array
_insert_sorted(GUINT hashkey,const T & value)472 inline GUINT _insert_sorted(GUINT hashkey, const T& value)
473 {
474 if (hashkey == GIM_INVALID_HASH || size() == 0)
475 {
476 m_nodes.push_back(_node_type(hashkey, value));
477 return GIM_INVALID_HASH;
478 }
479 //Insert at last position
480 //Sort element
481
482 GUINT result_ind = 0;
483 GUINT last_index = m_nodes.size() - 1;
484 _node_type* ptr = m_nodes.pointer();
485
486 bool found = gim_binary_search_ex(
487 ptr, 0, last_index, result_ind, hashkey, GIM_HASH_NODE_CMP_KEY_MACRO());
488
489 //Insert before found index
490 if (found)
491 {
492 return result_ind;
493 }
494 else
495 {
496 _insert_in_pos(hashkey, value, result_ind);
497 }
498 return GIM_INVALID_HASH;
499 }
500
_insert_sorted_replace(GUINT hashkey,const T & value)501 inline GUINT _insert_sorted_replace(GUINT hashkey, const T& value)
502 {
503 if (hashkey == GIM_INVALID_HASH || size() == 0)
504 {
505 m_nodes.push_back(_node_type(hashkey, value));
506 return GIM_INVALID_HASH;
507 }
508 //Insert at last position
509 //Sort element
510 GUINT result_ind;
511 GUINT last_index = m_nodes.size() - 1;
512 _node_type* ptr = m_nodes.pointer();
513
514 bool found = gim_binary_search_ex(
515 ptr, 0, last_index, result_ind, hashkey, GIM_HASH_NODE_CMP_KEY_MACRO());
516
517 //Insert before found index
518 if (found)
519 {
520 m_nodes[result_ind] = _node_type(hashkey, value);
521 }
522 else
523 {
524 _insert_in_pos(hashkey, value, result_ind);
525 }
526 return result_ind;
527 }
528
529 //! Fast insertion in m_nodes array
_insert_unsorted(GUINT hashkey,const T & value)530 inline GUINT _insert_unsorted(GUINT hashkey, const T& value)
531 {
532 m_nodes.push_back(_node_type(hashkey, value));
533 m_sorted = false;
534 return GIM_INVALID_HASH;
535 }
536
537 public:
538 /*!
539 <li> if node_size = 0, then this container becomes a simple sorted array allocator. reserve_size is used for reserve memory in m_nodes.
540 When the array size reaches the size equivalent to 'min_hash_table_size', then it becomes a hash table by calling check_for_switching_to_hashtable.
541 <li> If node_size != 0, then this container becomes a hash table for ever
542 </ul>
543 */
544 gim_hash_table(GUINT reserve_size = GIM_DEFAULT_HASH_TABLE_SIZE,
545 GUINT node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE,
546 GUINT min_hash_table_size = GIM_INVALID_HASH)
547 {
548 m_hash_table = NULL;
549 m_table_size = 0;
550 m_sorted = false;
551 m_node_size = node_size;
552 m_min_hash_table_size = min_hash_table_size;
553
554 if (m_node_size != 0)
555 {
556 if (reserve_size != 0)
557 {
558 m_nodes.reserve(reserve_size);
559 _reserve_table_memory(reserve_size);
560 _invalidate_keys();
561 }
562 else
563 {
564 m_nodes.reserve(GIM_DEFAULT_HASH_TABLE_SIZE);
565 _reserve_table_memory(GIM_DEFAULT_HASH_TABLE_SIZE);
566 _invalidate_keys();
567 }
568 }
569 else if (reserve_size != 0)
570 {
571 m_nodes.reserve(reserve_size);
572 }
573 }
574
~gim_hash_table()575 ~gim_hash_table()
576 {
577 _destroy();
578 }
579
is_hash_table()580 inline bool is_hash_table()
581 {
582 if (m_hash_table) return true;
583 return false;
584 }
585
is_sorted()586 inline bool is_sorted()
587 {
588 if (size() < 2) return true;
589 return m_sorted;
590 }
591
sort()592 bool sort()
593 {
594 if (is_sorted()) return true;
595 if (m_nodes.size() < 2) return false;
596
597 _node_type* ptr = m_nodes.pointer();
598 GUINT siz = m_nodes.size();
599 gim_sort_hash_node_array(ptr, siz);
600 m_sorted = true;
601
602 if (m_hash_table)
603 {
604 _rehash();
605 }
606 return true;
607 }
608
switch_to_hashtable()609 bool switch_to_hashtable()
610 {
611 if (m_hash_table) return false;
612 if (m_node_size == 0) m_node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE;
613 if (m_nodes.size() < GIM_DEFAULT_HASH_TABLE_SIZE)
614 {
615 _resize_table(GIM_DEFAULT_HASH_TABLE_SIZE);
616 }
617 else
618 {
619 _resize_table(m_nodes.size() + 1);
620 }
621
622 return true;
623 }
624
switch_to_sorted_array()625 bool switch_to_sorted_array()
626 {
627 if (m_hash_table == NULL) return true;
628 _clear_table_memory();
629 return sort();
630 }
631
632 //!If the container reaches the
check_for_switching_to_hashtable()633 bool check_for_switching_to_hashtable()
634 {
635 if (this->m_hash_table) return true;
636
637 if (!(m_nodes.size() < m_min_hash_table_size))
638 {
639 if (m_node_size == 0)
640 {
641 m_node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE;
642 }
643
644 _resize_table(m_nodes.size() + 1);
645 return true;
646 }
647 return false;
648 }
649
set_sorted(bool value)650 inline void set_sorted(bool value)
651 {
652 m_sorted = value;
653 }
654
655 //! Retrieves the amount of keys.
size()656 inline GUINT size() const
657 {
658 return m_nodes.size();
659 }
660
661 //! Retrieves the hash key.
get_key(GUINT index)662 inline GUINT get_key(GUINT index) const
663 {
664 return m_nodes[index].m_key;
665 }
666
667 //! Retrieves the value by index
668 /*!
669 */
get_value_by_index(GUINT index)670 inline T* get_value_by_index(GUINT index)
671 {
672 return &m_nodes[index].m_data;
673 }
674
675 inline const T& operator[](GUINT index) const
676 {
677 return m_nodes[index].m_data;
678 }
679
680 inline T& operator[](GUINT index)
681 {
682 return m_nodes[index].m_data;
683 }
684
685 //! Finds the index of the element with the key
686 /*!
687 \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted
688 If so, the element has been inserted at the last position of the array.
689 */
find(GUINT hashkey)690 inline GUINT find(GUINT hashkey)
691 {
692 if (m_hash_table)
693 {
694 GUINT cell_index = _find_cell(hashkey);
695 if (cell_index == GIM_INVALID_HASH) return GIM_INVALID_HASH;
696 return m_hash_table[cell_index];
697 }
698 GUINT last_index = m_nodes.size();
699 if (last_index < 2)
700 {
701 if (last_index == 0) return GIM_INVALID_HASH;
702 if (m_nodes[0].m_key == hashkey) return 0;
703 return GIM_INVALID_HASH;
704 }
705 else if (m_sorted)
706 {
707 //Binary search
708 GUINT result_ind = 0;
709 last_index--;
710 _node_type* ptr = m_nodes.pointer();
711
712 bool found = gim_binary_search_ex(ptr, 0, last_index, result_ind, hashkey, GIM_HASH_NODE_CMP_KEY_MACRO());
713
714 if (found) return result_ind;
715 }
716 return GIM_INVALID_HASH;
717 }
718
719 //! Retrieves the value associated with the index
720 /*!
721 \return the found element, or null
722 */
get_value(GUINT hashkey)723 inline T* get_value(GUINT hashkey)
724 {
725 GUINT index = find(hashkey);
726 if (index == GIM_INVALID_HASH) return NULL;
727 return &m_nodes[index].m_data;
728 }
729
730 /*!
731 */
erase_by_index(GUINT index)732 inline bool erase_by_index(GUINT index)
733 {
734 if (index > m_nodes.size()) return false;
735
736 if (m_hash_table == NULL)
737 {
738 if (is_sorted())
739 {
740 return this->_erase_sorted(index);
741 }
742 else
743 {
744 return this->_erase_unsorted(index);
745 }
746 }
747 else
748 {
749 return this->_erase_by_index_hash_table(index);
750 }
751 return false;
752 }
753
erase_by_index_unsorted(GUINT index)754 inline bool erase_by_index_unsorted(GUINT index)
755 {
756 if (index > m_nodes.size()) return false;
757
758 if (m_hash_table == NULL)
759 {
760 return this->_erase_unsorted(index);
761 }
762 else
763 {
764 return this->_erase_by_index_hash_table(index);
765 }
766 return false;
767 }
768
769 /*!
770
771 */
erase_by_key(GUINT hashkey)772 inline bool erase_by_key(GUINT hashkey)
773 {
774 if (size() == 0) return false;
775
776 if (m_hash_table)
777 {
778 return this->_erase_hash_table(hashkey);
779 }
780 //Binary search
781
782 if (is_sorted() == false) return false;
783
784 GUINT result_ind = find(hashkey);
785 if (result_ind != GIM_INVALID_HASH)
786 {
787 return this->_erase_sorted(result_ind);
788 }
789 return false;
790 }
791
clear()792 void clear()
793 {
794 m_nodes.clear();
795
796 if (m_hash_table == NULL) return;
797 GUINT datasize = m_table_size * m_node_size;
798 //Initialize the hashkeys.
799 GUINT i;
800 for (i = 0; i < datasize; i++)
801 {
802 m_hash_table[i] = GIM_INVALID_HASH; // invalidate keys
803 }
804 m_sorted = false;
805 }
806
807 //! Insert an element into the hash
808 /*!
809 \return If GIM_INVALID_HASH, the object has been inserted succesfully. Else it returns the position
810 of the existing element.
811 */
insert(GUINT hashkey,const T & element)812 inline GUINT insert(GUINT hashkey, const T& element)
813 {
814 if (m_hash_table)
815 {
816 return this->_insert_hash_table(hashkey, element);
817 }
818 if (this->is_sorted())
819 {
820 return this->_insert_sorted(hashkey, element);
821 }
822 return this->_insert_unsorted(hashkey, element);
823 }
824
825 //! Insert an element into the hash, and could overrite an existing object with the same hash.
826 /*!
827 \return If GIM_INVALID_HASH, the object has been inserted succesfully. Else it returns the position
828 of the replaced element.
829 */
insert_override(GUINT hashkey,const T & element)830 inline GUINT insert_override(GUINT hashkey, const T& element)
831 {
832 if (m_hash_table)
833 {
834 return this->_insert_hash_table_replace(hashkey, element);
835 }
836 if (this->is_sorted())
837 {
838 return this->_insert_sorted_replace(hashkey, element);
839 }
840 this->_insert_unsorted(hashkey, element);
841 return m_nodes.size();
842 }
843
844 //! Insert an element into the hash,But if this container is a sorted array, this inserts it unsorted
845 /*!
846 */
insert_unsorted(GUINT hashkey,const T & element)847 inline GUINT insert_unsorted(GUINT hashkey, const T& element)
848 {
849 if (m_hash_table)
850 {
851 return this->_insert_hash_table(hashkey, element);
852 }
853 return this->_insert_unsorted(hashkey, element);
854 }
855 };
856
857 #endif // GIM_CONTAINERS_H_INCLUDED
858