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