summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2011-03-18 23:02:54 +0000
committerMike Buland <eichlan@xagasoft.com>2011-03-18 23:02:54 +0000
commitcba6293cf22e2c2ae17dd3954ad7d097f379c7ac (patch)
treedcdbda1f54d3d39a0066f2f42c7e1714e1ceb834 /src
parentfcf2dde54316a3ac35936157babccae8c8d8d90b (diff)
downloadlibbu++-cba6293cf22e2c2ae17dd3954ad7d097f379c7ac.tar.gz
libbu++-cba6293cf22e2c2ae17dd3954ad7d097f379c7ac.tar.bz2
libbu++-cba6293cf22e2c2ae17dd3954ad7d097f379c7ac.tar.xz
libbu++-cba6293cf22e2c2ae17dd3954ad7d097f379c7ac.zip
Wow, a lot has changed. String is not a template class, and it can do it's own
formatting ala QString.
Diffstat (limited to 'src')
-rw-r--r--src/fmt.h92
-rw-r--r--src/formatter.cpp28
-rw-r--r--src/formatter.h101
-rw-r--r--src/lexer.cpp1
-rw-r--r--src/myriadstream.cpp4
-rw-r--r--src/string.cpp1295
-rw-r--r--src/string.h1566
-rw-r--r--src/tests/stringspeed.cpp122
-rw-r--r--src/tools/format.cpp124
-rw-r--r--src/udpsocket.cpp14
-rw-r--r--src/utfstring.h6
-rw-r--r--src/variant.cpp2
-rw-r--r--src/variant.h11
13 files changed, 1791 insertions, 1575 deletions
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 @@
1#ifndef BU_FMT_H
2#define BU_FMT_H
3
4namespace Bu
5{
6 typedef struct Fmt
7 {
8 enum Alignment
9 {
10 Left = 0,
11 Center = 1,
12 Right = 2
13 };
14 Fmt() :
15 uMinWidth( 0 ),
16 cFillChar(' '),
17 uRadix( 10 ),
18 uAlign( Right ),
19 bPlus( false ),
20 bCaps( true ),
21 bTokenize( true )
22 {
23 }
24
25 Fmt( unsigned int uMinWidth, unsigned int uRadix=10,
26 Alignment a=Right, bool bPlus=false, bool bCaps=true,
27 char cFill=' ') :
28 uMinWidth( uMinWidth ),
29 cFillChar(cFill),
30 uRadix( uRadix ),
31 uAlign( a ),
32 bPlus( bPlus ),
33 bCaps( bCaps ),
34 bTokenize( true )
35 {
36 }
37 Fmt( unsigned int uMinWidth, Alignment a,
38 unsigned int uRadix=10, bool bPlus=false, bool bCaps=true,
39 char cFill=' ') :
40 uMinWidth( uMinWidth ),
41 cFillChar(cFill),
42 uRadix( uRadix ),
43 uAlign( a ),
44 bPlus( bPlus ),
45 bCaps( bCaps ),
46 bTokenize( true )
47 {
48 }
49
50 static Fmt hex( unsigned int uWidth=0, bool bCaps=true )
51 {
52 return Fmt( uWidth, 16, Right, false, bCaps, '0' );
53 }
54
55 static Fmt oct( unsigned int uWidth=0 )
56 {
57 return Fmt( uWidth, 8, Right, false, false, '0' );
58 }
59
60 static Fmt bin( unsigned int uWidth=0 )
61 {
62 return Fmt( uWidth, 1, Right, false, false, '0' );
63 }
64
65 static Fmt ptr( bool bCaps=true )
66 {
67 return Fmt( sizeof(ptrdiff_t)*2, 16, Right, false, bCaps, '0' );
68 }
69
70 Fmt &width( unsigned int uWidth );
71 Fmt &fill( char cFill='0' );
72 Fmt &radix( unsigned int uRadix );
73 Fmt &align( Alignment eAlign );
74 Fmt &plus( bool bPlus=true );
75 Fmt &caps( bool bCaps=true );
76 Fmt &tokenize( bool bTokenize=true );
77
78 Fmt &left();
79 Fmt &right();
80 Fmt &center();
81
82 unsigned char uMinWidth;
83 char cFillChar;
84 unsigned short uRadix : 6;
85 unsigned short uAlign : 2;
86 unsigned short bPlus : 1;
87 unsigned short bCaps : 1;
88 unsigned short bTokenize : 1;
89 } Fmt;
90};
91
92#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 @@
7 7
8#include "bu/formatter.h" 8#include "bu/formatter.h"
9 9
10#include "bu/stream.h"
10#include <string.h> 11#include <string.h>
11 12
12Bu::Formatter::Formatter( Stream &rStream ) : 13Bu::Formatter::Formatter( Stream &rStream ) :
@@ -189,67 +190,72 @@ void Bu::Formatter::setIndentChar( char cIndent )
189 this->cIndent = cIndent; 190 this->cIndent = cIndent;
190} 191}
191 192
192Bu::Formatter::Fmt &Bu::Formatter::Fmt::width( unsigned int uWidth ) 193void Bu::Formatter::doFlush()
194{
195 rStream.flush();
196}
197
198Bu::Fmt &Bu::Fmt::width( unsigned int uWidth )
193{ 199{
194 this->uMinWidth = uWidth; 200 this->uMinWidth = uWidth;
195 return *this; 201 return *this;
196} 202}
197 203
198Bu::Formatter::Fmt &Bu::Formatter::Fmt::fill( char cFill ) 204Bu::Fmt &Bu::Fmt::fill( char cFill )
199{ 205{
200 this->cFillChar = (unsigned char)cFill; 206 this->cFillChar = (unsigned char)cFill;
201 return *this; 207 return *this;
202} 208}
203 209
204Bu::Formatter::Fmt &Bu::Formatter::Fmt::radix( unsigned int uRadix ) 210Bu::Fmt &Bu::Fmt::radix( unsigned int uRadix )
205{ 211{
206 this->uRadix = uRadix; 212 this->uRadix = uRadix;
207 return *this; 213 return *this;
208} 214}
209 215
210Bu::Formatter::Fmt &Bu::Formatter::Fmt::align( Alignment eAlign ) 216Bu::Fmt &Bu::Fmt::align( Alignment eAlign )
211{ 217{
212 this->uAlign = eAlign; 218 this->uAlign = eAlign;
213 return *this; 219 return *this;
214} 220}
215 221
216Bu::Formatter::Fmt &Bu::Formatter::Fmt::left() 222Bu::Fmt &Bu::Fmt::left()
217{ 223{
218 this->uAlign = Fmt::Left; 224 this->uAlign = Fmt::Left;
219 return *this; 225 return *this;
220} 226}
221 227
222Bu::Formatter::Fmt &Bu::Formatter::Fmt::center() 228Bu::Fmt &Bu::Fmt::center()
223{ 229{
224 this->uAlign = Fmt::Center; 230 this->uAlign = Fmt::Center;
225 return *this; 231 return *this;
226} 232}
227 233
228Bu::Formatter::Fmt &Bu::Formatter::Fmt::right() 234Bu::Fmt &Bu::Fmt::right()
229{ 235{
230 this->uAlign = Fmt::Right; 236 this->uAlign = Fmt::Right;
231 return *this; 237 return *this;
232} 238}
233 239
234Bu::Formatter::Fmt &Bu::Formatter::Fmt::plus( bool bPlus ) 240Bu::Fmt &Bu::Fmt::plus( bool bPlus )
235{ 241{
236 this->bPlus = bPlus; 242 this->bPlus = bPlus;
237 return *this; 243 return *this;
238} 244}
239 245
240Bu::Formatter::Fmt &Bu::Formatter::Fmt::caps( bool bCaps ) 246Bu::Fmt &Bu::Fmt::caps( bool bCaps )
241{ 247{
242 this->bCaps = bCaps; 248 this->bCaps = bCaps;
243 return *this; 249 return *this;
244} 250}
245 251
246Bu::Formatter::Fmt &Bu::Formatter::Fmt::tokenize( bool bTokenize ) 252Bu::Fmt &Bu::Fmt::tokenize( bool bTokenize )
247{ 253{
248 this->bTokenize = bTokenize; 254 this->bTokenize = bTokenize;
249 return *this; 255 return *this;
250} 256}
251 257
252Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Formatter::Fmt &fmt ) 258Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Fmt &fmt )
253{ 259{
254 f.setTempFormat( fmt ); 260 f.setTempFormat( fmt );
255 return f; 261 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 @@
8#ifndef BU_FORMATTER_H 8#ifndef BU_FORMATTER_H
9#define BU_FORMATTER_H 9#define BU_FORMATTER_H
10 10
11#include "stream.h" 11#include "bu/string.h"
12#include "bu/fmt.h"
12 13
13namespace Bu 14namespace Bu
14{ 15{
16 class Stream;
17
15 class Formatter 18 class Formatter
16 { 19 {
17 public: 20 public:
18 Formatter( Stream &rStream ); 21 Formatter( Stream &rStream );
19 virtual ~Formatter(); 22 virtual ~Formatter();
20 23
21 typedef struct Fmt
22 {
23 enum Alignment
24 {
25 Left = 0,
26 Center = 1,
27 Right = 2
28 };
29 Fmt() :
30 uMinWidth( 0 ),
31 cFillChar(' '),
32 uRadix( 10 ),
33 uAlign( Right ),
34 bPlus( false ),
35 bCaps( true ),
36 bTokenize( true )
37 {
38 }
39
40 Fmt( unsigned int uMinWidth, unsigned int uRadix=10,
41 Alignment a=Right, bool bPlus=false, bool bCaps=true,
42 char cFill=' ') :
43 uMinWidth( uMinWidth ),
44 cFillChar(cFill),
45 uRadix( uRadix ),
46 uAlign( a ),
47 bPlus( bPlus ),
48 bCaps( bCaps ),
49 bTokenize( true )
50 {
51 }
52 Fmt( unsigned int uMinWidth, Alignment a,
53 unsigned int uRadix=10, bool bPlus=false, bool bCaps=true,
54 char cFill=' ') :
55 uMinWidth( uMinWidth ),
56 cFillChar(cFill),
57 uRadix( uRadix ),
58 uAlign( a ),
59 bPlus( bPlus ),
60 bCaps( bCaps ),
61 bTokenize( true )
62 {
63 }
64
65 static Fmt hex( unsigned int uWidth=0, bool bCaps=true )
66 {
67 return Fmt( uWidth, 16, Right, false, bCaps, '0' );
68 }
69
70 static Fmt oct( unsigned int uWidth=0 )
71 {
72 return Fmt( uWidth, 8, Right, false, false, '0' );
73 }
74
75 static Fmt bin( unsigned int uWidth=0 )
76 {
77 return Fmt( uWidth, 1, Right, false, false, '0' );
78 }
79
80 static Fmt ptr( bool bCaps=true )
81 {
82 return Fmt( sizeof(ptrdiff_t)*2, 16, Right, false, bCaps, '0' );
83 }
84
85 Fmt &width( unsigned int uWidth );
86 Fmt &fill( char cFill='0' );
87 Fmt &radix( unsigned int uRadix );
88 Fmt &align( Alignment eAlign );
89 Fmt &plus( bool bPlus=true );
90 Fmt &caps( bool bCaps=true );
91 Fmt &tokenize( bool bTokenize=true );
92
93 Fmt &left();
94 Fmt &right();
95 Fmt &center();
96
97 unsigned char uMinWidth;
98 char cFillChar;
99 unsigned short uRadix : 6;
100 unsigned short uAlign : 2;
101 unsigned short bPlus : 1;
102 unsigned short bCaps : 1;
103 unsigned short bTokenize : 1;
104 } Fmt;
105
106 void write( const Bu::String &sStr ); 24 void write( const Bu::String &sStr );
107 void write( const void *sStr, int iLen ); 25 void write( const void *sStr, int iLen );
108 void writeAligned( const Bu::String &sStr ); 26 void writeAligned( const Bu::String &sStr );
@@ -200,7 +118,7 @@ namespace Bu
200 void ffmt( type f ) 118 void ffmt( type f )
201 { 119 {
202 Bu::String fTmp; 120 Bu::String fTmp;
203 fTmp.format("%f", f ); 121// fTmp.format("%f", f );
204// writeAligned("**make floats work**"); 122// writeAligned("**make floats work**");
205 writeAligned( fTmp ); 123 writeAligned( fTmp );
206 usedFormat(); 124 usedFormat();
@@ -269,10 +187,7 @@ namespace Bu
269 flush 187 flush
270 }; 188 };
271 189
272 void doFlush() 190 void doFlush();
273 {
274 rStream.flush();
275 }
276 191
277 private: 192 private:
278 Stream &rStream; 193 Stream &rStream;
@@ -282,9 +197,7 @@ namespace Bu
282 char cIndent; 197 char cIndent;
283 }; 198 };
284 199
285 typedef Formatter::Fmt Fmt; 200 Formatter &operator<<( Formatter &f, const Fmt &fmt );
286
287 Formatter &operator<<( Formatter &f, const Formatter::Fmt &fmt );
288 Formatter &operator<<( Formatter &f, Formatter::Special s ); 201 Formatter &operator<<( Formatter &f, Formatter::Special s );
289 Formatter &operator<<( Formatter &f, const char *sStr ); 202 Formatter &operator<<( Formatter &f, const char *sStr );
290 Formatter &operator<<( Formatter &f, char *sStr ); 203 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 @@
7 7
8#include "bu/lexer.h" 8#include "bu/lexer.h"
9#include "bu/membuf.h" 9#include "bu/membuf.h"
10#include "bu/formatter.h"
10 11
11Bu::Lexer::Lexer() 12Bu::Lexer::Lexer()
12{ 13{
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
304 304
305Bu::String Bu::MyriadStream::getLocation() const 305Bu::String Bu::MyriadStream::getLocation() const
306{ 306{
307 Bu::String s; 307 return Bu::String("%1").arg( pStream->iId );
308 s.format("%d", pStream->iId );
309 return s;
310} 308}
311 309
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 @@
10 10
11#include "bu/string.h" 11#include "bu/string.h"
12#include "bu/hash.h" 12#include "bu/hash.h"
13#include "bu/membuf.h"
14#include "bu/formatter.h"
15#include <stdlib.h>
16
17Bu::StringCore::StringCore() :
18 nLength( 0 ),
19 pFirst( NULL ),
20 pLast( NULL )
21{
22}
23
24Bu::StringCore::StringCore( const StringCore &rSrc ) :
25 nLength( rSrc.nLength ),
26 pFirst( NULL ),
27 pLast( NULL )
28{
29 if( rSrc.pFirst == NULL || rSrc.nLength == 0 )
30 {
31 pFirst = pLast = NULL;
32 }
33 else
34 {
35 pFirst = pLast = newChunk( nLength );
36 Chunk *pLink = rSrc.pFirst;
37 int iPos = 0;
38 while( pLink != NULL )
39 {
40 memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
41 iPos += pLink->nLength;
42 pLink = pLink->pNext;
43 }
44 }
45}
46
47Bu::StringCore::~StringCore()
48{
49 clear();
50}
51
52void Bu::StringCore::clear() const
53{
54 if( pFirst == NULL )
55 return;
56
57 Chunk *i = pFirst;
58 for(;;)
59 {
60 Chunk *n = i->pNext;
61 delete[] i->pData;
62 delete i;
63 if( n == NULL )
64 break;
65 i = n;
66 }
67 pFirst = pLast = NULL;
68 nLength = 0;
69}
70
71Bu::StringCore::Chunk *Bu::StringCore::newChunk() const
72{
73 Chunk *pNew = new Chunk;
74 pNew->pNext = NULL;
75 return pNew;
76}
77
78Bu::StringCore::Chunk *Bu::StringCore::newChunk( long nLen ) const
79{
80 Chunk *pNew = new Chunk;
81 pNew->pNext = NULL;
82 pNew->nLength = nLen;
83 pNew->pData = new char[(nLen<nMinSize)?(nMinSize):(nLen)+1];
84 pNew->pData[nLen] = (char)0;
85 return pNew;
86}
87
88Bu::StringCore::Chunk *Bu::StringCore::copyChunk(
89 Bu::StringCore::Chunk *pSrc ) const
90{
91 Chunk *pNew = new Chunk;
92 pNew->pNext = pSrc->pNext;
93 pNew->nLength = pSrc->nLength;
94 pNew->pData = new char[
95 (pNew->nLength<nMinSize)?(nMinSize):(pNew->nLength)+1
96 ];
97 memcpy( pNew->pData, pSrc->pData, pSrc->nLength );
98 pNew->pData[pNew->nLength] = (char)0;
99 return pNew;
100}
101
102void Bu::StringCore::appendChunk( Bu::StringCore::Chunk *pNewChunk )
103{
104 if( pFirst == NULL )
105 pLast = pFirst = pNewChunk;
106 else
107 {
108 pLast->pNext = pNewChunk;
109 pLast = pNewChunk;
110 }
111
112 nLength += pNewChunk->nLength;
113}
114
115void Bu::StringCore::prependChunk( Bu::StringCore::Chunk *pNewChunk )
116{
117 if( pFirst == NULL )
118 pLast = pFirst = pNewChunk;
119 else
120 {
121 pNewChunk->pNext = pFirst;
122 pFirst = pNewChunk;
123 }
124
125 nLength += pNewChunk->nLength;
126}
127
128Bu::String::String()
129{
130}
131
132Bu::String::String( const char *pData )
133{
134 append( pData );
135}
136
137Bu::String::String( const char *pData, long nLength )
138{
139 append( pData, nLength );
140}
141
142Bu::String::String( const Bu::String::String &rSrc ) :
143 Bu::SharedCore<Bu::String, Bu::StringCore>( rSrc )
144{
145}
146
147Bu::String::String( const Bu::String &rSrc, long nLength )
148{
149 append( rSrc, nLength );
150}
151
152Bu::String::String( const Bu::String &rSrc, long nStart, long nLength )
153{
154 append( rSrc, nStart, nLength );
155}
156
157Bu::String::String( long nSize )
158{
159 core->pFirst = core->pLast = core->newChunk( nSize );
160 core->nLength = nSize;
161}
162
163Bu::String::String( const Bu::String::const_iterator &s )
164{
165 append( s );
166}
167
168Bu::String::String( const Bu::String::const_iterator &s,
169 const Bu::String::const_iterator &e )
170{
171 append( s, e );
172}
173
174Bu::String::~String()
175{
176}
177
178void Bu::String::append( const char *pData )
179{
180 if( !pData ) return;
181 long nLen;
182 for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { }
183
184 append( pData, 0, nLen );
185}
186
187void Bu::String::append( const char *pData, long nLen )
188{
189 append( pData, 0, nLen );
190}
191
192void Bu::String::append( const char *pData, long nStart, long nLen )
193{
194 if( !pData ) return;
195 if( nLen <= 0 )
196 return;
197
198 pData += nStart;
199
200 _hardCopy();
201
202 if( core->pLast && core->pLast->nLength < nMinSize )
203 {
204 int nAmnt = nMinSize - core->pLast->nLength;
205 if( nAmnt > nLen )
206 nAmnt = nLen;
207 memcpy(
208 core->pLast->pData+core->pLast->nLength,
209 pData,
210 nAmnt
211 );
212 pData += nAmnt;
213 core->pLast->nLength += nAmnt;
214 nLen -= nAmnt;
215 core->nLength += nAmnt;
216 }
217
218 if( nLen > 0 )
219 {
220 Chunk *pNew = core->newChunk( nLen );
221 memcpy( pNew->pData, pData, nLen );
222 core->appendChunk( pNew );
223// core->nLength += nLen;
224 }
225}
226
227void Bu::String::append( const char &cData )
228{
229 if( core->pLast && core->pLast->nLength < nMinSize )
230 {
231 _hardCopy();
232 core->pLast->pData[core->pLast->nLength] = cData;
233 ++core->pLast->nLength; ++core->nLength;
234// pLast->pData[pLast->nLength] = (char)0;
235 }
236 else
237 {
238 append( &cData, 1 );
239 }
240}
241
242void Bu::String::append( const String & sData )
243{
244 append( sData.getStr(), 0, sData.getSize() );
245}
246
247void Bu::String::append( const String & sData, long nLen )
248{
249 append( sData.getStr(), 0, nLen );
250}
251
252void Bu::String::append( const String & sData, long nStart, long nLen )
253{
254 if( nLen < 0 )
255 nLen = sData.getSize() - nStart;
256 append( sData.getStr(), nStart, nLen );
257}
258
259void Bu::String::append( const const_iterator &s )
260{
261 if( !s.isValid() )
262 return;
263 Chunk *pSrc = s.pChunk;
264
265 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
266 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
267
268 _hardCopy();
269 core->appendChunk( pNew );
270
271 while( (pSrc = pSrc->pNext) )
272 {
273 core->appendChunk( core->copyChunk( pSrc ) );
274 }
275}
276
277void Bu::String::append( const iterator &s )
278{
279 append( const_iterator( s ) );
280}
281
282void Bu::String::append( const const_iterator &s, const const_iterator &e )
283{
284 if( !s.isValid() )
285 return;
286 if( !e.isValid() )
287 {
288 append( s );
289 return;
290 }
291 _hardCopy();
292 if( s.pChunk == e.pChunk )
293 {
294 // Simple case, they're the same chunk
295 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
296 memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
297 core->appendChunk( pNew );
298 }
299 else
300 {
301 // A little trickier, scan the blocks...
302 Chunk *pSrc = s.pChunk;
303 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
304 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
305 core->appendChunk( pNew );
306
307 while( (pSrc = pSrc->pNext) != e.pChunk )
308 {
309 core->appendChunk( core->copyChunk( pSrc ) );
310 }
311
312 pNew = core->newChunk( e.iPos );
313 memcpy( pNew->pData, pSrc->pData, e.iPos );
314 core->appendChunk( pNew );
315 }
316}
317
318void Bu::String::prepend( const String & sData )
319{
320 prepend( sData.getStr(), sData.getSize() );
321}
322
323void Bu::String::prepend( const char *pData )
324{
325 if( pData == NULL )
326 return;
327
328 _hardCopy();
329 long nLen;
330 for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { }
331
332 Chunk *pNew = core->newChunk( nLen );
333 memcpy( pNew->pData, pData, nLen );
334
335 core->prependChunk( pNew );
336}
337
338void Bu::String::prepend( const char *pData, long nLen )
339{
340 Chunk *pNew = core->newChunk( nLen );
341
342 memcpy( pNew->pData, pData, nLen );
343
344 _hardCopy();
345 core->prependChunk( pNew );
346}
347
348void Bu::String::prepend( const char c )
349{
350 prepend( &c, 1 );
351}
352
353void Bu::String::insert( long nPos, const char *pData, long nLen )
354{
355 if( nLen <= 0 )
356 return;
357 if( nPos <= 0 )
358 {
359 prepend( pData, nLen );
360 }
361 else if( nPos >= core->nLength )
362 {
363 append( pData, nLen );
364 }
365 else
366 {
367 // If we're going to flatten anyway, might as well for everyone
368 flatten();
369 _hardCopy();
370 Chunk *p1 = core->newChunk( nPos );
371 Chunk *p2 = core->newChunk( nLen );
372 Chunk *p3 = core->newChunk( core->nLength-nPos );
373 memcpy( p1->pData, core->pFirst->pData, nPos );
374 memcpy( p2->pData, pData, nLen );
375 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
376 core->clear();
377 core->appendChunk( p1 );
378 core->appendChunk( p2 );
379 core->appendChunk( p3 );
380 }
381}
382
383void Bu::String::insert( long nPos, const String &str )
384{
385 if( nPos <= 0 )
386 {
387 prepend( str );
388 }
389 else if( nPos >= core->nLength )
390 {
391 append( str );
392 }
393 else
394 {
395 flatten();
396 _hardCopy();
397 Chunk *p1 = core->newChunk( nPos );
398 Chunk *p3 = core->newChunk( core->nLength-nPos );
399 memcpy( p1->pData, core->pFirst->pData, nPos );
400 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
401 core->clear();
402 core->appendChunk( p1 );
403 for( Chunk *pChnk = str.core->pFirst; pChnk;
404 pChnk = pChnk->pNext )
405 {
406 core->appendChunk( core->copyChunk( pChnk ) );
407 }
408
409 core->appendChunk( p3 );
410 }
411}
412
413void Bu::String::insert( long nPos, const char *pData )
414{
415 insert( nPos, pData, strlen( pData ) );
416}
417
418void Bu::String::remove( long nPos, long nLen )
419{
420 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
421 return;
422 if( nLen > core->nLength-nPos )
423 nLen = core->nLength-nPos;
424 flatten();
425 _hardCopy();
426 memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
427 core->nLength -= nLen;
428 core->pFirst->nLength -= nLen;
429}
430
431void Bu::String::clear()
432{
433 _hardCopy();
434 core->clear();
435}
436
437Bu::String Bu::String::replace( const Bu::String &fnd,
438 const Bu::String &rep ) const
439{
440 String out;
441 const_iterator o = begin();
442 while( true )
443 {
444 const_iterator i = o.find( fnd );
445 if( !i )
446 {
447 out.append( o );
448 return out;
449 }
450 else
451 {
452 out.append( o, i );
453 out.append( rep );
454 o = i;
455 o += fnd.getSize();
456 }
457 }
458}
459
460void Bu::String::resize( long nNewSize )
461{
462 if( core->nLength == nNewSize )
463 return;
464 if( nNewSize < 0 )
465 nNewSize = 0;
466
467 flatten();
468 _hardCopy();
469
470 // TODO: This is bad
471
472 Chunk *pNew = core->newChunk( nNewSize );
473 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
474 if( core->nLength > 0 )
475 {
476 memcpy( pNew->pData, core->pFirst->pData, nNewLen );
477 delete[] core->pFirst->pData;
478 delete core->pFirst;
479 }
480 pNew->pData[nNewLen] = (char)0;
481 core->pFirst = core->pLast = pNew;
482 core->nLength = nNewSize;
483}
484
485long Bu::String::getSize() const
486{
487 return core->nLength;
488}
489
490char *Bu::String::getStr()
491{
492 if( core->pFirst == NULL || core->nLength == 0 )
493 return (char *)"";
494
495 flatten();
496 _hardCopy();
497 core->pFirst->pData[core->nLength] = (char)0;
498 return core->pFirst->pData;
499}
500
501const char *Bu::String::getStr() const
502{
503 if( core->pFirst == NULL || core->nLength == 0 )
504 return (char *)"";
505
506 flatten();
507 core->pFirst->pData[core->nLength] = (char)0;
508 return core->pFirst->pData;
509}
510
511const char *Bu::String::getConstStr() const
512{
513 return getStr();
514}
515
516Bu::String Bu::String::getSubStrIdx( long iStart, long iSize ) const
517{
518 if( iStart < 0 )
519 iStart = 0;
520 if( iStart >= core->nLength )
521 return (const char[]){(char)0};
522 if( iSize < 0 )
523 iSize = core->nLength;
524 if( iStart+iSize > core->nLength )
525 iSize = core->nLength-iStart;
526 if( iSize == 0 )
527 return (const char[]){(char)0};
528
529 flatten();
530 String ret( core->pFirst->pData+iStart, iSize );
531 return ret;
532}
533
534Bu::String Bu::String::getSubStr( const_iterator iBegin,
535 const_iterator iEnd ) const
536{
537 if( !iBegin.isValid() )
538 return String();
539 if( iBegin.pChunk == iEnd.pChunk )
540 {
541 return String( iBegin.pChunk->pData+iBegin.iPos,
542 iEnd.iPos-iBegin.iPos );
543 }
544 else if( !iEnd.isValid() )
545 {
546 String ret;
547 ret.append(
548 iBegin.pChunk->pData+iBegin.iPos,
549 iBegin.pChunk->nLength-iBegin.iPos
550 );
551 for( Chunk *pCur = iBegin.pChunk->pNext;
552 pCur; pCur = pCur->pNext )
553 {
554 ret.append( pCur->pData, pCur->nLength );
555 }
556 return ret;
557 }
558 else
559 {
560 String ret;
561 ret.append(
562 iBegin.pChunk->pData+iBegin.iPos,
563 iBegin.pChunk->nLength-iBegin.iPos
564 );
565 for( Chunk *pCur = iBegin.pChunk->pNext;
566 pCur != iEnd.pChunk; pCur = pCur->pNext )
567 {
568 ret.append( pCur->pData, pCur->nLength );
569 }
570 ret.append(
571 iEnd.pChunk->pData,
572 iEnd.iPos
573 );
574 return ret;
575 }
576}
577
578Bu::StringList Bu::String::split( const char c ) const
579{
580 Bu::StringList ret;
581 const_iterator l, r;
582 l = begin();
583 for(r=l; l;)
584 {
585 for( r = l; r && r != c; r++ ) { }
586 ret.append( String( l, r ) );
587 l = r;
588 l++;
589 }
590 return ret;
591}
592
593Bu::String &Bu::String::operator+=( const char *pData )
594{
595 append( pData );
596
597 return (*this);
598}
599
600Bu::String &Bu::String::operator+=( const Bu::String &rSrc )
601{
602 append( rSrc );
603
604 return (*this);
605}
606
607Bu::String &Bu::String::operator+=( const Bu::String::const_iterator &i )
608{
609 append( i, i+1 );
610
611 return (*this);
612}
613
614Bu::String &Bu::String::operator+=( const char cData )
615{
616 if( core->pLast && core->pLast->nLength < nMinSize )
617 {
618 _hardCopy();
619 core->pLast->pData[core->pLast->nLength] = cData;
620 ++core->pLast->nLength; ++core->nLength;
621// pLast->pData[pLast->nLength] = (char)0;
622 }
623 else
624 {
625 append( &cData, 1 );
626 }
627 //append( pData );
628
629 return (*this);
630}
631
632Bu::String &Bu::String::operator=( const char *pData )
633{
634 set( pData );
635
636 return (*this);
637}
638
639Bu::String Bu::String::operator+( const Bu::String &rRight ) const
640{
641 String ret( *this );
642 ret.append( rRight );
643 return ret;
644}
645
646Bu::String Bu::String::operator+( const char *pRight ) const
647{
648 String ret( *this );
649 ret.append( pRight );
650 return ret;
651}
652
653Bu::String Bu::String::operator+( char *pRight ) const
654{
655 String ret( *this );
656 ret.append( pRight );
657 return ret;
658}
659
660void Bu::String::set( const char *pData )
661{
662 clear();
663 append( pData );
664}
665
666void Bu::String::set( const char *pData, long nSize )
667{
668 clear();
669 append( pData, nSize );
670}
671
672void Bu::String::set( const char *pData, long nStart, long nSize )
673{
674 clear();
675 append( pData, nStart, nSize );
676}
677
678void Bu::String::set( const String &rData )
679{
680 clear();
681 append( rData );
682}
683
684void Bu::String::set( const String &rData, long nSize )
685{
686 clear();
687 append( rData, nSize );
688}
689
690void Bu::String::set( const String &rData, long nStart, long nSize )
691{
692 clear();
693 append( rData, nStart, nSize );
694}
695
696void Bu::String::set( const_iterator s )
697{
698 clear();
699 append( s );
700}
701
702void Bu::String::set( const_iterator s, const_iterator e )
703{
704 clear();
705 append( s, e );
706}
707
708void Bu::String::setSize( long iSize )
709{
710 _hardCopy();
711 core->clear();
712 core->appendChunk( core->newChunk( iSize ) );
713}
714
715bool Bu::String::operator==( const char *pData ) const
716{
717 if( core->pFirst == NULL || core->nLength == 0 ) {
718 if( pData == NULL )
719 return true;
720 if( pData[0] == (char)0 )
721 return true;
722 return false;
723 }
724
725 flatten();
726 core->pFirst->pData[core->nLength] = (char)0;
727 const char *a = pData;
728 char *b = core->pFirst->pData;
729 for( long j = 0; *a!=(char)0 || *b!=(char)0; j++, a++, b++ )
730 {
731 if( *a != *b )
732 return false;
733 if( *a == (char)0 && j < core->nLength )
734 return false;
735 }
736
737 return true;
738}
739
740bool Bu::String::operator==( const String &pData ) const
741{
742 if( core == pData.core )
743 return true;
744 if( core->pFirst == pData.core->pFirst )
745 return true;
746 if( (core->nLength == 0 && pData.core->nLength == 0) )
747 return true;
748 if( core->nLength != pData.core->nLength )
749 return false;
750 if( pData.core->pFirst == NULL || core->pFirst == NULL )
751 return false;
752
753 flatten();
754 pData.flatten();
755 const char *a = pData.core->pFirst->pData;
756 char *b = core->pFirst->pData;
757 for( long j = 0; j < core->nLength; j++, a++, b++ )
758 {
759 if( *a != *b )
760 return false;
761 }
762
763 return true;
764}
765
766bool Bu::String::operator!=(const char *pData ) const
767{
768 return !(*this == pData);
769}
770
771bool Bu::String::operator!=(const String &pData ) const
772{
773 return !(*this == pData);
774}
775
776bool Bu::String::operator<(const String &pData ) const
777{
778 flatten();
779 pData.flatten();
780
781 const char *a = core->pFirst->pData;
782 char *b = pData.core->pFirst->pData;
783 for( long j = 0; j < core->nLength; j++, a++, b++ )
784 {
785 if( *a != *b )
786 return *a < *b;
787 }
788
789 return false;
790}
791
792bool Bu::String::operator<=(const String &pData ) const
793{
794 flatten();
795 pData.flatten();
796
797 const char *a = core->pFirst->pData;
798 char *b = pData.core->pFirst->pData;
799 for( long j = 0; j < core->nLength; j++, a++, b++ )
800 {
801 if( *a != *b )
802 return *a < *b;
803 }
804
805 return true;
806}
807
808bool Bu::String::operator>(const String &pData ) const
809{
810 flatten();
811 pData.flatten();
812
813 const char *a = core->pFirst->pData;
814 char *b = pData.core->pFirst->pData;
815 for( long j = 0; j < core->nLength; j++, a++, b++ )
816 {
817 if( *a != *b )
818 return *a > *b;
819 }
820
821 return false;
822}
823
824bool Bu::String::operator>=(const String &pData ) const
825{
826 flatten();
827 pData.flatten();
828
829 const char *a = core->pFirst->pData;
830 char *b = pData.core->pFirst->pData;
831 for( long j = 0; j < core->nLength; j++, a++, b++ )
832 {
833 if( *a != *b )
834 return *a > *b;
835 }
836
837 return true;
838}
839
840char &Bu::String::operator[]( long nIndex )
841{
842 if( nIndex < 0 || nIndex >= core->nLength )
843 throw Bu::ExceptionBase("Index out of range.");
844 flatten();
845 _hardCopy();
846
847 return core->pFirst->pData[nIndex];
848}
849
850const char &Bu::String::operator[]( long nIndex ) const
851{
852 if( nIndex < 0 || nIndex >= core->nLength )
853 throw Bu::ExceptionBase("Index out of range.");
854 flatten();
855
856 return core->pFirst->pData[nIndex];
857}
858
859bool Bu::String::isSet() const
860{
861 return (core->pFirst != NULL);
862}
863
864bool Bu::String::compareSub( const char *pData, long nIndex, long nLen ) const
865{
866 if( core->pFirst == NULL || core->nLength == 0 ) {
867 if( pData == NULL )
868 return true;
869 if( nLen == 0 )
870 return true;
871 if( pData[0] == (char)0 )
872 return true;
873 return false;
874 }
875 if( nIndex+nLen > core->nLength )
876 return false;
877
878 flatten();
879 core->pFirst->pData[core->nLength] = (char)0;
880 const char *a = pData;
881 char *b = core->pFirst->pData+nIndex;
882 for( long j = 0; j < nLen; j++, a++, b++ )
883 {
884 if( *a != *b )
885 return false;
886 if( *a == (char)0 && j < core->nLength )
887 return false;
888 }
889
890 return true;
891}
892
893bool Bu::String::compareSub( const String &rData, long nIndex, long nLen ) const
894{
895 if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 )
896 return false;
897 if( nLen < 0 )
898 nLen = rData.core->nLength;
899 if( nIndex+nLen > core->nLength )
900 return false;
901
902 flatten();
903 rData.flatten();
904 const char *a = rData.core->pFirst->pData;
905 char *b = core->pFirst->pData + nIndex;
906 for( long j = 0; j < nLen; j++, a++, b++ )
907 {
908 if( *a != *b )
909 return false;
910 }
911
912 return true;
913}
914
915bool Bu::String::isWS( long nIndex ) const
916{
917 flatten();
918
919 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
920 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
921}
922
923bool Bu::String::isAlpha( long nIndex ) const
924{
925 flatten();
926
927 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
928 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
929}
930
931Bu::String Bu::String::toLower() const
932{
933 Bu::String sRet = *this;
934
935 sRet.flatten();
936 sRet._hardCopy();
937
938 for( long j = 0; j < sRet.core->nLength; j++ )
939 {
940 if( sRet.core->pFirst->pData[j] >= 'A' &&
941 sRet.core->pFirst->pData[j] <= 'Z' )
942 sRet.core->pFirst->pData[j] -= 'A'-'a';
943 }
944
945 return sRet;
946}
947
948Bu::String Bu::String::toUpper() const
949{
950 Bu::String sRet = *this;
951
952 sRet.flatten();
953 sRet._hardCopy();
954
955 for( long j = 0; j < sRet.core->nLength; j++ )
956 {
957 if( sRet.core->pFirst->pData[j] >= 'a' &&
958 sRet.core->pFirst->pData[j] <= 'z' )
959 sRet.core->pFirst->pData[j] += 'A'-'a';
960 }
961
962 return sRet;
963}
964
965Bu::String::const_iterator Bu::String::find( const char cChar,
966 Bu::String::const_iterator iStart ) const
967{
968 if( !iStart ) iStart = begin();
969 for( ; iStart; iStart++ )
970 {
971 if( cChar == *iStart )
972 return iStart;
973 }
974 return end();
975}
976
977Bu::String::const_iterator Bu::String::find( const char *sText, int nLen,
978 Bu::String::const_iterator iStart ) const
979{
980 if( !iStart ) iStart = begin();
981 for( ; iStart; iStart++ )
982 {
983 if( iStart.compare( sText, nLen ) )
984 return iStart;
985 }
986 return end();
987}
988
989Bu::String::const_iterator Bu::String::find( const String &rStr,
990 Bu::String::const_iterator iStart ) const
991{
992 if( !iStart ) iStart = begin();
993 for( ; iStart; iStart++ )
994 {
995 if( iStart.compare( rStr ) )
996 return iStart;
997 }
998 return end();
999}
1000
1001Bu::String::const_iterator Bu::String::find( const String &rStr, int nLen,
1002 Bu::String::const_iterator iStart ) const
1003{
1004 if( !iStart ) iStart = begin();
1005 for( ; iStart; iStart++ )
1006 {
1007 if( iStart.compare( rStr, nLen ) )
1008 return iStart;
1009 }
1010 return end();
1011}
1012
1013Bu::String::iterator Bu::String::find( const char cChar,
1014 Bu::String::const_iterator iStart )
1015{
1016 if( !iStart ) iStart = begin();
1017 for( ; iStart; iStart++ )
1018 {
1019 if( cChar == *iStart )
1020 return iterator( iStart.pChunk, iStart.iPos );
1021 }
1022 return end();
1023}
1024
1025Bu::String::iterator Bu::String::find( const char *sText, int nLen,
1026 Bu::String::const_iterator iStart )
1027{
1028 if( !iStart ) iStart = begin();
1029 for( ; iStart; iStart++ )
1030 {
1031 if( iStart.compare( sText, nLen ) )
1032 return iterator( iStart.pChunk, iStart.iPos );
1033 }
1034 return end();
1035}
1036
1037Bu::String::iterator Bu::String::find( const String &rStr,
1038 Bu::String::const_iterator iStart )
1039{
1040 if( !iStart ) iStart = begin();
1041 for( ; iStart; iStart++ )
1042 {
1043 if( iStart.compare( rStr ) )
1044 return iterator( iStart.pChunk, iStart.iPos );
1045 }
1046 return end();
1047}
1048
1049Bu::String::iterator Bu::String::find( const String &rStr, int nLen,
1050 Bu::String::const_iterator iStart )
1051{
1052 if( !iStart ) iStart = begin();
1053 for( ; iStart; iStart++ )
1054 {
1055 if( iStart.compare( rStr, nLen ) )
1056 return iterator( iStart.pChunk, iStart.iPos );
1057 }
1058 return end();
1059}
1060
1061long Bu::String::findIdx( const char cChar, long iStart ) const
1062{
1063 flatten();
1064 for( long j = iStart; j < core->pFirst->nLength; j++ )
1065 {
1066 if( core->pFirst->pData[j] == cChar )
1067 return j;
1068 }
1069 return -1;
1070}
1071
1072long Bu::String::findIdx( const char *sText, long iStart ) const
1073{
1074 long nTLen = strlen( sText );
1075 flatten();
1076 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1077 {
1078 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1079 return j;
1080 }
1081 return -1;
1082}
1083
1084long Bu::String::rfindIdx( const char *sText ) const
1085{
1086 long nTLen = strlen( sText );
1087 flatten();
1088 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1089 {
1090 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1091 return j;
1092 }
1093 return -1;
1094}
1095
1096void Bu::String::trimFront( long nAmnt )
1097{
1098 long nNewLen = core->nLength - nAmnt;
1099 flatten();
1100 Chunk *pNew = core->newChunk( nNewLen );
1101 memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1102 _hardCopy();
1103 core->clear();
1104 core->appendChunk( pNew );
1105}
1106
1107void Bu::String::trimBack( char c )
1108{
1109 if( core->pFirst == NULL || core->nLength == 0 )
1110 return;
1111 flatten();
1112 for( ; core->pFirst->nLength > 0 &&
1113 core->pFirst->pData[core->pFirst->nLength-1] == c;
1114 core->pFirst->nLength--, core->nLength-- ) { }
1115}
1116
1117Bu::String::iterator Bu::String::begin()
1118{
1119 if( core->nLength == 0 )
1120 return iterator( NULL, 0 );
1121 return iterator( core->pFirst, 0 );
1122}
1123
1124Bu::String::const_iterator Bu::String::begin() const
1125{
1126 if( core->nLength == 0 )
1127 return const_iterator( NULL, 0 );
1128 return iterator( core->pFirst, 0 );
1129}
1130
1131Bu::String::iterator Bu::String::end()
1132{
1133 return iterator( NULL, 0 );
1134}
1135
1136Bu::String::const_iterator Bu::String::end() const
1137{
1138 return const_iterator( NULL, 0 );
1139}
1140
1141bool Bu::String::isEmpty() const
1142{
1143 if( core->nLength == 0 )
1144 return true;
1145 return false;
1146}
1147
1148void Bu::String::flatten() const
1149{
1150 if( isFlat() )
1151 return;
1152
1153 if( core->pFirst == NULL || core->nLength == 0 )
1154 return;
1155
1156 Chunk *pNew = core->newChunk( core->nLength );
1157 char *pos = pNew->pData;
1158 Chunk *i = core->pFirst;
1159 for(;;)
1160 {
1161 memcpy( pos, i->pData, i->nLength );
1162 pos += i->nLength;
1163 i = i->pNext;
1164 if( i == NULL )
1165 break;
1166 }
1167 core->clear();
1168
1169 core->pLast = core->pFirst = pNew;
1170 core->nLength = pNew->nLength;
1171}
1172
1173bool Bu::String::isFlat() const
1174{
1175 return (core->pFirst == core->pLast);
1176}
1177
1178//
1179// Sub-class Bu::String::FormatProxy
1180//
1181
1182Bu::String::FormatProxy::FormatProxy( const String &rFmt ) :
1183 rFmt( rFmt )
1184{
1185}
1186
1187Bu::String::FormatProxy::~FormatProxy()
1188{
1189}
1190
1191Bu::String::FormatProxy::operator Bu::String() const
1192{
1193 int iCount = lArgs.getSize();
1194 ArgList::const_iterator *aArg =
1195 new ArgList::const_iterator[iCount];
1196 {
1197 int j = 0;
1198 for( ArgList::const_iterator i = lArgs.begin();
1199 i; i++, j++ )
1200 {
1201 aArg[j] = i;
1202 }
1203 }
1204 Bu::MemBuf mbOut;
1205 Bu::Formatter f( mbOut );
1206 for( String::const_iterator s = rFmt.begin(); s; s++ )
1207 {
1208 if( *s == '%' )
1209 {
1210 s++;
1211 if( *s == '%' )
1212 f << *s;
1213 else
1214 {
1215 String sNum;
1216 while( s && *s >= '0' && *s <= '9' )
1217 {
1218 sNum += *s;
1219 s++;
1220 }
1221 int iIndex = strtol( sNum.getStr(), 0, 10 )-1;
1222 if( iIndex < 0 || iIndex >= iCount )
1223 {
1224 delete[] aArg;
1225 throw Bu::ExceptionBase(
1226 "Argument index %d is outside of "
1227 "valid range (1-%d).", iIndex+1, iCount
1228 );
1229 }
1230
1231 f << (*aArg[iIndex]).format << (*aArg[iIndex]).value;
1232 if( s )
1233 f << *s;
1234 }
1235 }
1236 else
1237 {
1238 f << *s;
1239 }
1240 }
1241
1242 delete[] aArg;
1243 return mbOut.getString();
1244}
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
13 1290
14template class Bu::BasicString<char>;
15 1291
16template<> uint32_t Bu::__calcHashCode<Bu::String>( const Bu::String &k ) 1292template<> uint32_t Bu::__calcHashCode<Bu::String>( const Bu::String &k )
17{ 1293{
@@ -126,3 +1402,20 @@ Bu::String &Bu::operator<<( Bu::String &dst, const Bu::String &sIn )
126 return dst; 1402 return dst;
127} 1403}
128 1404
1405Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, const Bu::String &s )
1406{
1407 long n = s.getSize();
1408 ar << n;
1409 ar.write( s.getConstStr(), n );
1410 return ar;
1411}
1412
1413Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, Bu::String &s )
1414{
1415 long n;
1416 ar >> n;
1417 s.setSize( n );
1418 ar.read( s.getStr(), n );
1419 return ar;
1420}
1421
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 @@
20#include "bu/exceptionbase.h" 20#include "bu/exceptionbase.h"
21#include "bu/archivebase.h" 21#include "bu/archivebase.h"
22#include "bu/list.h" 22#include "bu/list.h"
23#include "bu/fmt.h"
24#include "bu/variant.h"
23 25
24#include <string.h> 26#include <string.h>
27
28#define nMinSize (256)
25 29
26namespace Bu 30namespace Bu
27{ 31{
28 /** @cond DEVEL */ 32 class String;
29 template< typename chr >
30 struct StringChunk
31 {
32 long nLength;
33 chr *pData;
34 StringChunk *pNext;
35 };
36
37 template< typename chr, int nMinSize, typename chralloc,
38 typename chunkalloc> class BasicString;
39
40 template<typename chr>
41 size_t strlen( const chr *pData )
42 {
43 for( size_t tLen = 0;; ++tLen )
44 {
45 if( pData[tLen] == (chr)0 )
46 return tLen;
47 }
48 return -1;
49 }
50
51 template<char>
52 size_t strlen( const char *pData )
53 {
54 return ::strlen( pData );
55 }
56
57 template<typename chr>
58 int strncmp( const chr *a, const chr *b, size_t iLen )
59 {
60 for( size_t iPos = 0; iPos < iLen; iPos++ )
61 {
62 if( a[iPos] != b[iPos] )
63 {
64 return a[iPos]-b[iPos];
65 }
66 }
67 return 0;
68 }
69
70 template<char>
71 int strncmp( const char *a, const char *b, size_t iLen )
72 {
73 return ::strncmp( a, b, iLen );
74 }
75 33
76 template<typename chr, int nMinSize, typename chralloc, typename chunkalloc> 34 /** @cond DEVEL */
77 struct StringCore 35 class StringCore
78 { 36 {
79 friend class BasicString<chr, nMinSize, chralloc, chunkalloc>; 37 friend class String;
80 friend class SharedCore< 38 friend class SharedCore<String, StringCore>;
81 BasicString<chr, nMinSize, chralloc, chunkalloc>,
82 StringCore<chr, nMinSize, chralloc, chunkalloc>
83 >;
84 private: 39 private:
85 typedef struct StringCore<chr, nMinSize, chralloc, chunkalloc> MyType; 40 struct Chunk
86 typedef struct StringChunk<chr> Chunk;
87 StringCore() :
88 nLength( 0 ),
89 pFirst( NULL ),
90 pLast( NULL )
91 {
92 }
93
94 StringCore( const MyType &rSrc ) :
95 nLength( rSrc.nLength ),
96 pFirst( NULL ),
97 pLast( NULL ),
98 aChr( rSrc.aChr ),
99 aChunk( rSrc.aChunk )
100 { 41 {
101 if( rSrc.pFirst == NULL || rSrc.nLength == 0 ) 42 long nLength;
102 { 43 char *pData;
103 pFirst = pLast = NULL; 44 Chunk *pNext;
104 } 45 };
105 else
106 {
107 pFirst = pLast = newChunk( nLength );
108 Chunk *pLink = rSrc.pFirst;
109 int iPos = 0;
110 while( pLink != NULL )
111 {
112 memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
113 iPos += pLink->nLength;
114 pLink = pLink->pNext;
115 }
116 }
117 }
118 46
119 virtual ~StringCore() 47 StringCore();
120 { 48 StringCore( const StringCore &rSrc );
121 clear(); 49 virtual ~StringCore();
122 }
123 50
124 mutable long nLength; 51 mutable long nLength;
125 mutable Chunk *pFirst; 52 mutable Chunk *pFirst;
126 mutable Chunk *pLast; 53 mutable Chunk *pLast;
127 54
128 mutable chralloc aChr; 55 void clear() const;
129 mutable chunkalloc aChunk; 56 Chunk *newChunk() const;
130 57 Chunk *newChunk( long nLen ) const;
131 void clear() const 58 Chunk *copyChunk( Chunk *pSrc ) const;
132 { 59 void appendChunk( Chunk *pNewChunk );
133 if( pFirst == NULL ) 60 void prependChunk( Chunk *pNewChunk );
134 return;
135
136 Chunk *i = pFirst;
137 for(;;)
138 {
139 Chunk *n = i->pNext;
140 aChr.deallocate( i->pData,
141 (i->nLength<nMinSize)?(nMinSize):(i->nLength)+1 );
142 aChunk.deallocate( i, 1 );
143 if( n == NULL )
144 break;
145 i = n;
146 }
147 pFirst = pLast = NULL;
148 nLength = 0;
149 }
150
151 Chunk *newChunk() const
152 {
153 Chunk *pNew = aChunk.allocate( 1 );
154 pNew->pNext = NULL;
155 return pNew;
156 }
157
158 Chunk *newChunk( long nLen ) const
159 {
160 Chunk *pNew = aChunk.allocate( 1 );
161 pNew->pNext = NULL;
162 pNew->nLength = nLen;
163 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
164 pNew->pData[nLen] = (chr)0;
165 return pNew;
166 }
167
168 Chunk *copyChunk( Chunk *pSrc ) const
169 {
170 Chunk *pNew = aChunk.allocate( 1 );
171 pNew->pNext = pSrc->pNext;
172 pNew->nLength = pSrc->nLength;
173 pNew->pData = aChr.allocate(
174 (pNew->nLength<nMinSize)?(nMinSize):(pNew->nLength)+1 );
175 memcpy( pNew->pData, pSrc->pData, pSrc->nLength );
176 pNew->pData[pNew->nLength] = (chr)0;
177 return pNew;
178 }
179
180 void appendChunk( Chunk *pNewChunk )
181 {
182 if( pFirst == NULL )
183 pLast = pFirst = pNewChunk;
184 else
185 {
186 pLast->pNext = pNewChunk;
187 pLast = pNewChunk;
188 }
189
190 nLength += pNewChunk->nLength;
191 }
192
193 void prependChunk( Chunk *pNewChunk )
194 {
195 if( pFirst == NULL )
196 pLast = pFirst = pNewChunk;
197 else
198 {
199 pNewChunk->pNext = pFirst;
200 pFirst = pNewChunk;
201 }
202
203 nLength += pNewChunk->nLength;
204 }
205 }; 61 };
206 /** @endcond */ 62 /** @endcond */
207 63
208 /** 64 /**
209 * Flexible String class. This class was designed with string passing and
210 * generation in mind. Like the standard string class you can specify what
211 * datatype to use for each character. Unlike the standard string class,
212 * collection of appended and prepended terms is done lazily, making long
213 * operations that involve many appends very inexpensive. In addition
214 * internal ref-counting means that if you pass strings around between
215 * functions there's almost no overhead in time or memory since a reference
216 * is created and no data is actually copied. This also means that you
217 * never need to put any BasicString into a ref-counting container class.
218 *
219 *@param chr (typename) Type of character (i.e. char)
220 *@param nMinSize (int) Chunk size (default: 256)
221 *@param chralloc (typename) Memory Allocator for chr
222 *@param chunkalloc (typename) Memory Allocator for chr chunks
223 */ 65 */
224 template< typename chr, int nMinSize=256, 66 class String : public SharedCore<String, StringCore>
225 typename chralloc=std::allocator<chr>,
226 typename chunkalloc=std::allocator<struct StringChunk<chr> > >
227 class BasicString : public SharedCore<
228 BasicString<chr, nMinSize, chralloc, chunkalloc>,
229 StringCore<chr, nMinSize, chralloc, chunkalloc> >
230 { 67 {
231 protected: 68 protected:
232 typedef struct StringChunk<chr> Chunk; 69 using SharedCore<String, StringCore >::core;
233 typedef struct BasicString<chr, nMinSize, chralloc, chunkalloc> MyType; 70 using SharedCore<String, StringCore >::_hardCopy;
234 typedef struct StringCore<chr, nMinSize, chralloc, chunkalloc> Core;
235 71
236 using SharedCore<MyType, Core >::core; 72 private:
237 using SharedCore<MyType, Core >::_hardCopy; 73 typedef StringCore::Chunk Chunk;
238 74
239 public: // Iterators 75 public: // Iterators
240 struct iterator; 76 struct iterator;
241 typedef struct const_iterator 77 typedef struct const_iterator
242 { 78 {
243 friend class BasicString<chr, nMinSize, chralloc, chunkalloc>; 79 friend class String;
244 friend struct iterator; 80 friend struct iterator;
245 private: 81 private:
246 const_iterator( Chunk *pChunk, int iPos ) : 82 const_iterator( Chunk *pChunk, int iPos ) :
@@ -334,19 +170,19 @@ namespace Bu
334 return ret; 170 return ret;
335 } 171 }
336 172
337 const chr &operator *() const 173 const char &operator *() const
338 { 174 {
339 if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator."); 175 if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator.");
340 return pChunk->pData[iPos]; 176 return pChunk->pData[iPos];
341 } 177 }
342 178
343 bool operator==( const chr &c ) const 179 bool operator==( const char &c ) const
344 { 180 {
345 if( !pChunk ) return false; 181 if( !pChunk ) return false;
346 return pChunk->pData[iPos] == c; 182 return pChunk->pData[iPos] == c;
347 } 183 }
348 184
349 bool operator!=( const chr &c ) const 185 bool operator!=( const char &c ) const
350 { 186 {
351 if( !pChunk ) return false; 187 if( !pChunk ) return false;
352 return pChunk->pData[iPos] != c; 188 return pChunk->pData[iPos] != c;
@@ -390,7 +226,7 @@ namespace Bu
390 return true; 226 return true;
391 } 227 }
392 228
393 bool compare( const chr *c ) const 229 bool compare( const char *c ) const
394 { 230 {
395 if( !pChunk ) return false; 231 if( !pChunk ) return false;
396 const_iterator a = *this; 232 const_iterator a = *this;
@@ -399,12 +235,12 @@ namespace Bu
399 if( *a != *c ) 235 if( *a != *c )
400 return false; 236 return false;
401 } 237 }
402 if( a.isValid() != (*c!=(chr)0) ) 238 if( a.isValid() != (*c!=(char)0) )
403 return false; 239 return false;
404 return true; 240 return true;
405 } 241 }
406 242
407 bool compare( const chr *c, int nLen ) const 243 bool compare( const char *c, int nLen ) const
408 { 244 {
409 if( !pChunk ) return false; 245 if( !pChunk ) return false;
410 const_iterator a = *this; 246 const_iterator a = *this;
@@ -419,19 +255,19 @@ namespace Bu
419 return true; 255 return true;
420 } 256 }
421 257
422 bool compare( const MyType &s ) const 258 bool compare( const String &s ) const
423 { 259 {
424 if( !pChunk ) return false; 260 if( !pChunk ) return false;
425 return compare( s.begin() ); 261 return compare( s.begin() );
426 } 262 }
427 263
428 bool compare( const MyType &s, int nLen ) const 264 bool compare( const String &s, int nLen ) const
429 { 265 {
430 if( !pChunk ) return false; 266 if( !pChunk ) return false;
431 return compare( s.begin(), nLen ); 267 return compare( s.begin(), nLen );
432 } 268 }
433 269
434 const_iterator find( const chr c ) const 270 const_iterator find( const char c ) const
435 { 271 {
436 for( const_iterator i = *this; i; i++ ) 272 for( const_iterator i = *this; i; i++ )
437 { 273 {
@@ -441,7 +277,7 @@ namespace Bu
441 return const_iterator( NULL, 0 ); 277 return const_iterator( NULL, 0 );
442 } 278 }
443 279
444 const_iterator find( const chr *pStr, int nLen ) const 280 const_iterator find( const char *pStr, int nLen ) const
445 { 281 {
446 for( const_iterator i = *this; i; i++ ) 282 for( const_iterator i = *this; i; i++ )
447 { 283 {
@@ -451,7 +287,7 @@ namespace Bu
451 return const_iterator( NULL, 0 ); 287 return const_iterator( NULL, 0 );
452 } 288 }
453 289
454 const_iterator find( const MyType &s ) const 290 const_iterator find( const String &s ) const
455 { 291 {
456 for( const_iterator i = *this; i; i++ ) 292 for( const_iterator i = *this; i; i++ )
457 { 293 {
@@ -461,7 +297,7 @@ namespace Bu
461 return const_iterator( NULL, 0 ); 297 return const_iterator( NULL, 0 );
462 } 298 }
463 299
464 const_iterator find( const MyType &s, int nLen ) const 300 const_iterator find( const String &s, int nLen ) const
465 { 301 {
466 for( const_iterator i = *this; i; i++ ) 302 for( const_iterator i = *this; i; i++ )
467 { 303 {
@@ -474,7 +310,7 @@ namespace Bu
474 310
475 typedef struct iterator 311 typedef struct iterator
476 { 312 {
477 friend class BasicString<chr, nMinSize, chralloc, chunkalloc>; 313 friend class String;
478 friend struct const_iterator; 314 friend struct const_iterator;
479 private: 315 private:
480 iterator( Chunk *pChunk, int iPos ) : 316 iterator( Chunk *pChunk, int iPos ) :
@@ -567,31 +403,31 @@ namespace Bu
567 return ret; 403 return ret;
568 } 404 }
569 405
570 chr &operator*() 406 char &operator*()
571 { 407 {
572 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); 408 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
573 return pChunk->pData[iPos]; 409 return pChunk->pData[iPos];
574 } 410 }
575 411
576 const chr &operator*() const 412 const char &operator*() const
577 { 413 {
578 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); 414 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
579 return pChunk->pData[iPos]; 415 return pChunk->pData[iPos];
580 } 416 }
581 417
582 bool operator==( const chr &c ) const 418 bool operator==( const char &c ) const
583 { 419 {
584 if( !pChunk ) return false; 420 if( !pChunk ) return false;
585 return pChunk->pData[iPos] == c; 421 return pChunk->pData[iPos] == c;
586 } 422 }
587 423
588 bool operator!=( const chr &c ) const 424 bool operator!=( const char &c ) const
589 { 425 {
590 if( !pChunk ) return false; 426 if( !pChunk ) return false;
591 return pChunk->pData[iPos] != c; 427 return pChunk->pData[iPos] != c;
592 } 428 }
593 429
594 iterator &operator=( const chr &c ) 430 iterator &operator=( const char &c )
595 { 431 {
596 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator."); 432 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
597 pChunk->pData[iPos] = c; 433 pChunk->pData[iPos] = c;
@@ -636,7 +472,7 @@ namespace Bu
636 return true; 472 return true;
637 } 473 }
638 474
639 bool compare( const chr *c ) const 475 bool compare( const char *c ) const
640 { 476 {
641 if( !pChunk ) return false; 477 if( !pChunk ) return false;
642 iterator a = *this; 478 iterator a = *this;
@@ -645,12 +481,12 @@ namespace Bu
645 if( *a != *c ) 481 if( *a != *c )
646 return false; 482 return false;
647 } 483 }
648 if( a.isValid() != (*c!=(chr)0) ) 484 if( a.isValid() != (*c!=(char)0) )
649 return false; 485 return false;
650 return true; 486 return true;
651 } 487 }
652 488
653 bool compare( const chr *c, int nLen ) const 489 bool compare( const char *c, int nLen ) const
654 { 490 {
655 if( !pChunk ) return false; 491 if( !pChunk ) return false;
656 iterator a = *this; 492 iterator a = *this;
@@ -665,19 +501,19 @@ namespace Bu
665 return true; 501 return true;
666 } 502 }
667 503
668 bool compare( const MyType &s ) const 504 bool compare( const String &s ) const
669 { 505 {
670 if( !pChunk ) return false; 506 if( !pChunk ) return false;
671 return compare( s.begin() ); 507 return compare( s.begin() );
672 } 508 }
673 509
674 bool compare( const MyType &s, int nLen ) const 510 bool compare( const String &s, int nLen ) const
675 { 511 {
676 if( !pChunk ) return false; 512 if( !pChunk ) return false;
677 return compare( s.begin(), nLen ); 513 return compare( s.begin(), nLen );
678 } 514 }
679 515
680 iterator find( const chr c ) const 516 iterator find( const char c ) const
681 { 517 {
682 for( iterator i = *this; i; i++ ) 518 for( iterator i = *this; i; i++ )
683 { 519 {
@@ -687,7 +523,7 @@ namespace Bu
687 return iterator( NULL, 0 ); 523 return iterator( NULL, 0 );
688 } 524 }
689 525
690 iterator find( const chr *pStr, int nLen ) const 526 iterator find( const char *pStr, int nLen ) const
691 { 527 {
692 for( iterator i = *this; i; i++ ) 528 for( iterator i = *this; i; i++ )
693 { 529 {
@@ -697,7 +533,7 @@ namespace Bu
697 return iterator( NULL, 0 ); 533 return iterator( NULL, 0 );
698 } 534 }
699 535
700 iterator find( const MyType &s ) const 536 iterator find( const String &s ) const
701 { 537 {
702 for( iterator i = *this; i; i++ ) 538 for( iterator i = *this; i; i++ )
703 { 539 {
@@ -707,7 +543,7 @@ namespace Bu
707 return iterator( NULL, 0 ); 543 return iterator( NULL, 0 );
708 } 544 }
709 545
710 iterator find( const MyType &s, int nLen ) const 546 iterator find( const String &s, int nLen ) const
711 { 547 {
712 for( iterator i = *this; i; i++ ) 548 for( iterator i = *this; i; i++ )
713 { 549 {
@@ -719,711 +555,232 @@ namespace Bu
719 } iterator; 555 } iterator;
720 556
721 public: 557 public:
722 BasicString() 558 String();
723 { 559 String( const char *pData );
724 } 560 String( const char *pData, long nLength );
725 561 String( const String &rSrc );
726 BasicString( const chr *pData ) 562 String( const String &rSrc, long nLength );
727 { 563 String( const String &rSrc, long nStart, long nLength );
728 append( pData ); 564 String( long nSize );
729 } 565 String( const const_iterator &s );
730 566 String( const const_iterator &s, const const_iterator &e );
731 BasicString( const chr *pData, long nLength ) 567 virtual ~String();
732 {
733 append( pData, nLength );
734 }
735
736 BasicString( const MyType &rSrc ) :
737 SharedCore<MyType, Core>( rSrc )
738 {
739 }
740
741 BasicString( const MyType &rSrc, long nLength )
742 {
743 append( rSrc, nLength );
744 }
745
746 BasicString( const MyType &rSrc, long nStart, long nLength )
747 {
748 append( rSrc, nStart, nLength );
749 }
750
751 BasicString( long nSize )
752 {
753 core->pFirst = core->pLast = core->newChunk( nSize );
754 core->nLength = nSize;
755 }
756
757 BasicString( const const_iterator &s )
758 {
759 append( s );
760 }
761
762 BasicString( const const_iterator &s, const const_iterator &e )
763 {
764 append( s, e );
765 }
766
767 virtual ~BasicString()
768 {
769 }
770 568
771 /** 569 /**
772 * Append data to your string. 570 * Append data to your string.
773 *@param pData (const chr *) The data to append. 571 *@param pData (const char *) The data to append.
774 */ 572 */
775 void append( const chr *pData ) 573 void append( const char *pData );
776 {
777 if( !pData ) return;
778 long nLen;
779 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
780
781 append( pData, 0, nLen );
782 }
783 574
784 /** 575 /**
785 * Append data to your string. 576 * Append data to your string.
786 *@param pData (const chr *) The data to append. 577 *@param pData (const char *) The data to append.
787 *@param nLen (long) The length of the data to append. 578 *@param nLen (long) The length of the data to append.
788 */ 579 */
789 void append( const chr *pData, long nLen ) 580 void append( const char *pData, long nLen );
790 {
791 append( pData, 0, nLen );
792 }
793 581
794 /** 582 /**
795 * Append data to your string. 583 * Append data to your string.
796 *@param pData (const chr *) The data to append. 584 *@param pData (const char *) The data to append.
797 *@param nStart (long) The start position to copy from. 585 *@param nStart (long) The start position to copy from.
798 *@param nLen (long) The length of the data to append. 586 *@param nLen (long) The length of the data to append.
799 */ 587 */
800 void append( const chr *pData, long nStart, long nLen ) 588 void append( const char *pData, long nStart, long nLen );
801 {
802 if( !pData ) return;
803 if( nLen <= 0 )
804 return;
805
806 pData += nStart;
807
808 _hardCopy();
809
810 if( core->pLast && core->pLast->nLength < nMinSize )
811 {
812 int nAmnt = nMinSize - core->pLast->nLength;
813 if( nAmnt > nLen )
814 nAmnt = nLen;
815 memcpy(
816 core->pLast->pData+core->pLast->nLength,
817 pData,
818 nAmnt
819 );
820 pData += nAmnt;
821 core->pLast->nLength += nAmnt;
822 nLen -= nAmnt;
823 core->nLength += nAmnt;
824 }
825
826 if( nLen > 0 )
827 {
828 Chunk *pNew = core->newChunk( nLen );
829 memcpy( pNew->pData, pData, nLen );
830 core->appendChunk( pNew );
831// core->nLength += nLen;
832 }
833 }
834 589
835 /** 590 /**
836 * Append a single chr to your string. 591 * Append a single char to your string.
837 *@param cData (const chr &) The character to append. 592 *@param cData (const char &) The character to append.
838 */ 593 */
839 void append( const chr &cData ) 594 void append( const char &cData );
840 {
841 if( core->pLast && core->pLast->nLength < nMinSize )
842 {
843 _hardCopy();
844 core->pLast->pData[core->pLast->nLength] = cData;
845 ++core->pLast->nLength; ++core->nLength;
846 // pLast->pData[pLast->nLength] = (chr)0;
847 }
848 else
849 {
850 append( &cData, 1 );
851 }
852 }
853 595
854 /** 596 /**
855 * Append another String to this one. 597 * Append another String to this one.
856 *@param sData (MyType &) The String to append. 598 *@param sData (String &) The String to append.
857 *@todo This function can be made much faster by not using getStr() 599 *@todo This function can be made much faster by not using getStr()
858 */ 600 */
859 void append( const MyType & sData ) 601 void append( const String & sData );
860 {
861 append( sData.getStr(), 0, sData.getSize() );
862 }
863 602
864 /** 603 /**
865 * Append another String to this one. 604 * Append another String to this one.
866 *@param sData (MyType &) The String to append. 605 *@param sData (String &) The String to append.
867 *@param nLen How much data to append. 606 *@param nLen How much data to append.
868 *@todo This function can be made much faster by not using getStr() 607 *@todo This function can be made much faster by not using getStr()
869 */ 608 */
870 void append( const MyType & sData, long nLen ) 609 void append( const String & sData, long nLen );
871 {
872 append( sData.getStr(), 0, nLen );
873 }
874 610
875 /** 611 /**
876 * Append another String to this one. 612 * Append another String to this one.
877 *@param sData (MyType &) The String to append. 613 *@param sData (String &) The String to append.
878 *@param nStart Start position in sData to start copying from. 614 *@param nStart Start position in sData to start copying from.
879 *@param nLen How much data to append. 615 *@param nLen How much data to append.
880 *@todo This function can be made much faster by not using getStr() 616 *@todo This function can be made much faster by not using getStr()
881 */ 617 */
882 void append( const MyType & sData, long nStart, long nLen ) 618 void append( const String & sData, long nStart, long nLen );
883 {
884 if( nLen < 0 )
885 nLen = sData.getSize() - nStart;
886 append( sData.getStr(), nStart, nLen );
887 }
888 619
889 /** 620 /**
890 * Append data to this String using the passed in iterator as a base. 621 * Append data to this String using the passed in iterator as a base.
891 * The iterator is const, it is not changed. 622 * The iterator is const, it is not changed.
892 *@param s Iterator from any compatible BasicString to copy data from. 623 *@param s Iterator from any compatible String to copy data from.
893 */ 624 */
894 void append( const const_iterator &s ) 625 void append( const const_iterator &s );
895 {
896 if( !s.isValid() )
897 return;
898 Chunk *pSrc = s.pChunk;
899
900 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
901 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
902
903 _hardCopy();
904 core->appendChunk( pNew );
905
906 while( (pSrc = pSrc->pNext) )
907 {
908 core->appendChunk( core->copyChunk( pSrc ) );
909 }
910 }
911 626
912 /** 627 /**
913 * Append data to this String using the passed in iterator as a base. 628 * Append data to this String using the passed in iterator as a base.
914 * The iterator is const, it is not changed. 629 * The iterator is const, it is not changed.
915 *@param s Iterator from any compatible BasicString to copy data from. 630 *@param s Iterator from any compatible String to copy data from.
916 */ 631 */
917 void append( const iterator &s ) // I get complaints without this one 632 void append( const iterator &s );
918 {
919 append( const_iterator( s ) );
920 }
921 633
922 /** 634 /**
923 * Append data to this String using the passed in iterator as a base, 635 * Append data to this String using the passed in iterator as a base,
924 * and copy data until the ending iterator is reached. The character 636 * and copy data until the ending iterator is reached. The character
925 * at the ending iterator is not copied. 637 * at the ending iterator is not copied.
926 * The iterators are const, they are not changed. 638 * The iterators are const, they are not changed.
927 *@param s Iterator from any compatible BasicString to copy data from. 639 *@param s Iterator from any compatible String to copy data from.
928 *@param e Iterator to stop copying at. 640 *@param e Iterator to stop copying at.
929 */ 641 */
930 void append( const const_iterator &s, const const_iterator &e ) 642 void append( const const_iterator &s, const const_iterator &e );
931 {
932 if( !s.isValid() )
933 return;
934 if( !e.isValid() )
935 {
936 append( s );
937 return;
938 }
939 _hardCopy();
940 if( s.pChunk == e.pChunk )
941 {
942 // Simple case, they're the same chunk
943 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
944 memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
945 core->appendChunk( pNew );
946 }
947 else
948 {
949 // A little trickier, scan the blocks...
950 Chunk *pSrc = s.pChunk;
951 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
952 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
953 core->appendChunk( pNew );
954
955 while( (pSrc = pSrc->pNext) != e.pChunk )
956 {
957 core->appendChunk( core->copyChunk( pSrc ) );
958 }
959
960 pNew = core->newChunk( e.iPos );
961 memcpy( pNew->pData, pSrc->pData, e.iPos );
962 core->appendChunk( pNew );
963 }
964 }
965 643
966 /** 644 /**
967 * Prepend another String to this one. 645 * Prepend another String to this one.
968 *@param sData (MyType &) The String to prepend. 646 *@param sData (String &) The String to prepend.
969 *@todo This function can be made much faster by not using getStr() 647 *@todo This function can be made much faster by not using getStr()
970 */ 648 */
971 void prepend( const MyType & sData ) 649 void prepend( const String & sData );
972 {
973 prepend( sData.getStr(), sData.getSize() );
974 }
975 650
976 /** 651 /**
977 * Prepend data to your string. 652 * Prepend data to your string.
978 *@param pData (const chr *) The data to prepend. 653 *@param pData (const char *) The data to prepend.
979 */ 654 */
980 void prepend( const chr *pData ) 655 void prepend( const char *pData );
981 {
982 if( pData == NULL )
983 return;
984
985 _hardCopy();
986 long nLen;
987 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
988
989 Chunk *pNew = core->newChunk( nLen );
990 memcpy( pNew->pData, pData, nLen );
991
992 core->prependChunk( pNew );
993 }
994 656
995 /** 657 /**
996 * Prepend data to your string. 658 * Prepend data to your string.
997 *@param pData (const chr *) The data to prepend. 659 *@param pData (const char *) The data to prepend.
998 *@param nLen (long) The length of the data to prepend. 660 *@param nLen (long) The length of the data to prepend.
999 */ 661 */
1000 void prepend( const chr *pData, long nLen ) 662 void prepend( const char *pData, long nLen );
1001 {
1002 Chunk *pNew = core->newChunk( nLen );
1003
1004 memcpy( pNew->pData, pData, nLen );
1005
1006 _hardCopy();
1007 core->prependChunk( pNew );
1008 }
1009 663
1010 void prepend( const chr c ) 664 void prepend( const char c );
1011 {
1012 prepend( &c, 1 );
1013 }
1014 665
1015 /** 666 /**
1016 * Insert pData before byte nPos, that is, the first byte of pData will 667 * Insert pData before byte nPos, that is, the first byte of pData will
1017 * start at nPos. This could probably be made faster by avoiding 668 * start at nPos. This could probably be made faster by avoiding
1018 * flattening. 669 * flattening.
1019 */ 670 */
1020 void insert( long nPos, const chr *pData, long nLen ) 671 void insert( long nPos, const char *pData, long nLen );
1021 {
1022 if( nLen <= 0 )
1023 return;
1024 if( nPos <= 0 )
1025 {
1026 prepend( pData, nLen );
1027 }
1028 else if( nPos >= core->nLength )
1029 {
1030 append( pData, nLen );
1031 }
1032 else
1033 {
1034 // If we're going to flatten anyway, might as well for everyone
1035 flatten();
1036 _hardCopy();
1037 Chunk *p1 = core->newChunk( nPos );
1038 Chunk *p2 = core->newChunk( nLen );
1039 Chunk *p3 = core->newChunk( core->nLength-nPos );
1040 memcpy( p1->pData, core->pFirst->pData, nPos );
1041 memcpy( p2->pData, pData, nLen );
1042 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
1043 core->clear();
1044 core->appendChunk( p1 );
1045 core->appendChunk( p2 );
1046 core->appendChunk( p3 );
1047 }
1048 }
1049
1050 void insert( long nPos, const MyType &str )
1051 {
1052 if( nPos <= 0 )
1053 {
1054 prepend( str );
1055 }
1056 else if( nPos >= core->nLength )
1057 {
1058 append( str );
1059 }
1060 else
1061 {
1062 flatten();
1063 _hardCopy();
1064 Chunk *p1 = core->newChunk( nPos );
1065 Chunk *p3 = core->newChunk( core->nLength-nPos );
1066 memcpy( p1->pData, core->pFirst->pData, nPos );
1067 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
1068 core->clear();
1069 core->appendChunk( p1 );
1070 for( Chunk *pChnk = str.core->pFirst; pChnk;
1071 pChnk = pChnk->pNext )
1072 {
1073 core->appendChunk( core->copyChunk( pChnk ) );
1074 }
1075 672
1076 core->appendChunk( p3 ); 673 void insert( long nPos, const String &str );
1077 }
1078 }
1079 674
1080 /** 675 /**
1081 *@todo This function shouldn't use strlen, we should add our own to 676 *@todo This function shouldn't use strlen, we should add our own to
1082 * this class, one that can be overridden in a specific implementation. 677 * this class, one that can be overridden in a specific implementation.
1083 */ 678 */
1084 void insert( long nPos, const chr *pData ) 679 void insert( long nPos, const char *pData );
1085 {
1086 insert( nPos, pData, Bu::strlen( pData ) );
1087 }
1088 680
1089 void remove( long nPos, long nLen ) 681 void remove( long nPos, long nLen );
1090 {
1091 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
1092 return;
1093 if( nLen > core->nLength-nPos )
1094 nLen = core->nLength-nPos;
1095 flatten();
1096 _hardCopy();
1097 memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
1098 core->nLength -= nLen;
1099 core->pFirst->nLength -= nLen;
1100 }
1101 682
1102 /** 683 /**
1103 * Clear all data from the string. 684 * Clear all data from the string.
1104 */ 685 */
1105 void clear() 686 void clear();
1106 {
1107 _hardCopy();
1108 core->clear();
1109 }
1110 687
1111 MyType replace( const MyType &fnd, const MyType &rep ) const 688 String replace( const String &fnd, const String &rep ) const;
1112 {
1113 MyType out;
1114 const_iterator o = begin();
1115 while( true )
1116 {
1117 const_iterator i = o.find( fnd );
1118 if( !i )
1119 {
1120 out.append( o );
1121 return out;
1122 }
1123 else
1124 {
1125 out.append( o, i );
1126 out.append( rep );
1127 o = i;
1128 o += fnd.getSize();
1129 }
1130 }
1131 }
1132 689
1133 /** 690 /**
1134 * Force the string to resize 691 * Force the string to resize
1135 *@param nNewSize (long) The new size of the string. 692 *@param nNewSize (long) The new size of the string.
1136 */ 693 */
1137 void resize( long nNewSize ) 694 void resize( long nNewSize );
1138 {
1139 if( core->nLength == nNewSize )
1140 return;
1141 if( nNewSize < 0 )
1142 nNewSize = 0;
1143
1144 flatten();
1145 _hardCopy();
1146
1147 // TODO: This is bad
1148
1149 Chunk *pNew = core->newChunk( nNewSize );
1150 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
1151 if( core->nLength > 0 )
1152 {
1153 memcpy( pNew->pData, core->pFirst->pData, nNewLen );
1154 core->aChr.deallocate( core->pFirst->pData,
1155 (core->pFirst->nLength<nMinSize)?(nMinSize):(core->pFirst->nLength)+1 );
1156 core->aChunk.deallocate( core->pFirst, 1 );
1157 }
1158 pNew->pData[nNewLen] = (chr)0;
1159 core->pFirst = core->pLast = pNew;
1160 core->nLength = nNewSize;
1161 }
1162 695
1163 /** 696 /**
1164 * Get the current size of the string. 697 * Get the current size of the string.
1165 *@returns (long) The current size of the string. 698 *@returns (long) The current size of the string.
1166 */ 699 */
1167 long getSize() const 700 long getSize() const;
1168 {
1169 return core->nLength;
1170 }
1171 701
1172 /** 702 /**
1173 * Get a pointer to the string array. 703 * Get a pointer to the string array.
1174 *@returns (chr *) The string data. 704 *@returns (char *) The string data.
1175 */ 705 */
1176 chr *getStr() 706 char *getStr();
1177 {
1178 if( core->pFirst == NULL || core->nLength == 0 )
1179 return (chr *)"";
1180
1181 flatten();
1182 _hardCopy();
1183 core->pFirst->pData[core->nLength] = (chr)0;
1184 return core->pFirst->pData;
1185 }
1186 707
1187 /** 708 /**
1188 * Get a const pointer to the string array. 709 * Get a const pointer to the string array.
1189 *@returns (const chr *) The string data. 710 *@returns (const char *) The string data.
1190 */ 711 */
1191 const chr *getStr() const 712 const char *getStr() const;
1192 {
1193 if( core->pFirst == NULL || core->nLength == 0 )
1194 return (chr *)"";
1195
1196 flatten();
1197 core->pFirst->pData[core->nLength] = (chr)0;
1198 return core->pFirst->pData;
1199 }
1200 713
1201 /** 714 /**
1202 * A convinience function, this one won't cause as much work as the 715 * A convinience function, this one won't cause as much work as the
1203 * non-const getStr, so if you're not changing the data, consider it. 716 * non-const getStr, so if you're not changing the data, consider it.
1204 */ 717 */
1205 const chr *getConstStr() const 718 const char *getConstStr() const;
1206 {
1207 return getStr();
1208 }
1209 719
1210 MyType getSubStrIdx( long iStart, long iSize=-1 ) const 720 String getSubStrIdx( long iStart, long iSize=-1 ) const;
1211 {
1212 if( iStart < 0 )
1213 iStart = 0;
1214 if( iStart >= core->nLength )
1215 return (const chr[]){(chr)0};
1216 if( iSize < 0 )
1217 iSize = core->nLength;
1218 if( iStart+iSize > core->nLength )
1219 iSize = core->nLength-iStart;
1220 if( iSize == 0 )
1221 return (const chr[]){(chr)0};
1222
1223 flatten();
1224 MyType ret( core->pFirst->pData+iStart, iSize );
1225 return ret;
1226 }
1227 721
1228 MyType getSubStr( const_iterator iBegin, 722 String getSubStr( const_iterator iBegin,
1229 const_iterator iEnd=typename MyType::const_iterator() ) const 723 const_iterator iEnd=String::const_iterator() ) const;
1230 {
1231 if( !iBegin.isValid() )
1232 return MyType();
1233 if( iBegin.pChunk == iEnd.pChunk )
1234 {
1235 return MyType( iBegin.pChunk->pData+iBegin.iPos,
1236 iEnd.iPos-iBegin.iPos );
1237 }
1238 else if( !iEnd.isValid() )
1239 {
1240 MyType ret;
1241 ret.append(
1242 iBegin.pChunk->pData+iBegin.iPos,
1243 iBegin.pChunk->nLength-iBegin.iPos
1244 );
1245 for( Chunk *pCur = iBegin.pChunk->pNext;
1246 pCur; pCur = pCur->pNext )
1247 {
1248 ret.append( pCur->pData, pCur->nLength );
1249 }
1250 return ret;
1251 }
1252 else
1253 {
1254 MyType ret;
1255 ret.append(
1256 iBegin.pChunk->pData+iBegin.iPos,
1257 iBegin.pChunk->nLength-iBegin.iPos
1258 );
1259 for( Chunk *pCur = iBegin.pChunk->pNext;
1260 pCur != iEnd.pChunk; pCur = pCur->pNext )
1261 {
1262 ret.append( pCur->pData, pCur->nLength );
1263 }
1264 ret.append(
1265 iEnd.pChunk->pData,
1266 iEnd.iPos
1267 );
1268 return ret;
1269 }
1270 }
1271 724
1272 Bu::List<MyType> split( const chr c ) const 725 Bu::List<String> split( const char c ) const;
1273 {
1274 Bu::List<MyType> ret;
1275 const_iterator l, r;
1276 l = begin();
1277 for(r=l; l;)
1278 {
1279 for( r = l; r && r != c; r++ ) { }
1280 ret.append( MyType( l, r ) );
1281 l = r;
1282 l++;
1283 }
1284 return ret;
1285 }
1286 726
1287 /** 727 /**
1288 * Plus equals operator for String. 728 * Plus equals operator for String.
1289 *@param pData (const chr *) The data to append to your String. 729 *@param pData (const char *) The data to append to your String.
1290 */ 730 */
1291 MyType &operator+=( const chr *pData ) 731 String &operator+=( const char *pData );
1292 {
1293 append( pData );
1294
1295 return (*this);
1296 }
1297 732
1298 /** 733 /**
1299 * Plus equals operator for String. 734 * Plus equals operator for String.
1300 *@param rSrc (const MyType &) The String to append to your String. 735 *@param rSrc (const String &) The String to append to your String.
1301 */ 736 */
1302 MyType &operator+=( const MyType &rSrc ) 737 String &operator+=( const String &rSrc );
1303 {
1304 append( rSrc );
1305
1306 return (*this);
1307 }
1308 738
1309 MyType &operator+=( const MyType::const_iterator &i ) 739 String &operator+=( const String::const_iterator &i );
1310 {
1311 append( i, i+1 );
1312
1313 return (*this);
1314 }
1315 740
1316 /** 741 /**
1317 * Plus equals operator for String. 742 * Plus equals operator for String.
1318 *@param cData (const chr) The character to append to your String. 743 *@param cData (const char) The character to append to your String.
1319 */ 744 */
1320 MyType &operator+=( const chr cData ) 745 String &operator+=( const char cData );
1321 {
1322 if( core->pLast && core->pLast->nLength < nMinSize )
1323 {
1324 _hardCopy();
1325 core->pLast->pData[core->pLast->nLength] = cData;
1326 ++core->pLast->nLength; ++core->nLength;
1327 // pLast->pData[pLast->nLength] = (chr)0;
1328 }
1329 else
1330 {
1331 append( &cData, 1 );
1332 }
1333 //append( pData );
1334
1335 return (*this);
1336 }
1337 746
1338 /** 747 /**
1339 * Assignment operator. 748 * Assignment operator.
1340 *@param pData (const chr *) The character array to append to your 749 *@param pData (const char *) The character array to append to your
1341 * String. 750 * String.
1342 */ 751 */
1343 MyType &operator=( const chr *pData ) 752 String &operator=( const char *pData );
1344 {
1345 set( pData );
1346 753
1347 return (*this); 754 String operator+( const String &rRight ) const;
1348 }
1349 755
1350 MyType operator+( const MyType &rRight ) const 756 String operator+( const char *pRight ) const;
1351 {
1352 MyType ret( *this );
1353 ret.append( rRight );
1354 return ret;
1355 }
1356 757
1357 MyType operator+( const chr *pRight ) const 758 String operator+( char *pRight ) const;
1358 {
1359 MyType ret( *this );
1360 ret.append( pRight );
1361 return ret;
1362 }
1363
1364 MyType operator+( chr *pRight ) const
1365 {
1366 MyType ret( *this );
1367 ret.append( pRight );
1368 return ret;
1369 }
1370 759
1371 /** 760 /**
1372 * Reset your String to this character array. 761 * Reset your String to this character array.
1373 *@param pData (const chr *) The character array to set your String to. 762 *@param pData (const char *) The character array to set your String to.
1374 */ 763 */
1375 void set( const chr *pData ) 764 void set( const char *pData );
1376 {
1377 clear();
1378 append( pData );
1379 }
1380 765
1381 /** 766 /**
1382 * Reset your String to this character array. 767 * Reset your String to this character array.
1383 *@param pData (const chr *) The character array to set your String to. 768 *@param pData (const char *) The character array to set your String to.
1384 *@param nSize (long) The length of the inputted character array. 769 *@param nSize (long) The length of the inputted character array.
1385 */ 770 */
1386 void set( const chr *pData, long nSize ) 771 void set( const char *pData, long nSize );
1387 {
1388 clear();
1389 append( pData, nSize );
1390 }
1391 772
1392 void set( const chr *pData, long nStart, long nSize ) 773 void set( const char *pData, long nStart, long nSize );
1393 {
1394 clear();
1395 append( pData, nStart, nSize );
1396 }
1397 774
1398 void set( const MyType &rData ) 775 void set( const String &rData );
1399 {
1400 clear();
1401 append( rData );
1402 }
1403 776
1404 void set( const MyType &rData, long nSize ) 777 void set( const String &rData, long nSize );
1405 {
1406 clear();
1407 append( rData, nSize );
1408 }
1409 778
1410 void set( const MyType &rData, long nStart, long nSize ) 779 void set( const String &rData, long nStart, long nSize );
1411 {
1412 clear();
1413 append( rData, nStart, nSize );
1414 }
1415 780
1416 void set( const_iterator s ) 781 void set( const_iterator s );
1417 {
1418 clear();
1419 append( s );
1420 }
1421 782
1422 void set( const_iterator s, const_iterator e ) 783 void set( const_iterator s, const_iterator e );
1423 {
1424 clear();
1425 append( s, e );
1426 }
1427 784
1428 /** 785 /**
1429 * Resize the string, possibly to make room for a copy. At the moment 786 * Resize the string, possibly to make room for a copy. At the moment
@@ -1433,453 +790,109 @@ namespace Bu
1433 *@param iSize the new size in bytes. The string is guranteed to have 790 *@param iSize the new size in bytes. The string is guranteed to have
1434 * at least this much contiguous space available when done. 791 * at least this much contiguous space available when done.
1435 */ 792 */
1436 void setSize( long iSize ) 793 void setSize( long iSize );
1437 {
1438 _hardCopy();
1439 core->clear();
1440 core->appendChunk( core->newChunk( iSize ) );
1441 }
1442
1443 void expand()
1444 {
1445#ifndef WIN32
1446 flatten();
1447 _hardCopy();
1448
1449 wordexp_t result;
1450
1451 /* Expand the string for the program to run. */
1452 switch (wordexp ((char *)core->pFirst->pData, &result, 0))
1453 {
1454 case 0: /* Successful. */
1455 {
1456 set( (chr *)result.we_wordv[0] );
1457 wordfree( &result );
1458 return;
1459 }
1460 break;
1461 case WRDE_NOSPACE:
1462 /* If the error was `WRDE_NOSPACE',
1463 then perhaps part of the result was allocated. */
1464 wordfree (&result);
1465 default: /* Some other error. */
1466 return;
1467 }
1468#endif
1469 }
1470
1471 /**
1472 * Assignment operator.
1473 *@param rSrc (const MyType &) The String to set your String to.
1474 */
1475 /* MyType &operator=( const MyType &rSrc )
1476 {
1477 set( rSrc );
1478 794
1479 return (*this);
1480 } */
1481
1482 /** 795 /**
1483 * Equals comparison operator. 796 * Equals comparison operator.
1484 *@param pData (const chr *) The character array to compare your String 797 *@param pData (const char *) The character array to compare your String
1485 * to. 798 * to.
1486 */ 799 */
1487 bool operator==( const chr *pData ) const 800 bool operator==( const char *pData ) const;
1488 {
1489 if( core->pFirst == NULL || core->nLength == 0 ) {
1490 if( pData == NULL )
1491 return true;
1492 if( pData[0] == (chr)0 )
1493 return true;
1494 return false;
1495 }
1496
1497 flatten();
1498 core->pFirst->pData[core->nLength] = (chr)0;
1499 const chr *a = pData;
1500 chr *b = core->pFirst->pData;
1501 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
1502 {
1503 if( *a != *b )
1504 return false;
1505 if( *a == (chr)0 && j < core->nLength )
1506 return false;
1507 }
1508
1509 return true;
1510 }
1511 801
1512 /** 802 /**
1513 * Equals comparison operator. 803 * Equals comparison operator.
1514 *@param pData (const MyType &) The String to compare your String to. 804 *@param pData (const String &) The String to compare your String to.
1515 */ 805 */
1516 bool operator==( const MyType &pData ) const 806 bool operator==( const String &pData ) const;
1517 {
1518 if( core == pData.core )
1519 return true;
1520 if( core->pFirst == pData.core->pFirst )
1521 return true;
1522 if( (core->nLength == 0 && pData.core->nLength == 0) )
1523 return true;
1524 if( core->nLength != pData.core->nLength )
1525 return false;
1526 if( pData.core->pFirst == NULL || core->pFirst == NULL )
1527 return false;
1528
1529 flatten();
1530 pData.flatten();
1531 const chr *a = pData.core->pFirst->pData;
1532 chr *b = core->pFirst->pData;
1533 for( long j = 0; j < core->nLength; j++, a++, b++ )
1534 {
1535 if( *a != *b )
1536 return false;
1537 }
1538
1539 return true;
1540 }
1541 807
1542 /** 808 /**
1543 * Not equals comparison operator. 809 * Not equals comparison operator.
1544 *@param pData (const chr *) The character array to compare your String 810 *@param pData (const char *) The character array to compare your String
1545 * to. 811 * to.
1546 */ 812 */
1547 bool operator!=(const chr *pData ) const 813 bool operator!=(const char *pData ) const;
1548 {
1549 return !(*this == pData);
1550 }
1551 814
1552 /** 815 /**
1553 * Not equals comparison operator. 816 * Not equals comparison operator.
1554 *@param pData (const MyType &) The String to compare your String to. 817 *@param pData (const String &) The String to compare your String to.
1555 */ 818 */
1556 bool operator!=(const MyType &pData ) const 819 bool operator!=(const String &pData ) const;
1557 {
1558 return !(*this == pData);
1559 }
1560
1561 bool operator<(const MyType &pData ) const
1562 {
1563 flatten();
1564 pData.flatten();
1565 820
1566 const chr *a = core->pFirst->pData; 821 bool operator<(const String &pData ) const;
1567 chr *b = pData.core->pFirst->pData;
1568 for( long j = 0; j < core->nLength; j++, a++, b++ )
1569 {
1570 if( *a != *b )
1571 return *a < *b;
1572 }
1573
1574 return false;
1575 }
1576 822
1577 bool operator<=(const MyType &pData ) const 823 bool operator<=(const String &pData ) const;
1578 {
1579 flatten();
1580 pData.flatten();
1581
1582 const chr *a = core->pFirst->pData;
1583 chr *b = pData.core->pFirst->pData;
1584 for( long j = 0; j < core->nLength; j++, a++, b++ )
1585 {
1586 if( *a != *b )
1587 return *a < *b;
1588 }
1589
1590 return true;
1591 }
1592
1593 bool operator>(const MyType &pData ) const
1594 {
1595 flatten();
1596 pData.flatten();
1597 824
1598 const chr *a = core->pFirst->pData; 825 bool operator>(const String &pData ) const;
1599 chr *b = pData.core->pFirst->pData;
1600 for( long j = 0; j < core->nLength; j++, a++, b++ )
1601 {
1602 if( *a != *b )
1603 return *a > *b;
1604 }
1605 826
1606 return false; 827 bool operator>=(const String &pData ) const;
1607 }
1608
1609 bool operator>=(const MyType &pData ) const
1610 {
1611 flatten();
1612 pData.flatten();
1613
1614 const chr *a = core->pFirst->pData;
1615 chr *b = pData.core->pFirst->pData;
1616 for( long j = 0; j < core->nLength; j++, a++, b++ )
1617 {
1618 if( *a != *b )
1619 return *a > *b;
1620 }
1621
1622 return true;
1623 }
1624 828
1625 /** 829 /**
1626 * Indexing operator 830 * Indexing operator
1627 *@param nIndex (long) The index of the character you want. 831 *@param nIndex (long) The index of the character you want.
1628 *@returns (chr &) The character at position (nIndex). 832 *@returns (char &) The character at position (nIndex).
1629 */ 833 */
1630 chr &operator[]( long nIndex ) 834 char &operator[]( long nIndex );
1631 {
1632 if( nIndex < 0 || nIndex >= core->nLength )
1633 throw Bu::ExceptionBase("Index out of range.");
1634 flatten();
1635 _hardCopy();
1636
1637 return core->pFirst->pData[nIndex];
1638 }
1639 835
1640 /** 836 /**
1641 * Const indexing operator 837 * Const indexing operator
1642 *@param nIndex (long) The index of the character you want. 838 *@param nIndex (long) The index of the character you want.
1643 *@returns (const chr &) The character at position (nIndex). 839 *@returns (const char &) The character at position (nIndex).
1644 */ 840 */
1645 const chr &operator[]( long nIndex ) const 841 const char &operator[]( long nIndex ) const;
1646 {
1647 if( nIndex < 0 || nIndex >= core->nLength )
1648 throw Bu::ExceptionBase("Index out of range.");
1649 flatten();
1650
1651 return core->pFirst->pData[nIndex];
1652 }
1653/*
1654 operator const chr *() const
1655 {
1656 if( !pFirst ) return NULL;
1657 flatten();
1658 return pFirst->pData;
1659 }
1660 */
1661 /*
1662 operator bool() const
1663 {
1664 return (core->pFirst != NULL);
1665 }
1666 */
1667
1668 bool isSet() const
1669 {
1670 return (core->pFirst != NULL);
1671 }
1672
1673 bool compareSub( const chr *pData, long nIndex, long nLen ) const
1674 {
1675 if( core->pFirst == NULL || core->nLength == 0 ) {
1676 if( pData == NULL )
1677 return true;
1678 if( nLen == 0 )
1679 return true;
1680 if( pData[0] == (chr)0 )
1681 return true;
1682 return false;
1683 }
1684 if( nIndex+nLen > core->nLength )
1685 return false;
1686
1687 flatten();
1688 core->pFirst->pData[core->nLength] = (chr)0;
1689 const chr *a = pData;
1690 chr *b = core->pFirst->pData+nIndex;
1691 for( long j = 0; j < nLen; j++, a++, b++ )
1692 {
1693 if( *a != *b )
1694 return false;
1695 if( *a == (chr)0 && j < core->nLength )
1696 return false;
1697 }
1698 842
1699 return true; 843 bool isSet() const;
1700 }
1701 844
1702 bool compareSub( const MyType &rData, long nIndex, long nLen ) const 845 bool compareSub( const char *pData, long nIndex, long nLen ) const;
1703 {
1704 if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 )
1705 return false;
1706 if( nLen < 0 )
1707 nLen = rData.core->nLength;
1708 if( nIndex+nLen > core->nLength )
1709 return false;
1710
1711 flatten();
1712 rData.flatten();
1713 const chr *a = rData.core->pFirst->pData;
1714 chr *b = core->pFirst->pData + nIndex;
1715 for( long j = 0; j < nLen; j++, a++, b++ )
1716 {
1717 if( *a != *b )
1718 return false;
1719 }
1720 846
1721 return true; 847 bool compareSub( const String &rData, long nIndex, long nLen ) const;
1722 }
1723 848
1724 /** 849 /**
1725 * Is the character at index (nIndex) white space? 850 * Is the character at index (nIndex) white space?
1726 *@param nIndex (long) The index of the character you want to check. 851 *@param nIndex (long) The index of the character you want to check.
1727 *@returns (bool) Is it white space? 852 *@returns (bool) Is it white space?
1728 */ 853 */
1729 bool isWS( long nIndex ) const 854 bool isWS( long nIndex ) const;
1730 {
1731 flatten();
1732
1733 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
1734 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
1735 }
1736 855
1737 /** 856 /**
1738 * Is the character at index (nIndex) a letter? 857 * Is the character at index (nIndex) a letter?
1739 *@param nIndex (long) The index of the character you want to check. 858 *@param nIndex (long) The index of the character you want to check.
1740 *@returns (bool) Is it a letter? 859 *@returns (bool) Is it a letter?
1741 */ 860 */
1742 bool isAlpha( long nIndex ) const 861 bool isAlpha( long nIndex ) const;
1743 {
1744 flatten();
1745
1746 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
1747 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
1748 }
1749 862
1750 /** 863 /**
1751 * Convert your alpha characters to lower case. 864 * Convert your alpha characters to lower case.
1752 */ 865 */
1753 void toLower() 866 String toLower() const;
1754 {
1755 flatten();
1756 _hardCopy();
1757
1758 for( long j = 0; j < core->nLength; j++ )
1759 {
1760 if( core->pFirst->pData[j] >= 'A' && core->pFirst->pData[j] <= 'Z' )
1761 core->pFirst->pData[j] -= 'A'-'a';
1762 }
1763 }
1764 867
1765 /** 868 /**
1766 * Convert your alpha characters to upper case. 869 * Convert your alpha characters to upper case.
1767 */ 870 */
1768 void toUpper() 871 String toUpper() const;
1769 {
1770 flatten();
1771 _hardCopy();
1772
1773 for( long j = 0; j < core->nLength; j++ )
1774 {
1775 if( core->pFirst->pData[j] >= 'a' && core->pFirst->pData[j] <= 'z' )
1776 core->pFirst->pData[j] += 'A'-'a';
1777 }
1778 }
1779
1780// template<typename out>
1781// void to( out &dst );
1782/* {
1783 flatten();
1784 872
1785 dst = strtol( pFirst->pData, NULL, 0 ); 873 const_iterator find( const char cChar,
1786 } */ 874 const_iterator iStart=const_iterator() ) const;
1787 875
1788 const_iterator find( const chr cChar, 876 const_iterator find( const char *sText, int nLen,
1789 const_iterator iStart=typename MyType::const_iterator() ) const 877 const_iterator iStart=const_iterator() ) const;
1790 {
1791 if( !iStart ) iStart = begin();
1792 for( ; iStart; iStart++ )
1793 {
1794 if( cChar == *iStart )
1795 return iStart;
1796 }
1797 return end();
1798 }
1799 878
1800 const_iterator find( const chr *sText, int nLen, 879 const_iterator find( const String &rStr,
1801 const_iterator iStart=typename MyType::const_iterator() ) const 880 const_iterator iStart=const_iterator() ) const;
1802 {
1803 if( !iStart ) iStart = begin();
1804 for( ; iStart; iStart++ )
1805 {
1806 if( iStart.compare( sText, nLen ) )
1807 return iStart;
1808 }
1809 return end();
1810 }
1811
1812 const_iterator find( const MyType &rStr,
1813 const_iterator iStart=typename MyType::const_iterator() ) const
1814 {
1815 if( !iStart ) iStart = begin();
1816 for( ; iStart; iStart++ )
1817 {
1818 if( iStart.compare( rStr ) )
1819 return iStart;
1820 }
1821 return end();
1822 }
1823 881
1824 const_iterator find( const MyType &rStr, int nLen, 882 const_iterator find( const String &rStr, int nLen,
1825 const_iterator iStart=typename MyType::const_iterator() ) const 883 const_iterator iStart=const_iterator() ) const;
1826 {
1827 if( !iStart ) iStart = begin();
1828 for( ; iStart; iStart++ )
1829 {
1830 if( iStart.compare( rStr, nLen ) )
1831 return iStart;
1832 }
1833 return end();
1834 }
1835 884
1836 iterator find( const chr cChar, 885 iterator find( const char cChar,
1837 const_iterator iStart=typename MyType::const_iterator() ) 886 const_iterator iStart=const_iterator() );
1838 {
1839 if( !iStart ) iStart = begin();
1840 for( ; iStart; iStart++ )
1841 {
1842 if( cChar == *iStart )
1843 return iterator( iStart.pChunk, iStart.iPos );
1844 }
1845 return end();
1846 }
1847 887
1848 iterator find( const chr *sText, int nLen, 888 iterator find( const char *sText, int nLen,
1849 const_iterator iStart=typename MyType::const_iterator() ) 889 const_iterator iStart=const_iterator() );
1850 {
1851 if( !iStart ) iStart = begin();
1852 for( ; iStart; iStart++ )
1853 {
1854 if( iStart.compare( sText, nLen ) )
1855 return iterator( iStart.pChunk, iStart.iPos );
1856 }
1857 return end();
1858 }
1859 890
1860 iterator find( const MyType &rStr, 891 iterator find( const String &rStr,
1861 const_iterator iStart=typename MyType::const_iterator() ) 892 const_iterator iStart=const_iterator() );
1862 {
1863 if( !iStart ) iStart = begin();
1864 for( ; iStart; iStart++ )
1865 {
1866 if( iStart.compare( rStr ) )
1867 return iterator( iStart.pChunk, iStart.iPos );
1868 }
1869 return end();
1870 }
1871 893
1872 iterator find( const MyType &rStr, int nLen, 894 iterator find( const String &rStr, int nLen,
1873 const_iterator iStart=typename MyType::const_iterator() ) 895 const_iterator iStart=const_iterator() );
1874 {
1875 if( !iStart ) iStart = begin();
1876 for( ; iStart; iStart++ )
1877 {
1878 if( iStart.compare( rStr, nLen ) )
1879 return iterator( iStart.pChunk, iStart.iPos );
1880 }
1881 return end();
1882 }
1883 896
1884 /** 897 /**
1885 * Find the index of the first occurrance of cChar 898 * Find the index of the first occurrance of cChar
@@ -1887,16 +900,7 @@ namespace Bu
1887 *@param iStart The position in the string to start searching from. 900 *@param iStart The position in the string to start searching from.
1888 *@returns (long) The index of the first occurrance. -1 for not found. 901 *@returns (long) The index of the first occurrance. -1 for not found.
1889 */ 902 */
1890 long findIdx( const chr cChar, long iStart=0 ) const 903 long findIdx( const char cChar, long iStart=0 ) const;
1891 {
1892 flatten();
1893 for( long j = iStart; j < core->pFirst->nLength; j++ )
1894 {
1895 if( core->pFirst->pData[j] == cChar )
1896 return j;
1897 }
1898 return -1;
1899 }
1900 904
1901 /** 905 /**
1902 * Find the index of the first occurrance of sText 906 * Find the index of the first occurrance of sText
@@ -1904,201 +908,109 @@ namespace Bu
1904 *@param iStart The position in the string to start searching from. 908 *@param iStart The position in the string to start searching from.
1905 *@returns The index of the first occurrance. -1 for not found. 909 *@returns The index of the first occurrance. -1 for not found.
1906 */ 910 */
1907 long findIdx( const chr *sText, long iStart=0 ) const 911 long findIdx( const char *sText, long iStart=0 ) const;
1908 {
1909 long nTLen = strlen( sText );
1910 flatten();
1911 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1912 {
1913 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1914 return j;
1915 }
1916 return -1;
1917 }
1918 912
1919 /** 913 /**
1920 * Do a reverse search for (sText) 914 * Do a reverse search for (sText)
1921 *@param sText (const chr *) The string to search for. 915 *@param sText (const char *) The string to search for.
1922 *@returns (long) The index of the last occurrance. -1 for not found. 916 *@returns (long) The index of the last occurrance. -1 for not found.
1923 */ 917 */
1924 long rfindIdx( const chr *sText ) const 918 long rfindIdx( const char *sText ) const;
1925 {
1926 long nTLen = strlen( sText );
1927 flatten();
1928 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1929 {
1930 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1931 return j;
1932 }
1933 return -1;
1934 }
1935 919
1936 /** 920 /**
1937 * Remove nAmnt bytes from the front of the string. This function 921 * Remove nAmnt bytes from the front of the string. This function
1938 * operates in O(n) time and should be used sparingly. 922 * operates in O(n) time and should be used sparingly.
1939 */ 923 */
1940 void trimFront( long nAmnt ) 924 void trimFront( long nAmnt );
1941 {
1942 long nNewLen = core->nLength - nAmnt;
1943 flatten();
1944 Chunk *pNew = core->newChunk( nNewLen );
1945 memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1946 _hardCopy();
1947 core->clear();
1948 core->appendChunk( pNew );
1949 }
1950 925
1951 void trimBack( chr c ) 926 void trimBack( char c );
1952 {
1953 if( core->pFirst == NULL || core->nLength == 0 )
1954 return;
1955 flatten();
1956 for( ; core->pFirst->nLength > 0 && core->pFirst->pData[core->pFirst->nLength-1] == c; core->pFirst->nLength--, core->nLength-- ) { }
1957 }
1958 927
1959 MyType &format( const char *sFrmt, ...) 928 iterator begin();
1960 {
1961 _hardCopy();
1962 clear();
1963 929
1964 va_list ap; 930 const_iterator begin() const;
1965 va_start( ap, sFrmt );
1966 931
1967 long iLen = vsnprintf( NULL, 0, sFrmt, ap ); 932 iterator end();
1968
1969 Chunk *pNew = core->newChunk( iLen );
1970 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
1971 core->appendChunk( pNew );
1972 933
1973 va_end( ap ); 934 const_iterator end() const;
1974 935
1975 return *this; 936 bool isEmpty() const;
1976 }
1977
1978 MyType &formatAppend( const char *sFrmt, ...)
1979 {
1980 _hardCopy();
1981 va_list ap;
1982 va_start( ap, sFrmt );
1983
1984 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1985 937
1986 Chunk *pNew = core->newChunk( iLen ); 938 private:
1987 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); 939 void flatten() const;
1988 core->appendChunk( pNew ); 940 bool isFlat() const;
1989
1990 va_end( ap );
1991
1992 return *this;
1993 }
1994 941
1995 MyType &formatPrepend( const char *sFrmt, ...) 942 class FormatProxy
1996 { 943 {
1997 _hardCopy(); 944 public:
1998 va_list ap; 945 FormatProxy( const String &rFmt );
1999 va_start( ap, sFrmt ); 946 virtual ~FormatProxy();
2000 947
2001 long iLen = vsnprintf( NULL, 0, sFrmt, ap ); 948 template<typename T>
2002 949 FormatProxy &arg( const T &x )
2003 Chunk *pNew = core->newChunk( iLen ); 950 {
2004 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); 951 lArgs.append( Arg( x ) );
2005 core->prependChunk( pNew );
2006 952
2007 va_end( ap ); 953 return *this;
954 }
2008 955
2009 return *this; 956 template<typename T>
2010 } 957 FormatProxy &arg( const T &x, const Bu::Fmt &f )
958 {
959 lArgs.append( Arg( x, f ) );
2011 960
2012 iterator begin() 961 return *this;
2013 { 962 }
2014 if( core->nLength == 0 )
2015 return iterator( NULL, 0 );
2016 return iterator( core->pFirst, 0 );
2017 }
2018 963
2019 const_iterator begin() const 964 operator String() const;
2020 {
2021 if( core->nLength == 0 )
2022 return const_iterator( NULL, 0 );
2023 return iterator( core->pFirst, 0 );
2024 }
2025 965
2026 iterator end() 966 private:
2027 { 967 const String &rFmt;
2028 return iterator( NULL, 0 ); 968 class Arg
2029 } 969 {
970 public:
971 template<typename T>
972 Arg( const T &v ) :
973 value( v )
974 {
975 }
2030 976
2031 const_iterator end() const 977 template<typename T>
2032 { 978 Arg( const T &v, const Bu::Fmt &f ) :
2033 return const_iterator( NULL, 0 ); 979 value( v ),
2034 } 980 format( f )
981 {
982 }
2035 983
2036 bool isEmpty() const 984 Bu::Variant value;
2037 { 985 Bu::Fmt format;
2038 if( core->nLength == 0 ) 986 };
2039 return true; 987 typedef Bu::List<Arg> ArgList;
2040 return false; 988 ArgList lArgs;
2041 } 989 };
2042 990
2043 private: 991 public:
2044 void flatten() const 992 template<typename ArgType>
993 FormatProxy arg( const ArgType &x )
2045 { 994 {
2046 if( isFlat() ) 995 return FormatProxy( *this ).arg( x );
2047 return;
2048
2049 if( core->pFirst == NULL || core->nLength == 0 )
2050 return;
2051
2052 Chunk *pNew = core->newChunk( core->nLength );
2053 chr *pos = pNew->pData;
2054 Chunk *i = core->pFirst;
2055 for(;;)
2056 {
2057 memcpy( pos, i->pData, i->nLength );
2058 pos += i->nLength;
2059 i = i->pNext;
2060 if( i == NULL )
2061 break;
2062 }
2063 core->clear();
2064
2065 core->pLast = core->pFirst = pNew;
2066 core->nLength = pNew->nLength;
2067 } 996 }
2068 997
2069 bool isFlat() const 998 template<typename ArgType>
999 FormatProxy arg( const ArgType &x, const Bu::Fmt &f )
2070 { 1000 {
2071 return (core->pFirst == core->pLast); 1001 return FormatProxy( *this ).arg( x, f );
2072 } 1002 }
2073 }; 1003 };
2074 1004
2075 template<class T> BasicString<T> operator+( const T *pLeft, const BasicString<T> &rRight ) 1005 template<class T> String operator+( const T *pLeft, const String &rRight )
2076 { 1006 {
2077 Bu::BasicString<T> ret( pLeft ); 1007 Bu::String ret( pLeft );
2078 ret.append( rRight ); 1008 ret.append( rRight );
2079 return ret; 1009 return ret;
2080 } 1010 }
2081 1011
2082 template<class chr, int b, class c, class d> 1012 ArchiveBase &operator<<( ArchiveBase &ar, const String &s );
2083 ArchiveBase &operator<<( ArchiveBase &ar, const BasicString<chr, b, c, d> &s ) 1013 ArchiveBase &operator>>( ArchiveBase &ar, String &s );
2084 {
2085 long n = s.getSize();
2086 ar << n;
2087 ar.write( s.getConstStr(), n );
2088 return ar;
2089 }
2090
2091 template<class chr, int b, class c, class d>
2092 ArchiveBase &operator>>( ArchiveBase &ar, BasicString<chr, b, c, d> &s )
2093 {
2094 long n;
2095 ar >> n;
2096 s.setSize( n );
2097 ar.read( s.getStr(), n );
2098 return ar;
2099 }
2100
2101 typedef BasicString<char> String;
2102 1014
2103 template<typename T> 1015 template<typename T>
2104 uint32_t __calcHashCode( const T &k ); 1016 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 @@
1#include <bu/string.h>
2
3#include <sys/time.h>
4#include <stdio.h>
5
6void timeit( void (*func)(), const char *sName, int iIter )
7{
8 struct timeval ts, te;
9
10 gettimeofday( &ts, NULL );
11 for( int j = 0; j < iIter; j++ )
12 {
13 func();
14 }
15 gettimeofday( &te, NULL );
16
17 double dTotal = (double)(te.tv_sec-ts.tv_sec) + (double)(te.tv_usec-ts.tv_usec)/1000000.0;
18 printf("%10s: %f spi (%f total)\n", sName, dTotal/iIter, dTotal );
19}
20
21void append1()
22{
23 Bu::String sTmp;
24 for( int c = 0; c < 5000; c++ )
25 {
26 sTmp += (char)(c%256);
27 }
28}
29
30void append2()
31{
32 Bu::String sTmp;
33 for( int c = 0; c < 5000; c++ )
34 {
35 sTmp.append( (char)(c%256) );
36 }
37}
38
39void append3()
40{
41 Bu::String sTmp;
42 for( int c = 0; c < 5000; c++ )
43 {
44 sTmp += "Test";
45 }
46}
47
48void append4()
49{
50 Bu::String sTmp;
51 for( int c = 0; c < 5000; c++ )
52 {
53 sTmp.append("Test");
54 }
55}
56
57void append5()
58{
59 Bu::String sTmp, sAdd("Test");
60 for( int c = 0; c < 5000; c++ )
61 {
62 sTmp += sAdd;
63 }
64}
65
66void append6()
67{
68 Bu::String sTmp, sAdd("Test");
69 for( int c = 0; c < 5000; c++ )
70 {
71 sTmp.append( sAdd );
72 }
73}
74
75void prepend1()
76{
77 Bu::String sTmp;
78 for( int c = 0; c < 5000; c++ )
79 {
80 sTmp.prepend('c');
81 }
82}
83
84void copy1()
85{
86 Bu::String sSrc;
87 for( int c = 0; c < 1000; c++ )
88 {
89 sSrc += (char)(c%256);
90 Bu::String sTmp = sSrc;
91 sTmp.append( '-' );
92 }
93}
94
95void copy2()
96{
97 Bu::String sSrc;
98 for( int c = 0; c < 1000; c++ )
99 {
100 sSrc += (char)(c%256);
101 Bu::String sTmp = sSrc;
102 }
103}
104
105void replace1()
106{
107 Bu::String s("Hey, this is a replacement test, what do you thing of it?");
108 s.replace("e", "X").replace("a", "X").replace("what","XXX");
109}
110
111int main()
112{
113 timeit( append1, "Append1", 5000 );
114 timeit( append2, "Append2", 5000 );
115 timeit( append3, "Append3", 2000 );
116 timeit( append4, "Append4", 2000 );
117 timeit( append4, "Prepend1", 2000 );
118 timeit( copy1, "Copy1", 2000 );
119 timeit( copy2, "Copy2", 2000 );
120 timeit( replace1, "Replace1", 10000 );
121}
122
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 @@
1#include <bu/string.h>
2#include <bu/formatter.h>
3#include <bu/sio.h>
4#include <bu/variant.h>
5#include <bu/membuf.h>
6
7#include <stdlib.h>
8
9using namespace Bu;
10
11class Fmter
12{
13public:
14 Fmter( const Bu::String &sSrc ) :
15 sSrc( sSrc )
16 {
17 }
18
19 template<typename T>
20 Fmter &arg( const T &x )
21 {
22 lParm.append( Pair( x ) );
23
24 return *this;
25 }
26
27 template<typename T>
28 Fmter &arg( const T &x, Bu::Formatter::Fmt f )
29 {
30 lParm.append( Pair( x, f ) );
31
32 return *this;
33 }
34
35 operator Bu::String() const
36 {
37 int iCount = lParm.getSize();
38 ParmList::const_iterator *aParm =
39 new ParmList::const_iterator[iCount];
40 {
41 int j = 0;
42 for( ParmList::const_iterator i = lParm.begin(); i; i++, j++ )
43 {
44 aParm[j] = i;
45 }
46 }
47 Bu::MemBuf mbOut;
48 Bu::Formatter f( mbOut );
49 for( Bu::String::const_iterator s = sSrc.begin(); s; s++ )
50 {
51 if( *s == '%' )
52 {
53 s++;
54 if( *s == '%' )
55 f << *s;
56 else
57 {
58 Bu::String sNum;
59 while( s && *s >= '0' && *s <= '9' )
60 {
61 sNum += *s;
62 s++;
63 }
64 int iIndex = strtol( sNum.getStr(), 0, 10 )-1;
65 if( iIndex < 0 || iIndex >= iCount )
66 {
67 delete[] aParm;
68 throw Bu::ExceptionBase(
69 "Argument index %d is outside of "
70 "valid range (1-%d).", iIndex+1, iCount
71 );
72 }
73
74 f << (*aParm[iIndex]).format << (*aParm[iIndex]).value;
75 if( s )
76 f << *s;
77 }
78 }
79 else
80 {
81 f << *s;
82 }
83 }
84
85 delete[] aParm;
86 return mbOut.getString();
87 }
88
89private:
90 const Bu::String &sSrc;
91 class Pair
92 {
93 public:
94 template<typename T>
95 Pair( const T &v ) :
96 value( v )
97 {
98 }
99
100 template<typename T>
101 Pair( const T &v, Bu::Formatter::Fmt f ) :
102 value( v ),
103 format( f )
104 {
105 }
106
107 Bu::Variant value;
108 Bu::Formatter::Fmt format;
109 };
110 typedef Bu::List<Pair> ParmList;
111 ParmList lParm;
112};
113
114Bu::Formatter &operator<<( Bu::Formatter &f, const Fmter &r )
115{
116 return f << (Bu::String)r;
117}
118
119int main()
120{
121 sio << Fmter("A word is %1 and a number is %2 %1").
122 arg("Hello").arg(75, Fmt::hex() ).arg(" - ") << sio.nl;
123}
124
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()
83 83
84Bu::String Bu::UdpSocket::addrToStr( const addr &a ) 84Bu::String Bu::UdpSocket::addrToStr( const addr &a )
85{ 85{
86 Bu::String sOut; 86 return Bu::String("%1.%2.%3.%4").
87 sOut.format("%d.%d.%d.%d", 87 arg( (a&0xff) ).
88 (a&0xff), 88 arg( (a&0xff00)>>8 ).
89 (a&0xff00)>>8, 89 arg( (a&0xff0000)>>16 ).
90 (a&0xff0000)>>16, 90 arg( (a&0xff000000)>>24 );
91 (a&0xff000000)>>24
92 );
93
94 return sOut;
95} 91}
96 92
97void Bu::UdpSocket::close() 93void 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 @@
8#ifndef BU_UTF_STRING_H 8#ifndef BU_UTF_STRING_H
9#define BU_UTF_STRING_H 9#define BU_UTF_STRING_H
10 10
11#include "bu/string.h" 11#include <stdint.h>
12 12
13namespace Bu 13namespace Bu
14{ 14{
@@ -21,8 +21,8 @@ namespace Bu
21 typedef uint32_t point; 21 typedef uint32_t point;
22 22
23 private: 23 private:
24 typedef BasicString<uint16_t> RawString; 24// typedef BasicString<uint16_t> RawString;
25 RawString rsStore; 25// RawString rsStore;
26 }; 26 };
27}; 27};
28 28
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 @@
6 */ 6 */
7 7
8#include "bu/variant.h" 8#include "bu/variant.h"
9 9#include "bu/formatter.h"
10#include "bu/membuf.h" 10#include "bu/membuf.h"
11 11
12namespace Bu 12namespace 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 @@
8#ifndef BU_VARIANT_H 8#ifndef BU_VARIANT_H
9#define BU_VARIANT_H 9#define BU_VARIANT_H
10 10
11#include <bu/string.h> 11//#include <bu/string.h>
12#include <typeinfo> 12#include <typeinfo>
13#include <bu/formatter.h> 13// #include <bu/formatter.h>
14
15#ifndef NULL
16#define NULL (0L)
17#endif
18
19#include "bu/exceptionbase.h"
14 20
15namespace Bu 21namespace Bu
16{ 22{
23 class String;
17 class Formatter; 24 class Formatter;
18 class Variant; 25 class Variant;
19 /** @cond DEVEL */ 26 /** @cond DEVEL */