Branch: Tag:

1998-02-12

1998-02-12 01:25:28 by Mirar (Pontus Hagland) <pike@sort.mirar.org>

Array.diff (etc) added!

Rev: lib/modules/Array.pmod:1.8
Rev: src/array.c:1.28
Rev: src/array.h:1.9
Rev: src/builtin_functions.c:1.69
Rev: src/version.c:1.26

4:   ||| See the files COPYING and DISCLAIMER for more information.   \*/   #include "global.h" - RCSID("$Id: builtin_functions.c,v 1.68 1998/02/10 15:45:52 per Exp $"); + RCSID("$Id: builtin_functions.c,v 1.69 1998/02/12 01:25:25 mirar Exp $");   #include "interpret.h"   #include "svalue.h"   #include "pike_macros.h"
1571:    }   }    + /**** diff ************************************************************/ +  + static struct array* diff_compare_table(struct array *a,struct array *b) + { +  struct array *res; +  struct mapping *map; +  struct svalue *pval; +  int i; +  +  map=allocate_mapping(256); +  push_mapping(map); /* in case of out of memory */ +  +  for (i=0; i<b->size; i++) +  { +  pval=low_mapping_lookup(map,b->item+i); +  if (!pval) +  { +  struct svalue val; +  val.type=T_ARRAY; +  val.u.array=low_allocate_array(1,1); +  val.u.array->item[0].type=T_INT; +  val.u.array->item[0].subtype=NUMBER_NUMBER; +  val.u.array->item[0].u.integer=i; +  mapping_insert(map,b->item+i,&val); +  free_svalue(&val); +  } +  else +  { +  pval->u.array=resize_array(pval->u.array,pval->u.array->size+1); +  pval->u.array->item[pval->u.array->size-1].type=T_INT; +  pval->u.array->item[pval->u.array->size-1].subtype=NUMBER_NUMBER; +  pval->u.array->item[pval->u.array->size-1].u.integer=i; +  } +  } +  +  res=low_allocate_array(a->size,0); +  +  for (i=0; i<a->size; i++) +  { +  pval=low_mapping_lookup(map,a->item+i); +  if (!pval) +  { +  res->item[i].type=T_ARRAY; +  (res->item[i].u.array=&empty_array)->refs++; +  } +  else +  { +  assign_svalue(res->item+i,pval); +  } +  } +  +  pop_stack(); +  return res; + } +  + struct diff_link { int x,l; }; +  + static INLINE int diff_ponder_stack(int x,struct diff_link *dl,int top) + { +  int middle,a,b; +  if (!top || x>dl[top-1].x) return top; +  +  a=0; +  b=top; +  while (b>a) +  { +  middle=(a+b)/2; +  if (dl[middle].x<x) a=middle+1; +  else if (dl[middle].x>x) b=middle; +  else return middle; +  } +  if (a<top && dl[a].x<x) a++; +  return a; + } +  + static struct array* diff_longest_sequence(struct array *cmptbl) + { +  struct diff_link *stack; +  struct diff_link *links; +  int i,j,top=0,l=0,ltop=-1,lsize=0; +  struct array *a; +  +  for (i=0; i<cmptbl->size; i++) +  lsize+=cmptbl->item[i].u.array->size; +  +  stack=malloc(sizeof(struct diff_link)*cmptbl->size); +  links=malloc(sizeof(struct diff_link)*lsize); +  +  if (!stack || !links) +  { +  if (stack) free(stack); +  if (links) free(links); +  error("out of memory\n"); +  } +  +  for (i=0; i<cmptbl->size; i++) +  for (j=cmptbl->item[i].u.array->size; j--;) +  { +  int x=cmptbl->item[i].u.array->item[j].u.integer; +  int pos; +  links[l].x=x; +  pos=diff_ponder_stack(x,stack,top); +  if (pos==top || stack[pos].x!=x) +  { +  if (pos==top) { top++; ltop=l; } +  if (pos!=0) links[l].l=stack[pos-1].l; +  else links[l].l=-1; +  stack[pos].x=x; +  stack[pos].l=l; +  } +  l++; +  } +  +  /* FIXME(?) memory unfreed upon error here */ +  a=low_allocate_array(top,0); +  while (ltop!=-1) +  { +  a->item[--top].u.integer=links[ltop].x; +  ltop=links[ltop].l; +  } +  +  free(stack); +  free(links); +  return a; + } +  + static struct array* diff_build(struct array *a, +  struct array *b, +  struct array *seq) + { +  struct array *ad,*bd; +  int bi,ai,lbi,lai,i,eqstart; +  +  b->refs++; +  a->refs++; /* protect from getting optimized... */ +  +  /* FIXME(?) memory unfreed upon error here (and later) */ +  ad=low_allocate_array(0,32); +  bd=low_allocate_array(0,32); +  +  eqstart=0; +  lbi=bi=ai=-1; +  for (i=0; i<seq->size; i++) +  { +  bi=seq->item[i].u.integer; +  +  if (bi!=lbi+1 || !is_equal(a->item+ai+1,b->item+bi)) +  { +  /* insert the equality */ +  if (lbi>=eqstart) +  { +  struct array *eq; +  eq=slice_array(b,eqstart,lbi+1); +  push_array(eq); sp--; +  ad=resize_array(ad,ad->size+1); +  bd=resize_array(bd,bd->size+1); +  +  sp->u.refs[0]++; +  ad->item[ad->size-1] = bd->item[bd->size-1] = *sp; +  } +  /* insert the difference */ +  lai=ai; +  ai=array_search(a,b->item+bi,ai+1)-1; +  +  bd=resize_array(bd,bd->size+1); +  ad=resize_array(ad,ad->size+1); +  +  push_array(slice_array(b,lbi+1,bi)); +  bd->item[bd->size-1]=*--sp; +  +  push_array(slice_array(a,lai+1,ai+1)); +  ad->item[ad->size-1]=*--sp; +  +  eqstart=bi; +  } +  ai++; +  lbi=bi; +  } +  +  if (lbi>=eqstart) +  { +  struct array *eq; +  eq=slice_array(b,eqstart,lbi+1); +  push_array(eq); sp--; +  ad=resize_array(ad,ad->size+1); +  bd=resize_array(bd,bd->size+1); +  +  sp->u.refs[0]++; +  ad->item[ad->size-1] = bd->item[bd->size-1] = *sp; +  } +  +  if (b->size>bi+1 || a->size>ai+1) +  { +  ad=resize_array(ad,ad->size+1); +  bd=resize_array(bd,bd->size+1); +  +  push_array(slice_array(b,lbi+1,b->size)); +  bd->item[bd->size-1]=*--sp; +  +  push_array(slice_array(a,ai+1,a->size)); +  ad->item[ad->size-1]=*--sp; +  } +  +  b->refs--; +  a->refs--; /* i know what i'm doing... */ +  +  push_array(ad); +  push_array(bd); +  f_aggregate(2); +  sp--; +  return sp->u.array; + } +  + void f_diff(INT32 args) + { +  struct array *seq; +  struct array *cmptbl; +  struct array *diff; +  +  if (args<2) +  error("Too few arguments to diff().\n"); +  +  if (sp[-args].type!=T_ARRAY || +  sp[1-args].type!=T_ARRAY) +  error("Illegal arguments to diff().\n"); +  +  cmptbl=diff_compare_table(sp[-args].u.array,sp[1-args].u.array); +  push_array(cmptbl); +  seq=diff_longest_sequence(cmptbl); +  push_array(seq); +  +  diff=diff_build(sp[-2-args].u.array,sp[1-2-args].u.array,seq); +  +  pop_n_elems(2+args); +  push_array(diff); + } +  + void f_diff_compare_table(INT32 args) + { +  struct array *cmptbl; +  +  if (args<2) +  error("Too few arguments to diff().\n"); +  +  if (sp[-args].type!=T_ARRAY || +  sp[1-args].type!=T_ARRAY) +  error("Illegal arguments to diff().\n"); +  +  cmptbl=diff_compare_table(sp[-args].u.array,sp[1-args].u.array); +  +  pop_n_elems(args); +  push_array(cmptbl); + } +  + void f_diff_longest_sequence(INT32 args) + { +  struct array *seq; +  struct array *cmptbl; +  struct array *diff; +  +  if (args<2) +  error("Too few arguments to diff().\n"); +  +  if (sp[-args].type!=T_ARRAY || +  sp[1-args].type!=T_ARRAY) +  error("Illegal arguments to diff().\n"); +  +  cmptbl=diff_compare_table(sp[-args].u.array,sp[1-args].u.array); +  push_array(cmptbl); +  seq=diff_longest_sequence(cmptbl); +  pop_n_elems(args+1); +  push_array(seq); + } +  + /**********************************************************************/ +    static struct callback_list memory_usage_callback;      struct callback *add_memory_usage_callback(callback_func call,
1913:    add_efun("encode_value", f_encode_value, "function(mixed:string)", OPT_TRY_OPTIMIZE);    add_efun("decode_value", f_decode_value, "function(string:mixed)", OPT_TRY_OPTIMIZE);    add_efun("object_variablep", f_object_variablep, "function(object,string:int)", OPT_EXTERNAL_DEPEND); +  +  add_function("diff",f_diff,"function(array,array:array(array))",OPT_TRY_OPTIMIZE); +  add_function("diff_longest_sequence",f_diff_longest_sequence,"function(array,array:array(int))",OPT_TRY_OPTIMIZE); +  add_function("diff_compare_table",f_diff_compare_table,"function(array,array:array(array))",OPT_TRY_OPTIMIZE); +  add_function("sort",f_sort,"function(array(mixed),array(mixed)...:array(mixed))",OPT_SIDE_EFFECT);   }