aboutsummaryrefslogtreecommitdiff
path: root/src/fstring.h
diff options
context:
space:
mode:
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