From 088e2ecb37a9d537dedf4488539880fc973bd907 Mon Sep 17 00:00:00 2001
From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org>
Date: Thu, 12 Feb 1998 02:25:28 +0100
Subject: [PATCH] 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
---
 lib/modules/Array.pmod  |   8 +-
 src/array.c             |   2 +-
 src/array.h             |   1 +
 src/builtin_functions.c | 283 +++++++++++++++++++++++++++++++++++++++-
 src/version.c           |   2 +-
 5 files changed, 292 insertions(+), 4 deletions(-)

diff --git a/lib/modules/Array.pmod b/lib/modules/Array.pmod
index f806cc9064..9efb4a2877 100644
--- a/lib/modules/Array.pmod
+++ b/lib/modules/Array.pmod
@@ -1,5 +1,11 @@
 #define error(X) throw( ({ (X), backtrace()[0..sizeof(backtrace())-2] }) )
 
+constant diff = __builtin.diff;
+constant diff_longest_sequence = __builtin.diff_longest_sequence;
+constant diff_compare_table = __builtin.diff_compare_table;
+
+constant sort = __builtin.sort;
+
 mixed map(mixed arr, mixed fun, mixed ... args)
 {
   int e;
@@ -178,4 +184,4 @@ array transpose(array x)
   array ret=allocate(sizeof(x[0]));
   for(int e=0;e<sizeof(x[0]);e++) ret[e]=column(x,e);
   return ret;
-}
\ No newline at end of file
+}
diff --git a/src/array.c b/src/array.c
index c13b92ca1c..b1cf7c100f 100644
--- a/src/array.c
+++ b/src/array.c
@@ -268,7 +268,7 @@ struct array *array_insert(struct array *v,struct svalue *s,INT32 index)
 /*
  * resize array, resize an array destructively
  */
-static struct array *resize_array(struct array *a, INT32 size)
+struct array *resize_array(struct array *a, INT32 size)
 {
   if(a->size == size) return a;
   if(size > a->size)
diff --git a/src/array.h b/src/array.h
index ef2851883a..a9f69a6a64 100644
--- a/src/array.h
+++ b/src/array.h
@@ -63,6 +63,7 @@ typedef short_cmpfun (*cmpfun_getter)(TYPE_T);
 struct array *low_allocate_array(INT32 size,INT32 extra_space);
 void really_free_array(struct array *v);
 void do_free_array(struct array *a);
+struct array *resize_array(struct array *a, INT32 size);
 void array_index_no_free(struct svalue *s,struct array *v,INT32 index);
 void array_index(struct svalue *s,struct array *v,INT32 index);
 void simple_array_index_no_free(struct svalue *s,
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 23e14ba69c..cc15c3a9ad 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -4,7 +4,7 @@
 ||| 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,6 +1571,282 @@ void f_glob(INT32 args)
   }
 }
 
+/**** 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,5 +2189,10 @@ void init_builtin_efuns(void)
   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);
 }
 
diff --git a/src/version.c b/src/version.c
index 448fa29737..451333ce25 100644
--- a/src/version.c
+++ b/src/version.c
@@ -12,5 +12,5 @@
 void f_version(INT32 args)
 {
   pop_n_elems(args);
-  push_text("Pike v0.6 release 0");
+  push_text("Pike v0.6 release 0 I");
 }
-- 
GitLab