aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--build.conf10
-rwxr-xr-xmkunit.sh34
-rw-r--r--src/fbasicstring.cpp9
-rw-r--r--src/fbasicstring.h1132
-rw-r--r--src/fstring.cpp8
-rw-r--r--src/fstring.h1111
-rw-r--r--src/unit/archive.cpp145
-rw-r--r--src/unit/archive.unit130
-rw-r--r--src/unit/array.cpp101
-rw-r--r--src/unit/array.unit80
-rw-r--r--src/unit/file.cpp117
-rw-r--r--src/unit/file.unit95
-rw-r--r--src/unit/fstring.cpp170
-rw-r--r--src/unit/fstring.unit140
-rw-r--r--src/unit/hash.cpp109
-rw-r--r--src/unit/hash.unit86
-rw-r--r--src/unit/membuf.cpp60
-rw-r--r--src/unit/membuf.unit45
-rw-r--r--src/unit/taf.cpp133
-rw-r--r--src/unit/taf.unit112
-rw-r--r--src/unit/xml.cpp39
-rw-r--r--src/unit/xml.unit20
-rw-r--r--src/unitsuite.cpp2
-rw-r--r--src/unitsuite.h8
24 files changed, 1911 insertions, 1985 deletions
diff --git a/build.conf b/build.conf
index 898d6d4..769fa31 100644
--- a/build.conf
+++ b/build.conf
@@ -49,7 +49,7 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"):
49 "tests/itoheap"]: 49 "tests/itoheap"]:
50 set "LDFLAGS" += "-lpthread" 50 set "LDFLAGS" += "-lpthread"
51 51
52filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): 52filesIn("src/unit") filter regexp("^src/unit/(.*)\\.unit$", "unit/{re:1}"):
53 rule "exe", 53 rule "exe",
54 target file, 54 target file,
55 group "tests", 55 group "tests",
@@ -57,7 +57,7 @@ filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"):
57 requires "libbu++.a", 57 requires "libbu++.a",
58 set "CXXFLAGS" += "-I.", 58 set "CXXFLAGS" += "-I.",
59 set "LDFLAGS" += "-L. -lbu++", 59 set "LDFLAGS" += "-L. -lbu++",
60 input "src/{target}.cpp" 60 input "src/{target}.unit"
61 61
62"tests/plugin": set "LDFLAGS" += "-ldl" 62"tests/plugin": set "LDFLAGS" += "-ldl"
63 63
@@ -79,6 +79,12 @@ rule "cpp":
79 requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), 79 requires commandToList("g++ -M {CXXFLAGS} {match}", "make"),
80 perform command("g++ {CXXFLAGS} -c -o {target} {match}") 80 perform command("g++ {CXXFLAGS} -c -o {target} {match}")
81 81
82rule "unit":
83 matches regexp("(.*)\\.unit$"),
84 produces "{re:1}.cpp",
85 requires "mkunit.sh",
86 perform command("./mkunit.sh \"{match}\" \"{target}\"")
87
82rule "hln": 88rule "hln":
83 matches regexp("src/(.*)\\.h"), 89 matches regexp("src/(.*)\\.h"),
84 produces "bu/{re:1}.h", 90 produces "bu/{re:1}.h",
diff --git a/mkunit.sh b/mkunit.sh
new file mode 100755
index 0000000..867d6df
--- /dev/null
+++ b/mkunit.sh
@@ -0,0 +1,34 @@
1#!/bin/bash
2
3function mkfunc()
4{
5 echo "void $1() /**< expect ${2:-pass} */"
6}
7
8function mkadd()
9{
10 ex="expectPass"
11 if [ "$2" == "fail" ]; then
12 ex="expectFail"
13 fi
14 echo "\\\\tadd( static_cast<Bu::UnitSuite::Test>(\\&Unit::$1), \"$1\", Bu::UnitSuite::${ex} );\\\\n"
15}
16
17sedbits=""
18init="#include \"bu/unitsuite.h\"\\\\n\\\\nclass Unit : public Bu::UnitSuite\\\\n{\\\\npublic:\\\\n\\\\nUnit()\\\\n{\\\\n\\\\tsetName(\"${1%.*}\");\\\\n"
19for i in $(grep {% "$1"); do
20 sedbits="${sedbits}s@${i}@$(mkfunc $(echo $i | sed -e 's/.*{%\(.*\)}/\1/' -e 's/:/ /g'))@\n"
21 init="${init}$(mkadd $(echo $i | sed -e 's/.*{%\(.*\)}/\1/' -e 's/:/ /g'))"
22done
23
24init="${init}\\\\n}\\\\n\\\\nvirtual ~Unit() { }\\\\n\\\\n"
25
26sedbits="${sedbits}s@.*{=Init}@${init}@\n"
27
28temp=$(mktemp)
29echo -e "$sedbits" > $temp
30sed -f $temp $1 > $2
31echo -e "\n};\n\nint main( int argc, char *argv[] )\n{\n\treturn Unit().run( argc, argv );\n}\n" >> $2
32
33rm $temp
34
diff --git a/src/fbasicstring.cpp b/src/fbasicstring.cpp
new file mode 100644
index 0000000..6ef4893
--- /dev/null
+++ b/src/fbasicstring.cpp
@@ -0,0 +1,9 @@
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#include "fbasicstring.h"
9
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
diff --git a/src/fstring.cpp b/src/fstring.cpp
index 3ed4f2b..e4dc716 100644
--- a/src/fstring.cpp
+++ b/src/fstring.cpp
@@ -8,8 +8,10 @@
8#define BU_TRACE 8#define BU_TRACE
9#include "bu/trace.h" 9#include "bu/trace.h"
10 10
11#include "fstring.h" 11#include "bu/fstring.h"
12#include "hash.h" 12#include "bu/hash.h"
13
14template class Bu::FBasicString<char>;
13 15
14template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k ) 16template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k )
15{ 17{
@@ -37,8 +39,8 @@ std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FS
37 return os; 39 return os;
38} 40}
39 41
40
41template<> void Bu::__tracer_format<Bu::FString>( const Bu::FString &v ) 42template<> void Bu::__tracer_format<Bu::FString>( const Bu::FString &v )
42{ 43{
43 printf("(%ld)\"%s\"", v.getSize(), v.getStr() ); 44 printf("(%ld)\"%s\"", v.getSize(), v.getStr() );
44} 45}
46
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
diff --git a/src/unit/archive.cpp b/src/unit/archive.cpp
deleted file mode 100644
index 8e71f4b..0000000
--- a/src/unit/archive.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
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#include "bu/unitsuite.h"
9#include "bu/membuf.h"
10
11class Unit : public Bu::UnitSuite
12{
13public:
14 Unit()
15 {
16 setName("Archive");
17 addTest( Unit::testPrimitives );
18 addTest( Unit::testContainers );
19 }
20
21 virtual ~Unit()
22 {
23 }
24
25 void testPrimitives()
26 {
27 Bu::MemBuf mb;
28 {
29 Bu::Archive ar( mb, Bu::Archive::save );
30 ar << (int8_t)1;
31 ar << (uint8_t)2;
32 ar << (int16_t)3;
33 ar << (uint16_t)4;
34 ar << (int32_t)5;
35 ar << (uint32_t)6;
36 ar << (int64_t)7;
37 ar << (uint64_t)8;
38 ar << (char)9;
39 ar << (unsigned char)10;
40 ar << (short)11;
41 ar << (unsigned short)12;
42 ar << (int)13;
43 ar << (unsigned int)14;
44 ar << (long)15;
45 ar << (unsigned long)16;
46 ar << (long long)17;
47 ar << (unsigned long long)18;
48 ar.close();
49 }
50 mb.setPos( 0 );
51 {
52 Bu::Archive ar( mb, Bu::Archive::load );
53 int8_t p1;
54 uint8_t p2;
55 int16_t p3;
56 uint16_t p4;
57 int32_t p5;
58 uint32_t p6;
59 int64_t p7;
60 uint64_t p8;
61 char p9;
62 unsigned char p10;
63 short p11;
64 unsigned short p12;
65 int p13;
66 unsigned int p14;
67 long p15;
68 unsigned long p16;
69 long long p17;
70 unsigned long long p18;
71 ar >> p1;
72 ar >> p2;
73 ar >> p3;
74 ar >> p4;
75 ar >> p5;
76 ar >> p6;
77 ar >> p7;
78 ar >> p8;
79 ar >> p9;
80 ar >> p10;
81 ar >> p11;
82 ar >> p12;
83 ar >> p13;
84 ar >> p14;
85 ar >> p15;
86 ar >> p16;
87 ar >> p17;
88 ar >> p18;
89 unitTest( p1 == 1 );
90 unitTest( p2 == 2 );
91 unitTest( p3 == 3 );
92 unitTest( p4 == 4 );
93 unitTest( p5 == 5 );
94 unitTest( p6 == 6 );
95 unitTest( p7 == 7 );
96 unitTest( p8 == 8 );
97 unitTest( p9 == 9 );
98 unitTest( p10 == 10 );
99 unitTest( p11 == 11 );
100 unitTest( p12 == 12 );
101 unitTest( p13 == 13 );
102 unitTest( p14 == 14 );
103 unitTest( p15 == 15 );
104 unitTest( p16 == 16 );
105 unitTest( p17 == 17 );
106 unitTest( p18 == 18 );
107 ar.close();
108 }
109 }
110
111 void testContainers()
112 {
113 Bu::MemBuf mb;
114 {
115 Bu::Archive ar( mb, Bu::Archive::save );
116 Bu::FString sStr("This is a test string.");
117 Bu::List<int> lList;
118 lList.append( 10 );
119 lList.append( 20 );
120 lList.append( 30 );
121 lList.append( 40 );
122 ar << sStr;
123 ar << lList;
124 ar.close();
125 }
126 mb.setPos( 0 );
127 {
128 Bu::Archive ar( mb, Bu::Archive::load );
129 Bu::FString sStr;
130 Bu::List<int> lList;
131 ar >> sStr;
132 ar >> lList;
133 unitTest( sStr == "This is a test string." );
134 unitTest( lList.getSize() == 4 );
135 Bu::List<int>::iterator i = lList.begin();
136 unitTest( *i == 10 ); i++;
137 unitTest( *i == 20 ); i++;
138 unitTest( *i == 30 ); i++;
139 unitTest( *i == 40 );
140 ar.close();
141 }
142 }
143};
144
145int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
diff --git a/src/unit/archive.unit b/src/unit/archive.unit
new file mode 100644
index 0000000..ecc589b
--- /dev/null
+++ b/src/unit/archive.unit
@@ -0,0 +1,130 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/membuf.h"
10
11{=Init}
12
13{%testPrimitives}
14{
15 Bu::MemBuf mb;
16 {
17 Bu::Archive ar( mb, Bu::Archive::save );
18 ar << (int8_t)1;
19 ar << (uint8_t)2;
20 ar << (int16_t)3;
21 ar << (uint16_t)4;
22 ar << (int32_t)5;
23 ar << (uint32_t)6;
24 ar << (int64_t)7;
25 ar << (uint64_t)8;
26 ar << (char)9;
27 ar << (unsigned char)10;
28 ar << (short)11;
29 ar << (unsigned short)12;
30 ar << (int)13;
31 ar << (unsigned int)14;
32 ar << (long)15;
33 ar << (unsigned long)16;
34 ar << (long long)17;
35 ar << (unsigned long long)18;
36 ar.close();
37 }
38 mb.setPos( 0 );
39 {
40 Bu::Archive ar( mb, Bu::Archive::load );
41 int8_t p1;
42 uint8_t p2;
43 int16_t p3;
44 uint16_t p4;
45 int32_t p5;
46 uint32_t p6;
47 int64_t p7;
48 uint64_t p8;
49 char p9;
50 unsigned char p10;
51 short p11;
52 unsigned short p12;
53 int p13;
54 unsigned int p14;
55 long p15;
56 unsigned long p16;
57 long long p17;
58 unsigned long long p18;
59 ar >> p1;
60 ar >> p2;
61 ar >> p3;
62 ar >> p4;
63 ar >> p5;
64 ar >> p6;
65 ar >> p7;
66 ar >> p8;
67 ar >> p9;
68 ar >> p10;
69 ar >> p11;
70 ar >> p12;
71 ar >> p13;
72 ar >> p14;
73 ar >> p15;
74 ar >> p16;
75 ar >> p17;
76 ar >> p18;
77 unitTest( p1 == 1 );
78 unitTest( p2 == 2 );
79 unitTest( p3 == 3 );
80 unitTest( p4 == 4 );
81 unitTest( p5 == 5 );
82 unitTest( p6 == 6 );
83 unitTest( p7 == 7 );
84 unitTest( p8 == 8 );
85 unitTest( p9 == 9 );
86 unitTest( p10 == 10 );
87 unitTest( p11 == 11 );
88 unitTest( p12 == 12 );
89 unitTest( p13 == 13 );
90 unitTest( p14 == 14 );
91 unitTest( p15 == 15 );
92 unitTest( p16 == 16 );
93 unitTest( p17 == 17 );
94 unitTest( p18 == 18 );
95 ar.close();
96 }
97}
98
99{%testContainers}
100{
101 Bu::MemBuf mb;
102 {
103 Bu::Archive ar( mb, Bu::Archive::save );
104 Bu::FString sStr("This is a test string.");
105 Bu::List<int> lList;
106 lList.append( 10 );
107 lList.append( 20 );
108 lList.append( 30 );
109 lList.append( 40 );
110 ar << sStr;
111 ar << lList;
112 ar.close();
113 }
114 mb.setPos( 0 );
115 {
116 Bu::Archive ar( mb, Bu::Archive::load );
117 Bu::FString sStr;
118 Bu::List<int> lList;
119 ar >> sStr;
120 ar >> lList;
121 unitTest( sStr == "This is a test string." );
122 unitTest( lList.getSize() == 4 );
123 Bu::List<int>::iterator i = lList.begin();
124 unitTest( *i == 10 ); i++;
125 unitTest( *i == 20 ); i++;
126 unitTest( *i == 30 ); i++;
127 unitTest( *i == 40 );
128 ar.close();
129 }
130}
diff --git a/src/unit/array.cpp b/src/unit/array.cpp
deleted file mode 100644
index f7dc0ae..0000000
--- a/src/unit/array.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
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#include "bu/unitsuite.h"
9#include "bu/hash.h"
10#include "bu/array.h"
11
12class Unit : public Bu::UnitSuite
13{
14public:
15 Unit()
16 {
17 setName("Array");
18 addTest( Unit::general );
19 addTest( Unit::iterate1 );
20 addTest( Unit::iterate2 );
21 addTest( Unit::copy );
22 }
23
24 virtual ~Unit()
25 {
26 }
27
28 void general()
29 {
30 Bu::Array<int> ai;
31
32 ai.append( 5 );
33 ai.append( 10 );
34 unitTest( ai.getSize() == 2 );
35 unitTest( ai.getCapacity() == 10 );
36 unitTest( ai[0] == 5 );
37 unitTest( ai[1] == 10 );
38 }
39
40 void iterate1()
41 {
42 Bu::Array<int> ai;
43 for( int j = 0; j < 10; j++ )
44 ai.append( j );
45
46 int j = 0;
47 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
48 unitTest( (*i) == j++ );
49
50 const Bu::Array<int> &ci = ai;
51 j = 0;
52 for( Bu::Array<int>::const_iterator i = ci.begin(); i != ci.end(); i++ )
53 unitTest( (*i) == j++ );
54 }
55
56 void iterate2()
57 {
58 Bu::Array<int> ai;
59 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
60 unitFailed("Empty lists shouldn't be iterated through.");
61 }
62
63 void copy()
64 {
65 typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
66 typedef Bu::Array<StrHash> StrHashArray;
67
68 StrHash h1;
69 h1["Hi"] = "Yo";
70 h1["Bye"] = "Later";
71
72 StrHash h2;
73 h2["Test"] = "Bloop";
74 h2["Foo"] = "ooF";
75
76 StrHashArray a1;
77 a1.append( h1 );
78 a1.append( h2 );
79
80 StrHashArray a2(a1);
81
82 unitTest( a2[0].get("Hi") == "Yo" );
83 unitTest( a2[0].get("Bye") == "Later" );
84 unitTest( a2[1].get("Test") == "Bloop" );
85 unitTest( a2[1].get("Foo") == "ooF" );
86
87 StrHashArray a3;
88 a3 = a1;
89
90 unitTest( a3[0].get("Hi") == "Yo" );
91 unitTest( a3[0].get("Bye") == "Later" );
92 unitTest( a3[1].get("Test") == "Bloop" );
93 unitTest( a3[1].get("Foo") == "ooF" );
94 }
95};
96
97int main( int argc, char *argv[] )
98{
99 return Unit().run( argc, argv );
100}
101
diff --git a/src/unit/array.unit b/src/unit/array.unit
new file mode 100644
index 0000000..d5fc573
--- /dev/null
+++ b/src/unit/array.unit
@@ -0,0 +1,80 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/hash.h"
10#include "bu/array.h"
11
12{=Init}
13
14{%general}
15{
16 Bu::Array<int> ai;
17
18 ai.append( 5 );
19 ai.append( 10 );
20 unitTest( ai.getSize() == 2 );
21 unitTest( ai.getCapacity() == 10 );
22 unitTest( ai[0] == 5 );
23 unitTest( ai[1] == 10 );
24}
25
26{%iterate1}
27{
28 Bu::Array<int> ai;
29 for( int j = 0; j < 10; j++ )
30 ai.append( j );
31
32 int j = 0;
33 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
34 unitTest( (*i) == j++ );
35
36 const Bu::Array<int> &ci = ai;
37 j = 0;
38 for( Bu::Array<int>::const_iterator i = ci.begin(); i != ci.end(); i++ )
39 unitTest( (*i) == j++ );
40}
41
42{%iterate2}
43{
44 Bu::Array<int> ai;
45 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
46 unitFailed("Empty lists shouldn't be iterated through.");
47}
48
49{%copy}
50{
51 typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
52 typedef Bu::Array<StrHash> StrHashArray;
53
54 StrHash h1;
55 h1["Hi"] = "Yo";
56 h1["Bye"] = "Later";
57
58 StrHash h2;
59 h2["Test"] = "Bloop";
60 h2["Foo"] = "ooF";
61
62 StrHashArray a1;
63 a1.append( h1 );
64 a1.append( h2 );
65
66 StrHashArray a2(a1);
67
68 unitTest( a2[0].get("Hi") == "Yo" );
69 unitTest( a2[0].get("Bye") == "Later" );
70 unitTest( a2[1].get("Test") == "Bloop" );
71 unitTest( a2[1].get("Foo") == "ooF" );
72
73 StrHashArray a3;
74 a3 = a1;
75
76 unitTest( a3[0].get("Hi") == "Yo" );
77 unitTest( a3[0].get("Bye") == "Later" );
78 unitTest( a3[1].get("Test") == "Bloop" );
79 unitTest( a3[1].get("Foo") == "ooF" );
80}
diff --git a/src/unit/file.cpp b/src/unit/file.cpp
deleted file mode 100644
index cc19fac..0000000
--- a/src/unit/file.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
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#include "bu/unitsuite.h"
9#include "bu/file.h"
10
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15class Unit : public Bu::UnitSuite
16{
17public:
18 Unit()
19 {
20 setName("File");
21 addTest( Unit::writeFull );
22 addTest( Unit::readBlocks );
23 addTest( Unit::readError1 );
24 addTest( Unit::readError2 );
25 }
26
27 virtual ~Unit() { }
28
29 //
30 // Tests go here
31 //
32 void writeFull()
33 {
34 Bu::File sf("testfile1", Bu::File::Write );
35 for( int c = 0; c < 256; c++ )
36 {
37 unsigned char ch = (unsigned char)c;
38 sf.write( &ch, 1 );
39 unitTest( sf.tell() == c+1 );
40 }
41 //unitTest( sf.canRead() == false );
42 //unitTest( sf.canWrite() == true );
43 //unitTest( sf.canSeek() == true );
44 sf.close();
45 struct stat sdat;
46 stat("testfile1", &sdat );
47 unitTest( sdat.st_size == 256 );
48 }
49
50 void readBlocks()
51 {
52 Bu::File sf("testfile1", Bu::File::Read );
53 unsigned char buf[50];
54 size_t total = 0;
55 for(;;)
56 {
57 size_t s = sf.read( buf, 50 );
58 for( size_t c = 0; c < s; c++ )
59 {
60 unitTest( buf[c] == (unsigned char)(c+total) );
61 }
62 total += s;
63 if( s < 50 )
64 {
65 unitTest( total == 256 );
66 unitTest( sf.isEOS() == true );
67 break;
68 }
69 }
70 sf.close();
71 }
72
73 void readError1()
74 {
75 try
76 {
77 Bu::File sf("doesn'texist", Bu::File::Read );
78 unitFailed("No exception thrown");
79 }
80 catch( Bu::FileException &e )
81 {
82 return;
83 }
84 }
85
86 void readError2()
87 {
88 Bu::File sf("testfile1", Bu::File::Read );
89 char buf[256];
90 int r = sf.read( buf, 256 );
91 unitTest( r == 256 );
92 // You have to read past the end to set the EOS flag.
93 unitTest( sf.isEOS() == false );
94 try
95 {
96 if( sf.read( buf, 5 ) > 0 )
97 {
98 unitFailed("Non-zero read result");
99 }
100 else
101 {
102 sf.close();
103 }
104 }
105 catch( Bu::FileException &e )
106 {
107 sf.close();
108 return;
109 }
110 }
111};
112
113int main( int argc, char *argv[] )
114{
115 return Unit().run( argc, argv );
116}
117
diff --git a/src/unit/file.unit b/src/unit/file.unit
new file mode 100644
index 0000000..e6320ad
--- /dev/null
+++ b/src/unit/file.unit
@@ -0,0 +1,95 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/file.h"
10
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15{=Init}
16
17{%writeFull}
18{
19 Bu::File sf("testfile1", Bu::File::Write );
20 for( int c = 0; c < 256; c++ )
21 {
22 unsigned char ch = (unsigned char)c;
23 sf.write( &ch, 1 );
24 unitTest( sf.tell() == c+1 );
25 }
26 //unitTest( sf.canRead() == false );
27 //unitTest( sf.canWrite() == true );
28 //unitTest( sf.canSeek() == true );
29 sf.close();
30 struct stat sdat;
31 stat("testfile1", &sdat );
32 unitTest( sdat.st_size == 256 );
33}
34
35{%readBlocks}
36{
37 Bu::File sf("testfile1", Bu::File::Read );
38 unsigned char buf[50];
39 size_t total = 0;
40 for(;;)
41 {
42 size_t s = sf.read( buf, 50 );
43 for( size_t c = 0; c < s; c++ )
44 {
45 unitTest( buf[c] == (unsigned char)(c+total) );
46 }
47 total += s;
48 if( s < 50 )
49 {
50 unitTest( total == 256 );
51 unitTest( sf.isEOS() == true );
52 break;
53 }
54 }
55 sf.close();
56}
57
58{%readError1}
59{
60 try
61 {
62 Bu::File sf("doesn'texist", Bu::File::Read );
63 unitFailed("No exception thrown");
64 }
65 catch( Bu::FileException &e )
66 {
67 return;
68 }
69}
70
71{%readError2}
72{
73 Bu::File sf("testfile1", Bu::File::Read );
74 char buf[256];
75 int r = sf.read( buf, 256 );
76 unitTest( r == 256 );
77 // You have to read past the end to set the EOS flag.
78 unitTest( sf.isEOS() == false );
79 try
80 {
81 if( sf.read( buf, 5 ) > 0 )
82 {
83 unitFailed("Non-zero read result");
84 }
85 else
86 {
87 sf.close();
88 }
89 }
90 catch( Bu::FileException &e )
91 {
92 sf.close();
93 return;
94 }
95}
diff --git a/src/unit/fstring.cpp b/src/unit/fstring.cpp
deleted file mode 100644
index 9430a83..0000000
--- a/src/unit/fstring.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
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#include "bu/fstring.h"
9#include "bu/unitsuite.h"
10
11#include <dirent.h>
12
13class Unit : public Bu::UnitSuite
14{
15public:
16 Unit()
17 {
18 setName("FString");
19 addTest( Unit::compare1 );
20 addTest( Unit::compare2 );
21 addTest( Unit::appendSingle );
22 addTest( Unit::shared1 );
23 addTest( Unit::insert );
24 addTest( Unit::remove );
25 addTest( Unit::add1 );
26 addTest( Unit::add2 );
27 addTest( Unit::add3 );
28 addTest( Unit::add4 );
29 addTest( Unit::add5 );
30 addTest( Unit::add6 );
31 addTest( Unit::subStr1 );
32 }
33
34 virtual ~Unit()
35 {
36 }
37
38 void compare1()
39 {
40 Bu::FString b("Bob");
41 unitTest( !(b == "Bobo") );
42 unitTest( b == "Bob" );
43 }
44
45 void compare2()
46 {
47 Bu::FString b("Bobo");
48 unitTest( !(b == "Bob") );
49 unitTest( b == "Bobo" );
50 }
51
52 void appendSingle()
53 {
54 Bu::FString b;
55 for( char l = 'a'; l < 'g'; l++ )
56 b += l;
57 unitTest( b == "abcdef" );
58 unitTest( strcmp( b.getStr(), "abcdef" ) == 0 );
59 }
60
61 void shared1()
62 {
63 Bu::FString a("Hey there");
64 Bu::FString b( a );
65 unitTest( a.getStr() == b.getStr() );
66 b += " guy";
67 unitTest( a.getStr() != b.getStr() );
68 a = b;
69 unitTest( a.getStr() == b.getStr() );
70 }
71
72 void insert()
73 {
74 Bu::FString a("abcd");
75 a.insert( 2, "-!-", 3 );
76 unitTest( a == "ab-!-cd" );
77
78 a.insert( 0, "!!", 2 );
79 unitTest( a == "!!ab-!-cd" );
80
81 a.insert( -10, "789", 3 );
82 unitTest( a == "789!!ab-!-cd" );
83
84 a.insert( 12, "89", 2 );
85 unitTest( a == "789!!ab-!-cd89" );
86
87 a.insert( 1203, "12", 2 );
88 unitTest( a == "789!!ab-!-cd8912" );
89 }
90
91 void remove()
92 {
93 Bu::FString a("abHEYcd");
94 a.remove( 2, 3 );
95 unitTest( a == "abcd" );
96 a.remove( 2, 5 );
97 unitTest( a == "ab" );
98 a += "cdefghijklmnop";
99 a.remove( 5, 1 );
100 unitTest( a = "abcdeghijklmnop" );
101 }
102
103 void add1()
104 {
105 Bu::FString a("hi there");
106 Bu::FString b(", yeah!");
107 Bu::FString c = a + b;
108
109 unitTest( c == "hi there, yeah!" );
110 }
111
112 void add2()
113 {
114 Bu::FString a("hi there");
115 Bu::FString c = a + ", yeah!";
116
117 unitTest( c == "hi there, yeah!" );
118 }
119
120 void add3()
121 {
122 Bu::FString a("hi there");
123 Bu::FString b(", yeah!");
124 Bu::FString c = a + ", Mr. Man" + b;
125
126 unitTest( c == "hi there, Mr. Man, yeah!" );
127 }
128
129 void add4()
130 {
131 Bu::FString b(", yeah!");
132 Bu::FString c = "hi there" + b;
133
134 unitTest( c == "hi there, yeah!" );
135 }
136
137 void add5()
138 {
139 Bu::FString b;
140 Bu::FString c = "sup?";
141 b += "hey, " + c;
142
143 unitTest( b == "hey, sup?" );
144 }
145
146 void add6()
147 {
148 Bu::FString a("Hello");
149 char b[256] = {"Dude"};
150 Bu::FString c = a + "/" + b;
151
152 unitTest( c == "Hello/Dude" );
153 }
154
155 void subStr1()
156 {
157 Bu::FString a("abcdefghijklmnop");
158 unitTest( a.getSubStr( 5, 3 ) == "fgh" );
159 unitTest( a.getSubStr( 10 ) == "klmnop" );
160 unitTest( a.getSubStr( 40 ) == "" );
161 unitTest( a.getSubStr( -10 ) == "abcdefghijklmnop" );
162 unitTest( a.getSubStr( -15, 4 ) == "abcd" );
163 }
164};
165
166int main( int argc, char *argv[] )
167{
168 return Unit().run( argc, argv );
169}
170
diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit
new file mode 100644
index 0000000..93065fe
--- /dev/null
+++ b/src/unit/fstring.unit
@@ -0,0 +1,140 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/fstring.h"
10
11#include <dirent.h>
12
13{=Init}
14
15{%compare1}
16{
17 Bu::FString b("Bob");
18 unitTest( !(b == "Bobo") );
19 unitTest( b == "Bob" );
20}
21
22{%compare2}
23{
24 Bu::FString b("Bobo");
25 unitTest( !(b == "Bob") );
26 unitTest( b == "Bobo" );
27}
28
29{%appendSingle}
30{
31 Bu::FString b;
32 for( char l = 'a'; l < 'g'; l++ )
33 b += l;
34 unitTest( b == "abcdef" );
35 unitTest( strcmp( b.getStr(), "abcdef" ) == 0 );
36}
37
38{%shared1}
39{
40 Bu::FString a("Hey there");
41 Bu::FString b( a );
42 unitTest( a.getStr() == b.getStr() );
43 b += " guy";
44 unitTest( a.getStr() != b.getStr() );
45 a = b;
46 unitTest( a.getStr() == b.getStr() );
47}
48
49{%insert}
50{
51 Bu::FString a("abcd");
52 a.insert( 2, "-!-", 3 );
53 unitTest( a == "ab-!-cd" );
54
55 a.insert( 0, "!!", 2 );
56 unitTest( a == "!!ab-!-cd" );
57
58 a.insert( -10, "789", 3 );
59 unitTest( a == "789!!ab-!-cd" );
60
61 a.insert( 12, "89", 2 );
62 unitTest( a == "789!!ab-!-cd89" );
63
64 a.insert( 1203, "12", 2 );
65 unitTest( a == "789!!ab-!-cd8912" );
66}
67
68{%remove}
69{
70 Bu::FString a("abHEYcd");
71 a.remove( 2, 3 );
72 unitTest( a == "abcd" );
73 a.remove( 2, 5 );
74 unitTest( a == "ab" );
75 a += "cdefghijklmnop";
76 a.remove( 5, 1 );
77 unitTest( a = "abcdeghijklmnop" );
78}
79
80{%add1}
81{
82 Bu::FString a("hi there");
83 Bu::FString b(", yeah!");
84 Bu::FString c = a + b;
85
86 unitTest( c == "hi there, yeah!" );
87}
88
89{%add2}
90{
91 Bu::FString a("hi there");
92 Bu::FString c = a + ", yeah!";
93
94 unitTest( c == "hi there, yeah!" );
95}
96
97{%add3}
98{
99 Bu::FString a("hi there");
100 Bu::FString b(", yeah!");
101 Bu::FString c = a + ", Mr. Man" + b;
102
103 unitTest( c == "hi there, Mr. Man, yeah!" );
104}
105
106{%add4}
107{
108 Bu::FString b(", yeah!");
109 Bu::FString c = "hi there" + b;
110
111 unitTest( c == "hi there, yeah!" );
112}
113
114{%add5}
115{
116 Bu::FString b;
117 Bu::FString c = "sup?";
118 b += "hey, " + c;
119
120 unitTest( b == "hey, sup?" );
121}
122
123{%add6}
124{
125 Bu::FString a("Hello");
126 char b[256] = {"Dude"};
127 Bu::FString c = a + "/" + b;
128
129 unitTest( c == "Hello/Dude" );
130}
131
132{%subStr1}
133{
134 Bu::FString a("abcdefghijklmnop");
135 unitTest( a.getSubStr( 5, 3 ) == "fgh" );
136 unitTest( a.getSubStr( 10 ) == "klmnop" );
137 unitTest( a.getSubStr( 40 ) == "" );
138 unitTest( a.getSubStr( -10 ) == "abcdefghijklmnop" );
139 unitTest( a.getSubStr( -15, 4 ) == "abcd" );
140}
diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp
deleted file mode 100644
index e04a656..0000000
--- a/src/unit/hash.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
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#include "bu/fstring.h"
9#include "bu/hash.h"
10#include "bu/unitsuite.h"
11
12#include <stdio.h>
13
14class Unit : public Bu::UnitSuite
15{
16private:
17 typedef Bu::Hash<Bu::FString, int> StrIntHash;
18 typedef Bu::Hash<Bu::FString, Bu::FString> StrStrHash;
19 typedef Bu::Hash<int, Bu::FString> IntStrHash;
20
21public:
22 Unit()
23 {
24 setName("Hash");
25 addTest( Unit::insert1 );
26 addTest( Unit::insert2 );
27 addTest( Unit::insert3 );
28 addTest( Unit::probe1 );
29 addTest( Unit::erase1 );
30 }
31
32 virtual ~Unit()
33 {
34 }
35
36 void probe1()
37 {
38 StrIntHash h;
39 char buf[20];
40 for(int i=1;i<10000;i++)
41 {
42 sprintf(buf,"%d",i);
43 Bu::FString sTmp(buf);
44 h[sTmp] = i;
45 unitTest( h.has(sTmp) );
46 }
47 }
48
49 void insert1()
50 {
51 StrIntHash h;
52 h["Hi"] = 42;
53 unitTest( h["Hi"] == 42 );
54 }
55
56 void insert2()
57 {
58 StrStrHash h;
59 h["Hi"] = "Yo";
60 h["Bye"] = "Later";
61 unitTest( h["Hi"].getValue() == "Yo" );
62
63 StrStrHash h2(h);
64 unitTest( h2["Hi"].getValue() = "Yo" );
65 unitTest( h2["Bye"].getValue() = "Later" );
66
67 StrStrHash h3;
68 h3 = h;
69 unitTest( h3["Hi"].getValue() = "Yo" );
70 unitTest( h3["Bye"].getValue() = "Later" );
71 }
72
73 void insert3()
74 {
75 IntStrHash h;
76
77 for( unsigned int i=1; i<50; i++ )
78 {
79 h[i] = "testing";
80 unitTest( h.getSize() == i );
81 }
82 }
83
84 void erase1()
85 {
86 StrIntHash h;
87 h.insert("Number 1", 1 );
88 h.insert("Number 2", 2 );
89 h.insert("Number 3", 3 );
90 h.erase("Number 2");
91 h.get("Number 3");
92 try {
93 h.get("Number 2");
94 unitFailed("h.get(\"Number 2\") should have thrown an exception.");
95 } catch( Bu::HashException &e ) { }
96
97 /* printf("\n");
98 for( StrIntHash::iterator i = h.begin(); i != h.end(); i++ )
99 {
100 printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() );
101 } */
102 }
103};
104
105int main( int argc, char *argv[] )
106{
107 return Unit().run( argc, argv );
108}
109
diff --git a/src/unit/hash.unit b/src/unit/hash.unit
new file mode 100644
index 0000000..bd7da61
--- /dev/null
+++ b/src/unit/hash.unit
@@ -0,0 +1,86 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/fstring.h"
10#include "bu/hash.h"
11
12#include <stdio.h>
13
14typedef Bu::Hash<Bu::FString, int> StrIntHash;
15typedef Bu::Hash<Bu::FString, Bu::FString> StrStrHash;
16typedef Bu::Hash<int, Bu::FString> IntStrHash;
17
18{=Init}
19
20{%probe1}
21{
22 StrIntHash h;
23 char buf[20];
24 for(int i=1;i<10000;i++)
25 {
26 sprintf(buf,"%d",i);
27 Bu::FString sTmp(buf);
28 h[sTmp] = i;
29 unitTest( h.has(sTmp) );
30 }
31}
32
33{%insert1}
34{
35 StrIntHash h;
36 h["Hi"] = 42;
37 unitTest( h["Hi"] == 42 );
38}
39
40{%insert2}
41{
42 StrStrHash h;
43 h["Hi"] = "Yo";
44 h["Bye"] = "Later";
45 unitTest( h["Hi"].getValue() == "Yo" );
46
47 StrStrHash h2(h);
48 unitTest( h2["Hi"].getValue() = "Yo" );
49 unitTest( h2["Bye"].getValue() = "Later" );
50
51 StrStrHash h3;
52 h3 = h;
53 unitTest( h3["Hi"].getValue() = "Yo" );
54 unitTest( h3["Bye"].getValue() = "Later" );
55}
56
57{%insert3}
58{
59 IntStrHash h;
60
61 for( unsigned int i=1; i<50; i++ )
62 {
63 h[i] = "testing";
64 unitTest( h.getSize() == i );
65 }
66}
67
68{%erase1}
69{
70 StrIntHash h;
71 h.insert("Number 1", 1 );
72 h.insert("Number 2", 2 );
73 h.insert("Number 3", 3 );
74 h.erase("Number 2");
75 h.get("Number 3");
76 try {
77 h.get("Number 2");
78 unitFailed("h.get(\"Number 2\") should have thrown an exception.");
79 } catch( Bu::HashException &e ) { }
80
81/* printf("\n");
82 for( StrIntHash::iterator i = h.begin(); i != h.end(); i++ )
83 {
84 printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() );
85 } */
86}
diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp
deleted file mode 100644
index dc02aa3..0000000
--- a/src/unit/membuf.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
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#include "bu/unitsuite.h"
9#include "bu/membuf.h"
10
11class Unit : public Bu::UnitSuite
12{
13public:
14 Unit()
15 {
16 setName("MemBuf");
17 addTest( Unit::testWriteRead01 );
18 addTest( Unit::testOverwrite1 );
19 }
20
21 virtual ~Unit()
22 {
23 }
24
25 void testWriteRead01()
26 {
27 Bu::MemBuf mb;
28 unitTest( mb.write("ab", 2 ) == 2 );
29 unitTest( mb.write("cde", 3 ) == 3 );
30 unitTest( mb.write("FG", 2 ) == 2 );
31
32 mb.setPos( 0 );
33
34 char buf[8];
35 buf[7] = '\0';
36 unitTest( mb.read( buf, 7 ) == 7 );
37 unitTest( !strncmp( buf, "abcdeFG", 7 ) );
38 unitTest( mb.read( buf, 7 ) == 0 );
39 mb.seek( -3 );
40 unitTest( mb.read( buf, 7 ) == 3 );
41 unitTest( !strncmp( buf, "eFG", 3 ) );
42 }
43
44 void testOverwrite1()
45 {
46 Bu::MemBuf mb;
47 unitTest( mb.write("0123456789") == 10 );
48 mb.setPos( 4 );
49 unitTest( mb.write("-5-") == 3 );
50 mb.setPos( 9 );
51 mb.write("Hey!!!");
52 unitTest( mb.tell() == 15 );
53 char buf[50];
54 mb.setPos( 0 );
55 buf[mb.read( buf, 50 )] = '\0';
56 unitTest( !strcmp( buf, "0123-5-78Hey!!!" ) );
57 }
58};
59
60int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
diff --git a/src/unit/membuf.unit b/src/unit/membuf.unit
new file mode 100644
index 0000000..aebf36c
--- /dev/null
+++ b/src/unit/membuf.unit
@@ -0,0 +1,45 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/membuf.h"
10
11{=Init}
12
13{%testWriteRead01}
14{
15 Bu::MemBuf mb;
16 unitTest( mb.write("ab", 2 ) == 2 );
17 unitTest( mb.write("cde", 3 ) == 3 );
18 unitTest( mb.write("FG", 2 ) == 2 );
19
20 mb.setPos( 0 );
21
22 char buf[8];
23 buf[7] = '\0';
24 unitTest( mb.read( buf, 7 ) == 7 );
25 unitTest( !strncmp( buf, "abcdeFG", 7 ) );
26 unitTest( mb.read( buf, 7 ) == 0 );
27 mb.seek( -3 );
28 unitTest( mb.read( buf, 7 ) == 3 );
29 unitTest( !strncmp( buf, "eFG", 3 ) );
30}
31
32{%testOverwrite1}
33{
34 Bu::MemBuf mb;
35 unitTest( mb.write("0123456789") == 10 );
36 mb.setPos( 4 );
37 unitTest( mb.write("-5-") == 3 );
38 mb.setPos( 9 );
39 mb.write("Hey!!!");
40 unitTest( mb.tell() == 15 );
41 char buf[50];
42 mb.setPos( 0 );
43 buf[mb.read( buf, 50 )] = '\0';
44 unitTest( !strcmp( buf, "0123-5-78Hey!!!" ) );
45}
diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp
deleted file mode 100644
index e4b3ccc..0000000
--- a/src/unit/taf.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
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#include "bu/unitsuite.h"
9#include "bu/file.h"
10#include "bu/tafreader.h"
11#include "bu/tafwriter.h"
12#include "bu/membuf.h"
13
14#include <string.h>
15#include <unistd.h>
16
17class Unit : public Bu::UnitSuite
18{
19public:
20 Unit()
21 {
22 setName("taf");
23 addTest( Unit::read1 );
24 addTest( Unit::encode1 );
25 addTest( Unit::emptyStr1 );
26 addTest( Unit::incomplete1 );
27 }
28
29 virtual ~Unit()
30 {
31 }
32
33 void read1()
34 {
35#define FN_TMP ("/tmp/tmpXXXXXXXX")
36 Bu::FString sFnTmp(FN_TMP);
37 Bu::File fOut = Bu::File::tempFile( sFnTmp );
38 const char *data =
39"{test: name=\"Bob\"}"
40;
41 fOut.write(data,strlen(data));
42 fOut.close();
43
44 Bu::File fIn(sFnTmp.getStr(), Bu::File::Read );
45 Bu::TafReader tr(fIn);
46
47 Bu::TafGroup *tn = tr.readGroup();
48 unitTest( !strcmp("Bob", tn->getProperty("name").getStr()) );
49 delete tn;
50
51 unlink(sFnTmp.getStr());
52#undef FN_TMP
53 }
54
55 void encode1()
56 {
57 Bu::MemBuf mb;
58 Bu::TafWriter tw( mb );
59
60 Bu::TafGroup g("Test data");
61 Bu::FString sData( 256 );
62 for( int j = 0; j < 256; j++ )
63 sData[j] = (unsigned char)j;
64 g.addChild( new Bu::TafProperty("Encoded", sData) );
65 tw.writeGroup( &g );
66
67 static const char *cmpdata = "{\"Test data\":\n \"Encoded\"=\""
68 "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07"
69 "\\x08\\x09\\x0A\\x0B\\x0C\\x0D\\x0E\\x0F"
70 "\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17"
71 "\\x18\\x19\\x1A\\x1B\\x1C\\x1D\\x1E\\x1F"
72 " !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCD"
73 "EFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghi"
74 "jklmnopqrstuvwxyz{|}~\\x7F"
75 "\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87"
76 "\\x88\\x89\\x8A\\x8B\\x8C\\x8D\\x8E\\x8F"
77 "\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97"
78 "\\x98\\x99\\x9A\\x9B\\x9C\\x9D\\x9E\\x9F"
79 "\\xA0\\xA1\\xA2\\xA3\\xA4\\xA5\\xA6\\xA7"
80 "\\xA8\\xA9\\xAA\\xAB\\xAC\\xAD\\xAE\\xAF"
81 "\\xB0\\xB1\\xB2\\xB3\\xB4\\xB5\\xB6\\xB7"
82 "\\xB8\\xB9\\xBA\\xBB\\xBC\\xBD\\xBE\\xBF"
83 "\\xC0\\xC1\\xC2\\xC3\\xC4\\xC5\\xC6\\xC7"
84 "\\xC8\\xC9\\xCA\\xCB\\xCC\\xCD\\xCE\\xCF"
85 "\\xD0\\xD1\\xD2\\xD3\\xD4\\xD5\\xD6\\xD7"
86 "\\xD8\\xD9\\xDA\\xDB\\xDC\\xDD\\xDE\\xDF"
87 "\\xE0\\xE1\\xE2\\xE3\\xE4\\xE5\\xE6\\xE7"
88 "\\xE8\\xE9\\xEA\\xEB\\xEC\\xED\\xEE\\xEF"
89 "\\xF0\\xF1\\xF2\\xF3\\xF4\\xF5\\xF6\\xF7"
90 "\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\"\n}\n";
91 unitTest( mb.getString() == cmpdata );
92 mb.setPos( 0 );
93 Bu::TafReader tr( mb );
94 Bu::TafGroup *rg = tr.readGroup();
95 unitTest( rg->getProperty("Encoded") == sData );
96 delete rg;
97 }
98
99 void emptyStr1()
100 {
101 Bu::MemBuf mb;
102 Bu::TafWriter tw( mb );
103
104 Bu::TafGroup g("Test Group");
105 Bu::FString sVal;
106 g.addChild( new Bu::TafProperty("Lame", sVal) );
107 tw.writeGroup( &g );
108
109 unitTest(
110 mb.getString() == "{\"Test Group\":\n \"Lame\"=\"\"\n}\n" );
111 }
112
113 void incomplete1()
114 {
115 try
116 {
117 Bu::MemBuf mb("{Lame: \"Hello=\"");
118 Bu::TafReader tr( mb );
119 delete tr.readGroup();
120 unitFailed("Should have thrown an exception, didn't.");
121 }
122 catch( Bu::TafException &e )
123 {
124 // Woot
125 }
126 }
127};
128
129int main( int argc, char *argv[] )
130{
131 return Unit().run( argc, argv );
132}
133
diff --git a/src/unit/taf.unit b/src/unit/taf.unit
new file mode 100644
index 0000000..5588c85
--- /dev/null
+++ b/src/unit/taf.unit
@@ -0,0 +1,112 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/file.h"
10#include "bu/tafreader.h"
11#include "bu/tafwriter.h"
12#include "bu/membuf.h"
13
14#include <string.h>
15#include <unistd.h>
16
17{=Init}
18
19{%read1}
20{
21#define FN_TMP ("/tmp/tmpXXXXXXXX")
22 Bu::FString sFnTmp(FN_TMP);
23 Bu::File fOut = Bu::File::tempFile( sFnTmp );
24 const char *data =
25"{test: name=\"Bob\"}"
26;
27 fOut.write(data,strlen(data));
28 fOut.close();
29
30 Bu::File fIn(sFnTmp.getStr(), Bu::File::Read );
31 Bu::TafReader tr(fIn);
32
33 Bu::TafGroup *tn = tr.readGroup();
34 unitTest( !strcmp("Bob", tn->getProperty("name").getStr()) );
35 delete tn;
36
37 unlink(sFnTmp.getStr());
38#undef FN_TMP
39}
40
41{%encode1}
42{
43 Bu::MemBuf mb;
44 Bu::TafWriter tw( mb );
45
46 Bu::TafGroup g("Test data");
47 Bu::FString sData( 256 );
48 for( int j = 0; j < 256; j++ )
49 sData[j] = (unsigned char)j;
50 g.addChild( new Bu::TafProperty("Encoded", sData) );
51 tw.writeGroup( &g );
52
53 static const char *cmpdata = "{\"Test data\":\n \"Encoded\"=\""
54 "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07"
55 "\\x08\\x09\\x0A\\x0B\\x0C\\x0D\\x0E\\x0F"
56 "\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17"
57 "\\x18\\x19\\x1A\\x1B\\x1C\\x1D\\x1E\\x1F"
58 " !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCD"
59 "EFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghi"
60 "jklmnopqrstuvwxyz{|}~\\x7F"
61 "\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87"
62 "\\x88\\x89\\x8A\\x8B\\x8C\\x8D\\x8E\\x8F"
63 "\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97"
64 "\\x98\\x99\\x9A\\x9B\\x9C\\x9D\\x9E\\x9F"
65 "\\xA0\\xA1\\xA2\\xA3\\xA4\\xA5\\xA6\\xA7"
66 "\\xA8\\xA9\\xAA\\xAB\\xAC\\xAD\\xAE\\xAF"
67 "\\xB0\\xB1\\xB2\\xB3\\xB4\\xB5\\xB6\\xB7"
68 "\\xB8\\xB9\\xBA\\xBB\\xBC\\xBD\\xBE\\xBF"
69 "\\xC0\\xC1\\xC2\\xC3\\xC4\\xC5\\xC6\\xC7"
70 "\\xC8\\xC9\\xCA\\xCB\\xCC\\xCD\\xCE\\xCF"
71 "\\xD0\\xD1\\xD2\\xD3\\xD4\\xD5\\xD6\\xD7"
72 "\\xD8\\xD9\\xDA\\xDB\\xDC\\xDD\\xDE\\xDF"
73 "\\xE0\\xE1\\xE2\\xE3\\xE4\\xE5\\xE6\\xE7"
74 "\\xE8\\xE9\\xEA\\xEB\\xEC\\xED\\xEE\\xEF"
75 "\\xF0\\xF1\\xF2\\xF3\\xF4\\xF5\\xF6\\xF7"
76 "\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\"\n}\n";
77 unitTest( mb.getString() == cmpdata );
78 mb.setPos( 0 );
79 Bu::TafReader tr( mb );
80 Bu::TafGroup *rg = tr.readGroup();
81 unitTest( rg->getProperty("Encoded") == sData );
82 delete rg;
83}
84
85{%emptyStr1}
86{
87 Bu::MemBuf mb;
88 Bu::TafWriter tw( mb );
89
90 Bu::TafGroup g("Test Group");
91 Bu::FString sVal;
92 g.addChild( new Bu::TafProperty("Lame", sVal) );
93 tw.writeGroup( &g );
94
95 unitTest(
96 mb.getString() == "{\"Test Group\":\n \"Lame\"=\"\"\n}\n" );
97}
98
99{%incomplete1}
100{
101 try
102 {
103 Bu::MemBuf mb("{Lame: \"Hello=\"");
104 Bu::TafReader tr( mb );
105 delete tr.readGroup();
106 unitFailed("Should have thrown an exception, didn't.");
107 }
108 catch( Bu::TafException &e )
109 {
110 // Woot
111 }
112}
diff --git a/src/unit/xml.cpp b/src/unit/xml.cpp
deleted file mode 100644
index e845cc1..0000000
--- a/src/unit/xml.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
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#include "bu/fstring.h"
9#include "bu/unitsuite.h"
10#include "bu/xmlreader.h"
11#include "bu/membuf.h"
12
13class Unit : public Bu::UnitSuite
14{
15public:
16 Unit()
17 {
18 setName("Xml");
19 addTest( Unit::declaration );
20 }
21
22 virtual ~Unit()
23 {
24 }
25
26 void declaration()
27 {
28 Bu::FString sXml("<?xml ?> <hi />");
29 Bu::MemBuf buf( sXml );
30 Bu::XmlReader xr( buf );
31 }
32
33};
34
35int main( int argc, char *argv[] )
36{
37 return Unit().run( argc, argv );
38}
39
diff --git a/src/unit/xml.unit b/src/unit/xml.unit
new file mode 100644
index 0000000..738ad66
--- /dev/null
+++ b/src/unit/xml.unit
@@ -0,0 +1,20 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/fstring.h"
10#include "bu/xmlreader.h"
11#include "bu/membuf.h"
12
13{=Init}
14
15{%declaration}
16{
17 Bu::FString sXml("<?xml ?> <hi />");
18 Bu::MemBuf buf( sXml );
19 Bu::XmlReader xr( buf );
20}
diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp
index 0008721..b61baa5 100644
--- a/src/unitsuite.cpp
+++ b/src/unitsuite.cpp
@@ -72,7 +72,7 @@ int Bu::UnitSuite::run( int /*argc*/, char * /*argv */ [] )
72 return 0; 72 return 0;
73} 73}
74 74
75void Bu::UnitSuite::add( Test fTest, Bu::FString sName ) 75void Bu::UnitSuite::add( Test fTest, const Bu::FString &sName, Expect e )
76{ 76{
77 TestInfo ti; 77 TestInfo ti;
78 ti.sName = sName; 78 ti.sName = sName;
diff --git a/src/unitsuite.h b/src/unitsuite.h
index d27e322..d75211a 100644
--- a/src/unitsuite.h
+++ b/src/unitsuite.h
@@ -81,9 +81,15 @@ namespace Bu
81 { 81 {
82 optStopOnError = 0x000001 82 optStopOnError = 0x000001
83 }; 83 };
84
85 enum Expect
86 {
87 expectPass,
88 expectFail
89 };
84 90
85 protected: 91 protected:
86 void add( Test fTest, Bu::FString sName ); 92 void add( Test fTest, const Bu::FString &sName, Expect e=expectPass );
87 void setName( const FString &sName ); 93 void setName( const FString &sName );
88 94
89 private: 95 private: