forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			903 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			903 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#ifndef GIM_HASH_TABLE_H_INCLUDED
							 | 
						||
| 
								 | 
							
								#define GIM_HASH_TABLE_H_INCLUDED
							 | 
						||
| 
								 | 
							
								/*! \file gim_trimesh_data.h
							 | 
						||
| 
								 | 
							
								\author Francisco Leon Najera
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								-----------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								This source file is part of GIMPACT Library.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For the latest info, see http://gimpact.sourceforge.net/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
							 | 
						||
| 
								 | 
							
								email: projectileman@yahoo.com
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 This library is free software; you can redistribute it and/or
							 | 
						||
| 
								 | 
							
								 modify it under the terms of EITHER:
							 | 
						||
| 
								 | 
							
								   (1) The GNU Lesser General Public License as published by the Free
							 | 
						||
| 
								 | 
							
								       Software Foundation; either version 2.1 of the License, or (at
							 | 
						||
| 
								 | 
							
								       your option) any later version. The text of the GNU Lesser
							 | 
						||
| 
								 | 
							
								       General Public License is included with this library in the
							 | 
						||
| 
								 | 
							
								       file GIMPACT-LICENSE-LGPL.TXT.
							 | 
						||
| 
								 | 
							
								   (2) The BSD-style license that is included with this library in
							 | 
						||
| 
								 | 
							
								       the file GIMPACT-LICENSE-BSD.TXT.
							 | 
						||
| 
								 | 
							
								   (3) The zlib/libpng license that is included with this library in
							 | 
						||
| 
								 | 
							
								       the file GIMPACT-LICENSE-ZLIB.TXT.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 This library is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								 but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
							 | 
						||
| 
								 | 
							
								 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								-----------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "gim_radixsort.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define GIM_INVALID_HASH 0xffffffff //!< A very very high value
							 | 
						||
| 
								 | 
							
								#define GIM_DEFAULT_HASH_TABLE_SIZE 380
							 | 
						||
| 
								 | 
							
								#define GIM_DEFAULT_HASH_TABLE_NODE_SIZE 4
							 | 
						||
| 
								 | 
							
								#define GIM_HASH_TABLE_GROW_FACTOR 2
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define GIM_MIN_RADIX_SORT_SIZE 860 //!< calibrated on a PIII
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								struct GIM_HASH_TABLE_NODE
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    GUINT m_key;
							 | 
						||
| 
								 | 
							
								    T m_data;
							 | 
						||
| 
								 | 
							
								    GIM_HASH_TABLE_NODE()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    GIM_HASH_TABLE_NODE(const GIM_HASH_TABLE_NODE & value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        m_key = value.m_key;
							 | 
						||
| 
								 | 
							
								        m_data = value.m_data;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    GIM_HASH_TABLE_NODE(GUINT key, const T & data)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        m_key = key;
							 | 
						||
| 
								 | 
							
								        m_data = data;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool operator <(const GIM_HASH_TABLE_NODE<T> & other) const
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										///inverse order, further objects are first
							 | 
						||
| 
								 | 
							
										if(m_key <  other.m_key) return true;
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bool operator >(const GIM_HASH_TABLE_NODE<T> & other) const
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										///inverse order, further objects are first
							 | 
						||
| 
								 | 
							
										if(m_key >  other.m_key) return true;
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bool operator ==(const GIM_HASH_TABLE_NODE<T> & other) const
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										///inverse order, further objects are first
							 | 
						||
| 
								 | 
							
										if(m_key ==  other.m_key) return true;
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///Macro for getting the key
							 | 
						||
| 
								 | 
							
								class GIM_HASH_NODE_GET_KEY
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
									template<class T>
							 | 
						||
| 
								 | 
							
									inline GUINT operator()( const T& a)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return a.m_key;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///Macro for comparing the key and the element
							 | 
						||
| 
								 | 
							
								class GIM_HASH_NODE_CMP_KEY_MACRO
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
									template<class T>
							 | 
						||
| 
								 | 
							
									inline int operator() ( const T& a, GUINT key)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return ((int)(a.m_key - key));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///Macro for comparing Hash nodes
							 | 
						||
| 
								 | 
							
								class GIM_HASH_NODE_CMP_MACRO
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
									template<class T>
							 | 
						||
| 
								 | 
							
									inline int operator() ( const T& a, const T& b )
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return ((int)(a.m_key - b.m_key));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//! Sorting for hash table
							 | 
						||
| 
								 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								switch automatically between quicksort and radixsort
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								template<typename T>
							 | 
						||
| 
								 | 
							
								void gim_sort_hash_node_array(T * array, GUINT array_count)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if(array_count<GIM_MIN_RADIX_SORT_SIZE)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    	gim_heap_sort(array,array_count,GIM_HASH_NODE_CMP_MACRO());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    	memcopy_elements_func cmpfunc;
							 | 
						||
| 
								 | 
							
								    	gim_radix_sort(array,array_count,GIM_HASH_NODE_GET_KEY(),cmpfunc);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Note: assumes long is at least 32 bits.
							 | 
						||
| 
								 | 
							
								#define GIM_NUM_PRIME 28
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const GUINT gim_prime_list[GIM_NUM_PRIME] =
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  53ul,         97ul,         193ul,       389ul,       769ul,
							 | 
						||
| 
								 | 
							
								  1543ul,       3079ul,       6151ul,      12289ul,     24593ul,
							 | 
						||
| 
								 | 
							
								  49157ul,      98317ul,      196613ul,    393241ul,    786433ul,
							 | 
						||
| 
								 | 
							
								  1572869ul,    3145739ul,    6291469ul,   12582917ul,  25165843ul,
							 | 
						||
| 
								 | 
							
								  50331653ul,   100663319ul,  201326611ul, 402653189ul, 805306457ul,
							 | 
						||
| 
								 | 
							
								  1610612741ul, 3221225473ul, 4294967291ul
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								inline GUINT gim_next_prime(GUINT number)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    //Find nearest upper prime
							 | 
						||
| 
								 | 
							
								    GUINT result_ind = 0;
							 | 
						||
| 
								 | 
							
								    gim_binary_search(gim_prime_list,0,(GIM_NUM_PRIME-2),number,result_ind);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // inv: result_ind < 28
							 | 
						||
| 
								 | 
							
								    return gim_prime_list[result_ind];
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//! A compact hash table implementation
							 | 
						||
| 
								 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								A memory aligned compact hash table that coud be treated as an array.
							 | 
						||
| 
								 | 
							
								It could be a simple sorted array without the overhead of the hash key bucked, or could
							 | 
						||
| 
								 | 
							
								be a formely hash table with an array of keys.
							 | 
						||
| 
								 | 
							
								You can use switch_to_hashtable() and switch_to_sorted_array for saving space or increase speed.
							 | 
						||
| 
								 | 
							
								</br>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<ul>
							 | 
						||
| 
								 | 
							
								<li> if node_size = 0, then this container becomes a simple sorted array allocator. reserve_size is used for reserve memory in m_nodes.
							 | 
						||
| 
								 | 
							
								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.
							 | 
						||
| 
								 | 
							
								<li> If node_size != 0, then this container becomes a hash table for ever
							 | 
						||
| 
								 | 
							
								</ul>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								template<class T>
							 | 
						||
| 
								 | 
							
								class gim_hash_table
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
								    typedef GIM_HASH_TABLE_NODE<T> _node_type;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //!The nodes
							 | 
						||
| 
								 | 
							
								    //array< _node_type, SuperAllocator<_node_type> > m_nodes;
							 | 
						||
| 
								 | 
							
								    gim_array< _node_type > m_nodes;
							 | 
						||
| 
								 | 
							
								    //SuperBufferedArray< _node_type > m_nodes;
							 | 
						||
| 
								 | 
							
								    bool m_sorted;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ///Hash table data management. The hash table has the indices to the corresponding m_nodes array
							 | 
						||
| 
								 | 
							
								    GUINT * m_hash_table;//!<
							 | 
						||
| 
								 | 
							
								    GUINT m_table_size;//!<
							 | 
						||
| 
								 | 
							
								    GUINT m_node_size;//!<
							 | 
						||
| 
								 | 
							
								    GUINT m_min_hash_table_size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Returns the cell index
							 | 
						||
| 
								 | 
							
								    inline GUINT _find_cell(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _node_type * nodesptr = m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								        GUINT start_index = (hashkey%m_table_size)*m_node_size;
							 | 
						||
| 
								 | 
							
								        GUINT end_index = start_index + m_node_size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        while(start_index<end_index)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            GUINT value = m_hash_table[start_index];
							 | 
						||
| 
								 | 
							
								            if(value != GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if(nodesptr[value].m_key == hashkey) return start_index;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            start_index++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Find the avaliable cell for the hashkey, and return an existing cell if it has the same hash key
							 | 
						||
| 
								 | 
							
								    inline GUINT _find_avaliable_cell(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _node_type * nodesptr = m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								        GUINT avaliable_index = GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        GUINT start_index = (hashkey%m_table_size)*m_node_size;
							 | 
						||
| 
								 | 
							
								        GUINT end_index = start_index + m_node_size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        while(start_index<end_index)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            GUINT value = m_hash_table[start_index];
							 | 
						||
| 
								 | 
							
								            if(value == GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if(avaliable_index==GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    avaliable_index = start_index;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if(nodesptr[value].m_key == hashkey)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return start_index;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            start_index++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return avaliable_index;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! reserves the memory for the hash table.
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    \pre hash table must be empty
							 | 
						||
| 
								 | 
							
								    \post reserves the memory for the hash table, an initializes all elements to GIM_INVALID_HASH.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline void _reserve_table_memory(GUINT newtablesize)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(newtablesize==0) return;
							 | 
						||
| 
								 | 
							
								        if(m_node_size==0) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Get a Prime size
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_table_size = gim_next_prime(newtablesize);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT datasize = m_table_size*m_node_size;
							 | 
						||
| 
								 | 
							
								        //Alloc the data buffer
							 | 
						||
| 
								 | 
							
								        m_hash_table =  (GUINT *)gim_alloc(datasize*sizeof(GUINT));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline void _invalidate_keys()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        GUINT datasize = m_table_size*m_node_size;
							 | 
						||
| 
								 | 
							
								        for(GUINT i=0;i<datasize;i++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_hash_table[i] = GIM_INVALID_HASH;// invalidate keys
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Clear all memory for the hash table
							 | 
						||
| 
								 | 
							
								    inline void _clear_table_memory()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table==NULL) return;
							 | 
						||
| 
								 | 
							
								        gim_free(m_hash_table);
							 | 
						||
| 
								 | 
							
								        m_hash_table = NULL;
							 | 
						||
| 
								 | 
							
								        m_table_size = 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Invalidates the keys (Assigning GIM_INVALID_HASH to all) Reorders the hash keys
							 | 
						||
| 
								 | 
							
								    inline void _rehash()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _invalidate_keys();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        _node_type * nodesptr = m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								        for(GUINT i=0;i<(GUINT)m_nodes.size();i++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            GUINT nodekey = nodesptr[i].m_key;
							 | 
						||
| 
								 | 
							
								            if(nodekey != GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                //Search for the avaliable cell in buffer
							 | 
						||
| 
								 | 
							
								                GUINT index = _find_avaliable_cell(nodekey);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if(m_hash_table[index]!=GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
												{//The new index is alreade used... discard this new incomming object, repeated key
							 | 
						||
| 
								 | 
							
												    btAssert(m_hash_table[index]==nodekey);
							 | 
						||
| 
								 | 
							
													nodesptr[i].m_key = GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												else
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													//;
							 | 
						||
| 
								 | 
							
													//Assign the value for alloc
							 | 
						||
| 
								 | 
							
													m_hash_table[index] = i;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Resize hash table indices
							 | 
						||
| 
								 | 
							
								    inline void _resize_table(GUINT newsize)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        //Clear memory
							 | 
						||
| 
								 | 
							
								        _clear_table_memory();
							 | 
						||
| 
								 | 
							
								        //Alloc the data
							 | 
						||
| 
								 | 
							
								        _reserve_table_memory(newsize);
							 | 
						||
| 
								 | 
							
								        //Invalidate keys and rehash
							 | 
						||
| 
								 | 
							
								        _rehash();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Destroy hash table memory
							 | 
						||
| 
								 | 
							
								    inline void _destroy()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table==NULL) return;
							 | 
						||
| 
								 | 
							
								        _clear_table_memory();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Finds an avaliable hash table cell, and resizes the table if there isn't space
							 | 
						||
| 
								 | 
							
								    inline GUINT _assign_hash_table_cell(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        GUINT cell_index = _find_avaliable_cell(hashkey);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(cell_index==GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            //rehashing
							 | 
						||
| 
								 | 
							
								            _resize_table(m_table_size+1);
							 | 
						||
| 
								 | 
							
								            GUINT cell_index = _find_avaliable_cell(hashkey);
							 | 
						||
| 
								 | 
							
								            btAssert(cell_index!=GIM_INVALID_HASH);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return cell_index;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! erase by index in hash table
							 | 
						||
| 
								 | 
							
								    inline bool _erase_by_index_hash_table(GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(index >= m_nodes.size()) return false;
							 | 
						||
| 
								 | 
							
								        if(m_nodes[index].m_key != GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            //Search for the avaliable cell in buffer
							 | 
						||
| 
								 | 
							
								            GUINT cell_index = _find_cell(m_nodes[index].m_key);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            btAssert(cell_index!=GIM_INVALID_HASH);
							 | 
						||
| 
								 | 
							
								            btAssert(m_hash_table[cell_index]==index);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            m_hash_table[cell_index] = GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return this->_erase_unsorted(index);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! erase by key in hash table
							 | 
						||
| 
								 | 
							
								    inline bool _erase_hash_table(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(hashkey == GIM_INVALID_HASH) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Search for the avaliable cell in buffer
							 | 
						||
| 
								 | 
							
								        GUINT cell_index = _find_cell(hashkey);
							 | 
						||
| 
								 | 
							
								        if(cell_index ==GIM_INVALID_HASH) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT index = m_hash_table[cell_index];
							 | 
						||
| 
								 | 
							
								        m_hash_table[cell_index] = GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return this->_erase_unsorted(index);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! insert an element in hash table
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    If the element exists, this won't insert the element
							 | 
						||
| 
								 | 
							
								    \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted
							 | 
						||
| 
								 | 
							
								    If so, the element has been inserted at the last position of the array.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline GUINT _insert_hash_table(GUINT hashkey, const T & value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(hashkey==GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            //Insert anyway
							 | 
						||
| 
								 | 
							
								            _insert_unsorted(hashkey,value);
							 | 
						||
| 
								 | 
							
								            return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT cell_index = _assign_hash_table_cell(hashkey);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT value_key = m_hash_table[cell_index];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(value_key!= GIM_INVALID_HASH) return value_key;// Not overrited
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_hash_table[cell_index] = m_nodes.size();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        _insert_unsorted(hashkey,value);
							 | 
						||
| 
								 | 
							
								        return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! insert an element in hash table.
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    If the element exists, this replaces the element.
							 | 
						||
| 
								 | 
							
								    \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted
							 | 
						||
| 
								 | 
							
								    If so, the element has been inserted at the last position of the array.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline GUINT _insert_hash_table_replace(GUINT hashkey, const T & value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(hashkey==GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            //Insert anyway
							 | 
						||
| 
								 | 
							
								            _insert_unsorted(hashkey,value);
							 | 
						||
| 
								 | 
							
								            return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT cell_index = _assign_hash_table_cell(hashkey);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT value_key = m_hash_table[cell_index];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(value_key!= GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								        {//replaces the existing
							 | 
						||
| 
								 | 
							
								            m_nodes[value_key] = _node_type(hashkey,value);
							 | 
						||
| 
								 | 
							
								            return value_key;// index of the replaced element
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        m_hash_table[cell_index] = m_nodes.size();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        _insert_unsorted(hashkey,value);
							 | 
						||
| 
								 | 
							
								        return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    ///Sorted array data management. The hash table has the indices to the corresponding m_nodes array
							 | 
						||
| 
								 | 
							
								    inline bool _erase_sorted(GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(index>=(GUINT)m_nodes.size()) return false;
							 | 
						||
| 
								 | 
							
								        m_nodes.erase_sorted(index);
							 | 
						||
| 
								 | 
							
										if(m_nodes.size()<2) m_sorted = false;
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! faster, but unsorted
							 | 
						||
| 
								 | 
							
								    inline bool _erase_unsorted(GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(index>=m_nodes.size()) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT lastindex = m_nodes.size()-1;
							 | 
						||
| 
								 | 
							
								        if(index<lastindex && m_hash_table!=0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
											GUINT hashkey =  m_nodes[lastindex].m_key;
							 | 
						||
| 
								 | 
							
											if(hashkey!=GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												//update the new position of the last element
							 | 
						||
| 
								 | 
							
												GUINT cell_index = _find_cell(hashkey);
							 | 
						||
| 
								 | 
							
												btAssert(cell_index!=GIM_INVALID_HASH);
							 | 
						||
| 
								 | 
							
												//new position of the last element which will be swaped
							 | 
						||
| 
								 | 
							
												m_hash_table[cell_index] = index;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        m_nodes.erase(index);
							 | 
						||
| 
								 | 
							
								        m_sorted = false;
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Insert in position ordered
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    Also checks if it is needed to transform this container to a hash table, by calling check_for_switching_to_hashtable
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline void _insert_in_pos(GUINT hashkey, const T & value, GUINT pos)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        m_nodes.insert(_node_type(hashkey,value),pos);
							 | 
						||
| 
								 | 
							
								        this->check_for_switching_to_hashtable();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Insert an element in an ordered array
							 | 
						||
| 
								 | 
							
								    inline GUINT _insert_sorted(GUINT hashkey, const T & value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(hashkey==GIM_INVALID_HASH || size()==0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_nodes.push_back(_node_type(hashkey,value));
							 | 
						||
| 
								 | 
							
								            return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        //Insert at last position
							 | 
						||
| 
								 | 
							
								        //Sort element
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT result_ind=0;
							 | 
						||
| 
								 | 
							
								        GUINT last_index = m_nodes.size()-1;
							 | 
						||
| 
								 | 
							
								        _node_type * ptr = m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        bool found = gim_binary_search_ex(
							 | 
						||
| 
								 | 
							
								        	ptr,0,last_index,result_ind,hashkey,GIM_HASH_NODE_CMP_KEY_MACRO());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Insert before found index
							 | 
						||
| 
								 | 
							
								        if(found)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return result_ind;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _insert_in_pos(hashkey, value, result_ind);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline GUINT _insert_sorted_replace(GUINT hashkey, const T & value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(hashkey==GIM_INVALID_HASH || size()==0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_nodes.push_back(_node_type(hashkey,value));
							 | 
						||
| 
								 | 
							
								            return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        //Insert at last position
							 | 
						||
| 
								 | 
							
								        //Sort element
							 | 
						||
| 
								 | 
							
								        GUINT result_ind;
							 | 
						||
| 
								 | 
							
								        GUINT last_index = m_nodes.size()-1;
							 | 
						||
| 
								 | 
							
								        _node_type * ptr = m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        bool found = gim_binary_search_ex(
							 | 
						||
| 
								 | 
							
								        	ptr,0,last_index,result_ind,hashkey,GIM_HASH_NODE_CMP_KEY_MACRO());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //Insert before found index
							 | 
						||
| 
								 | 
							
								        if(found)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_nodes[result_ind] = _node_type(hashkey,value);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _insert_in_pos(hashkey, value, result_ind);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return result_ind;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Fast insertion in m_nodes array
							 | 
						||
| 
								 | 
							
								    inline GUINT  _insert_unsorted(GUINT hashkey, const T & value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        m_nodes.push_back(_node_type(hashkey,value));
							 | 
						||
| 
								 | 
							
								        m_sorted = false;
							 | 
						||
| 
								 | 
							
								        return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								        <li> if node_size = 0, then this container becomes a simple sorted array allocator. reserve_size is used for reserve memory in m_nodes.
							 | 
						||
| 
								 | 
							
								        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.
							 | 
						||
| 
								 | 
							
								        <li> If node_size != 0, then this container becomes a hash table for ever
							 | 
						||
| 
								 | 
							
								        </ul>
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    gim_hash_table(GUINT reserve_size = GIM_DEFAULT_HASH_TABLE_SIZE,
							 | 
						||
| 
								 | 
							
								                     GUINT node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE,
							 | 
						||
| 
								 | 
							
								                     GUINT min_hash_table_size = GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        m_hash_table = NULL;
							 | 
						||
| 
								 | 
							
								        m_table_size = 0;
							 | 
						||
| 
								 | 
							
								        m_sorted = false;
							 | 
						||
| 
								 | 
							
								        m_node_size = node_size;
							 | 
						||
| 
								 | 
							
								        m_min_hash_table_size = min_hash_table_size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(m_node_size!=0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if(reserve_size!=0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                m_nodes.reserve(reserve_size);
							 | 
						||
| 
								 | 
							
								                _reserve_table_memory(reserve_size);
							 | 
						||
| 
								 | 
							
								                _invalidate_keys();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                m_nodes.reserve(GIM_DEFAULT_HASH_TABLE_SIZE);
							 | 
						||
| 
								 | 
							
								                _reserve_table_memory(GIM_DEFAULT_HASH_TABLE_SIZE);
							 | 
						||
| 
								 | 
							
								                _invalidate_keys();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if(reserve_size!=0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_nodes.reserve(reserve_size);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ~gim_hash_table()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _destroy();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline bool is_hash_table()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table) return true;
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline bool is_sorted()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(size()<2) return true;
							 | 
						||
| 
								 | 
							
								        return m_sorted;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool sort()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(is_sorted()) return true;
							 | 
						||
| 
								 | 
							
								        if(m_nodes.size()<2) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        _node_type * ptr = m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								        GUINT siz = m_nodes.size();
							 | 
						||
| 
								 | 
							
								        gim_sort_hash_node_array(ptr,siz);
							 | 
						||
| 
								 | 
							
								        m_sorted=true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(m_hash_table)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _rehash();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool switch_to_hashtable()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table) return false;
							 | 
						||
| 
								 | 
							
								        if(m_node_size==0) m_node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE;
							 | 
						||
| 
								 | 
							
								        if(m_nodes.size()<GIM_DEFAULT_HASH_TABLE_SIZE)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _resize_table(GIM_DEFAULT_HASH_TABLE_SIZE);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _resize_table(m_nodes.size()+1);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool switch_to_sorted_array()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table==NULL) return true;
							 | 
						||
| 
								 | 
							
								        _clear_table_memory();
							 | 
						||
| 
								 | 
							
								        return sort();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //!If the container reaches the
							 | 
						||
| 
								 | 
							
								    bool check_for_switching_to_hashtable()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(this->m_hash_table) return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(!(m_nodes.size()< m_min_hash_table_size))
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if(m_node_size == 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                m_node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            _resize_table(m_nodes.size()+1);
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline void set_sorted(bool value)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    	m_sorted = value;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Retrieves the amount of keys.
							 | 
						||
| 
								 | 
							
								    inline GUINT size() const
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return m_nodes.size();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Retrieves the hash key.
							 | 
						||
| 
								 | 
							
								    inline GUINT get_key(GUINT index) const
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return m_nodes[index].m_key;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Retrieves the value by index
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline T * get_value_by_index(GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return &m_nodes[index].m_data;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline const T& operator[](GUINT index) const
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return m_nodes[index].m_data;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline T& operator[](GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return m_nodes[index].m_data;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Finds the index of the element with the key
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted
							 | 
						||
| 
								 | 
							
								    If so, the element has been inserted at the last position of the array.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline GUINT find(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            GUINT cell_index = _find_cell(hashkey);
							 | 
						||
| 
								 | 
							
								            if(cell_index==GIM_INVALID_HASH) return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								            return m_hash_table[cell_index];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
										GUINT last_index = m_nodes.size();
							 | 
						||
| 
								 | 
							
								        if(last_index<2)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
											if(last_index==0) return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								            if(m_nodes[0].m_key == hashkey) return 0;
							 | 
						||
| 
								 | 
							
								            return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if(m_sorted)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            //Binary search
							 | 
						||
| 
								 | 
							
								            GUINT result_ind = 0;
							 | 
						||
| 
								 | 
							
											last_index--;
							 | 
						||
| 
								 | 
							
								            _node_type *  ptr =  m_nodes.pointer();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            bool found = gim_binary_search_ex(ptr,0,last_index,result_ind,hashkey,GIM_HASH_NODE_CMP_KEY_MACRO());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(found) return result_ind;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return GIM_INVALID_HASH;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Retrieves the value associated with the index
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    \return the found element, or null
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline T * get_value(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        GUINT index = find(hashkey);
							 | 
						||
| 
								 | 
							
								        if(index == GIM_INVALID_HASH) return NULL;
							 | 
						||
| 
								 | 
							
								        return &m_nodes[index].m_data;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline bool erase_by_index(GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(index > m_nodes.size()) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(m_hash_table == NULL)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if(is_sorted())
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return this->_erase_sorted(index);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return this->_erase_unsorted(index);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_erase_by_index_hash_table(index);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    inline bool erase_by_index_unsorted(GUINT index)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(index > m_nodes.size()) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(m_hash_table == NULL)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_erase_unsorted(index);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_erase_by_index_hash_table(index);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline bool erase_by_key(GUINT hashkey)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(size()==0) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(m_hash_table)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_erase_hash_table(hashkey);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        //Binary search
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(is_sorted()==false) return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        GUINT result_ind = find(hashkey);
							 | 
						||
| 
								 | 
							
								        if(result_ind!= GIM_INVALID_HASH)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_erase_sorted(result_ind);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void clear()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        m_nodes.clear();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if(m_hash_table==NULL) return;
							 | 
						||
| 
								 | 
							
								        GUINT datasize = m_table_size*m_node_size;
							 | 
						||
| 
								 | 
							
								        //Initialize the hashkeys.
							 | 
						||
| 
								 | 
							
								        GUINT i;
							 | 
						||
| 
								 | 
							
								        for(i=0;i<datasize;i++)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_hash_table[i] = GIM_INVALID_HASH;// invalidate keys
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
										m_sorted = false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Insert an element into the hash
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    \return If GIM_INVALID_HASH, the object has been inserted succesfully. Else it returns the position
							 | 
						||
| 
								 | 
							
								    of the existing element.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline GUINT insert(GUINT hashkey, const T & element)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_insert_hash_table(hashkey,element);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if(this->is_sorted())
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_insert_sorted(hashkey,element);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return this->_insert_unsorted(hashkey,element);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Insert an element into the hash, and could overrite an existing object with the same hash.
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    \return If GIM_INVALID_HASH, the object has been inserted succesfully. Else it returns the position
							 | 
						||
| 
								 | 
							
								    of the replaced element.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline GUINT insert_override(GUINT hashkey, const T & element)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_insert_hash_table_replace(hashkey,element);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if(this->is_sorted())
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_insert_sorted_replace(hashkey,element);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        this->_insert_unsorted(hashkey,element);
							 | 
						||
| 
								 | 
							
								        return m_nodes.size();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Insert an element into the hash,But if this container is a sorted array, this inserts it unsorted
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    inline GUINT insert_unsorted(GUINT hashkey,const T & element)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if(m_hash_table)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return this->_insert_hash_table(hashkey,element);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return this->_insert_unsorted(hashkey,element);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // GIM_CONTAINERS_H_INCLUDED
							 |