From 4b8bad3d711f39db84f094edf83c5496a3f02cd6 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 21 Nov 2006 12:23:13 +0000 Subject: Wow, craziness. Part way through working on the confpair system I got some sudden insperation and completely redid Hash. Now everything but delete is implemented, including typesafe iterators and more. It's really cool, and everyone should check it out and start using it right away! --- src/hash.h | 447 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 386 insertions(+), 61 deletions(-) (limited to 'src/hash.h') diff --git a/src/hash.h b/src/hash.h index 8385bb9..b8ced99 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,106 +1,431 @@ #ifndef HASH_H #define HASH_H -/* + #include #include +#include +#include #include "hashable.h" -#define bitsToBytes( n ) (n/8+(n%8>0 ? 1 : 0)) +#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; + } -template + value operator=( value nval ) + { + hsh.insert( tKey, nval ); + return nval; + } + +}; + +template class Hash { - class iterator +public: + Hash() : + nCapacity( 11 ), + nFilled( 0 ), + nDeleted( 0 ), + bFilled( NULL ), + aKeys( NULL ), + aValues( NULL ), + aHashCodes( NULL ) { - friend class Hash; - private: - iterator( Hash *hsh, int nIndex, key keyval, bool bInsert ) : - hsh( hsh ), - nIndex( nIndex ), - keyval( keyval ), - bInsert( bInsert ) + 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 ); + } - public: - iterator() : - hsh( NULL ), - nIndex( -1 ) + 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 ); - iterator &operator=( iterator &src ) + if( bFill ) { - this->hsh = src.hsh; - this->nIndex = src.nIndex; + 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 ); - iterator &operator=( value &src ) + if( bFill ) { - if( bInsert ) - printf("You wanted to insert %d\n", src ); - else - printf("You wanted to insert %d\n", src ); + 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++; } + } - private: - Hash *hsh; - int nIndex; - bool bInsert; - key keyval; - }; + 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< - class VRef + void fill( uint32_t loc ) { + bFilled[loc/32] |= (1<<(loc%32)); + } + + bool isFilled( uint32_t loc ) + { + return (bFilled[loc/32]&(1<<(loc%32)))!=0; + } + + bool isDeleted( uint32_t loc ) + { + return (bDeleted[loc/32]&(1<<(loc%32)))!=0; + } + + typedef struct iterator + { + friend class Hash; + 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: - VRef( refval &data ) : - data( data ) + 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 ); } - refval &data; }; -public: - Hash() : - nCapacity( 11 ), - nFilled( 0 ), - bFilled( NULL ), - aKeys( NULL ), - aValues( NULL ), - aHashCodes( NULL ) + iterator begin() { - int nKeysSize = bitsToBytes( nCapacity ); - bFilled = new unsigned char[ nKeysSize ]; - memset( bFilled, 0, nKeysSize ); - - aKeys = new VRef*[nCapacity]; - aValues = new value[nCapacity]; + return iterator( *this ); + } + + iterator end() + { + return iterator( *this, true ); } - virtual ~Hash() +private: + std::pair getAtPos( uint32_t nPos ) { + return std::pair(aKeys[nPos],aValues[nPos]); } - iterator operator[]( key keyval ) + uint32_t getFirstPos( bool &bFinished ) { - //iterator i( this, 4, keyval, true ); - //return i; - printf("%s\n", keyval.getString() ); + for( uint32_t j = 0; j < nCapacity; j++ ) + { + if( isFilled( j ) ) + return j; + } + + bFinished = true; } - int hasKey( key keyval ) + uint32_t getNextPos( uint32_t nPos, bool &bFinished ) { - printf("%s\n", keyval.getString() ); + for( uint32_t j = nPos+1; j < nCapacity; j++ ) + { + if( isFilled( j ) ) + return j; + } + + bFinished = true; } private: - int nCapacity; - int nFilled; - unsigned char *bFilled; - VRef **aKeys; - unsigned long int *aHashCodes; + 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 -- cgit v1.2.3