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