summaryrefslogtreecommitdiff
path: root/src/fstring.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2007-03-15 05:24:58 +0000
committerMike Buland <eichlan@xagasoft.com>2007-03-15 05:24:58 +0000
commitcf847cc534a2a7ad06750c446028b7c6d126fe21 (patch)
treef4de1b9bcc261fe5dc758f13ee0b6d19b7ba5e27 /src/fstring.h
parent46725741fc82866e41652dee7adeddf376fde618 (diff)
downloadlibbu++-cf847cc534a2a7ad06750c446028b7c6d126fe21.tar.gz
libbu++-cf847cc534a2a7ad06750c446028b7c6d126fe21.tar.bz2
libbu++-cf847cc534a2a7ad06750c446028b7c6d126fe21.tar.xz
libbu++-cf847cc534a2a7ad06750c446028b7c6d126fe21.zip
Looks like FString is ready for general consumption, not too shabby.
Diffstat (limited to 'src/fstring.h')
-rw-r--r--src/fstring.h241
1 files changed, 221 insertions, 20 deletions
diff --git a/src/fstring.h b/src/fstring.h
index 287641f..db54cdd 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -20,6 +20,7 @@ class FBasicString
20{ 20{
21private: 21private:
22 typedef struct FStringChunk<chr> Chunk; 22 typedef struct FStringChunk<chr> Chunk;
23 typedef struct FBasicString<chr, chralloc, chunkalloc> MyType;
23 24
24public: 25public:
25 FBasicString() : 26 FBasicString() :
@@ -48,8 +49,31 @@ public:
48 append( pData, nLength ); 49 append( pData, nLength );
49 } 50 }
50 51
52 FBasicString( MyType &rSrc ) :
53 nLength( 0 ),
54 pnRefs( NULL ),
55 pFirst( NULL ),
56 pLast( NULL )
57 {
58 joinShare( rSrc );
59 }
60
61 FBasicString( const FBasicString<chr, chralloc, chunkalloc> &rSrc ) :
62 nLength( 0 ),
63 pnRefs( NULL ),
64 pFirst( NULL ),
65 pLast( NULL )
66 {
67 // Here we have no choice but to copy, since the other guy is a const.
68 // In the case that the source were flat, we could get a reference, it
69 // would make some things faster, but not matter in many other cases.
70
71 copyFrom( rSrc );
72 }
73
51 virtual ~FBasicString() 74 virtual ~FBasicString()
52 { 75 {
76 clear();
53 } 77 }
54 78
55 void append( const chr *pData ) 79 void append( const chr *pData )
@@ -58,7 +82,7 @@ public:
58 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 82 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
59 83
60 Chunk *pNew = newChunk( nLen ); 84 Chunk *pNew = newChunk( nLen );
61 memcpy( pNew->pData, pData, nLen * sizeof(chr) ); 85 cpy( pNew->pData, pData, nLen );
62 86
63 appendChunk( pNew ); 87 appendChunk( pNew );
64 } 88 }
@@ -67,7 +91,7 @@ public:
67 { 91 {
68 Chunk *pNew = newChunk( nLen ); 92 Chunk *pNew = newChunk( nLen );
69 93
70 memcpy( pNew->pData, pData, nLen * sizeof(chr) ); 94 cpy( pNew->pData, pData, nLen );
71 95
72 appendChunk( pNew ); 96 appendChunk( pNew );
73 } 97 }
@@ -78,7 +102,7 @@ public:
78 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 102 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
79 103
80 Chunk *pNew = newChunk( nLen ); 104 Chunk *pNew = newChunk( nLen );
81 memcpy( pNew->pData, pData, nLen * sizeof(chr) ); 105 cpy( pNew->pData, pData, nLen );
82 106
83 prependChunk( pNew ); 107 prependChunk( pNew );
84 } 108 }
@@ -87,7 +111,7 @@ public:
87 { 111 {
88 Chunk *pNew = newChunk( nLen ); 112 Chunk *pNew = newChunk( nLen );
89 113
90 memcpy( pNew->pData, pData, nLen * sizeof(chr) ); 114 cpy( pNew->pData, pData, nLen );
91 115
92 prependChunk( pNew ); 116 prependChunk( pNew );
93 } 117 }
@@ -97,18 +121,25 @@ public:
97 if( pFirst == NULL ) 121 if( pFirst == NULL )
98 return; 122 return;
99 123
100 Chunk *i = pFirst; 124 if( isShared() )
101 for(;;)
102 { 125 {
103 Chunk *n = i->pNext; 126 decRefs();
104 aChr.deallocate( i->pData, i->nLength+1 ); 127 }
105 aChunk.deallocate( i, 1 ); 128 else
106 if( n == NULL ) 129 {
107 break; 130 Chunk *i = pFirst;
108 i = n; 131 for(;;)
132 {
133 Chunk *n = i->pNext;
134 aChr.deallocate( i->pData, i->nLength+1 );
135 aChunk.deallocate( i, 1 );
136 if( n == NULL )
137 break;
138 i = n;
139 }
140 pFirst = pLast = NULL;
141 nLength = 0;
109 } 142 }
110 pFirst = pLast = NULL;
111 nLength = 0;
112 } 143 }
113 144
114 chr *c_str() 145 chr *c_str()
@@ -120,14 +151,14 @@ public:
120 return pFirst->pData; 151 return pFirst->pData;
121 } 152 }
122 153
123 FBasicString<chr, chralloc, chunkalloc> &operator +=( const chr *pData ) 154 MyType &operator +=( const chr *pData )
124 { 155 {
125 append( pData ); 156 append( pData );
126 157
127 return (*this); 158 return (*this);
128 } 159 }
129 160
130 FBasicString<chr, chralloc, chunkalloc> &operator =( const chr *pData ) 161 MyType &operator =( const chr *pData )
131 { 162 {
132 clear(); 163 clear();
133 append( pData ); 164 append( pData );
@@ -135,6 +166,27 @@ public:
135 return (*this); 166 return (*this);
136 } 167 }
137 168
169 MyType &operator =( const MyType &rSrc )
170 {
171 if( rSrc.isFlat() )
172 {
173 joinShare( rSrc );
174 }
175 else
176 {
177 copyFrom( rSrc );
178 }
179
180 return (*this);
181 }
182
183 MyType &operator =( MyType &rSrc )
184 {
185 joinShare( rSrc );
186
187 return (*this);
188 }
189
138 bool operator ==( const chr *pData ) 190 bool operator ==( const chr *pData )
139 { 191 {
140 if( pFirst == NULL ) { 192 if( pFirst == NULL ) {
@@ -160,7 +212,12 @@ public:
160 return !(*this == pData); 212 return !(*this == pData);
161 } 213 }
162 214
215 chr &operator[]( long nIndex )
216 {
217 flatten();
163 218
219 return pFirst->pData[nIndex];
220 }
164 221
165private: 222private:
166 void flatten() 223 void flatten()
@@ -171,12 +228,37 @@ private:
171 if( pFirst == NULL ) 228 if( pFirst == NULL )
172 return; 229 return;
173 230
231 unShare();
232
174 Chunk *pNew = newChunk( nLength ); 233 Chunk *pNew = newChunk( nLength );
175 chr *pos = pNew->pData; 234 chr *pos = pNew->pData;
176 Chunk *i = pFirst; 235 Chunk *i = pFirst;
177 for(;;) 236 for(;;)
178 { 237 {
179 memcpy( pos, i->pData, i->nLength*sizeof(chr) ); 238 cpy( pos, i->pData, i->nLength );
239 pos += i->nLength;
240 i = i->pNext;
241 if( i == NULL )
242 break;
243 }
244 clear();
245
246 appendChunk( pNew );
247 }
248
249 void copyFrom( const FBasicString<chr, chralloc, chunkalloc> &rSrc )
250 {
251 if( rSrc.pFirst == NULL )
252 return;
253
254 decRefs();
255
256 Chunk *pNew = newChunk( rSrc.nLength );
257 chr *pos = pNew->pData;
258 Chunk *i = rSrc.pFirst;
259 for(;;)
260 {
261 cpy( pos, i->pData, i->nLength );
180 pos += i->nLength; 262 pos += i->nLength;
181 i = i->pNext; 263 i = i->pNext;
182 if( i == NULL ) 264 if( i == NULL )
@@ -187,12 +269,12 @@ private:
187 appendChunk( pNew ); 269 appendChunk( pNew );
188 } 270 }
189 271
190 bool isFlat() 272 bool isFlat() const
191 { 273 {
192 return (pFirst == pLast); 274 return (pFirst == pLast);
193 } 275 }
194 276
195 bool isShared() 277 bool isShared() const
196 { 278 {
197 return (pnRefs != NULL); 279 return (pnRefs != NULL);
198 } 280 }
@@ -210,11 +292,14 @@ private:
210 pNew->pNext = NULL; 292 pNew->pNext = NULL;
211 pNew->nLength = nLen; 293 pNew->nLength = nLen;
212 pNew->pData = aChr.allocate( nLen+1 ); 294 pNew->pData = aChr.allocate( nLen+1 );
295 pNew->pData[nLen] = (chr)0;
213 return pNew; 296 return pNew;
214 } 297 }
215 298
216 void appendChunk( Chunk *pNewChunk ) 299 void appendChunk( Chunk *pNewChunk )
217 { 300 {
301 unShare();
302
218 if( pFirst == NULL ) 303 if( pFirst == NULL )
219 pLast = pFirst = pNewChunk; 304 pLast = pFirst = pNewChunk;
220 else 305 else
@@ -228,6 +313,8 @@ private:
228 313
229 void prependChunk( Chunk *pNewChunk ) 314 void prependChunk( Chunk *pNewChunk )
230 { 315 {
316 unShare();
317
231 if( pFirst == NULL ) 318 if( pFirst == NULL )
232 pLast = pFirst = pNewChunk; 319 pLast = pFirst = pNewChunk;
233 else 320 else
@@ -239,9 +326,123 @@ private:
239 nLength += pNewChunk->nLength; 326 nLength += pNewChunk->nLength;
240 } 327 }
241 328
329 void joinShare( MyType &rSrc )
330 {
331 clear();
332
333 if( !rSrc.isFlat() )
334 rSrc.flatten();
335
336 rSrc.initCount();
337 pnRefs = rSrc.pnRefs;
338 (*pnRefs)++;
339 nLength = rSrc.nLength;
340 pFirst = rSrc.pFirst;
341 pLast = rSrc.pLast;
342 }
343
344 void joinShare( const MyType &rSrc )
345 {
346 clear();
347
348 if( !rSrc.isFlat() )
349 return;
350
351 if( !rSrc.isShared() )
352 {
353 rSrc.pnRefs = new uint32_t;
354 (*rSrc.pnRefs) = 1;
355 }
356 pnRefs = rSrc.pnRefs;
357 (*pnRefs)++;
358 nLength = rSrc.nLength;
359 pFirst = rSrc.pFirst;
360 pLast = rSrc.pLast;
361 }
362
363 /**
364 * This takes an object that was shared and makes a copy of the base data
365 * that was being shared so that this copy can be changed. This should be
366 * added before any call that will change this object;
367 */
368 void unShare()
369 {
370 if( isShared() == false )
371 return;
372
373 Chunk *pNew = newChunk( nLength );
374 chr *pos = pNew->pData;
375 Chunk *i = pFirst;
376 for(;;)
377 {
378 cpy( pos, i->pData, i->nLength );
379 pos += i->nLength;
380 i = i->pNext;
381 if( i == NULL )
382 break;
383 }
384 decRefs();
385 appendChunk( pNew );
386 decRefs();
387 }
388
389 /**
390 * This decrements our ref count and pulls us out of the share. If the ref
391 * count hits zero because of this, it destroys the share. This is not
392 * safe to call on it's own, it's much better to call unShare.
393 */
394 void decRefs()
395 {
396 if( isShared() )
397 {
398 (*pnRefs)--;
399 if( (*pnRefs) == 0 )
400 destroyShare();
401 else
402 {
403 pnRefs = NULL;
404 pFirst = NULL;
405 pLast = NULL;
406 nLength = 0;
407 }
408 }
409 }
410
411 /**
412 * While the unShare function removes an instance from a share, this
413 * function destroys the data that was in the share, removing the share
414 * itself. This should only be called when the refcount for the share has
415 * or is about to reach zero.
416 */
417 void destroyShare()
418 {
419 delete pnRefs;
420 pnRefs = NULL;
421 clear();
422 }
423
424 void cpy( chr *dest, const chr *src, long count )
425 {
426 for( int j = 0; j < count; j++ )
427 {
428 *dest = *src;
429 dest++;
430 src++;
431 }
432 }
433
434 void initCount() const
435 {
436 if( !isShared() )
437 {
438 pnRefs = new uint32_t;
439 (*pnRefs) = 1;
440 }
441 }
442
242private: 443private:
243 long nLength; 444 long nLength;
244 uint32_t *pnRefs; 445 mutable uint32_t *pnRefs;
245 Chunk *pFirst; 446 Chunk *pFirst;
246 Chunk *pLast; 447 Chunk *pLast;
247 448