-- cgit v1.2.3 From 867dae89929a11a421ec21af71d494ad0ecc1963 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 14 Oct 2010 23:26:25 +0000 Subject: SharedCore has more features now, which is cool, including a test to see if another object of the parent type has the same core, and another to clone the parent object. That one is pretty cool, it means you can now get a real copy when you want to, great for multi-threaded stuff. Also, two more classes are now SharedCore: Hash and Heap! --- src/archive.cpp | 9 +- src/archive.h | 4 +- src/archivebase.h | 5 +- src/array.h | 27 +- src/fbasicstring.h | 23 +- src/hash.h | 1046 +++++++++++++++++++++++----------------------- src/heap.h | 298 ++++++++----- src/list.h | 26 +- src/set.h | 760 +-------------------------------- src/sharedcore.h | 30 +- src/tests/sharedcore.cpp | 2 +- src/unit/hash.unit | 13 + 12 files changed, 841 insertions(+), 1402 deletions(-) diff --git a/src/archive.cpp b/src/archive.cpp index 69d4a0c..7a10921 100644 --- a/src/archive.cpp +++ b/src/archive.cpp @@ -22,20 +22,15 @@ Bu::Archive::~Archive() { } -void Bu::Archive::write( const void *pData, int32_t nSize ) +void Bu::Archive::write( const void *pData, size_t nSize ) { if( nSize == 0 || pData == NULL ) return; -// Bu::sio << "Writing starting at pos: " << rStream.tell() << " - " -// << Bu::sio.flush; - rStream.write( (const char *)pData, nSize ); -// -// Bu::sio << rStream.tell() << " (" << nSize << "b)" << Bu::sio.nl; } -void Bu::Archive::read( void *pData, int32_t nSize ) +void Bu::Archive::read( void *pData, size_t nSize ) { if( nSize == 0 || pData == NULL ) return; diff --git a/src/archive.h b/src/archive.h index bd85113..9d2aee2 100644 --- a/src/archive.h +++ b/src/archive.h @@ -83,8 +83,8 @@ namespace Bu virtual ~Archive(); virtual void close(); - virtual void write(const void *, int32_t); - virtual void read(void *, int32_t); + virtual void write( const void *pData, size_t iSize ); + virtual void read( void *pData, size_t iSize ); /** * For storage, get an ID for the pointer to the object you're going to diff --git a/src/archivebase.h b/src/archivebase.h index c871bb5..18591f0 100644 --- a/src/archivebase.h +++ b/src/archivebase.h @@ -9,6 +9,7 @@ #define BU_ARCHIVE_BASE_H #include +#include namespace Bu { @@ -19,8 +20,8 @@ namespace Bu virtual ~ArchiveBase(); virtual void close()=0; - virtual void write( const void *pData, int32_t iLength )=0; - virtual void read( void *pData, int32_t iLength )=0; + virtual void write( const void *pData, size_t iLength )=0; + virtual void read( void *pData, size_t iLength )=0; virtual bool isLoading()=0; }; diff --git a/src/array.h b/src/array.h index eeee677..fc4fb12 100644 --- a/src/array.h +++ b/src/array.h @@ -17,10 +17,18 @@ namespace Bu { subExceptionDecl( ArrayException ) + template + class Array; + template class ArrayCore { - public: + friend class Array; + friend class SharedCore< + Array, + ArrayCore + >; + private: ArrayCore() : pData( NULL ), iSize( 0 ), @@ -110,16 +118,20 @@ namespace Bu *@ingroup Containers */ template > - class Array : public SharedCore > + class Array : public SharedCore< + Array, + ArrayCore + > { private: typedef class Array MyType; typedef class ArrayCore Core; protected: - using SharedCore< Core >::core; - using SharedCore< Core >::_hardCopy; - using SharedCore< Core >::_allocateCore; + using SharedCore::core; + using SharedCore::_hardCopy; + using SharedCore::_resetCore; + using SharedCore::_allocateCore; public: struct const_iterator; @@ -130,7 +142,7 @@ namespace Bu } Array( const MyType &src ) : - SharedCore< Core >( src ) + SharedCore( src ) { } @@ -168,8 +180,7 @@ namespace Bu */ void clear() { - _hardCopy(); - core->clear(); + _resetCore(); } MyType &append( const value &rVal ) diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 19853f5..82c5137 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -34,10 +34,19 @@ namespace Bu }; #define cpy( dest, src, size ) Bu::memcpy( dest, src, size*sizeof(chr) ) + + template< typename chr, int nMinSize, typename chralloc, + typename chunkalloc> class FBasicString; template struct FStringCore { + friend class FBasicString; + friend class SharedCore< + FBasicString, + FStringCore + >; + private: typedef struct FStringCore MyType; typedef struct FStringChunk Chunk; FStringCore() : @@ -174,16 +183,20 @@ namespace Bu *@param chralloc (typename) Memory Allocator for chr *@param chunkalloc (typename) Memory Allocator for chr chunks */ - template< typename chr, int nMinSize=256, typename chralloc=std::allocator, typename chunkalloc=std::allocator > > - class FBasicString : public SharedCore< FStringCore > + template< typename chr, int nMinSize=256, + typename chralloc=std::allocator, + typename chunkalloc=std::allocator > > + class FBasicString : public SharedCore< + FBasicString, + FStringCore > { protected: typedef struct FStringChunk Chunk; typedef struct FBasicString MyType; typedef struct FStringCore Core; - using SharedCore< Core >::core; - using SharedCore< Core >::_hardCopy; + using SharedCore::core; + using SharedCore::_hardCopy; public: FBasicString() @@ -201,7 +214,7 @@ namespace Bu } FBasicString( const MyType &rSrc ) : - SharedCore( rSrc ) + SharedCore( rSrc ) { } diff --git a/src/hash.h b/src/hash.h index 1cb539b..714a7f7 100644 --- a/src/hash.h +++ b/src/hash.h @@ -12,7 +12,8 @@ #include "bu/exceptionbase.h" #include "bu/list.h" #include "bu/util.h" -#include "archivebase.h" +#include "bu/archivebase.h" +#include "bu/sharedcore.h" #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) @@ -49,137 +50,354 @@ namespace Bu } }; - template, typename valuealloc = std::allocator, typename challoc = std::allocator > + template class Hash; - template< typename key, typename _value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator, typename valuealloc = std::allocator<_value>, typename challoc = std::allocator > - struct HashProxy + template + class HashCore { - friend class Hash; + friend class Hash; + friend class SharedCore< + Hash, + HashCore + >; private: - HashProxy( Hash &h, const key *k, uint32_t nPos, uint32_t hash ) : - hsh( h ), - pKey( k ), - nPos( nPos ), - hash( hash ), - bFilled( false ) + HashCore() : + nCapacity( 0 ), + nFilled( 0 ), + nDeleted( 0 ), + bFilled( NULL ), + bDeleted( NULL ), + aKeys( NULL ), + aValues( NULL ), + aHashCodes( NULL ) { } - HashProxy( Hash &h, uint32_t nPos, _value *pValue ) : - hsh( h ), - nPos( nPos ), - pValue( pValue ), - bFilled( true ) + virtual ~HashCore() { + clear(); } - Hash &hsh; - const key *pKey; - uint32_t nPos; - _value *pValue; - uint32_t hash; - bool bFilled; + void init() + { + if( nCapacity > 0 ) + return; - public: - /** - * Cast operator for HashProxy. - *@returns (value_type &) The value the HashProxy is pointing to. - */ - operator _value &() + nCapacity = 11; + nKeysSize = bitsToBytes( nCapacity ); + bFilled = ca.allocate( nKeysSize ); + bDeleted = ca.allocate( nKeysSize ); + clearBits(); + + aHashCodes = ca.allocate( nCapacity ); + aKeys = ka.allocate( nCapacity ); + aValues = va.allocate( nCapacity ); + } + + void clearBits() { - if( bFilled == false ) - throw HashException( - excodeNotFilled, - "No data assosiated with that key." - ); - return *pValue; + if( nCapacity == 0 ) + return; + + for( uint32_t j = 0; j < nKeysSize; j++ ) + { + bFilled[j] = bDeleted[j] = 0; + } } - /** - * Direct function for retrieving a value out of the HashProxy. - *@returns (value_type &) The value pointed to by this HashProxy. - */ - DEPRECATED - _value &value() + void fill( uint32_t loc, const key &k, const value &v, uint32_t hash ) { - if( bFilled == false ) - throw HashException( - excodeNotFilled, - "No data assosiated with that key." - ); - return *pValue; + init(); + + bFilled[loc/32] |= (1<<(loc%32)); + va.construct( &aValues[loc], v ); + ka.construct( &aKeys[loc], k ); + aHashCodes[loc] = hash; + nFilled++; + //printf("Filled: %d, Deleted: %d, Capacity: %d\n", + // nFilled, nDeleted, nCapacity ); + } + + void _erase( uint32_t loc ) + { + if( nCapacity == 0 ) + return; + + bDeleted[loc/32] |= (1<<(loc%32)); + va.destroy( &aValues[loc] ); + ka.destroy( &aKeys[loc] ); + nDeleted++; + //printf("Filled: %d, Deleted: %d, Capacity: %d\n", + // nFilled, nDeleted, nCapacity ); + } + + key &getKeyAtPos( uint32_t nPos ) + { + if( nPos >= nCapacity ) + throw HashException("Referenced position invalid."); + return aKeys[nPos]; } - /** - * Direct function for retrieving a value out of the HashProxy. - *@returns (value_type &) The value pointed to by this HashProxy. - */ - _value &getValue() + const key &getKeyAtPos( uint32_t nPos ) const { - if( bFilled == false ) - throw HashException( - excodeNotFilled, - "No data assosiated with that key." - ); - return *pValue; + if( nPos >= nCapacity ) + throw HashException("Referenced position invalid."); + return aKeys[nPos]; + } + + value &getValueAtPos( uint32_t nPos ) + { + if( nPos >= nCapacity ) + throw HashException("Referenced position invalid."); + return aValues[nPos]; + } + + const value &getValueAtPos( uint32_t nPos ) const + { + if( nPos >= nCapacity ) + throw HashException("Referenced position invalid."); + return aValues[nPos]; } - /** - * Whether this HashProxy points to something real or not. - */ - bool isFilled() + uint32_t getFirstPos( bool &bFinished ) const { - return bFilled; + for( uint32_t j = 0; j < nCapacity; j++ ) + { + if( isFilled( j ) ) + if( !isDeleted( j ) ) + return j; + } + + bFinished = true; + return 0; } - /** - * Erase the data pointed to by this HashProxy. - */ - void erase() + uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const { - if( bFilled ) + for( uint32_t j = nPos+1; j < nCapacity; j++ ) { - hsh._erase( nPos ); - hsh.onDelete(); + if( isFilled( j ) ) + if( !isDeleted( j ) ) + return j; } + + bFinished = true; + return 0; } - /** - * Assign data to this point in the hash table. - *@param nval (value_type) the data to assign. - */ - _value operator=( _value nval ) + uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true ) + { + init(); + + 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 + int8_t j; + for( j = 0; + isFilled( nCur ) && j < 32; + nCur = (nCur + (1<() + bool isFilled( uint32_t loc ) const { - if( bFilled == false ) - throw HashException( - excodeNotFilled, - "No data assosiated with that key." - ); - return pValue; + if( loc >= nCapacity ) + throw HashException("Referenced position invalid."); + return (bFilled[loc/32]&(1<<(loc%32)))!=0; } + + bool isDeleted( uint32_t loc ) const + { + if( loc >= nCapacity ) + throw HashException("Referenced position invalid."); + return (bDeleted[loc/32]&(1<<(loc%32)))!=0; + } + + void clear() + { + for( uint32_t j = 0; j < nCapacity; j++ ) + { + if( isFilled( j ) ) + if( !isDeleted( 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 ); + + bFilled = NULL; + bDeleted = NULL; + aKeys = NULL; + aValues = NULL; + aHashCodes = NULL; + + nCapacity = 0; + nFilled = 0; + nDeleted = 0; + } + + uint32_t nCapacity; + uint32_t nFilled; + uint32_t nDeleted; + uint32_t *bFilled; + uint32_t *bDeleted; + uint32_t nKeysSize; + key *aKeys; + value *aValues; + uint32_t *aHashCodes; + valuealloc va; + keyalloc ka; + challoc ca; + sizecalc szCalc; }; /** @@ -224,119 +442,38 @@ namespace Bu *@param challoc (typename) Byte allocator for bitflags *@ingroup Containers */ - template - class Hash + template, + typename valuealloc = std::allocator, + typename challoc = std::allocator + > + class Hash : public SharedCore< + Hash, + HashCore + > { - friend struct HashProxy; + private: + typedef class HashCore Core; typedef class Hash MyType; + protected: + using SharedCore::core; + using SharedCore::_hardCopy; + using SharedCore::_resetCore; + using SharedCore::_allocateCore; + public: - Hash() : - nCapacity( 11 ), - nFilled( 0 ), - nDeleted( 0 ), - bFilled( NULL ), - bDeleted( NULL ), - aKeys( NULL ), - aValues( NULL ), - aHashCodes( NULL ) + Hash() { - nKeysSize = bitsToBytes( nCapacity ); - bFilled = ca.allocate( nKeysSize ); - bDeleted = ca.allocate( nKeysSize ); - clearBits(); - - aHashCodes = ca.allocate( nCapacity ); - aKeys = ka.allocate( nCapacity ); - aValues = va.allocate( nCapacity ); } - Hash( const Hash &src ) : - nCapacity( src.nCapacity ), - nFilled( 0 ), - nDeleted( 0 ), - bFilled( NULL ), - bDeleted( NULL ), - aKeys( NULL ), - aValues( NULL ), - aHashCodes( NULL ) + Hash( const MyType &src ) : + SharedCore( src ) { - nKeysSize = bitsToBytes( nCapacity ); - bFilled = ca.allocate( nKeysSize ); - bDeleted = ca.allocate( nKeysSize ); - clearBits(); - - aHashCodes = ca.allocate( nCapacity ); - aKeys = ka.allocate( nCapacity ); - aValues = va.allocate( nCapacity ); - - for( uint32_t j = 0; j < src.nCapacity; j++ ) - { - if( src.isFilled( j ) && !src.isDeleted( j ) ) - { - insert( src.aKeys[j], src.aValues[j] ); - } - } - } - - /** - * Hashtable assignment operator. Clears this hashtable and - * copies RH into it. - */ - Hash &operator=( const Hash &src ) - { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) && !isDeleted( 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 ); - - nFilled = 0; - nDeleted = 0; - nCapacity = src.nCapacity; - nKeysSize = bitsToBytes( nCapacity ); - bFilled = ca.allocate( nKeysSize ); - bDeleted = ca.allocate( nKeysSize ); - clearBits(); - - aHashCodes = ca.allocate( nCapacity ); - aKeys = ka.allocate( nCapacity ); - aValues = va.allocate( nCapacity ); - - for( uint32_t j = 0; j < src.nCapacity; j++ ) - { - if( src.isFilled( j ) && !src.isDeleted( j ) ) - { - insert( src.aKeys[j], src.aValues[j] ); - } - } - - return *this; } virtual ~Hash() { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( 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 ); } /** @@ -345,7 +482,7 @@ namespace Bu */ uint32_t getCapacity() const { - return nCapacity; + return core->nCapacity; } /** @@ -355,7 +492,7 @@ namespace Bu */ uint32_t getFill() const { - return nFilled; + return core->nFilled; } /** @@ -364,12 +501,12 @@ namespace Bu */ uint32_t getSize() const { - return nFilled-nDeleted; + return core->nFilled-core->nDeleted; } bool isEmpty() const { - return (nFilled-nDeleted) == 0; + return (core->nFilled-core->nDeleted) == 0; } /** @@ -379,68 +516,170 @@ namespace Bu */ uint32_t getDeleted() const { - return nDeleted; + return core->nDeleted; } - /** - * Hash table index operator - *@param k (key_type) Key of data to be retrieved. - *@returns (HashProxy) Proxy pointing to the data. - */ - virtual HashProxy operator[]( const key &k ) + struct HashProxy { - uint32_t hash = __calcHashCode( k ); - bool bFill; - uint32_t nPos = probe( hash, k, bFill ); + friend class Hash; + private: + HashProxy( MyType &h, const key *k, uint32_t nPos, uint32_t hash ) : + hsh( h ), + pKey( k ), + nPos( nPos ), + hash( hash ), + bFilled( false ) + { + } - if( bFill ) + HashProxy( MyType &h, uint32_t nPos, value *pValue ) : + hsh( h ), + nPos( nPos ), + pValue( pValue ), + bFilled( true ) { - return HashProxy( *this, nPos, &aValues[nPos] ); } - else + + MyType &hsh; + const key *pKey; + uint32_t nPos; + value *pValue; + uint32_t hash; + bool bFilled; + + public: + /** + * Cast operator for HashProxy. + *@returns (value_type &) The value the HashProxy is pointing to. + */ + operator value &() { - return HashProxy( *this, &k, nPos, hash ); + if( bFilled == false ) + throw HashException( + excodeNotFilled, + "No data assosiated with that key." + ); + return *pValue; + } + + /** + * Direct function for retrieving a value out of the HashProxy. + *@returns (value_type &) The value pointed to by this HashProxy. + */ + value &getValue() + { + if( bFilled == false ) + throw HashException( + excodeNotFilled, + "No data assosiated with that key." + ); + return *pValue; + } + + /** + * Whether this HashProxy points to something real or not. + */ + bool isFilled() + { + return bFilled; + } + + /** + * Erase the data pointed to by this HashProxy. + */ + void erase() + { + if( bFilled ) + { + hsh.core->_erase( nPos ); + } + } + + /** + * Assign data to this point in the hash table. + *@param nval (value_type) the data to assign. + */ + value operator=( value nval ) + { + if( bFilled ) + { + hsh.core->va.destroy( &hsh.core->aValues[nPos] ); + hsh.core->va.construct( &hsh.core->aValues[nPos], nval ); + } + else + { + hsh.core->fill( nPos, *pKey, nval, hash ); + } + + return nval; } - } + + /** + * Pointer extraction operator. Access to members of data pointed to + * by HashProxy. + *@returns (value_type *) + */ + value *operator->() + { + if( bFilled == false ) + throw HashException( + excodeNotFilled, + "No data assosiated with that key." + ); + return pValue; + } + }; /** - * Insert a value (v) under key (k) into the hash table - *@param k (key_type) Key to list the value under. - *@param v (value_type) Value to store in the hash table. + * Hash table index operator + *@param k (key_type) Key of data to be retrieved. + *@returns (HashProxy) Proxy pointing to the data. */ - virtual void insert( const key &k, const value &v ) + HashProxy operator[]( const key &k ) { + _hardCopy(); + uint32_t hash = __calcHashCode( k ); bool bFill; - uint32_t nPos = probe( hash, k, bFill ); + uint32_t nPos = core->probe( hash, k, bFill ); if( bFill ) { - va.destroy( &aValues[nPos] ); - va.construct( &aValues[nPos], v ); - onUpdate(); + return HashProxy( *this, nPos, &core->aValues[nPos] ); } else { - fill( nPos, k, v, hash ); - onInsert(); + return HashProxy( *this, &k, nPos, hash ); } } + /** + * Insert a value (v) under key (k) into the hash table + *@param k (key_type) Key to list the value under. + *@param v (value_type) Value to store in the hash table. + */ + void insert( const key &k, const value &v ) + { + _hardCopy(); + + core->insert( k, v ); + } + /** * Remove a value from the hash table. *@param k (key_type) The data under this key will be erased. */ - virtual void erase( const key &k ) + void erase( const key &k ) { + _hardCopy(); + uint32_t hash = __calcHashCode( k ); bool bFill; - uint32_t nPos = probe( hash, k, bFill ); + uint32_t nPos = core->probe( hash, k, bFill ); if( bFill ) { - _erase( nPos ); - onDelete(); + core->_erase( nPos ); } } @@ -450,14 +689,16 @@ namespace Bu * Remove a value from the hash pointed to from an iterator. *@param i (iterator &) The data to be erased. */ - virtual void erase( struct iterator &i ) + void erase( struct iterator &i ) { if( this != i.hsh ) throw HashException("This iterator didn't come from this Hash."); - if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) + + _hardCopy(); + + if( core->isFilled( i.nPos ) && !core->isDeleted( i.nPos ) ) { - _erase( i.nPos ); - onDelete(); + core->_erase( i.nPos ); } } @@ -466,17 +707,7 @@ namespace Bu */ virtual void clear() { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - { - _erase( j ); - onDelete(); - } - } - - clearBits(); + _resetCore(); } /** @@ -484,15 +715,17 @@ namespace Bu *@param k (key_type) Key pointing to the data to be retrieved. *@returns (value_type &) The data pointed to by (k). */ - virtual value &get( const key &k ) + value &get( const key &k ) { + _hardCopy(); + uint32_t hash = __calcHashCode( k ); bool bFill; - uint32_t nPos = probe( hash, k, bFill, false ); + uint32_t nPos = core->probe( hash, k, bFill, false ); if( bFill ) { - return aValues[nPos]; + return core->aValues[nPos]; } else { @@ -509,15 +742,15 @@ namespace Bu *@returns (const value_type &) A const version of the data pointed * to by (k). */ - virtual const value &get( const key &k ) const + const value &get( const key &k ) const { uint32_t hash = __calcHashCode( k ); bool bFill; - uint32_t nPos = probe( hash, k, bFill ); + uint32_t nPos = core->probe( hash, k, bFill ); if( bFill ) { - return aValues[nPos]; + return core->aValues[nPos]; } else { @@ -533,18 +766,10 @@ namespace Bu *@param k (key_type) The key to check. *@returns (bool) Whether there was an item in the hash under key (k). */ - virtual bool has( const key &k ) - { - bool bFill; - probe( __calcHashCode( k ), k, bFill, false ); - - return bFill; - } - - virtual bool has( const key &k ) const + bool has( const key &k ) const { bool bFill; - probe( __calcHashCode( k ), k, bFill ); + core->probe( __calcHashCode( k ), k, bFill ); return bFill; } @@ -561,7 +786,7 @@ namespace Bu nPos( 0 ), bFinished( false ) { - nPos = hsh->getFirstPos( bFinished ); + nPos = hsh->core->getFirstPos( bFinished ); } iterator( MyType *hsh, bool bDone ) : @@ -590,11 +815,6 @@ namespace Bu { } - DEPRECATED bool isActive() const - { - return !bFinished; - } - bool isValid() const { return !bFinished; @@ -611,7 +831,7 @@ namespace Bu iterator operator++( int ) { if( bFinished == false ) - nPos = hsh->getNextPos( nPos, bFinished ); + nPos = hsh->core->getNextPos( nPos, bFinished ); return *this; } @@ -622,7 +842,7 @@ namespace Bu iterator operator++() { if( bFinished == false ) - nPos = hsh->getNextPos( nPos, bFinished ); + nPos = hsh->core->getNextPos( nPos, bFinished ); return *this; } @@ -671,21 +891,22 @@ namespace Bu */ value &operator *() { - return hsh->getValueAtPos( nPos ); + hsh->_hardCopy(); + return hsh->core->getValueAtPos( nPos ); } const value &operator *() const { - return hsh->getValueAtPos( nPos ); + return hsh->core->getValueAtPos( nPos ); } /** * Get the key behind this iterator. *@returns (key_type &) The key behind this iterator. */ - key &getKey() + const key &getKey() const { - return hsh->getKeyAtPos( nPos ); + return hsh->core->getKeyAtPos( nPos ); } /** @@ -694,7 +915,17 @@ namespace Bu */ value &getValue() { - return hsh->getValueAtPos( nPos ); + hsh->_hardCopy(); + return hsh->core->getValueAtPos( nPos ); + } + + /** + * Get the value behind this iterator. + *@returns (value_type &) The value behind this iterator. + */ + const value &getValue() const + { + return hsh->core->getValueAtPos( nPos ); } } iterator; @@ -710,7 +941,7 @@ namespace Bu nPos( 0 ), bFinished( false ) { - nPos = hsh->getFirstPos( bFinished ); + nPos = hsh->core->getFirstPos( bFinished ); } const_iterator( const MyType *hsh, bool bDone ) : @@ -762,7 +993,7 @@ namespace Bu const_iterator operator++( int ) { if( bFinished == false ) - nPos = hsh->getNextPos( nPos, bFinished ); + nPos = hsh->core->getNextPos( nPos, bFinished ); return *this; } @@ -773,7 +1004,7 @@ namespace Bu const_iterator operator++() { if( bFinished == false ) - nPos = hsh->getNextPos( nPos, bFinished ); + nPos = hsh->core->getNextPos( nPos, bFinished ); return *this; } @@ -822,7 +1053,7 @@ namespace Bu */ const value &operator *() const { - return hsh->getValueAtPos( nPos ); + return hsh->core->getValueAtPos( nPos ); } /** @@ -831,7 +1062,7 @@ namespace Bu */ const key &getKey() const { - return hsh->getKeyAtPos( nPos ); + return hsh->core->getKeyAtPos( nPos ); } /** @@ -840,7 +1071,7 @@ namespace Bu */ const value &getValue() const { - return hsh->getValueAtPos( nPos ); + return hsh->core->getValueAtPos( nPos ); } } const_iterator; @@ -883,13 +1114,13 @@ namespace Bu { Bu::List lKeys; - for( uint32_t j = 0; j < nCapacity; j++ ) + for( uint32_t j = 0; j < core->nCapacity; j++ ) { - if( isFilled( j ) ) + if( core->isFilled( j ) ) { - if( !isDeleted( j ) ) + if( !core->isDeleted( j ) ) { - lKeys.append( aKeys[j] ); + lKeys.append( core->aKeys[j] ); } } } @@ -901,13 +1132,13 @@ namespace Bu { Bu::List lValues; - for( uint32_t j = 0; j < nCapacity; j++ ) + for( uint32_t j = 0; j < core->nCapacity; j++ ) { - if( isFilled( j ) ) + if( core->isFilled( j ) ) { - if( !isDeleted( j ) ) + if( !core->isDeleted( j ) ) { - lValues.append( aValues[j] ); + lValues.append( core->aValues[j] ); } } } @@ -916,243 +1147,32 @@ namespace Bu } protected: - virtual void onInsert() {} - virtual void onUpdate() {} - virtual void onDelete() {} - virtual void onReHash() {} - - virtual void clearBits() - { - for( uint32_t j = 0; j < nKeysSize; j++ ) - { - bFilled[j] = bDeleted[j] = 0; - } - } - - virtual void fill( uint32_t loc, const key &k, const value &v, uint32_t hash ) - { - bFilled[loc/32] |= (1<<(loc%32)); - va.construct( &aValues[loc], v ); - ka.construct( &aKeys[loc], k ); - aHashCodes[loc] = hash; - nFilled++; - //printf("Filled: %d, Deleted: %d, Capacity: %d\n", - // nFilled, nDeleted, nCapacity ); - } - - virtual void _erase( uint32_t loc ) - { - bDeleted[loc/32] |= (1<<(loc%32)); - va.destroy( &aValues[loc] ); - ka.destroy( &aKeys[loc] ); - nDeleted++; - //printf("Filled: %d, Deleted: %d, Capacity: %d\n", - // nFilled, nDeleted, nCapacity ); - } - - virtual key &getKeyAtPos( uint32_t nPos ) - { - return aKeys[nPos]; - } - - virtual const key &getKeyAtPos( uint32_t nPos ) const - { - return aKeys[nPos]; - } - - virtual value &getValueAtPos( uint32_t nPos ) - { - return aValues[nPos]; - } - - virtual const value &getValueAtPos( uint32_t nPos ) const - { - return aValues[nPos]; - } - - virtual uint32_t getFirstPos( bool &bFinished ) const - { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - return j; - } - - bFinished = true; - return 0; - } - - virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const - { - for( uint32_t j = nPos+1; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - return j; - } - - bFinished = true; - return 0; - } - - uint32_t probe( uint32_t hash, const 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 - int8_t j; - for( j = 0; - isFilled( nCur ) && j < 32; - nCur = (nCur + (1<nFilled = 0; + pRet->nDeleted = 0; + pRet->nCapacity = src->nCapacity; + pRet->nKeysSize = bitsToBytes( pRet->nCapacity ); + pRet->bFilled = pRet->ca.allocate( pRet->nKeysSize ); + pRet->bDeleted = pRet->ca.allocate( pRet->nKeysSize ); + pRet->clearBits(); - // Re-insert all of the old data (except deleted items) - for( uint32_t j = 0; j < nOldCapacity; j++ ) - { - if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && - (bOldDeleted[j/32]&(1<<(j%32)))==0 ) - { - insert( aOldKeys[j], aOldValues[j] ); - } - } + pRet->aHashCodes = pRet->ca.allocate( pRet->nCapacity ); + pRet->aKeys = pRet->ka.allocate( pRet->nCapacity ); + pRet->aValues = pRet->va.allocate( pRet->nCapacity ); - // Delete all of the old data - for( uint32_t j = 0; j < nOldCapacity; j++ ) + for( uint32_t j = 0; j < src->nCapacity; j++ ) { - if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && - (bOldDeleted[j/32]&(1<<(j%32)))==0 ) + if( src->isFilled( j ) && !src->isDeleted( j ) ) { - va.destroy( &aOldValues[j] ); - ka.destroy( &aOldKeys[j] ); + pRet->insert( src->aKeys[j], src->aValues[j] ); } } - va.deallocate( aOldValues, nOldCapacity ); - ka.deallocate( aOldKeys, nOldCapacity ); - ca.deallocate( bOldFilled, nOldKeysSize ); - ca.deallocate( bOldDeleted, nOldKeysSize ); - ca.deallocate( aOldHashCodes, nOldCapacity ); - } - - virtual bool isFilled( uint32_t loc ) const - { - return (bFilled[loc/32]&(1<<(loc%32)))!=0; - } - virtual bool isDeleted( uint32_t loc ) const - { - return (bDeleted[loc/32]&(1<<(loc%32)))!=0; + return pRet; } - - protected: - uint32_t nCapacity; - uint32_t nFilled; - uint32_t nDeleted; - uint32_t *bFilled; - uint32_t *bDeleted; - uint32_t nKeysSize; - key *aKeys; - value *aValues; - uint32_t *aHashCodes; - valuealloc va; - keyalloc ka; - challoc ca; - sizecalc szCalc; }; template uint32_t __calcHashCode( const T &k ) diff --git a/src/heap.h b/src/heap.h index 9df4121..1dac69b 100644 --- a/src/heap.h +++ b/src/heap.h @@ -13,76 +13,92 @@ #include "bu/exceptionbase.h" #include "bu/util.h" #include "bu/queue.h" +#include "bu/sharedcore.h" namespace Bu { subExceptionDecl( HeapException ); - /** - * A priority queue that allows for an unlimited number of priorities. All - * objects enqueued must support less-than-comparison. Then every time an - * item is dequeued it is always the least item in the heap. The heap - * operates using a binary tree for storage, which allows most operations - * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins - * whereas peeking is constant time. - * - * This heap implementation allows iterating, however please note that any - * enqueue or dequeue operation will invalidate the iterator and make it - * unusable (if it still works, you shouldn't trust the results). Also, - * the items are not stored in memory in order, they are optomized into a - * tree. This means that the items will be in effectively random order - * while iterating through them, and the order cannot be trusted. Also, - * modifying an item in the heap will not cause that item to be re-sorted. - * If you want to change the position of an item in the heap you will have - * to dequeue every item before it, dequeue that item, change it, and - * re-enqueue all of the items removed. - */ - template, typename itemalloc=std::allocator > - class Heap : public Queue + template + class Heap; + + template + class HeapCore { - public: - Heap() : - iSize( 7 ), + friend class Heap; + friend class SharedCore< + Heap, HeapCore + >; + private: + HeapCore() : + iSize( 0 ), iFill( 0 ), - aItem( ia.allocate( iSize ) ) + aItem( NULL ) { } - - Heap( cmpfunc cmpin ) : - iSize( 7 ), - iFill( 0 ), - aItem( ia.allocate( iSize ) ), - cmp( cmpin ) + + virtual ~HeapCore() { + clear(); } - Heap( int iInitialCapacity ) : - iSize( 0 ), - iFill( 0 ), - aItem( NULL ) + void init() { - for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } + if( iSize > 0 ) + return; + + iSize = 7; + iFill = 0; aItem = ia.allocate( iSize ); } - - Heap( cmpfunc cmpin, int iInitialCapacity ) : - iSize( 0 ), - iFill( 0 ), - aItem( NULL ), - cmp( cmpin ) + + void init( int iCap ) { - for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } + if( iSize > 0 ) + return; + + for( iSize = 1; iSize < iCap; iSize=iSize*2+1 ) { } + iFill = 0; aItem = ia.allocate( iSize ); } - virtual ~Heap() + void clear() { + if( iSize == 0 ) + return; + for( int j = 0; j < iFill; j++ ) ia.destroy( &aItem[j] ); ia.deallocate( aItem, iSize ); aItem = NULL; + iSize = 0; + iFill = 0; } + + void upSize() + { + if( iSize == 0 ) + { + init(); + return; + } + item *aNewItems = ia.allocate( iSize*2+1 ); + // + // We cannot use a memcopy here because we don't know what kind + // of datastructures are being used, we have to copy them one at + // a time. + // + for( int j = 0; j < iFill; j++ ) + { + ia.construct( &aNewItems[j], aItem[j] ); + ia.destroy( &aItem[j] ); + } + ia.deallocate( aItem, iSize ); + aItem = aNewItems; + iSize = iSize*2+1; + } + virtual void enqueue( const item &it ) { item i = it; // TODO: This is a silly workaround, put the i item @@ -126,20 +142,6 @@ namespace Bu iFill++; } - virtual item &peek() - { - if( iFill == 0 ) - throw HeapException("Heap empty."); - return aItem[0]; - } - - virtual const item &peek() const - { - if( iFill == 0 ) - throw HeapException("Heap empty."); - return aItem[0]; - } - virtual item dequeue() { if( iFill == 0 ) @@ -174,14 +176,117 @@ namespace Bu return iRet; } + private: + int iSize; + int iFill; + item *aItem; + cmpfunc cmp; + itemalloc ia; + }; + + /** + * A priority queue that allows for an unlimited number of priorities. All + * objects enqueued must support less-than-comparison. Then every time an + * item is dequeued it is always the least item in the heap. The heap + * operates using a binary tree for storage, which allows most operations + * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins + * whereas peeking is constant time. + * + * This heap implementation allows iterating, however please note that any + * enqueue or dequeue operation will invalidate the iterator and make it + * unusable (if it still works, you shouldn't trust the results). Also, + * the items are not stored in memory in order, they are optomized into a + * tree. This means that the items will be in effectively random order + * while iterating through them, and the order cannot be trusted. Also, + * modifying an item in the heap will not cause that item to be re-sorted. + * If you want to change the position of an item in the heap you will have + * to dequeue every item before it, dequeue that item, change it, and + * re-enqueue all of the items removed. + */ + template, typename itemalloc=std::allocator > + class Heap : public Queue, public SharedCore< + Heap, + HeapCore + > + { + private: + typedef class Heap MyType; + typedef class HeapCore Core; + + protected: + using SharedCore::core; + using SharedCore::_hardCopy; + using SharedCore::_resetCore; + using SharedCore::_allocateCore; + + public: + Heap() + { + } + + Heap( cmpfunc cmpin ) + { + core->cmp = cmpin; + } + + Heap( int iInitialCapacity ) + { + core->init( iInitialCapacity ); + } + + Heap( cmpfunc cmpin, int iInitialCapacity ) + { + core->cmp = cmpin; + core->init( iInitialCapacity ); + } + + Heap( const MyType &rSrc ) : + SharedCore( rSrc ) + { + } + + virtual ~Heap() + { + } + + virtual void enqueue( const item &it ) + { + _hardCopy(); + + core->enqueue( it ); + } + + virtual item &peek() + { + _hardCopy(); + + if( core->iFill == 0 ) + throw HeapException("Heap empty."); + return core->aItem[0]; + } + + virtual const item &peek() const + { + if( core->iFill == 0 ) + throw HeapException("Heap empty."); + return core->aItem[0]; + } + + virtual item dequeue() + { + _hardCopy(); + + return core->dequeue(); + } + virtual bool isEmpty() const { - return (iFill==0); + return (core->iFill==0); } virtual int getSize() const { - return iFill; + return core->iFill; } class iterator @@ -201,7 +306,7 @@ namespace Bu { if( pHeap == NULL ) throw Bu::ExceptionBase("Iterator not initialized."); - if( iIndex < 0 || iIndex >= pHeap->iFill ) + if( iIndex < 0 || iIndex >= pHeap->core->iFill ) throw Bu::ExceptionBase("Iterator out of bounds."); } @@ -230,12 +335,16 @@ namespace Bu item &operator*() { - return pHeap->aItem[iIndex]; + pHeap->_hardCopy(); + + return pHeap->core->aItem[iIndex]; } item *operator->() { - return &(pHeap->aItem[iIndex]); + pHeap->_hardCopy(); + + return &(pHeap->core->aItem[iIndex]); } iterator &operator++() @@ -260,7 +369,7 @@ namespace Bu { checkValid(); iIndex++; - if( iIndex >= pHeap->iFill ) + if( iIndex >= pHeap->core->iFill ) iIndex = -1; return *this; @@ -279,7 +388,7 @@ namespace Bu checkValid(); iterator ret( *this ); ret.iIndex += iDelta; - if( ret.iIndex >= pHeap->iFill ) + if( ret.iIndex >= pHeap->core->iFill ) ret.iIndex = -1; return ret; } @@ -294,12 +403,12 @@ namespace Bu return ret; } - operator bool() + operator bool() const { return iIndex != -1; } - bool isValid() + bool isValid() const { return iIndex != -1; } @@ -328,7 +437,7 @@ namespace Bu { if( pHeap == NULL ) throw Bu::ExceptionBase("Iterator not initialized."); - if( iIndex < 0 || iIndex >= pHeap->iFill ) + if( iIndex < 0 || iIndex >= pHeap->core->iFill ) throw Bu::ExceptionBase("Iterator out of bounds."); } @@ -363,19 +472,23 @@ namespace Bu const item &operator*() { - return pHeap->aItem[iIndex]; + pHeap->_hardCopy(); + + return pHeap->core->aItem[iIndex]; } const item *operator->() { - return &(pHeap->aItem[iIndex]); + pHeap->_hardCopy(); + + return &(pHeap->core->aItem[iIndex]); } const_iterator &operator++() { checkValid(); iIndex++; - if( iIndex >= pHeap->iFill ) + if( iIndex >= pHeap->core->iFill ) iIndex = -1; return *this; @@ -393,7 +506,7 @@ namespace Bu { checkValid(); iIndex++; - if( iIndex >= pHeap->iFill ) + if( iIndex >= pHeap->core->iFill ) iIndex = -1; return *this; @@ -427,12 +540,12 @@ namespace Bu return ret; } - operator bool() + operator bool() const { return iIndex != -1; } - bool isValid() + bool isValid() const { return iIndex != -1; } @@ -452,14 +565,14 @@ namespace Bu iterator begin() { - if( iFill == 0 ) + if( core->iFill == 0 ) return end(); return iterator( this, 0 ); } const_iterator begin() const { - if( iFill == 0 ) + if( core->iFill == 0 ) return end(); return const_iterator( this, 0 ); } @@ -475,31 +588,22 @@ namespace Bu } - private: - void upSize() + protected: + virtual Core *_copyCore( Core *src ) { - item *aNewItems = ia.allocate( iSize*2+1 ); - // - // We cannot use a memcopy here because we don't know what kind - // of datastructures are being used, we have to copy them one at - // a time. - // - for( int j = 0; j < iFill; j++ ) + Core *pRet = _allocateCore(); + + pRet->iSize = src->iSize; + pRet->iFill = src->iFill; + pRet->cmp = src->cmp; + pRet->aItem = pRet->ia.allocate( pRet->iSize ); + for( int j = 0; j < pRet->iFill; j++ ) { - ia.construct( &aNewItems[j], aItem[j] ); - ia.destroy( &aItem[j] ); + pRet->ia.construct( &pRet->aItem[j], src->aItem[j] ); } - ia.deallocate( aItem, iSize ); - aItem = aNewItems; - iSize = iSize*2+1; - } - private: - int iSize; - int iFill; - item *aItem; - cmpfunc cmp; - itemalloc ia; + return pRet; + } }; }; diff --git a/src/list.h b/src/list.h index 9b95983..ba1d2c4 100644 --- a/src/list.h +++ b/src/list.h @@ -24,10 +24,18 @@ namespace Bu ListLink *pPrev; }; - template + template + class List; + + template struct ListCore { + friend class List; + friend class SharedCore< + List, + ListCore + >; + private: typedef struct ListLink Link; ListCore() : pFirst( NULL ), @@ -193,8 +201,10 @@ namespace Bu */ template, typename linkalloc=std::allocator > > - class List : public SharedCore< struct ListCore > + class List : public SharedCore< + List, + ListCore + > { private: typedef struct ListLink Link; @@ -202,9 +212,9 @@ namespace Bu typedef struct ListCore Core; protected: - using SharedCore< Core >::core; - using SharedCore< Core >::_hardCopy; - using SharedCore< Core >::_allocateCore; + using SharedCore::core; + using SharedCore::_hardCopy; + using SharedCore::_allocateCore; public: struct const_iterator; @@ -215,7 +225,7 @@ namespace Bu } List( const MyType &src ) : - SharedCore< Core >( src ) + SharedCore( src ) { } diff --git a/src/set.h b/src/set.h index 6a2abce..047ff7f 100644 --- a/src/set.h +++ b/src/set.h @@ -24,17 +24,10 @@ namespace Bu { subExceptionDecl( SetException ) - template - uint32_t __calcHashCode( const T &k ); - - template - bool __cmpHashKeys( const T &a, const T &b ); - - template, typename challoc = std::allocator > - class Set; - /** - * Libbu Template Set + *@todo Set should be rewritten, possibly using a b-tree as ordered storage + * in the backend. It should use either a b-tree or array for storage and + * allow set intersections, unions, etc. *@param key (typename) The datatype of the hashtable keys *@param sizecalc (typename) Functor to compute new table size on rehash *@param keyalloc (typename) Memory allocator for hashtable keys @@ -45,754 +38,7 @@ namespace Bu class Set { public: - Set() : - nCapacity( 11 ), - nFilled( 0 ), - nDeleted( 0 ), - bFilled( NULL ), - bDeleted( NULL ), - aKeys( NULL ), - aHashCodes( NULL ) - { - nKeysSize = bitsToBytes( nCapacity ); - bFilled = ca.allocate( nKeysSize ); - bDeleted = ca.allocate( nKeysSize ); - clearBits(); - - aHashCodes = ca.allocate( nCapacity ); - aKeys = ka.allocate( nCapacity ); - } - - Set( const Set &src ) : - nCapacity( src.nCapacity ), - nFilled( 0 ), - nDeleted( 0 ), - bFilled( NULL ), - bDeleted( NULL ), - aKeys( NULL ), - aHashCodes( NULL ) - { - nKeysSize = bitsToBytes( nCapacity ); - bFilled = ca.allocate( nKeysSize ); - bDeleted = ca.allocate( nKeysSize ); - clearBits(); - - aHashCodes = ca.allocate( nCapacity ); - aKeys = ka.allocate( nCapacity ); - - for( uint32_t j = 0; j < src.nCapacity; j++ ) - { - if( src.isFilled( j ) ) - { - insert( src.aKeys[j] ); - } - } - } - - /** - * Set assignment operator. Clears this hashtable and - * copies RH into it. - */ - Set &operator=( const Set &src ) - { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - { - ka.destroy( &aKeys[j] ); - } - } - ka.deallocate( aKeys, nCapacity ); - ca.deallocate( bFilled, nKeysSize ); - ca.deallocate( bDeleted, nKeysSize ); - ca.deallocate( aHashCodes, nCapacity ); - - nFilled = 0; - nDeleted = 0; - nCapacity = src.nCapacity; - nKeysSize = bitsToBytes( nCapacity ); - bFilled = ca.allocate( nKeysSize ); - bDeleted = ca.allocate( nKeysSize ); - clearBits(); - - aHashCodes = ca.allocate( nCapacity ); - aKeys = ka.allocate( nCapacity ); - - for( uint32_t j = 0; j < src.nCapacity; j++ ) - { - if( src.isFilled( j ) ) - { - insert( src.aKeys[j] ); - } - } - - return *this; - } - - virtual ~Set() - { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - { - ka.destroy( &aKeys[j] ); - } - } - ka.deallocate( aKeys, nCapacity ); - ca.deallocate( bFilled, nKeysSize ); - ca.deallocate( bDeleted, nKeysSize ); - ca.deallocate( aHashCodes, nCapacity ); - } - - /** - * Get the current hash table capacity. (Changes at re-hash) - *@returns (uint32_t) The current capacity. - */ - uint32_t getCapacity() - { - return nCapacity; - } - - /** - * Get the number of hash locations spoken for. (Including - * not-yet-cleaned-up deleted items.) - *@returns (uint32_t) The current fill state. - */ - uint32_t getFill() - { - return nFilled; - } - - /** - * Get the number of items stored in the hash table. - *@returns (uint32_t) The number of items stored in the hash table. - */ - uint32_t getSize() - { - return nFilled-nDeleted; - } - - /** - * Get the number of items which have been deleted, but not yet - * cleaned up. - *@returns (uint32_t) The number of deleted items. - */ - uint32_t getDeleted() - { - return nDeleted; - } - - /** - * Insert key (k) into the set - *@param k (key_type) Key to list the value under. - */ - virtual void insert( key k ) - { - uint32_t hash = __calcHashCode( k ); - bool bFill; - uint32_t nPos = probe( hash, k, bFill ); - - if( bFill ) - { - onUpdate(); - } - else - { - fill( nPos, k, hash ); - onInsert(); - } - } - - /** - * Remove a value from the hash table. - *@param k (key_type) The data under this key will be erased. - */ - virtual void erase( key k ) - { - uint32_t hash = __calcHashCode( k ); - bool bFill; - uint32_t nPos = probe( hash, k, bFill ); - - if( bFill ) - { - _erase( nPos ); - onDelete(); - } - } - - struct iterator; - - /** - * Remove a value from the hash pointed to from an iterator. - *@param i (iterator &) The data to be erased. - */ - virtual void erase( struct iterator &i ) - { - if( this != &i.hsh ) - throw SetException("This iterator didn't come from this Hash."); - if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) - { - _erase( i.nPos ); - onDelete(); - } - } - - /** - * Remove all data from the hash table. - */ - virtual void clear() - { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - { - _erase( j ); - onDelete(); - } - } - - clearBits(); - } - - /** - * Does the hash table contain an item under key (k). - *@param k (key_type) The key to check. - *@returns (bool) Whether there was an item in the hash under key (k). - */ - virtual bool has( key k ) - { - bool bFill; - probe( __calcHashCode( k ), k, bFill, false ); - - return bFill; - } - - /** - * Iteration structure for iterating through the hash. - */ - typedef struct iterator - { - friend class Set; - private: - iterator( Set &hsh ) : - hsh( hsh ), - nPos( 0 ), - bFinished( false ) - { - nPos = hsh.getFirstPos( bFinished ); - } - - iterator( Set &hsh, bool bDone ) : - hsh( hsh ), - nPos( 0 ), - bFinished( bDone ) - { - } - - Set &hsh; - uint32_t nPos; - bool bFinished; - - public: - /** - * Iterator incrementation operator. Move the iterator forward. - */ - iterator operator++( int ) - { - if( bFinished == false ) - nPos = hsh.getNextPos( nPos, bFinished ); - - return *this; - } - - /** - * Iterator incrementation operator. Move the iterator forward. - */ - iterator operator++() - { - if( bFinished == false ) - nPos = hsh.getNextPos( nPos, bFinished ); - - return *this; - } - - /** - * Iterator equality comparison operator. Iterators the same? - */ - bool operator==( const iterator &oth ) const - { - if( bFinished != oth.bFinished ) - return false; - if( bFinished == true ) - { - return true; - } - else - { - if( oth.nPos == nPos ) - return true; - return false; - } - } - - /** - * Iterator not equality comparison operator. Not the same? - */ - bool operator!=( const iterator &oth ) const - { - return !(*this == oth ); - } - - /** - * Iterator assignment operator. - */ - iterator operator=( const iterator &oth ) - { - if( &hsh != &oth.hsh ) - throw SetException( - "Cannot mix iterators from different set objects."); - nPos = oth.nPos; - bFinished = oth.bFinished; - } - - /** - * Iterator dereference operator... err.. get the value - *@returns (value_type &) The value behind this iterator. - */ - key &operator *() - { - return hsh.getKeyAtPos( nPos ); - } - - const key &operator *() const - { - return hsh.getKeyAtPos( nPos ); - } - - bool isValid() const - { - return !bFinished; - } - - operator bool() const - { - return !bFinished; - } - } iterator; - - /** - * Iteration structure for iterating through the set (const). - */ - typedef struct const_iterator - { - friend class Set; - private: - const_iterator( const Set &hsh ) : - hsh( hsh ), - nPos( 0 ), - bFinished( false ) - { - nPos = hsh.getFirstPos( bFinished ); - } - - const_iterator( const Set &hsh, bool bDone ) : - hsh( hsh ), - nPos( 0 ), - bFinished( bDone ) - { - } - - const Set &hsh; - uint32_t nPos; - bool bFinished; - - public: - /** - * Iterator incrementation operator. Move the iterator forward. - */ - const_iterator operator++( int ) - { - if( bFinished == false ) - nPos = hsh.getNextPos( nPos, bFinished ); - - return *this; - } - - /** - * Iterator incrementation operator. Move the iterator forward. - */ - const_iterator operator++() - { - if( bFinished == false ) - nPos = hsh.getNextPos( nPos, bFinished ); - - return *this; - } - - /** - * Iterator equality comparison operator. Iterators the same? - */ - bool operator==( const const_iterator &oth ) const - { - if( bFinished != oth.bFinished ) - return false; - if( bFinished == true ) - { - return true; - } - else - { - if( oth.nPos == nPos ) - return true; - return false; - } - } - - /** - * Iterator not equality comparison operator. Not the same? - */ - bool operator!=( const const_iterator &oth ) const - { - return !(*this == oth ); - } - - /** - * Iterator assignment operator. - */ - const_iterator operator=( const const_iterator &oth ) - { - if( &hsh != &oth.hsh ) - throw SetException( - "Cannot mix iterators from different hash objects."); - nPos = oth.nPos; - bFinished = oth.bFinished; - } - - /** - * Iterator dereference operator... err.. get the value - *@returns (value_type &) The value behind this iterator. - */ - const key &operator *() const - { - return hsh.getKeyAtPos( nPos ); - } - - bool isValid() const - { - return !bFinished; - } - - operator bool() const - { - return !bFinished; - } - } const_iterator; - - /** - * Get an iterator pointing to the first item in the hash table. - *@returns (iterator) An iterator pointing to the first item in the - * hash table. - */ - iterator begin() - { - return iterator( *this ); - } - - const_iterator begin() const - { - return const_iterator( *this ); - } - - /** - * Get an iterator pointing to a point just past the last item in the - * hash table. - *@returns (iterator) An iterator pointing to a point just past the - * last item in the hash table. - */ - iterator end() - { - return iterator( *this, true ); - } - - const_iterator end() const - { - return const_iterator( *this, true ); - } - - /** - * Get a list of all the keys in the hash table. - *@returns (std::list) The list of keys in the hash table. - */ - Bu::List getKeys() const - { - Bu::List lKeys; - - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - { - if( !isDeleted( j ) ) - { - lKeys.append( aKeys[j] ); - } - } - } - - return lKeys; - } - - protected: - virtual void onInsert() {} - virtual void onUpdate() {} - virtual void onDelete() {} - virtual void onReHash() {} - - virtual void clearBits() - { - for( uint32_t j = 0; j < nKeysSize; j++ ) - { - bFilled[j] = bDeleted[j] = 0; - } - } - - virtual void fill( uint32_t loc, key &k, uint32_t hash ) - { - bFilled[loc/32] |= (1<<(loc%32)); - ka.construct( &aKeys[loc], k ); - aHashCodes[loc] = hash; - nFilled++; - //printf("Filled: %d, Deleted: %d, Capacity: %d\n", - // nFilled, nDeleted, nCapacity ); - } - - virtual void _erase( uint32_t loc ) - { - bDeleted[loc/32] |= (1<<(loc%32)); - ka.destroy( &aKeys[loc] ); - nDeleted++; - //printf("Filled: %d, Deleted: %d, Capacity: %d\n", - // nFilled, nDeleted, nCapacity ); - } - - virtual key &getKeyAtPos( uint32_t nPos ) - { - return aKeys[nPos]; - } - - virtual const key &getKeyAtPos( uint32_t nPos ) const - { - return aKeys[nPos]; - } - - virtual uint32_t getFirstPos( bool &bFinished ) const - { - for( uint32_t j = 0; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - return j; - } - - bFinished = true; - return 0; - } - - virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const - { - for( uint32_t j = nPos+1; j < nCapacity; j++ ) - { - if( isFilled( j ) ) - if( !isDeleted( j ) ) - return j; - } - - bFinished = true; - return 0; - } - - 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 - int8_t j; - for( j = 0; - isFilled( nCur ) && j < 32; - nCur = (nCur + (1< - Archive &operator<<( Archive &ar, const Set &h ) - { - ar << h.getSize(); - for( typename Set::const_iterator i = h.begin(); i != h.end(); i++ ) - { - ar << (*i); - } - - return ar; - } - - template - Archive &operator>>( Archive &ar, Set &h ) - { - h.clear(); - long nSize; - ar >> nSize; - - for( long j = 0; j < nSize; j++ ) - { - key v; - ar >> v; - h.insert( v ); - } - - return ar; - } } #endif diff --git a/src/sharedcore.h b/src/sharedcore.h index 5a44df9..ac36606 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h @@ -15,10 +15,10 @@ namespace Bu { - template + template class SharedCore { - typedef class SharedCore _SharedType; + typedef class SharedCore _SharedType; public: SharedCore() : core( NULL ), @@ -54,6 +54,18 @@ namespace Bu return *iRefCount; } + Shell clone() const + { + Shell s( dynamic_cast(*this) ); + s._hardCopy(); + return s; + } + + bool isCoreShared( const Shell &rOther ) const + { + return rOther.core == core; + } + protected: Core *core; void _hardCopy() @@ -68,6 +80,20 @@ namespace Bu iRefCount = new int( 1 ); } + /** + * Reset core acts like a hard copy, except instead of providing a + * standalone copy of the shared core, it provides a brand new core. + * + * Very useful in functions used to reset the state of an object. + */ + void _resetCore() + { + if( core ) + _deref(); + core = _allocateCore(); + iRefCount = new int( 1 ); + } + virtual Core *_allocateCore() { return new Core(); diff --git a/src/tests/sharedcore.cpp b/src/tests/sharedcore.cpp index 1d0c16e..9b0a0ec 100644 --- a/src/tests/sharedcore.cpp +++ b/src/tests/sharedcore.cpp @@ -14,7 +14,7 @@ struct ShintCore { int val; }; -class Shint : public Bu::SharedCore +class Shint : public Bu::SharedCore { public: Shint() diff --git a/src/unit/hash.unit b/src/unit/hash.unit index e3d7e42..124b074 100644 --- a/src/unit/hash.unit +++ b/src/unit/hash.unit @@ -84,4 +84,17 @@ suite Hash printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); } */ } + + test copy + { + StrIntHash h; + h.insert("hello", 55 ); + h.insert("goodbye", -1812 ); + + StrIntHash h2 = h; + unitTest( h2.isCoreShared( h ) ); + + StrIntHash h3 = h.clone(); + unitTest( !h3.isCoreShared( h ) ); + } } -- cgit v1.2.3 From 93c028162318a00b9bd03fc4a48383f830cc529d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 15 Oct 2010 15:12:31 +0000 Subject: RingBuffer is now SharedCore. I think that's all the container classes, there may be a few other things that should change too, we'll see. Played with doxygen docs on List, we can actually use @cond to remove things from the docs, either permenently or conditionally, and so I could trick it into making all of the sharedcore classes inherit from the same SharedCore in the docs instead of different ones. Or, just not inherit from SharedCore at all. What to do...? :-P I also got rid of ListHash, it wasn't working out yet anyway. --- src/list.h | 7 +- src/listhash.cpp | 8 --- src/listhash.h | 54 --------------- src/ringbuffer.h | 207 +++++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 168 insertions(+), 108 deletions(-) delete mode 100644 src/listhash.cpp delete mode 100644 src/listhash.h diff --git a/src/list.h b/src/list.h index ba1d2c4..b1e0d0f 100644 --- a/src/list.h +++ b/src/list.h @@ -16,6 +16,7 @@ namespace Bu { + /** @cond DEVEL */ template struct ListLink { @@ -185,6 +186,7 @@ namespace Bu } } }; + /** @endcond */ /** * Linked list template container. This class is similar to the stl list @@ -197,14 +199,15 @@ namespace Bu *@param value (typename) The type of data to store in your list *@param valuealloc (typename) Memory Allocator for your value type *@param linkalloc (typename) Memory Allocator for the list links. + *@extends SharedCore *@ingroup Containers */ template, typename linkalloc=std::allocator > > - class List : public SharedCore< + class List /** @cond */ : public SharedCore< List, ListCore - > + > /** @endcond */ { private: typedef struct ListLink Link; diff --git a/src/listhash.cpp b/src/listhash.cpp deleted file mode 100644 index b798a1f..0000000 --- a/src/listhash.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - - diff --git a/src/listhash.h b/src/listhash.h deleted file mode 100644 index e5ec4ee..0000000 --- a/src/listhash.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_LIST_HASH_H -#define BU_LIST_HASH_H - -#include "bu/hash.h" -#include "bu/list.h" - -namespace Bu -{ - template, typename valuealloc = std::allocator >, typename challoc = std::allocator > - class ListHash : public Hash, sizecalc, keyalloc, valuealloc, challoc> - { - typedef Hash, sizecalc, keyalloc, valuealloc, challoc> ParentType; - public: - ListHash() - { - } - - ListHash( const ListHash &src ) : - ParentType( src ) - { - } - - virtual ~ListHash() - { - } - - ListHash &operator=( const ListHash &src ) - { - *dynamic_cast(this) = - dynamic_cast(src); - } - - virtual void insert( const key &k, const value &v ) - { - if( !has( k ) ) - { - ParentType::insert( k, List() ); - } - get( k ).append( v ); - } - - private: - }; - -}; - -#endif diff --git a/src/ringbuffer.h b/src/ringbuffer.h index e984d18..04add42 100644 --- a/src/ringbuffer.h +++ b/src/ringbuffer.h @@ -10,97 +10,216 @@ #include #include "bu/exceptionbase.h" +#include "bu/queue.h" +#include "bu/sharedcore.h" namespace Bu { - /** - *@ingroup Containers - */ - template > - class RingBuffer + template class RingBuffer; + + template + class RingBufferCore { - public: - RingBuffer( int nCapacity ) : - nCapacity( nCapacity ), - nStart( -1 ), - nEnd( -2 ) + friend class RingBuffer; + friend class SharedCore, + RingBufferCore >; + private: + RingBufferCore() : + iCapacity( 0 ), + iStart( -1 ), + iEnd( -2 ), + aData( NULL ) { - aData = va.allocate( nCapacity ); } - virtual ~RingBuffer() + virtual ~RingBufferCore() { - for( int j = nStart; j < nEnd; j=(j+1%nCapacity) ) - { - va.destroy( &aData[j] ); - } - va.deallocate( aData, nCapacity ); + clear(); } - int getCapacity() + void init( int iNewCapacity ) { - return nCapacity; - } + if( iCapacity > 0 ) + return; - bool isFilled() - { - return (nStart == nEnd); + iCapacity = iNewCapacity; + iStart = -1; + iEnd = -2; + aData = va.allocate( iCapacity ); } - bool isEmpty() + void clear() { - return (nStart == -1); + for( int j = iStart; j < iEnd; j=(j+1%iCapacity) ) + { + va.destroy( &aData[j] ); + } + va.deallocate( aData, iCapacity ); + aData = NULL; + iCapacity = 0; } - + void enqueue( const value &v ) { - if( nStart == -1 ) + if( iStart == -1 ) { - nStart = 0; - nEnd = 1; + iStart = 0; + iEnd = 1; va.construct( &aData[0], v ); } - else if( nStart == nEnd ) + else if( iStart == iEnd ) { throw ExceptionBase("Hey, it's full!"); } else { - va.construct( &aData[nEnd], v ); - nEnd = (nEnd+1)%nCapacity; + va.construct( &aData[iEnd], v ); + iEnd = (iEnd+1)%iCapacity; } } value dequeue() { - if( nStart == -1 ) + if( iStart == -1 ) { throw ExceptionBase("No data"); } else { - value &v = aData[nStart]; - va.destroy( &aData[nStart] ); - nStart = (nStart+1)%nCapacity; - if( nStart == nEnd ) + value &v = aData[iStart]; + va.destroy( &aData[iStart] ); + iStart = (iStart+1)%iCapacity; + if( iStart == iEnd ) { - nStart = -1; - nEnd = -2; + iStart = -1; + iEnd = -2; } return v; } } - value &operator[]( int nIndex ) + value &get( int iIndex ) { - return aData[(nIndex+nStart)%nCapacity]; + return aData[(iIndex+iStart)%iCapacity]; } - private: - int nCapacity; + int getSize() + { + if( iStart < 0 ) + return 0; + if( iEnd == iStart ) + return iCapacity; + if( iEnd < iStart ) + return iEnd-iStart; + return iCapacity-(iEnd-iStart); + } + + int iCapacity; + int iStart, iEnd; value *aData; valuealloc va; - int nStart, nEnd; + }; + + /** + *@ingroup Containers + */ + template > + class RingBuffer : public Queue, public SharedCore< + RingBuffer, + RingBufferCore + > + { + private: + typedef RingBuffer MyType; + typedef RingBufferCore Core; + + protected: + using SharedCore::core; + using SharedCore::_hardCopy; + using SharedCore::_allocateCore; + + public: + RingBuffer( int iCapacity ) + { + core->init( iCapacity ); + } + + RingBuffer( const RingBuffer &rSrc ) : + SharedCore( rSrc ) + { + } + + virtual ~RingBuffer() + { + } + + int getCapacity() const + { + return core->iCapacity; + } + + bool isFilled() const + { + return (core->iStart == core->iEnd); + } + + bool isEmpty() const + { + return (core->iStart == -1); + } + + virtual void enqueue( const value &v ) + { + _hardCopy(); + + core->enqueue( v ); + } + + virtual value dequeue() + { + _hardCopy(); + + return core->dequeue(); + } + + virtual int getSize() const + { + return core->getSize(); + } + + virtual value &peek() + { + _hardCopy(); + + return core->get( 0 ); + } + + virtual const value &peek() const + { + return core->get( 0 ); + } + + value &operator[]( int iIndex ) + { + _hardCopy(); + + return core->get( iIndex ); + } + + protected: + virtual Core *_copyCore( Core *src ) + { + Core *pRet = _allocateCore(); + + pRet->init( src->iCapacity ); + int iSize = src->getSize(); + for( int j = 0; j < iSize; j++ ) + { + pRet->enqueue( src->get( j ) ); + } + + return pRet; + } }; } -- cgit v1.2.3 From 9031e2af7dd4e65ec70890ee78a7cf600d1b2cc5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sat, 16 Oct 2010 03:02:11 +0000 Subject: Many, many changes. Documentation changes, renamed the socket class to TcpSocket, fixed many other things, and finally removed ParamProc. Anything that needs it will now have to switch to OptParser. --- src/array.h | 2 + src/client.cpp | 9 +- src/client.h | 8 +- src/fastcgi.cpp | 22 +- src/fastcgi.h | 18 +- src/fbasicstring.h | 2 + src/hash.h | 2 + src/heap.h | 2 + src/httpget.h | 4 +- src/itoserver.cpp | 12 +- src/itoserver.h | 6 +- src/newline.h | 2 +- src/paramproc.cpp | 523 ---------------------------------------------- src/paramproc.h | 163 --------------- src/ringbuffer.h | 2 + src/server.cpp | 14 +- src/server.h | 6 +- src/serversocket.cpp | 249 ---------------------- src/serversocket.h | 64 ------ src/sharedcore.h | 47 +++++ src/socket.cpp | 446 --------------------------------------- src/socket.h | 115 ---------- src/tcpserversocket.cpp | 249 ++++++++++++++++++++++ src/tcpserversocket.h | 64 ++++++ src/tcpsocket.cpp | 450 +++++++++++++++++++++++++++++++++++++++ src/tcpsocket.h | 116 ++++++++++ src/tests/socket.cpp | 73 ------- src/tests/socketblock.cpp | 10 +- src/tests/socketbreak.cpp | 10 +- src/tests/tcpsocket.cpp | 73 +++++++ src/variant.h | 18 +- 31 files changed, 1087 insertions(+), 1694 deletions(-) delete mode 100644 src/paramproc.cpp delete mode 100644 src/paramproc.h delete mode 100644 src/serversocket.cpp delete mode 100644 src/serversocket.h delete mode 100644 src/socket.cpp delete mode 100644 src/socket.h create mode 100644 src/tcpserversocket.cpp create mode 100644 src/tcpserversocket.h create mode 100644 src/tcpsocket.cpp create mode 100644 src/tcpsocket.h delete mode 100644 src/tests/socket.cpp create mode 100644 src/tests/tcpsocket.cpp diff --git a/src/array.h b/src/array.h index fc4fb12..f225c97 100644 --- a/src/array.h +++ b/src/array.h @@ -20,6 +20,7 @@ namespace Bu template class Array; + /** @cond DEVEL */ template class ArrayCore { @@ -107,6 +108,7 @@ namespace Bu long iSize; long iCapacity; }; + /** @endcond */ /** * Array type container, just like a normal array only flexible and keeps diff --git a/src/client.cpp b/src/client.cpp index becd1bd..b635c8b 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -6,7 +6,7 @@ */ #include "bu/client.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include #include #include "bu/protocol.h" @@ -16,7 +16,8 @@ /** Read buffer size. */ #define RBS (1024*2) -Bu::Client::Client( Bu::Socket *pSocket, class Bu::ClientLinkFactory *pfLink ) : +Bu::Client::Client( Bu::TcpSocket *pSocket, + class Bu::ClientLinkFactory *pfLink ) : pTopStream( pSocket ), pSocket( pSocket ), pProto( NULL ), @@ -59,7 +60,7 @@ void Bu::Client::processInput() break; } } - catch( Bu::SocketException &e ) + catch( Bu::TcpSocketException &e ) { pTopStream->close(); bWantsDisconnect = true; @@ -195,7 +196,7 @@ long Bu::Client::getOutputSize() return qbWrite.getSize(); } -const Bu::Socket *Bu::Client::getSocket() const +const Bu::TcpSocket *Bu::Client::getSocket() const { return pSocket; } diff --git a/src/client.h b/src/client.h index f336524..096df2f 100644 --- a/src/client.h +++ b/src/client.h @@ -17,7 +17,7 @@ namespace Bu { class Protocol; class Stream; - class Socket; + class TcpSocket; class ClientLinkFactory; /** @@ -26,7 +26,7 @@ namespace Bu class Client : public Bu::Stream { public: - Client( Bu::Socket *pSocket, Bu::ClientLinkFactory *pfLink ); + Client( Bu::TcpSocket *pSocket, Bu::ClientLinkFactory *pfLink ); virtual ~Client(); void processInput(); @@ -58,7 +58,7 @@ namespace Bu void close(); void tick(); - const Bu::Socket *getSocket() const; + const Bu::TcpSocket *getSocket() const; void disconnect(); bool wantsDisconnect(); @@ -117,7 +117,7 @@ namespace Bu typedef Bu::List FilterList; FilterList lFilts; Bu::Stream *pTopStream; - Bu::Socket *pSocket; + Bu::TcpSocket *pSocket; Bu::Protocol *pProto; Bu::QueueBuf qbRead; Bu::QueueBuf qbWrite; diff --git a/src/fastcgi.cpp b/src/fastcgi.cpp index 8168928..ca3010e 100644 --- a/src/fastcgi.cpp +++ b/src/fastcgi.cpp @@ -24,14 +24,14 @@ Bu::FastCgi::FastCgi() : pSrv( NULL ), bRunning( true ) { - pSrv = new Bu::ServerSocket( STDIN_FILENO, false ); + pSrv = new Bu::TcpServerSocket( STDIN_FILENO, false ); } Bu::FastCgi::FastCgi( int iPort ) : pSrv( NULL ), bRunning( true ) { - pSrv = new Bu::ServerSocket( iPort ); + pSrv = new Bu::TcpServerSocket( iPort ); } Bu::FastCgi::~FastCgi() @@ -64,17 +64,17 @@ bool Bu::FastCgi::isEmbedded() #endif } -void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::Record &r ) +void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r ) { int iRead = s.read( &r, sizeof(Record) ); if( iRead != sizeof(Record) ) - throw Bu::SocketException("Hey, the size %d is wrong for Record. (%s)", + throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)", iRead, strerror( errno ) ); r.uRequestId = ntohs( r.uRequestId ); r.uContentLength = ntohs( r.uContentLength ); } -void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) +void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r ) { // sio << "Out -> " << r << sio.nl; r.uRequestId = htons( r.uRequestId ); @@ -82,19 +82,19 @@ void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) s.write( &r, sizeof(Record) ); } -void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::BeginRequestBody &b ) +void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b ) { s.read( &b, sizeof(BeginRequestBody) ); b.uRole = ntohs( b.uRole ); } -void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::EndRequestBody b ) +void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b ) { b.uStatus = htonl( b.uStatus ); s.write( &b, sizeof(b) ); } -uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) +uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead ) { uint8_t uByte[4]; s.read( uByte, 1 ); @@ -107,7 +107,7 @@ uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); } -void Bu::FastCgi::readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uRead ) +void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead ) { uint32_t uName = readLen( s, uRead ); uint32_t uValue = readLen( s, uRead ); @@ -162,7 +162,7 @@ void Bu::FastCgi::run() if( iSock < 0 ) continue; - Bu::Socket s( iSock ); + Bu::TcpSocket s( iSock ); s.setBlocking( true ); // sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; try @@ -362,7 +362,7 @@ void Bu::FastCgi::run() } } } - catch( Bu::SocketException &e ) + catch( Bu::TcpSocketException &e ) { // sio << "Bu::SocketException: " << e.what() << sio.nl << // "\tSocket open: " << s.isOpen() << sio.nl; diff --git a/src/fastcgi.h b/src/fastcgi.h index 262872c..7c1c04c 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h @@ -11,8 +11,8 @@ #include "bu/fstring.h" #include "bu/hash.h" #include "bu/array.h" -#include "bu/socket.h" -#include "bu/serversocket.h" +#include "bu/tcpsocket.h" +#include "bu/tcpserversocket.h" namespace Bu { @@ -109,18 +109,18 @@ namespace Bu virtual void onUninit() { }; private: - void read( Bu::Socket &s, Record &r ); - void read( Bu::Socket &s, BeginRequestBody &b ); - uint32_t readLen( Bu::Socket &s, uint16_t &uUsed ); - void readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uUsed ); + void read( Bu::TcpSocket &s, Record &r ); + void read( Bu::TcpSocket &s, BeginRequestBody &b ); + uint32_t readLen( Bu::TcpSocket &s, uint16_t &uUsed ); + void readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uUsed ); - void write( Bu::Socket &s, Record r ); - void write( Bu::Socket &s, EndRequestBody b ); + void write( Bu::TcpSocket &s, Record r ); + void write( Bu::TcpSocket &s, EndRequestBody b ); bool hasChannel( int iChan ); private: - Bu::ServerSocket *pSrv; + Bu::TcpServerSocket *pSrv; bool bRunning; Bu::Array aChannel; }; diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 82c5137..7167f4a 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -25,6 +25,7 @@ namespace Bu { + /** @cond DEVEL */ template< typename chr > struct FStringChunk { @@ -166,6 +167,7 @@ namespace Bu nLength += pNewChunk->nLength; } }; + /** @endcond */ /** * Flexible String class. This class was designed with string passing and diff --git a/src/hash.h b/src/hash.h index 714a7f7..d251c46 100644 --- a/src/hash.h +++ b/src/hash.h @@ -54,6 +54,7 @@ namespace Bu typename valuealloc, typename challoc> class Hash; + /** @cond DEVEL */ template class HashCore @@ -399,6 +400,7 @@ namespace Bu challoc ca; sizecalc szCalc; }; + /** @endcond */ /** * Libbu++ Template Hash Table. This is your average hash table, that uses diff --git a/src/heap.h b/src/heap.h index 1dac69b..31c2435 100644 --- a/src/heap.h +++ b/src/heap.h @@ -22,6 +22,7 @@ namespace Bu template class Heap; + /** @cond DEVEL */ template class HeapCore { @@ -183,6 +184,7 @@ namespace Bu cmpfunc cmp; itemalloc ia; }; + /** @endcond */ /** * A priority queue that allows for an unlimited number of priorities. All diff --git a/src/httpget.h b/src/httpget.h index 410914c..783f880 100644 --- a/src/httpget.h +++ b/src/httpget.h @@ -11,7 +11,7 @@ #include "bu/stream.h" #include "bu/fstring.h" #include "bu/url.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include "bu/hash.h" namespace Bu @@ -52,7 +52,7 @@ namespace Bu private: Bu::Url uSrc; Bu::FString sMethod; - Bu::Socket sSrv; + Bu::TcpSocket sSrv; typedef Bu::Hash MimeHash; MimeHash hMimeIn; MimeHash hMimeOut; diff --git a/src/itoserver.cpp b/src/itoserver.cpp index a1d804a..ea737bf 100644 --- a/src/itoserver.cpp +++ b/src/itoserver.cpp @@ -7,9 +7,9 @@ #include "bu/itoserver.h" #include -#include "bu/serversocket.h" +#include "bu/tcpserversocket.h" #include "bu/client.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include "bu/config.h" @@ -41,7 +41,7 @@ Bu::ItoServer::~ItoServer() void Bu::ItoServer::addPort( int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -49,7 +49,7 @@ void Bu::ItoServer::addPort( int nPort, int nPoolSize ) void Bu::ItoServer::addPort( const FString &sAddr, int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -92,7 +92,7 @@ void Bu::ItoServer::run() { if( FD_ISSET( i.getKey(), &fdRead ) ) { - ServerSocket *pSrv = i.getValue(); + TcpServerSocket *pSrv = i.getValue(); addClient( pSrv->accept(), pSrv->getPort() ); } } @@ -126,7 +126,7 @@ Bu::ItoServer::ItoClient::ItoClient( ItoServer &rSrv, int iSocket, int iPort, FD_SET( iSocket, &fdActive ); pClient = new Client( - new Bu::Socket( iSocket ), + new Bu::TcpSocket( iSocket ), new SrvClientLinkFactory( rSrv ) ); } diff --git a/src/itoserver.h b/src/itoserver.h index c08d453..81e42cc 100644 --- a/src/itoserver.h +++ b/src/itoserver.h @@ -26,8 +26,8 @@ namespace Bu { - class ServerSocket; - class Socket; + class TcpServerSocket; + class TcpSocket; class Client; /** @@ -126,7 +126,7 @@ namespace Bu int nTimeoutSec; int nTimeoutUSec; fd_set fdActive; - typedef Hash ServerHash; + typedef Hash ServerHash; ServerHash hServers; typedef Hash ClientHash; typedef ItoQueue ClientQueue; diff --git a/src/newline.h b/src/newline.h index b69cdb5..243c876 100644 --- a/src/newline.h +++ b/src/newline.h @@ -14,7 +14,7 @@ namespace Bu { /** * Converts new-line characters from any standard convention into linefeeds - * (\n) on reading, and converts them to either your OS's standard or a + * (\\n) on reading, and converts them to either your OS's standard or a * specified standard, depending on how you construct the class. * * If you're reading in a text file, then this filter is practically diff --git a/src/paramproc.cpp b/src/paramproc.cpp deleted file mode 100644 index f4fd36e..0000000 --- a/src/paramproc.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include "bu/paramproc.h" -#include -#include -#include - -#define ptrtype( iitype, iiname ) \ - Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ - type( vt ##iiname ) { val.iiname = iiname; } - -Bu::ParamProc::ParamPtr::ParamPtr() -{ - val.str = NULL; - type = vtunset; -} - -ptrtype( Bu::FString, str ); -ptrtype( uint64_t, uint64 ); -ptrtype( uint32_t, uint32 ); -ptrtype( uint16_t, uint16 ); -ptrtype( uint8_t, uint8 ); -ptrtype( int64_t, int64 ); -ptrtype( int32_t, int32 ); -ptrtype( int16_t, int16 ); -ptrtype( int8_t, int8 ); -ptrtype( float, float32 ); -ptrtype( double, float64 ); -ptrtype( long double, float96 ); -ptrtype( bool, bln ); - -Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) -{ - val = ptr.val; - type = ptr.type; - - return *this; -} - -bool Bu::ParamProc::ParamPtr::isSet() -{ - return type != vtunset; -} - -Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str ) -{ - if( !isSet() ) return *this; - switch( type ) - { - case vtstr: - (*val.str) = str; - break; - - case vtuint64: - (*val.uint64) = strtoull( str, NULL, 10 ); - break; - - case vtuint32: - (*val.uint32) = strtoul( str, NULL, 10 ); - break; - - case vtuint16: - (*val.uint16) = (uint16_t)strtoul( str, NULL, 10 ); - break; - - case vtuint8: - (*val.uint8) = (uint8_t)strtoul( str, NULL, 10 ); - break; - - case vtint64: - (*val.int64) = strtoll( str, NULL, 10 ); - break; - - case vtint32: - (*val.int32) = strtol( str, NULL, 10 ); - break; - - case vtint16: - (*val.int16) = (int16_t)strtol( str, NULL, 10 ); - break; - - case vtint8: - (*val.int8) = (int8_t)strtol( str, NULL, 10 ); - break; - - case vtfloat32: - (*val.float32) = strtof( str, NULL ); - break; - - case vtfloat64: - (*val.float64) = strtod( str, NULL ); - break; - - case vtfloat96: - (*val.float96) = strtold( str, NULL ); - break; - - case vtbln: - if( strcasecmp("yes", str ) == 0 || - strcasecmp("true", str ) == 0 ) - { - (*val.bln) = true; - } - else - { - (*val.bln) = false; - } - break; - } - - return *this; -} - -Bu::ParamProc::ParamProc() -{ -} - -Bu::ParamProc::~ParamProc() -{ - for( Bu::List::iterator i = lArg.begin(); - i != lArg.end(); i++ ) - { - delete *i; - } - - for( Bu::List::iterator i = lBan.begin(); - i != lBan.end(); i++ ) - { - delete *i; - } - -} -/* -void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) -{ - printf("Calling callback...\n"); - val = "Hello there, this is set in the ParamProc"; - (this->*proc)(); -}*/ - -void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, - ParamPtr val, const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - ArgSpec *as = new ArgSpec; - if( lpWord ) - as->sWord = lpWord; - - as->cChar = cChar; - as->proc = proc; - as->val = val; - if( lpDesc ) - as->sDesc = lpDesc; - if( lpExtra ) - as->sExtra = lpExtra; - if( lpValue ) - as->sValue = lpValue; - - lArg.append( as ); - - if( !lBan.isEmpty() ) - { - if( lBan.last()->pBefore == NULL ) - lBan.last()->pBefore = as; - } -} - -void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( char cChar, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( char cChar, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::process( int argc, char *argv[] ) -{ - for( int arg = 1; arg < argc; arg++ ) - { - //printf(":::%d:::%s\n", arg, argv[arg] ); - if( argv[arg][0] == '-' ) - { - if( argv[arg][1] == '-' ) - { - ArgSpec *s = checkWord( argv[arg]+2 ); - if( s ) - { - if( argv[arg][s->sWord.getSize()+2] == '=' ) - { - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - s->val = argv[arg]+s->sWord.getSize()+3; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - char **tmp = new char*[argc-arg]; - tmp[0] = argv[arg]+s->sWord.getSize()+3; - for( int k = 1; k < argc-arg; k++ ) - tmp[k] = argv[arg+k]; - int ret = (this->*s->proc)( argc-arg, tmp ); - if( ret > 0 ) - { - arg += ret-1; - } - delete tmp; - } - } - else - { - int add = 0; - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - if( arg+1 >= argc ) - { - return; - } - s->val = argv[arg+1]; - add++; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - int ret = (this->*s->proc)( - argc-arg-1, argv+arg+1 ); - - if( ret > add ) - add = 0; - else - add -= ret; - arg += ret; - } - arg += add; - } - continue; - } - else - { - unknownParam( argc-arg, argv+arg ); - } - } - else - { - for( int chr = 1; argv[arg][chr]; chr++ ) - { - ArgSpec *s = checkLetr( argv[arg][chr] ); - if( s ) - { - if( argv[arg][chr+1] != '\0' ) - { - bool bUsed = false; - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - s->val = argv[arg]+chr+1; - bUsed = true; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - char **tmp = new char*[argc-arg]; - tmp[0] = argv[arg]+chr+1; - for( int k = 1; k < argc-arg; k++ ) - tmp[k] = argv[arg+k]; - int ret = (this->*s->proc)( argc-arg, tmp ); - if( ret > 0 ) - { - arg += ret - 1; - delete tmp; - break; - } - delete tmp; - } - if( bUsed ) - { - break; - } - } - else - { - bool bUsed = false; - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - s->val = argv[arg+1]; - bUsed = true; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - int ret = (this->*s->proc)( - argc-arg-1, argv+arg+1 - ); - if( ret > 0 ) - { - arg += ret; - break; - } - } - if( bUsed ) - { - arg++; - break; - } - } - } - else - { - unknownParam( argc-arg, argv+arg ); - } - } - } - } - else - { - cmdParam( argc-arg, argv+arg ); - } - } -} - -Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg ) -{ - //printf("Checking \"%s\"...\n", arg ); - Bu::List::const_iterator i = lArg.begin(); - for( ; i != lArg.end(); i++ ) - { - if( (*i)->sWord == "" ) - continue; - - if( !strcmp( (*i)->sWord.getStr(), arg ) ) - return *i; - - if( (*i)->val.isSet() ) - { - if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) && - arg[(*i)->sWord.getSize()] == '=' ) - { - return *i; - } - } - } - - return NULL; -} - -Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg ) -{ - //printf("Checking \'%c\'...\n", arg ); - Bu::List::const_iterator i = lArg.begin(); - for( ; i != lArg.end(); i++ ) - { - if( (*i)->cChar == '\0' ) - continue; - - if( (*i)->cChar == arg ) - { - return *i; - } - } - - return NULL; -} - -int Bu::ParamProc::cmdParam( int /*argc*/, char *argv[] ) -{ - printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); - return 0; -} - -int Bu::ParamProc::unknownParam( int /*argc*/, char *argv[] ) -{ - printf("Unknown parameter \"%s\" found!\n", argv[0] ); - return 0; -} - -int Bu::ParamProc::help( int /*argc*/, char * /*argv*/ [] ) -{ - Bu::List::const_iterator b = lBan.begin(); - Bu::List::const_iterator i = lArg.begin(); - int len=0; - for( ; i != lArg.end(); i++ ) - { - if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() ) - len = (*i)->sWord.getSize() + (*i)->sExtra.getSize(); - } - char fmt[10]; - sprintf( fmt, "%%-%ds ", len ); - - for( i = lArg.begin(); i != lArg.end(); i++ ) - { - if( b != lBan.end() ) - { - if( (*b)->pBefore == (*i) ) - { - printf( (*b)->sBanner.getStr() ); - b++; - } - } - printf(" "); - if( (*i)->cChar ) - { - if( (*i)->sWord.getStr() ) - { - printf("-%c, ", (*i)->cChar ); - } - else - { - printf("-%c ", (*i)->cChar ); - } - } - else - { - printf(" "); - } - if( (*i)->sWord.getStr() ) - { - printf("--"); - Bu::FString sTmp = (*i)->sWord.getStr(); - if( (*i)->sExtra.getStr() ) - sTmp += (*i)->sExtra.getStr(); - printf( fmt, sTmp.getStr() ); - } - else - { - printf(" "); - printf(fmt, "" ); - } - printf("%s\n", (*i)->sDesc.getStr() ); - } - if( b != lBan.end() ) - { - if( (*b)->pBefore == NULL ) - { - printf( (*b)->sBanner.getStr() ); - } - } - - exit( 0 ); -} - -void Bu::ParamProc::addHelpBanner( const char *sHelpBanner ) -{ - Banner *pBan = new Banner; - pBan->sBanner = sHelpBanner; - pBan->pBefore = NULL; - lBan.append( pBan ); -} - diff --git a/src/paramproc.h b/src/paramproc.h deleted file mode 100644 index ddc1876..0000000 --- a/src/paramproc.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_PARAM_PROC_H -#define BU_PARAM_PROC_H - -#include -#include "bu/list.h" -#include "bu/fstring.h" - -namespace Bu -{ - class ParamProc - { - public: - class ParamPtr - { - public: - ParamPtr(); - ParamPtr( Bu::FString *str ); - ParamPtr( uint64_t *uint64 ); - ParamPtr( uint32_t *uint32 ); - ParamPtr( uint16_t *uint16 ); - ParamPtr( uint8_t *uint8 ); - ParamPtr( int64_t *int64 ); - ParamPtr( int32_t *int32 ); - ParamPtr( int16_t *int16 ); - ParamPtr( int8_t *int8 ); - ParamPtr( float *float32 ); - ParamPtr( double *float64 ); - ParamPtr( long double *float96 ); - ParamPtr( bool *bln ); - - enum - { - vtunset, - vtstr, - vtuint64, - vtuint32, - vtuint16, - vtuint8, - vtint64, - vtint32, - vtint16, - vtint8, - vtfloat32, - vtfloat64, - vtfloat96, - vtbln, - }; - ParamPtr &operator=( ParamPtr &ptr ); - ParamPtr &operator=( const char *str ); - - bool isSet(); - - private: - int type; - union - { - Bu::FString *str; - uint64_t *uint64; - uint32_t *uint32; - uint16_t *uint16; - uint8_t *uint8; - int64_t *int64; - int32_t *int32; - int16_t *int16; - int8_t *int8; - float *float32; - double *float64; - long double *float96; - bool *bln; - } val; - }; - - typedef int (ParamProc::*Proc)( int, char *[] ); - - typedef struct ArgSpec - { - uint8_t nFlags; - Bu::FString sWord; - char cChar; - Proc proc; - ParamProc::ParamPtr val; - Bu::FString sExtra; - Bu::FString sDesc; - Bu::FString sValue; - } ArgSpec; - - public: - DEPRECATED - ParamProc(); - virtual ~ParamProc(); - - void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, char cChar, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, char cChar, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void addParam( const char *lpWord, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void addParam( char cChar, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( char cChar, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( char cChar, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void process( int argc, char *argv[] ); - void addHelpBanner( const char *sHelpBanner ); - - private: - ArgSpec *checkWord( const char *arg ); - ArgSpec *checkLetr( const char arg ); - - public: - virtual int cmdParam( int argc, char *argv[] ); - virtual int unknownParam( int argc, char *argv[] ); - virtual int help( int argc, char *argv[] ); - - private: - typedef struct Banner - { - Bu::FString sBanner; - ArgSpec *pBefore; - } Banner; - Bu::List lBan; - Bu::List lArg; - }; -} - -#define mkproc( cls ) static_cast(&cls) - -#endif diff --git a/src/ringbuffer.h b/src/ringbuffer.h index 04add42..f4fd58c 100644 --- a/src/ringbuffer.h +++ b/src/ringbuffer.h @@ -17,6 +17,7 @@ namespace Bu { template class RingBuffer; + /** @cond DEVEL */ template class RingBufferCore { @@ -119,6 +120,7 @@ namespace Bu value *aData; valuealloc va; }; + /** @endcond */ /** *@ingroup Containers diff --git a/src/server.cpp b/src/server.cpp index 51c056a..e701a69 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -8,9 +8,9 @@ #include "bu/server.h" #include #include -#include "bu/serversocket.h" +#include "bu/tcpserversocket.h" #include "bu/client.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include "bu/config.h" Bu::Server::Server() : @@ -28,7 +28,7 @@ Bu::Server::~Server() void Bu::Server::addPort( int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -36,7 +36,7 @@ void Bu::Server::addPort( int nPort, int nPoolSize ) void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -75,7 +75,7 @@ void Bu::Server::scan() { if( hServers.has( j ) ) { - ServerSocket *pSrv = hServers.get( j ); + TcpServerSocket *pSrv = hServers.get( j ); addClient( pSrv->accept(), pSrv->getPort() ); } else @@ -97,7 +97,7 @@ void Bu::Server::scan() { pClient->processOutput(); } - catch( Bu::SocketException &e ) + catch( Bu::TcpSocketException &e ) { closeClient( j ); } @@ -136,7 +136,7 @@ void Bu::Server::addClient( int nSocket, int nPort ) FD_SET( nSocket, &fdActive ); Client *c = new Client( - new Bu::Socket( nSocket ), + new Bu::TcpSocket( nSocket ), new SrvClientLinkFactory() ); hClients.insert( nSocket, c ); diff --git a/src/server.h b/src/server.h index 74ee99a..d6726fd 100644 --- a/src/server.h +++ b/src/server.h @@ -25,8 +25,8 @@ namespace Bu { - class ServerSocket; - class Socket; + class TcpServerSocket; + class TcpSocket; class Client; /** @@ -97,7 +97,7 @@ namespace Bu int nTimeoutSec; int nTimeoutUSec; fd_set fdActive; - typedef Hash SrvHash; + typedef Hash SrvHash; SrvHash hServers; typedef Hash ClientHash; ClientHash hClients; diff --git a/src/serversocket.cpp b/src/serversocket.cpp deleted file mode 100644 index 87d0035..0000000 --- a/src/serversocket.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef WIN32 - #include - #include - #include - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include "bu/serversocket.h" - -#include "bu/config.h" - -namespace Bu { subExceptionDef( ServerSocketException ) } - -Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : - nPort( nPort ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - /* Create the socket and set it up to accept connections. */ - struct sockaddr_in name; - - /* Give the socket a name. */ - name.sin_family = AF_INET; - name.sin_port = bu_htons( nPort ); - - // I think this specifies who we will accept connections from, - // a good thing to make configurable later on - name.sin_addr.s_addr = bu_htonl( INADDR_ANY ); - - startServer( name, nPoolSize ); -} - -Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : - nPort( nPort ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - /* Create the socket and set it up to accept connections. */ - struct sockaddr_in name; - - /* Give the socket a name. */ - name.sin_family = AF_INET; - - name.sin_port = bu_htons( nPort ); - -#ifdef WIN32 - name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() ); -#else - inet_aton( sAddr.getStr(), &name.sin_addr ); -#endif - - startServer( name, nPoolSize ); -} - -Bu::ServerSocket::ServerSocket( int nServer, bool bInit, int nPoolSize ) : - nServer( nServer ), - nPort( 0 ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - if( bInit ) - { - struct sockaddr name; - socklen_t namelen = sizeof(name); - getpeername( nServer, &name, &namelen ); - - initServer( *((sockaddr_in *)&name), nPoolSize ); - } - else - { - FD_ZERO( &fdActive ); - FD_SET( nServer, &fdActive ); - } -} - -Bu::ServerSocket::ServerSocket( const ServerSocket &rSrc ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - nServer = dup( rSrc.nServer ); - nPort = rSrc.nPort; - FD_ZERO( &fdActive ); - FD_SET( nServer, &fdActive ); -} - -Bu::ServerSocket::~ServerSocket() -{ - if( nServer > -1 ) - ::close( nServer ); -} - -void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) -{ - /* Create the socket. */ - nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); - - if( nServer < 0 ) - { - throw Bu::ServerSocketException("Couldn't create a listen socket."); - } - - int opt = 1; - bu_setsockopt( - nServer, - SOL_SOCKET, - SO_REUSEADDR, - (char *)&opt, - sizeof( opt ) - ); - - initServer( name, nPoolSize ); -} - -void Bu::ServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) -{ - if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) - { - throw Bu::ServerSocketException("Couldn't bind to the listen socket."); - } - - if( bu_listen( nServer, nPoolSize ) < 0 ) - { - throw Bu::ServerSocketException( - "Couldn't begin listening to the server socket." - ); - } - - FD_ZERO( &fdActive ); - /* Initialize the set of active sockets. */ - FD_SET( nServer, &fdActive ); -} - -int Bu::ServerSocket::getSocket() -{ - return nServer; -} - -int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) -{ - fd_set fdRead = fdActive; - - struct timeval xT; - - xT.tv_sec = nTimeoutSec; - xT.tv_usec = nTimeoutUSec; - - if( TEMP_FAILURE_RETRY( - bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) - { - throw Bu::ServerSocketException( - "Error scanning for new connections: %s", strerror( errno ) - ); - } - - if( FD_ISSET( nServer, &fdRead ) ) - { - struct sockaddr_in clientname; - socklen_t size; - int nClient; - - size = sizeof( clientname ); -#ifdef WIN32 - nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size); -#else /* not-WIN32 */ -#ifdef __CYGWIN__ - nClient = ::accept( nServer, (struct sockaddr *)&clientname, - (int *)&size - ); -#else /* not-cygwin */ -#ifdef __APPLE__ - nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size ); -#else /* linux */ - nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); -#endif /* __APPLE__ */ -#endif /* __CYGWIN__ */ -#endif /* WIN32 */ - if( nClient < 0 ) - { - throw Bu::ServerSocketException( - "Error accepting a new connection: %s", strerror( errno ) - ); - } - -#ifndef WIN32 - char tmpa[20]; - inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); - //"New connection from host %s, port %hd.", - // tmpa, ntohs (clientname.sin_port) ); -#endif - - { -#ifndef WIN32 - int flags; - flags = fcntl( nClient, F_GETFL, 0 ); - flags |= O_NONBLOCK; - if( fcntl( nClient, F_SETFL, flags ) < 0) - { - throw Bu::ServerSocketException( - "Error setting option on client socket: %s", - strerror( errno ) - ); - } -#else - //------------------------- - // Set the socket I/O mode: In this case FIONBIO - // enables or disables the blocking mode for the - // socket based on the numerical value of iMode. - // If iMode = 0, blocking is enabled; - // If iMode != 0, non-blocking mode is enabled. - u_long iMode = 1; - bu_ioctlsocket(nClient, FIONBIO, &iMode); -#endif - } - - return nClient; - } - - return -1; -} - -int Bu::ServerSocket::getPort() -{ - return nPort; -} - diff --git a/src/serversocket.h b/src/serversocket.h deleted file mode 100644 index ee357a4..0000000 --- a/src/serversocket.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_SERVER_SOCKET_H -#define BU_SERVER_SOCKET_H - -#include -#include "bu/fstring.h" -#include "bu/exceptionbase.h" - -#ifdef WIN32 - #include -#else - #include -#endif - -namespace Bu -{ - subExceptionDecl( ServerSocketException ); - - /** - * A single tcp/ip server socket. When created the server socket will bind - * to the specified interface and port, and immediately begin listening for - * connections. When connections come in they are pooled by the networking - * drivers in the kernel until they are accepted, this means that failure - * to keep space in the connection pool will result in connection refusals. - * - * Although the accept function returns an integral file descriptor, it is - * designed to be used with the Socket class. - * - *@ingroup Serving - */ - class ServerSocket - { - public: - ServerSocket( int nPort, int nPoolSize=40 ); - ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); - ServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); - ServerSocket( const ServerSocket &rSrc ); - virtual ~ServerSocket(); - - int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); - int getSocket(); - int getPort(); - - private: - void startServer( struct sockaddr_in &name, int nPoolSize ); - void initServer( struct sockaddr_in &name, int nPoolSize ); - - fd_set fdActive; -#ifdef WIN32 - unsigned int nServer; -#else - int nServer; -#endif - int nPort; - }; -} - -#endif diff --git a/src/sharedcore.h b/src/sharedcore.h index ac36606..1887ca2 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h @@ -15,6 +15,53 @@ namespace Bu { + /** + * A mechanism for creating classes that perform lazy copies. The concept + * behind this is that instead of copying a large object when it is assigned + * or passed into a copy constructor we simply copy a pointer internally. + * The assumption is that many times when an object is passed by value we + * don't really want to keep the object around, we want the recipient to + * take ownership without allocating a new object. This allows that to + * happen. + * + * When used properly this makes object copying essentially free (O(1), + * that is) and performs the actual copy when a user tries to modify the + * object. + * + * For example, lets look at something like the getKeys function in + * Bu::Hash. When this function is called it creates a Bu::List of + * appropriate type, fills it with keys, and returns it. This is a good + * way for this function to behave, there may be additional issues if the + * List object were allocated with new and not on the stack. However, + * returning the List at the end of the function could potentially take + * a very long time depending on the size of the list and the type of the + * key. In this case the getKeys function doesn't want ownership of the + * List object, and when it returns it, it's local copy will be destroyed. + * + * However, List inherits from SharedCore, which means that when it is + * returned all we do is copy a pointer to the "core" of the list, which + * is a very fast operatorion. For a brief moment, before anyone can do + * anything else, there are two objects referencing the core of that single + * list. However, the getKeys() function will destroy it's local copy + * before the calling function can use it's new copy. That means that by + * the time the calling function can use it's new List of keys it is the + * only one with a reference to the core, and no copy will need to happen. + * + * Using SharedCore on your own classes is fairly straight forward. There + * are only a couple of steps. First, break the class into two classes. + * Move every variable from the original class (generally everything that's + * private) into the new class. Then make the original class inherit from + * SharedCore. The SharedCore template takes 2 parameters, first is the + * class it's inheriting from, second is the new core class. Now, in your + * original class you will have one class variable, a pointer named core. + * All of your original variables will be accessable through core. The next + * step is to access everything you used to through core, and to find + * every function that may change data in the core. At the top of every + * function that may change data you want to call _hardCopy(). + * + * That's more or less it. A more detailed guide will be written soon. + * @todo Write a guide for this. + */ template class SharedCore { diff --git a/src/socket.cpp b/src/socket.cpp deleted file mode 100644 index baf3be3..0000000 --- a/src/socket.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bu/socket.h" - -#include "bu/config.h" - -#ifndef WIN32 - #include - #include - #include - #include -#else - #include -#endif - -#define RBS (1024*2) - -namespace Bu { subExceptionDef( SocketException ) } - -Bu::Socket::Socket( int nSocket ) : - nSocket( nSocket ), - bActive( true ), - bBlocking( true ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - setAddress(); -} - -Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : - nSocket( 0 ), - bActive( false ), - bBlocking( true ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - /* Create the socket. */ - nSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); - - if( nSocket < 0 ) - { - throw ExceptionBase("Couldn't create socket.\n"); - } - - setBlocking( false ); - - /* Connect to the server. */ - //printf("Resolving hostname (%s)...\n", sAddr ); - { - struct addrinfo *pAddr = NULL; - struct addrinfo aiHints; - memset( &aiHints, 0, sizeof(addrinfo) ); - aiHints.ai_flags = AI_CANONNAME; - aiHints.ai_family = AF_INET; - aiHints.ai_socktype = SOCK_STREAM; - char ibuf[10]; - sprintf( ibuf, "%d", nPort ); - - int ret; - if( (ret = bu_getaddrinfo( - sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) - { - close(); - throw Bu::SocketException("Couldn't resolve hostname %s (%s).\n", - sAddr.getStr(), bu_gai_strerror(ret)); - } - - bu_connect( - nSocket, - pAddr->ai_addr, - pAddr->ai_addrlen - ); - - sAddress = pAddr->ai_canonname; - - bu_freeaddrinfo( pAddr ); - } - - bActive = true; - - if( nTimeout > 0 ) - { - fd_set rfds, wfds, efds; - int retval; - - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - FD_ZERO(&wfds); - FD_SET(nSocket, &wfds); - FD_ZERO(&efds); - FD_SET(nSocket, &efds); - - struct timeval tv; - tv.tv_sec = nTimeout; - tv.tv_usec = 0; - - retval = bu_select( nSocket+1, &rfds, &wfds, &efds, &tv ); - - if( retval == 0 ) - { - close(); - throw ExceptionBase("Connection timeout.\n"); - } - read( NULL, 0 ); // See if we can get any errors out of the way early. - } -} - -Bu::Socket::~Socket() -{ - close(); -} - -void Bu::Socket::close() -{ - if( bActive ) - { -#ifndef WIN32 - fsync( nSocket ); -#endif -#ifdef WIN32 - #ifndef SHUT_RDWR - #define SHUT_RDWR (SD_BOTH) - #endif -#endif - bu_shutdown( nSocket, SHUT_RDWR ); - ::close( nSocket ); - } - bActive = false; -} - -size_t Bu::Socket::read( void *pBuf, size_t nBytes ) -{ - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - struct timeval tv = {0, 0}; - if( bu_select( nSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) - { - int iErr = errno; - close(); - throw SocketException( SocketException::cRead, strerror(iErr) ); - } - if( FD_ISSET( nSocket, &rfds ) || bBlocking ) - { - int nRead = TEMP_FAILURE_RETRY( - bu_recv( nSocket, (char *) pBuf, nBytes, 0 ) ); - if( nRead == 0 ) - { - close(); - throw SocketException( SocketException::cClosed, "Socket closed."); - } - if( nRead < 0 ) - { -#ifdef WIN32 - int iWSAError = bu_WSAGetLastError(); - if( iWSAError == WSAEWOULDBLOCK ) - return 0; -#else - if( errno == ENETRESET || errno == ECONNRESET ) - { - close(); - throw SocketException( SocketException::cClosed, - strerror(errno) ); - } - if( errno == EAGAIN ) - return 0; - int iErr = errno; - close(); - throw SocketException( SocketException::cRead, strerror(iErr) ); -#endif - } - return nRead; - } - return 0; -} - -size_t Bu::Socket::read( void *pBuf, size_t nBytes, - uint32_t nSec, uint32_t nUSec ) -{ - struct timeval tv; - size_t nRead = 0; - - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - -#ifdef WIN32 - DWORD dwStart = GetTickCount(); - uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); - DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; -#else - struct timeval nt, ct; - gettimeofday( &nt, NULL ); - nt.tv_sec += nSec; - nt.tv_usec += nUSec; -#endif - - for(;;) - { - tv.tv_sec = nSec; - tv.tv_usec = nUSec; - bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); - nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); - if( nRead >= nBytes ) - break; -#ifdef WIN32 - DWORD dwNow = GetTickCount(); - if( dwNow > dwEnd ) - break; -#else - gettimeofday( &ct, NULL ); - if( (ct.tv_sec > nt.tv_sec) || - (ct.tv_sec == nt.tv_sec && - ct.tv_usec >= nt.tv_usec) ) - break; -#endif - } - return nRead; -} - -size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) -{ -//#ifdef WIN32 - int nWrote = TEMP_FAILURE_RETRY( - bu_send( nSocket, (const char *) pBuf, nBytes, 0 ) ); -//#else -// int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); -//#endif - if( nWrote < 0 ) - { -#ifdef WIN32 - int iWSAError = bu_WSAGetLastError(); - if( iWSAError == WSAEWOULDBLOCK ) - return 0; -#else - if( errno == EAGAIN ) return 0; -#endif - throw SocketException( SocketException::cWrite, strerror(errno) ); - } - return nWrote; -} - -size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) -{ - struct timeval tv; - size_t nWrote = 0; - - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(nSocket, &wfds); - -#ifdef WIN32 - DWORD dwStart = GetTickCount(); - uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); - DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; -#else - struct timeval nt, ct; - gettimeofday( &nt, NULL ); - nt.tv_sec += nSec; - nt.tv_usec += nUSec; -#endif - - for(;;) - { - tv.tv_sec = nSec; - tv.tv_usec = nUSec; - bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); - nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); - if( nWrote >= nBytes ) - break; -#ifdef WIN32 - DWORD dwNow = GetTickCount(); - if( dwNow > dwEnd ) - break; -#else - gettimeofday( &ct, NULL ); - if( (ct.tv_sec > nt.tv_sec) || - (ct.tv_sec == nt.tv_sec && - ct.tv_usec >= nt.tv_usec) ) - break; -#endif - } - return nWrote; -} - -long Bu::Socket::tell() -{ - throw UnsupportedException(); -} - -void Bu::Socket::seek( long ) -{ - throw UnsupportedException(); -} - -void Bu::Socket::setPos( long ) -{ - throw UnsupportedException(); -} - -void Bu::Socket::setPosEnd( long ) -{ - throw UnsupportedException(); -} - -bool Bu::Socket::isEos() -{ - return !bActive; -} - -bool Bu::Socket::canRead() -{ - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - struct timeval tv = { 0, 0 }; - int retval = bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); - if( retval == -1 ) - throw SocketException( - SocketException::cBadRead, - "Bad Read error" - ); - - if( !FD_ISSET( nSocket, &rfds ) ) - return false; - return true; -} - -bool Bu::Socket::canWrite() -{ - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(nSocket, &wfds); - struct timeval tv = { 0, 0 }; - int retval = bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); - if( retval == -1 ) - throw SocketException( - SocketException::cBadRead, - "Bad Read error" - ); - if( !FD_ISSET( nSocket, &wfds ) ) - return false; - return true; -} - -bool Bu::Socket::isReadable() -{ - return true; -} - -bool Bu::Socket::isWritable() -{ - return true; -} - -bool Bu::Socket::isSeekable() -{ - return false; -} - -bool Bu::Socket::isBlocking() -{ -#ifndef WIN32 - return ((fcntl( nSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); -#else - return false; -#endif -} - -void Bu::Socket::setBlocking( bool bBlocking ) -{ - this->bBlocking = bBlocking; -#ifndef WIN32 - if( bBlocking ) - { - fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); - } - else - { - fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) | O_NONBLOCK ); - } -#else - u_long iMode; - if( bBlocking ) - iMode = 0; - else - iMode = 1; - //------------------------- - // Set the socket I/O mode: In this case FIONBIO - // enables or disables the blocking mode for the - // socket based on the numerical value of iMode. - // If iMode = 0, blocking is enabled; - // If iMode != 0, non-blocking mode is enabled. - bu_ioctlsocket(nSocket, FIONBIO, &iMode); -#endif -} - -void Bu::Socket::setSize( long ) -{ -} - -void Bu::Socket::flush() -{ -} - -bool Bu::Socket::isOpen() -{ - return bActive; -} - -void Bu::Socket::setAddress() -{ - struct sockaddr_in addr; - socklen_t len = sizeof(addr); - addr.sin_family = AF_INET; - bu_getpeername( nSocket, (sockaddr *)(&addr), &len ); - sAddress = bu_inet_ntoa( addr.sin_addr ); -} - -Bu::FString Bu::Socket::getAddress() const -{ - return sAddress; -} - -Bu::Socket::operator int() const -{ - return nSocket; -} - diff --git a/src/socket.h b/src/socket.h deleted file mode 100644 index c8f78f0..0000000 --- a/src/socket.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_SOCKET_H -#define BU_SOCKET_H - -#include - -#include "bu/stream.h" -#include "bu/fstring.h" -#include "bu/exceptionbase.h" - -namespace Bu -{ - subExceptionDeclBegin( SocketException ); - enum { - cRead, - cWrite, - cBadRead, - cClosed, - cTimeout - }; - subExceptionDeclEnd(); - - /** - * Network socket stream class. This class provides a mechanism for - * communicating over a network using TCP/IP. It will provide other low - * level protocol and addressing support later on, but for now it's just - * standard STREAM TCP/IP sockets. - * - * Unlike system sockets, these sockets are opened by default in - * non-blocking mode, you can specify your own timeout for opening a socket, - * and a number of non-fatal error messages have been automatically handled - * and treated as standard no-data-available-yet situations on read. - * - * Please note that there is a condition that will occur eventually (at - * least on *nix systems) that will trigger a SIGPIPE condition. This - * will terminate your program immediately unless handled properly. Most - * people doing any connections with Socket will want to put this in their - * program somewhere before they use it: - *@code - #include - ... - ... - ... - sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::Socket - @endcode - * When this is done, Bu::Socket will simply throw a broken pipe exception - * just like every other error condition, allowing your program to handle - * it sanely. - * - *@ingroup Serving - *@ingroup Streams - */ - class Socket : public Stream - { - public: - Socket( int nSocket ); - Socket( const FString &sAddr, int nPort, int nTimeout=30 ); - virtual ~Socket(); - - virtual void close(); - //virtual void read(); - virtual size_t read( void *pBuf, size_t nBytes ); - virtual size_t read( void *pBuf, size_t nBytes, - uint32_t nSec, uint32_t nUSec=0 ); - virtual size_t write( const void *pBuf, size_t nBytes ); - virtual size_t write( const void *pBuf, size_t nBytes, - uint32_t nSec, uint32_t nUSec=0 ); - using Stream::write; - - virtual long tell(); - virtual void seek( long offset ); - virtual void setPos( long pos ); - virtual void setPosEnd( long pos ); - virtual bool isEos(); - virtual bool isOpen(); - - virtual void flush(); - - virtual bool canRead(); - virtual bool canWrite(); - - virtual bool isReadable(); - virtual bool isWritable(); - virtual bool isSeekable(); - - virtual bool isBlocking(); - virtual void setBlocking( bool bBlocking=true ); - - virtual void setSize( long iSize ); - - Bu::FString getAddress() const; - operator int() const; - - private: - void setAddress(); - -#ifdef WIN32 - unsigned int nSocket; -#else - int nSocket; -#endif - bool bActive; - bool bBlocking; - FString sReadBuf; - FString sAddress; - }; -} - -#endif diff --git a/src/tcpserversocket.cpp b/src/tcpserversocket.cpp new file mode 100644 index 0000000..7d7f6e4 --- /dev/null +++ b/src/tcpserversocket.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef WIN32 + #include + #include + #include + #include +#endif + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "bu/tcpserversocket.h" + +#include "bu/config.h" + +namespace Bu { subExceptionDef( TcpServerSocketException ) } + +Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) : + nPort( nPort ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + /* Create the socket and set it up to accept connections. */ + struct sockaddr_in name; + + /* Give the socket a name. */ + name.sin_family = AF_INET; + name.sin_port = bu_htons( nPort ); + + // I think this specifies who we will accept connections from, + // a good thing to make configurable later on + name.sin_addr.s_addr = bu_htonl( INADDR_ANY ); + + startServer( name, nPoolSize ); +} + +Bu::TcpServerSocket::TcpServerSocket(const FString &sAddr,int nPort, int nPoolSize) : + nPort( nPort ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + /* Create the socket and set it up to accept connections. */ + struct sockaddr_in name; + + /* Give the socket a name. */ + name.sin_family = AF_INET; + + name.sin_port = bu_htons( nPort ); + +#ifdef WIN32 + name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() ); +#else + inet_aton( sAddr.getStr(), &name.sin_addr ); +#endif + + startServer( name, nPoolSize ); +} + +Bu::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) : + nServer( nServer ), + nPort( 0 ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + if( bInit ) + { + struct sockaddr name; + socklen_t namelen = sizeof(name); + getpeername( nServer, &name, &namelen ); + + initServer( *((sockaddr_in *)&name), nPoolSize ); + } + else + { + FD_ZERO( &fdActive ); + FD_SET( nServer, &fdActive ); + } +} + +Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + nServer = dup( rSrc.nServer ); + nPort = rSrc.nPort; + FD_ZERO( &fdActive ); + FD_SET( nServer, &fdActive ); +} + +Bu::TcpServerSocket::~TcpServerSocket() +{ + if( nServer > -1 ) + ::close( nServer ); +} + +void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) +{ + /* Create the socket. */ + nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); + + if( nServer < 0 ) + { + throw Bu::TcpServerSocketException("Couldn't create a listen socket."); + } + + int opt = 1; + bu_setsockopt( + nServer, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&opt, + sizeof( opt ) + ); + + initServer( name, nPoolSize ); +} + +void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) +{ + if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) + { + throw Bu::TcpServerSocketException("Couldn't bind to the listen socket."); + } + + if( bu_listen( nServer, nPoolSize ) < 0 ) + { + throw Bu::TcpServerSocketException( + "Couldn't begin listening to the server socket." + ); + } + + FD_ZERO( &fdActive ); + /* Initialize the set of active sockets. */ + FD_SET( nServer, &fdActive ); +} + +int Bu::TcpServerSocket::getSocket() +{ + return nServer; +} + +int Bu::TcpServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) +{ + fd_set fdRead = fdActive; + + struct timeval xT; + + xT.tv_sec = nTimeoutSec; + xT.tv_usec = nTimeoutUSec; + + if( TEMP_FAILURE_RETRY( + bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) + { + throw Bu::TcpServerSocketException( + "Error scanning for new connections: %s", strerror( errno ) + ); + } + + if( FD_ISSET( nServer, &fdRead ) ) + { + struct sockaddr_in clientname; + socklen_t size; + int nClient; + + size = sizeof( clientname ); +#ifdef WIN32 + nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size); +#else /* not-WIN32 */ +#ifdef __CYGWIN__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, + (int *)&size + ); +#else /* not-cygwin */ +#ifdef __APPLE__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size ); +#else /* linux */ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); +#endif /* __APPLE__ */ +#endif /* __CYGWIN__ */ +#endif /* WIN32 */ + if( nClient < 0 ) + { + throw Bu::TcpServerSocketException( + "Error accepting a new connection: %s", strerror( errno ) + ); + } + +#ifndef WIN32 + char tmpa[20]; + inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); + //"New connection from host %s, port %hd.", + // tmpa, ntohs (clientname.sin_port) ); +#endif + + { +#ifndef WIN32 + int flags; + flags = fcntl( nClient, F_GETFL, 0 ); + flags |= O_NONBLOCK; + if( fcntl( nClient, F_SETFL, flags ) < 0) + { + throw Bu::TcpServerSocketException( + "Error setting option on client socket: %s", + strerror( errno ) + ); + } +#else + //------------------------- + // Set the socket I/O mode: In this case FIONBIO + // enables or disables the blocking mode for the + // socket based on the numerical value of iMode. + // If iMode = 0, blocking is enabled; + // If iMode != 0, non-blocking mode is enabled. + u_long iMode = 1; + bu_ioctlsocket(nClient, FIONBIO, &iMode); +#endif + } + + return nClient; + } + + return -1; +} + +int Bu::TcpServerSocket::getPort() +{ + return nPort; +} + diff --git a/src/tcpserversocket.h b/src/tcpserversocket.h new file mode 100644 index 0000000..b1d7e02 --- /dev/null +++ b/src/tcpserversocket.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_TCP_SERVER_SOCKET_H +#define BU_TCP_SERVER_SOCKET_H + +#include +#include "bu/fstring.h" +#include "bu/exceptionbase.h" + +#ifdef WIN32 + #include +#else + #include +#endif + +namespace Bu +{ + subExceptionDecl( TcpServerSocketException ); + + /** + * A single tcp/ip server socket. When created the server socket will bind + * to the specified interface and port, and immediately begin listening for + * connections. When connections come in they are pooled by the networking + * drivers in the kernel until they are accepted, this means that failure + * to keep space in the connection pool will result in connection refusals. + * + * Although the accept function returns an integral file descriptor, it is + * designed to be used with the Socket class. + * + *@ingroup Serving + */ + class TcpServerSocket + { + public: + TcpServerSocket( int nPort, int nPoolSize=40 ); + TcpServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); + TcpServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); + TcpServerSocket( const TcpServerSocket &rSrc ); + virtual ~TcpServerSocket(); + + int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); + int getSocket(); + int getPort(); + + private: + void startServer( struct sockaddr_in &name, int nPoolSize ); + void initServer( struct sockaddr_in &name, int nPoolSize ); + + fd_set fdActive; +#ifdef WIN32 + unsigned int nServer; +#else + int nServer; +#endif + int nPort; + }; +} + +#endif diff --git a/src/tcpsocket.cpp b/src/tcpsocket.cpp new file mode 100644 index 0000000..bbd9cf5 --- /dev/null +++ b/src/tcpsocket.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bu/tcpsocket.h" + +#include "bu/config.h" + +#ifndef WIN32 + #include + #include + #include + #include +#else + #include +#endif + +#define RBS (1024*2) + +namespace Bu { subExceptionDef( TcpSocketException ) } + +Bu::TcpSocket::TcpSocket( int nTcpSocket ) : + nTcpSocket( nTcpSocket ), + bActive( true ), + bBlocking( true ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + setAddress(); +} + +Bu::TcpSocket::TcpSocket( const Bu::FString &sAddr, int nPort, int nTimeout, + bool bBlocking ) : + nTcpSocket( 0 ), + bActive( false ), + bBlocking( true ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + /* Create the socket. */ + nTcpSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); + + if( nTcpSocket < 0 ) + { + throw ExceptionBase("Couldn't create socket.\n"); + } + + setBlocking( false ); + + /* Connect to the server. */ + //printf("Resolving hostname (%s)...\n", sAddr ); + { + struct addrinfo *pAddr = NULL; + struct addrinfo aiHints; + memset( &aiHints, 0, sizeof(addrinfo) ); + aiHints.ai_flags = AI_CANONNAME; + aiHints.ai_family = AF_INET; + aiHints.ai_socktype = SOCK_STREAM; + char ibuf[10]; + sprintf( ibuf, "%d", nPort ); + + int ret; + if( (ret = bu_getaddrinfo( + sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) + { + close(); + throw Bu::TcpSocketException("Couldn't resolve hostname %s (%s).\n", + sAddr.getStr(), bu_gai_strerror(ret)); + } + + bu_connect( + nTcpSocket, + pAddr->ai_addr, + pAddr->ai_addrlen + ); + + sAddress = pAddr->ai_canonname; + + bu_freeaddrinfo( pAddr ); + } + + bActive = true; + + if( nTimeout > 0 ) + { + fd_set rfds, wfds, efds; + int retval; + + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + FD_ZERO(&wfds); + FD_SET(nTcpSocket, &wfds); + FD_ZERO(&efds); + FD_SET(nTcpSocket, &efds); + + struct timeval tv; + tv.tv_sec = nTimeout; + tv.tv_usec = 0; + + retval = bu_select( nTcpSocket+1, &rfds, &wfds, &efds, &tv ); + + if( retval == 0 ) + { + close(); + throw ExceptionBase("Connection timeout.\n"); + } + read( NULL, 0 ); // See if we can get any errors out of the way early. + } + + if( bBlocking ) + setBlocking( bBlocking ); +} + +Bu::TcpSocket::~TcpSocket() +{ + close(); +} + +void Bu::TcpSocket::close() +{ + if( bActive ) + { +#ifndef WIN32 + fsync( nTcpSocket ); +#endif +#ifdef WIN32 + #ifndef SHUT_RDWR + #define SHUT_RDWR (SD_BOTH) + #endif +#endif + bu_shutdown( nTcpSocket, SHUT_RDWR ); + ::close( nTcpSocket ); + } + bActive = false; +} + +size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes ) +{ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + struct timeval tv = {0, 0}; + if( bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) + { + int iErr = errno; + close(); + throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); + } + if( FD_ISSET( nTcpSocket, &rfds ) || bBlocking ) + { + int nRead = TEMP_FAILURE_RETRY( + bu_recv( nTcpSocket, (char *) pBuf, nBytes, 0 ) ); + if( nRead == 0 ) + { + close(); + throw TcpSocketException( TcpSocketException::cClosed, "TcpSocket closed."); + } + if( nRead < 0 ) + { +#ifdef WIN32 + int iWSAError = bu_WSAGetLastError(); + if( iWSAError == WSAEWOULDBLOCK ) + return 0; +#else + if( errno == ENETRESET || errno == ECONNRESET ) + { + close(); + throw TcpSocketException( TcpSocketException::cClosed, + strerror(errno) ); + } + if( errno == EAGAIN ) + return 0; + int iErr = errno; + close(); + throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); +#endif + } + return nRead; + } + return 0; +} + +size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes, + uint32_t nSec, uint32_t nUSec ) +{ + struct timeval tv; + size_t nRead = 0; + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + +#ifdef WIN32 + DWORD dwStart = GetTickCount(); + uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); + DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; +#else + struct timeval nt, ct; + gettimeofday( &nt, NULL ); + nt.tv_sec += nSec; + nt.tv_usec += nUSec; +#endif + + for(;;) + { + tv.tv_sec = nSec; + tv.tv_usec = nUSec; + bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); + nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); + if( nRead >= nBytes ) + break; +#ifdef WIN32 + DWORD dwNow = GetTickCount(); + if( dwNow > dwEnd ) + break; +#else + gettimeofday( &ct, NULL ); + if( (ct.tv_sec > nt.tv_sec) || + (ct.tv_sec == nt.tv_sec && + ct.tv_usec >= nt.tv_usec) ) + break; +#endif + } + return nRead; +} + +size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes ) +{ +//#ifdef WIN32 + int nWrote = TEMP_FAILURE_RETRY( + bu_send( nTcpSocket, (const char *) pBuf, nBytes, 0 ) ); +//#else +// int nWrote = TEMP_FAILURE_RETRY( ::write( nTcpSocket, pBuf, nBytes ) ); +//#endif + if( nWrote < 0 ) + { +#ifdef WIN32 + int iWSAError = bu_WSAGetLastError(); + if( iWSAError == WSAEWOULDBLOCK ) + return 0; +#else + if( errno == EAGAIN ) return 0; +#endif + throw TcpSocketException( TcpSocketException::cWrite, strerror(errno) ); + } + return nWrote; +} + +size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) +{ + struct timeval tv; + size_t nWrote = 0; + + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(nTcpSocket, &wfds); + +#ifdef WIN32 + DWORD dwStart = GetTickCount(); + uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); + DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; +#else + struct timeval nt, ct; + gettimeofday( &nt, NULL ); + nt.tv_sec += nSec; + nt.tv_usec += nUSec; +#endif + + for(;;) + { + tv.tv_sec = nSec; + tv.tv_usec = nUSec; + bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); + nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); + if( nWrote >= nBytes ) + break; +#ifdef WIN32 + DWORD dwNow = GetTickCount(); + if( dwNow > dwEnd ) + break; +#else + gettimeofday( &ct, NULL ); + if( (ct.tv_sec > nt.tv_sec) || + (ct.tv_sec == nt.tv_sec && + ct.tv_usec >= nt.tv_usec) ) + break; +#endif + } + return nWrote; +} + +long Bu::TcpSocket::tell() +{ + throw UnsupportedException(); +} + +void Bu::TcpSocket::seek( long ) +{ + throw UnsupportedException(); +} + +void Bu::TcpSocket::setPos( long ) +{ + throw UnsupportedException(); +} + +void Bu::TcpSocket::setPosEnd( long ) +{ + throw UnsupportedException(); +} + +bool Bu::TcpSocket::isEos() +{ + return !bActive; +} + +bool Bu::TcpSocket::canRead() +{ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + struct timeval tv = { 0, 0 }; + int retval = bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); + if( retval == -1 ) + throw TcpSocketException( + TcpSocketException::cBadRead, + "Bad Read error" + ); + + if( !FD_ISSET( nTcpSocket, &rfds ) ) + return false; + return true; +} + +bool Bu::TcpSocket::canWrite() +{ + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(nTcpSocket, &wfds); + struct timeval tv = { 0, 0 }; + int retval = bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); + if( retval == -1 ) + throw TcpSocketException( + TcpSocketException::cBadRead, + "Bad Read error" + ); + if( !FD_ISSET( nTcpSocket, &wfds ) ) + return false; + return true; +} + +bool Bu::TcpSocket::isReadable() +{ + return true; +} + +bool Bu::TcpSocket::isWritable() +{ + return true; +} + +bool Bu::TcpSocket::isSeekable() +{ + return false; +} + +bool Bu::TcpSocket::isBlocking() +{ +#ifndef WIN32 + return ((fcntl( nTcpSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); +#else + return false; +#endif +} + +void Bu::TcpSocket::setBlocking( bool bBlocking ) +{ + this->bBlocking = bBlocking; +#ifndef WIN32 + if( bBlocking ) + { + fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); + } + else + { + fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) | O_NONBLOCK ); + } +#else + u_long iMode; + if( bBlocking ) + iMode = 0; + else + iMode = 1; + //------------------------- + // Set the socket I/O mode: In this case FIONBIO + // enables or disables the blocking mode for the + // socket based on the numerical value of iMode. + // If iMode = 0, blocking is enabled; + // If iMode != 0, non-blocking mode is enabled. + bu_ioctlsocket(nTcpSocket, FIONBIO, &iMode); +#endif +} + +void Bu::TcpSocket::setSize( long ) +{ +} + +void Bu::TcpSocket::flush() +{ +} + +bool Bu::TcpSocket::isOpen() +{ + return bActive; +} + +void Bu::TcpSocket::setAddress() +{ + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + addr.sin_family = AF_INET; + bu_getpeername( nTcpSocket, (sockaddr *)(&addr), &len ); + sAddress = bu_inet_ntoa( addr.sin_addr ); +} + +Bu::FString Bu::TcpSocket::getAddress() const +{ + return sAddress; +} + +Bu::TcpSocket::operator int() const +{ + return nTcpSocket; +} + diff --git a/src/tcpsocket.h b/src/tcpsocket.h new file mode 100644 index 0000000..3361e84 --- /dev/null +++ b/src/tcpsocket.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_TCP_SOCKET_H +#define BU_TCP_SOCKET_H + +#include + +#include "bu/stream.h" +#include "bu/fstring.h" +#include "bu/exceptionbase.h" + +namespace Bu +{ + subExceptionDeclBegin( TcpSocketException ); + enum { + cRead, + cWrite, + cBadRead, + cClosed, + cTimeout + }; + subExceptionDeclEnd(); + + /** + * Network socket stream class. This class provides a mechanism for + * communicating over a network using TCP/IP. It will provide other low + * level protocol and addressing support later on, but for now it's just + * standard STREAM TCP/IP sockets. + * + * Unlike system sockets, these sockets are opened by default in + * non-blocking mode, you can specify your own timeout for opening a socket, + * and a number of non-fatal error messages have been automatically handled + * and treated as standard no-data-available-yet situations on read. + * + * Please note that there is a condition that will occur eventually (at + * least on *nix systems) that will trigger a SIGPIPE condition. This + * will terminate your program immediately unless handled properly. Most + * people doing any connections with TcpSocket will want to put this in + * their program somewhere before they use it: + *@code + #include + ... + ... + ... + sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::TcpSocket + @endcode + * When this is done, Bu::TcpSocket will simply throw a broken pipe + * exception just like every other error condition, allowing your program + * to handle it sanely. + * + *@ingroup Serving + *@ingroup Streams + */ + class TcpSocket : public Stream + { + public: + TcpSocket( int nTcpSocket ); + TcpSocket( const FString &sAddr, int nPort, int nTimeout=30, + bool bBlocking=true ); + virtual ~TcpSocket(); + + virtual void close(); + //virtual void read(); + virtual size_t read( void *pBuf, size_t nBytes ); + virtual size_t read( void *pBuf, size_t nBytes, + uint32_t nSec, uint32_t nUSec=0 ); + virtual size_t write( const void *pBuf, size_t nBytes ); + virtual size_t write( const void *pBuf, size_t nBytes, + uint32_t nSec, uint32_t nUSec=0 ); + using Stream::write; + + virtual long tell(); + virtual void seek( long offset ); + virtual void setPos( long pos ); + virtual void setPosEnd( long pos ); + virtual bool isEos(); + virtual bool isOpen(); + + virtual void flush(); + + virtual bool canRead(); + virtual bool canWrite(); + + virtual bool isReadable(); + virtual bool isWritable(); + virtual bool isSeekable(); + + virtual bool isBlocking(); + virtual void setBlocking( bool bBlocking=true ); + + virtual void setSize( long iSize ); + + Bu::FString getAddress() const; + operator int() const; + + private: + void setAddress(); + +#ifdef WIN32 + unsigned int nTcpSocket; +#else + int nTcpSocket; +#endif + bool bActive; + bool bBlocking; + FString sReadBuf; + FString sAddress; + }; +} + +#endif diff --git a/src/tests/socket.cpp b/src/tests/socket.cpp deleted file mode 100644 index ba4e9b9..0000000 --- a/src/tests/socket.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include -#include - -#include -#include - -using namespace Bu; - -bool isUp() -{ - try - { - Socket s("xagasoft.com", 9898, 1 ); - - char buf[5]; - buf[s.read(buf, 2, 1, 0)] = '\0'; - - if( !strcmp( buf, "hi" ) ) - return true; - else - return false; - } - catch(...) - { - return false; - } -} - -int main() -{ - uint32_t uUp = 0; - uint32_t uDown = 0; - uint32_t uTotal = 0; - struct timeval tv; - - for(;;) - { - gettimeofday( &tv, NULL ); - time_t goal = ((tv.tv_sec/5)+1)*5; - tv.tv_sec = goal-tv.tv_sec; - tv.tv_usec = 0-tv.tv_usec; - if( tv.tv_usec < 0 ) - { - tv.tv_sec--; - tv.tv_usec = 1000000+tv.tv_usec; - } - select( 0, NULL, NULL, NULL, &tv ); - gettimeofday( &tv, NULL ); - if( isUp() ) - { - uUp++; - sio << "status: up "; - } - else - { - uDown++; - sio << "status: down "; - } - uTotal++; - - sio << "(up=" << (uUp*5) << "s, down=" << (uDown*5) << ") up for " - << uUp*100/uTotal << "% of " << uTotal*5 << "s" << sio.nl - << sio.flush; - } -} - diff --git a/src/tests/socketblock.cpp b/src/tests/socketblock.cpp index a1ea18d..793ef96 100644 --- a/src/tests/socketblock.cpp +++ b/src/tests/socketblock.cpp @@ -6,8 +6,8 @@ */ #include "bu/ito.h" -#include "bu/socket.h" -#include "bu/serversocket.h" +#include "bu/tcpsocket.h" +#include "bu/tcpserversocket.h" #include #include @@ -21,7 +21,7 @@ public: virtual void run() { - Bu::Socket c = s.accept( 45, 0 ); + Bu::TcpSocket c = s.accept( 45, 0 ); printf("TstServer: Accetped connection.\n"); fflush( stdout ); sleep( 1 ); @@ -35,7 +35,7 @@ public: c.close(); } - Bu::ServerSocket s; + Bu::TcpServerSocket s; }; int main() @@ -45,7 +45,7 @@ int main() ts.start(); printf("main: Connecting to server.\n"); fflush( stdout ); - Bu::Socket s( "localhost", 55678 ); + Bu::TcpSocket s( "localhost", 55678 ); printf("main: Sending 4 bytes.\n"); fflush( stdout ); s.write( "aoeu", 4 ); diff --git a/src/tests/socketbreak.cpp b/src/tests/socketbreak.cpp index 8339630..7d3c71a 100644 --- a/src/tests/socketbreak.cpp +++ b/src/tests/socketbreak.cpp @@ -5,17 +5,17 @@ * terms of the license contained in the file LICENSE. */ -#include "bu/serversocket.h" -#include "bu/socket.h" +#include "bu/tcpserversocket.h" +#include "bu/tcpsocket.h" #include int main() { - Bu::ServerSocket sSrv( 9987 ); + Bu::TcpServerSocket sSrv( 9987 ); - Bu::Socket sSend("localhost", 9987 ); + Bu::TcpSocket sSend("localhost", 9987 ); - Bu::Socket sRecv( sSrv.accept() ); + Bu::TcpSocket sRecv( sSrv.accept() ); printf("Connected sockets.\n"); diff --git a/src/tests/tcpsocket.cpp b/src/tests/tcpsocket.cpp new file mode 100644 index 0000000..30dd22f --- /dev/null +++ b/src/tests/tcpsocket.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include +#include + +#include +#include + +using namespace Bu; + +bool isUp() +{ + try + { + TcpSocket s("xagasoft.com", 9898, 1 ); + + char buf[5]; + buf[s.read(buf, 2, 1, 0)] = '\0'; + + if( !strcmp( buf, "hi" ) ) + return true; + else + return false; + } + catch(...) + { + return false; + } +} + +int main() +{ + uint32_t uUp = 0; + uint32_t uDown = 0; + uint32_t uTotal = 0; + struct timeval tv; + + for(;;) + { + gettimeofday( &tv, NULL ); + time_t goal = ((tv.tv_sec/5)+1)*5; + tv.tv_sec = goal-tv.tv_sec; + tv.tv_usec = 0-tv.tv_usec; + if( tv.tv_usec < 0 ) + { + tv.tv_sec--; + tv.tv_usec = 1000000+tv.tv_usec; + } + select( 0, NULL, NULL, NULL, &tv ); + gettimeofday( &tv, NULL ); + if( isUp() ) + { + uUp++; + sio << "status: up "; + } + else + { + uDown++; + sio << "status: down "; + } + uTotal++; + + sio << "(up=" << (uUp*5) << "s, down=" << (uDown*5) << ") up for " + << uUp*100/uTotal << "% of " << uTotal*5 << "s" << sio.nl + << sio.flush; + } +} + diff --git a/src/variant.h b/src/variant.h index 5482ee3..9819f2c 100644 --- a/src/variant.h +++ b/src/variant.h @@ -17,6 +17,7 @@ namespace Bu { class Formatter; class Variant; + /** @cond DEVEL */ template class VariantType; class VariantTypeRoot @@ -92,7 +93,22 @@ namespace Bu private: t data; }; - + /** @endcond */ + + /** + * Store any data type and access it safely. Variant gives you a way to + * pass arbitrary data types around without having to worry about what + * type a variable is. It allows code to be easily extended and to manage + * data without having to know what type it is ahead of time. + * + * Because of the generic method that this class was implemented it may seem + * to have some drawbacks compared to other Variant classes you may have + * seen, however it is fairly easy to get it to do just about anything you + * may need. It is also very low overhead. On most compilers the class + * itself has only 3 words of overhead + the size of the variable you store + * in it. And, since many parts of it are templatized they can often be + * optimized quite a bit. + */ class Variant { public: -- cgit v1.2.3 From 00ecd458ced768b3b8752cdd421a22244b7adc01 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 17 Oct 2010 05:50:57 +0000 Subject: Hey! The parser parses now! It's actually a little stupid, I didn't implement lookahead or precedence, but I should be able to do that easily with the next version. I'm treating this more as a proof of concept than a real working model. Although it can handle +, -, (), and = :) --- src/parser.cpp | 24 +++++++++++--- src/parser.h | 3 ++ src/tools/parser.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index e4e8ae5..3ce73b6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -22,16 +22,25 @@ void Bu::Parser::popLexer() delete sLexer.peekPop(); } +Lexer::Token *Bu::Parser::popToken() +{ + return sToken.peekPop(); +} + +void Bu::Parser::pushToken( Lexer::Token *pTok ) +{ + sToken.push( pTok ); +} + void Bu::Parser::parse() { int iCurNt = iRootNonTerminal; Lexer::Token *ptCur = sLexer.peek()->nextToken(); - sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; + sio << "Token(a): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; selectProduction( iCurNt, ptCur ); while( !sState.isEmpty() ) { - sio << "Currently: " << *sState.peek() << sio.nl; switch( (*sState.peek()).eType ) { case State::typeTerminal: @@ -42,7 +51,7 @@ void Bu::Parser::parse() advanceState(); delete ptCur; ptCur = sLexer.peek()->nextToken(); - sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; + sio << "Token(b): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; } else { @@ -59,7 +68,7 @@ void Bu::Parser::parse() sToken.push( ptCur ); ptCur = sLexer.peek()->nextToken(); - sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; + sio << "Token(c): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; } else { @@ -72,7 +81,7 @@ void Bu::Parser::parse() << (*sState.peek()).iIndex << sio.nl; { int iNt = (*sState.peek()).iIndex; - advanceState(); + sio << "Current state: " << *sState.peek() << sio.nl; if( !selectProduction( iNt, ptCur ) ) { throw Bu::ExceptionBase("Error parsing code."); @@ -132,7 +141,11 @@ bool Bu::Parser::selectProduction( int iNt, Lexer::Token *ptCur ) } } if( nt.bCanSkip ) + { + sio << "Nothing matches, skipping non-terminal." << sio.nl; + advanceState(); return true; + } sio << "-->(Found nothing)" << sio.nl; return false; } @@ -148,6 +161,7 @@ void Bu::Parser::advanceState() sio.decIndent(); sState.pop(); sio << "State advanced, End of production." << sio.nl; + advanceState(); return; } sio << "State advanced, now: " << *(sState.peek()) << sio.nl; diff --git a/src/parser.h b/src/parser.h index 5b5d4a8..1679c7f 100644 --- a/src/parser.h +++ b/src/parser.h @@ -34,6 +34,9 @@ namespace Bu */ void popLexer(); + Lexer::Token *popToken(); + void pushToken( Lexer::Token *pTok ); + /** * Execute a parse. */ diff --git a/src/tools/parser.cpp b/src/tools/parser.cpp index 76d4a72..7933f31 100644 --- a/src/tools/parser.cpp +++ b/src/tools/parser.cpp @@ -151,10 +151,43 @@ private: void redAdd( Bu::Parser &p ) { + Lexer::Token *a = p.popToken(); + Lexer::Token *b = p.popToken(); + + sio << "Add! " << b->vExtra.get() << " + " + << a->vExtra.get() << sio.nl; + + Lexer::Token *c = new Lexer::Token( tokNumber, + b->vExtra.get() + a->vExtra.get() + ); + p.pushToken( c ); + + delete a; + delete b; +} + +void redSubtract( Bu::Parser &p ) +{ + Lexer::Token *a = p.popToken(); + Lexer::Token *b = p.popToken(); + + sio << "Subtract! " << b->vExtra.get() << " - " + << a->vExtra.get() << sio.nl; + + Lexer::Token *c = new Lexer::Token( tokNumber, + b->vExtra.get() - a->vExtra.get() + ); + p.pushToken( c ); + + delete a; + delete b; } void redPrint( Bu::Parser &p ) { + Lexer::Token *a = p.popToken(); + sio << "Print! = " << a->vExtra.get() << sio.nl; + delete a; } /* Basic grammer example: @@ -170,14 +203,15 @@ void redPrint( Bu::Parser &p ) * The problem is, that we can't actually make something left hand recursive, * so we break it into two exprs: * - * expr': '(' expr ')' + * expr-sub1: '(' expr ')' * | NUMBER * ; * - * expr: expr' expr'' + * expr: expr-sub1 expr-sub2 * ; * - * expr'': '+' expr + * expr-sub2: '+' expr + * | '-' expr * | * ; * @@ -191,8 +225,8 @@ int main( int argc, char *argv[] ) Parser p; p.addNonTerminal("expr"); - p.addNonTerminal("expr'"); - p.addNonTerminal("expr''"); + p.addNonTerminal("expr-sub1"); + p.addNonTerminal("expr-sub2"); { Parser::NonTerminal nt; nt.addProduction( @@ -213,12 +247,30 @@ int main( int argc, char *argv[] ) ) ) ); + nt.addProduction( + Parser::Production( + Parser::State( + Parser::State::typeTerminal, + tokMinus + ) + ).append( + Parser::State( + Parser::State::typeNonTerminal, + p.getNonTerminalId("expr") + ) + ).append( + Parser::State( + Parser::State::typeReduction, + p.addReduction("subtract") + ) + ) + ); nt.addProduction( Parser::Production( ) ); nt.setCanSkip(); - p.setNonTerminal("expr''", nt ); + p.setNonTerminal("expr-sub2", nt ); } { Parser::NonTerminal nt; @@ -230,7 +282,25 @@ int main( int argc, char *argv[] ) ) ) ); - p.setNonTerminal("expr'", nt ); + nt.addProduction( + Parser::Production( + Parser::State( + Parser::State::typeTerminal, + tokOpenParen + ) + ).append( + Parser::State( + Parser::State::typeNonTerminal, + p.getNonTerminalId("expr") + ) + ).append( + Parser::State( + Parser::State::typeTerminal, + tokCloseParen + ) + ) + ); + p.setNonTerminal("expr-sub1", nt ); } { Parser::NonTerminal nt; @@ -238,12 +308,12 @@ int main( int argc, char *argv[] ) Parser::Production( Parser::State( Parser::State::typeNonTerminal, - p.getNonTerminalId("expr'") + p.getNonTerminalId("expr-sub1") ) ).append( Parser::State( Parser::State::typeNonTerminal, - p.getNonTerminalId("expr''") + p.getNonTerminalId("expr-sub2") ) ) ); @@ -275,6 +345,7 @@ int main( int argc, char *argv[] ) p.setRootNonTerminal("input"); p.setReduction("add", Bu::slot( &redAdd ) ); + p.setReduction("subtract", Bu::slot( &redSubtract ) ); p.setReduction("print", Bu::slot( &redPrint ) ); p.pushLexer( new MathLexer( fIn ) ); -- cgit v1.2.3 From 78463c30031a478936b21168a6fc93ae6eeaaeb9 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 18 Oct 2010 04:38:19 +0000 Subject: Several of these new files will go away, but I didn't want to lose them for now. The parser works! The parser compiler works! It makes parsers! Now we just have to implement post processing, token lookup tables, and storage. --- bnftest | 18 +++ bnftest.2 | 24 +++ src/lexer.h | 4 + src/parser.cpp | 10 ++ src/parser.h | 2 + src/tools/bnfcompile.cpp | 410 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 468 insertions(+) create mode 100644 bnftest create mode 100644 bnftest.2 create mode 100644 src/tools/bnfcompile.cpp diff --git a/bnftest b/bnftest new file mode 100644 index 0000000..7e61b1a --- /dev/null +++ b/bnftest @@ -0,0 +1,18 @@ +tokens = tokPlus tokMinus tokMult tokDivide tokOpenParen tokCloseParen + tokEquals tokNumber; + +input: input line + | + ; + +line: expr tokEquals {print} + ; + +expr: expr tokPlus expr {add} + | expr tokMinus expr {subtract} + | expr tokMult expr {multiply} + | expr tokDivide expr {divide} + | tokOpenParen expr tokCloseParen + | [tokNumber] + ; + diff --git a/bnftest.2 b/bnftest.2 new file mode 100644 index 0000000..229943b --- /dev/null +++ b/bnftest.2 @@ -0,0 +1,24 @@ +tokens = tokPlus tokMinus tokMult tokDivide tokOpenParen tokCloseParen + tokEquals tokNumber; + +input: line input# + | + ; + +input#: line input# + | + ; + +line: expr tokEquals {print} + ; + +expr: tokOpenParen expr tokCloseParen expr# + | [tokNumber] expr# + ; + +expr#: tokPlus expr {add} expr# + | tokMinus expr {subtract} expr# + | tokMult expr {multiply} expr# + | tokDivide expr {divide} expr# + | + ; diff --git a/src/lexer.h b/src/lexer.h index 2cb5f51..9840afe 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -36,6 +36,10 @@ namespace Bu } TokenType iToken; Bu::Variant vExtra; + int iStartCol; + int iStartRow; + int iEndCol; + int iEndRow; }; virtual Token *nextToken()=0; diff --git a/src/parser.cpp b/src/parser.cpp index 3ce73b6..4ad4ff9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -205,6 +205,11 @@ int Bu::Parser::getNonTerminalId( const Bu::FString &sName ) return hNonTerminalName.get( sName ); } +bool Bu::Parser::hasNonTerminal( const Bu::FString &sName ) +{ + return hNonTerminalName.has( sName ); +} + int Bu::Parser::addReduction( const Bu::FString &sName, const Reduction &r ) { int iId = aReduction.getSize(); @@ -231,6 +236,11 @@ int Bu::Parser::getReductionId( const Bu::FString &sName ) return hReductionName.get( sName ); } +bool Bu::Parser::hasReduction( const Bu::FString &sName ) +{ + return hReductionName.has( sName ); +} + // // Bu::Parser::State // diff --git a/src/parser.h b/src/parser.h index 1679c7f..a925188 100644 --- a/src/parser.h +++ b/src/parser.h @@ -91,11 +91,13 @@ namespace Bu int addNonTerminal( const Bu::FString &sName ); void setNonTerminal( const Bu::FString &sName, NonTerminal &nt ); int getNonTerminalId( const Bu::FString &sName ); + bool hasNonTerminal( const Bu::FString &sName ); int addReduction( const Bu::FString &sName, const Reduction &r ); int addReduction( const Bu::FString &sName ); void setReduction( const Bu::FString &sName, const Reduction &r ); int getReductionId( const Bu::FString &sName ); + bool hasReduction( const Bu::FString &sName ); private: bool selectProduction( int iNt, Lexer::Token *ptCur ); diff --git a/src/tools/bnfcompile.cpp b/src/tools/bnfcompile.cpp new file mode 100644 index 0000000..16e75a5 --- /dev/null +++ b/src/tools/bnfcompile.cpp @@ -0,0 +1,410 @@ +#include +#include +#include +#include +#include + +using namespace Bu; + +enum TokenType +{ + tokIdentifier, + tokColon, + tokOr, + tokSemiColon, + tokTokens, + tokEquals, + tokOpenCurly, + tokCloseCurly, + tokOpenSquare, + tokCloseSquare, + + tokEos=-1 +}; + +class BnfLexer : public Lexer +{ +public: + BnfLexer( Stream &rSrc ) : + rSrc( rSrc ) + { + } + + virtual ~BnfLexer() + { + } + + virtual Token *nextToken() + { + char cBuf; + + for(;;) + { + if( qbIn.getSize() == 0 ) + { + char buf[4096]; + qbIn.write( buf, rSrc.read( buf, 4096 ) ); + + if( rSrc.isEos() && qbIn.getSize() == 0 ) + return new Token( tokEos ); + } + qbIn.peek( &cBuf, 1 ); + if( (cBuf >= 'a' && cBuf <= 'z') || + (cBuf >= 'A' && cBuf <= 'Z') || + (cBuf >= '0' && cBuf <= '9') || + cBuf == '_' ) + { + sBuf.append( cBuf ); + qbIn.seek( 1 ); + } + else if( sBuf.isSet() ) + { + if( sBuf == "tokens" ) + { + sBuf.clear(); + return new Token( tokTokens ); + } + else + { + Token *pRet = new Token( tokIdentifier, sBuf ); + sBuf.clear(); + return pRet; + } + } + else + { + switch( cBuf ) + { + case ' ': + case '\t': + case '\n': + case '\r': + qbIn.seek( 1 ); + continue; + + case ':': + qbIn.seek( 1 ); + return new Token( tokColon ); + + case ';': + qbIn.seek( 1 ); + return new Token( tokSemiColon ); + + case '|': + qbIn.seek( 1 ); + return new Token( tokOr ); + + case '=': + qbIn.seek( 1 ); + return new Token( tokEquals ); + + case '[': + qbIn.seek( 1 ); + return new Token( tokOpenSquare ); + + case ']': + qbIn.seek( 1 ); + return new Token( tokCloseSquare ); + + case '{': + qbIn.seek( 1 ); + return new Token( tokOpenCurly ); + + case '}': + qbIn.seek( 1 ); + return new Token( tokCloseCurly ); + + default: + throw ExceptionBase("Unexpected character '%c'.", + cBuf ); + break; + } + } + } + } + + virtual FString tokenToString( const Token &t ) + { + switch( (TokenType)t.iToken ) + { + case tokIdentifier: return "tokIdentifier"; + case tokColon: return "tokColon"; + case tokOr: return "tokOr"; + case tokSemiColon: return "tokSemiColon"; + case tokTokens: return "tokTokens"; + case tokEquals: return "tokEquals"; + case tokOpenCurly: return "tokOpenCurly"; + case tokCloseCurly: return "tokCloseCurly"; + case tokOpenSquare: return "tokOpenSquare"; + case tokCloseSquare: return "tokCloseSquare"; + case tokEos: return "tokEos"; + } + + return "???"; + } + +private: + Stream &rSrc; + QueueBuf qbIn; + FString sBuf; +}; + +class BnfParser +{ +public: + BnfParser( BnfLexer &l ) : + l( l ), + pCur( NULL ), + iLastToken( 0 ) + { + } + + virtual ~BnfParser() + { + delete pCur; + pCur = NULL; + } + + void parse() + { + for(;;) + { + next(); + switch( pCur->iToken ) + { + case tokTokens: + tokens(); + break; + + case tokIdentifier: + nonTerminal(); + break; + + case tokEos: + return; + break; + + default: + tokenError("tokTokens, tokIdentifier, or tokEos"); + } + } + } + +private: + void tokens() + { + next(); + if( pCur->iToken != tokEquals ) + tokenError("tokEquals"); + for(;;) + { + next(); + if( pCur->iToken == tokIdentifier ) + { + hTokens.insert( pCur->vExtra.get(), ++iLastToken ); + sio << "Added token[" << iLastToken << "]: " + << pCur->vExtra.get() << sio.nl; + } + else if( pCur->iToken == tokSemiColon ) + break; + else + tokenError("tokIdentifier or tokSemiColon"); + } + } + + void nonTerminal() + { + Bu::FString sNtName = pCur->vExtra.get(); + Parser::NonTerminal nt; + p.addNonTerminal( sNtName ); + sio.incIndent(); + sio << "Created non-terminal: " << sNtName << sio.nl; + + next(); + if( pCur->iToken != tokColon ) + tokenError("tokColon"); + production( nt ); + for(;;) + { + switch( pCur->iToken ) + { + case tokOr: + production( nt ); + break; + + case tokSemiColon: + p.setNonTerminal( sNtName, nt ); + sio.decIndent(); + sio << "Closing non-terminal." << sio.nl; + return; + + default: + tokenError("tkOr or tokSemiColon"); + break; + } + } + } + + void production( Parser::NonTerminal &nt ) + { + sio.incIndent(); + sio << "Adding new production:" << sio.nl; + Parser::Production pr; + bool bAnything = false; + for(;;) + { + next(); + switch( pCur->iToken ) + { + case tokIdentifier: + { + const Bu::FString &sName = + pCur->vExtra.get(); + if( hTokens.has( sName ) ) + { + pr.append( + Parser::State( + Parser::State::typeTerminal, + hTokens.get( sName ) + ) + ); + sio << "Added terminal " << sName << sio.nl; + } + else + { + if( !p.hasNonTerminal( sName ) ) + { + p.addNonTerminal( sName ); + } + pr.append( + Parser::State( + Parser::State::typeNonTerminal, + p.getNonTerminalId( sName ) + ) + ); + sio << "Added non-terminal " << sName << sio.nl; + } + } + break; + + case tokOpenSquare: + { + next(); + if( pCur->iToken != tokIdentifier ) + tokenError("tokIdentifier"); + Bu::FString sName = + pCur->vExtra.get(); + next(); + if( pCur->iToken != tokCloseSquare ) + tokenError("tokCloseSquare"); + + if( !hTokens.has( sName ) ) + throw ExceptionBase("Only token names may be " + "enclosed in square brackets."); + + pr.append( + Parser::State( + Parser::State::typeTerminalPush, + hTokens.get( sName ) + ) + ); + sio << "Added terminal-push " << sName << sio.nl; + } + break; + + case tokOpenCurly: + { + next(); + if( pCur->iToken != tokIdentifier ) + tokenError("tokIdentifier"); + Bu::FString sName = + pCur->vExtra.get(); + next(); + if( pCur->iToken != tokCloseCurly ) + tokenError("tokCloseCurly"); + + if( !p.hasReduction( sName ) ) + p.addReduction( sName ); + + pr.append( + Parser::State( + Parser::State::typeReduction, + p.getReductionId( sName ) + ) + ); + sio << "Added reduction " << sName << sio.nl; + } + break; + + case tokOr: + case tokSemiColon: + if( bAnything ) + { + nt.addProduction( pr ); + sio.decIndent(); + sio << "Closing production." << sio.nl; + } + else + { + nt.setCanSkip(); + sio.decIndent(); + sio << "Closing empty production." << sio.nl; + } + return; + + default: + tokenError("tokIdentifier, tokOpenSquare, tokOr, " + "tokOpenCurly, or tokSemiColon"); + } + } + } + +private: + void next() + { + delete pCur; + pCur = l.nextToken(); + } + + void tokenError( const FString &s ) + { + throw ExceptionBase( ("Expected " + s + " but found " + + l.tokenToString( *pCur ) + ".").getStr() ); + } + +private: + typedef Bu::Hash TokenHash; + TokenHash hTokens; + BnfLexer &l; + BnfLexer::Token *pCur; + int iLastToken; + Parser p; +}; + +int main( int argc, char *argv[] ) +{ + File fIn( argv[1], File::Read ); + + BnfLexer bl( fIn ); + BnfParser parser( bl ); + + parser.parse(); + +/* + for(;;) + { + Lexer::Token *pTok = bl.nextToken(); + sio << bl.tokenToString(*pTok); + if( pTok->vExtra.isSet() ) + { + sio << " - " << pTok->vExtra; + } + sio << sio.nl; + if( pTok->iToken == tokEos ) + break; + } +*/ + + return 0; +} + -- cgit v1.2.3 From 2fe32ba19571ff775a55f61eca355a46f269393e Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 4 Nov 2010 19:48:53 +0000 Subject: FString tests, the new one causes a segfault with the old fstring. --- src/unit/fstring.unit | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit index 00b6eed..c6d7414 100644 --- a/src/unit/fstring.unit +++ b/src/unit/fstring.unit @@ -339,4 +339,13 @@ suite FString a = "This is a test."; unitTest( a.replace("i", "ooo") == "Thooos ooos a test." ); } + + test coreDerefBug1 + { + Bu::FString a, b; + a = "bob"; + a.setSize( 0 ); + b = a; + b.getStr(); + } } -- cgit v1.2.3 From 7c335ede527eaf4a3053ef35b1299141d34aaf40 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 19 Nov 2010 05:54:14 +0000 Subject: I now think that this may not work out at all. It looks like if we want proper Unicode handling we'll need to implement a series of codecs and converters as well as tables of codepages and lookups. It'll be interesting, I guess, but it makes me care a lot less about proper encoding. Anyway, UtfString uses shorts instead of chars, so it's a step in the right direction, but still not enough to be able to handle proper UTF-16 encoding, maybe UCS-2 encoding, but... ...that's lame. Bu::FBasicString has been generalized a bit with optimizations from libc for char based strings. It also, unfortunately, still uses char-only functions in several places, those all rely on char casting strings at the moment just to get the thing to compile. Basically, it's not a good UTF-16 solution yet, and it may never be and remain compatible with char based strings. --- src/fbasicstring.h | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- src/utfstring.cpp | 29 +++++++++++++++++++++++++++++ src/utfstring.h | 24 ++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 src/utfstring.cpp create mode 100644 src/utfstring.h diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 7167f4a..af11bb2 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -39,6 +39,42 @@ namespace Bu template< typename chr, int nMinSize, typename chralloc, typename chunkalloc> class FBasicString; + template + size_t strlen( const chr *pData ) + { + for( size_t tLen = 0;; ++tLen ) + { + if( pData[tLen] == (chr)0 ) + return tLen; + } + return -1; + } + + template + size_t strlen( const char *pData ) + { + return ::strlen( pData ); + } + + template + int strncmp( const chr *a, const chr *b, size_t iLen ) + { + for( size_t iPos = 0; iPos < iLen; iPos++ ) + { + if( a[iPos] != b[iPos] ) + { + return a[iPos]-b[iPos]; + } + } + return 0; + } + + template + int strncmp( const char *a, const char *b, size_t iLen ) + { + return ::strncmp( a, b, iLen ); + } + template struct FStringCore { @@ -1044,7 +1080,7 @@ namespace Bu */ void insert( long nPos, const chr *pData ) { - insert( nPos, pData, strlen( pData ) ); + insert( nPos, pData, Bu::strlen( pData ) ); } void remove( long nPos, long nLen ) @@ -1170,13 +1206,13 @@ namespace Bu if( iStart < 0 ) iStart = 0; if( iStart >= core->nLength ) - return ""; + return (const chr[]){(chr)0}; if( iSize < 0 ) iSize = core->nLength; if( iStart+iSize > core->nLength ) iSize = core->nLength-iStart; if( iSize == 0 ) - return ""; + return (const chr[]){(chr)0}; flatten(); MyType ret( core->pFirst->pData+iStart, iSize ); @@ -1438,11 +1474,11 @@ namespace Bu wordexp_t result; /* Expand the string for the program to run. */ - switch (wordexp (core->pFirst->pData, &result, 0)) + switch (wordexp ((char *)core->pFirst->pData, &result, 0)) { case 0: /* Successful. */ { - set( result.we_wordv[0] ); + set( (chr *)result.we_wordv[0] ); wordfree( &result ); return; } @@ -1954,7 +1990,7 @@ namespace Bu long iLen = vsnprintf( NULL, 0, sFrmt, ap ); Chunk *pNew = core->newChunk( iLen ); - vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); + vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); core->appendChunk( pNew ); va_end( ap ); @@ -1971,7 +2007,7 @@ namespace Bu long iLen = vsnprintf( NULL, 0, sFrmt, ap ); Chunk *pNew = core->newChunk( iLen ); - vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); + vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); core->appendChunk( pNew ); va_end( ap ); @@ -1988,7 +2024,7 @@ namespace Bu long iLen = vsnprintf( NULL, 0, sFrmt, ap ); Chunk *pNew = core->newChunk( iLen ); - vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); + vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); core->prependChunk( pNew ); va_end( ap ); diff --git a/src/utfstring.cpp b/src/utfstring.cpp new file mode 100644 index 0000000..ae5efaf --- /dev/null +++ b/src/utfstring.cpp @@ -0,0 +1,29 @@ +#include "bu/utfstring.h" + +template class Bu::FBasicString; + +template<> uint32_t Bu::__calcHashCode( const Bu::UtfString &k ) +{ + long j, sz = k.getSize()*2; + const char *s = (const char *)k.getStr(); + + long nPos = 0; + for( j = 0; j < sz; j++, s++ ) + { + nPos = *s + (nPos << 6) + (nPos << 16) - nPos; + } + + return nPos; +} + +template<> bool Bu::__cmpHashKeys( + const Bu::UtfString &a, const Bu::UtfString &b ) +{ + return a == b; +} + +template<> void Bu::__tracer_format( const Bu::UtfString &v ) +{ + printf("(%ld)\"%s\"", v.getSize(), (const char *)v.getStr() ); +} + diff --git a/src/utfstring.h b/src/utfstring.h new file mode 100644 index 0000000..bbacb74 --- /dev/null +++ b/src/utfstring.h @@ -0,0 +1,24 @@ +#ifndef BU_UTF_STRING_H +#define BU_UTF_STRING_H + +#include "bu/fbasicstring.h" + +namespace Bu +{ + typedef FBasicString UtfString; + + template + uint32_t __calcHashCode( const T &k ); + + template + bool __cmpHashKeys( const T &a, const T &b ); + + template<> uint32_t __calcHashCode( const UtfString &k ); + template<> bool __cmpHashKeys( + const UtfString &a, const UtfString &b ); + + template void __tracer_format( const t &v ); + template<> void __tracer_format( const UtfString &v ); +} + +#endif -- cgit v1.2.3 From d013208dd0cbd42b4f46279772d02ec85c47735f Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 19 Nov 2010 16:48:23 +0000 Subject: Wow, I can't believe I forgot to add myriadfs. --- src/myriadfs.cpp | 10 ++++++++++ src/myriadfs.h | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/myriadfs.cpp create mode 100644 src/myriadfs.h diff --git a/src/myriadfs.cpp b/src/myriadfs.cpp new file mode 100644 index 0000000..bb72cd5 --- /dev/null +++ b/src/myriadfs.cpp @@ -0,0 +1,10 @@ +#include "myriadfs.h" + +Bu::MyriadFs::MyriadFs() +{ +} + +Bu::MyriadFs::~MyriadFs() +{ +} + diff --git a/src/myriadfs.h b/src/myriadfs.h new file mode 100644 index 0000000..687584b --- /dev/null +++ b/src/myriadfs.h @@ -0,0 +1,38 @@ +#ifndef MYRIAD_FS_H +#define MYRIAD_FS_H + +namespace Bu +{ + /** + * A POSIX compliant, node based filesystem built on top of Myriad. + * + * Header format: + * int32_t iMagicHeader + * int8_t iVersion (1) + * int32_t iNodeSize + * int32_t iNumNodes + * NodeLookup[iNumNodes] nNode + * + * Node lookup: + * int32_t iInode + * int32_t iPosition + * + * Basic node header format: + * int32_t iUser + * int32_t iGroup + * int16_t iMeta + * int16_t iPerms + * int32_t iStreamIndex + * int32_t iParentNode + * int16_t iNameSize + * char[iNameSize] sName + */ + class MyriadFs + { + public: + MyriadFs(); + virtual ~MyriadFs(); + }; +}; + +#endif -- cgit v1.2.3 From 2545d1f2a82bc7c23abc0034958b169f9fffe613 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 19 Nov 2010 23:48:03 +0000 Subject: MyriadFs is starting out...but the FUSE system is...akward at best. --- default.bld | 16 +++++++++++ src/file.cpp | 1 - src/myriad.h | 2 +- src/myriadfs.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/myriadfs.h | 20 ++++++++++++-- src/tools/myriadfs.cpp | 38 ++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 src/tools/myriadfs.cpp diff --git a/default.bld b/default.bld index 857e988..50baefb 100644 --- a/default.bld +++ b/default.bld @@ -81,6 +81,22 @@ target "viewcsv" LDFLAGS += "-lncurses"; } +// +// This shouldn't be. Basically, if you set a property on a top level target +// that has children it seems like the items should apply to the children. +// I'm honestly not 100% sure what the policy should be yet, but this seems like +// I shouldn't have to do it this way. +// +target "src/tools/myriadfs.o" +{ + CXXFLAGS += "-D_FILE_OFFSET_BITS=64"; +} + +target "myriadfs" +{ + LDFLAGS += "-lfuse"; +} + // // General Tests // diff --git a/src/file.cpp b/src/file.cpp index 0566ee8..008b88e 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -11,7 +11,6 @@ #include #include #include -#include // for mkstemp #include #include "bu/config.h" diff --git a/src/myriad.h b/src/myriad.h index 79c3cda..ed0ef53 100644 --- a/src/myriad.h +++ b/src/myriad.h @@ -46,7 +46,7 @@ namespace Bu * Header format is as follows: * * MMMMvBssssSSSS* - * M = Magic number (FFC399BD) + * M = Magic number (0AD3FA84) * v = version number * B = Bits per int * s = Blocksize in bytes diff --git a/src/myriadfs.cpp b/src/myriadfs.cpp index bb72cd5..af60c08 100644 --- a/src/myriadfs.cpp +++ b/src/myriadfs.cpp @@ -1,7 +1,75 @@ -#include "myriadfs.h" +#include "bu/myriadfs.h" +#include "bu/myriadstream.h" -Bu::MyriadFs::MyriadFs() +#include +#include + +namespace Bu { subExceptionDef( MyriadFsException ) } + +#define Myriad_Fs_MAGIC_CODE ((char *)"\xa7\x18\x8b\x39") + +Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : + rStore( rStore ), + mStore( rStore, iBlockSize ) { + if( mStore.hasStream( 1 ) ) + { + // Check to see if this is a MyriadFs stream. + Bu::MyriadStream ms = mStore.openStream( 1 ); + char sMagic[4]; + if( ms.read( sMagic, 4 ) < 4 ) + throw MyriadFsException("The provided stream does not appear to be " + "a MyriadFs stream."); + if( ::strncmp( sMagic, Myriad_Fs_MAGIC_CODE, 4 ) ) + throw MyriadFsException("The provided stream does not appear to be " + "a MyriadFs stream."); + + int8_t iVer; + } + else + { + // Create initial header stream + { + mStore.createStream( 1 ); + Bu::MyriadStream ms = mStore.openStream( 1 ); + ms.write( Myriad_Fs_MAGIC_CODE, 4 ); + int8_t iVer = 1; + int32_t iTmp = 1; + ms.write( &iVer, 1 ); + ms.write( &iBlockSize, 4 ); + ms.write( &iTmp, 4 ); // iNumNodes + iTmp = 0; + ms.write( &iTmp, 4 ); // iInode + ms.write( &iTmp, 0 ); // iPosition + } + + // Create initial inode stream, with one root node. + { + mStore.createStream( 2 ); + Bu::MyriadStream ms = mStore.openStream( 2 ); + int32_t iUser = 0, iGroup = 0; +#ifndef WIN32 + iUser = getuid(); + iGroup = getgid(); +#endif + int32_t iTmp32 = 0; + int16_t iTmp16 = 0; + ms.write( &iUser, 4 ); + ms.write( &iGroup, 4 ); + ms.write( &iTmp16, 2 ); + ms.write( &iTmp16, 2 ); + iTmp32 = 3; + ms.write( &iTmp32, 4 ); + iTmp32 = 0; + ms.write( &iTmp32, 4 ); + ms.write( &iTmp16, 2 ); + } + + // Create inode 0's storage stream. + { + mStore.createStream( 3 ); + } + } } Bu::MyriadFs::~MyriadFs() diff --git a/src/myriadfs.h b/src/myriadfs.h index 687584b..42a3493 100644 --- a/src/myriadfs.h +++ b/src/myriadfs.h @@ -1,13 +1,20 @@ #ifndef MYRIAD_FS_H #define MYRIAD_FS_H +#include "bu/myriad.h" + namespace Bu { + class Stream; + + subExceptionDecl( MyriadFsException ); + /** * A POSIX compliant, node based filesystem built on top of Myriad. * + * A header is placed into stream 1. * Header format: - * int32_t iMagicHeader + * int32_t iMagicHeader (A7188B39) * int8_t iVersion (1) * int32_t iNodeSize * int32_t iNumNodes @@ -17,6 +24,11 @@ namespace Bu * int32_t iInode * int32_t iPosition * + * The node headers or inode structures have a base size of 22 bytes. + * Everything else in the block is used for the name. I.e. if you have + * a blocksize of 512 bytes then you wind up with a max name size of + * 512-22=490 characters, or a blocksize of 256 gives you 234 chraacters + * as a max. The node headers are all stored in stream 2. * Basic node header format: * int32_t iUser * int32_t iGroup @@ -30,8 +42,12 @@ namespace Bu class MyriadFs { public: - MyriadFs(); + MyriadFs( Bu::Stream &rStore, int iBlockSize=512 ); virtual ~MyriadFs(); + + private: + Bu::Stream &rStore; + Bu::Myriad mStore; }; }; diff --git a/src/tools/myriadfs.cpp b/src/tools/myriadfs.cpp new file mode 100644 index 0000000..66955a5 --- /dev/null +++ b/src/tools/myriadfs.cpp @@ -0,0 +1,38 @@ +#define FUSE_USE_VERSION 26 + +#include + +#include + +extern "C" { + static int myriadfs_getattr( const char *sPath, struct stat *stbuf ) + { + + } + + static int myriadfs_readdir( const char *sPath, void *buf, + fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi ) + { + } + + static int myriadfs_open( const char *sPath, struct fuse_file_info *fi ) + { + } + + static int myriadfs_read( const char *sPath, char *buf, size_t iSize, + off_t iOffset, struct fuse_file_info *fi ) + { + } + + static struct fuse_operations myriadfs_oper; + + int main( int argc, char *argv[] ) + { + memset( &myriadfs_oper, sizeof(myriadfs_oper), 0 ); + myriadfs_oper.getattr = myriadfs_getattr; + myriadfs_oper.readdir = myriadfs_readdir; + myriadfs_oper.open = myriadfs_open; + myriadfs_oper.read = myriadfs_read; + return fuse_main( argc, argv, &myriadfs_oper, NULL ); + } +} -- cgit v1.2.3 From 9f3d53ebab425f49a554d8be8b8896bd11465447 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 6 Jan 2011 23:40:32 +0000 Subject: This may be about it for updates to core, I can't think of anything else I need to do right now. This commit contains minor fixes to the cache stores so they don't generate any warnings, and the hashtable includes == and != operators now. --- src/cachestorefiles.h | 2 +- src/cachestoremyriad.h | 2 +- src/hash.h | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/cachestorefiles.h b/src/cachestorefiles.h index 1906b13..c2cf091 100644 --- a/src/cachestorefiles.h +++ b/src/cachestorefiles.h @@ -83,7 +83,7 @@ namespace Bu } } - virtual void unload( obtype *pObj, const keytype &key ) + virtual void unload( obtype *pObj, const keytype & ) { delete pObj; } diff --git a/src/cachestoremyriad.h b/src/cachestoremyriad.h index b90793d..21c84e6 100644 --- a/src/cachestoremyriad.h +++ b/src/cachestoremyriad.h @@ -85,7 +85,7 @@ namespace Bu return pOb; } - virtual void unload( obtype *pObj, const keytype &key ) + virtual void unload( obtype *pObj, const keytype & ) { delete pObj; } diff --git a/src/hash.h b/src/hash.h index d251c46..354569e 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1148,6 +1148,47 @@ namespace Bu return lValues; } + bool operator==( const MyType &rhs ) const + { + if( this == &rhs ) + return true; + if( core == rhs.core ) + return true; + if( core == NULL || rhs.core == NULL ) + return false; + if( getSize() != rhs.getSize() ) + return false; + + for( uint32_t j = 0; j < core->nCapacity; j++ ) + { + if( core->isFilled( j ) ) + { + if( !core->isDeleted( j ) ) + { + // Check to see if this key is in the other hash + if( rhs.has( core->aKeys[j] ) ) + { + if( !(core->aValues[j] == rhs.get( core->aKeys[j]) ) ) + { + return false; + } + } + else + { + return false; + } + } + } + } + + return true; + } + + bool operator!=( const MyType &rhs ) const + { + return !(*this == rhs); + } + protected: virtual Core *_copyCore( Core *src ) { -- cgit v1.2.3 From 55cb78b785360bb349e6a60e965dfd4dd2058597 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 10 Jan 2011 09:27:15 +0000 Subject: Tweaking the fstring, almost done. --- src/fbasicstring.h | 119 ++++++++++++++++++++--------------------------------- 1 file changed, 44 insertions(+), 75 deletions(-) diff --git a/src/fbasicstring.h b/src/fbasicstring.h index af11bb2..9378c1c 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -236,44 +236,8 @@ namespace Bu using SharedCore::core; using SharedCore::_hardCopy; - public: - FBasicString() - { - } - - FBasicString( const chr *pData ) - { - append( pData ); - } - - FBasicString( const chr *pData, long nLength ) - { - append( pData, nLength ); - } - - FBasicString( const MyType &rSrc ) : - SharedCore( rSrc ) - { - } - - FBasicString( const MyType &rSrc, long nLength ) - { - append( rSrc, nLength ); - } - - FBasicString( const MyType &rSrc, long nStart, long nLength ) - { - append( rSrc, nStart, nLength ); - } - - FBasicString( long nSize ) - { - core->pFirst = core->pLast = core->newChunk( nSize ); - core->nLength = nSize; - } - - struct iterator; - struct const_iterator + public: // Iterators + typedef struct const_iterator { friend class FBasicString; friend struct iterator; @@ -505,7 +469,7 @@ namespace Bu } return const_iterator( NULL, 0 ); } - }; + } const_iterator; typedef struct iterator { @@ -753,11 +717,41 @@ namespace Bu } } iterator; - typedef struct const_iterator const_iterator; + public: + FBasicString() + { + } + + FBasicString( const chr *pData ) + { + append( pData ); + } + + FBasicString( const chr *pData, long nLength ) + { + append( pData, nLength ); + } + + FBasicString( const MyType &rSrc ) : + SharedCore( rSrc ) + { + } - //typedef chr *iterator; -// typedef const chr *const_iterator; - // typedef iterator const_iterator; + FBasicString( const MyType &rSrc, long nLength ) + { + append( rSrc, nLength ); + } + + FBasicString( const MyType &rSrc, long nStart, long nLength ) + { + append( rSrc, nStart, nLength ); + } + + FBasicString( long nSize ) + { + core->pFirst = core->pLast = core->newChunk( nSize ); + core->nLength = nSize; + } FBasicString( const const_iterator &s ) { @@ -784,7 +778,13 @@ namespace Bu for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } if( nLen == 0 ) return; - + + if( core->pLast->nLength < nMinSize ) + { + // Put things here, good things + // yeah...spare space block mapping + } + Chunk *pNew = core->newChunk( nLen ); cpy( pNew->pData, pData, nLen ); @@ -1263,37 +1263,6 @@ namespace Bu } } - /** - * (std::string compatability) Get a pointer to the string array. - *@returns (chr *) The string data. - */ - DEPRECATED - chr *c_str() - { - if( core->pFirst == NULL ) - return NULL; - - flatten(); - _hardCopy(); - core->pFirst->pData[core->nLength] = (chr)0; - return core->pFirst->pData; - } - - /** - * (std::string compatability) Get a const pointer to the string array. - *@returns (const chr *) The string data. - */ - DEPRECATED - const chr *c_str() const - { - if( core->pFirst == NULL ) - return NULL; - - flatten(); - core->pFirst->pData[core->nLength] = (chr)0; - return core->pFirst->pData; - } - Bu::List split( const chr c ) const { Bu::List ret; -- cgit v1.2.3 From 3611f253f6fdfa4954d374ab85ddaa7f799c130c Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 10 Jan 2011 20:49:22 +0000 Subject: The FString is much more optimized, and hopefully still works accurately. --- src/fbasicstring.h | 63 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 9378c1c..bf43502 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -237,6 +237,7 @@ namespace Bu using SharedCore::_hardCopy; public: // Iterators + struct iterator; typedef struct const_iterator { friend class FBasicString; @@ -258,7 +259,7 @@ namespace Bu { } - const_iterator( const iterator &i ) : + const_iterator( const struct iterator &i ) : pChunk( i.pChunk ), iPos( i.iPos ) { @@ -776,20 +777,8 @@ namespace Bu if( !pData ) return; long nLen; for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } - if( nLen == 0 ) - return; - - if( core->pLast->nLength < nMinSize ) - { - // Put things here, good things - // yeah...spare space block mapping - } - Chunk *pNew = core->newChunk( nLen ); - cpy( pNew->pData, pData, nLen ); - - _hardCopy(); - core->appendChunk( pNew ); + append( pData, 0, nLen ); } /** @@ -799,15 +788,7 @@ namespace Bu */ void append( const chr *pData, long nLen ) { - if( nLen == 0 ) - return; - - Chunk *pNew = core->newChunk( nLen ); - - cpy( pNew->pData, pData, nLen ); - - _hardCopy(); - core->appendChunk( pNew ); + append( pData, 0, nLen ); } /** @@ -818,15 +799,37 @@ namespace Bu */ void append( const chr *pData, long nStart, long nLen ) { - if( nLen == 0 ) + if( !pData ) return; + if( nLen <= 0 ) return; - Chunk *pNew = core->newChunk( nLen ); - - cpy( pNew->pData, pData+nStart, nLen ); + pData += nStart; _hardCopy(); - core->appendChunk( pNew ); + + if( core->pLast && core->pLast->nLength < nMinSize ) + { + int nAmnt = nMinSize - core->pLast->nLength; + if( nAmnt > nLen ) + nAmnt = nLen; + cpy( + core->pLast->pData+core->pLast->nLength, + pData, + nAmnt + ); + pData += nAmnt; + core->pLast->nLength += nAmnt; + nLen -= nAmnt; + core->nLength += nAmnt; + } + + if( nLen > 0 ) + { + Chunk *pNew = core->newChunk( nLen ); + cpy( pNew->pData, pData, nLen ); + core->appendChunk( pNew ); +// core->nLength += nLen; + } } /** @@ -855,7 +858,7 @@ namespace Bu */ void append( const MyType & sData ) { - append( sData.getStr(), sData.getSize() ); + append( sData.getStr(), 0, sData.getSize() ); } /** @@ -866,7 +869,7 @@ namespace Bu */ void append( const MyType & sData, long nLen ) { - append( sData.getStr(), nLen ); + append( sData.getStr(), 0, nLen ); } /** -- cgit v1.2.3