PIPS
stack.c
Go to the documentation of this file.
1 /*
2 
3  $Id: stack.c 1357 2016-03-02 08:18:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of NewGen.
8 
9  NewGen is free software: you can redistribute it and/or modify it under the
10  terms of the GNU General Public License as published by the Free Software
11  Foundation, either version 3 of the License, or any later version.
12 
13  NewGen is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16  License for more details.
17 
18  You should have received a copy of the GNU General Public License along with
19  NewGen. If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 /*
23  * STACK MANAGEMENT
24  *
25  * Fabien COELHO, 05/12/1994
26  *
27  * Could be integrated in Newgen as a building type (as lists, mappings).
28  * there is no actual need of such a type on the functional point of view.
29  * I put it there since it may be much more efficient than lists.
30  * Stack print out and read in functions would be needed.
31  * (direction problem).
32  *
33  * More thoughts needed.
34  */
35 #ifdef HAVE_CONFIG_H
36  #include "config.h"
37 #endif
38 
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include "genC.h"
42 #include "newgen_include.h"
43 
44 /* STACK STRUCTURES
45  */
46 
47 /* the stack buckets, i.e. arrays containing the elements
48  */
49 typedef struct __stack_bucket
50 {
51  size_t n_item; /* next available item in the bucket */
52  size_t max_items; /* the max number of items of this bucket */
53  void ** items; /* the items (only pointers at the moment) */
54  struct __stack_bucket *succ;/* the next bucket */
55  /* we could keep the previous bucket? */
56 }
58 
59 /* the stack head
60  */
61 typedef struct __stack_head
62 {
63  size_t size; /* current number of elements in stack */
64  size_t max_extent; /* maximum extension of the stack */
65  _stack_ptr stack;/* buckets in use by the stack */
66  _stack_ptr avail;/* allocated buckets not in use anymore */
67  size_t bucket_size; /* reference bucket size for allocation */
68  size_t n_buckets; /* number of allocated buckets */
69  int type; /* as BASIC, LIST, EXTERNAL, CHUNK, domain? */
70  int policy; /* may be used to indicate an allocation policy */
71 }
72  _stack_head; /* and also *stack (in headers) */
73 
74 /* usefull defines
75  */
76 #define STACK_PTR_NULL ((_stack_ptr) NULL)
77 #define STACK_PTR_NULL_P(x) ((x)==STACK_PTR_NULL)
78 #define STACK_DEFAULT_SIZE 50
79 
80 /* STACK ITERATOR
81  */
82 typedef struct __stack_iterator
83 {
84  _stack_ptr bucket; /* current bucket */
85  bool downward; /* true if downward iterations */
86  size_t index; /* current index in bucket */
87  _stack_ptr list; /* all buckets */
88 }
89  _stack_iterator; /* and also *stack_iterator (in headers) */
90 
92 {
93  _stack_ptr x=i->list;
94 
95  while(!STACK_PTR_NULL_P(x) && x->succ!=i->bucket)
96  x=x->succ;
97 
98  i->bucket=x, i->index=0;
99 
100  if (x && i->bucket->n_item==0)
101  i->bucket = STACK_PTR_NULL;
102 }
103 
104 #define STACK_ITERATOR_END_P(i) STACK_PTR_NULL_P(i->bucket)
105 
106 #define DEFINE_ITERATOR(i,blk,idx,dwn,lst) \
107  { \
108  i->bucket=(blk); \
109  i->index=(idx); \
110  i->list=lst; \
111  i->downward=dwn; \
112  }
113 
114 #define UPDATE_ITERATOR_DOWNWARD(i) \
115  if (i->index == (size_t) -1) \
116  { \
117  i->bucket = i->bucket->succ; \
118  i->index = (i->bucket) ? (i->bucket->n_item)-1 : (size_t) -1; \
119  }
120 
121 #define UPDATE_ITERATOR_UPWARD(i) \
122  if (i->index==i->bucket->n_item) \
123  update_iterator_upward(i);
124 
125 #define NEXT_ITERATION(i) \
126  if (i->downward) \
127  { \
128  i->index--; UPDATE_ITERATOR_DOWNWARD(i); \
129  } \
130  else \
131  { \
132  i->index++; UPDATE_ITERATOR_UPWARD(i); \
133  }
134 
136  (const stack s, int down, stack_iterator i)
137 {
138  STACK_CHECK(s);
139 
140  if ((s->size)==0)
142  else
143  {
144  if (down)
145  {
146  DEFINE_ITERATOR(i, s->stack, (s->stack->n_item)-1, down, s->stack);
148  }
149  else
150  {
151  DEFINE_ITERATOR(i, STACK_PTR_NULL, 0, down, s->stack);
152  update_iterator_upward(i); /* NOT the define! */
153  }
154  }
155 }
156 
158 {
160  stack_iterator_internal_init(s, down, i);
161  return i;
162 }
163 
165 {
166  if (STACK_ITERATOR_END_P(i))
167  {
168  *pitem = (void*) NULL;
169  return false;
170  }
171  else
172  {
173  *pitem = (i->bucket->items)[i->index];
174  NEXT_ITERATION(i);
175  return true;
176  }
177 }
178 
180 {
181  return STACK_ITERATOR_END_P(i);
182 }
183 
185 {
186  (*pi)->bucket = NEWGEN_FREED;
187  (*pi)->downward = 0;
188  (*pi)->index = 0;
189  (*pi)->list = NEWGEN_FREED;
190  free(*pi);
191  *pi=(stack_iterator) NULL;
192 }
193 
194 /*
195  * STACK ALLOCATION
196  *
197  */
198 
199 /* allocates a bucket of size size
200  */
201 static _stack_ptr allocate_bucket(int size)
202 {
204  message_assert("pointer was allocated", x);
205 
206  x->n_item = 0;
207  x->max_items = size;
208  x->items = (void **) malloc(sizeof(void *)*size);
209  message_assert("pointer was allocated", x->items);
210  x->succ = STACK_PTR_NULL;
211 
212  return x;
213 }
214 
215 /* search for a new bucket, first in the available list,
216  * if none are available, a new bucket is allocated
217  */
219 {
220  if (!STACK_PTR_NULL_P(s->avail))
221  {
222  _stack_ptr x = s->avail;
223  s->avail = (s->avail)->succ;
224  x->succ = STACK_PTR_NULL; /* clean the bucket to be returned */
225  return x;
226  }
227  else
228  {
229  s->n_buckets++;
230  /* may depend from the policy? */
231  return allocate_bucket(s->bucket_size);
232  }
233 }
234 
235 /* ALLOCATEs a new stack of @p type
236 
237  @param type record newgen domain of stack contents. should be used
238  to check the type of appended elements.
239 
240  @param bucket_size is the number of elements in the elemental stack
241  container. If you now you will have big stacks, try big numbers here to
242  save memory.
243 
244  @param policy not used, 0 is fine.
245  */
246 stack stack_make(int type, int bucket_size, int policy)
247 {
248  stack s = (stack) malloc(sizeof(_stack_head));
249  message_assert("pointer was allocated", s);
250 
251  if (bucket_size<10) bucket_size=STACK_DEFAULT_SIZE; /* not too small */
252 
253  s->size = 0;
254  s->type = type;
255  s->policy = policy; /* not used */
256  s->bucket_size = bucket_size;
257  s->max_extent = 0;
258  s->n_buckets = 0;
259  s->stack = allocate_bucket(bucket_size);
260  s->avail = STACK_PTR_NULL;
261 
262  return s;
263 }
264 
265 /* duplicate a stack with its contents.
266  */
268 {
269  stack n = stack_make(s->type, s->bucket_size, s->policy);
270  STACK_MAP_X(i, void*, stack_push(i, n), s, 0);
271  return n;
272 }
273 
274 /* FREEs the stack
275  */
277 {
278  gen_free_area(x->items, x->max_items*sizeof(void*));
279  gen_free_area((void**) x, sizeof(_stack_bucket));
280 }
281 
283 {
284  _stack_ptr tmp;
285  while(!STACK_PTR_NULL_P(x))
286  {
287  tmp=x, x=x->succ, tmp->succ=STACK_PTR_NULL;
288  free_bucket(tmp);
289  }
290 }
291 
292 void stack_free(stack * ps)
293 {
294  free_buckets((*ps)->stack), (*ps)->stack=STACK_PTR_NULL;
295  free_buckets((*ps)->avail), (*ps)->avail=STACK_PTR_NULL;
296  gen_free_area((void**) *ps, sizeof(stack_head));
297  *ps = STACK_NULL;
298 }
299 
300 /* STACK MISCELLANEOUS
301  */
302 #define STACK_OBSERVER(name, what) \
303  int stack_##name(const stack s) { STACK_CHECK(s); return(what); }
304 
305 /* Here we define stack_size(), stack_bsize(), stack_policy() and
306  stack_max_extent(): */
307 STACK_OBSERVER(size, s->size)
308 STACK_OBSERVER(bsize, s->bucket_size)
309 STACK_OBSERVER(policy, s->policy)
310 STACK_OBSERVER(max_extent, s->max_extent)
311 STACK_OBSERVER(consistent_p, 1) /* well, it is not implemented */
312 
313 bool stack_empty_p(const stack s)
314 {
315  STACK_CHECK(s);
316  return s->size==0;
317 }
318 
319 #undef STACK_OBSERVER
320 
321 /* APPLY f to all items of stack s;
322  */
324 {
325  _stack_ptr x;
326  int i;
327 
328  STACK_CHECK(s);
329 
330  for(x=s->stack; x!=NULL; x=x->succ)
331  for(i=(x->n_item)-1; i>=0; i--)
332  (*f)(x->items[i]);
333 }
334 
336 {
337  int n=0;
338  for(; !STACK_PTR_NULL_P(x); x=x->succ, n++);
339  return n;
340 }
341 
342 void stack_info(FILE * f, const stack s)
343 {
344  fprintf(f, "stack_info about stack %p\n", s);
345 
346  if (STACK_NULL_P(s))
347  {
348  fprintf(f, " - is null\n");
349  return;
350  }
351  /* else */
352  if (stack_undefined_p(s))
353  {
354  fprintf(f, " - is undefined\n");
355  return;
356  }
357  /* else */
358  fprintf(f, " - type %d, size %zd, max extent %zd\n",
359  s->type, s->size, s->max_extent);
360  fprintf(f, " - buckets: %d in use, %d available\n",
362 }
363 
364 /* STACK USE
365  */
366 
367 /* PUSHes the item on stack s
368  *
369  * a new bucket is allocated if necessary.
370  * the size it the same than the initial bucket size.
371  * Other policies may be considered.
372  */
373 void stack_push(void * item, stack s)
374 {
375  _stack_ptr x = s->stack;
376 
378 
379  if (x->n_item == x->max_items)
380  {
381  _stack_ptr saved = x;
382  x = find_or_allocate(s);
383  x->succ = saved;
384  s->stack = x;
385  }
386 
387  /* PUSH!
388  */
389  s->size++;
390  if (s->size > s->max_extent) s->max_extent = s->size;
391  x->items[x->n_item++] = item;
392 }
393 
394 /* POPs one item from stack s
395  *
396  * the empty buckets are not freed here.
397  * stack_free does the job.
398  */
399 void *stack_pop(stack s)
400 {
401  _stack_ptr x = s->stack;
402 
403  if (x->n_item==0)
404  {
405  _stack_ptr saved = x->succ;
406  x->succ = s->avail, s->avail = x;
407  s->stack = saved, x = saved;
408  }
409 
410  assert(!STACK_PTR_NULL_P(x) && x->n_item>0);
411 
412  /* POP!
413  */
414  s->size--;
415  return x->items[--x->n_item];
416 }
417 
418 /* returns the item on top of stack s
419  */
420 void *stack_head(const stack s)
421 {
422  _stack_ptr x = s->stack;
423  if (x->n_item==0) x = x->succ;
424  assert(!STACK_PTR_NULL_P(x) && x->n_item>0);
425 
426  /* HEAD
427  */
428  return x->items[(x->n_item)-1];
429 }
430 
431 /* returns the nth item starting from the head and counting from 1,
432  when possible, or NULL, elsewhere.
433 
434  stack_nth(stack,1)==stack_head(stack) if stack_size(stack)>=1.
435  */
436 void *stack_nth(const stack s, int nskip)
437 {
438  void * value = NULL;
439  message_assert("positive nskip", nskip>=0);
440  // message_assert("deep enough stack", stack_size(s)>=nskip);
441  _stack_iterator si;
442  stack_iterator_internal_init(s, true, &si);
443  while (nskip && stack_iterator_next_and_go(&si, &value))
444  nskip--;
445  return value;
446 }
447 
448 /* REPLACEs the item on top of stack s, and returns the old item
449  */
450 void *stack_replace(void * item, stack s)
451 {
452  _stack_ptr x = s->stack;
453  void *old;
454 
455  if (x->n_item==0) x = x->succ;
456  assert(!STACK_PTR_NULL_P(x) && x->n_item>0);
457 
458  /* REPLACE
459  */
460  old = x->items[(x->n_item)-1];
461  x->items[(x->n_item)-1] = item;
462 
463  return old;
464 }
465 
466 
467 /* that is all
468  */
struct _newgen_struct_type_ * type
void * malloc(YYSIZE_T)
void free(void *)
void gen_free_area(void **p, int size)
free an area.
Definition: list.c:775
#define assert(ex)
Definition: newgen_assert.h:41
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
#define NEWGEN_FREED
struct __stack_iterator * stack_iterator
Definition: newgen_stack.h:48
#define STACK_NULL
defines for empty values
Definition: newgen_stack.h:52
#define STACK_MAP_X(_item, _itemtype, _code, _stack, _downwards)
not needed
Definition: newgen_stack.h:104
bool stack_empty_p(const stack)
#define STACK_NULL_P(s)
Definition: newgen_stack.h:53
#define STACK_CHECK(s)
Definition: newgen_stack.h:58
struct __stack_head * stack
STACK MANAGEMENT – headers.
Definition: newgen_stack.h:47
#define stack_undefined_p(s)
Definition: newgen_stack.h:56
void(* gen_iter_func_t)(void *)
Definition: newgen_types.h:116
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
struct _newgen_struct_value_ * value
Definition: ri.h:455
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
static char * x
Definition: split_file.c:159
stack stack_make(int type, int bucket_size, int policy)
ALLOCATEs a new stack of type.
Definition: stack.c:246
#define STACK_DEFAULT_SIZE
Definition: stack.c:78
struct __stack_bucket * _stack_ptr
static void update_iterator_upward(stack_iterator i)
and also *stack_iterator (in headers)
Definition: stack.c:91
static void stack_iterator_internal_init(const stack s, int down, stack_iterator i)
Definition: stack.c:136
static void free_bucket(_stack_ptr x)
FREEs the stack.
Definition: stack.c:276
struct __stack_iterator _stack_iterator
STACK ITERATOR.
bool stack_iterator_next_and_go(stack_iterator i, void **pitem)
X-ward.
Definition: stack.c:164
static _stack_ptr find_or_allocate(stack s)
search for a new bucket, first in the available list, if none are available, a new bucket is allocate...
Definition: stack.c:218
stack stack_copy(const stack s)
duplicate a stack with its contents.
Definition: stack.c:267
#define UPDATE_ITERATOR_DOWNWARD(i)
Definition: stack.c:114
static _stack_ptr allocate_bucket(int size)
allocates a bucket of size size
Definition: stack.c:201
static void free_buckets(_stack_ptr x)
Definition: stack.c:282
struct __stack_bucket _stack_bucket
STACK STRUCTURES.
stack_iterator stack_iterator_init(const stack s, bool down)
stack iterator
Definition: stack.c:157
#define STACK_PTR_NULL
and also *stack (in headers)
Definition: stack.c:76
void stack_iterator_end(stack_iterator *pi)
Definition: stack.c:184
static int number_of_buckets(_stack_ptr x)
Definition: stack.c:335
void stack_info(FILE *f, const stack s)
Definition: stack.c:342
#define STACK_ITERATOR_END_P(i)
Definition: stack.c:104
void stack_free(stack *ps)
type, bucket_size, policy
Definition: stack.c:292
void * stack_head(const stack s)
returns the item on top of stack s
Definition: stack.c:420
struct __stack_head _stack_head
the stack head
#define NEXT_ITERATION(i)
Definition: stack.c:125
bool stack_iterator_end_p(stack_iterator i)
Definition: stack.c:179
void * stack_nth(const stack s, int nskip)
returns the nth item starting from the head and counting from 1, when possible, or NULL,...
Definition: stack.c:436
#define STACK_OBSERVER(name, what)
STACK MISCELLANEOUS.
Definition: stack.c:302
void * stack_replace(void *item, stack s)
REPLACEs the item on top of stack s, and returns the old item.
Definition: stack.c:450
void * stack_pop(stack s)
POPs one item from stack s.
Definition: stack.c:399
#define STACK_PTR_NULL_P(x)
Definition: stack.c:77
void stack_push(void *item, stack s)
STACK USE.
Definition: stack.c:373
void stack_map(const stack s, gen_iter_func_t f)
APPLY f to all items of stack s;.
Definition: stack.c:323
#define DEFINE_ITERATOR(i, blk, idx, dwn, lst)
Definition: stack.c:106
STACK STRUCTURES.
Definition: stack.c:50
struct __stack_bucket * succ
the items (only pointers at the moment)
Definition: stack.c:54
void ** items
the max number of items of this bucket
Definition: stack.c:53
size_t n_item
Definition: stack.c:51
size_t max_items
next available item in the bucket
Definition: stack.c:52
the stack head
Definition: stack.c:62
int type
number of allocated buckets
Definition: stack.c:69
int policy
as BASIC, LIST, EXTERNAL, CHUNK, domain?
Definition: stack.c:70
size_t size
Definition: stack.c:63
_stack_ptr avail
buckets in use by the stack
Definition: stack.c:66
_stack_ptr stack
maximum extension of the stack
Definition: stack.c:65
size_t max_extent
current number of elements in stack
Definition: stack.c:64
size_t n_buckets
reference bucket size for allocation
Definition: stack.c:68
size_t bucket_size
allocated buckets not in use anymore
Definition: stack.c:67
STACK ITERATOR.
Definition: stack.c:83
size_t index
true if downward iterations
Definition: stack.c:86
bool downward
current bucket
Definition: stack.c:85
_stack_ptr list
current index in bucket
Definition: stack.c:87
_stack_ptr bucket
Definition: stack.c:84