Files
Leviathan/Library/Internal/include/toolkit/khash.h
T
2026-06-01 12:46:52 +02:00

462 lines
10 KiB
C++

#pragma once
#include <vector>
#include <string>
#include <cassert>
#include "../toolkit/safe_function.h"
// nocase_tr에서 repr 함수가 아스키 값 'a' ~ 'z'일 경우만 처리하던 것을 tolower을 사용하도록 변경(해외 현지어에 따른 처리가 추가됨)
// by Synastry, 2009/09/03
// 단항 lookup 추가. 문자열 메모리를 갖고 있는 string 과 포인터만 갖는 pchar 분리 (hashPr)
// by Tyburn, 2006/05/09
// index 를 -1 로 받아오는 버그 수정함. ( 참고. 음수에는 % 연산이 안먹는다우~ -_- )
// by Testors, 2004/08/30
template< class T, class hashPr >
class KHash
{
public:
KHash( unsigned int _capacity = 50 )
: m_nCapacity(_capacity)
{
m_nTrace = 0;
m_nSize = 0;
m_slots = new slot[m_nCapacity];
m_pIsSlotUse = new char[m_nCapacity];
memset( m_pIsSlotUse, 0, m_nCapacity );
m_nIterSlot = 0;
m_nIterNode = 0;
}
~KHash()
{
clear();
delete[] m_pIsSlotUse;
delete[] m_slots;
}
size_t size() const
{
return m_nSize;
}
T* lookup( const typename hashPr::Key& key )
{
return _lookup( hashPr::getindex( key, m_nCapacity ), key );
}
const T* lookup( const typename hashPr::Key& key ) const
{
return _lookup( hashPr::getindex( key, m_nCapacity ), key );
}
bool lookup( const typename hashPr::Key& key, T& value ) const
{
const T* p = lookup( key );
if ( p == NULL )
return false;
value = *p;
return true;
}
bool has( const typename hashPr::Key& key ) const
{
return lookup( key ) != NULL;
}
void clear()
{
for ( int i=0 ; i< m_nCapacity ; i++ )
{
{ // VS2005 sp1 버그를 회피하기 위해 brace 추가함. by Testors
auto it = m_slots[i].m_node.begin();
auto end = m_slots[i].m_node.end();
for ( ; it != end ; ++it )
{
delete (*it);
}
}
m_slots[i].m_node.clear();
}
memset( m_pIsSlotUse, 0, m_nCapacity );
m_nSize = 0;
}
T* add( const typename hashPr::Key& key, const T& value )
{
return _add( hashPr::getindex( key, m_nCapacity ), key, value );
}
T* modify( const typename hashPr::Key& key, const T& value )
{
int index = hashPr::getindex( key, m_nCapacity );
if ( m_pIsSlotUse[index] == 0 )
return NULL;
slot* pSlot = m_slots + index;
node* _node = getNode( pSlot, key );
if ( _node )
{
_node->value = value;
return &_node->value;
}
return NULL;
}
bool erase( const typename hashPr::Key& key )
{
int index = hashPr::getindex( key, m_nCapacity );
if ( m_pIsSlotUse[index] == 0 )
return false;
slot* pSlot = m_slots + index;
if ( eraseNode( pSlot, key ) == true )
{
if ( pSlot->m_node.size() == 0 )
{
m_pIsSlotUse[index] = 0;
}
--m_nSize;
return true;
}
return false;
}
T& operator [] ( const typename hashPr::Key& key )
{
int index = hashPr::getindex( key, m_nCapacity );
while ( true )
{
if ( m_pIsSlotUse[index] != 0 )
{
slot* pSlot = m_slots + index;
node* _node = getNode( pSlot, key );
if ( _node )
return _node->value;
}
T temp;
_add( index, key, temp );
}
}
struct node
{
node( const T & v, const typename hashPr::Key & k ) : value( v ), key( k ) {}
T value;
typename hashPr::Key key;
};
bool get_first_node( node*& _node )
{
m_nIterSlot = 0;
m_nIterNode = 0;
slot* s = NULL;
while (m_nIterSlot < m_nCapacity)
{
if ( m_pIsSlotUse[m_nIterSlot] ==1 )
{
s = m_slots + m_nIterSlot;
assert( s->m_node.size() > 0 );
_node = s->m_node[m_nIterNode++];
return true;
}
++m_nIterSlot;
}
_node = NULL;
return false;
}
bool get_next_node( node*& _node )
{
slot* s = NULL;
s = m_slots + m_nIterSlot;
if ( m_nIterNode == int(s->m_node.size()) )
{
m_nIterNode = 0;
++m_nIterSlot;
while (m_nIterSlot < m_nCapacity)
{
if ( m_pIsSlotUse[m_nIterSlot] ==1 )
{
s = m_slots + m_nIterSlot;
assert( s->m_node.size() > 0 );
_node = s->m_node[m_nIterNode++];
return true;
}
++m_nIterSlot;
}
_node = NULL;
return false;
}
_node = s->m_node[m_nIterNode++];
return true;
}
bool get_first_value( T& value )
{
node* pNode;
if ( !get_first_node( pNode ) )
return false;
value = pNode->value;
return true;
}
bool get_next_value( T& value )
{
node* pNode;
if ( !get_next_node( pNode ) )
return false;
value = pNode->value;
return true;
}
private:
KHash( const KHash< T, hashPr >& );
KHash< T, hashPr >& operator=( const KHash< T, hashPr >& );
T* _lookup( int index, const typename hashPr::Key& key )
{
if ( m_pIsSlotUse[index] == 0 )
return NULL;
slot* pSlot = m_slots + index;
node* _node = getNode( pSlot, key );
return _node ? &_node->value : NULL;
}
const T* _lookup( int index, const typename hashPr::Key& key ) const
{
if ( m_pIsSlotUse[index] == 0 )
return NULL;
slot* pSlot = m_slots + index;
const node* _node = getNode( pSlot, key );
return _node ? &_node->value : NULL;
}
T* _add( int index, const typename hashPr::Key& key, const T& value )
{
slot* pSlot = m_slots + index;
node* _node = new node( value, key );
if ( setNode( pSlot, _node ) == false )
{
delete _node;
return NULL;
}
m_pIsSlotUse[ index ] = 1;
++m_nSize;
return &_node->value;
}
struct slot
{
slot() {}
typename typedef std::vector< node* >::iterator slot_iterater;
std::vector< node* > m_node;
};
template<class _FI, class _Ty, class _Pd, class _Pr> inline
_FI _Lowerbound(_FI _F, _FI _L, const _Ty& _V, _Pr _P, _Pd *) const
{
_Pd _N = 0;
std::_Distance(_F, _L, _N);
for (; 0 < _N; )
{
_Pd _N2 = _N / 2;
_FI _M = _F;
std::advance(_M, _N2);
if (_P((*_M)->key, _V))
_F = ++_M, _N -= _N2 + 1;
else
_N = _N2;
}
return (_F);
}
template<class _FI, class _Ty, class _Pr> inline
_FI lowerbound(_FI _F, _FI _L, const _Ty& _V, _Pr _P) const
{
return (_Lowerbound(_F, _L, _V, _P, std::_Dist_type(_F)));
}
bool eraseNode( slot* _slot, const typename hashPr::Key& key )
{
slot::slot_iterater it = lowerbound( _slot->m_node.begin(), _slot->m_node.end(), key, hashPr::isless );
if ( it == _slot->m_node.end() )
{
//assert(0);
return false;
}
if ( hashPr::isequal( key, (*it)->key ) )
{
delete (*it);
_slot->m_node.erase( it );
return true;
}
return false;
}
bool setNode( slot* _slot, typename node* _node )
{
slot::slot_iterater it = lowerbound( _slot->m_node.begin(), _slot->m_node.end(), _node->key, hashPr::isless );
if ( it != _slot->m_node.end() )
{
if ( hashPr::isequal( _node->key, (*it)->key ) )
return false;
}
if ( _slot->m_node.size() > 0 )
_slot->m_node.insert( it, _node );
else _slot->m_node.push_back( _node );
return true;
}
node* getNode( slot* _slot, const typename hashPr::Key& key )
{
slot::slot_iterater it = lowerbound( _slot->m_node.begin(), _slot->m_node.end(), key, hashPr::isless );
if ( it == _slot->m_node.end() || !hashPr::isequal( key, (*it)->key ) )
{
return NULL;
}
return (*it);
}
const node* getNode( slot* _slot, const typename hashPr::Key& key ) const
{
slot::slot_iterater it = lowerbound( _slot->m_node.begin(), _slot->m_node.end(), key, hashPr::isless );
if ( it == _slot->m_node.end() || !hashPr::isequal( key, (*it)->key ) )
{
return NULL;
}
return (*it);
}
int m_nTrace;
int m_nCapacity;
slot* m_slots;
char* m_pIsSlotUse;
// for iterating
int m_nIterSlot;
int m_nIterNode;
size_t m_nSize;
};
namespace khash_def
{
template< typename T >
struct hashPr_mod_basic
{
typedef T Key;
static inline unsigned getindex( Key key, int nCapacity )
{
return unsigned( uintptr_t(key) % nCapacity );
}
static inline bool isequal( Key key1, Key key2 )
{
return key1 == key2;
}
static inline bool isless( Key key1, Key key2 )
{
return key1 < key2;
}
};
template< typename mem_traits, typename comp_traits >
struct hashPr_str
{
struct Key
{
Key() { m_pStr = NULL; m_unIntKey = 0; }
Key( const Key& str ) { mem_traits::assign( m_pStr, str.m_pStr ); init_int_key(); }
Key( const char* pStr ) { mem_traits::assign( m_pStr, pStr ); init_int_key(); }
Key( std::string & str ) { mem_traits::assign( m_pStr, str.c_str() ); init_int_key(); }
~Key() { mem_traits::release( m_pStr ); }
void init_int_key()
{
const char *str = m_pStr;
for ( m_unIntKey = 0; *str; str++ ) m_unIntKey = m_unIntKey * 32 - m_unIntKey + comp_traits::repr( *str );
}
char* m_pStr;
unsigned int m_unIntKey;
};
static inline unsigned getindex( const Key &keystr, int nCapacity )
{
return keystr.m_unIntKey % nCapacity;
}
static inline bool isequal( const Key &str1, const Key &str2 )
{
if ( str1.m_unIntKey != str2.m_unIntKey ) return false;
return comp_traits::compare( str1.m_pStr, str2.m_pStr ) == 0;
}
static inline bool isless( const Key &str1, const Key &str2 )
{
if ( str1.m_unIntKey < str2.m_unIntKey ) return true;
if ( str1.m_unIntKey > str2.m_unIntKey ) return false;
return comp_traits::compare( str1.m_pStr, str2.m_pStr ) < 0;
}
};
struct string_tr
{
static inline void assign( char*& pDst, const char* pSrc )
{
size_t len = strlen( pSrc ) + 1;
pDst = new char[len];
s_strcpy( pDst, len, pSrc );
}
static inline void release( char* p ) { delete[] p; }
};
struct pchar_tr
{
static inline void assign( char*& pDst, const char* pSrc ) { pDst = const_cast< char* >( pSrc ); }
static inline void release( char* p ) {}
};
struct case_tr
{
static inline int compare( const char* p, const char* q ) { return strcmp( p, q ); }
static inline int repr( int c ) { return c; }
};
struct nocase_tr
{
static inline int compare( const char* p, const char* q ) { return _stricmp( p, q ); }
static inline int repr( int c ) { return tolower( c ); }
};
}
using khash_def::hashPr_mod_basic;
typedef khash_def::hashPr_mod_basic< int > hashPr_mod_int;
typedef khash_def::hashPr_str< khash_def::string_tr, khash_def::case_tr > hashPr_string;
typedef khash_def::hashPr_str< khash_def::string_tr, khash_def::nocase_tr > hashPr_string_nocase;
typedef khash_def::hashPr_str< khash_def::pchar_tr, khash_def::case_tr > hashPr_pchar;
typedef khash_def::hashPr_str< khash_def::pchar_tr, khash_def::nocase_tr > hashPr_pchar_nocase;