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