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