aboutsummaryrefslogtreecommitdiff
path: root/src/old/fstring.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2007-04-03 03:49:53 +0000
committerMike Buland <eichlan@xagasoft.com>2007-04-03 03:49:53 +0000
commitf4c20290509d7ed3a8fd5304577e7a4cc0b9d974 (patch)
tree13cdf64f7cf134f397a7165b7a3fe0807e37026b /src/old/fstring.h
parent74d4c8cd27334fc7204d5a8773deb3d424565778 (diff)
downloadlibbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.tar.gz
libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.tar.bz2
libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.tar.xz
libbu++-f4c20290509d7ed3a8fd5304577e7a4cc0b9d974.zip
Ok, no code is left in src, it's all in src/old. We'll gradually move code back
into src as it's fixed and re-org'd. This includes tests, which, I may write a unit test system into libbu++ just to make my life easier.
Diffstat (limited to 'src/old/fstring.h')
-rw-r--r--src/old/fstring.h651
1 files changed, 651 insertions, 0 deletions
diff --git a/src/old/fstring.h b/src/old/fstring.h
new file mode 100644
index 0000000..c5397cc
--- /dev/null
+++ b/src/old/fstring.h
@@ -0,0 +1,651 @@
1#ifndef F_STRING_H
2#define F_STRING_H
3
4#include <stdint.h>
5#include <memory>
6#include "serializable.h"
7#include "serializer.h"
8
9template< typename chr >
10struct FStringChunk
11{
12 long nLength;
13 chr *pData;
14 FStringChunk *pNext;
15};
16
17/**
18 * Flexible String class. This class was designed with string passing and
19 * generation in mind. Like the standard string class you can specify what
20 * datatype to use for each character. Unlike the standard string class,
21 * collection of appended and prepended terms is done lazily, making long
22 * operations that involve many appends very inexpensive. In addition internal
23 * ref-counting means that if you pass strings around between functions there's
24 * almost no overhead in time or memory since a reference is created and no
25 * data is actually copied. This also means that you never need to put any
26 * FBasicString into a ref-counting container class.
27 */
28template< typename chr, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
29class FBasicString : public Serializable
30{
31#ifndef VALTEST
32#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
33#endif
34private:
35 typedef struct FStringChunk<chr> Chunk;
36 typedef struct FBasicString<chr, chralloc, chunkalloc> MyType;
37
38public:
39 FBasicString() :
40 nLength( 0 ),
41 pnRefs( NULL ),
42 pFirst( NULL ),
43 pLast( NULL )
44 {
45 }
46
47 FBasicString( const chr *pData ) :
48 nLength( 0 ),
49 pnRefs( NULL ),
50 pFirst( NULL ),
51 pLast( NULL )
52 {
53 append( pData );
54 }
55
56 FBasicString( const chr *pData, long nLength ) :
57 nLength( 0 ),
58 pnRefs( NULL ),
59 pFirst( NULL ),
60 pLast( NULL )
61 {
62 append( pData, nLength );
63 }
64
65 FBasicString( const MyType &rSrc ) :
66 nLength( 0 ),
67 pnRefs( NULL ),
68 pFirst( NULL ),
69 pLast( NULL )
70 {
71 // Here we have no choice but to copy, since the other guy is a const.
72 // In the case that the source were flat, we could get a reference, it
73 // would make some things faster, but not matter in many other cases.
74
75 joinShare( rSrc );
76 //copyFrom( rSrc );
77 }
78
79 FBasicString( const MyType &rSrc, long nLength ) :
80 nLength( 0 ),
81 pnRefs( NULL ),
82 pFirst( NULL ),
83 pLast( NULL )
84 {
85 append( rSrc.pFirst->pData, nLength );
86 }
87
88 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
89 nLength( 0 ),
90 pnRefs( NULL ),
91 pFirst( NULL ),
92 pLast( NULL )
93 {
94 append( rSrc.pFirst->pData+nStart, nLength );
95 }
96
97 FBasicString( long nSize ) :
98 nLength( nSize ),
99 pnRefs( NULL ),
100 pFirst( NULL ),
101 pLast( NULL )
102 {
103 pFirst = pLast = newChunk( nSize );
104 }
105
106 virtual ~FBasicString()
107 {
108 clear();
109 }
110
111 void append( const chr *pData )
112 {
113 long nLen;
114 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
115
116 Chunk *pNew = newChunk( nLen );
117 cpy( pNew->pData, pData, nLen );
118
119 appendChunk( pNew );
120 }
121
122 void append( const chr *pData, long nLen )
123 {
124 Chunk *pNew = newChunk( nLen );
125
126 cpy( pNew->pData, pData, nLen );
127
128 appendChunk( pNew );
129 }
130
131 void prepend( const chr *pData )
132 {
133 long nLen;
134 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
135
136 Chunk *pNew = newChunk( nLen );
137 cpy( pNew->pData, pData, nLen );
138
139 prependChunk( pNew );
140 }
141
142 void prepend( const chr *pData, long nLen )
143 {
144 Chunk *pNew = newChunk( nLen );
145
146 cpy( pNew->pData, pData, nLen );
147
148 prependChunk( pNew );
149 }
150
151 void clear()
152 {
153 realClear();
154 }
155
156 void resize( long nNewSize )
157 {
158 if( nLength == nNewSize )
159 return;
160
161 flatten();
162
163 Chunk *pNew = newChunk( nNewSize );
164 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
165 cpy( pNew->pData, pFirst->pData, nNewLen );
166 pNew->pData[nNewLen] = (chr)0;
167 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
168 aChunk.deallocate( pFirst, 1 );
169 pFirst = pLast = pNew;
170 nLength = nNewSize;
171 }
172
173 long getSize() const
174 {
175 return nLength;
176 }
177
178 chr *getStr()
179 {
180 if( pFirst == NULL )
181 return NULL;
182
183 flatten();
184 return pFirst->pData;
185 }
186
187 const chr *getStr() const
188 {
189 if( pFirst == NULL )
190 return NULL;
191
192 flatten();
193 return pFirst->pData;
194 }
195
196 chr *c_str()
197 {
198 if( pFirst == NULL )
199 return NULL;
200
201 flatten();
202 return pFirst->pData;
203 }
204
205 const chr *c_str() const
206 {
207 if( pFirst == NULL )
208 return NULL;
209
210 flatten();
211 return pFirst->pData;
212 }
213
214 MyType &operator +=( const chr *pData )
215 {
216 append( pData );
217
218 return (*this);
219 }
220
221 MyType &operator +=( const MyType &rSrc )
222 {
223 rSrc.flatten();
224 append( rSrc.pFirst->pData, rSrc.nLength );
225
226 return (*this);
227 }
228
229 MyType &operator +=( const chr pData )
230 {
231 chr tmp[2] = { pData, (chr)0 };
232 append( tmp );
233
234 return (*this);
235 }
236
237 MyType &operator =( const chr *pData )
238 {
239 clear();
240 append( pData );
241
242 return (*this);
243 }
244
245 MyType &operator =( const MyType &rSrc )
246 {
247 //if( rSrc.isFlat() )
248 //{
249 joinShare( rSrc );
250 //}
251 //else
252 //{
253 // copyFrom( rSrc );
254 //}
255 //
256
257 return (*this);
258 }
259
260 bool operator ==( const chr *pData ) const
261 {
262 if( pFirst == NULL ) {
263 if( pData == NULL )
264 return true;
265 return false;
266 }
267
268 flatten();
269 const chr *a = pData;
270 chr *b = pFirst->pData;
271 for( ; *a!=(chr)0; a++, b++ )
272 {
273 if( *a != *b )
274 return false;
275 }
276
277 return true;
278 }
279
280 bool operator ==( const MyType &pData ) const
281 {
282 if( pFirst == pData.pFirst )
283 return true;
284 if( pFirst == NULL )
285 return false;
286
287 flatten();
288 pData.flatten();
289 const chr *a = pData.pFirst->pData;
290 chr *b = pFirst->pData;
291 for( ; *a!=(chr)0; a++, b++ )
292 {
293 if( *a != *b )
294 return false;
295 }
296
297 return true;
298 }
299
300 bool operator !=(const chr *pData ) const
301 {
302 return !(*this == pData);
303 }
304
305 bool operator !=(const MyType &pData ) const
306 {
307 return !(*this == pData);
308 }
309
310 chr &operator[]( long nIndex )
311 {
312 flatten();
313
314 return pFirst->pData[nIndex];
315 }
316
317 const chr &operator[]( long nIndex ) const
318 {
319 flatten();
320
321 return pFirst->pData[nIndex];
322 }
323
324 bool isWS( long nIndex ) const
325 {
326 flatten();
327
328 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t'
329 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n';
330 }
331
332 bool isAlpha( long nIndex ) const
333 {
334 flatten();
335
336 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z')
337 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z');
338 }
339
340 void toLower()
341 {
342 flatten();
343 unShare();
344
345 for( long j = 0; j < nLength; j++ )
346 {
347 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' )
348 pFirst->pData[j] -= 'A'-'a';
349 }
350 }
351
352 void toUpper()
353 {
354 flatten();
355 unShare();
356
357 for( long j = 0; j < nLength; j++ )
358 {
359 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' )
360 pFirst->pData[j] += 'A'-'a';
361 }
362 }
363
364 void serialize( class Serializer &ar )
365 {
366 if( ar.isLoading() )
367 {
368 clear();
369 long nLen;
370 ar >> nLen;
371
372 Chunk *pNew = newChunk( nLen );
373 ar.read( pNew->pData, nLen*sizeof(chr) );
374 appendChunk( pNew );
375 }
376 else
377 {
378 flatten();
379
380 ar << nLength;
381 ar.write( pFirst->pData, nLength*sizeof(chr) );
382 }
383 }
384
385private:
386 void flatten() const
387 {
388 if( isFlat() )
389 return;
390
391 if( pFirst == NULL )
392 return;
393
394 unShare();
395
396 Chunk *pNew = newChunk( nLength );
397 chr *pos = pNew->pData;
398 Chunk *i = pFirst;
399 for(;;)
400 {
401 cpy( pos, i->pData, i->nLength );
402 pos += i->nLength;
403 i = i->pNext;
404 if( i == NULL )
405 break;
406 }
407 realClear();
408
409 pLast = pFirst = pNew;
410 nLength = pNew->nLength;
411 }
412
413 void realClear() const
414 {
415 if( pFirst == NULL )
416 return;
417
418 if( isShared() )
419 {
420 decRefs();
421 }
422 else
423 {
424 Chunk *i = pFirst;
425 for(;;)
426 {
427 Chunk *n = i->pNext;
428 aChr.deallocate( i->pData, i->nLength+1 );
429 aChunk.deallocate( i, 1 );
430 if( n == NULL )
431 break;
432 i = n;
433 }
434 pFirst = pLast = NULL;
435 nLength = 0;
436 }
437 }
438
439 void copyFrom( const FBasicString<chr, chralloc, chunkalloc> &rSrc )
440 {
441 if( rSrc.pFirst == NULL )
442 return;
443
444 decRefs();
445
446 Chunk *pNew = newChunk( rSrc.nLength );
447 chr *pos = pNew->pData;
448 Chunk *i = rSrc.pFirst;
449 for(;;)
450 {
451 cpy( pos, i->pData, i->nLength );
452 pos += i->nLength;
453 i = i->pNext;
454 if( i == NULL )
455 break;
456 }
457 clear();
458
459 appendChunk( pNew );
460 }
461
462 bool isFlat() const
463 {
464 return (pFirst == pLast);
465 }
466
467 bool isShared() const
468 {
469 return (pnRefs != NULL);
470 }
471
472 Chunk *newChunk() const
473 {
474 Chunk *pNew = aChunk.allocate( 1 );
475 pNew->pNext = NULL;
476 return pNew;
477 }
478
479 Chunk *newChunk( long nLen ) const
480 {
481 Chunk *pNew = aChunk.allocate( 1 );
482 pNew->pNext = NULL;
483 pNew->nLength = nLen;
484 pNew->pData = aChr.allocate( nLen+1 );
485 pNew->pData[nLen] = (chr)0;
486 return pNew;
487 }
488
489 void appendChunk( Chunk *pNewChunk )
490 {
491 unShare();
492
493 if( pFirst == NULL )
494 pLast = pFirst = pNewChunk;
495 else
496 {
497 pLast->pNext = pNewChunk;
498 pLast = pNewChunk;
499 }
500
501 nLength += pNewChunk->nLength;
502 }
503
504 void prependChunk( Chunk *pNewChunk )
505 {
506 unShare();
507
508 if( pFirst == NULL )
509 pLast = pFirst = pNewChunk;
510 else
511 {
512 pNewChunk->pNext = pFirst;
513 pFirst = pNewChunk;
514 }
515
516 nLength += pNewChunk->nLength;
517 }
518
519 void joinShare( MyType &rSrc )
520 {
521 clear();
522
523 if( !rSrc.isFlat() )
524 rSrc.flatten();
525
526 rSrc.initCount();
527 pnRefs = rSrc.pnRefs;
528 (*pnRefs)++;
529 nLength = rSrc.nLength;
530 pFirst = rSrc.pFirst;
531 pLast = rSrc.pLast;
532 }
533
534 void joinShare( const MyType &rSrc )
535 {
536 clear();
537
538 rSrc.flatten();
539
540 if( !rSrc.isShared() )
541 {
542 rSrc.pnRefs = new uint32_t;
543 (*rSrc.pnRefs) = 1;
544 }
545 pnRefs = rSrc.pnRefs;
546 (*pnRefs)++;
547 nLength = rSrc.nLength;
548 pFirst = rSrc.pFirst;
549 pLast = rSrc.pLast;
550 }
551
552 /**
553 * This takes an object that was shared and makes a copy of the base data
554 * that was being shared so that this copy can be changed. This should be
555 * added before any call that will change this object;
556 */
557 void unShare() const
558 {
559 if( isShared() == false )
560 return;
561
562 Chunk *pNew = newChunk( nLength );
563 chr *pos = pNew->pData;
564 Chunk *i = pFirst;
565 for(;;)
566 {
567 cpy( pos, i->pData, i->nLength );
568 pos += i->nLength;
569 i = i->pNext;
570 if( i == NULL )
571 break;
572 }
573 decRefs();
574 pLast = pFirst = pNew;
575 nLength = pNew->nLength;
576 }
577
578 /**
579 * This decrements our ref count and pulls us out of the share. If the ref
580 * count hits zero because of this, it destroys the share. This is not
581 * safe to call on it's own, it's much better to call unShare.
582 */
583 void decRefs() const
584 {
585 if( isShared() )
586 {
587 (*pnRefs)--;
588 if( (*pnRefs) == 0 )
589 destroyShare();
590 else
591 {
592 pnRefs = NULL;
593 pFirst = NULL;
594 pLast = NULL;
595 nLength = 0;
596 }
597 }
598 }
599
600 /**
601 * While the unShare function removes an instance from a share, this
602 * function destroys the data that was in the share, removing the share
603 * itself. This should only be called when the refcount for the share has
604 * or is about to reach zero.
605 */
606 void destroyShare() const
607 {
608 delete pnRefs;
609 pnRefs = NULL;
610 realClear();
611 }
612
613#ifdef VALTEST
614 void cpy( chr *dest, const chr *src, long count ) const
615 {
616 for( int j = 0; j < count; j++ )
617 {
618 *dest = *src;
619 dest++;
620 src++;
621 }
622 }
623#endif
624
625 void initCount() const
626 {
627 if( !isShared() )
628 {
629 pnRefs = new uint32_t;
630 (*pnRefs) = 1;
631 }
632 }
633
634private:
635 mutable long nLength;
636 mutable uint32_t *pnRefs;
637 mutable Chunk *pFirst;
638 mutable Chunk *pLast;
639
640 mutable chralloc aChr;
641 mutable chunkalloc aChunk;
642};
643
644typedef FBasicString<char> FString;
645
646#include "hash.h"
647template<> uint32_t __calcHashCode<FString>( const FString &k );
648template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b );
649
650
651#endif