#ifndef HASH_H #define HASH_H #include #include #include #include #include "hashable.h" #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) template uint32_t __calcHashCode( T k ); template bool __cmpHashKeys( T a, T b ); struct __calcNextTSize_fast { uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const { return nCapacity*2+1; } }; template, typename valuealloc = std::allocator, typename challoc = std::allocator > class Hash; template< typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > struct HashProxy { friend class Hash; private: HashProxy( Hash &h, key k, value v ) : hsh( h ), tKey( k ), tValue( v ), bFilled( true ) { } HashProxy( Hash &h, key k ) : hsh( h ), tKey( k ), bFilled( false ) { } Hash &hsh; key tKey; value tValue; bool bFilled; public: operator value() { if( bFilled == false ) throw "Nope, no data there"; return tValue; } value operator=( value nval ) { hsh.insert( tKey, nval ); return nval; } }; template class Hash { public: Hash() : nCapacity( 11 ), nFilled( 0 ), nDeleted( 0 ), bFilled( NULL ), aKeys( NULL ), aValues( NULL ), aHashCodes( NULL ) { nKeysSize = bitsToBytes( nCapacity ); bFilled = ca.allocate( nKeysSize ); bDeleted = ca.allocate( nKeysSize ); clearBits(); aHashCodes = ca.allocate( nCapacity ); aKeys = ka.allocate( nCapacity ); aValues = va.allocate( nCapacity ); } virtual ~Hash() { for( uint32_t j = 0; j < nCapacity; j++ ) { if( isFilled( j ) ) { va.destroy( &aValues[j] ); ka.destroy( &aKeys[j] ); } } va.deallocate( aValues, nCapacity ); ka.deallocate( aKeys, nCapacity ); ca.deallocate( bFilled, nKeysSize ); ca.deallocate( bDeleted, nKeysSize ); ca.deallocate( aHashCodes, nCapacity ); } void clearBits() { for( uint32_t j = 0; j < nKeysSize; j++ ) { bFilled[j] = bDeleted[j] = 0; } } int hasKey( key keyval ) { printf("%s\n", keyval ); } uint32_t getCapacity() { return nCapacity; } uint32_t getFill() { return nFilled; } uint32_t getDeleted() { return nDeleted; } HashProxy operator[]( key k ) { uint32_t hash = __calcHashCode( k ); bool bFill; uint32_t nPos = probe( hash, k, bFill ); if( bFill ) { return HashProxy( *this, aKeys[nPos], aValues[nPos] ); } else { return HashProxy( *this, k ); } } void insert( key k, value v ) { uint32_t hash = __calcHashCode( k ); bool bFill; uint32_t nPos = probe( hash, k, bFill ); if( bFill ) { va.destroy( &aValues[nPos] ); va.construct( &aValues[nPos], v ); } else { va.construct( &aValues[nPos], v ); ka.construct( &aKeys[nPos], k ); fill( nPos ); aHashCodes[nPos] = hash; nFilled++; } } value get( key k ) { uint32_t hash = __calcHashCode( k ); bool bFill; uint32_t nPos = probe( hash, k, bFill ); if( bFill ) { return aValues[nPos]; } else { throw "Hey, no such thing..."; } } uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) { uint32_t nCur = hash%nCapacity; // First we scan to see if the key is already there, abort if we // run out of probing room, or we find a non-filled entry for( int8_t j = 0; isFilled( nCur ) && j < 32; nCur = (nCur + (1<; private: iterator( Hash &hsh ) : hsh( hsh ), bFinished( false ), nPos( 0 ) { nPos = hsh.getFirstPos( bFinished ); } iterator( Hash &hsh, bool bDone ) : hsh( hsh ), nPos( 0 ), bFinished( bDone ) { } Hash &hsh; uint32_t nPos; bool bFinished; public: iterator operator++( int ) { if( bFinished == false ) nPos = hsh.getNextPos( nPos, bFinished ); return *this; } iterator operator++() { if( bFinished == false ) nPos = hsh.getNextPos( nPos, bFinished ); return *this; } bool operator==( const iterator &oth ) { if( bFinished != oth.bFinished ) return false; if( bFinished == true ) { return true; } else { if( oth.nPos == nPos ) return true; return false; } } bool operator!=( const iterator &oth ) { return !(*this == oth ); } std::pair operator *() { return hsh.getAtPos( nPos ); } }; iterator begin() { return iterator( *this ); } iterator end() { return iterator( *this, true ); } private: std::pair getAtPos( uint32_t nPos ) { return std::pair(aKeys[nPos],aValues[nPos]); } uint32_t getFirstPos( bool &bFinished ) { for( uint32_t j = 0; j < nCapacity; j++ ) { if( isFilled( j ) ) return j; } bFinished = true; } uint32_t getNextPos( uint32_t nPos, bool &bFinished ) { for( uint32_t j = nPos+1; j < nCapacity; j++ ) { if( isFilled( j ) ) return j; } bFinished = true; } private: uint32_t nCapacity; uint32_t nFilled; uint32_t nDeleted; uint32_t *bFilled; uint32_t *bDeleted; uint32_t *aHashCodes; uint32_t nKeysSize; value *aValues; key *aKeys; valuealloc va; keyalloc ka; challoc ca; sizecalc szCalc; }; template<> uint32_t __calcHashCode( const char *k ); template<> bool __cmpHashKeys( const char *a, const char *b ); template<> uint32_t __calcHashCode( char *k ); template<> bool __cmpHashKeys( char *a, char *b ); template<> uint32_t __calcHashCode( const std::string k ); template<> bool __cmpHashKeys( const std::string a, const std::string b ); template<> uint32_t __calcHashCode( std::string k ); template<> bool __cmpHashKeys( std::string a, std::string b ); template<> uint32_t __calcHashCode( Hashable &k ); template<> bool __cmpHashKeys( Hashable &a, Hashable &b ); #endif