1 /*
2 * Copyright 1993, 1995 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7 /*
8 * lists.c - maintain lists of objects
9 */
10
11 #include "jam.h"
12 #include "lists.h"
13 #include "output.h"
14
15 #include <assert.h>
16
17 static LIST * freelist[ 32 ]; /* junkpile for list_dealloc() */
18
get_bucket(unsigned size)19 static unsigned get_bucket( unsigned size )
20 {
21 unsigned bucket = 0;
22 while ( size > ( 1u << bucket ) ) ++bucket;
23 return bucket;
24 }
25
list_alloc(unsigned const size)26 static LIST * list_alloc( unsigned const size )
27 {
28 unsigned const bucket = get_bucket( size );
29 if ( freelist[ bucket ] )
30 {
31 LIST * result = freelist[ bucket ];
32 freelist[ bucket ] = result->impl.next;
33 return result;
34 }
35 return (LIST *)BJAM_MALLOC( sizeof( LIST ) + ( 1u << bucket ) *
36 sizeof( OBJECT * ) );
37 }
38
list_dealloc(LIST * l)39 static void list_dealloc( LIST * l )
40 {
41 unsigned size = list_length( l );
42 unsigned bucket;
43 LIST * node = l;
44
45 if ( size == 0 ) return;
46
47 bucket = get_bucket( size );;
48
49 #ifdef BJAM_NO_MEM_CACHE
50 BJAM_FREE( node );
51 #else
52 node->impl.next = freelist[ bucket ];
53 freelist[ bucket ] = node;
54 #endif
55 }
56
57 /*
58 * list_append() - append a list onto another one, returning total
59 */
60
list_append(LIST * l,LIST * nl)61 LIST * list_append( LIST * l, LIST * nl )
62 {
63 if ( list_empty( l ) )
64 return nl;
65 if ( !list_empty( nl ) )
66 {
67 unsigned int const l_size = list_length( l );
68 int const nl_size = list_length( nl );
69 int const size = l_size + nl_size;
70 unsigned const bucket = get_bucket( size );
71
72 /* Do we need to reallocate? */
73 if ( l_size <= ( 1u << ( bucket - 1 ) ) )
74 {
75 LIST * result = list_alloc( size );
76 memcpy( list_begin( result ), list_begin( l ), l_size * sizeof(
77 OBJECT * ) );
78 list_dealloc( l );
79 l = result;
80 }
81
82 l->impl.size = size;
83 memcpy( list_begin( l ) + l_size, list_begin( nl ), nl_size * sizeof(
84 OBJECT * ) );
85 list_dealloc( nl );
86 }
87 return l;
88 }
89
list_begin(LIST * l)90 LISTITER list_begin( LIST * l )
91 {
92 return l ? (LISTITER)( (char *)l + sizeof( LIST ) ) : 0;
93 }
94
list_end(LIST * l)95 LISTITER list_end( LIST * l )
96 {
97 return l ? list_begin( l ) + l->impl.size : 0;
98 }
99
list_new(OBJECT * value)100 LIST * list_new( OBJECT * value )
101 {
102 LIST * const head = list_alloc( 1 ) ;
103 head->impl.size = 1;
104 list_begin( head )[ 0 ] = value;
105 return head;
106 }
107
108 /*
109 * list_push_back() - tack a string onto the end of a list of strings
110 */
111
list_push_back(LIST * head,OBJECT * value)112 LIST * list_push_back( LIST * head, OBJECT * value )
113 {
114 unsigned int size = list_length( head );
115
116 if ( DEBUG_LISTS )
117 out_printf( "list > %s <\n", object_str( value ) );
118
119 /* If the size is a power of 2, reallocate. */
120 if ( size == 0 )
121 {
122 head = list_alloc( 1 );
123 }
124 else if ( ( ( size - 1 ) & size ) == 0 )
125 {
126 LIST * l = list_alloc( size + 1 );
127 memcpy( l, head, sizeof( LIST ) + size * sizeof( OBJECT * ) );
128 list_dealloc( head );
129 head = l;
130 }
131
132 list_begin( head )[ size ] = value;
133 head->impl.size = size + 1;
134
135 return head;
136 }
137
138
139 /*
140 * list_copy() - copy a whole list of strings (nl) onto end of another (l).
141 */
142
list_copy(LIST * l)143 LIST * list_copy( LIST * l )
144 {
145 int size = list_length( l );
146 int i;
147 LIST * result;
148
149 if ( size == 0 ) return L0;
150
151 result = list_alloc( size );
152 result->impl.size = size;
153 for ( i = 0; i < size; ++i )
154 list_begin( result )[ i ] = object_copy( list_begin( l )[ i ] );
155 return result;
156 }
157
158
list_copy_range(LIST * l,LISTITER first,LISTITER last)159 LIST * list_copy_range( LIST * l, LISTITER first, LISTITER last )
160 {
161 if ( first == last )
162 return L0;
163 else
164 {
165 int size = last - first;
166 LIST * result = list_alloc( size );
167 LISTITER dest = list_begin( result );
168 result->impl.size = size;
169 for ( ; first != last; ++first, ++dest )
170 *dest = object_copy( *first );
171 return result;
172 }
173 }
174
175
176 /*
177 * list_sublist() - copy a subset of a list of strings.
178 */
179
list_sublist(LIST * l,int start,int count)180 LIST * list_sublist( LIST * l, int start, int count )
181 {
182 int end = start + count;
183 int size = list_length( l );
184 if ( start >= size ) return L0;
185 if ( end > size ) end = size;
186 return list_copy_range( l, list_begin( l ) + start, list_begin( l ) + end );
187 }
188
189
str_ptr_compare(void const * va,void const * vb)190 static int str_ptr_compare( void const * va, void const * vb )
191 {
192 OBJECT * a = *( (OBJECT * *)va );
193 OBJECT * b = *( (OBJECT * *)vb );
194 return strcmp( object_str( a ), object_str( b ) );
195 }
196
197
list_sort(LIST * l)198 LIST * list_sort( LIST * l )
199 {
200 int len;
201 LIST * result;
202
203 if ( !l )
204 return L0;
205
206 len = list_length( l );
207 result = list_copy( l );
208
209 qsort( list_begin( result ), len, sizeof( OBJECT * ), str_ptr_compare );
210
211 return result;
212 }
213
214
215 /*
216 * list_free() - free a list of strings
217 */
218
list_free(LIST * head)219 void list_free( LIST * head )
220 {
221 if ( !list_empty( head ) )
222 {
223 LISTITER iter = list_begin( head );
224 LISTITER const end = list_end( head );
225 for ( ; iter != end; iter = list_next( iter ) )
226 object_free( list_item( iter ) );
227 list_dealloc( head );
228 }
229 }
230
231
232 /*
233 * list_pop_front() - remove the front element from a list of strings
234 */
235
list_pop_front(LIST * l)236 LIST * list_pop_front( LIST * l )
237 {
238 unsigned size = list_length( l );
239 assert( size );
240 --size;
241 object_free( list_front( l ) );
242
243 if ( size == 0 )
244 {
245 list_dealloc( l );
246 return L0;
247 }
248
249 if ( ( ( size - 1 ) & size ) == 0 )
250 {
251 LIST * const nl = list_alloc( size );
252 nl->impl.size = size;
253 memcpy( list_begin( nl ), list_begin( l ) + 1, size * sizeof( OBJECT * )
254 );
255 list_dealloc( l );
256 return nl;
257 }
258
259 l->impl.size = size;
260 memmove( list_begin( l ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
261 return l;
262 }
263
list_reverse(LIST * l)264 LIST * list_reverse( LIST * l )
265 {
266 int size = list_length( l );
267 if ( size == 0 ) return L0;
268 {
269 LIST * const result = list_alloc( size );
270 int i;
271 result->impl.size = size;
272 for ( i = 0; i < size; ++i )
273 list_begin( result )[ i ] = object_copy( list_begin( l )[ size - i -
274 1 ] );
275 return result;
276 }
277 }
278
list_cmp(LIST * t,LIST * s)279 int list_cmp( LIST * t, LIST * s )
280 {
281 int status = 0;
282 LISTITER t_it = list_begin( t );
283 LISTITER const t_end = list_end( t );
284 LISTITER s_it = list_begin( s );
285 LISTITER const s_end = list_end( s );
286
287 while ( !status && ( t_it != t_end || s_it != s_end ) )
288 {
289 char const * st = t_it != t_end ? object_str( list_item( t_it ) ) : "";
290 char const * ss = s_it != s_end ? object_str( list_item( s_it ) ) : "";
291
292 status = strcmp( st, ss );
293
294 t_it = t_it != t_end ? list_next( t_it ) : t_it;
295 s_it = s_it != s_end ? list_next( s_it ) : s_it;
296 }
297
298 return status;
299 }
300
list_is_sublist(LIST * sub,LIST * l)301 int list_is_sublist( LIST * sub, LIST * l )
302 {
303 LISTITER iter = list_begin( sub );
304 LISTITER const end = list_end( sub );
305 for ( ; iter != end; iter = list_next( iter ) )
306 if ( !list_in( l, list_item( iter ) ) )
307 return 0;
308 return 1;
309 }
310
311 /*
312 * list_print() - print a list of strings to stdout
313 */
314
list_print(LIST * l)315 void list_print( LIST * l )
316 {
317 LISTITER iter = list_begin( l ), end = list_end( l );
318 if ( iter != end )
319 {
320 out_printf( "%s", object_str( list_item( iter ) ) );
321 iter = list_next( iter );
322 for ( ; iter != end; iter = list_next( iter ) )
323 out_printf( " %s", object_str( list_item( iter ) ) );
324 }
325 }
326
327
328 /*
329 * list_length() - return the number of items in the list
330 */
331
list_length(LIST * l)332 int list_length( LIST * l )
333 {
334 return l ? l->impl.size : 0;
335 }
336
337
list_in(LIST * l,OBJECT * value)338 int list_in( LIST * l, OBJECT * value )
339 {
340 LISTITER iter = list_begin( l );
341 LISTITER end = list_end( l );
342 for ( ; iter != end; iter = list_next( iter ) )
343 if ( object_equal( list_item( iter ), value ) )
344 return 1;
345 return 0;
346 }
347
348
list_unique(LIST * sorted_list)349 LIST * list_unique( LIST * sorted_list )
350 {
351 LIST * result = L0;
352 OBJECT * last_added = 0;
353
354 LISTITER iter = list_begin( sorted_list ), end = list_end( sorted_list );
355 for ( ; iter != end; iter = list_next( iter ) )
356 {
357 if ( !last_added || !object_equal( list_item( iter ), last_added ) )
358 {
359 result = list_push_back( result, object_copy( list_item( iter ) ) );
360 last_added = list_item( iter );
361 }
362 }
363 return result;
364 }
365
list_done()366 void list_done()
367 {
368 unsigned int i;
369 for ( i = 0; i < sizeof( freelist ) / sizeof( freelist[ 0 ] ); ++i )
370 {
371 LIST * l = freelist[ i ];
372 while ( l )
373 {
374 LIST * const tmp = l;
375 l = l->impl.next;
376 BJAM_FREE( tmp );
377 }
378 }
379 }
380
381
382 /*
383 * lol_init() - initialize a LOL (list of lists).
384 */
385
lol_init(LOL * lol)386 void lol_init( LOL * lol )
387 {
388 lol->count = 0;
389 }
390
391
392 /*
393 * lol_add() - append a LIST onto an LOL.
394 */
395
lol_add(LOL * lol,LIST * l)396 void lol_add( LOL * lol, LIST * l )
397 {
398 if ( lol->count < LOL_MAX )
399 lol->list[ lol->count++ ] = l;
400 }
401
402
403 /*
404 * lol_free() - free the LOL and its LISTs.
405 */
406
lol_free(LOL * lol)407 void lol_free( LOL * lol )
408 {
409 int i;
410 for ( i = 0; i < lol->count; ++i )
411 list_free( lol->list[ i ] );
412 lol->count = 0;
413 }
414
415
416 /*
417 * lol_get() - return one of the LISTs in the LOL.
418 */
419
lol_get(LOL * lol,int i)420 LIST * lol_get( LOL * lol, int i )
421 {
422 return i < lol->count ? lol->list[ i ] : L0;
423 }
424
425
426 /*
427 * lol_print() - debug print LISTS separated by ":".
428 */
429
lol_print(LOL * lol)430 void lol_print( LOL * lol )
431 {
432 int i;
433 for ( i = 0; i < lol->count; ++i )
434 {
435 if ( i )
436 out_printf( " : " );
437 list_print( lol->list[ i ] );
438 }
439 }
440
441 #ifdef HAVE_PYTHON
442
list_to_python(LIST * l)443 PyObject * list_to_python( LIST * l )
444 {
445 PyObject * result = PyList_New( 0 );
446 LISTITER iter = list_begin( l );
447 LISTITER const end = list_end( l );
448 for ( ; iter != end; iter = list_next( iter ) )
449 {
450 PyObject * s = PyString_FromString( object_str( list_item( iter ) ) );
451 PyList_Append( result, s );
452 Py_DECREF( s );
453 }
454
455 return result;
456 }
457
list_from_python(PyObject * l)458 LIST * list_from_python( PyObject * l )
459 {
460 LIST * result = L0;
461
462 Py_ssize_t n = PySequence_Size( l );
463 Py_ssize_t i;
464 for ( i = 0; i < n; ++i )
465 {
466 PyObject * v = PySequence_GetItem( l, i );
467 result = list_push_back( result, object_new( PyString_AsString( v ) ) );
468 Py_DECREF( v );
469 }
470
471 return result;
472 }
473
474 #endif
475