pike.git / src / mapping.c

version» Context lines:

pike.git/src/mapping.c:1:   /*\ - ||| This file a part of uLPC, and is copyright by Fredrik Hubinette - ||| uLPC is distributed as GPL (General Public License) + ||| 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 "main.h"   #include "types.h" -  + #include "object.h"   #include "mapping.h"   #include "svalue.h"   #include "array.h"   #include "macros.h"   #include "language.h"   #include "error.h"   #include "memory.h"   #include "dynamic_buffer.h"   #include "interpret.h" -  + #include "las.h" + #include "gc.h"    -  +  + #define AVG_LINK_LENGTH 4 + #define MIN_LINK_LENGTH 1 + #define MAP_SLOTS(X) ((X)+((X)>>4)+8) + #define LOOP(m) for(e=0;e<m->hashsize;e++) for(k=m->hash[e];k;k=k->next) +  + struct keypair + { +  struct keypair *next; +  struct svalue ind, val; + }; +    struct mapping *first_mapping;    - /* -  * This function puts looks up an index in a mapping and assigns -  * the value to dest. It does not free dest first though +  + #ifdef DEBUG + /* This function checks that the type field isn't lacking any bits. +  * It is used for debugging purposes only.    */ - void mapping_index_no_free(struct svalue *dest, -  struct mapping *m, -  struct svalue *ind) + static void check_mapping_type_fields(struct mapping *m)   { -  INT32 i; -  i=set_lookup(m->ind, ind); -  if(i < 0) +  INT32 e; +  struct keypair *k,**prev; +  TYPE_FIELD ind_types, val_types; +  +  ind_types=val_types=0; +  +  for(e=0;e<m->hashsize;e++)    { -  dest->type=T_INT; -  dest->subtype=NUMBER_UNDEFINED; -  dest->u.integer=0; -  }else{ -  array_index_no_free(dest, m->val, i); +  for(k=m->hash[e];k;k=k->next) +  { +  val_types |= 1 << k->val.type; +  ind_types |= 1 << k->ind.type;    }    }    - #if 0 - /* -  * This funciton does the same thing as the one above, but -  * frees dest first. +  if(val_types & ~(m->val_types)) +  fatal("Mapping value types out of order!\n"); +  +  if(ind_types & ~(m->ind_types)) +  fatal("Mapping indices types out of order!\n"); + } + #endif +  +  + /* This function allocates the hash table and svalue space for a mapping +  * struct. The size is the max number of indices that can fit in the +  * allocated space.    */ - void mapping_index(struct svalue *dest, -  struct mapping *m, -  struct svalue *ind) + static void init_mapping(struct mapping *m, INT32 size)   { -  INT32 i; -  m->refs++; -  i=set_lookup(m->ind, ind); -  if(i < 0) -  { -  dest->type=T_INT; -  dest->subtype=NUMBER_UNDEFINED; -  dest->u.integer=0; -  }else{ -  array_index(dest, m->val, i); -  } -  free_mapping(m); - } +  char *tmp; +  INT32 e; +  INT32 hashsize,hashspace; +  + #ifdef DEBUG +  if(size < 0) fatal("init_mapping with negative value.\n");   #endif    - /* -  * allocate and init a new mapping +  hashsize=size / AVG_LINK_LENGTH + 1; +  if(!(hashsize & 1)) hashsize++; +  hashspace=hashsize+1; +  e=sizeof(struct keypair)*size+ sizeof(struct keypair *)*hashspace; +  tmp=(char *)xalloc(e); +  +  m->hash=(struct keypair **) tmp; +  m->hashsize=hashsize; +  +  tmp+=sizeof(struct keypair *)*hashspace; +  m->free_list=(struct keypair *) tmp; +  +  MEMSET((char *)m->hash, 0, sizeof(struct keypair *) * m->hashsize); +  +  for(e=1;e<size;e++) +  m->free_list[e-1].next = m->free_list + e; +  m->free_list[e-1].next=0; +  +  m->ind_types = 0; +  m->val_types = 0; +  m->size = 0; + } +  + /* This function allocates an empty mapping with room for 'size' values    */ - static struct mapping *allocate_mapping(struct array *ind, struct array *val) + static struct mapping *allocate_mapping(int size)   {    struct mapping *m; -  +  +  GC_ALLOC(); +     m=ALLOC_STRUCT(mapping); -  +  +  init_mapping(m,size); +     m->next = first_mapping;    m->prev = 0;    m->refs = 1; -  m->ind=ind; -  m->val=val; +     if(first_mapping) first_mapping->prev = m;    first_mapping=m;       return m;   }    - /* -  * free a mapping + /* This function should only be called by the free_mapping() macro. +  * It frees the storate used by the mapping.    */   void really_free_mapping(struct mapping *m)   { -  +  INT32 e; +  struct keypair *k;   #ifdef DEBUG    if(m->refs)    fatal("really free mapping on mapping with nonzero refs.\n");   #endif    -  free_array(m->ind); -  free_array(m->val); +  LOOP(m) +  { +  free_svalue(& k->val); +  free_svalue(& k->ind); +  }    -  if(m->prev) m->prev->next = m->next; +  if(m->prev) +  m->prev->next = m->next; +  else +  first_mapping = m->next; +     if(m->next) m->next->prev = m->prev; -  if(first_mapping == m) first_mapping = 0; +     -  +  free((char *)m->hash);    free((char *)m); -  +  +  GC_FREE();   }    - static void order_mapping(struct mapping *m) + /* This function is used to rehash a mapping without loosing the internal +  * order in each hash chain. This is to prevent mappings from becoming +  * very inefficient just after being rehashed. +  */ + static void mapping_rehash_backwards(struct mapping *m, struct keypair *p)   { -  INT32 *order; -  order = get_set_order(m->ind); -  if(!order) return; -  m->ind = order_array(m->ind, order); -  m->val = order_array(m->val, order); -  free((char *)order); +  unsigned INT32 h; +  struct keypair *tmp; +  +  if(!p) return; +  mapping_rehash_backwards(m,p->next); +  h=hash_svalue(& p->ind) % m->hashsize; +  tmp=m->free_list; +  m->free_list=tmp->next; +  tmp->next=m->hash[h]; +  m->hash[h]=tmp; +  tmp->ind=p->ind; +  tmp->val=p->val; +  m->size++; +  m->ind_types |= 1 << p->ind.type; +  m->val_types |= 1 << p->val.type;   }    - struct mapping *mkmapping(struct array *ind, struct array *val) + /* This function re-allocates a mapping. It adjusts the max no. of +  * values can be fitted into the mapping. It takes a bit of time to +  * run, but is used seldom enough not to degrade preformance significantly. +  */ + static struct mapping *rehash(struct mapping *m, int new_size)   { -  struct mapping *m; -  m=allocate_mapping(copy_array(ind), copy_array(val)); -  order_mapping(m); + #ifdef DEBUG +  INT32 tmp=m->size; + #endif +  INT32 e,hashsize; +  struct keypair *k,**hash; +  +  hashsize=m->hashsize; +  hash=m->hash; +  +  init_mapping(m, new_size); +  +  for(e=0;e<hashsize;e++) +  mapping_rehash_backwards(m, hash[e]); +  + #ifdef DEBUG +  if(m->size != tmp) +  fatal("Rehash failed, size not same any more.\n"); + #endif +  +  free((char *)hash); +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +     return m;   }    -  + /* This function brings the type fields in the mapping up to speed. +  * I only use it when the type fields MUST be correct, which is not +  * very often. +  */ + void mapping_fix_type_field(struct mapping *m) + { +  INT32 e; +  struct keypair *k; +  TYPE_FIELD ind_types, val_types; +  +  val_types = ind_types = 0; +  +  for(e=0;e<m->hashsize;e++) +  { +  for(k=m->hash[e];k;k=k->next) +  { +  val_types |= 1 << k->val.type; +  ind_types |= 1 << k->ind.type; +  } +  } +  + #ifdef DEBUG +  if(val_types & ~(m->val_types)) +  fatal("Mapping value types out of order!\n"); +  +  if(ind_types & ~(m->ind_types)) +  fatal("Mapping indices types out of order!\n"); + #endif +  m->val_types = val_types; +  m->ind_types = ind_types; + } +  + /* This function inserts key:val into the mapping m. +  * Same as doing m[key]=val; in pike. +  */   void mapping_insert(struct mapping *m, -  struct svalue *ind, -  struct svalue *from) +  struct svalue *key, +  struct svalue *val)   { -  INT32 i; -  i=set_lookup(m->ind, ind); +  unsigned INT32 h; +  struct keypair *k, **prev;    -  if(i < 0) +  h=hash_svalue(key) % m->hashsize; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  if(m->ind_types & (1 << key->type))    { -  i = ~i; -  m->ind=array_insert(m->ind, ind, i); -  m->val=array_insert(m->val, from, i); -  }else{ -  array_set_index(m->ind, i, ind); -  array_set_index(m->val, i, from); +  for(prev= m->hash + h;k=*prev;prev=&k->next) +  { +  if(is_eq(& k->ind, key)) +  { +  *prev=k->next; +  k->next=m->hash[h]; +  m->hash[h]=k; +  +  m->val_types |= 1 << val->type; +  assign_svalue(& k->val, val); +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  return;    }    } -  +  }    - #if 0 - struct array *mapping_indices(struct mapping *m) +  if(!(k=m->free_list))    { -  return m->ind; +  rehash(m, m->size * 2 + 1); +  h=hash_svalue(key) % m->hashsize; +  k=m->free_list;    }    - struct array *mapping_values(struct mapping *m) +  m->free_list=k->next; +  k->next=m->hash[h]; +  m->hash[h]=k; +  m->ind_types |= 1 << key->type; +  m->val_types |= 1 << val->type; +  assign_svalue_no_free(& k->ind, key); +  assign_svalue_no_free(& k->val, val); +  m->size++; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif + } +  + union anything *mapping_get_item_ptr(struct mapping *m, +  struct svalue *key, +  TYPE_T t)   { -  return m->val; +  unsigned INT32 h; +  struct keypair *k, **prev; +  +  h=hash_svalue(key) % m->hashsize; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  +  for(prev= m->hash + h;k=*prev;prev=&k->next) +  { +  if(is_eq(& k->ind, key)) +  { +  *prev=k->next; +  k->next=m->hash[h]; +  m->hash[h]=k; +  +  if(k->val.type == t) return & ( k->val.u ); +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  +  return 0;    } -  +  } +  +  if(!(k=m->free_list)) +  { +  rehash(m, m->size * 2 + 1); +  h=hash_svalue(key) % m->hashsize; +  k=m->free_list; +  } +  +  m->free_list=k->next; +  k->next=m->hash[h]; +  m->hash[h]=k; +  assign_svalue_no_free(& k->ind, key); +  k->val.type=T_INT; +  k->val.subtype=NUMBER_NUMBER; +  k->val.u.integer=0; +  m->ind_types |= 1 << key->type; +  m->val_types |= BIT_INT; +  m->size++; +  +  if(t != T_INT) return 0; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m);   #endif    - void map_delete(struct mapping *m,struct svalue *ind) +  return & ( k->val.u ); + } +  + void map_delete(struct mapping *m, +  struct svalue *key)   { -  INT32 i; -  i=set_lookup(m->ind, ind); +  unsigned INT32 h; +  struct keypair *k, **prev;    -  if(i >= 0) +  h=hash_svalue(key) % m->hashsize; +  +  for(prev= m->hash + h;k=*prev;prev=&k->next)    { -  m->ind=array_remove(m->ind, i); -  m->val=array_remove(m->val, i); +  if(is_eq(& k->ind, key)) +  { +  *prev=k->next; +  free_svalue(& k->ind); +  free_svalue(& k->val); +  k->next=m->free_list; +  m->free_list=k; +  m->size--; +  +  if(m->size < (m->hashsize + 1) * MIN_LINK_LENGTH) +  rehash(m, MAP_SLOTS(m->size)); +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  return;    }    } -  + }      void check_mapping_for_destruct(struct mapping *m)   { -  INT32 i; -  check_array_for_destruct(m->val); -  while( (i=array_find_destructed_object(m->ind)) >= 0) +  INT32 e; +  struct keypair *k, **prev; +  TYPE_FIELD ind_types, val_types; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  +  if((m->ind_types | m->val_types) & BIT_OBJECT)    { -  m->ind=array_remove(m->ind, i); -  m->val=array_remove(m->val, i); +  val_types = ind_types = 0; +  m->val_types |= BIT_INT; +  for(e=0;e<m->hashsize;e++) +  { +  for(prev= m->hash + e;k=*prev;prev=&k->next) +  { +  check_destructed(& k->val); +  +  if(k->ind.type == T_OBJECT && !k->ind.u.object->prog) +  { +  *prev=k->next; +  free_svalue(& k->ind); +  free_svalue(& k->val); +  k->next=m->free_list; +  m->free_list=k; +  m->size--; +  }else{ +  val_types |= 1 << k->val.type; +  ind_types |= 1 << k->ind.type;    }    } -  +  } +  if(MAP_SLOTS(m->size) < m->hashsize * MIN_LINK_LENGTH) +  rehash(m, MAP_SLOTS(m->size));    - union anything *mapping_get_item_ptr(struct mapping *m, -  struct svalue *ind, -  TYPE_T t) +  m->val_types = val_types; +  m->ind_types = ind_types; + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  } + } +  + struct svalue *low_mapping_lookup(struct mapping *m, +  struct svalue *key)   { -  INT32 i; -  i=set_lookup(m->ind, ind); -  if(i < 0) +  unsigned INT32 h; +  struct keypair *k, **prev; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  +  if((1 << key->type) & m->ind_types)    { -  struct svalue from; -  from.type=T_INT; -  from.subtype=NUMBER_NUMBER; -  from.u.integer=0; -  i = ~i; -  m->ind=array_insert(m->ind, ind, i); -  m->val=array_insert(m->val, &from, i); +  h=hash_svalue(key) % m->hashsize; +  +  for(prev= m->hash + h;k=*prev;prev=&k->next) +  { +  if(is_eq(& k->ind, key)) +  { +  *prev=k->next; +  k->next=m->hash[h]; +  m->hash[h]=k; +  +  return &k->val;    } -  return low_array_get_item_ptr(m->val, i, t); +     } -  +  }    - struct mapping *copy_mapping(struct mapping *tmp) +  return 0; + } +  + void mapping_index_no_free(struct svalue *dest, +  struct mapping *m, +  struct svalue *key)   { -  check_mapping_for_destruct(tmp); -  return allocate_mapping(copy_array(tmp->ind),copy_array(tmp->val)); +  struct svalue *p; +  +  if(p=low_mapping_lookup(m,key)) +  { +  if(p->type==T_INT) +  p->subtype=NUMBER_NUMBER; +  +  assign_svalue_no_free(dest, p); +  }else{ +  dest->type=T_INT; +  dest->u.integer=0; +  dest->subtype=NUMBER_UNDEFINED;    } -  + }    - struct mapping *merge_mappings(struct mapping *a, -  struct mapping *b, -  INT32 operator) + struct array *mapping_indices(struct mapping *m)   { -  struct mapping *ret; +  INT32 e; +  struct array *a; +  struct svalue *s; +  struct keypair *k; +  +  a=allocate_array(m->size); +  s=ITEM(a); +  +  LOOP(m) assign_svalue(s++, & k->ind); +  +  a->type_field = m->ind_types; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  +  return a; + } +  + struct array *mapping_values(struct mapping *m) + { +  INT32 e; +  struct keypair *k; +  struct array *a; +  struct svalue *s; +  +  a=allocate_array(m->size); +  s=ITEM(a); +  +  LOOP(m) assign_svalue(s++, & k->val); +  +  a->type_field = m->val_types; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  +  return a; + } +  + void mapping_replace(struct mapping *m,struct svalue *from, struct svalue *to) + { +  INT32 e; +  struct keypair *k; +  +  LOOP(m) +  if(is_eq(& k->val, from)) +  assign_svalue(& k->val, to); +  +  m->val_types |= 1 << to->type; +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m); + #endif +  + } +  + struct mapping *mkmapping(struct array *ind, struct array *val) + { +  struct mapping *m; +  struct svalue *i,*v; +  INT32 e; +  + #ifdef DEBUG +  if(ind->size != val->size) +  fatal("mkmapping on different sized arrays.\n"); + #endif +  +  m=allocate_mapping(MAP_SLOTS(ind->size)); +  i=ITEM(ind); +  v=ITEM(val); +  for(e=0;e<ind->size;e++) mapping_insert(m, i++, v++); +  +  return m; + } +  + struct mapping *copy_mapping(struct mapping *m) + { +  INT32 e; +  struct mapping *n; +  struct keypair *k; +  +  n=allocate_mapping(MAP_SLOTS(m->size)); +  +  LOOP(m) mapping_insert(n, &k->ind, &k->val); +  +  return m; + } +  + struct mapping *merge_mappings(struct mapping *a, struct mapping *b, INT32 op) + { +  struct array *ai, *av; +  struct array *bi, *bv; +  struct array *ci, *cv;    INT32 *zipper; -  +  struct mapping *m;    -  check_mapping_for_destruct(a); -  check_mapping_for_destruct(b); +  ai=mapping_indices(a); +  av=mapping_values(a); +  zipper=get_set_order(ai); +  order_array(ai, zipper); +  order_array(av, zipper); +  free((char *)zipper);    -  zipper=merge(a->ind,b->ind,operator); -  ret=allocate_mapping(array_zip(a->ind,b->ind,zipper), -  array_zip(a->val,b->val,zipper)); +  bi=mapping_indices(b); +  bv=mapping_values(b); +  zipper=get_set_order(bi); +  order_array(bi, zipper); +  order_array(bv, zipper); +  free((char *)zipper);    -  +  zipper=merge(ai,bi,op); +  +  ci=array_zip(ai,bi,zipper); +  free_array(ai); +  free_array(bi); +  +  cv=array_zip(av,bv,zipper); +  free_array(av); +  free_array(bv); +     free((char *)zipper); -  return ret; +  +  m=mkmapping(ci, cv); +  free_array(ci); +  free_array(cv); +  +  return m;   }    - struct mapping *add_mappings(struct svalue *argp,INT32 args) + struct mapping *add_mappings(struct svalue *argp, INT32 args)   {    struct mapping *ret,*a,*b;    switch(args)    { -  case 0: -  ret=allocate_mapping(allocate_array_no_init(0,0,T_MIXED), -  allocate_array_no_init(0,0,T_MIXED)); -  break; -  -  case 1: -  ret=copy_mapping(argp->u.mapping); -  break; -  -  case 2: -  ret=merge_mappings(argp[0].u.mapping,argp[1].u.mapping,OP_ADD); -  break; -  +  case 0: return allocate_mapping(0); +  case 1: return copy_mapping(argp->u.mapping); +  case 2: return merge_mappings(argp[0].u.mapping, argp[1].u.mapping, OP_ADD);    case 3:    a=merge_mappings(argp[0].u.mapping,argp[1].u.mapping,OP_ADD);    ret=merge_mappings(a,argp[2].u.mapping,OP_ADD);    free_mapping(a); -  break; -  +  return ret;    default:    a=add_mappings(argp,args/2);    b=add_mappings(argp+args/2,args-args/2);    ret=merge_mappings(a,b,OP_ADD);    free_mapping(a);    free_mapping(b); -  break; -  } -  +     return ret;    } -  + }      int mapping_equal_p(struct mapping *a, struct mapping *b, struct processing *p)   { -  if(a == b) return 1; +  struct processing curr; +  struct keypair *k; +  INT32 e; +  +  if(a==b) return 1; +  if(a->size != b->size) return 0; +  +  curr.pointer_a = a; +  curr.pointer_b = b; +  curr.next = p; +  +  for( ;p ;p=p->next) +  if(p->pointer_a == (void *)a && p->pointer_b == (void *)b) +  return 1; +     check_mapping_for_destruct(a);    check_mapping_for_destruct(b);    -  return array_equal_p(a->ind, b->ind, p) -  && array_equal_p(a->val, b->val, p); +  LOOP(a) +  { +  struct svalue *s; +  if(s=low_mapping_lookup(b, & k->ind)) +  { +  if(!low_is_equal(s, &k->val, &curr)) return 0; +  }else{ +  return 0;    } -  +  } +  return 1; + }      void describe_mapping(struct mapping *m,struct processing *p,int indent)   {    struct processing doing;    INT32 e,d; -  +  struct keypair *k;    char buf[40];    -  if(! m->ind->size) +  if(! m->size)    {    my_strcat("([ ])");    return;    }       doing.next=p;    doing.pointer_a=(void *)m;    for(e=0;p;e++,p=p->next)    {    if(p->pointer_a == (void *)m)    {    sprintf(buf,"@%ld",(long)e);    my_strcat(buf);    return;    }    }    -  sprintf(buf,"([ /* %ld elements */\n",(long) m->ind->size); +  sprintf(buf,"([ /* %ld elements */\n",(long) m->size);    my_strcat(buf); -  for(e=0;e<m->ind->size;e++) +  +  d=0; +  +  LOOP(m)    { -  if(e) my_strcat(",\n"); +  if(!d) +  { +  my_strcat(",\n"); +  d=1; +  }    for(d=0; d<indent; d++) my_putchar(' '); -  describe_index(m->ind, e, &doing, indent+2); +  describe_svalue(& k->ind, indent+2, p);    my_putchar(':'); -  describe_index(m->val, e, &doing, indent+2); +  describe_svalue(& k->val, indent+2, p);    } -  +     my_putchar('\n');    for(e=2; e<indent; e++) my_putchar(' ');    my_strcat("])");   }      node * make_node_from_mapping(struct mapping *m)   { -  if(check_that_array_is_constant(m->ind) && -  check_that_array_is_constant(m->val)) +  struct keypair *k; +  INT32 e; +  +  mapping_fix_type_field(m); +  +  if((m->ind_types | m->val_types) & (BIT_FUNCTION | BIT_OBJECT))    { -  +  struct array *ind, *val; +  node *n; +  ind=mapping_indices(m); +  val=mapping_indices(m); +  n=mkefuncallnode("mkmapping",mknode(F_ARG_LIST,make_node_from_array(ind),make_node_from_array(val))); +  free_array(ind); +  free_array(val); +  return n; +  }else{    struct svalue s;    s.type=T_MAPPING;    s.subtype=0;    s.u.mapping=m;    return mkconstantsvaluenode(&s); -  }else{ -  return mkefuncallnode("mkmapping",mknode(F_ARG_LIST,make_node_from_array(m->ind),make_node_from_array(m->val))); +     }   }      void f_m_delete(INT32 args)   {    if(args < 2)    error("Too few arguments to m_delete.\n");    if(sp[-args].type != T_MAPPING)    error("Bad argument to to m_delete.\n");       map_delete(sp[-args].u.mapping,sp+1-args);    pop_n_elems(args-1);   }      void f_aggregate_mapping(INT32 args)   {    INT32 e; -  struct array *ind,*val; -  struct svalue *s; +  struct keypair *k;    struct mapping *m;       if(args & 1)    error("Uneven number of arguments to aggregage_mapping.\n");    -  ind=allocate_array_no_init(args/2,0,T_MIXED); -  val=allocate_array_no_init(args/2,0,T_MIXED); +  m=allocate_mapping(MAP_SLOTS(args / 2));    -  s=sp-args; -  for(e=0;e<args/2;e++) -  { -  ITEM(ind)[e]=*(s++); -  ITEM(val)[e]=*(s++); +  for(e=-args;e<0;e+=2) mapping_insert(m, sp+e, sp+e+1); +  pop_n_elems(args); +  push_mapping(m);   } -  sp-=args; -  m=allocate_mapping(ind,val); -  order_mapping(m); -  sp->u.mapping=m; -  sp->type=T_MAPPING; -  sp++; - } +       struct mapping *copy_mapping_recursively(struct mapping *m,    struct processing *p)   {    struct processing doing;    struct mapping *ret; -  +  INT32 e; +  struct keypair *k;       doing.next=p;    doing.pointer_a=(void *)m;    for(;p;p=p->next)    {    if(p->pointer_a == (void *)m)    {    ret=(struct mapping *)p->pointer_b;    ret->refs++;    return ret;    }    }    -  ret=allocate_mapping(0,0); -  doing.pointer_b=(void *)ret; +  ret=allocate_mapping(MAP_SLOTS(m->size)); +  doing.pointer_b=ret;    -  ret->ind=copy_array_recursively(m->ind,&doing); -  ret->val=copy_array_recursively(m->val,&doing); +  check_stack(2);    -  order_mapping(ret); +  LOOP(m) +  { +  copy_svalues_recursively_no_free(sp,&k->ind, 1, p); +  sp++; +  copy_svalues_recursively_no_free(sp,&k->val, 1, p); +  sp++;    -  +  mapping_insert(ret, sp-2, sp-1); +  pop_n_elems(2); +  } +     return ret;   }    -  +    void mapping_search_no_free(struct svalue *to,    struct mapping *m,    struct svalue *look_for,    struct svalue *start)   { -  INT32 start_pos; -  start_pos=0; +  unsigned INT32 h; +  struct keypair *k; +  +  h=0; +  k=m->hash[h];    if(start)    { -  start_pos=set_lookup(m->ind, start); -  if(start_pos < 0) +  h=hash_svalue(start) % m->hashsize; +  for(k=m->hash[h];k;k=k->next) +  if(is_eq(&k->ind, start)) +  break; +  +  if(!k)    {    to->type=T_INT;    to->subtype=NUMBER_UNDEFINED;    to->u.integer=0;    return;    } -  +  k=k->next;    } -  start_pos=array_search(m->val,look_for,start_pos); -  if(start_pos < 0) +  +  while(h < (unsigned INT32)m->hashsize)    { -  +  while(k) +  { +  if(is_eq(look_for, &k->val)) +  { +  assign_svalue_no_free(to,&k->ind); +  return; +  } +  k=k->next; +  } +  k=m->hash[++h]; +  } +     to->type=T_INT;    to->subtype=NUMBER_UNDEFINED;    to->u.integer=0; -  return; +    } -  array_index_no_free(to,m->ind,start_pos); - } +     -  +    #ifdef DEBUG    - void check_mapping(struct mapping *m,int pass) + void check_mapping(struct mapping *m)   { -  if(pass) -  { -  if(checked((void *)m,0) != m->refs) -  fatal("Mapping has wrong number of refs.\n"); -  return; -  } -  +     if(m->refs <=0)    fatal("Mapping has zero refs.\n");       if(m->next && m->next->prev != m)    fatal("Mapping ->next->prev != mapping.\n");       if(m->prev)    {    if(m->prev->next != m)    fatal("Mapping ->prev->next != mapping.\n");    }else{    if(first_mapping != m)    fatal("Mapping ->prev == 0 but first_mapping != mapping.\n");    } -  checked((void *)m->ind,1); -  checked((void *)m->val,1); +  +  if(m->hashsize < 0) +  fatal("Assert: I don't think he's going to make it Jim.\n"); +  +  if(m->size < 0) +  fatal("Core breach, evacuate ship!\n"); +  +  if(m->size > (m->hashsize + 3) * AVG_LINK_LENGTH) +  fatal("Pretty mean hashtable there buster!.\n"); +  +  if(m->size < (m->hashsize - 3) * MIN_LINK_LENGTH) +  fatal("Hashsize is too small for mapping.\n"); +  +  if(m->size > 0 && (!m->ind_types || !m->val_types)) +  fatal("Mapping type fields are... wrong.\n"); +  +  if(!m->hash) +  fatal("Hey! where did my hashtable go??\n"); +    }    - void check_all_mappings(int pass) + void check_all_mappings()   {    struct mapping *m;    for(m=first_mapping;m;m=m->next) -  check_mapping(m,pass); +  check_mapping(m); + } + #endif    -  if(!pass) -  checked((void *)first_mapping,1); +  + #ifdef GC2 +  + void gc_mark_mapping_as_referenced(struct mapping *m) + { +  INT32 e; +  struct keypair *k; +  +  if(gc_mark(m)) +  { +  if((m->ind_types | m->val_types) & BIT_COMPLEX) +  { +  LOOP(m) +  { +  gc_mark_svalues(&k->ind, 1); +  gc_mark_svalues(&k->val, 1);    } -  +  } +  } + } +  + void gc_check_all_mappings() + { +  INT32 e; +  struct keypair *k; +  struct mapping *m; +  +  for(m=first_mapping;m;m=m->next) +  { +  if((m->ind_types | m->val_types) & BIT_COMPLEX) +  { +  check_mapping_for_destruct(m); +  LOOP(m) +  { +  gc_check_svalues(&k->ind, 1); +  gc_check_svalues(&k->val, 1); +  } +  + #ifdef DEBUG +  if(d_flag > 1) check_mapping_type_fields(m);   #endif -  +  +  } +  } + } +  + void gc_mark_all_mappings() + { +  struct mapping *m; +  for(m=first_mapping;m;m=m->next) +  if(gc_is_referenced(m)) +  gc_mark_mapping_as_referenced(m); + } +  + void gc_free_all_unreferenced_mappings() + { +  INT32 e; +  struct keypair *k; +  struct mapping *m,*next; +  +  for(m=first_mapping;m;m=next) +  { +  if(gc_do_free(m)) +  { +  m->refs++; +  +  for(e=0;e<m->hashsize;e++) +  { +  k=m->hash[e]; +  while(k) +  { +  free_svalue(&k->ind); +  free_svalue(&k->val); +  +  if(k->next) +  { +  k = k->next; +  } else { +  k->next=m->free_list; +  m->free_list=m->hash[e]; +  m->hash[e]=0; +  break; +  } +  } +  } +  m->size=0; +  +  next=m->next; +  +  free_mapping(m); +  }else{ +  next=m->next; +  } +  } + } +  + #endif /* GC2 */ +  + void zap_all_mappings() + { +  INT32 e; +  struct keypair *k; +  struct mapping *m,*next; +  +  for(m=first_mapping;m;m=next) +  { +  m->refs++; +  +  for(e=0;e<m->hashsize;e++) +  { +  for(k=m->hash[e];k;k=k->next) +  { +  free_svalue(&k->ind); +  free_svalue(&k->val); +  } +  k->next=m->free_list; +  m->hash[e]=0; +  } +  m->size=0; +  +  next=m->next; +  +  free_mapping(m); +  } + }