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