diff options
-rw-r--r-- | build.conf | 1 | ||||
-rw-r--r-- | src/fstring.h | 239 | ||||
-rw-r--r-- | src/tests/fstring.cpp | 28 |
3 files changed, 260 insertions, 8 deletions
@@ -4,6 +4,7 @@ default action: check "libbu++.a" | |||
4 | "clean" action: clean targets() | 4 | "clean" action: clean targets() |
5 | "tests" action: check targets() filter regexp("^tests/.*$") | 5 | "tests" action: check targets() filter regexp("^tests/.*$") |
6 | "all" action: check targets() | 6 | "all" action: check targets() |
7 | "fstring" action: check "tests/fstring" | ||
7 | 8 | ||
8 | set "CXXFLAGS" += "-ggdb -Wall" | 9 | set "CXXFLAGS" += "-ggdb -Wall" |
9 | 10 | ||
diff --git a/src/fstring.h b/src/fstring.h index 2eaa4ba..287641f 100644 --- a/src/fstring.h +++ b/src/fstring.h | |||
@@ -4,28 +4,251 @@ | |||
4 | #include <stdint.h> | 4 | #include <stdint.h> |
5 | #include <memory> | 5 | #include <memory> |
6 | 6 | ||
7 | template< typename chr=char > | ||
8 | struct FStringChunk | ||
9 | { | ||
10 | long nLength; | ||
11 | chr *pData; | ||
12 | FStringChunk *pNext; | ||
13 | }; | ||
14 | |||
7 | /** | 15 | /** |
8 | * | 16 | * |
9 | */ | 17 | */ |
10 | template< typename chr, typename chralloc = std::allocator<chr> > | 18 | template< typename chr=char, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > |
11 | class FString | 19 | class FBasicString |
12 | { | 20 | { |
21 | private: | ||
22 | typedef struct FStringChunk<chr> Chunk; | ||
23 | |||
13 | public: | 24 | public: |
14 | FString() : | 25 | FBasicString() : |
15 | pData( NULL ), | 26 | nLength( 0 ), |
16 | pnRefs( NULL ) | 27 | pnRefs( NULL ), |
28 | pFirst( NULL ), | ||
29 | pLast( NULL ) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | FBasicString( const chr *pData ) : | ||
34 | nLength( 0 ), | ||
35 | pnRefs( NULL ), | ||
36 | pFirst( NULL ), | ||
37 | pLast( NULL ) | ||
38 | { | ||
39 | append( pData ); | ||
40 | } | ||
41 | |||
42 | FBasicString( const chr *pData, long nLength ) : | ||
43 | nLength( 0 ), | ||
44 | pnRefs( NULL ), | ||
45 | pFirst( NULL ), | ||
46 | pLast( NULL ) | ||
47 | { | ||
48 | append( pData, nLength ); | ||
49 | } | ||
50 | |||
51 | virtual ~FBasicString() | ||
52 | { | ||
53 | } | ||
54 | |||
55 | void append( const chr *pData ) | ||
56 | { | ||
57 | long nLen; | ||
58 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); | ||
59 | |||
60 | Chunk *pNew = newChunk( nLen ); | ||
61 | memcpy( pNew->pData, pData, nLen * sizeof(chr) ); | ||
62 | |||
63 | appendChunk( pNew ); | ||
64 | } | ||
65 | |||
66 | void append( const chr *pData, long nLen ) | ||
67 | { | ||
68 | Chunk *pNew = newChunk( nLen ); | ||
69 | |||
70 | memcpy( pNew->pData, pData, nLen * sizeof(chr) ); | ||
71 | |||
72 | appendChunk( pNew ); | ||
73 | } | ||
74 | |||
75 | void prepend( const chr *pData ) | ||
76 | { | ||
77 | long nLen; | ||
78 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); | ||
79 | |||
80 | Chunk *pNew = newChunk( nLen ); | ||
81 | memcpy( pNew->pData, pData, nLen * sizeof(chr) ); | ||
82 | |||
83 | prependChunk( pNew ); | ||
84 | } | ||
85 | |||
86 | void prepend( const chr *pData, long nLen ) | ||
87 | { | ||
88 | Chunk *pNew = newChunk( nLen ); | ||
89 | |||
90 | memcpy( pNew->pData, pData, nLen * sizeof(chr) ); | ||
91 | |||
92 | prependChunk( pNew ); | ||
93 | } | ||
94 | |||
95 | void clear() | ||
96 | { | ||
97 | if( pFirst == NULL ) | ||
98 | return; | ||
99 | |||
100 | Chunk *i = pFirst; | ||
101 | for(;;) | ||
102 | { | ||
103 | Chunk *n = i->pNext; | ||
104 | aChr.deallocate( i->pData, i->nLength+1 ); | ||
105 | aChunk.deallocate( i, 1 ); | ||
106 | if( n == NULL ) | ||
107 | break; | ||
108 | i = n; | ||
109 | } | ||
110 | pFirst = pLast = NULL; | ||
111 | nLength = 0; | ||
112 | } | ||
113 | |||
114 | chr *c_str() | ||
115 | { | ||
116 | if( pFirst == NULL ) | ||
117 | return NULL; | ||
118 | |||
119 | flatten(); | ||
120 | return pFirst->pData; | ||
121 | } | ||
122 | |||
123 | FBasicString<chr, chralloc, chunkalloc> &operator +=( const chr *pData ) | ||
17 | { | 124 | { |
125 | append( pData ); | ||
126 | |||
127 | return (*this); | ||
18 | } | 128 | } |
19 | 129 | ||
20 | virtual ~FString() | 130 | FBasicString<chr, chralloc, chunkalloc> &operator =( const chr *pData ) |
21 | { | 131 | { |
132 | clear(); | ||
133 | append( pData ); | ||
134 | |||
135 | return (*this); | ||
136 | } | ||
137 | |||
138 | bool operator ==( const chr *pData ) | ||
139 | { | ||
140 | if( pFirst == NULL ) { | ||
141 | if( pData == NULL ) | ||
142 | return true; | ||
143 | return false; | ||
144 | } | ||
145 | |||
146 | flatten(); | ||
147 | const chr *a = pData; | ||
148 | chr *b = pFirst->pData; | ||
149 | for( ; *a!=(chr)0; a++, b++ ) | ||
150 | { | ||
151 | if( *a != *b ) | ||
152 | return false; | ||
153 | } | ||
154 | |||
155 | return true; | ||
156 | } | ||
157 | |||
158 | bool operator !=(const chr *pData ) | ||
159 | { | ||
160 | return !(*this == pData); | ||
161 | } | ||
162 | |||
163 | |||
164 | |||
165 | private: | ||
166 | void flatten() | ||
167 | { | ||
168 | if( isFlat() ) | ||
169 | return; | ||
170 | |||
171 | if( pFirst == NULL ) | ||
172 | return; | ||
173 | |||
174 | Chunk *pNew = newChunk( nLength ); | ||
175 | chr *pos = pNew->pData; | ||
176 | Chunk *i = pFirst; | ||
177 | for(;;) | ||
178 | { | ||
179 | memcpy( pos, i->pData, i->nLength*sizeof(chr) ); | ||
180 | pos += i->nLength; | ||
181 | i = i->pNext; | ||
182 | if( i == NULL ) | ||
183 | break; | ||
184 | } | ||
185 | clear(); | ||
186 | |||
187 | appendChunk( pNew ); | ||
188 | } | ||
189 | |||
190 | bool isFlat() | ||
191 | { | ||
192 | return (pFirst == pLast); | ||
193 | } | ||
194 | |||
195 | bool isShared() | ||
196 | { | ||
197 | return (pnRefs != NULL); | ||
198 | } | ||
199 | |||
200 | Chunk *newChunk() | ||
201 | { | ||
202 | Chunk *pNew = aChunk.allocate( 1 ); | ||
203 | pNew->pNext = NULL; | ||
204 | return pNew; | ||
205 | } | ||
206 | |||
207 | Chunk *newChunk( long nLen ) | ||
208 | { | ||
209 | Chunk *pNew = aChunk.allocate( 1 ); | ||
210 | pNew->pNext = NULL; | ||
211 | pNew->nLength = nLen; | ||
212 | pNew->pData = aChr.allocate( nLen+1 ); | ||
213 | return pNew; | ||
214 | } | ||
215 | |||
216 | void appendChunk( Chunk *pNewChunk ) | ||
217 | { | ||
218 | if( pFirst == NULL ) | ||
219 | pLast = pFirst = pNewChunk; | ||
220 | else | ||
221 | { | ||
222 | pLast->pNext = pNewChunk; | ||
223 | pLast = pNewChunk; | ||
224 | } | ||
225 | |||
226 | nLength += pNewChunk->nLength; | ||
227 | } | ||
228 | |||
229 | void prependChunk( Chunk *pNewChunk ) | ||
230 | { | ||
231 | if( pFirst == NULL ) | ||
232 | pLast = pFirst = pNewChunk; | ||
233 | else | ||
234 | { | ||
235 | pNewChunk->pNext = pFirst; | ||
236 | pFirst = pNewChunk; | ||
237 | } | ||
238 | |||
239 | nLength += pNewChunk->nLength; | ||
22 | } | 240 | } |
23 | 241 | ||
24 | private: | 242 | private: |
25 | long nLength; | 243 | long nLength; |
26 | chr *pData; | ||
27 | uint32_t *pnRefs; | 244 | uint32_t *pnRefs; |
28 | chralloc aChars; | 245 | Chunk *pFirst; |
246 | Chunk *pLast; | ||
247 | |||
248 | chralloc aChr; | ||
249 | chunkalloc aChunk; | ||
29 | }; | 250 | }; |
30 | 251 | ||
252 | typedef FBasicString<char> FString; | ||
253 | |||
31 | #endif | 254 | #endif |
diff --git a/src/tests/fstring.cpp b/src/tests/fstring.cpp new file mode 100644 index 0000000..26905ac --- /dev/null +++ b/src/tests/fstring.cpp | |||
@@ -0,0 +1,28 @@ | |||
1 | #include "fstring.h" | ||
2 | |||
3 | int main( int argc, char *argv ) | ||
4 | { | ||
5 | FString str("[] this won't be in there", 3); | ||
6 | |||
7 | str.append("Hello"); | ||
8 | str.append(" th"); | ||
9 | str.append("ere."); | ||
10 | |||
11 | if( str == "[] Hello there." ) | ||
12 | printf("1) check\n"); | ||
13 | |||
14 | if( str != "[] Hello there. " ) | ||
15 | printf("2) check\n"); | ||
16 | |||
17 | if( str != "[] Hello there." ) | ||
18 | printf("3) failed\n"); | ||
19 | else | ||
20 | printf("3) check\n"); | ||
21 | |||
22 | str += " How are you?"; | ||
23 | |||
24 | str.prepend("Bob says: "); | ||
25 | |||
26 | printf("%s\n", str.c_str() ); | ||
27 | } | ||
28 | |||