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. \*/
57d4d32000-08-23Henrik Grubbström (Grubba) /**/
06983f1996-09-22Fredrik Hübinette (Hubbe) #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"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #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) 
c9e8202001-04-14Johan Sundström RCSID("$Id: multiset.c,v 1.34 2001/04/14 11:22:33 jhs 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;
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int multiset_member(struct multiset *l, struct svalue *ind)
06983f1996-09-22Fredrik Hübinette (Hubbe) {
49398c2000-11-08Fredrik Hübinette (Hubbe)  int i; add_ref(l->ind); i=set_lookup(l->ind, ind) >= 0; free_array(l->ind); return i;
06983f1996-09-22Fredrik Hübinette (Hubbe) } /* * allocate and init a new multiset */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT 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);
45637c2001-04-07Fredrik Hübinette (Hubbe)  INIT_PIKE_MEMOBJ(l);
06983f1996-09-22Fredrik Hübinette (Hubbe)  l->ind=ind;
e2d9e62000-06-10Martin Stjernholm  DOUBLELINK(first_multiset, l);
06983f1996-09-22Fredrik Hübinette (Hubbe)  return l; } /* * free a multiset */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void really_free_multiset(struct multiset *l)
06983f1996-09-22Fredrik Hübinette (Hubbe) {
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);
45637c2001-04-07Fredrik Hübinette (Hubbe)  EXIT_PIKE_MEMOBJ(l);
06983f1996-09-22Fredrik Hübinette (Hubbe) 
e2d9e62000-06-10Martin Stjernholm  DOUBLEUNLINK(first_multiset, l);
06983f1996-09-22Fredrik Hübinette (Hubbe)  free((char *)l);
553d232000-09-14Martin Stjernholm  GC_FREE(l);
06983f1996-09-22Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void do_free_multiset(struct multiset *l)
65b6732000-07-07Martin Stjernholm { if (l) free_multiset(l); }
49398c2000-11-08Fredrik Hübinette (Hubbe) #define BEGIN() do{ \ struct array *ind=l->ind; \ struct array *ind_bak=ind; \ if(ind->refs > 1) \ { \ ind=copy_array(l->ind); \ free_array(l->ind); \ l->ind=ind; \ } \ add_ref(ind) #define END() \ if(l->ind == ind_bak) \ { \ free_array(l->ind); \ l->ind=ind; \ }else{ \ free_array(ind); \ } \ }while(0)
1a3e1b1999-04-13Fredrik Hübinette (Hubbe) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT 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;
49398c2000-11-08Fredrik Hübinette (Hubbe)  BEGIN(); #if 0 order = get_set_order(ind); flags = ind->flags; ind = order_array(ind, order); ind->flags = flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  free((char *)order);
49398c2000-11-08Fredrik Hübinette (Hubbe) #else { extern void set_sort_svalues(struct svalue *, struct svalue *); set_sort_svalues(ITEM(ind),ITEM(ind)+ind->size-1); } #endif END();
06983f1996-09-22Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct multiset *mkmultiset(struct array *ind)
06983f1996-09-22Fredrik Hübinette (Hubbe) { struct multiset *l; l=allocate_multiset(copy_array(ind)); order_multiset(l); return l; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void multiset_insert(struct multiset *l,
49398c2000-11-08Fredrik Hübinette (Hubbe)  struct svalue *v)
06983f1996-09-22Fredrik Hübinette (Hubbe) { INT32 i;
49398c2000-11-08Fredrik Hübinette (Hubbe)  BEGIN(); i=set_lookup(ind, v);
06983f1996-09-22Fredrik Hübinette (Hubbe)  if(i < 0) {
49398c2000-11-08Fredrik Hübinette (Hubbe)  int flags = ind->flags; ind=array_insert(ind, v, ~i); ind->flags = flags;
06983f1996-09-22Fredrik Hübinette (Hubbe)  }
49398c2000-11-08Fredrik Hübinette (Hubbe)  END();
06983f1996-09-22Fredrik Hübinette (Hubbe) } #if 0 struct array *multiset_indices(struct multiset *l) { return l->ind; } #endif
49398c2000-11-08Fredrik Hübinette (Hubbe) PMOD_EXPORT void multiset_delete(struct multiset *l,struct svalue *v)
06983f1996-09-22Fredrik Hübinette (Hubbe) { INT32 i;
49398c2000-11-08Fredrik Hübinette (Hubbe)  BEGIN(); i=set_lookup(ind, v);
06983f1996-09-22Fredrik Hübinette (Hubbe) 
3619041999-10-29Martin Stjernholm  if(i >= 0) {
49398c2000-11-08Fredrik Hübinette (Hubbe)  int flags = ind->flags; ind=array_remove(ind, i); ind->flags = flags;
3619041999-10-29Martin Stjernholm  }
49398c2000-11-08Fredrik Hübinette (Hubbe)  END();
06983f1996-09-22Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void check_multiset_for_destruct(struct multiset *l)
06983f1996-09-22Fredrik Hübinette (Hubbe) {
3619041999-10-29Martin Stjernholm /* Horrifying worst case!!!!! */
06983f1996-09-22Fredrik Hübinette (Hubbe)  INT32 i;
49398c2000-11-08Fredrik Hübinette (Hubbe)  BEGIN(); { int flags = ind->flags; while( (i=array_find_destructed_object(ind)) >= 0) ind=array_remove(ind, i); ind->flags = flags; } END();
06983f1996-09-22Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct multiset *copy_multiset(struct multiset *tmp)
06983f1996-09-22Fredrik Hübinette (Hubbe) { check_multiset_for_destruct(tmp); return allocate_multiset(copy_array(tmp->ind)); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct multiset *merge_multisets(struct multiset *a,
06983f1996-09-22Fredrik Hübinette (Hubbe)  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; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct multiset *add_multisets(struct svalue *argp,INT32 args)
06983f1996-09-22Fredrik Hübinette (Hubbe) { 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; } }
57d4d32000-08-23Henrik Grubbström (Grubba)  if (l->ind->size == 1) { my_strcat("(< /* 1 element */\n"); } else { sprintf(buf, "(< /* %ld elements */\n", (long)l->ind->size); my_strcat(buf); }
06983f1996-09-22Fredrik Hübinette (Hubbe)  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)); } }
ce4d672001-01-31Henrik Grubbström (Grubba) /*! @decl multiset aggregate_multiset(mixed ... elems) *! *! Construct a multiset. *! *! Construct a multiset with the arguments as indices.
c9e8202001-04-14Johan Sundström  *! This method is most useful when constructing multisets *! with @[map] or similar; generally, the multiset literal *! syntax is handier: @code{(< elem1, elem2, ... >)@}
ce4d672001-01-31Henrik Grubbström (Grubba)  *! *! @seealso *! @[sizeof()], @[multisetp()], @[mkmultiset()] */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_aggregate_multiset(INT32 args)
06983f1996-09-22Fredrik Hübinette (Hubbe) { 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  } }
45d87e2000-07-18Martin Stjernholm void real_gc_cycle_check_multiset(struct multiset *l, int weak)
e2d9e62000-06-10Martin Stjernholm {
45d87e2000-07-18Martin Stjernholm  GC_CYCLE_ENTER(l, weak) { gc_cycle_check_array(l->ind, 0);
e2d9e62000-06-10Martin Stjernholm  } 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) {
45d87e2000-07-18Martin Stjernholm  real_gc_cycle_check_multiset(l, 0); gc_cycle_run_queue();
e2d9e62000-06-10Martin Stjernholm  }
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)