From cba6293cf22e2c2ae17dd3954ad7d097f379c7ac Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 18 Mar 2011 23:02:54 +0000 Subject: Wow, a lot has changed. String is not a template class, and it can do it's own formatting ala QString. --- src/fmt.h | 92 +++ src/formatter.cpp | 28 +- src/formatter.h | 101 +-- src/lexer.cpp | 1 + src/myriadstream.cpp | 4 +- src/string.cpp | 1295 ++++++++++++++++++++++++++++++++++++- src/string.h | 1566 +++++++-------------------------------------- src/tests/stringspeed.cpp | 122 ++++ src/tools/format.cpp | 124 ---- src/udpsocket.cpp | 14 +- src/utfstring.h | 6 +- src/variant.cpp | 2 +- src/variant.h | 11 +- 13 files changed, 1791 insertions(+), 1575 deletions(-) create mode 100644 src/fmt.h create mode 100644 src/tests/stringspeed.cpp delete mode 100644 src/tools/format.cpp diff --git a/src/fmt.h b/src/fmt.h new file mode 100644 index 0000000..15d8efc --- /dev/null +++ b/src/fmt.h @@ -0,0 +1,92 @@ +#ifndef BU_FMT_H +#define BU_FMT_H + +namespace Bu +{ + typedef struct Fmt + { + enum Alignment + { + Left = 0, + Center = 1, + Right = 2 + }; + Fmt() : + uMinWidth( 0 ), + cFillChar(' '), + uRadix( 10 ), + uAlign( Right ), + bPlus( false ), + bCaps( true ), + bTokenize( true ) + { + } + + Fmt( unsigned int uMinWidth, unsigned int uRadix=10, + Alignment a=Right, bool bPlus=false, bool bCaps=true, + char cFill=' ') : + uMinWidth( uMinWidth ), + cFillChar(cFill), + uRadix( uRadix ), + uAlign( a ), + bPlus( bPlus ), + bCaps( bCaps ), + bTokenize( true ) + { + } + Fmt( unsigned int uMinWidth, Alignment a, + unsigned int uRadix=10, bool bPlus=false, bool bCaps=true, + char cFill=' ') : + uMinWidth( uMinWidth ), + cFillChar(cFill), + uRadix( uRadix ), + uAlign( a ), + bPlus( bPlus ), + bCaps( bCaps ), + bTokenize( true ) + { + } + + static Fmt hex( unsigned int uWidth=0, bool bCaps=true ) + { + return Fmt( uWidth, 16, Right, false, bCaps, '0' ); + } + + static Fmt oct( unsigned int uWidth=0 ) + { + return Fmt( uWidth, 8, Right, false, false, '0' ); + } + + static Fmt bin( unsigned int uWidth=0 ) + { + return Fmt( uWidth, 1, Right, false, false, '0' ); + } + + static Fmt ptr( bool bCaps=true ) + { + return Fmt( sizeof(ptrdiff_t)*2, 16, Right, false, bCaps, '0' ); + } + + Fmt &width( unsigned int uWidth ); + Fmt &fill( char cFill='0' ); + Fmt &radix( unsigned int uRadix ); + Fmt &align( Alignment eAlign ); + Fmt &plus( bool bPlus=true ); + Fmt &caps( bool bCaps=true ); + Fmt &tokenize( bool bTokenize=true ); + + Fmt &left(); + Fmt &right(); + Fmt ¢er(); + + unsigned char uMinWidth; + char cFillChar; + unsigned short uRadix : 6; + unsigned short uAlign : 2; + unsigned short bPlus : 1; + unsigned short bCaps : 1; + unsigned short bTokenize : 1; + } Fmt; +}; + +#endif diff --git a/src/formatter.cpp b/src/formatter.cpp index f73d46e..dcaa3a5 100644 --- a/src/formatter.cpp +++ b/src/formatter.cpp @@ -7,6 +7,7 @@ #include "bu/formatter.h" +#include "bu/stream.h" #include Bu::Formatter::Formatter( Stream &rStream ) : @@ -189,67 +190,72 @@ void Bu::Formatter::setIndentChar( char cIndent ) this->cIndent = cIndent; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::width( unsigned int uWidth ) +void Bu::Formatter::doFlush() +{ + rStream.flush(); +} + +Bu::Fmt &Bu::Fmt::width( unsigned int uWidth ) { this->uMinWidth = uWidth; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::fill( char cFill ) +Bu::Fmt &Bu::Fmt::fill( char cFill ) { this->cFillChar = (unsigned char)cFill; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::radix( unsigned int uRadix ) +Bu::Fmt &Bu::Fmt::radix( unsigned int uRadix ) { this->uRadix = uRadix; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::align( Alignment eAlign ) +Bu::Fmt &Bu::Fmt::align( Alignment eAlign ) { this->uAlign = eAlign; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::left() +Bu::Fmt &Bu::Fmt::left() { this->uAlign = Fmt::Left; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::center() +Bu::Fmt &Bu::Fmt::center() { this->uAlign = Fmt::Center; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::right() +Bu::Fmt &Bu::Fmt::right() { this->uAlign = Fmt::Right; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::plus( bool bPlus ) +Bu::Fmt &Bu::Fmt::plus( bool bPlus ) { this->bPlus = bPlus; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::caps( bool bCaps ) +Bu::Fmt &Bu::Fmt::caps( bool bCaps ) { this->bCaps = bCaps; return *this; } -Bu::Formatter::Fmt &Bu::Formatter::Fmt::tokenize( bool bTokenize ) +Bu::Fmt &Bu::Fmt::tokenize( bool bTokenize ) { this->bTokenize = bTokenize; return *this; } -Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Formatter::Fmt &fmt ) +Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Fmt &fmt ) { f.setTempFormat( fmt ); return f; diff --git a/src/formatter.h b/src/formatter.h index 49507de..f87a9be 100644 --- a/src/formatter.h +++ b/src/formatter.h @@ -8,101 +8,19 @@ #ifndef BU_FORMATTER_H #define BU_FORMATTER_H -#include "stream.h" +#include "bu/string.h" +#include "bu/fmt.h" namespace Bu { + class Stream; + class Formatter { public: Formatter( Stream &rStream ); virtual ~Formatter(); - typedef struct Fmt - { - enum Alignment - { - Left = 0, - Center = 1, - Right = 2 - }; - Fmt() : - uMinWidth( 0 ), - cFillChar(' '), - uRadix( 10 ), - uAlign( Right ), - bPlus( false ), - bCaps( true ), - bTokenize( true ) - { - } - - Fmt( unsigned int uMinWidth, unsigned int uRadix=10, - Alignment a=Right, bool bPlus=false, bool bCaps=true, - char cFill=' ') : - uMinWidth( uMinWidth ), - cFillChar(cFill), - uRadix( uRadix ), - uAlign( a ), - bPlus( bPlus ), - bCaps( bCaps ), - bTokenize( true ) - { - } - Fmt( unsigned int uMinWidth, Alignment a, - unsigned int uRadix=10, bool bPlus=false, bool bCaps=true, - char cFill=' ') : - uMinWidth( uMinWidth ), - cFillChar(cFill), - uRadix( uRadix ), - uAlign( a ), - bPlus( bPlus ), - bCaps( bCaps ), - bTokenize( true ) - { - } - - static Fmt hex( unsigned int uWidth=0, bool bCaps=true ) - { - return Fmt( uWidth, 16, Right, false, bCaps, '0' ); - } - - static Fmt oct( unsigned int uWidth=0 ) - { - return Fmt( uWidth, 8, Right, false, false, '0' ); - } - - static Fmt bin( unsigned int uWidth=0 ) - { - return Fmt( uWidth, 1, Right, false, false, '0' ); - } - - static Fmt ptr( bool bCaps=true ) - { - return Fmt( sizeof(ptrdiff_t)*2, 16, Right, false, bCaps, '0' ); - } - - Fmt &width( unsigned int uWidth ); - Fmt &fill( char cFill='0' ); - Fmt &radix( unsigned int uRadix ); - Fmt &align( Alignment eAlign ); - Fmt &plus( bool bPlus=true ); - Fmt &caps( bool bCaps=true ); - Fmt &tokenize( bool bTokenize=true ); - - Fmt &left(); - Fmt &right(); - Fmt ¢er(); - - unsigned char uMinWidth; - char cFillChar; - unsigned short uRadix : 6; - unsigned short uAlign : 2; - unsigned short bPlus : 1; - unsigned short bCaps : 1; - unsigned short bTokenize : 1; - } Fmt; - void write( const Bu::String &sStr ); void write( const void *sStr, int iLen ); void writeAligned( const Bu::String &sStr ); @@ -200,7 +118,7 @@ namespace Bu void ffmt( type f ) { Bu::String fTmp; - fTmp.format("%f", f ); +// fTmp.format("%f", f ); // writeAligned("**make floats work**"); writeAligned( fTmp ); usedFormat(); @@ -269,10 +187,7 @@ namespace Bu flush }; - void doFlush() - { - rStream.flush(); - } + void doFlush(); private: Stream &rStream; @@ -282,9 +197,7 @@ namespace Bu char cIndent; }; - typedef Formatter::Fmt Fmt; - - Formatter &operator<<( Formatter &f, const Formatter::Fmt &fmt ); + Formatter &operator<<( Formatter &f, const Fmt &fmt ); Formatter &operator<<( Formatter &f, Formatter::Special s ); Formatter &operator<<( Formatter &f, const char *sStr ); Formatter &operator<<( Formatter &f, char *sStr ); diff --git a/src/lexer.cpp b/src/lexer.cpp index a071695..185456a 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -7,6 +7,7 @@ #include "bu/lexer.h" #include "bu/membuf.h" +#include "bu/formatter.h" Bu::Lexer::Lexer() { diff --git a/src/myriadstream.cpp b/src/myriadstream.cpp index a968a0c..e6e94bc 100644 --- a/src/myriadstream.cpp +++ b/src/myriadstream.cpp @@ -304,8 +304,6 @@ Bu::size Bu::MyriadStream::getBlockSize() const Bu::String Bu::MyriadStream::getLocation() const { - Bu::String s; - s.format("%d", pStream->iId ); - return s; + return Bu::String("%1").arg( pStream->iId ); } diff --git a/src/string.cpp b/src/string.cpp index 538ac52..ce86c0d 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -10,8 +10,1284 @@ #include "bu/string.h" #include "bu/hash.h" +#include "bu/membuf.h" +#include "bu/formatter.h" +#include + +Bu::StringCore::StringCore() : + nLength( 0 ), + pFirst( NULL ), + pLast( NULL ) +{ +} + +Bu::StringCore::StringCore( const StringCore &rSrc ) : + nLength( rSrc.nLength ), + pFirst( NULL ), + pLast( NULL ) +{ + if( rSrc.pFirst == NULL || rSrc.nLength == 0 ) + { + pFirst = pLast = NULL; + } + else + { + pFirst = pLast = newChunk( nLength ); + Chunk *pLink = rSrc.pFirst; + int iPos = 0; + while( pLink != NULL ) + { + memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength ); + iPos += pLink->nLength; + pLink = pLink->pNext; + } + } +} + +Bu::StringCore::~StringCore() +{ + clear(); +} + +void Bu::StringCore::clear() const +{ + if( pFirst == NULL ) + return; + + Chunk *i = pFirst; + for(;;) + { + Chunk *n = i->pNext; + delete[] i->pData; + delete i; + if( n == NULL ) + break; + i = n; + } + pFirst = pLast = NULL; + nLength = 0; +} + +Bu::StringCore::Chunk *Bu::StringCore::newChunk() const +{ + Chunk *pNew = new Chunk; + pNew->pNext = NULL; + return pNew; +} + +Bu::StringCore::Chunk *Bu::StringCore::newChunk( long nLen ) const +{ + Chunk *pNew = new Chunk; + pNew->pNext = NULL; + pNew->nLength = nLen; + pNew->pData = new char[(nLenpData[nLen] = (char)0; + return pNew; +} + +Bu::StringCore::Chunk *Bu::StringCore::copyChunk( + Bu::StringCore::Chunk *pSrc ) const +{ + Chunk *pNew = new Chunk; + pNew->pNext = pSrc->pNext; + pNew->nLength = pSrc->nLength; + pNew->pData = new char[ + (pNew->nLengthnLength)+1 + ]; + memcpy( pNew->pData, pSrc->pData, pSrc->nLength ); + pNew->pData[pNew->nLength] = (char)0; + return pNew; +} + +void Bu::StringCore::appendChunk( Bu::StringCore::Chunk *pNewChunk ) +{ + if( pFirst == NULL ) + pLast = pFirst = pNewChunk; + else + { + pLast->pNext = pNewChunk; + pLast = pNewChunk; + } + + nLength += pNewChunk->nLength; +} + +void Bu::StringCore::prependChunk( Bu::StringCore::Chunk *pNewChunk ) +{ + if( pFirst == NULL ) + pLast = pFirst = pNewChunk; + else + { + pNewChunk->pNext = pFirst; + pFirst = pNewChunk; + } + + nLength += pNewChunk->nLength; +} + +Bu::String::String() +{ +} + +Bu::String::String( const char *pData ) +{ + append( pData ); +} + +Bu::String::String( const char *pData, long nLength ) +{ + append( pData, nLength ); +} + +Bu::String::String( const Bu::String::String &rSrc ) : + Bu::SharedCore( rSrc ) +{ +} + +Bu::String::String( const Bu::String &rSrc, long nLength ) +{ + append( rSrc, nLength ); +} + +Bu::String::String( const Bu::String &rSrc, long nStart, long nLength ) +{ + append( rSrc, nStart, nLength ); +} + +Bu::String::String( long nSize ) +{ + core->pFirst = core->pLast = core->newChunk( nSize ); + core->nLength = nSize; +} + +Bu::String::String( const Bu::String::const_iterator &s ) +{ + append( s ); +} + +Bu::String::String( const Bu::String::const_iterator &s, + const Bu::String::const_iterator &e ) +{ + append( s, e ); +} + +Bu::String::~String() +{ +} + +void Bu::String::append( const char *pData ) +{ + if( !pData ) return; + long nLen; + for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { } + + append( pData, 0, nLen ); +} + +void Bu::String::append( const char *pData, long nLen ) +{ + append( pData, 0, nLen ); +} + +void Bu::String::append( const char *pData, long nStart, long nLen ) +{ + if( !pData ) return; + if( nLen <= 0 ) + return; + + pData += nStart; + + _hardCopy(); + + if( core->pLast && core->pLast->nLength < nMinSize ) + { + int nAmnt = nMinSize - core->pLast->nLength; + if( nAmnt > nLen ) + nAmnt = nLen; + memcpy( + 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 ); + memcpy( pNew->pData, pData, nLen ); + core->appendChunk( pNew ); +// core->nLength += nLen; + } +} + +void Bu::String::append( const char &cData ) +{ + if( core->pLast && core->pLast->nLength < nMinSize ) + { + _hardCopy(); + core->pLast->pData[core->pLast->nLength] = cData; + ++core->pLast->nLength; ++core->nLength; +// pLast->pData[pLast->nLength] = (char)0; + } + else + { + append( &cData, 1 ); + } +} + +void Bu::String::append( const String & sData ) +{ + append( sData.getStr(), 0, sData.getSize() ); +} + +void Bu::String::append( const String & sData, long nLen ) +{ + append( sData.getStr(), 0, nLen ); +} + +void Bu::String::append( const String & sData, long nStart, long nLen ) +{ + if( nLen < 0 ) + nLen = sData.getSize() - nStart; + append( sData.getStr(), nStart, nLen ); +} + +void Bu::String::append( const const_iterator &s ) +{ + if( !s.isValid() ) + return; + Chunk *pSrc = s.pChunk; + + Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos ); + memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); + + _hardCopy(); + core->appendChunk( pNew ); + + while( (pSrc = pSrc->pNext) ) + { + core->appendChunk( core->copyChunk( pSrc ) ); + } +} + +void Bu::String::append( const iterator &s ) +{ + append( const_iterator( s ) ); +} + +void Bu::String::append( const const_iterator &s, const const_iterator &e ) +{ + if( !s.isValid() ) + return; + if( !e.isValid() ) + { + append( s ); + return; + } + _hardCopy(); + if( s.pChunk == e.pChunk ) + { + // Simple case, they're the same chunk + Chunk *pNew = core->newChunk( e.iPos-s.iPos ); + memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos ); + core->appendChunk( pNew ); + } + else + { + // A little trickier, scan the blocks... + Chunk *pSrc = s.pChunk; + Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos ); + memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); + core->appendChunk( pNew ); + + while( (pSrc = pSrc->pNext) != e.pChunk ) + { + core->appendChunk( core->copyChunk( pSrc ) ); + } + + pNew = core->newChunk( e.iPos ); + memcpy( pNew->pData, pSrc->pData, e.iPos ); + core->appendChunk( pNew ); + } +} + +void Bu::String::prepend( const String & sData ) +{ + prepend( sData.getStr(), sData.getSize() ); +} + +void Bu::String::prepend( const char *pData ) +{ + if( pData == NULL ) + return; + + _hardCopy(); + long nLen; + for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { } + + Chunk *pNew = core->newChunk( nLen ); + memcpy( pNew->pData, pData, nLen ); + + core->prependChunk( pNew ); +} + +void Bu::String::prepend( const char *pData, long nLen ) +{ + Chunk *pNew = core->newChunk( nLen ); + + memcpy( pNew->pData, pData, nLen ); + + _hardCopy(); + core->prependChunk( pNew ); +} + +void Bu::String::prepend( const char c ) +{ + prepend( &c, 1 ); +} + +void Bu::String::insert( long nPos, const char *pData, long nLen ) +{ + if( nLen <= 0 ) + return; + if( nPos <= 0 ) + { + prepend( pData, nLen ); + } + else if( nPos >= core->nLength ) + { + append( pData, nLen ); + } + else + { + // If we're going to flatten anyway, might as well for everyone + flatten(); + _hardCopy(); + Chunk *p1 = core->newChunk( nPos ); + Chunk *p2 = core->newChunk( nLen ); + Chunk *p3 = core->newChunk( core->nLength-nPos ); + memcpy( p1->pData, core->pFirst->pData, nPos ); + memcpy( p2->pData, pData, nLen ); + memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos ); + core->clear(); + core->appendChunk( p1 ); + core->appendChunk( p2 ); + core->appendChunk( p3 ); + } +} + +void Bu::String::insert( long nPos, const String &str ) +{ + if( nPos <= 0 ) + { + prepend( str ); + } + else if( nPos >= core->nLength ) + { + append( str ); + } + else + { + flatten(); + _hardCopy(); + Chunk *p1 = core->newChunk( nPos ); + Chunk *p3 = core->newChunk( core->nLength-nPos ); + memcpy( p1->pData, core->pFirst->pData, nPos ); + memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos ); + core->clear(); + core->appendChunk( p1 ); + for( Chunk *pChnk = str.core->pFirst; pChnk; + pChnk = pChnk->pNext ) + { + core->appendChunk( core->copyChunk( pChnk ) ); + } + + core->appendChunk( p3 ); + } +} + +void Bu::String::insert( long nPos, const char *pData ) +{ + insert( nPos, pData, strlen( pData ) ); +} + +void Bu::String::remove( long nPos, long nLen ) +{ + if( nLen <= 0 || nPos < 0 || nPos >= core->nLength ) + return; + if( nLen > core->nLength-nPos ) + nLen = core->nLength-nPos; + flatten(); + _hardCopy(); + memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 ); + core->nLength -= nLen; + core->pFirst->nLength -= nLen; +} + +void Bu::String::clear() +{ + _hardCopy(); + core->clear(); +} + +Bu::String Bu::String::replace( const Bu::String &fnd, + const Bu::String &rep ) const +{ + String out; + const_iterator o = begin(); + while( true ) + { + const_iterator i = o.find( fnd ); + if( !i ) + { + out.append( o ); + return out; + } + else + { + out.append( o, i ); + out.append( rep ); + o = i; + o += fnd.getSize(); + } + } +} + +void Bu::String::resize( long nNewSize ) +{ + if( core->nLength == nNewSize ) + return; + if( nNewSize < 0 ) + nNewSize = 0; + + flatten(); + _hardCopy(); + + // TODO: This is bad + + Chunk *pNew = core->newChunk( nNewSize ); + long nNewLen = (nNewSizenLength)?(nNewSize):(core->nLength); + if( core->nLength > 0 ) + { + memcpy( pNew->pData, core->pFirst->pData, nNewLen ); + delete[] core->pFirst->pData; + delete core->pFirst; + } + pNew->pData[nNewLen] = (char)0; + core->pFirst = core->pLast = pNew; + core->nLength = nNewSize; +} + +long Bu::String::getSize() const +{ + return core->nLength; +} + +char *Bu::String::getStr() +{ + if( core->pFirst == NULL || core->nLength == 0 ) + return (char *)""; + + flatten(); + _hardCopy(); + core->pFirst->pData[core->nLength] = (char)0; + return core->pFirst->pData; +} + +const char *Bu::String::getStr() const +{ + if( core->pFirst == NULL || core->nLength == 0 ) + return (char *)""; + + flatten(); + core->pFirst->pData[core->nLength] = (char)0; + return core->pFirst->pData; +} + +const char *Bu::String::getConstStr() const +{ + return getStr(); +} + +Bu::String Bu::String::getSubStrIdx( long iStart, long iSize ) const +{ + if( iStart < 0 ) + iStart = 0; + if( iStart >= core->nLength ) + return (const char[]){(char)0}; + if( iSize < 0 ) + iSize = core->nLength; + if( iStart+iSize > core->nLength ) + iSize = core->nLength-iStart; + if( iSize == 0 ) + return (const char[]){(char)0}; + + flatten(); + String ret( core->pFirst->pData+iStart, iSize ); + return ret; +} + +Bu::String Bu::String::getSubStr( const_iterator iBegin, + const_iterator iEnd ) const +{ + if( !iBegin.isValid() ) + return String(); + if( iBegin.pChunk == iEnd.pChunk ) + { + return String( iBegin.pChunk->pData+iBegin.iPos, + iEnd.iPos-iBegin.iPos ); + } + else if( !iEnd.isValid() ) + { + String ret; + ret.append( + iBegin.pChunk->pData+iBegin.iPos, + iBegin.pChunk->nLength-iBegin.iPos + ); + for( Chunk *pCur = iBegin.pChunk->pNext; + pCur; pCur = pCur->pNext ) + { + ret.append( pCur->pData, pCur->nLength ); + } + return ret; + } + else + { + String ret; + ret.append( + iBegin.pChunk->pData+iBegin.iPos, + iBegin.pChunk->nLength-iBegin.iPos + ); + for( Chunk *pCur = iBegin.pChunk->pNext; + pCur != iEnd.pChunk; pCur = pCur->pNext ) + { + ret.append( pCur->pData, pCur->nLength ); + } + ret.append( + iEnd.pChunk->pData, + iEnd.iPos + ); + return ret; + } +} + +Bu::StringList Bu::String::split( const char c ) const +{ + Bu::StringList ret; + const_iterator l, r; + l = begin(); + for(r=l; l;) + { + for( r = l; r && r != c; r++ ) { } + ret.append( String( l, r ) ); + l = r; + l++; + } + return ret; +} + +Bu::String &Bu::String::operator+=( const char *pData ) +{ + append( pData ); + + return (*this); +} + +Bu::String &Bu::String::operator+=( const Bu::String &rSrc ) +{ + append( rSrc ); + + return (*this); +} + +Bu::String &Bu::String::operator+=( const Bu::String::const_iterator &i ) +{ + append( i, i+1 ); + + return (*this); +} + +Bu::String &Bu::String::operator+=( const char cData ) +{ + if( core->pLast && core->pLast->nLength < nMinSize ) + { + _hardCopy(); + core->pLast->pData[core->pLast->nLength] = cData; + ++core->pLast->nLength; ++core->nLength; +// pLast->pData[pLast->nLength] = (char)0; + } + else + { + append( &cData, 1 ); + } + //append( pData ); + + return (*this); +} + +Bu::String &Bu::String::operator=( const char *pData ) +{ + set( pData ); + + return (*this); +} + +Bu::String Bu::String::operator+( const Bu::String &rRight ) const +{ + String ret( *this ); + ret.append( rRight ); + return ret; +} + +Bu::String Bu::String::operator+( const char *pRight ) const +{ + String ret( *this ); + ret.append( pRight ); + return ret; +} + +Bu::String Bu::String::operator+( char *pRight ) const +{ + String ret( *this ); + ret.append( pRight ); + return ret; +} + +void Bu::String::set( const char *pData ) +{ + clear(); + append( pData ); +} + +void Bu::String::set( const char *pData, long nSize ) +{ + clear(); + append( pData, nSize ); +} + +void Bu::String::set( const char *pData, long nStart, long nSize ) +{ + clear(); + append( pData, nStart, nSize ); +} + +void Bu::String::set( const String &rData ) +{ + clear(); + append( rData ); +} + +void Bu::String::set( const String &rData, long nSize ) +{ + clear(); + append( rData, nSize ); +} + +void Bu::String::set( const String &rData, long nStart, long nSize ) +{ + clear(); + append( rData, nStart, nSize ); +} + +void Bu::String::set( const_iterator s ) +{ + clear(); + append( s ); +} + +void Bu::String::set( const_iterator s, const_iterator e ) +{ + clear(); + append( s, e ); +} + +void Bu::String::setSize( long iSize ) +{ + _hardCopy(); + core->clear(); + core->appendChunk( core->newChunk( iSize ) ); +} + +bool Bu::String::operator==( const char *pData ) const +{ + if( core->pFirst == NULL || core->nLength == 0 ) { + if( pData == NULL ) + return true; + if( pData[0] == (char)0 ) + return true; + return false; + } + + flatten(); + core->pFirst->pData[core->nLength] = (char)0; + const char *a = pData; + char *b = core->pFirst->pData; + for( long j = 0; *a!=(char)0 || *b!=(char)0; j++, a++, b++ ) + { + if( *a != *b ) + return false; + if( *a == (char)0 && j < core->nLength ) + return false; + } + + return true; +} + +bool Bu::String::operator==( const String &pData ) const +{ + if( core == pData.core ) + return true; + if( core->pFirst == pData.core->pFirst ) + return true; + if( (core->nLength == 0 && pData.core->nLength == 0) ) + return true; + if( core->nLength != pData.core->nLength ) + return false; + if( pData.core->pFirst == NULL || core->pFirst == NULL ) + return false; + + flatten(); + pData.flatten(); + const char *a = pData.core->pFirst->pData; + char *b = core->pFirst->pData; + for( long j = 0; j < core->nLength; j++, a++, b++ ) + { + if( *a != *b ) + return false; + } + + return true; +} + +bool Bu::String::operator!=(const char *pData ) const +{ + return !(*this == pData); +} + +bool Bu::String::operator!=(const String &pData ) const +{ + return !(*this == pData); +} + +bool Bu::String::operator<(const String &pData ) const +{ + flatten(); + pData.flatten(); + + const char *a = core->pFirst->pData; + char *b = pData.core->pFirst->pData; + for( long j = 0; j < core->nLength; j++, a++, b++ ) + { + if( *a != *b ) + return *a < *b; + } + + return false; +} + +bool Bu::String::operator<=(const String &pData ) const +{ + flatten(); + pData.flatten(); + + const char *a = core->pFirst->pData; + char *b = pData.core->pFirst->pData; + for( long j = 0; j < core->nLength; j++, a++, b++ ) + { + if( *a != *b ) + return *a < *b; + } + + return true; +} + +bool Bu::String::operator>(const String &pData ) const +{ + flatten(); + pData.flatten(); + + const char *a = core->pFirst->pData; + char *b = pData.core->pFirst->pData; + for( long j = 0; j < core->nLength; j++, a++, b++ ) + { + if( *a != *b ) + return *a > *b; + } + + return false; +} + +bool Bu::String::operator>=(const String &pData ) const +{ + flatten(); + pData.flatten(); + + const char *a = core->pFirst->pData; + char *b = pData.core->pFirst->pData; + for( long j = 0; j < core->nLength; j++, a++, b++ ) + { + if( *a != *b ) + return *a > *b; + } + + return true; +} + +char &Bu::String::operator[]( long nIndex ) +{ + if( nIndex < 0 || nIndex >= core->nLength ) + throw Bu::ExceptionBase("Index out of range."); + flatten(); + _hardCopy(); + + return core->pFirst->pData[nIndex]; +} + +const char &Bu::String::operator[]( long nIndex ) const +{ + if( nIndex < 0 || nIndex >= core->nLength ) + throw Bu::ExceptionBase("Index out of range."); + flatten(); + + return core->pFirst->pData[nIndex]; +} + +bool Bu::String::isSet() const +{ + return (core->pFirst != NULL); +} + +bool Bu::String::compareSub( const char *pData, long nIndex, long nLen ) const +{ + if( core->pFirst == NULL || core->nLength == 0 ) { + if( pData == NULL ) + return true; + if( nLen == 0 ) + return true; + if( pData[0] == (char)0 ) + return true; + return false; + } + if( nIndex+nLen > core->nLength ) + return false; + + flatten(); + core->pFirst->pData[core->nLength] = (char)0; + const char *a = pData; + char *b = core->pFirst->pData+nIndex; + for( long j = 0; j < nLen; j++, a++, b++ ) + { + if( *a != *b ) + return false; + if( *a == (char)0 && j < core->nLength ) + return false; + } + + return true; +} + +bool Bu::String::compareSub( const String &rData, long nIndex, long nLen ) const +{ + if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 ) + return false; + if( nLen < 0 ) + nLen = rData.core->nLength; + if( nIndex+nLen > core->nLength ) + return false; + + flatten(); + rData.flatten(); + const char *a = rData.core->pFirst->pData; + char *b = core->pFirst->pData + nIndex; + for( long j = 0; j < nLen; j++, a++, b++ ) + { + if( *a != *b ) + return false; + } + + return true; +} + +bool Bu::String::isWS( long nIndex ) const +{ + flatten(); + + return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t' + || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n'; +} + +bool Bu::String::isAlpha( long nIndex ) const +{ + flatten(); + + return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z') + || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z'); +} + +Bu::String Bu::String::toLower() const +{ + Bu::String sRet = *this; + + sRet.flatten(); + sRet._hardCopy(); + + for( long j = 0; j < sRet.core->nLength; j++ ) + { + if( sRet.core->pFirst->pData[j] >= 'A' && + sRet.core->pFirst->pData[j] <= 'Z' ) + sRet.core->pFirst->pData[j] -= 'A'-'a'; + } + + return sRet; +} + +Bu::String Bu::String::toUpper() const +{ + Bu::String sRet = *this; + + sRet.flatten(); + sRet._hardCopy(); + + for( long j = 0; j < sRet.core->nLength; j++ ) + { + if( sRet.core->pFirst->pData[j] >= 'a' && + sRet.core->pFirst->pData[j] <= 'z' ) + sRet.core->pFirst->pData[j] += 'A'-'a'; + } + + return sRet; +} + +Bu::String::const_iterator Bu::String::find( const char cChar, + Bu::String::const_iterator iStart ) const +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( cChar == *iStart ) + return iStart; + } + return end(); +} + +Bu::String::const_iterator Bu::String::find( const char *sText, int nLen, + Bu::String::const_iterator iStart ) const +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( iStart.compare( sText, nLen ) ) + return iStart; + } + return end(); +} + +Bu::String::const_iterator Bu::String::find( const String &rStr, + Bu::String::const_iterator iStart ) const +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( iStart.compare( rStr ) ) + return iStart; + } + return end(); +} + +Bu::String::const_iterator Bu::String::find( const String &rStr, int nLen, + Bu::String::const_iterator iStart ) const +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( iStart.compare( rStr, nLen ) ) + return iStart; + } + return end(); +} + +Bu::String::iterator Bu::String::find( const char cChar, + Bu::String::const_iterator iStart ) +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( cChar == *iStart ) + return iterator( iStart.pChunk, iStart.iPos ); + } + return end(); +} + +Bu::String::iterator Bu::String::find( const char *sText, int nLen, + Bu::String::const_iterator iStart ) +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( iStart.compare( sText, nLen ) ) + return iterator( iStart.pChunk, iStart.iPos ); + } + return end(); +} + +Bu::String::iterator Bu::String::find( const String &rStr, + Bu::String::const_iterator iStart ) +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( iStart.compare( rStr ) ) + return iterator( iStart.pChunk, iStart.iPos ); + } + return end(); +} + +Bu::String::iterator Bu::String::find( const String &rStr, int nLen, + Bu::String::const_iterator iStart ) +{ + if( !iStart ) iStart = begin(); + for( ; iStart; iStart++ ) + { + if( iStart.compare( rStr, nLen ) ) + return iterator( iStart.pChunk, iStart.iPos ); + } + return end(); +} + +long Bu::String::findIdx( const char cChar, long iStart ) const +{ + flatten(); + for( long j = iStart; j < core->pFirst->nLength; j++ ) + { + if( core->pFirst->pData[j] == cChar ) + return j; + } + return -1; +} + +long Bu::String::findIdx( const char *sText, long iStart ) const +{ + long nTLen = strlen( sText ); + flatten(); + for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ ) + { + if( !strncmp( sText, core->pFirst->pData+j, nTLen ) ) + return j; + } + return -1; +} + +long Bu::String::rfindIdx( const char *sText ) const +{ + long nTLen = strlen( sText ); + flatten(); + for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- ) + { + if( !strncmp( sText, core->pFirst->pData+j, nTLen ) ) + return j; + } + return -1; +} + +void Bu::String::trimFront( long nAmnt ) +{ + long nNewLen = core->nLength - nAmnt; + flatten(); + Chunk *pNew = core->newChunk( nNewLen ); + memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen ); + _hardCopy(); + core->clear(); + core->appendChunk( pNew ); +} + +void Bu::String::trimBack( char c ) +{ + if( core->pFirst == NULL || core->nLength == 0 ) + return; + flatten(); + for( ; core->pFirst->nLength > 0 && + core->pFirst->pData[core->pFirst->nLength-1] == c; + core->pFirst->nLength--, core->nLength-- ) { } +} + +Bu::String::iterator Bu::String::begin() +{ + if( core->nLength == 0 ) + return iterator( NULL, 0 ); + return iterator( core->pFirst, 0 ); +} + +Bu::String::const_iterator Bu::String::begin() const +{ + if( core->nLength == 0 ) + return const_iterator( NULL, 0 ); + return iterator( core->pFirst, 0 ); +} + +Bu::String::iterator Bu::String::end() +{ + return iterator( NULL, 0 ); +} + +Bu::String::const_iterator Bu::String::end() const +{ + return const_iterator( NULL, 0 ); +} + +bool Bu::String::isEmpty() const +{ + if( core->nLength == 0 ) + return true; + return false; +} + +void Bu::String::flatten() const +{ + if( isFlat() ) + return; + + if( core->pFirst == NULL || core->nLength == 0 ) + return; + + Chunk *pNew = core->newChunk( core->nLength ); + char *pos = pNew->pData; + Chunk *i = core->pFirst; + for(;;) + { + memcpy( pos, i->pData, i->nLength ); + pos += i->nLength; + i = i->pNext; + if( i == NULL ) + break; + } + core->clear(); + + core->pLast = core->pFirst = pNew; + core->nLength = pNew->nLength; +} + +bool Bu::String::isFlat() const +{ + return (core->pFirst == core->pLast); +} + +// +// Sub-class Bu::String::FormatProxy +// + +Bu::String::FormatProxy::FormatProxy( const String &rFmt ) : + rFmt( rFmt ) +{ +} + +Bu::String::FormatProxy::~FormatProxy() +{ +} + +Bu::String::FormatProxy::operator Bu::String() const +{ + int iCount = lArgs.getSize(); + ArgList::const_iterator *aArg = + new ArgList::const_iterator[iCount]; + { + int j = 0; + for( ArgList::const_iterator i = lArgs.begin(); + i; i++, j++ ) + { + aArg[j] = i; + } + } + Bu::MemBuf mbOut; + Bu::Formatter f( mbOut ); + for( String::const_iterator s = rFmt.begin(); s; s++ ) + { + if( *s == '%' ) + { + s++; + if( *s == '%' ) + f << *s; + else + { + String sNum; + while( s && *s >= '0' && *s <= '9' ) + { + sNum += *s; + s++; + } + int iIndex = strtol( sNum.getStr(), 0, 10 )-1; + if( iIndex < 0 || iIndex >= iCount ) + { + delete[] aArg; + throw Bu::ExceptionBase( + "Argument index %d is outside of " + "valid range (1-%d).", iIndex+1, iCount + ); + } + + f << (*aArg[iIndex]).format << (*aArg[iIndex]).value; + if( s ) + f << *s; + } + } + else + { + f << *s; + } + } + + delete[] aArg; + return mbOut.getString(); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -template class Bu::BasicString; template<> uint32_t Bu::__calcHashCode( const Bu::String &k ) { @@ -126,3 +1402,20 @@ Bu::String &Bu::operator<<( Bu::String &dst, const Bu::String &sIn ) return dst; } +Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, const Bu::String &s ) +{ + long n = s.getSize(); + ar << n; + ar.write( s.getConstStr(), n ); + return ar; +} + +Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, Bu::String &s ) +{ + long n; + ar >> n; + s.setSize( n ); + ar.read( s.getStr(), n ); + return ar; +} + diff --git a/src/string.h b/src/string.h index 8583558..59a2cd1 100644 --- a/src/string.h +++ b/src/string.h @@ -20,227 +20,63 @@ #include "bu/exceptionbase.h" #include "bu/archivebase.h" #include "bu/list.h" +#include "bu/fmt.h" +#include "bu/variant.h" -#include +#include + +#define nMinSize (256) namespace Bu { - /** @cond DEVEL */ - template< typename chr > - struct StringChunk - { - long nLength; - chr *pData; - StringChunk *pNext; - }; - - template< typename chr, int nMinSize, typename chralloc, - typename chunkalloc> class BasicString; - - 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 ); - } + class String; - template - struct StringCore + /** @cond DEVEL */ + class StringCore { - friend class BasicString; - friend class SharedCore< - BasicString, - StringCore - >; + friend class String; + friend class SharedCore; private: - typedef struct StringCore MyType; - typedef struct StringChunk Chunk; - StringCore() : - nLength( 0 ), - pFirst( NULL ), - pLast( NULL ) - { - } - - StringCore( const MyType &rSrc ) : - nLength( rSrc.nLength ), - pFirst( NULL ), - pLast( NULL ), - aChr( rSrc.aChr ), - aChunk( rSrc.aChunk ) + struct Chunk { - if( rSrc.pFirst == NULL || rSrc.nLength == 0 ) - { - pFirst = pLast = NULL; - } - else - { - pFirst = pLast = newChunk( nLength ); - Chunk *pLink = rSrc.pFirst; - int iPos = 0; - while( pLink != NULL ) - { - memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength ); - iPos += pLink->nLength; - pLink = pLink->pNext; - } - } - } + long nLength; + char *pData; + Chunk *pNext; + }; - virtual ~StringCore() - { - clear(); - } + StringCore(); + StringCore( const StringCore &rSrc ); + virtual ~StringCore(); mutable long nLength; mutable Chunk *pFirst; mutable Chunk *pLast; - mutable chralloc aChr; - mutable chunkalloc aChunk; - - void clear() const - { - if( pFirst == NULL ) - return; - - Chunk *i = pFirst; - for(;;) - { - Chunk *n = i->pNext; - aChr.deallocate( i->pData, - (i->nLengthnLength)+1 ); - aChunk.deallocate( i, 1 ); - if( n == NULL ) - break; - i = n; - } - pFirst = pLast = NULL; - nLength = 0; - } - - Chunk *newChunk() const - { - Chunk *pNew = aChunk.allocate( 1 ); - pNew->pNext = NULL; - return pNew; - } - - Chunk *newChunk( long nLen ) const - { - Chunk *pNew = aChunk.allocate( 1 ); - pNew->pNext = NULL; - pNew->nLength = nLen; - pNew->pData = aChr.allocate( (nLenpData[nLen] = (chr)0; - return pNew; - } - - Chunk *copyChunk( Chunk *pSrc ) const - { - Chunk *pNew = aChunk.allocate( 1 ); - pNew->pNext = pSrc->pNext; - pNew->nLength = pSrc->nLength; - pNew->pData = aChr.allocate( - (pNew->nLengthnLength)+1 ); - memcpy( pNew->pData, pSrc->pData, pSrc->nLength ); - pNew->pData[pNew->nLength] = (chr)0; - return pNew; - } - - void appendChunk( Chunk *pNewChunk ) - { - if( pFirst == NULL ) - pLast = pFirst = pNewChunk; - else - { - pLast->pNext = pNewChunk; - pLast = pNewChunk; - } - - nLength += pNewChunk->nLength; - } - - void prependChunk( Chunk *pNewChunk ) - { - if( pFirst == NULL ) - pLast = pFirst = pNewChunk; - else - { - pNewChunk->pNext = pFirst; - pFirst = pNewChunk; - } - - nLength += pNewChunk->nLength; - } + void clear() const; + Chunk *newChunk() const; + Chunk *newChunk( long nLen ) const; + Chunk *copyChunk( Chunk *pSrc ) const; + void appendChunk( Chunk *pNewChunk ); + void prependChunk( Chunk *pNewChunk ); }; /** @endcond */ /** - * Flexible String class. This class was designed with string passing and - * generation in mind. Like the standard string class you can specify what - * datatype to use for each character. Unlike the standard string class, - * collection of appended and prepended terms is done lazily, making long - * operations that involve many appends very inexpensive. In addition - * internal ref-counting means that if you pass strings around between - * functions there's almost no overhead in time or memory since a reference - * is created and no data is actually copied. This also means that you - * never need to put any BasicString into a ref-counting container class. - * - *@param chr (typename) Type of character (i.e. char) - *@param nMinSize (int) Chunk size (default: 256) - *@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 BasicString : public SharedCore< - BasicString, - StringCore > + class String : public SharedCore { protected: - typedef struct StringChunk Chunk; - typedef struct BasicString MyType; - typedef struct StringCore Core; + using SharedCore::core; + using SharedCore::_hardCopy; - using SharedCore::core; - using SharedCore::_hardCopy; + private: + typedef StringCore::Chunk Chunk; public: // Iterators struct iterator; typedef struct const_iterator { - friend class BasicString; + friend class String; friend struct iterator; private: const_iterator( Chunk *pChunk, int iPos ) : @@ -334,19 +170,19 @@ namespace Bu return ret; } - const chr &operator *() const + const char &operator *() const { if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator."); return pChunk->pData[iPos]; } - bool operator==( const chr &c ) const + bool operator==( const char &c ) const { if( !pChunk ) return false; return pChunk->pData[iPos] == c; } - bool operator!=( const chr &c ) const + bool operator!=( const char &c ) const { if( !pChunk ) return false; return pChunk->pData[iPos] != c; @@ -390,7 +226,7 @@ namespace Bu return true; } - bool compare( const chr *c ) const + bool compare( const char *c ) const { if( !pChunk ) return false; const_iterator a = *this; @@ -399,12 +235,12 @@ namespace Bu if( *a != *c ) return false; } - if( a.isValid() != (*c!=(chr)0) ) + if( a.isValid() != (*c!=(char)0) ) return false; return true; } - bool compare( const chr *c, int nLen ) const + bool compare( const char *c, int nLen ) const { if( !pChunk ) return false; const_iterator a = *this; @@ -419,19 +255,19 @@ namespace Bu return true; } - bool compare( const MyType &s ) const + bool compare( const String &s ) const { if( !pChunk ) return false; return compare( s.begin() ); } - bool compare( const MyType &s, int nLen ) const + bool compare( const String &s, int nLen ) const { if( !pChunk ) return false; return compare( s.begin(), nLen ); } - const_iterator find( const chr c ) const + const_iterator find( const char c ) const { for( const_iterator i = *this; i; i++ ) { @@ -441,7 +277,7 @@ namespace Bu return const_iterator( NULL, 0 ); } - const_iterator find( const chr *pStr, int nLen ) const + const_iterator find( const char *pStr, int nLen ) const { for( const_iterator i = *this; i; i++ ) { @@ -451,7 +287,7 @@ namespace Bu return const_iterator( NULL, 0 ); } - const_iterator find( const MyType &s ) const + const_iterator find( const String &s ) const { for( const_iterator i = *this; i; i++ ) { @@ -461,7 +297,7 @@ namespace Bu return const_iterator( NULL, 0 ); } - const_iterator find( const MyType &s, int nLen ) const + const_iterator find( const String &s, int nLen ) const { for( const_iterator i = *this; i; i++ ) { @@ -474,7 +310,7 @@ namespace Bu typedef struct iterator { - friend class BasicString; + friend class String; friend struct const_iterator; private: iterator( Chunk *pChunk, int iPos ) : @@ -567,31 +403,31 @@ namespace Bu return ret; } - chr &operator*() + char &operator*() { if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); return pChunk->pData[iPos]; } - const chr &operator*() const + const char &operator*() const { if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); return pChunk->pData[iPos]; } - bool operator==( const chr &c ) const + bool operator==( const char &c ) const { if( !pChunk ) return false; return pChunk->pData[iPos] == c; } - bool operator!=( const chr &c ) const + bool operator!=( const char &c ) const { if( !pChunk ) return false; return pChunk->pData[iPos] != c; } - iterator &operator=( const chr &c ) + iterator &operator=( const char &c ) { if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); pChunk->pData[iPos] = c; @@ -636,7 +472,7 @@ namespace Bu return true; } - bool compare( const chr *c ) const + bool compare( const char *c ) const { if( !pChunk ) return false; iterator a = *this; @@ -645,12 +481,12 @@ namespace Bu if( *a != *c ) return false; } - if( a.isValid() != (*c!=(chr)0) ) + if( a.isValid() != (*c!=(char)0) ) return false; return true; } - bool compare( const chr *c, int nLen ) const + bool compare( const char *c, int nLen ) const { if( !pChunk ) return false; iterator a = *this; @@ -665,19 +501,19 @@ namespace Bu return true; } - bool compare( const MyType &s ) const + bool compare( const String &s ) const { if( !pChunk ) return false; return compare( s.begin() ); } - bool compare( const MyType &s, int nLen ) const + bool compare( const String &s, int nLen ) const { if( !pChunk ) return false; return compare( s.begin(), nLen ); } - iterator find( const chr c ) const + iterator find( const char c ) const { for( iterator i = *this; i; i++ ) { @@ -687,7 +523,7 @@ namespace Bu return iterator( NULL, 0 ); } - iterator find( const chr *pStr, int nLen ) const + iterator find( const char *pStr, int nLen ) const { for( iterator i = *this; i; i++ ) { @@ -697,7 +533,7 @@ namespace Bu return iterator( NULL, 0 ); } - iterator find( const MyType &s ) const + iterator find( const String &s ) const { for( iterator i = *this; i; i++ ) { @@ -707,7 +543,7 @@ namespace Bu return iterator( NULL, 0 ); } - iterator find( const MyType &s, int nLen ) const + iterator find( const String &s, int nLen ) const { for( iterator i = *this; i; i++ ) { @@ -719,711 +555,232 @@ namespace Bu } iterator; public: - BasicString() - { - } - - BasicString( const chr *pData ) - { - append( pData ); - } - - BasicString( const chr *pData, long nLength ) - { - append( pData, nLength ); - } - - BasicString( const MyType &rSrc ) : - SharedCore( rSrc ) - { - } - - BasicString( const MyType &rSrc, long nLength ) - { - append( rSrc, nLength ); - } - - BasicString( const MyType &rSrc, long nStart, long nLength ) - { - append( rSrc, nStart, nLength ); - } - - BasicString( long nSize ) - { - core->pFirst = core->pLast = core->newChunk( nSize ); - core->nLength = nSize; - } - - BasicString( const const_iterator &s ) - { - append( s ); - } - - BasicString( const const_iterator &s, const const_iterator &e ) - { - append( s, e ); - } - - virtual ~BasicString() - { - } + String(); + String( const char *pData ); + String( const char *pData, long nLength ); + String( const String &rSrc ); + String( const String &rSrc, long nLength ); + String( const String &rSrc, long nStart, long nLength ); + String( long nSize ); + String( const const_iterator &s ); + String( const const_iterator &s, const const_iterator &e ); + virtual ~String(); /** * Append data to your string. - *@param pData (const chr *) The data to append. + *@param pData (const char *) The data to append. */ - void append( const chr *pData ) - { - if( !pData ) return; - long nLen; - for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } - - append( pData, 0, nLen ); - } + void append( const char *pData ); /** * Append data to your string. - *@param pData (const chr *) The data to append. + *@param pData (const char *) The data to append. *@param nLen (long) The length of the data to append. */ - void append( const chr *pData, long nLen ) - { - append( pData, 0, nLen ); - } + void append( const char *pData, long nLen ); /** * Append data to your string. - *@param pData (const chr *) The data to append. + *@param pData (const char *) The data to append. *@param nStart (long) The start position to copy from. *@param nLen (long) The length of the data to append. */ - void append( const chr *pData, long nStart, long nLen ) - { - if( !pData ) return; - if( nLen <= 0 ) - return; - - pData += nStart; - - _hardCopy(); - - if( core->pLast && core->pLast->nLength < nMinSize ) - { - int nAmnt = nMinSize - core->pLast->nLength; - if( nAmnt > nLen ) - nAmnt = nLen; - memcpy( - 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 ); - memcpy( pNew->pData, pData, nLen ); - core->appendChunk( pNew ); -// core->nLength += nLen; - } - } + void append( const char *pData, long nStart, long nLen ); /** - * Append a single chr to your string. - *@param cData (const chr &) The character to append. + * Append a single char to your string. + *@param cData (const char &) The character to append. */ - void append( const chr &cData ) - { - if( core->pLast && core->pLast->nLength < nMinSize ) - { - _hardCopy(); - core->pLast->pData[core->pLast->nLength] = cData; - ++core->pLast->nLength; ++core->nLength; - // pLast->pData[pLast->nLength] = (chr)0; - } - else - { - append( &cData, 1 ); - } - } + void append( const char &cData ); /** * Append another String to this one. - *@param sData (MyType &) The String to append. + *@param sData (String &) The String to append. *@todo This function can be made much faster by not using getStr() */ - void append( const MyType & sData ) - { - append( sData.getStr(), 0, sData.getSize() ); - } + void append( const String & sData ); /** * Append another String to this one. - *@param sData (MyType &) The String to append. + *@param sData (String &) The String to append. *@param nLen How much data to append. *@todo This function can be made much faster by not using getStr() */ - void append( const MyType & sData, long nLen ) - { - append( sData.getStr(), 0, nLen ); - } + void append( const String & sData, long nLen ); /** * Append another String to this one. - *@param sData (MyType &) The String to append. + *@param sData (String &) The String to append. *@param nStart Start position in sData to start copying from. *@param nLen How much data to append. *@todo This function can be made much faster by not using getStr() */ - void append( const MyType & sData, long nStart, long nLen ) - { - if( nLen < 0 ) - nLen = sData.getSize() - nStart; - append( sData.getStr(), nStart, nLen ); - } + void append( const String & sData, long nStart, long nLen ); /** * Append data to this String using the passed in iterator as a base. * The iterator is const, it is not changed. - *@param s Iterator from any compatible BasicString to copy data from. + *@param s Iterator from any compatible String to copy data from. */ - void append( const const_iterator &s ) - { - if( !s.isValid() ) - return; - Chunk *pSrc = s.pChunk; - - Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos ); - memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); - - _hardCopy(); - core->appendChunk( pNew ); - - while( (pSrc = pSrc->pNext) ) - { - core->appendChunk( core->copyChunk( pSrc ) ); - } - } + void append( const const_iterator &s ); /** * Append data to this String using the passed in iterator as a base. * The iterator is const, it is not changed. - *@param s Iterator from any compatible BasicString to copy data from. + *@param s Iterator from any compatible String to copy data from. */ - void append( const iterator &s ) // I get complaints without this one - { - append( const_iterator( s ) ); - } + void append( const iterator &s ); /** * Append data to this String using the passed in iterator as a base, * and copy data until the ending iterator is reached. The character * at the ending iterator is not copied. * The iterators are const, they are not changed. - *@param s Iterator from any compatible BasicString to copy data from. + *@param s Iterator from any compatible String to copy data from. *@param e Iterator to stop copying at. */ - void append( const const_iterator &s, const const_iterator &e ) - { - if( !s.isValid() ) - return; - if( !e.isValid() ) - { - append( s ); - return; - } - _hardCopy(); - if( s.pChunk == e.pChunk ) - { - // Simple case, they're the same chunk - Chunk *pNew = core->newChunk( e.iPos-s.iPos ); - memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos ); - core->appendChunk( pNew ); - } - else - { - // A little trickier, scan the blocks... - Chunk *pSrc = s.pChunk; - Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos ); - memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); - core->appendChunk( pNew ); - - while( (pSrc = pSrc->pNext) != e.pChunk ) - { - core->appendChunk( core->copyChunk( pSrc ) ); - } - - pNew = core->newChunk( e.iPos ); - memcpy( pNew->pData, pSrc->pData, e.iPos ); - core->appendChunk( pNew ); - } - } + void append( const const_iterator &s, const const_iterator &e ); /** * Prepend another String to this one. - *@param sData (MyType &) The String to prepend. + *@param sData (String &) The String to prepend. *@todo This function can be made much faster by not using getStr() */ - void prepend( const MyType & sData ) - { - prepend( sData.getStr(), sData.getSize() ); - } + void prepend( const String & sData ); /** * Prepend data to your string. - *@param pData (const chr *) The data to prepend. + *@param pData (const char *) The data to prepend. */ - void prepend( const chr *pData ) - { - if( pData == NULL ) - return; - - _hardCopy(); - long nLen; - for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } - - Chunk *pNew = core->newChunk( nLen ); - memcpy( pNew->pData, pData, nLen ); - - core->prependChunk( pNew ); - } + void prepend( const char *pData ); /** * Prepend data to your string. - *@param pData (const chr *) The data to prepend. + *@param pData (const char *) The data to prepend. *@param nLen (long) The length of the data to prepend. */ - void prepend( const chr *pData, long nLen ) - { - Chunk *pNew = core->newChunk( nLen ); - - memcpy( pNew->pData, pData, nLen ); - - _hardCopy(); - core->prependChunk( pNew ); - } + void prepend( const char *pData, long nLen ); - void prepend( const chr c ) - { - prepend( &c, 1 ); - } + void prepend( const char c ); /** * Insert pData before byte nPos, that is, the first byte of pData will * start at nPos. This could probably be made faster by avoiding * flattening. */ - void insert( long nPos, const chr *pData, long nLen ) - { - if( nLen <= 0 ) - return; - if( nPos <= 0 ) - { - prepend( pData, nLen ); - } - else if( nPos >= core->nLength ) - { - append( pData, nLen ); - } - else - { - // If we're going to flatten anyway, might as well for everyone - flatten(); - _hardCopy(); - Chunk *p1 = core->newChunk( nPos ); - Chunk *p2 = core->newChunk( nLen ); - Chunk *p3 = core->newChunk( core->nLength-nPos ); - memcpy( p1->pData, core->pFirst->pData, nPos ); - memcpy( p2->pData, pData, nLen ); - memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos ); - core->clear(); - core->appendChunk( p1 ); - core->appendChunk( p2 ); - core->appendChunk( p3 ); - } - } - - void insert( long nPos, const MyType &str ) - { - if( nPos <= 0 ) - { - prepend( str ); - } - else if( nPos >= core->nLength ) - { - append( str ); - } - else - { - flatten(); - _hardCopy(); - Chunk *p1 = core->newChunk( nPos ); - Chunk *p3 = core->newChunk( core->nLength-nPos ); - memcpy( p1->pData, core->pFirst->pData, nPos ); - memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos ); - core->clear(); - core->appendChunk( p1 ); - for( Chunk *pChnk = str.core->pFirst; pChnk; - pChnk = pChnk->pNext ) - { - core->appendChunk( core->copyChunk( pChnk ) ); - } + void insert( long nPos, const char *pData, long nLen ); - core->appendChunk( p3 ); - } - } + void insert( long nPos, const String &str ); /** *@todo This function shouldn't use strlen, we should add our own to * this class, one that can be overridden in a specific implementation. */ - void insert( long nPos, const chr *pData ) - { - insert( nPos, pData, Bu::strlen( pData ) ); - } + void insert( long nPos, const char *pData ); - void remove( long nPos, long nLen ) - { - if( nLen <= 0 || nPos < 0 || nPos >= core->nLength ) - return; - if( nLen > core->nLength-nPos ) - nLen = core->nLength-nPos; - flatten(); - _hardCopy(); - memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 ); - core->nLength -= nLen; - core->pFirst->nLength -= nLen; - } + void remove( long nPos, long nLen ); /** * Clear all data from the string. */ - void clear() - { - _hardCopy(); - core->clear(); - } + void clear(); - MyType replace( const MyType &fnd, const MyType &rep ) const - { - MyType out; - const_iterator o = begin(); - while( true ) - { - const_iterator i = o.find( fnd ); - if( !i ) - { - out.append( o ); - return out; - } - else - { - out.append( o, i ); - out.append( rep ); - o = i; - o += fnd.getSize(); - } - } - } + String replace( const String &fnd, const String &rep ) const; /** * Force the string to resize *@param nNewSize (long) The new size of the string. */ - void resize( long nNewSize ) - { - if( core->nLength == nNewSize ) - return; - if( nNewSize < 0 ) - nNewSize = 0; - - flatten(); - _hardCopy(); - - // TODO: This is bad - - Chunk *pNew = core->newChunk( nNewSize ); - long nNewLen = (nNewSizenLength)?(nNewSize):(core->nLength); - if( core->nLength > 0 ) - { - memcpy( pNew->pData, core->pFirst->pData, nNewLen ); - core->aChr.deallocate( core->pFirst->pData, - (core->pFirst->nLengthpFirst->nLength)+1 ); - core->aChunk.deallocate( core->pFirst, 1 ); - } - pNew->pData[nNewLen] = (chr)0; - core->pFirst = core->pLast = pNew; - core->nLength = nNewSize; - } + void resize( long nNewSize ); /** * Get the current size of the string. *@returns (long) The current size of the string. */ - long getSize() const - { - return core->nLength; - } + long getSize() const; /** * Get a pointer to the string array. - *@returns (chr *) The string data. + *@returns (char *) The string data. */ - chr *getStr() - { - if( core->pFirst == NULL || core->nLength == 0 ) - return (chr *)""; - - flatten(); - _hardCopy(); - core->pFirst->pData[core->nLength] = (chr)0; - return core->pFirst->pData; - } + char *getStr(); /** * Get a const pointer to the string array. - *@returns (const chr *) The string data. + *@returns (const char *) The string data. */ - const chr *getStr() const - { - if( core->pFirst == NULL || core->nLength == 0 ) - return (chr *)""; - - flatten(); - core->pFirst->pData[core->nLength] = (chr)0; - return core->pFirst->pData; - } + const char *getStr() const; /** * A convinience function, this one won't cause as much work as the * non-const getStr, so if you're not changing the data, consider it. */ - const chr *getConstStr() const - { - return getStr(); - } + const char *getConstStr() const; - MyType getSubStrIdx( long iStart, long iSize=-1 ) const - { - if( iStart < 0 ) - iStart = 0; - if( iStart >= core->nLength ) - return (const chr[]){(chr)0}; - if( iSize < 0 ) - iSize = core->nLength; - if( iStart+iSize > core->nLength ) - iSize = core->nLength-iStart; - if( iSize == 0 ) - return (const chr[]){(chr)0}; - - flatten(); - MyType ret( core->pFirst->pData+iStart, iSize ); - return ret; - } + String getSubStrIdx( long iStart, long iSize=-1 ) const; - MyType getSubStr( const_iterator iBegin, - const_iterator iEnd=typename MyType::const_iterator() ) const - { - if( !iBegin.isValid() ) - return MyType(); - if( iBegin.pChunk == iEnd.pChunk ) - { - return MyType( iBegin.pChunk->pData+iBegin.iPos, - iEnd.iPos-iBegin.iPos ); - } - else if( !iEnd.isValid() ) - { - MyType ret; - ret.append( - iBegin.pChunk->pData+iBegin.iPos, - iBegin.pChunk->nLength-iBegin.iPos - ); - for( Chunk *pCur = iBegin.pChunk->pNext; - pCur; pCur = pCur->pNext ) - { - ret.append( pCur->pData, pCur->nLength ); - } - return ret; - } - else - { - MyType ret; - ret.append( - iBegin.pChunk->pData+iBegin.iPos, - iBegin.pChunk->nLength-iBegin.iPos - ); - for( Chunk *pCur = iBegin.pChunk->pNext; - pCur != iEnd.pChunk; pCur = pCur->pNext ) - { - ret.append( pCur->pData, pCur->nLength ); - } - ret.append( - iEnd.pChunk->pData, - iEnd.iPos - ); - return ret; - } - } + String getSubStr( const_iterator iBegin, + const_iterator iEnd=String::const_iterator() ) const; - Bu::List split( const chr c ) const - { - Bu::List ret; - const_iterator l, r; - l = begin(); - for(r=l; l;) - { - for( r = l; r && r != c; r++ ) { } - ret.append( MyType( l, r ) ); - l = r; - l++; - } - return ret; - } + Bu::List split( const char c ) const; /** * Plus equals operator for String. - *@param pData (const chr *) The data to append to your String. + *@param pData (const char *) The data to append to your String. */ - MyType &operator+=( const chr *pData ) - { - append( pData ); - - return (*this); - } + String &operator+=( const char *pData ); /** * Plus equals operator for String. - *@param rSrc (const MyType &) The String to append to your String. + *@param rSrc (const String &) The String to append to your String. */ - MyType &operator+=( const MyType &rSrc ) - { - append( rSrc ); - - return (*this); - } + String &operator+=( const String &rSrc ); - MyType &operator+=( const MyType::const_iterator &i ) - { - append( i, i+1 ); - - return (*this); - } + String &operator+=( const String::const_iterator &i ); /** * Plus equals operator for String. - *@param cData (const chr) The character to append to your String. + *@param cData (const char) The character to append to your String. */ - MyType &operator+=( const chr cData ) - { - if( core->pLast && core->pLast->nLength < nMinSize ) - { - _hardCopy(); - core->pLast->pData[core->pLast->nLength] = cData; - ++core->pLast->nLength; ++core->nLength; - // pLast->pData[pLast->nLength] = (chr)0; - } - else - { - append( &cData, 1 ); - } - //append( pData ); - - return (*this); - } + String &operator+=( const char cData ); /** * Assignment operator. - *@param pData (const chr *) The character array to append to your + *@param pData (const char *) The character array to append to your * String. */ - MyType &operator=( const chr *pData ) - { - set( pData ); + String &operator=( const char *pData ); - return (*this); - } + String operator+( const String &rRight ) const; - MyType operator+( const MyType &rRight ) const - { - MyType ret( *this ); - ret.append( rRight ); - return ret; - } + String operator+( const char *pRight ) const; - MyType operator+( const chr *pRight ) const - { - MyType ret( *this ); - ret.append( pRight ); - return ret; - } - - MyType operator+( chr *pRight ) const - { - MyType ret( *this ); - ret.append( pRight ); - return ret; - } + String operator+( char *pRight ) const; /** * Reset your String to this character array. - *@param pData (const chr *) The character array to set your String to. + *@param pData (const char *) The character array to set your String to. */ - void set( const chr *pData ) - { - clear(); - append( pData ); - } + void set( const char *pData ); /** * Reset your String to this character array. - *@param pData (const chr *) The character array to set your String to. + *@param pData (const char *) The character array to set your String to. *@param nSize (long) The length of the inputted character array. */ - void set( const chr *pData, long nSize ) - { - clear(); - append( pData, nSize ); - } + void set( const char *pData, long nSize ); - void set( const chr *pData, long nStart, long nSize ) - { - clear(); - append( pData, nStart, nSize ); - } + void set( const char *pData, long nStart, long nSize ); - void set( const MyType &rData ) - { - clear(); - append( rData ); - } + void set( const String &rData ); - void set( const MyType &rData, long nSize ) - { - clear(); - append( rData, nSize ); - } + void set( const String &rData, long nSize ); - void set( const MyType &rData, long nStart, long nSize ) - { - clear(); - append( rData, nStart, nSize ); - } + void set( const String &rData, long nStart, long nSize ); - void set( const_iterator s ) - { - clear(); - append( s ); - } + void set( const_iterator s ); - void set( const_iterator s, const_iterator e ) - { - clear(); - append( s, e ); - } + void set( const_iterator s, const_iterator e ); /** * Resize the string, possibly to make room for a copy. At the moment @@ -1433,453 +790,109 @@ namespace Bu *@param iSize the new size in bytes. The string is guranteed to have * at least this much contiguous space available when done. */ - void setSize( long iSize ) - { - _hardCopy(); - core->clear(); - core->appendChunk( core->newChunk( iSize ) ); - } - - void expand() - { -#ifndef WIN32 - flatten(); - _hardCopy(); - - wordexp_t result; - - /* Expand the string for the program to run. */ - switch (wordexp ((char *)core->pFirst->pData, &result, 0)) - { - case 0: /* Successful. */ - { - set( (chr *)result.we_wordv[0] ); - wordfree( &result ); - return; - } - break; - case WRDE_NOSPACE: - /* If the error was `WRDE_NOSPACE', - then perhaps part of the result was allocated. */ - wordfree (&result); - default: /* Some other error. */ - return; - } -#endif - } - - /** - * Assignment operator. - *@param rSrc (const MyType &) The String to set your String to. - */ - /* MyType &operator=( const MyType &rSrc ) - { - set( rSrc ); + void setSize( long iSize ); - return (*this); - } */ - /** * Equals comparison operator. - *@param pData (const chr *) The character array to compare your String + *@param pData (const char *) The character array to compare your String * to. */ - bool operator==( const chr *pData ) const - { - if( core->pFirst == NULL || core->nLength == 0 ) { - if( pData == NULL ) - return true; - if( pData[0] == (chr)0 ) - return true; - return false; - } - - flatten(); - core->pFirst->pData[core->nLength] = (chr)0; - const chr *a = pData; - chr *b = core->pFirst->pData; - for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ ) - { - if( *a != *b ) - return false; - if( *a == (chr)0 && j < core->nLength ) - return false; - } - - return true; - } + bool operator==( const char *pData ) const; /** * Equals comparison operator. - *@param pData (const MyType &) The String to compare your String to. + *@param pData (const String &) The String to compare your String to. */ - bool operator==( const MyType &pData ) const - { - if( core == pData.core ) - return true; - if( core->pFirst == pData.core->pFirst ) - return true; - if( (core->nLength == 0 && pData.core->nLength == 0) ) - return true; - if( core->nLength != pData.core->nLength ) - return false; - if( pData.core->pFirst == NULL || core->pFirst == NULL ) - return false; - - flatten(); - pData.flatten(); - const chr *a = pData.core->pFirst->pData; - chr *b = core->pFirst->pData; - for( long j = 0; j < core->nLength; j++, a++, b++ ) - { - if( *a != *b ) - return false; - } - - return true; - } + bool operator==( const String &pData ) const; /** * Not equals comparison operator. - *@param pData (const chr *) The character array to compare your String + *@param pData (const char *) The character array to compare your String * to. */ - bool operator!=(const chr *pData ) const - { - return !(*this == pData); - } + bool operator!=(const char *pData ) const; /** * Not equals comparison operator. - *@param pData (const MyType &) The String to compare your String to. + *@param pData (const String &) The String to compare your String to. */ - bool operator!=(const MyType &pData ) const - { - return !(*this == pData); - } - - bool operator<(const MyType &pData ) const - { - flatten(); - pData.flatten(); + bool operator!=(const String &pData ) const; - const chr *a = core->pFirst->pData; - chr *b = pData.core->pFirst->pData; - for( long j = 0; j < core->nLength; j++, a++, b++ ) - { - if( *a != *b ) - return *a < *b; - } - - return false; - } + bool operator<(const String &pData ) const; - bool operator<=(const MyType &pData ) const - { - flatten(); - pData.flatten(); - - const chr *a = core->pFirst->pData; - chr *b = pData.core->pFirst->pData; - for( long j = 0; j < core->nLength; j++, a++, b++ ) - { - if( *a != *b ) - return *a < *b; - } - - return true; - } - - bool operator>(const MyType &pData ) const - { - flatten(); - pData.flatten(); + bool operator<=(const String &pData ) const; - const chr *a = core->pFirst->pData; - chr *b = pData.core->pFirst->pData; - for( long j = 0; j < core->nLength; j++, a++, b++ ) - { - if( *a != *b ) - return *a > *b; - } + bool operator>(const String &pData ) const; - return false; - } - - bool operator>=(const MyType &pData ) const - { - flatten(); - pData.flatten(); - - const chr *a = core->pFirst->pData; - chr *b = pData.core->pFirst->pData; - for( long j = 0; j < core->nLength; j++, a++, b++ ) - { - if( *a != *b ) - return *a > *b; - } - - return true; - } + bool operator>=(const String &pData ) const; /** * Indexing operator *@param nIndex (long) The index of the character you want. - *@returns (chr &) The character at position (nIndex). + *@returns (char &) The character at position (nIndex). */ - chr &operator[]( long nIndex ) - { - if( nIndex < 0 || nIndex >= core->nLength ) - throw Bu::ExceptionBase("Index out of range."); - flatten(); - _hardCopy(); - - return core->pFirst->pData[nIndex]; - } + char &operator[]( long nIndex ); /** * Const indexing operator *@param nIndex (long) The index of the character you want. - *@returns (const chr &) The character at position (nIndex). + *@returns (const char &) The character at position (nIndex). */ - const chr &operator[]( long nIndex ) const - { - if( nIndex < 0 || nIndex >= core->nLength ) - throw Bu::ExceptionBase("Index out of range."); - flatten(); - - return core->pFirst->pData[nIndex]; - } -/* - operator const chr *() const - { - if( !pFirst ) return NULL; - flatten(); - return pFirst->pData; - } - */ - /* - operator bool() const - { - return (core->pFirst != NULL); - } - */ - - bool isSet() const - { - return (core->pFirst != NULL); - } - - bool compareSub( const chr *pData, long nIndex, long nLen ) const - { - if( core->pFirst == NULL || core->nLength == 0 ) { - if( pData == NULL ) - return true; - if( nLen == 0 ) - return true; - if( pData[0] == (chr)0 ) - return true; - return false; - } - if( nIndex+nLen > core->nLength ) - return false; - - flatten(); - core->pFirst->pData[core->nLength] = (chr)0; - const chr *a = pData; - chr *b = core->pFirst->pData+nIndex; - for( long j = 0; j < nLen; j++, a++, b++ ) - { - if( *a != *b ) - return false; - if( *a == (chr)0 && j < core->nLength ) - return false; - } + const char &operator[]( long nIndex ) const; - return true; - } + bool isSet() const; - bool compareSub( const MyType &rData, long nIndex, long nLen ) const - { - if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 ) - return false; - if( nLen < 0 ) - nLen = rData.core->nLength; - if( nIndex+nLen > core->nLength ) - return false; - - flatten(); - rData.flatten(); - const chr *a = rData.core->pFirst->pData; - chr *b = core->pFirst->pData + nIndex; - for( long j = 0; j < nLen; j++, a++, b++ ) - { - if( *a != *b ) - return false; - } + bool compareSub( const char *pData, long nIndex, long nLen ) const; - return true; - } + bool compareSub( const String &rData, long nIndex, long nLen ) const; /** * Is the character at index (nIndex) white space? *@param nIndex (long) The index of the character you want to check. *@returns (bool) Is it white space? */ - bool isWS( long nIndex ) const - { - flatten(); - - return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t' - || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n'; - } + bool isWS( long nIndex ) const; /** * Is the character at index (nIndex) a letter? *@param nIndex (long) The index of the character you want to check. *@returns (bool) Is it a letter? */ - bool isAlpha( long nIndex ) const - { - flatten(); - - return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z') - || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z'); - } + bool isAlpha( long nIndex ) const; /** * Convert your alpha characters to lower case. */ - void toLower() - { - flatten(); - _hardCopy(); - - for( long j = 0; j < core->nLength; j++ ) - { - if( core->pFirst->pData[j] >= 'A' && core->pFirst->pData[j] <= 'Z' ) - core->pFirst->pData[j] -= 'A'-'a'; - } - } + String toLower() const; /** * Convert your alpha characters to upper case. */ - void toUpper() - { - flatten(); - _hardCopy(); - - for( long j = 0; j < core->nLength; j++ ) - { - if( core->pFirst->pData[j] >= 'a' && core->pFirst->pData[j] <= 'z' ) - core->pFirst->pData[j] += 'A'-'a'; - } - } - -// template -// void to( out &dst ); -/* { - flatten(); + String toUpper() const; - dst = strtol( pFirst->pData, NULL, 0 ); - } */ + const_iterator find( const char cChar, + const_iterator iStart=const_iterator() ) const; - const_iterator find( const chr cChar, - const_iterator iStart=typename MyType::const_iterator() ) const - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( cChar == *iStart ) - return iStart; - } - return end(); - } + const_iterator find( const char *sText, int nLen, + const_iterator iStart=const_iterator() ) const; - const_iterator find( const chr *sText, int nLen, - const_iterator iStart=typename MyType::const_iterator() ) const - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( iStart.compare( sText, nLen ) ) - return iStart; - } - return end(); - } - - const_iterator find( const MyType &rStr, - const_iterator iStart=typename MyType::const_iterator() ) const - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( iStart.compare( rStr ) ) - return iStart; - } - return end(); - } + const_iterator find( const String &rStr, + const_iterator iStart=const_iterator() ) const; - const_iterator find( const MyType &rStr, int nLen, - const_iterator iStart=typename MyType::const_iterator() ) const - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( iStart.compare( rStr, nLen ) ) - return iStart; - } - return end(); - } + const_iterator find( const String &rStr, int nLen, + const_iterator iStart=const_iterator() ) const; - iterator find( const chr cChar, - const_iterator iStart=typename MyType::const_iterator() ) - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( cChar == *iStart ) - return iterator( iStart.pChunk, iStart.iPos ); - } - return end(); - } + iterator find( const char cChar, + const_iterator iStart=const_iterator() ); - iterator find( const chr *sText, int nLen, - const_iterator iStart=typename MyType::const_iterator() ) - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( iStart.compare( sText, nLen ) ) - return iterator( iStart.pChunk, iStart.iPos ); - } - return end(); - } + iterator find( const char *sText, int nLen, + const_iterator iStart=const_iterator() ); - iterator find( const MyType &rStr, - const_iterator iStart=typename MyType::const_iterator() ) - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( iStart.compare( rStr ) ) - return iterator( iStart.pChunk, iStart.iPos ); - } - return end(); - } + iterator find( const String &rStr, + const_iterator iStart=const_iterator() ); - iterator find( const MyType &rStr, int nLen, - const_iterator iStart=typename MyType::const_iterator() ) - { - if( !iStart ) iStart = begin(); - for( ; iStart; iStart++ ) - { - if( iStart.compare( rStr, nLen ) ) - return iterator( iStart.pChunk, iStart.iPos ); - } - return end(); - } + iterator find( const String &rStr, int nLen, + const_iterator iStart=const_iterator() ); /** * Find the index of the first occurrance of cChar @@ -1887,16 +900,7 @@ namespace Bu *@param iStart The position in the string to start searching from. *@returns (long) The index of the first occurrance. -1 for not found. */ - long findIdx( const chr cChar, long iStart=0 ) const - { - flatten(); - for( long j = iStart; j < core->pFirst->nLength; j++ ) - { - if( core->pFirst->pData[j] == cChar ) - return j; - } - return -1; - } + long findIdx( const char cChar, long iStart=0 ) const; /** * Find the index of the first occurrance of sText @@ -1904,201 +908,109 @@ namespace Bu *@param iStart The position in the string to start searching from. *@returns The index of the first occurrance. -1 for not found. */ - long findIdx( const chr *sText, long iStart=0 ) const - { - long nTLen = strlen( sText ); - flatten(); - for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ ) - { - if( !strncmp( sText, core->pFirst->pData+j, nTLen ) ) - return j; - } - return -1; - } + long findIdx( const char *sText, long iStart=0 ) const; /** * Do a reverse search for (sText) - *@param sText (const chr *) The string to search for. + *@param sText (const char *) The string to search for. *@returns (long) The index of the last occurrance. -1 for not found. */ - long rfindIdx( const chr *sText ) const - { - long nTLen = strlen( sText ); - flatten(); - for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- ) - { - if( !strncmp( sText, core->pFirst->pData+j, nTLen ) ) - return j; - } - return -1; - } + long rfindIdx( const char *sText ) const; /** * Remove nAmnt bytes from the front of the string. This function * operates in O(n) time and should be used sparingly. */ - void trimFront( long nAmnt ) - { - long nNewLen = core->nLength - nAmnt; - flatten(); - Chunk *pNew = core->newChunk( nNewLen ); - memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen ); - _hardCopy(); - core->clear(); - core->appendChunk( pNew ); - } + void trimFront( long nAmnt ); - void trimBack( chr c ) - { - if( core->pFirst == NULL || core->nLength == 0 ) - return; - flatten(); - for( ; core->pFirst->nLength > 0 && core->pFirst->pData[core->pFirst->nLength-1] == c; core->pFirst->nLength--, core->nLength-- ) { } - } + void trimBack( char c ); - MyType &format( const char *sFrmt, ...) - { - _hardCopy(); - clear(); + iterator begin(); - va_list ap; - va_start( ap, sFrmt ); + const_iterator begin() const; - long iLen = vsnprintf( NULL, 0, sFrmt, ap ); - - Chunk *pNew = core->newChunk( iLen ); - vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); - core->appendChunk( pNew ); + iterator end(); - va_end( ap ); + const_iterator end() const; - return *this; - } - - MyType &formatAppend( const char *sFrmt, ...) - { - _hardCopy(); - va_list ap; - va_start( ap, sFrmt ); - - long iLen = vsnprintf( NULL, 0, sFrmt, ap ); + bool isEmpty() const; - Chunk *pNew = core->newChunk( iLen ); - vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); - core->appendChunk( pNew ); - - va_end( ap ); - - return *this; - } + private: + void flatten() const; + bool isFlat() const; - MyType &formatPrepend( const char *sFrmt, ...) + class FormatProxy { - _hardCopy(); - va_list ap; - va_start( ap, sFrmt ); + public: + FormatProxy( const String &rFmt ); + virtual ~FormatProxy(); - long iLen = vsnprintf( NULL, 0, sFrmt, ap ); - - Chunk *pNew = core->newChunk( iLen ); - vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); - core->prependChunk( pNew ); + template + FormatProxy &arg( const T &x ) + { + lArgs.append( Arg( x ) ); - va_end( ap ); + return *this; + } - return *this; - } + template + FormatProxy &arg( const T &x, const Bu::Fmt &f ) + { + lArgs.append( Arg( x, f ) ); - iterator begin() - { - if( core->nLength == 0 ) - return iterator( NULL, 0 ); - return iterator( core->pFirst, 0 ); - } + return *this; + } - const_iterator begin() const - { - if( core->nLength == 0 ) - return const_iterator( NULL, 0 ); - return iterator( core->pFirst, 0 ); - } + operator String() const; - iterator end() - { - return iterator( NULL, 0 ); - } + private: + const String &rFmt; + class Arg + { + public: + template + Arg( const T &v ) : + value( v ) + { + } - const_iterator end() const - { - return const_iterator( NULL, 0 ); - } + template + Arg( const T &v, const Bu::Fmt &f ) : + value( v ), + format( f ) + { + } - bool isEmpty() const - { - if( core->nLength == 0 ) - return true; - return false; - } + Bu::Variant value; + Bu::Fmt format; + }; + typedef Bu::List ArgList; + ArgList lArgs; + }; - private: - void flatten() const + public: + template + FormatProxy arg( const ArgType &x ) { - if( isFlat() ) - return; - - if( core->pFirst == NULL || core->nLength == 0 ) - return; - - Chunk *pNew = core->newChunk( core->nLength ); - chr *pos = pNew->pData; - Chunk *i = core->pFirst; - for(;;) - { - memcpy( pos, i->pData, i->nLength ); - pos += i->nLength; - i = i->pNext; - if( i == NULL ) - break; - } - core->clear(); - - core->pLast = core->pFirst = pNew; - core->nLength = pNew->nLength; + return FormatProxy( *this ).arg( x ); } - - bool isFlat() const + + template + FormatProxy arg( const ArgType &x, const Bu::Fmt &f ) { - return (core->pFirst == core->pLast); + return FormatProxy( *this ).arg( x, f ); } }; - template BasicString operator+( const T *pLeft, const BasicString &rRight ) + template String operator+( const T *pLeft, const String &rRight ) { - Bu::BasicString ret( pLeft ); + Bu::String ret( pLeft ); ret.append( rRight ); return ret; } - template - ArchiveBase &operator<<( ArchiveBase &ar, const BasicString &s ) - { - long n = s.getSize(); - ar << n; - ar.write( s.getConstStr(), n ); - return ar; - } - - template - ArchiveBase &operator>>( ArchiveBase &ar, BasicString &s ) - { - long n; - ar >> n; - s.setSize( n ); - ar.read( s.getStr(), n ); - return ar; - } - - typedef BasicString String; + ArchiveBase &operator<<( ArchiveBase &ar, const String &s ); + ArchiveBase &operator>>( ArchiveBase &ar, String &s ); template uint32_t __calcHashCode( const T &k ); diff --git a/src/tests/stringspeed.cpp b/src/tests/stringspeed.cpp new file mode 100644 index 0000000..5636de7 --- /dev/null +++ b/src/tests/stringspeed.cpp @@ -0,0 +1,122 @@ +#include + +#include +#include + +void timeit( void (*func)(), const char *sName, int iIter ) +{ + struct timeval ts, te; + + gettimeofday( &ts, NULL ); + for( int j = 0; j < iIter; j++ ) + { + func(); + } + gettimeofday( &te, NULL ); + + double dTotal = (double)(te.tv_sec-ts.tv_sec) + (double)(te.tv_usec-ts.tv_usec)/1000000.0; + printf("%10s: %f spi (%f total)\n", sName, dTotal/iIter, dTotal ); +} + +void append1() +{ + Bu::String sTmp; + for( int c = 0; c < 5000; c++ ) + { + sTmp += (char)(c%256); + } +} + +void append2() +{ + Bu::String sTmp; + for( int c = 0; c < 5000; c++ ) + { + sTmp.append( (char)(c%256) ); + } +} + +void append3() +{ + Bu::String sTmp; + for( int c = 0; c < 5000; c++ ) + { + sTmp += "Test"; + } +} + +void append4() +{ + Bu::String sTmp; + for( int c = 0; c < 5000; c++ ) + { + sTmp.append("Test"); + } +} + +void append5() +{ + Bu::String sTmp, sAdd("Test"); + for( int c = 0; c < 5000; c++ ) + { + sTmp += sAdd; + } +} + +void append6() +{ + Bu::String sTmp, sAdd("Test"); + for( int c = 0; c < 5000; c++ ) + { + sTmp.append( sAdd ); + } +} + +void prepend1() +{ + Bu::String sTmp; + for( int c = 0; c < 5000; c++ ) + { + sTmp.prepend('c'); + } +} + +void copy1() +{ + Bu::String sSrc; + for( int c = 0; c < 1000; c++ ) + { + sSrc += (char)(c%256); + Bu::String sTmp = sSrc; + sTmp.append( '-' ); + } +} + +void copy2() +{ + Bu::String sSrc; + for( int c = 0; c < 1000; c++ ) + { + sSrc += (char)(c%256); + Bu::String sTmp = sSrc; + } +} + +void replace1() +{ + Bu::String s("Hey, this is a replacement test, what do you thing of it?"); + s.replace("e", "X").replace("a", "X").replace("what","XXX"); +} + +int main() +{ + timeit( append1, "Append1", 5000 ); + timeit( append2, "Append2", 5000 ); + timeit( append3, "Append3", 2000 ); + timeit( append4, "Append4", 2000 ); + timeit( append4, "Prepend1", 2000 ); + timeit( copy1, "Copy1", 2000 ); + timeit( copy2, "Copy2", 2000 ); + timeit( replace1, "Replace1", 10000 ); +} + diff --git a/src/tools/format.cpp b/src/tools/format.cpp deleted file mode 100644 index 6aa4c56..0000000 --- a/src/tools/format.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -using namespace Bu; - -class Fmter -{ -public: - Fmter( const Bu::String &sSrc ) : - sSrc( sSrc ) - { - } - - template - Fmter &arg( const T &x ) - { - lParm.append( Pair( x ) ); - - return *this; - } - - template - Fmter &arg( const T &x, Bu::Formatter::Fmt f ) - { - lParm.append( Pair( x, f ) ); - - return *this; - } - - operator Bu::String() const - { - int iCount = lParm.getSize(); - ParmList::const_iterator *aParm = - new ParmList::const_iterator[iCount]; - { - int j = 0; - for( ParmList::const_iterator i = lParm.begin(); i; i++, j++ ) - { - aParm[j] = i; - } - } - Bu::MemBuf mbOut; - Bu::Formatter f( mbOut ); - for( Bu::String::const_iterator s = sSrc.begin(); s; s++ ) - { - if( *s == '%' ) - { - s++; - if( *s == '%' ) - f << *s; - else - { - Bu::String sNum; - while( s && *s >= '0' && *s <= '9' ) - { - sNum += *s; - s++; - } - int iIndex = strtol( sNum.getStr(), 0, 10 )-1; - if( iIndex < 0 || iIndex >= iCount ) - { - delete[] aParm; - throw Bu::ExceptionBase( - "Argument index %d is outside of " - "valid range (1-%d).", iIndex+1, iCount - ); - } - - f << (*aParm[iIndex]).format << (*aParm[iIndex]).value; - if( s ) - f << *s; - } - } - else - { - f << *s; - } - } - - delete[] aParm; - return mbOut.getString(); - } - -private: - const Bu::String &sSrc; - class Pair - { - public: - template - Pair( const T &v ) : - value( v ) - { - } - - template - Pair( const T &v, Bu::Formatter::Fmt f ) : - value( v ), - format( f ) - { - } - - Bu::Variant value; - Bu::Formatter::Fmt format; - }; - typedef Bu::List ParmList; - ParmList lParm; -}; - -Bu::Formatter &operator<<( Bu::Formatter &f, const Fmter &r ) -{ - return f << (Bu::String)r; -} - -int main() -{ - sio << Fmter("A word is %1 and a number is %2 %1"). - arg("Hello").arg(75, Fmt::hex() ).arg(" - ") << sio.nl; -} - diff --git a/src/udpsocket.cpp b/src/udpsocket.cpp index b577302..055d584 100644 --- a/src/udpsocket.cpp +++ b/src/udpsocket.cpp @@ -83,15 +83,11 @@ Bu::UdpSocket::~UdpSocket() Bu::String Bu::UdpSocket::addrToStr( const addr &a ) { - Bu::String sOut; - sOut.format("%d.%d.%d.%d", - (a&0xff), - (a&0xff00)>>8, - (a&0xff0000)>>16, - (a&0xff000000)>>24 - ); - - return sOut; + return Bu::String("%1.%2.%3.%4"). + arg( (a&0xff) ). + arg( (a&0xff00)>>8 ). + arg( (a&0xff0000)>>16 ). + arg( (a&0xff000000)>>24 ); } void Bu::UdpSocket::close() diff --git a/src/utfstring.h b/src/utfstring.h index 2140af1..56e544e 100644 --- a/src/utfstring.h +++ b/src/utfstring.h @@ -8,7 +8,7 @@ #ifndef BU_UTF_STRING_H #define BU_UTF_STRING_H -#include "bu/string.h" +#include namespace Bu { @@ -21,8 +21,8 @@ namespace Bu typedef uint32_t point; private: - typedef BasicString RawString; - RawString rsStore; +// typedef BasicString RawString; +// RawString rsStore; }; }; diff --git a/src/variant.cpp b/src/variant.cpp index f7c87ad..5cdaa5b 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -6,7 +6,7 @@ */ #include "bu/variant.h" - +#include "bu/formatter.h" #include "bu/membuf.h" namespace Bu diff --git a/src/variant.h b/src/variant.h index a4f09af..45e3339 100644 --- a/src/variant.h +++ b/src/variant.h @@ -8,12 +8,19 @@ #ifndef BU_VARIANT_H #define BU_VARIANT_H -#include +//#include #include -#include +// #include + +#ifndef NULL +#define NULL (0L) +#endif + +#include "bu/exceptionbase.h" namespace Bu { + class String; class Formatter; class Variant; /** @cond DEVEL */ -- cgit v1.2.3