summaryrefslogtreecommitdiff
path: root/src/fstring.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2009-01-07 15:59:57 +0000
committerMike Buland <eichlan@xagasoft.com>2009-01-07 15:59:57 +0000
commit45e065bc4fc93731ea9a0543462bc7cf9e6084d7 (patch)
treea9e8279fe00b9b01dc2393f59dc7f41b5e416b2a /src/fstring.h
parentd96fe229e79f9b1947cbd24ff52d6bf7bb9bf80d (diff)
downloadlibbu++-45e065bc4fc93731ea9a0543462bc7cf9e6084d7.tar.gz
libbu++-45e065bc4fc93731ea9a0543462bc7cf9e6084d7.tar.bz2
libbu++-45e065bc4fc93731ea9a0543462bc7cf9e6084d7.tar.xz
libbu++-45e065bc4fc93731ea9a0543462bc7cf9e6084d7.zip
Only two real changes. First, Bu::FString and Bu::FBasicString are in different
files. This won't affect any programs at all anywhere. This will just make it easier to maintain and extend later. You still want to include "bu/fstring.h" and use Bu::FString in code. The other is kinda fun. I created a special format for unit tests, they use the extension .unit now and use the mkunit.sh script to convert them to c++ code. There are some nice features here too, maintaining unit tests is much, much easier, and we can have more features without making the code any harder to use. Also, it will be easier to have the unit tests generate reports and be run from a master program and the like.
Diffstat (limited to 'src/fstring.h')
-rw-r--r--src/fstring.h1111
1 files changed, 7 insertions, 1104 deletions
diff --git a/src/fstring.h b/src/fstring.h
index e1660f9..0793154 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -8,1121 +8,24 @@
8#ifndef BU_F_STRING_H 8#ifndef BU_F_STRING_H
9#define BU_F_STRING_H 9#define BU_F_STRING_H
10 10
11#include <stdint.h> 11#include "bu/fbasicstring.h"
12#include <string>
13#include <memory>
14
15#ifndef WIN32
16#include <wordexp.h>
17#endif
18
19#include "bu/archival.h"
20#include "bu/archive.h"
21#include "bu/hash.h"
22#include "bu/util.h"
23 12
24namespace Bu 13namespace Bu
25{ 14{
26 template< typename chr >
27 struct FStringChunk
28 {
29 long nLength;
30 chr *pData;
31 FStringChunk *pNext;
32 };
33
34 /**
35 * Flexible String class. This class was designed with string passing and
36 * generation in mind. Like the standard string class you can specify what
37 * datatype to use for each character. Unlike the standard string class,
38 * collection of appended and prepended terms is done lazily, making long
39 * operations that involve many appends very inexpensive. In addition
40 * internal ref-counting means that if you pass strings around between
41 * functions there's almost no overhead in time or memory since a reference
42 * is created and no data is actually copied. This also means that you
43 * never need to put any FBasicString into a ref-counting container class.
44 *
45 *@param chr (typename) Type of character (i.e. char)
46 *@param nMinSize (int) Chunk size (default: 256)
47 *@param chralloc (typename) Memory Allocator for chr
48 *@param chunkalloc (typename) Memory Allocator for chr chunks
49 */
50 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
51 class FBasicString : public Archival
52 {
53#ifndef VALTEST
54#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
55#endif
56 private:
57 typedef struct FStringChunk<chr> Chunk;
58 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
59
60 public:
61 FBasicString() :
62 nLength( 0 ),
63 pFirst( NULL ),
64 pLast( NULL )
65 {
66 }
67
68 FBasicString( const chr *pData ) :
69 nLength( 0 ),
70 pFirst( NULL ),
71 pLast( NULL )
72 {
73 append( pData );
74 }
75
76 FBasicString( const chr *pData, long nLength ) :
77 nLength( 0 ),
78 pFirst( NULL ),
79 pLast( NULL )
80 {
81 append( pData, nLength );
82 }
83
84 FBasicString( const MyType &rSrc ) :
85 Archival(),
86 nLength( 0 ),
87 pFirst( NULL ),
88 pLast( NULL )
89 {
90 if( rSrc.nLength > 0 )
91 {
92 rSrc.flatten();
93 append( rSrc.pFirst->pData, rSrc.nLength );
94 }
95 }
96
97 FBasicString( const MyType &rSrc, long nLength ) :
98 nLength( 0 ),
99 pFirst( NULL ),
100 pLast( NULL )
101 {
102 append( rSrc.pFirst->pData, nLength );
103 }
104
105 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
106 nLength( 0 ),
107 pFirst( NULL ),
108 pLast( NULL )
109 {
110 append( rSrc.pFirst->pData+nStart, nLength );
111 }
112
113 FBasicString( long nSize ) :
114 nLength( nSize ),
115 pFirst( NULL ),
116 pLast( NULL )
117 {
118 pFirst = pLast = newChunk( nSize );
119 }
120
121 virtual ~FBasicString()
122 {
123 clear();
124 }
125
126 /**
127 *@todo void append( const MyType & sData )
128 */
129
130 /**
131 * Append data to your string.
132 *@param pData (const chr *) The data to append.
133 */
134 void append( const chr *pData )
135 {
136 if( !pData ) return;
137 long nLen;
138 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
139 if( nLen == 0 )
140 return;
141
142 Chunk *pNew = newChunk( nLen );
143 cpy( pNew->pData, pData, nLen );
144
145 appendChunk( pNew );
146 }
147
148 /**
149 * Append data to your string.
150 *@param pData (const chr *) The data to append.
151 *@param nLen (long) The length of the data to append.
152 */
153 void append( const chr *pData, long nLen )
154 {
155 if( nLen == 0 )
156 return;
157
158 Chunk *pNew = newChunk( nLen );
159
160 cpy( pNew->pData, pData, nLen );
161
162 appendChunk( pNew );
163 }
164
165 /**
166 * Append a single chr to your string.
167 *@param cData (const chr &) The character to append.
168 */
169 void append( const chr &cData )
170 {
171 if( pLast && pLast->nLength < nMinSize )
172 {
173 pLast->pData[pLast->nLength] = cData;
174 ++pLast->nLength; ++nLength;
175 // pLast->pData[pLast->nLength] = (chr)0;
176 }
177 else
178 {
179 append( &cData, 1 );
180 }
181 }
182
183 /**
184 * Append another FString to this one.
185 *@param sData (MyType &) The FString to append.
186 */
187 void append( const MyType & sData )
188 {
189 append( sData.getStr(), sData.getSize() );
190 }
191
192 /**
193 * Append another FString to this one.
194 *@param sData (MyType &) The FString to append.
195 *@param nLen How much data to append.
196 */
197 void append( const MyType & sData, long nLen )
198 {
199 append( sData.getStr(), nLen );
200 }
201
202 /**
203 * Prepend another FString to this one.
204 *@param sData (MyType &) The FString to prepend.
205 */
206 void prepend( const MyType & sData )
207 {
208 prepend( sData.getStr(), sData.getSize() );
209 }
210
211 /**
212 * Prepend data to your string.
213 *@param pData (const chr *) The data to prepend.
214 */
215 void prepend( const chr *pData )
216 {
217 if( pData == NULL )
218 return;
219 long nLen;
220 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
221
222 Chunk *pNew = newChunk( nLen );
223 cpy( pNew->pData, pData, nLen );
224
225 prependChunk( pNew );
226 }
227
228 /**
229 * Prepend data to your string.
230 *@param pData (const chr *) The data to prepend.
231 *@param nLen (long) The length of the data to prepend.
232 */
233 void prepend( const chr *pData, long nLen )
234 {
235 Chunk *pNew = newChunk( nLen );
236
237 cpy( pNew->pData, pData, nLen );
238
239 prependChunk( pNew );
240 }
241
242 void insert( long nPos, const chr *pData, long nLen )
243 {
244 if( nLen <= 0 )
245 return;
246 if( nPos <= 0 )
247 {
248 prepend( pData, nLen );
249 }
250 else if( nPos >= nLength )
251 {
252 append( pData, nLen );
253 }
254 else
255 {
256 flatten();
257 Chunk *p1 = newChunk( nPos );
258 Chunk *p2 = newChunk( nLen );
259 Chunk *p3 = newChunk( nLength-nPos );
260 cpy( p1->pData, pFirst->pData, nPos );
261 cpy( p2->pData, pData, nLen );
262 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos );
263 clear();
264 appendChunk( p1 );
265 appendChunk( p2 );
266 appendChunk( p3 );
267 }
268 }
269
270 void insert( long nPos, const MyType &str )
271 {
272 if( nPos <= 0 )
273 {
274 prepend( str );
275 }
276 else if( nPos >= nLength )
277 {
278 append( str );
279 }
280 else
281 {
282 flatten();
283 Chunk *p1 = newChunk( nPos );
284 Chunk *p3 = newChunk( nLength-nPos );
285 cpy( p1->pData, pFirst->pData, nPos );
286 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos );
287 clear();
288 appendChunk( p1 );
289 for( Chunk *pChnk = str->pFirst; pChnk; pChnk = pChnk->next )
290 {
291 appendChunk( copyChunk( pChnk ) );
292 }
293
294 appendChunk( p3 );
295 }
296 }
297
298 void insert( long nPos, const chr *pData )
299 {
300 insert( nPos, pData, strlen( pData ) );
301 }
302
303 void remove( long nPos, long nLen )
304 {
305 if( nLen <= 0 || nPos < 0 || nPos >= nLength )
306 return;
307 if( nLen > nLength-nPos )
308 nLen = nLength-nPos;
309 flatten();
310 cpy( pFirst->pData+nPos, pFirst->pData+nPos+nLen, nLength-nPos-nLen+1 );
311 nLength -= nLen;
312 pFirst->nLength -= nLen;
313 }
314
315 /**
316 *@todo void prepend( const chr &cData )
317 */
318
319 /**
320 * Clear all data from the string.
321 */
322 void clear()
323 {
324 realClear();
325 }
326
327 /**
328 * Force the string to resize
329 *@param nNewSize (long) The new size of the string.
330 */
331 void resize( long nNewSize )
332 {
333 if( nLength == nNewSize )
334 return;
335 if( nNewSize < 0 )
336 nNewSize = 0;
337
338 flatten();
339
340 Chunk *pNew = newChunk( nNewSize );
341 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
342 if( nLength > 0 )
343 {
344 cpy( pNew->pData, pFirst->pData, nNewLen );
345 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
346 aChunk.deallocate( pFirst, 1 );
347 }
348 pNew->pData[nNewLen] = (chr)0;
349 pFirst = pLast = pNew;
350 nLength = nNewSize;
351 }
352
353 /**
354 * Get the current size of the string.
355 *@returns (long) The current size of the string.
356 */
357 long getSize() const
358 {
359 return nLength;
360 }
361
362 /**
363 * Get a pointer to the string array.
364 *@returns (chr *) The string data.
365 */
366 chr *getStr()
367 {
368 if( pFirst == NULL )
369 return (chr *)"";
370
371 flatten();
372 pFirst->pData[nLength] = (chr)0;
373 return pFirst->pData;
374 }
375
376 /**
377 * Get a const pointer to the string array.
378 *@returns (const chr *) The string data.
379 */
380 const chr *getStr() const
381 {
382 if( pFirst == NULL )
383 return (chr *)"";
384
385 flatten();
386 pFirst->pData[nLength] = (chr)0;
387 return pFirst->pData;
388 }
389
390 MyType getSubStr( long iStart, long iSize=-1 ) const
391 {
392 if( iStart < 0 )
393 iStart = 0;
394 if( iStart >= nLength )
395 return "";
396 if( iSize < 0 )
397 iSize = nLength;
398 if( iStart+iSize > nLength )
399 iSize = nLength-iStart;
400 if( iSize == 0 )
401 return "";
402
403 flatten();
404 MyType ret( pFirst->pData+iStart, iSize );
405 return ret;
406 }
407
408 /**
409 * (std::string compatability) Get a pointer to the string array.
410 *@returns (chr *) The string data.
411 */
412 DEPRECATED
413 chr *c_str()
414 {
415 if( pFirst == NULL )
416 return NULL;
417
418 flatten();
419 pFirst->pData[nLength] = (chr)0;
420 return pFirst->pData;
421 }
422
423 /**
424 * (std::string compatability) Get a const pointer to the string array.
425 *@returns (const chr *) The string data.
426 */
427 DEPRECATED
428 const chr *c_str() const
429 {
430 if( pFirst == NULL )
431 return NULL;
432
433 flatten();
434 pFirst->pData[nLength] = (chr)0;
435 return pFirst->pData;
436 }
437
438 /**
439 * Plus equals operator for FString.
440 *@param pData (const chr *) The data to append to your FString.
441 */
442 MyType &operator +=( const chr *pData )
443 {
444 append( pData );
445
446 return (*this);
447 }
448
449 /**
450 * Plus equals operator for FString.
451 *@param pData (const MyType &) The FString to append to your FString.
452 */
453 MyType &operator +=( const MyType &rSrc )
454 {
455 if( rSrc.nLength == 0 )
456 return (*this);
457 rSrc.flatten();
458 append( rSrc.pFirst->pData, rSrc.nLength );
459
460 return (*this);
461 }
462
463 /**
464 * Plus equals operator for FString.
465 *@param pData (const chr) The character to append to your FString.
466 */
467 MyType &operator +=( const chr cData )
468 {
469 if( pLast && pLast->nLength < nMinSize )
470 {
471 pLast->pData[pLast->nLength] = cData;
472 ++pLast->nLength; ++nLength;
473 // pLast->pData[pLast->nLength] = (chr)0;
474 }
475 else
476 {
477 append( &cData, 1 );
478 }
479 //append( pData );
480
481 return (*this);
482 }
483
484 /**
485 * Assignment operator.
486 *@param pData (const chr *) The character array to append to your
487 * FString.
488 */
489 MyType &operator =( const chr *pData )
490 {
491 clear();
492 append( pData );
493
494 return (*this);
495 }
496
497 MyType &operator =( const std::basic_string<chr> &rData )
498 {
499 clear();
500 append( rData.c_str(), rData.size() );
501
502 return (*this);
503 }
504
505 MyType operator +( const MyType &rRight )
506 {
507 MyType ret( *this );
508 ret.append( rRight );
509 return ret;
510 }
511
512 MyType operator +( const chr *pRight )
513 {
514 MyType ret( *this );
515 ret.append( pRight );
516 return ret;
517 }
518
519 MyType operator +( chr *pRight )
520 {
521 MyType ret( *this );
522 ret.append( pRight );
523 return ret;
524 }
525
526 /**
527 * Reset your FString to this character array.
528 *@param pData (const chr *) The character array to set your FString to.
529 */
530 void set( const chr *pData )
531 {
532 clear();
533 append( pData );
534 }
535
536 /**
537 * Reset your FString to this character array.
538 *@param pData (const chr *) The character array to set your FString to.
539 *@param nSize (long) The length of the inputted character array.
540 */
541 void set( const chr *pData, long nSize )
542 {
543 clear();
544 append( pData, nSize );
545 }
546
547 void expand()
548 {
549 flatten();
550
551#ifndef WIN32
552 wordexp_t result;
553
554 /* Expand the string for the program to run. */
555 switch (wordexp (pFirst->pData, &result, 0))
556 {
557 case 0: /* Successful. */
558 {
559 set( result.we_wordv[0] );
560 wordfree( &result );
561 return;
562 }
563 break;
564 case WRDE_NOSPACE:
565 /* If the error was `WRDE_NOSPACE',
566 then perhaps part of the result was allocated. */
567 wordfree (&result);
568 default: /* Some other error. */
569 return;
570 }
571#endif
572 }
573
574 /**
575 * Assignment operator.
576 *@param rSrc (const MyType &) The FString to set your FString to.
577 */
578 MyType &operator =( const MyType &rSrc )
579 {
580 copyFrom( rSrc );
581
582 return (*this);
583 }
584
585 /**
586 * Equals comparison operator.
587 *@param pData (const chr *) The character array to compare your FString
588 * to.
589 */
590 bool operator ==( const chr *pData ) const
591 {
592 if( pFirst == NULL ) {
593 if( pData == NULL )
594 return true;
595 if( pData[0] == (chr)0 )
596 return true;
597 return false;
598 }
599
600 flatten();
601 pFirst->pData[nLength] = (chr)0;
602 const chr *a = pData;
603 chr *b = pFirst->pData;
604 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
605 {
606 if( *a != *b )
607 return false;
608 if( *a == (chr)0 && j < nLength )
609 return false;
610 }
611
612 return true;
613 }
614
615 /**
616 * Equals comparison operator.
617 *@param pData (const MyType &) The FString to compare your FString to.
618 */
619 bool operator ==( const MyType &pData ) const
620 {
621 if( pFirst == pData.pFirst )
622 return true;
623 if( pFirst == NULL )
624 return false;
625 if( nLength != pData.nLength )
626 return false;
627
628 flatten();
629 pData.flatten();
630 const chr *a = pData.pFirst->pData;
631 chr *b = pFirst->pData;
632 for( long j = 0; j < nLength; j++, a++, b++ )
633 {
634 if( *a != *b )
635 return false;
636 }
637
638 return true;
639 }
640
641 /**
642 * Not equals comparison operator.
643 *@param pData (const chr *) The character array to compare your FString
644 * to.
645 */
646 bool operator !=(const chr *pData ) const
647 {
648 return !(*this == pData);
649 }
650
651 /**
652 * Not equals comparison operator.
653 *@param pData (const MyType &) The FString to compare your FString to.
654 */
655 bool operator !=(const MyType &pData ) const
656 {
657 return !(*this == pData);
658 }
659
660 /**
661 * Indexing operator
662 *@param nIndex (long) The index of the character you want.
663 *@returns (chr &) The character at position (nIndex).
664 */
665 chr &operator[]( long nIndex )
666 {
667 flatten();
668
669 return pFirst->pData[nIndex];
670 }
671
672 /**
673 * Const indexing operator
674 *@param nIndex (long) The index of the character you want.
675 *@returns (const chr &) The character at position (nIndex).
676 */
677 const chr &operator[]( long nIndex ) const
678 {
679 flatten();
680
681 return pFirst->pData[nIndex];
682 }
683/*
684 operator const chr *() const
685 {
686 if( !pFirst ) return NULL;
687 flatten();
688 return pFirst->pData;
689 }
690 */
691
692 operator bool() const
693 {
694 return (pFirst != NULL);
695 }
696
697 bool isSet() const
698 {
699 return (pFirst != NULL);
700 }
701
702 /**
703 * Is the character at index (nIndex) white space?
704 *@param nIndex (long) The index of the character you want to check.
705 *@returns (bool) Is it white space?
706 */
707 bool isWS( long nIndex ) const
708 {
709 flatten();
710
711 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t'
712 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n';
713 }
714
715 /**
716 * Is the character at index (nIndex) a letter?
717 *@param nIndex (long) The index of the character you want to check.
718 *@returns (bool) Is it a letter?
719 */
720 bool isAlpha( long nIndex ) const
721 {
722 flatten();
723
724 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z')
725 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z');
726 }
727
728 /**
729 * Convert your alpha characters to lower case.
730 */
731 void toLower()
732 {
733 flatten();
734
735 for( long j = 0; j < nLength; j++ )
736 {
737 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' )
738 pFirst->pData[j] -= 'A'-'a';
739 }
740 }
741
742 /**
743 * Convert your alpha characters to upper case.
744 */
745 void toUpper()
746 {
747 flatten();
748
749 for( long j = 0; j < nLength; j++ )
750 {
751 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' )
752 pFirst->pData[j] += 'A'-'a';
753 }
754 }
755
756 /**
757 * Find the index of the first occurrance of (sText)
758 *@param sText (const chr *) The string to search for.
759 *@returns (long) The index of the first occurrance. -1 for not found.
760 */
761 long find( const chr cChar ) const
762 {
763 flatten();
764 for( long j = 0; j < pFirst->nLength; j++ )
765 {
766 if( pFirst->pData[j] == cChar )
767 return j;
768 }
769 return -1;
770 }
771
772 /**
773 * Find the index of the first occurrance of cChar
774 *@param cChar (const chr) The character to search for.
775 *@returns (long) The index of the first occurrance. -1 for not found.
776 */
777 long find( const chr *sText ) const
778 {
779 long nTLen = strlen( sText );
780 flatten();
781 for( long j = 0; j < pFirst->nLength-nTLen; j++ )
782 {
783 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
784 return j;
785 }
786 return -1;
787 }
788
789 /**
790 * Find the index of the first occurrance of cChar
791 *@param sText (const chr *) The string to search for.
792 *@returns (long) The index of the first occurrance. -1 for not found.
793 */
794 long find( long iStart, const chr cChar ) const
795 {
796 flatten();
797 for( long j = iStart; j < pFirst->nLength; j++ )
798 {
799 if( pFirst->pData[j] == cChar )
800 return j;
801 }
802 return -1;
803 }
804
805 /**
806 * Find the index of the first occurrance of sText
807 *@param cChar (const chr) The character to search for.
808 *@returns (long) The index of the first occurrance. -1 for not found.
809 */
810 long find( long iStart, const chr *sText ) const
811 {
812 long nTLen = strlen( sText );
813 flatten();
814 for( long j = iStart; j < pFirst->nLength-nTLen; j++ )
815 {
816 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
817 return j;
818 }
819 return -1;
820 }
821
822 /**
823 * Do a reverse search for (sText)
824 *@param sText (const chr *) The string to search for.
825 *@returns (long) The index of the last occurrance. -1 for not found.
826 */
827 long rfind( const chr *sText ) const
828 {
829 long nTLen = strlen( sText );
830 flatten();
831 for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- )
832 {
833 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
834 return j;
835 }
836 return -1;
837 }
838
839 /**
840 * Remove nAmnt bytes from the front of the string. This function
841 * operates in O(n) time and should be used sparingly.
842 */
843 void trimFront( long nAmnt )
844 {
845 long nNewLen = nLength - nAmnt;
846 flatten();
847 Chunk *pNew = newChunk( nNewLen );
848 cpy( pNew->pData, pFirst->pData+nAmnt, nNewLen );
849 clear();
850 appendChunk( pNew );
851 }
852
853 void format( const char *sFrmt, ...)
854 {
855 clear();
856
857 va_list ap;
858 va_start( ap, sFrmt );
859
860 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
861
862 Chunk *pNew = newChunk( iLen );
863 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
864 appendChunk( pNew );
865
866 va_end( ap );
867 }
868
869 void formatAppend( const char *sFrmt, ...)
870 {
871 va_list ap;
872 va_start( ap, sFrmt );
873
874 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
875
876 Chunk *pNew = newChunk( iLen );
877 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
878 appendChunk( pNew );
879
880 va_end( ap );
881 }
882
883 void formatPrepend( const char *sFrmt, ...)
884 {
885 va_list ap;
886 va_start( ap, sFrmt );
887
888 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
889
890 Chunk *pNew = newChunk( iLen );
891 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
892 prependChunk( pNew );
893
894 va_end( ap );
895 }
896
897 /**
898 * Function the archiver calls to archive your FString.
899 *@param ar (Archive) The archive which is archiving your FString.
900 */
901 void archive( class Archive &ar )
902 {
903 if( ar.isLoading() )
904 {
905 clear();
906 long nLen;
907 ar >> nLen;
908
909 if( nLen > 0 )
910 {
911 Chunk *pNew = newChunk( nLen );
912 ar.read( pNew->pData, nLen*sizeof(chr) );
913 appendChunk( pNew );
914 }
915 }
916 else
917 {
918 flatten();
919
920 ar << nLength;
921 if( nLength )
922 ar.write( pFirst->pData, nLength*sizeof(chr) );
923 }
924 }
925
926 typedef chr *iterator;
927 typedef const chr *const_iterator;
928
929 iterator begin()
930 {
931 if( nLength == 0 )
932 return NULL;
933 flatten();
934 return pFirst->pData;
935 }
936
937 const_iterator begin() const
938 {
939 if( nLength == 0 )
940 return NULL;
941 flatten();
942 return pFirst->pData;
943 }
944
945 iterator end()
946 {
947 if( nLength == 0 )
948 return NULL;
949 return pFirst->pData+pFirst->nLength;
950 }
951
952 const_iterator end() const
953 {
954 if( nLength == 0 )
955 return NULL;
956 return pFirst->pData+pFirst->nLength;
957 }
958
959 bool isEmpty() const
960 {
961 if( nLength == 0 )
962 return true;
963 return false;
964 }
965
966 private:
967 void flatten() const
968 {
969 if( isFlat() )
970 return;
971
972 if( pFirst == NULL )
973 return;
974
975 Chunk *pNew = newChunk( nLength );
976 chr *pos = pNew->pData;
977 Chunk *i = pFirst;
978 for(;;)
979 {
980 cpy( pos, i->pData, i->nLength );
981 pos += i->nLength;
982 i = i->pNext;
983 if( i == NULL )
984 break;
985 }
986 realClear();
987
988 pLast = pFirst = pNew;
989 nLength = pNew->nLength;
990 }
991
992 void realClear() const
993 {
994 if( pFirst == NULL )
995 return;
996
997 Chunk *i = pFirst;
998 for(;;)
999 {
1000 Chunk *n = i->pNext;
1001 aChr.deallocate( i->pData, i->nLength+1 );
1002 aChunk.deallocate( i, 1 );
1003 if( n == NULL )
1004 break;
1005 i = n;
1006 }
1007 pFirst = pLast = NULL;
1008 nLength = 0;
1009 }
1010
1011 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
1012 {
1013 if( rSrc.pFirst == NULL )
1014 {
1015 clear();
1016 return;
1017 }
1018
1019 Chunk *pNew = newChunk( rSrc.nLength );
1020 chr *pos = pNew->pData;
1021 Chunk *i = rSrc.pFirst;
1022 for(;;)
1023 {
1024 cpy( pos, i->pData, i->nLength );
1025 pos += i->nLength;
1026 i = i->pNext;
1027 if( i == NULL )
1028 break;
1029 }
1030 clear();
1031
1032 appendChunk( pNew );
1033 }
1034
1035 bool isFlat() const
1036 {
1037 return (pFirst == pLast);
1038 }
1039
1040 Chunk *newChunk() const
1041 {
1042 Chunk *pNew = aChunk.allocate( 1 );
1043 pNew->pNext = NULL;
1044 return pNew;
1045 }
1046
1047 Chunk *newChunk( long nLen ) const
1048 {
1049 Chunk *pNew = aChunk.allocate( 1 );
1050 pNew->pNext = NULL;
1051 pNew->nLength = nLen;
1052 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
1053 pNew->pData[nLen] = (chr)0;
1054 return pNew;
1055 }
1056
1057 void appendChunk( Chunk *pNewChunk )
1058 {
1059 if( pFirst == NULL )
1060 pLast = pFirst = pNewChunk;
1061 else
1062 {
1063 pLast->pNext = pNewChunk;
1064 pLast = pNewChunk;
1065 }
1066
1067 nLength += pNewChunk->nLength;
1068 }
1069
1070 void prependChunk( Chunk *pNewChunk )
1071 {
1072 if( pFirst == NULL )
1073 pLast = pFirst = pNewChunk;
1074 else
1075 {
1076 pNewChunk->pNext = pFirst;
1077 pFirst = pNewChunk;
1078 }
1079
1080 nLength += pNewChunk->nLength;
1081 }
1082
1083#ifdef VALTEST
1084 void cpy( chr *dest, const chr *src, long count ) const
1085 {
1086 for( int j = 0; j < count; j++ )
1087 {
1088 *dest = *src;
1089 dest++;
1090 src++;
1091 }
1092 }
1093#endif
1094
1095 private:
1096 mutable long nLength;
1097 mutable Chunk *pFirst;
1098 mutable Chunk *pLast;
1099
1100 mutable chralloc aChr;
1101 mutable chunkalloc aChunk;
1102 };
1103
1104 typedef FBasicString<char> FString; 15 typedef FBasicString<char> FString;
1105 16
1106 template<> uint32_t __calcHashCode<FString>( const FString &k ); 17 template<> uint32_t __calcHashCode<FString>( const FString &k );
1107 template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); 18 template<> bool __cmpHashKeys<FString>(
1108 template<class T> FBasicString<T> operator +( const T *pLeft, const FBasicString<T> &rRight ) 19 const FString &a, const FString &b );
1109 {
1110 Bu::FBasicString<T> ret( pLeft );
1111 ret.append( rRight );
1112 return ret;
1113 }
1114 20
1115#ifdef BU_TRACE
1116 template<typename t> void __tracer_format( const t &v ); 21 template<typename t> void __tracer_format( const t &v );
1117 template<> void __tracer_format<FString>( const FString &v ); 22 template<> void __tracer_format<FString>( const FString &v );
1118#endif
1119} 23}
1120 24
25/***** I dunno about this block, I don't really want to have it... *****
1121#include <ostream> 26#include <ostream>
1122std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val ); 27std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os,
1123 28 const Bu::FString &val );
1124#ifndef VALTEST 29*/
1125#undef cpy
1126#endif
1127 30
1128#endif 31#endif