From 366a8063730aa7ae696bcb9cf56eafd13d43dfc0 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 8 Feb 2009 00:44:10 +0000 Subject: So many updates. I recommend using the new FString iterators instead of direct indexing. It is now many times faster, and requires less overhead. Also, more stuff iterator related in every class. More on that later. --- src/array.h | 28 +- src/fbasicstring.h | 720 ++++++++++++++++++++++++++++++++++++++++++++++---- src/hash.h | 35 ++- src/list.h | 20 ++ src/minimacro.cpp | 2 +- src/set.h | 33 ++- src/tafwriter.cpp | 5 +- src/tests/rh.cpp | 52 ---- src/tests/url.cpp | 32 +++ src/unit/fstring.unit | 155 +++++++++++ src/unitsuite.cpp | 2 +- src/url.cpp | 237 +++++++++++++++++ src/url.h | 74 ++++++ 13 files changed, 1280 insertions(+), 115 deletions(-) delete mode 100644 src/tests/rh.cpp create mode 100644 src/tests/url.cpp create mode 100644 src/url.cpp create mode 100644 src/url.h diff --git a/src/array.h b/src/array.h index 0fb0df3..e717fd5 100644 --- a/src/array.h +++ b/src/array.h @@ -219,12 +219,12 @@ namespace Bu return *this; } - bool operator==( const iterator &oth ) + bool operator==( const iterator &oth ) const { return iPos == oth.iPos; } - bool operator!=( const iterator &oth ) + bool operator!=( const iterator &oth ) const { return iPos != oth.iPos; } @@ -244,6 +244,16 @@ namespace Bu "Cannot dereference finished iterator."); return src[iPos]; } + + operator bool() const + { + return iPos < 0; + } + + bool isValid() const + { + return iPos < 0; + } } iterator; typedef struct const_iterator @@ -302,12 +312,12 @@ namespace Bu return *this; } - bool operator==( const const_iterator &oth ) + bool operator==( const const_iterator &oth ) const { return iPos == oth.iPos; } - bool operator!=( const const_iterator &oth ) + bool operator!=( const const_iterator &oth ) const { return iPos != oth.iPos; } @@ -327,6 +337,16 @@ namespace Bu "Cannot dereference finished iterator."); return src[iPos]; } + + operator bool() const + { + return iPos < 0; + } + + bool isValid() const + { + return iPos < 0; + } } const_iterator; iterator begin() diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 669784b..8303b5a 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -122,16 +122,487 @@ namespace Bu { pFirst = pLast = newChunk( nSize ); } + + struct iterator; + typedef struct const_iterator + { + friend class FBasicString; + private: + const_iterator( Chunk *pChunk, int iPos ) : + pChunk( pChunk ), + iPos( iPos ) + { + } + + Chunk *pChunk; + int iPos; + + public: + const_iterator( const const_iterator &i ) : + pChunk( i.pChunk ), + iPos( i.iPos ) + { + } + + const_iterator( const iterator &i ) : + pChunk( i.pChunk ), + iPos( i.iPos ) + { + } + + bool operator==( const const_iterator &i ) const + { + return pChunk == i.pChunk && iPos == i.iPos; + } + + bool operator!=( const const_iterator &i ) const + { + return !(*this == i); + } + + const_iterator &operator=( const const_iterator &i ) + { + pChunk = i.pChunk; + iPos = i.iPos; + return *this; + } + + const_iterator &operator++() + { + if( !pChunk ) return *this; + iPos++; + if( iPos >= pChunk->nLength ) + { + iPos = 0; + pChunk = pChunk->pNext; + } + return *this; + } + + const_iterator &operator++( int ) + { + if( !pChunk ) return *this; + iPos++; + if( iPos >= pChunk->nLength ) + { + iPos = 0; + pChunk = pChunk->pNext; + } + return *this; + } + + const_iterator &operator+=( int iAmnt ) + { + if( !pChunk ) return *this; + iPos += iAmnt; + while( iPos >= pChunk->nLength ) + { + iPos -= pChunk->nLength; + pChunk = pChunk->pNext; + if( pChunk == NULL ) + break; + } + return *this; + } + + const_iterator operator+( int iAmnt ) const + { + if( !pChunk ) return *this; + const_iterator ret( *this ); + ret += iAmnt; + return ret; + } + + const chr &operator *() const + { + if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator."); + return pChunk->pData[iPos]; + } + + bool operator==( const chr &c ) const + { + if( !pChunk ) return false; + return pChunk->pData[iPos] == c; + } + + operator bool() const + { + return pChunk != NULL; + } + + bool isValid() const + { + return pChunk != NULL; + } + + bool compare( const const_iterator &c ) const + { + const_iterator a = *this; + const_iterator b = c; + if( a == b ) + return true; + for(; a && b; a++, b++ ) + { + if( *a != *b ) + return false; + } + return true; + } + + bool compare( const const_iterator &c, int nLen ) const + { + const_iterator a = *this; + const_iterator b = c; + if( a == b ) + return true; + for(int j = 0; a && b && j < nLen; a++, b++, j++ ) + { + if( *a != *b ) + return false; + } + return true; + } + + bool compare( const chr *c ) const + { + if( !pChunk ) return false; + const_iterator a = *this; + for(; a && *c; a++, c++ ) + { + if( *a != *c ) + return false; + } + if( a.isValid() != (*c!=(chr)0) ) + return false; + return true; + } + + bool compare( const chr *c, int nLen ) const + { + if( !pChunk ) return false; + const_iterator a = *this; + int j = 0; + for(; a && j < nLen; a++, c++, j++ ) + { + if( *a != *c ) + return false; + } + if( j < nLen ) + return false; + return true; + } + + bool compare( const MyType &s ) const + { + if( !pChunk ) return false; + return compare( s.begin() ); + } + + bool compare( const MyType &s, int nLen ) const + { + if( !pChunk ) return false; + return compare( s.begin(), nLen ); + } + + const_iterator find( const chr c ) const + { + for( const_iterator i = *this; i; i++ ) + { + if( *i == c ) + return i; + } + return const_iterator( NULL, 0 ); + } + + const_iterator find( const chr *pStr, int nLen ) const + { + for( const_iterator i = *this; i; i++ ) + { + if( i.compare( pStr, nLen ) ) + return i; + } + return const_iterator( NULL, 0 ); + } + + const_iterator find( const MyType &s ) const + { + for( const_iterator i = *this; i; i++ ) + { + if( i.compare( s ) ) + return i; + } + return const_iterator( NULL, 0 ); + } + + const_iterator find( const MyType &s, int nLen ) const + { + for( const_iterator i = *this; i; i++ ) + { + if( i.compare( s, nLen ) ) + return i; + } + return const_iterator( NULL, 0 ); + } + } const_iterator; + + typedef struct iterator + { + friend class FBasicString; + private: + iterator( Chunk *pChunk, int iPos ) : + pChunk( pChunk ), + iPos( iPos ) + { + } + + Chunk *pChunk; + int iPos; + + public: + iterator( const iterator &i ) : + pChunk( i.pChunk ), + iPos( i.iPos ) + { + } + + operator const_iterator() const + { + return const_iterator( pChunk, iPos ); + } + + bool operator==( const iterator &i ) const + { + return pChunk == i.pChunk && iPos == i.iPos; + } + + bool operator!=( const iterator &i ) const + { + return !(*this == i); + } + + iterator &operator=( const iterator &i ) + { + pChunk = i.pChunk; + iPos = i.iPos; + return *this; + } + + iterator &operator++() + { + if( !pChunk ) return *this; + iPos++; + if( iPos >= pChunk->nLength ) + { + iPos = 0; + pChunk = pChunk->pNext; + } + return *this; + } + + iterator &operator++( int ) + { + if( !pChunk ) return *this; + iPos++; + if( iPos >= pChunk->nLength ) + { + iPos = 0; + pChunk = pChunk->pNext; + } + return *this; + } + + iterator &operator+=( int iAmnt ) + { + if( !pChunk ) return *this; + iPos += iAmnt; + while( iPos >= pChunk->nLength ) + { + iPos -= pChunk->nLength; + pChunk = pChunk->pNext; + if( pChunk == NULL ) + break; + } + return *this; + } + + iterator operator+( int iAmnt ) const + { + if( !pChunk ) return *this; + iterator ret( *this ); + ret += iAmnt; + return ret; + } + + chr &operator*() + { + if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); + return pChunk->pData[iPos]; + } + + const chr &operator*() const + { + if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); + return pChunk->pData[iPos]; + } + + bool operator==( const chr &c ) const + { + if( !pChunk ) return false; + return pChunk->pData[iPos] == c; + } + + iterator &operator=( const chr &c ) + { + if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); + pChunk->pData[iPos] = c; + return *this; + } + + operator bool() const + { + return pChunk != NULL; + } + + bool isValid() const + { + return pChunk != NULL; + } + + bool compare( const iterator &c ) const + { + iterator a = *this; + iterator b = c; + if( a == b ) + return true; + for(; a && b; a++, b++ ) + { + if( *a != *b ) + return false; + } + return true; + } + + bool compare( const iterator &c, int nLen ) const + { + iterator a = *this; + iterator b = c; + if( a == b ) + return true; + for(int j = 0; a && b && j < nLen; a++, b++, j++ ) + { + if( *a != *b ) + return false; + } + return true; + } + + bool compare( const chr *c ) const + { + if( !pChunk ) return false; + iterator a = *this; + for(; a && *c; a++, c++ ) + { + if( *a != *c ) + return false; + } + if( a.isValid() != (*c!=(chr)0) ) + return false; + return true; + } + + bool compare( const chr *c, int nLen ) const + { + if( !pChunk ) return false; + iterator a = *this; + int j = 0; + for(; a && j < nLen; a++, c++, j++ ) + { + if( *a != *c ) + return false; + } + if( j < nLen ) + return false; + return true; + } + + bool compare( const MyType &s ) const + { + if( !pChunk ) return false; + return compare( s.begin() ); + } + + bool compare( const MyType &s, int nLen ) const + { + if( !pChunk ) return false; + return compare( s.begin(), nLen ); + } + + iterator find( const chr c ) const + { + for( iterator i = *this; i; i++ ) + { + if( *i == c ) + return i; + } + return iterator( NULL, 0 ); + } + + iterator find( const chr *pStr, int nLen ) const + { + for( iterator i = *this; i; i++ ) + { + if( i.compare( pStr, nLen ) ) + return i; + } + return iterator( NULL, 0 ); + } + + iterator find( const MyType &s ) const + { + for( iterator i = *this; i; i++ ) + { + if( i.compare( s ) ) + return i; + } + return iterator( NULL, 0 ); + } + + iterator find( const MyType &s, int nLen ) const + { + for( iterator i = *this; i; i++ ) + { + if( i.compare( s, nLen ) ) + return i; + } + return iterator( NULL, 0 ); + } + } iterator; + + //typedef chr *iterator; +// typedef const chr *const_iterator; + // typedef iterator const_iterator; + + FBasicString( const const_iterator &s ) : + nLength( 0 ), + pFirst( NULL ), + pLast( NULL ) + { + append( s ); + } + + FBasicString( const const_iterator &s, const const_iterator &e ) : + nLength( 0 ), + pFirst( NULL ), + pLast( NULL ) + { + append( s, e ); + } virtual ~FBasicString() { clear(); } - /** - *@todo void append( const MyType & sData ) - */ - /** * Append data to your string. *@param pData (const chr *) The data to append. @@ -204,6 +675,74 @@ namespace Bu append( sData.getStr(), nLen ); } + /** + * Append another FString to this one. + *@param sData (MyType &) The FString to append. + *@param nLen How much data to append. + */ + void append( const MyType & sData, long nStart, long nLen ) + { + if( nLen < 0 ) + nLen = sData.getSize() - nStart; + append( sData.getStr(), nStart, nLen ); + } + + void append( const const_iterator &s ) + { + if( !s.isValid() ) + return; + Chunk *pSrc = s.pChunk; + + Chunk *pNew = newChunk( pSrc->nLength-s.iPos ); + cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); + appendChunk( pNew ); + + while( (pSrc = pSrc->pNext) ) + { + appendChunk( copyChunk( pSrc ) ); + } + } + + void append( const iterator &s ) // I get complainst without this one + { + append( const_iterator( s ) ); + } + + void append( const const_iterator &s, const const_iterator &e ) + { + if( !s.isValid() ) + return; + if( !e.isValid() ) + { + append( s ); + return; + } + if( s.pChunk == e.pChunk ) + { + // Simple case, they're the same chunk + Chunk *pNew = newChunk( e.iPos-s.iPos ); + cpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos ); + appendChunk( pNew ); + } + else + { + // A little trickier, scan the blocks... + Chunk *pSrc = s.pChunk; + Chunk *pNew = newChunk( pSrc->nLength-s.iPos ); + cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); + appendChunk( pNew ); + + while( (pSrc = pSrc->pNext) != e.pChunk ) + { + appendChunk( copyChunk( pSrc ) ); + } + + pNew = newChunk( e.iPos ); + cpy( pNew->pData, pSrc->pData, e.iPos ); + appendChunk( pNew ); + } + } + /** * Prepend another FString to this one. *@param sData (MyType &) The FString to prepend. @@ -549,6 +1088,42 @@ namespace Bu append( pData, nSize ); } + void set( const chr *pData, long nStart, long nSize ) + { + clear(); + append( pData, nStart, nSize ); + } + + void set( const MyType &rData ) + { + clear(); + append( rData ); + } + + void set( const MyType &rData, long nSize ) + { + clear(); + append( rData, nSize ); + } + + void set( const MyType &rData, long nStart, long nSize ) + { + clear(); + append( rData, nStart, nSize ); + } + + void set( const_iterator s ) + { + clear(); + append( s ); + } + + void set( const_iterator s, const_iterator e ) + { + clear(); + append( s, e ); + } + void expand() { flatten(); @@ -704,6 +1279,55 @@ namespace Bu return (pFirst != NULL); } + bool compareSub( const chr *pData, long nIndex, long nLen ) + { + if( pFirst == NULL ) { + if( pData == NULL ) + return true; + if( pData[0] == (chr)0 ) + return true; + return false; + } + if( nIndex+nLen > nLength ) + return false; + + flatten(); + pFirst->pData[nLength] = (chr)0; + const chr *a = pData; + chr *b = pFirst->pData+nIndex; + for( long j = 0; j < nLen; j++, a++, b++ ) + { + if( *a != *b ) + return false; + if( *a == (chr)0 && j < nLength ) + return false; + } + + return true; + } + + bool compareSub( const MyType &rData, long nIndex, long nLen ) + { + if( pFirst == NULL || rData.pFirst == NULL ) + return false; + if( nLen < 0 ) + nLen = rData.nLength; + if( nIndex+nLen > nLength ) + return false; + + flatten(); + rData.flatten(); + const chr *a = rData.pFirst->pData; + chr *b = pFirst->pData + nIndex; + for( long j = 0; j < nLen; j++, a++, b++ ) + { + if( *a != *b ) + return false; + } + + return true; + } + /** * Is the character at index (nIndex) white space? *@param nIndex (long) The index of the character you want to check. @@ -758,45 +1382,56 @@ namespace Bu } } - /** - * Find the index of the first occurrance of (sText) - *@param sText (const chr *) The string to search for. - *@returns (long) The index of the first occurrance. -1 for not found. - */ - long find( const chr cChar ) const + const_iterator find( const chr cChar, + const_iterator iStart=begin() ) const { - flatten(); - for( long j = 0; j < pFirst->nLength; j++ ) + for( ; iStart; iStart++ ) { - if( pFirst->pData[j] == cChar ) - return j; + if( cChar == *iStart ) + return iStart; } - return -1; + return end(); } - - /** - * Find the index of the first occurrance of cChar - *@param cChar (const chr) The character to search for. - *@returns (long) The index of the first occurrance. -1 for not found. - */ - long find( const chr *sText ) const + + const_iterator find( const chr *sText, int nLen, + const_iterator iStart=begin() ) const { - long nTLen = strlen( sText ); - flatten(); - for( long j = 0; j < pFirst->nLength-nTLen; j++ ) + for( ; iStart; iStart++ ) { - if( !strncmp( sText, pFirst->pData+j, nTLen ) ) - return j; + if( iStart.compare( sText, nLen ) ) + return iStart; } - return -1; + return end(); } - + + const_iterator find( const MyType &rStr, + const_iterator iStart=begin() ) const + { + for( ; iStart; iStart++ ) + { + if( iStart.compare( rStr ) ) + return iStart; + } + return end(); + } + + const_iterator find( const MyType &rStr, int nLen, + const_iterator iStart=begin() ) const + { + for( ; iStart; iStart++ ) + { + if( iStart.compare( rStr, nLen ) ) + return iStart; + } + return end(); + } + /** * Find the index of the first occurrance of cChar *@param sText (const chr *) The string to search for. *@returns (long) The index of the first occurrance. -1 for not found. */ - long find( long iStart, const chr cChar ) const + long findIdx( const chr cChar, long iStart=0 ) const { flatten(); for( long j = iStart; j < pFirst->nLength; j++ ) @@ -812,7 +1447,7 @@ namespace Bu *@param cChar (const chr) The character to search for. *@returns (long) The index of the first occurrance. -1 for not found. */ - long find( long iStart, const chr *sText ) const + long findIdx( const chr *sText, long iStart=0 ) const { long nTLen = strlen( sText ); flatten(); @@ -829,7 +1464,7 @@ namespace Bu *@param sText (const chr *) The string to search for. *@returns (long) The index of the last occurrance. -1 for not found. */ - long rfind( const chr *sText ) const + long rfindIdx( const chr *sText ) const { long nTLen = strlen( sText ); flatten(); @@ -928,37 +1563,28 @@ namespace Bu } } - typedef chr *iterator; - typedef const chr *const_iterator; - iterator begin() { if( nLength == 0 ) - return NULL; - flatten(); - return pFirst->pData; + return iterator( NULL, 0 ); + return iterator( pFirst, 0 ); } const_iterator begin() const { if( nLength == 0 ) - return NULL; - flatten(); - return pFirst->pData; + return const_iterator( NULL, 0 ); + return iterator( pFirst, 0 ); } iterator end() { - if( nLength == 0 ) - return NULL; - return pFirst->pData+pFirst->nLength; + return iterator( NULL, 0 ); } const_iterator end() const { - if( nLength == 0 ) - return NULL; - return pFirst->pData+pFirst->nLength; + return const_iterator( NULL, 0 ); } bool isEmpty() const diff --git a/src/hash.h b/src/hash.h index 8856860..3868a4e 100644 --- a/src/hash.h +++ b/src/hash.h @@ -575,7 +575,17 @@ namespace Bu { } - bool isActive() + DEPRECATED bool isActive() const + { + return !bFinished; + } + + bool isValid() const + { + return !bFinished; + } + + operator bool() const { return !bFinished; } @@ -605,7 +615,7 @@ namespace Bu /** * Iterator equality comparison operator. Iterators the same? */ - bool operator==( const iterator &oth ) + bool operator==( const iterator &oth ) const { if( bFinished != oth.bFinished ) return false; @@ -624,7 +634,7 @@ namespace Bu /** * Iterator not equality comparison operator. Not the same? */ - bool operator!=( const iterator &oth ) + bool operator!=( const iterator &oth ) const { return !(*this == oth ); } @@ -650,6 +660,11 @@ namespace Bu { return hsh.getValueAtPos( nPos ); } + + const value &operator *() const + { + return hsh.getValueAtPos( nPos ); + } /** * Get the key behind this iterator. @@ -697,6 +712,16 @@ namespace Bu bool bFinished; public: + bool isValid() const + { + return !bFinished; + } + + operator bool() const + { + return !bFinished; + } + /** * Iterator incrementation operator. Move the iterator forward. */ @@ -722,7 +747,7 @@ namespace Bu /** * Iterator equality comparison operator. Iterators the same? */ - bool operator==( const const_iterator &oth ) + bool operator==( const const_iterator &oth ) const { if( bFinished != oth.bFinished ) return false; @@ -741,7 +766,7 @@ namespace Bu /** * Iterator not equality comparison operator. Not the same? */ - bool operator!=( const const_iterator &oth ) + bool operator!=( const const_iterator &oth ) const { return !(*this == oth ); } diff --git a/src/list.h b/src/list.h index d16e606..f11336e 100644 --- a/src/list.h +++ b/src/list.h @@ -377,6 +377,16 @@ namespace Bu return *this; } + operator bool() + { + return pLink != NULL; + } + + bool isValid() + { + return pLink != NULL; + } + /** * Assignment operator. *@param oth (const iterator &) The other iterator to set this @@ -499,6 +509,16 @@ namespace Bu pLink = oth.pLink; return *this; } + + operator bool() + { + return pLink != NULL; + } + + bool isValid() + { + return pLink != NULL; + } } const_iterator; /** diff --git a/src/minimacro.cpp b/src/minimacro.cpp index b97cefc..0d524a9 100644 --- a/src/minimacro.cpp +++ b/src/minimacro.cpp @@ -141,7 +141,7 @@ Bu::FString Bu::MiniMacro::parseCmd() Bu::FString Bu::MiniMacro::callFunc( const Bu::FString &sIn, const Bu::FString &sFunc ) { - int i = sFunc.find('('); + int i = sFunc.findIdx('('); if( i < 0 ) throw Bu::ExceptionBase("That doesn't look like a function call"); Bu::FString sName( sFunc.getStr(), i ); diff --git a/src/set.h b/src/set.h index 42f9eb8..a25b0bf 100644 --- a/src/set.h +++ b/src/set.h @@ -322,7 +322,7 @@ namespace Bu /** * Iterator equality comparison operator. Iterators the same? */ - bool operator==( const iterator &oth ) + bool operator==( const iterator &oth ) const { if( bFinished != oth.bFinished ) return false; @@ -341,7 +341,7 @@ namespace Bu /** * Iterator not equality comparison operator. Not the same? */ - bool operator!=( const iterator &oth ) + bool operator!=( const iterator &oth ) const { return !(*this == oth ); } @@ -366,6 +366,21 @@ namespace Bu { return hsh.getKeyAtPos( nPos ); } + + const key &operator *() const + { + return hsh.getKeyAtPos( nPos ); + } + + bool isValid() const + { + return !bFinished; + } + + operator bool() const + { + return !bFinished; + } } iterator; /** @@ -420,7 +435,7 @@ namespace Bu /** * Iterator equality comparison operator. Iterators the same? */ - bool operator==( const const_iterator &oth ) + bool operator==( const const_iterator &oth ) const { if( bFinished != oth.bFinished ) return false; @@ -439,7 +454,7 @@ namespace Bu /** * Iterator not equality comparison operator. Not the same? */ - bool operator!=( const const_iterator &oth ) + bool operator!=( const const_iterator &oth ) const { return !(*this == oth ); } @@ -464,6 +479,16 @@ namespace Bu { return hsh.getKeyAtPos( nPos ); } + + bool isValid() const + { + return !bFinished; + } + + operator bool() const + { + return !bFinished; + } } const_iterator; /** diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp index b0f5def..82d39e5 100644 --- a/src/tafwriter.cpp +++ b/src/tafwriter.cpp @@ -104,7 +104,10 @@ void Bu::TafWriter::writeString( const Bu::FString &str ) sOut.write(buf, 4 ); } else - sOut.write( s, 1 ); + { + const char buf = *s; + sOut.write( &buf, 1 ); + } } sOut.write("\"", 1 ); } diff --git a/src/tests/rh.cpp b/src/tests/rh.cpp deleted file mode 100644 index 70abcb7..0000000 --- a/src/tests/rh.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "bu/file.h" -#include "bu/hash.h" -#include "bu/archive.h" -#include "bu/fstring.h" -#include "bu/nids.h" -#include "bu/nidsstream.h" - -int main( int argc, char *argv[] ) -{ - if( argv[1][0] == 'r' ) - { - typedef Bu::Hash Hsh; - - Bu::File fIn( argv[2], Bu::File::Read ); - Bu::Archive ar( fIn, Bu::Archive::load ); - - Hsh h; - ar >> h; - - printf("Read %d.\n", h.getSize() ); - for( Hsh::iterator i = h.begin(); i != h.end(); i++ ) - { - printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); - } - - printf("%d vs. %d\n", h.getSize(), h.getKeys().getSize() ); - } - else if( argv[1][0] == 'n' ) - { - typedef Bu::Hash Hsh; - - Bu::File fIn( argv[2], Bu::File::Read ); - Bu::Nids n( fIn ); - n.initialize(); - Bu::NidsStream sIn = n.openStream( 0 ); - Bu::Archive ar( sIn, Bu::Archive::load ); - - Hsh h; - ar >> h; - - printf("Read %d.\n", h.getSize() ); - for( Hsh::iterator i = h.begin(); i != h.end(); i++ ) - { - printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); - } - - printf("%d vs. %d\n", h.getSize(), h.getKeys().getSize() ); - } - - return 0; -} - diff --git a/src/tests/url.cpp b/src/tests/url.cpp new file mode 100644 index 0000000..c9af676 --- /dev/null +++ b/src/tests/url.cpp @@ -0,0 +1,32 @@ +#include "bu/url.h" + +#include + +int main( int argc, char *argv[] ) +{ + printf("encodede: %s\n", Bu::Url::encode( argv[1] ).getStr() ); + printf("decodede: %s\n", Bu::Url::decode( argv[1] ).getStr() ); + Bu::Url u( argv[1] ); + + printf("Protocol: %s\n", u.getProtocol().getStr() ); + printf("User: %s\n", u.getUser().getStr() ); + printf("Pass: %s\n", u.getPass().getStr() ); + printf("Host: %s\n", u.getHost().getStr() ); + printf("Path: %s\n", u.getPath().getStr() ); + try + { + printf("Port: %d\n", u.getPort() ); + } catch( Bu::ExceptionBase &e ) + { + printf("Port: not set.\n"); + } + printf("Parameters:\n"); + for( Bu::Url::ParamList::const_iterator i = u.getParamBegin(); i; i++ ) + { + printf(" \"%s\" = \"%s\"\n", + (*i).sName.getStr(), (*i).sValue.getStr() + ); + } + + return 0; +} diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit index 3912de2..a0d62da 100644 --- a/src/unit/fstring.unit +++ b/src/unit/fstring.unit @@ -138,3 +138,158 @@ unitTest( a.getSubStr( -10 ) == "abcdefghijklmnop" ); unitTest( a.getSubStr( -15, 4 ) == "abcd" ); } + +{%compareSub1} +{ + Bu::FString a("just a string."); + unitTest( a.compareSub("a ", 5, 2) == true ); + unitTest( a.compareSub("string.aoeu", 7, 11 ) == false ); + unitTest( a.compareSub("string.aoeu", 7, 3 ) == true ); +} + +{%compareSub2} +{ + Bu::FString a("just a string."); + unitTest( a.compareSub(Bu::FString("a "), 5, 2) == true ); + unitTest( a.compareSub(Bu::FString("string.aoeu"), 7, 11 ) == false ); + unitTest( a.compareSub(Bu::FString("string.aoeu"), 7, 3 ) == true ); +} + +{%iterator1} +{ + Bu::FString a("This is a test."); + Bu::FString b; + for( Bu::FString::iterator i = a.begin(); i; i++ ) + { + b += *i; + } + unitTest( a == b ); +} + +{%iterator2} +{ + Bu::FString a("This is a test."); + Bu::FString b("--This is a test."); + Bu::FString::iterator ai = a.begin(); + Bu::FString::iterator bi = b.begin(); + unitTest( ai.compare( bi ) == false ); + unitTest( bi.compare( ai ) == false ); + bi++; bi++; + unitTest( ai.compare( bi ) == true ); + unitTest( bi.compare( ai ) == true ); +} + +{%iterator3} +{ + Bu::FString a("1234honour"); + Bu::FString b("--1234ueje"); + Bu::FString::iterator ai = a.begin(); + Bu::FString::iterator bi = b.begin(); + unitTest( ai.compare( bi, 4 ) == false ); + unitTest( bi.compare( ai, 4 ) == false ); + bi++; bi++; + unitTest( ai.compare( bi, 4 ) == true ); + unitTest( bi.compare( ai, 4 ) == true ); + unitTest( ai.compare( bi, 5 ) == false ); + unitTest( bi.compare( ai, 5 ) == false ); + +} + +{%iterator4} +{ + Bu::FString a("1234aoeu"); + Bu::FString::iterator ai = a.begin(); + unitTest( ai.compare("1234") == false ); + unitTest( ai.compare("1234aoeu") == true ); + unitTest( ai.compare("1234aoeuee") == false ); +} + +{%iterator5} +{ + Bu::FString a("1234aoeu"); + Bu::FString::iterator ai = a.begin(); + unitTest( ai.compare("1234", 4) == true ); + unitTest( ai.compare("1234aoeu", 8) == true ); + unitTest( ai.compare("1234aoeuee", 10) == false ); +} + +{%iterator6} +{ + Bu::FString a("just ->this part"); + Bu::FString b; + Bu::FString::iterator s = a.begin(); + for(; s; s++ ) + { + if( *s == '>' ) + { + s++; + b.set( s ); + break; + } + } + unitTest( b == "this part" ); + + b.append( s ); + + Bu::FString c; + c.set( b.begin() ); + + // This is here because the comparison operator used to cause flattening. + unitTest( b == "this partthis part" ); + unitTest( c == b ); +} + +{%iterator7} +{ + Bu::FString a("just [this] part"); + Bu::FString b; + Bu::FString::iterator s = a.begin(); + for(; s; s++ ) + { + if( *s == '[' ) + { + s++; + break; + } + } + Bu::FString::iterator e = s; + for(; e; e++ ) + { + if( *e == ']' ) + { + b.set( s, e ); + break; + } + } + unitTest( b == "this" ); + + b.append( s, e ); + + for( Bu::FString::iterator i = b.begin(); i;) + { + Bu::FString::iterator k = i; + k++; + if( !k ) + { + b.append( b.begin(), i ); + break; + } + i = k; + } + Bu::FString l; + l.set( b.begin() ); + unitTest( l == "thisthisthisthi" ); + for( Bu::FString::iterator i = b.begin(); i;) + { + Bu::FString::iterator k = i; + k++; + if( !k ) + { + b.append( b.begin(), i ); + break; + } + i = k; + } + l.set( b.begin() ); + unitTest( l == "thisthisthisthithisthisthisth" ); +} diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp index 7421496..cdd6a2a 100644 --- a/src/unitsuite.cpp +++ b/src/unitsuite.cpp @@ -110,7 +110,7 @@ void Bu::UnitSuite::add( Test fTest, const Bu::FString &sName, Expect e ) TestInfo ti; ti.sName = sName; ti.eExpect = e; - long index = ti.sName.rfind("::"); + long index = ti.sName.rfindIdx("::"); if( index != -1 ) { FString tmp = sSuiteName; diff --git a/src/url.cpp b/src/url.cpp new file mode 100644 index 0000000..7cc4263 --- /dev/null +++ b/src/url.cpp @@ -0,0 +1,237 @@ +#include "bu/url.h" +#ifndef WIN32 +# include +# include +#endif +#include + +char Bu::Url::hexcode[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +Bu::Url::Url() +{ +} + +Bu::Url::Url( const Bu::FString &sUrl ) +{ + parseUrl( sUrl ); +} + +Bu::Url::~Url() +{ +} + +void Bu::Url::parseUrl( const Bu::FString &sUrl ) +{ + clear(); + + Bu::FString::const_iterator i = sUrl.begin(); + parseProtocol( i ); + parseUserPass( i ); + parseHost( i ); + parsePath( i ); +} + +Bu::FString Bu::Url::decode( const Bu::FString &sStr ) +{ + Bu::FString sRet; + char buf[3] = {0, 0, 0}; + for( Bu::FString::const_iterator i = sStr.begin(); i; i++ ) + { + if( *i == '+' ) + { + sRet += ' '; + } + else if( *i == '%' ) + { + i++; + buf[0] = *i; + i++; + buf[1] = *i; + sRet += (char)((unsigned char)strtol( buf, NULL, 16 )); + } + else + { + sRet += *i; + } + } + return sRet; +} + +Bu::FString Bu::Url::encode( const Bu::FString &sStr ) +{ + Bu::FString sRet; + for( Bu::FString::const_iterator i = sStr.begin(); i; i++ ) + { + if( *i == ' ' ) + { + sRet += '+'; + } + else if( + (*i >= 'A' && *i <= 'Z') || + (*i >= 'a' && *i <= 'z') || + (*i >= '0' && *i <= '9') || + (*i == '-' || *i == '_' || *i == '.' || *i == '~') + ) + { + sRet += *i; + } + else + { + unsigned char b = *i; + sRet += '%'; + sRet += hexcode[(b>>4)&0xF]; + sRet += hexcode[b&0xF]; + } + } + return sRet; +} + +void Bu::Url::parseProtocol( Bu::FString::const_iterator &i ) +{ + Bu::FString::const_iterator s = i.find("://", 3); + if( !s ) + throw Bu::ExceptionBase("No :// in url"); + Bu::FString sTmp( i, s ); + setProtocol( sTmp ); + i = s + 3; +} + +void Bu::Url::setProtocol( const Bu::FString &sNewProto, bool bAutoSetPort ) +{ + sProtocol = sNewProto; +#ifndef WIN32 + if( bAutoSetPort ) + { + struct servent *se = getservbyname( sProtocol.getStr(), "tcp" ); + if( se ) + { + iPort = ntohs( se->s_port ); + } + } +#endif +} + +void Bu::Url::parseUserPass( Bu::FString::const_iterator &i ) +{ + Bu::FString::const_iterator s = i.find('@'); + if( !s ) + return; + + Bu::FString::const_iterator p = i.find(':'); + if( p ) + { + sUser.set( i, p ); + sPass.set( p+1, s ); + } + else + { + sUser.set( i, s ); + } + + i = s + 1; +} + +void Bu::Url::parseHost( Bu::FString::const_iterator &i ) +{ + Bu::FString::const_iterator s = i; + for( ; s && *s != '/'; s++ ) + { + if( *s == ':' ) + { + sHost.set( i, s ); + i = s + 1; + s = i.find('/'); + Bu::FString sPort( i, s ); + iPort = strtol( sPort.getStr(), NULL, 10 ); + i = s; + return; + } + } + sHost.set( i, s ); + i = s; +} + +void Bu::Url::parsePath( Bu::FString::const_iterator &i ) +{ + if( i ) + { + Bu::FString::const_iterator s = i.find('?'); + sPath.set( i, s ); + i = s + 1; + if( s ) + { + parseParams( i ); + } + } + else + { + sPath = "/"; + } +} + +void Bu::Url::parseParams( Bu::FString::const_iterator &i ) +{ + bool bName = true; + Bu::FString sName, sValue; + for( Bu::FString::const_iterator s = i; s; s++ ) + { + if( bName ) + { + if( *s == '&' ) + { + sName.set( i, s ); + sValue.clear(); + i = s + 1; + addParam( decode( sName ), decode( sValue ) ); + } + else if( *s == '=' ) + { + sName.set( i, s ); + i = s + 1; + bName = false; + } + } + else + { + if( *s == '&' ) + { + sValue.set( i, s ); + i = s + 1; + bName = true; + addParam( decode( sName ), decode( sValue ) ); + } + } + } + if( i ) + { + if( bName ) + { + sName.set( i ); + sValue.clear(); + } + else + { + sValue.set( i ); + } + addParam( decode( sName ), decode( sValue ) ); + } +} + +void Bu::Url::addParam( const Bu::FString &n, const Bu::FString &v ) +{ + lParam.append( Param( n, v ) ); +} + +void Bu::Url::clear() +{ + sProtocol.clear(); + sUser.clear(); + sPass.clear(); + sHost.clear(); + sPath.clear(); + iPort.clear(); +} + diff --git a/src/url.h b/src/url.h new file mode 100644 index 0000000..861bb9f --- /dev/null +++ b/src/url.h @@ -0,0 +1,74 @@ +#ifndef BU_URL_H +#define BU_URL_H + +#include "bu/fstring.h" +#include "bu/atom.h" + +namespace Bu +{ + class Url + { + public: + typedef struct Param + { + Param() { } + Param( const Param &r ) : sName( r.sName ), sValue( r.sValue ) { } + Param( const Bu::FString &n, const Bu::FString &v ) : + sName( n ), sValue( v ) { } + Bu::FString sName; + Bu::FString sValue; + } Param; + typedef Bu::List ParamList; + + public: + Url(); + Url( const Bu::FString &sUrl ); + virtual ~Url(); + + void parseUrl( const Bu::FString &sUrl ); + void parseParams( Bu::FString::const_iterator &i ); + void clear(); + + Bu::FString getUrl(); + + const Bu::FString &getProtocol() { return sProtocol; } + const Bu::FString &getUser() { return sUser; } + const Bu::FString &getPass() { return sPass; } + const Bu::FString &getHost() { return sHost; } + const Bu::FString &getPath() { return sPath; } + int getPort() { return iPort; } + ParamList::const_iterator getParamBegin() { return lParam.begin(); } + + void setProtocol( const Bu::FString &sNewHost, bool bAutoSetPort=true ); + void setUser( const Bu::FString &s ) { sUser = s; } + void setPass( const Bu::FString &s ) { sPass = s; } + void setHost( const Bu::FString &s ) { sHost = s; } + void setPath( const Bu::FString &s ) { sPath = s; } + void setPort( int i ) { iPort = i; } + void addParam( const Bu::FString &n, const Bu::FString &v ); + + bool hasPort() { return iPort.has(); } + + static Bu::FString decode( const Bu::FString &sStr ); + static Bu::FString encode( const Bu::FString &sStr ); + + private: // Parsing code + void parseProtocol( Bu::FString::const_iterator &i ); + void parseUserPass( Bu::FString::const_iterator &i ); + void parseHost( Bu::FString::const_iterator &i ); + void parsePath( Bu::FString::const_iterator &i ); + + private: + Bu::FString sProtocol; + Bu::FString sUser; + Bu::FString sPass; + Bu::FString sHost; + Bu::FString sPath; + Bu::Atom iPort; + ParamList lParam; + + static char hexcode[16]; + }; +}; + +#endif -- cgit v1.2.3