06983f1996-09-22Fredrik Hübinette (Hubbe) /*\ ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License) ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" #include "array.h" #include "multiset.h" #include "svalue.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
9aa6fa1997-05-19Fredrik Hübinette (Hubbe) #include "pike_memory.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "error.h" #include "dynamic_buffer.h" #include "interpret.h" #include "builtin_functions.h" #include "gc.h"
7e97c31999-01-21Fredrik Hübinette (Hubbe) #include "security.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) 
65b6732000-07-07Martin Stjernholm RCSID("$Id: multiset.c,v 1.23 2000/07/06 23:25:26 mast Exp $");
24ddc71998-03-28Henrik Grubbström (Grubba) 
06983f1996-09-22Fredrik Hübinette (Hubbe) struct multiset *first_multiset;
e2d9e62000-06-10Martin Stjernholm struct multiset *gc_internal_multiset = 0; static struct multiset *gc_mark_multiset_pos = 0;
06983f1996-09-22Fredrik Hübinette (Hubbe) int multiset_member(struct multiset *l, struct svalue *ind) { return set_lookup(l->ind, ind) >= 0; } /* * allocate and init a new multiset */
1a3e1b1999-04-13Fredrik Hübinette (Hubbe) struct multiset *allocate_multiset(struct array *ind)
06983f1996-09-22Fredrik Hübinette (Hubbe) { struct multiset *l; l=ALLOC_STRUCT(multiset);
7bf6232000-04-23Martin Stjernholm  GC_ALLOC(l);
06983f1996-09-22Fredrik Hübinette (Hubbe)  l->refs = 1; l->ind=ind;
e2d9e62000-06-10Martin Stjernholm  DOUBLELINK(first_multiset, l);
06983f1996-09-22Fredrik Hübinette (Hubbe) 
7e97c31999-01-21Fredrik Hübinette (Hubbe)  INITIALIZE_PROT(l);
06983f1996-09-22Fredrik Hübinette (Hubbe)  return l; } /* * free a multiset */ void really_free_multiset(struct multiset *l) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
06983f1996-09-22Fredrik Hübinette (Hubbe)  if(l->refs) fatal("really free multiset on multiset with nonzero refs.\n"); #endif free_array(l->ind);
7e97c31999-01-21Fredrik Hübinette (Hubbe)  FREE_PROT(l);
06983f1996-09-22Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  if (gc_internal_multiset) { if (l == gc_internal_multiset) gc_internal_multiset = l->next; if (l == gc_mark_multiset_pos) gc_mark_multiset_pos = l->next; } DOUBLEUNLINK(first_multiset, l);
06983f1996-09-22Fredrik Hübinette (Hubbe)  free((char *)l);
e2d9e62000-06-10Martin Stjernholm  GC_FREE();
06983f1996-09-22Fredrik Hübinette (Hubbe) }
65b6732000-07-07Martin Stjernholm void do_free_multiset(struct multiset *l) { if (l) free_multiset(l); }
1a3e1b1999-04-13Fredrik Hübinette (Hubbe)  void order_multiset(struct multiset *l)
06983f1996-09-22Fredrik Hübinette (Hubbe) { INT32 *order;
3619041999-10-29Martin Stjernholm  int flags;
61e9a01998-01-25Fredrik Hübinette (Hubbe)  if(l->ind->size < 2) return;
06983f1996-09-22Fredrik Hübinette (Hubbe)  order = get_set_order(l->ind);
3619041999-10-29Martin Stjernholm  flags = l->ind->flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  l->ind = order_array(l->ind, order);
3619041999-10-29Martin Stjernholm  l->ind->flags = flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  free((char *)order); } struct multiset *mkmultiset(struct array *ind) { struct multiset *l; l=allocate_multiset(copy_array(ind)); order_multiset(l); return l; } void multiset_insert(struct multiset *l, struct svalue *ind) { INT32 i; i=set_lookup(l->ind, ind); if(i < 0) {
3619041999-10-29Martin Stjernholm  int flags = l->ind->flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  l->ind=array_insert(l->ind, ind, ~i);
3619041999-10-29Martin Stjernholm  l->ind->flags = flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  } } #if 0 struct array *multiset_indices(struct multiset *l) { return l->ind; } #endif void multiset_delete(struct multiset *l,struct svalue *ind) { INT32 i; i=set_lookup(l->ind, ind);
3619041999-10-29Martin Stjernholm  if(i >= 0) { int flags = l->ind->flags; l->ind=array_remove(l->ind, i); l->ind->flags = flags; }
06983f1996-09-22Fredrik Hübinette (Hubbe) } void check_multiset_for_destruct(struct multiset *l) {
3619041999-10-29Martin Stjernholm /* Horrifying worst case!!!!! */
06983f1996-09-22Fredrik Hübinette (Hubbe)  INT32 i;
3619041999-10-29Martin Stjernholm  int flags = l->ind->flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  while( (i=array_find_destructed_object(l->ind)) >= 0) l->ind=array_remove(l->ind, i);
3619041999-10-29Martin Stjernholm  l->ind->flags = flags;
06983f1996-09-22Fredrik Hübinette (Hubbe) } struct multiset *copy_multiset(struct multiset *tmp) { check_multiset_for_destruct(tmp); return allocate_multiset(copy_array(tmp->ind)); } struct multiset *merge_multisets(struct multiset *a, struct multiset *b, INT32 operator) { struct multiset *ret; INT32 *zipper; check_multiset_for_destruct(a); check_multiset_for_destruct(b); zipper=merge(a->ind,b->ind,operator); ret=allocate_multiset(array_zip(a->ind,b->ind,zipper)); free((char *)zipper); return ret; } struct multiset *add_multisets(struct svalue *argp,INT32 args) { struct multiset *ret,*a,*b; switch(args) { case 0: ret=allocate_multiset(allocate_array_no_init(0,0)); break; case 1: ret=copy_multiset(argp->u.multiset); break; case 2:
71f3a21998-11-22Fredrik Hübinette (Hubbe)  ret=merge_multisets(argp[0].u.multiset,argp[1].u.multiset,PIKE_ARRAY_OP_ADD);
06983f1996-09-22Fredrik Hübinette (Hubbe)  break; case 3:
71f3a21998-11-22Fredrik Hübinette (Hubbe)  a=merge_multisets(argp[0].u.multiset, argp[1].u.multiset, PIKE_ARRAY_OP_ADD); ret=merge_multisets(a, argp[2].u.multiset, PIKE_ARRAY_OP_ADD);
06983f1996-09-22Fredrik Hübinette (Hubbe)  free_multiset(a); break; default: a=add_multisets(argp,args/2); b=add_multisets(argp+args/2,args-args/2);
71f3a21998-11-22Fredrik Hübinette (Hubbe)  ret=merge_multisets(a,b,PIKE_ARRAY_OP_ADD);
06983f1996-09-22Fredrik Hübinette (Hubbe)  free_multiset(a); free_multiset(b); break; } return ret; } int multiset_equal_p(struct multiset *a, struct multiset *b, struct processing *p) { if(a == b) return 1; check_multiset_for_destruct(a); return array_equal_p(a->ind, b->ind, p); } void describe_multiset(struct multiset *l,struct processing *p,int indent) { struct processing doing; int e; char buf[40]; if(!l->ind->size) { my_strcat("(< >)"); return; } doing.next=p; doing.pointer_a=(void *)l; for(e=0;p;e++,p=p->next) { if(p->pointer_a == (void *)l) { sprintf(buf,"@%d",e); my_strcat(buf); return; } }
93c8a61999-09-24Fredrik Noring  sprintf(buf, l->ind->size == 1 ? "(< /* %ld element */\n" : "(< /* %ld elements */\n", (long)l->ind->size);
06983f1996-09-22Fredrik Hübinette (Hubbe)  my_strcat(buf); describe_array_low(l->ind,&doing,indent); my_putchar('\n'); for(e=2; e<indent; e++) my_putchar(' '); my_strcat(">)"); } node * make_node_from_multiset(struct multiset *l) { if(check_that_array_is_constant(l->ind)) { struct svalue s; s.type=T_MULTISET; s.subtype=0; s.u.multiset=l; return mkconstantsvaluenode(&s); }else{ return mkefuncallnode("mkmultiset",make_node_from_array(l->ind)); } } void f_aggregate_multiset(INT32 args) { struct multiset *l; f_aggregate(args); l=allocate_multiset(sp[-1].u.array); order_multiset(l); sp[-1].type=T_MULTISET; sp[-1].u.multiset=l; } struct multiset *copy_multiset_recursively(struct multiset *l, struct processing *p) { struct processing doing; struct multiset *ret; doing.next=p; doing.pointer_a=(void *)l; for(;p;p=p->next) { if(p->pointer_a == (void *)l) { ret=(struct multiset *)p->pointer_b;
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(ret);
06983f1996-09-22Fredrik Hübinette (Hubbe)  return ret; } } ret=allocate_multiset( & empty_array ); doing.pointer_b=(void *)ret; ret->ind=copy_array_recursively(l->ind,&doing); order_multiset(ret); return ret; } void gc_mark_multiset_as_referenced(struct multiset *l) {
e2d9e62000-06-10Martin Stjernholm  if(gc_mark(l)) { if (l == gc_mark_multiset_pos) gc_mark_multiset_pos = l->next; if (l == gc_internal_multiset) gc_internal_multiset = l->next; else { DOUBLEUNLINK(first_multiset, l); DOUBLELINK(first_multiset, l); /* Linked in first. */ }
06983f1996-09-22Fredrik Hübinette (Hubbe)  gc_mark_array_as_referenced(l->ind);
e2d9e62000-06-10Martin Stjernholm  } } void real_gc_cycle_check_multiset(struct multiset *l) { GC_CYCLE_ENTER(l, 0) { gc_cycle_check_array(l->ind); } GC_CYCLE_LEAVE; } void real_gc_cycle_check_multiset_weak(struct multiset *l) { GC_CYCLE_ENTER(l, 1) { gc_cycle_check_array(l->ind); } GC_CYCLE_LEAVE;
06983f1996-09-22Fredrik Hübinette (Hubbe) }
7bf6232000-04-23Martin Stjernholm #ifdef PIKE_DEBUG
e2d9e62000-06-10Martin Stjernholm unsigned gc_touch_all_multisets(void)
7bf6232000-04-23Martin Stjernholm {
e2d9e62000-06-10Martin Stjernholm  unsigned n = 0;
7bf6232000-04-23Martin Stjernholm  struct multiset *l;
e2d9e62000-06-10Martin Stjernholm  if (first_multiset && first_multiset->prev) fatal("Error in multiset link list.\n");
7bf6232000-04-23Martin Stjernholm  for(l=first_multiset;l;l=l->next) { debug_gc_touch(l); n++;
e2d9e62000-06-10Martin Stjernholm  if (l->next && l->next->prev != l) fatal("Error in multiset link list.\n");
7bf6232000-04-23Martin Stjernholm  } return n; } #endif
be478c1997-08-30Henrik Grubbström (Grubba) void gc_check_all_multisets(void)
06983f1996-09-22Fredrik Hübinette (Hubbe) { struct multiset *l; for(l=first_multiset;l;l=l->next)
e2d9e62000-06-10Martin Stjernholm  debug_gc_check(l->ind, T_MULTISET, l);
06983f1996-09-22Fredrik Hübinette (Hubbe) }
be478c1997-08-30Henrik Grubbström (Grubba) void gc_mark_all_multisets(void)
06983f1996-09-22Fredrik Hübinette (Hubbe) {
e2d9e62000-06-10Martin Stjernholm  gc_mark_multiset_pos = gc_internal_multiset; while (gc_mark_multiset_pos) { struct multiset *l = gc_mark_multiset_pos; gc_mark_multiset_pos = l->next;
06983f1996-09-22Fredrik Hübinette (Hubbe)  if(gc_is_referenced(l)) gc_mark_multiset_as_referenced(l);
e2d9e62000-06-10Martin Stjernholm  } } void gc_cycle_check_all_multisets(void) { struct multiset *l; for (l = gc_internal_multiset; l; l = l->next) { real_gc_cycle_check_multiset(l); run_lifo_queue(&gc_mark_queue); }
06983f1996-09-22Fredrik Hübinette (Hubbe) }
be478c1997-08-30Henrik Grubbström (Grubba) void gc_free_all_unreferenced_multisets(void)
06983f1996-09-22Fredrik Hübinette (Hubbe) { struct multiset *l,*next;
e2d9e62000-06-10Martin Stjernholm  for(l=gc_internal_multiset;l;l=next)
06983f1996-09-22Fredrik Hübinette (Hubbe)  { if(gc_do_free(l)) {
e2d9e62000-06-10Martin Stjernholm  /* Got an extra ref from gc_cycle_pop(). */
06983f1996-09-22Fredrik Hübinette (Hubbe)  free_svalues(ITEM(l->ind), l->ind->size, l->ind->type_field); l->ind->size=0;
e2d9e62000-06-10Martin Stjernholm  gc_free_extra_ref(l);
69ee4b2000-04-06Fredrik Hübinette (Hubbe)  SET_NEXT_AND_FREE(l, free_multiset);
06983f1996-09-22Fredrik Hübinette (Hubbe)  }else{ next=l->next; } } }
c3c7031996-12-04Fredrik Hübinette (Hubbe) void count_memory_in_multisets(INT32 *num_, INT32 *size_) { struct multiset *m; INT32 size=0, num=0; for(m=first_multiset;m;m=m->next) { num++; size+=sizeof(struct multiset); } *num_=num; *size_=size; }
61e9a01998-01-25Fredrik Hübinette (Hubbe)