1 /* $Id: vec.c,v 1.4 2002/10/20 18:19:17 tommy Exp $ */
2
3 /*
4 * Copyright (c) 2002 Tom Marshall <tommy@tig-grr.com>
5 *
6 * This program is free software. It may be distributed under the terms
7 * in the file LICENSE, found in the top level of the distribution.
8 *
9 * vec.c: vector functions for bmf.
10 * Vectors are used to hold token lists for input data and flatfile database
11 * entries in standalone mode. They dramatically reduce the number of small
12 * mallocs and, if used properly, have no performance penalty over fancier
13 * data structures.
14 */
15
16 #include "config.h"
17 #include "dbg.h"
18 #include "str.h"
19 #include "lex.h"
20 #include "vec.h"
21
22 /*****************************************************************************
23 * vector
24 */
25
vec_create(vec_t * pthis)26 void vec_create( vec_t* pthis )
27 {
28 pthis->nalloc = VEC_INITIAL_SIZE;
29 pthis->nitems = 0;
30 pthis->pitems = (str_t*)malloc( VEC_INITIAL_SIZE*sizeof(str_t) );
31 }
32
vec_destroy(vec_t * pthis)33 void vec_destroy( vec_t* pthis )
34 {
35 free( pthis->pitems );
36 }
37
vec_setsize(vec_t * pthis,uint nsize)38 static void vec_setsize( vec_t* pthis, uint nsize )
39 {
40 if( nsize > pthis->nalloc )
41 {
42 uint nnewalloc;
43 str_t* pnewitems;
44 uint n;
45
46 nnewalloc = pthis->nalloc * 2;
47 if( nnewalloc < nsize ) nnewalloc = nsize;
48 pnewitems = (str_t*)realloc( pthis->pitems, nnewalloc*sizeof(str_t) );
49 if( pnewitems == NULL )
50 {
51 exit( 2 );
52 }
53 for( n = pthis->nitems; n < nsize; n++ )
54 {
55 str_create( &pnewitems[n] );
56 }
57 pthis->pitems = pnewitems;
58 pthis->nalloc = nnewalloc;
59 }
60 }
61
vec_addhead(vec_t * pthis,str_t * pstr)62 void vec_addhead( vec_t* pthis, str_t* pstr )
63 {
64 assert( pstr->p != NULL && pstr->len > 0 );
65
66 vec_setsize( pthis, pthis->nitems+1 );
67 memmove( &pthis->pitems[1], &pthis->pitems[0], pthis->nitems*sizeof(str_t) );
68 pthis->pitems[0] = *pstr;
69 pthis->nitems++;
70 }
71
vec_addtail(vec_t * pthis,str_t * pstr)72 void vec_addtail( vec_t* pthis, str_t* pstr )
73 {
74 assert( pstr->p != NULL && pstr->len > 0 );
75
76 vec_setsize( pthis, pthis->nitems+1 );
77 pthis->pitems[pthis->nitems] = *pstr;
78 pthis->nitems++;
79 }
80
vec_delhead(vec_t * pthis)81 void vec_delhead( vec_t* pthis )
82 {
83 assert( pthis->nitems > 0 );
84 pthis->nitems--;
85 memmove( &pthis->pitems[0], &pthis->pitems[1], pthis->nitems*sizeof(str_t) );
86 }
87
vec_deltail(vec_t * pthis)88 void vec_deltail( vec_t* pthis )
89 {
90 assert( pthis->nitems > 0 );
91 pthis->nitems--;
92 }
93
vec_first(vec_t * pthis,veciter_t * piter)94 void vec_first( vec_t* pthis, veciter_t* piter )
95 {
96 piter->plist = pthis;
97 piter->index = 0;
98 }
99
vec_last(vec_t * pthis,veciter_t * piter)100 void vec_last( vec_t* pthis, veciter_t* piter )
101 {
102 piter->plist = pthis;
103 piter->index = pthis->nitems;
104 }
105
106 /*****************************************************************************
107 * sorted vector
108 */
109
svec_compare(const void * p1,const void * p2)110 static int svec_compare( const void* p1, const void* p2 )
111 {
112 return str_casecmp( (const str_t*)p1, (const str_t*)p2 );
113 }
114
svec_add(vec_t * pthis,str_t * pstr)115 void svec_add( vec_t* pthis, str_t* pstr )
116 {
117 int lo, hi, mid;
118 veciter_t iter;
119
120 if( pthis->nitems == 0 )
121 {
122 vec_addtail( pthis, pstr );
123 return;
124 }
125
126 if( str_casecmp( pstr, &pthis->pitems[0] ) < 0 )
127 {
128 vec_addhead( pthis, pstr );
129 return;
130 }
131
132 hi = pthis->nitems - 1;
133 lo = -1;
134 while( hi-lo > 1 )
135 {
136 mid = (hi+lo)/2;
137 if( str_casecmp( pstr, &pthis->pitems[mid] ) <= 0 )
138 hi = mid;
139 else
140 lo = mid;
141 }
142 assert( hi < pthis->nitems );
143
144 iter.plist = pthis;
145 iter.index = hi;
146
147 if( str_casecmp( pstr, &pthis->pitems[hi] ) < 0 )
148 {
149 veciter_addbefore( &iter, pstr );
150 }
151 else
152 {
153 veciter_addafter( &iter, pstr );
154 }
155 }
156
svec_find(vec_t * pthis,str_t * pstr)157 str_t* svec_find( vec_t* pthis, str_t* pstr )
158 {
159 int lo, hi, mid;
160
161 if( pthis->nitems == 0 )
162 {
163 return NULL;
164 }
165
166 hi = pthis->nitems - 1;
167 lo = -1;
168 while( hi-lo > 1 )
169 {
170 mid = (hi+lo)/2;
171 if( str_casecmp( pstr, &pthis->pitems[mid] ) <= 0 )
172 hi = mid;
173 else
174 lo = mid;
175 }
176 assert( hi >= 0 && hi < pthis->nitems );
177
178 if( str_casecmp( pstr, &pthis->pitems[hi] ) != 0 )
179 {
180 return NULL;
181 }
182
183 return &pthis->pitems[hi];
184 }
185
svec_sort(vec_t * pthis)186 void svec_sort( vec_t* pthis )
187 {
188 if( pthis->nitems > 1 )
189 {
190 qsort( pthis->pitems, pthis->nitems, sizeof(str_t), svec_compare );
191 }
192 }
193
194 /*****************************************************************************
195 * vector iterator
196 */
197
veciter_destroy(veciter_t * pthis)198 void veciter_destroy( veciter_t* pthis )
199 {
200 /* empty */
201 }
202
veciter_get(veciter_t * pthis)203 str_t* veciter_get( veciter_t* pthis )
204 {
205 if( pthis->plist == NULL || pthis->index >= pthis->plist->nitems )
206 {
207 return NULL;
208 }
209
210 return &pthis->plist->pitems[pthis->index];
211 }
212
veciter_equal(veciter_t * pthis,veciter_t * pthat)213 bool_t veciter_equal( veciter_t* pthis, veciter_t* pthat )
214 {
215 if( pthis->plist != pthat->plist ||
216 pthis->index != pthat->index )
217 {
218 return false;
219 }
220
221 return true;
222 }
223
veciter_hasitem(veciter_t * pthis)224 bool_t veciter_hasitem( veciter_t* pthis )
225 {
226 if( pthis->plist == NULL || pthis->index >= pthis->plist->nitems )
227 {
228 return false;
229 }
230 return true;
231 }
232
veciter_prev(veciter_t * pthis)233 bool_t veciter_prev( veciter_t* pthis )
234 {
235 if( pthis->index == 0 )
236 {
237 return false;
238 }
239 pthis->index--;
240 return true;
241 }
242
veciter_next(veciter_t * pthis)243 bool_t veciter_next( veciter_t* pthis )
244 {
245 pthis->index++;
246 if( pthis->index == pthis->plist->nitems )
247 {
248 return false;
249 }
250 return true;
251 }
252
veciter_addafter(veciter_t * pthis,str_t * pstr)253 void veciter_addafter( veciter_t* pthis, str_t* pstr )
254 {
255 str_t* pitems;
256
257 vec_setsize( pthis->plist, pthis->plist->nitems+1 );
258 assert( pthis->index < pthis->plist->nitems );
259 pitems = pthis->plist->pitems;
260
261 if( pthis->index != pthis->plist->nitems-1 )
262 {
263 memmove( &pitems[pthis->index+2], &pitems[pthis->index+1],
264 (pthis->plist->nitems-pthis->index-1) * sizeof(str_t) );
265 }
266
267 pitems[pthis->index+1] = *pstr;
268 pthis->plist->nitems++;
269 }
270
veciter_addbefore(veciter_t * pthis,str_t * pstr)271 void veciter_addbefore( veciter_t* pthis, str_t* pstr )
272 {
273 str_t* pitems;
274
275 vec_setsize( pthis->plist, pthis->plist->nitems+1 );
276 assert( pthis->index < pthis->plist->nitems );
277 pitems = pthis->plist->pitems;
278
279 memmove( &pitems[pthis->index+1], &pitems[pthis->index],
280 (pthis->plist->nitems-pthis->index) * sizeof(str_t) );
281
282 pitems[pthis->index] = *pstr;
283 pthis->plist->nitems++;
284 }
285
veciter_del(veciter_t * pthis)286 void veciter_del( veciter_t* pthis )
287 {
288 str_t* pitems;
289
290 assert( pthis->plist->nitems > 0 );
291 pthis->plist->nitems--;
292 if( pthis->index < pthis->plist->nitems )
293 {
294 pitems = pthis->plist->pitems;
295 memmove( &pitems[pthis->index], &pitems[pthis->index+1],
296 (pthis->plist->nitems-pthis->index) * sizeof(str_t) );
297 }
298 }
299
300 #ifdef UNIT_TEST
main(int argc,char ** argv)301 int main( int argc, char** argv )
302 {
303 vec_t vl;
304 veciter_t iter;
305 str_t* pstr;
306 uint n;
307
308 if( argc != 2 )
309 {
310 fprintf( stderr, "usage: %s <file>\n", argv[0] );
311 return 1;
312 }
313
314 for( n = 0; n < 100; n++ )
315 {
316 vec_create( &vl );
317 vec_load( &vl, argv[1] );
318
319 vec_first( &vl, &iter );
320 while( (pstr = veciter_get( &iter )) != NULL )
321 {
322 char buf[256];
323 char* p;
324 if( pstr->len > 200 )
325 {
326 fprintf( stderr, "str too long: %u chars\n", pstr->len );
327 break;
328 }
329 p = buf;
330 strcpy( buf, "str: " );
331 p += 6;
332 memcpy( p, pstr->p, pstr->len );
333 p += pstr->len;
334 sprintf( p, " %u", pstr->count );
335 puts( buf );
336
337 veciter_next( &iter );
338 }
339
340 vec_destroy( &vl );
341 }
342
343 return 0;
344 }
345 #endif /* def UNIT_TEST */
346