|
|
|
|
|
#include "global.h" |
#include "svalue.h" |
#include "array.h" |
#include "object.h" |
#include "las.h" |
#include "stralloc.h" |
#include "interpret.h" |
#include "language.h" |
#include "error.h" |
#include "pike_types.h" |
#include "fsort.h" |
#include "builtin_functions.h" |
#include "pike_memory.h" |
#include "gc.h" |
#include "main.h" |
|
RCSID("$Id: array.c,v 1.34 1998/04/23 23:58:52 hubbe Exp $"); |
|
struct array empty_array= |
{ |
1, |
&empty_array, |
&empty_array, |
0, |
0, |
0, |
0, |
}; |
|
|
|
|
|
|
|
|
struct array *low_allocate_array(INT32 size,INT32 extra_space) |
{ |
struct array *v; |
INT32 e; |
|
if(size == 0) |
{ |
add_ref(&empty_array); |
return &empty_array; |
} |
|
GC_ALLOC(); |
|
v=(struct array *)malloc(sizeof(struct array)+ |
(size+extra_space-1)*sizeof(struct svalue)); |
if(!v) |
error("Couldn't allocate array, out of memory.\n"); |
|
|
|
v->type_field=BIT_MIXED | BIT_UNFINISHED; |
v->flags=0; |
|
v->malloced_size=size+extra_space; |
v->size=size; |
v->refs=1; |
v->prev=&empty_array; |
v->next=empty_array.next; |
empty_array.next=v; |
v->next->prev=v; |
|
for(e=0;e<v->size;e++) |
{ |
ITEM(v)[e].type=T_INT; |
ITEM(v)[e].subtype=NUMBER_NUMBER; |
ITEM(v)[e].u.integer=0; |
} |
|
return v; |
} |
|
|
|
|
static void array_free_no_free(struct array *v) |
{ |
struct array *next,*prev; |
|
next = v->next; |
prev = v->prev; |
|
v->prev->next=next; |
v->next->prev=prev; |
|
free((char *)v); |
|
GC_FREE(); |
} |
|
|
|
|
void really_free_array(struct array *v) |
{ |
|
#ifdef DEBUG |
if(v == & empty_array) |
fatal("Tried to free the empty_array.\n"); |
#endif |
|
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(v); |
#endif |
|
add_ref(v); |
free_svalues(ITEM(v), v->size, v->type_field); |
v->refs--; |
array_free_no_free(v); |
} |
|
void do_free_array(struct array *a) |
{ |
free_array(a); |
} |
|
|
|
|
void array_index_no_free(struct svalue *s,struct array *v,INT32 index) |
{ |
#ifdef DEBUG |
if(index<0 || index>=v->size) |
fatal("Illegal index in low level index routine.\n"); |
#endif |
|
assign_svalue_no_free(s, ITEM(v) + index); |
} |
|
|
|
|
void array_index(struct svalue *s,struct array *v,INT32 index) |
{ |
#ifdef DEBUG |
if(index<0 || index>=v->size) |
fatal("Illegal index in low level index routine.\n"); |
#endif |
|
add_ref(v); |
assign_svalue(s, ITEM(v) + index); |
free_array(v); |
} |
|
void simple_array_index_no_free(struct svalue *s, |
struct array *a,struct svalue *ind) |
{ |
INT32 i; |
switch(ind->type) |
{ |
case T_INT: |
i=ind->u.integer; |
if(i<0) i+=a->size; |
if(i<0 || i>=a->size) error("Index out of range.\n"); |
array_index_no_free(s,a,i); |
break; |
|
case T_STRING: |
check_stack(4); |
ref_push_array(a); |
assign_svalue_no_free(sp++,ind); |
f_column(2); |
s[0]=sp[-1]; |
sp--; |
break; |
|
default: |
error("Index is not an integer.\n"); |
} |
} |
|
|
|
|
void array_free_index(struct array *v,INT32 index) |
{ |
#ifdef DEBUG |
if(index<0 || index>=v->size) |
fatal("Illegal index in low level free index routine.\n"); |
#endif |
|
free_svalue(ITEM(v) + index); |
} |
|
|
|
|
void array_set_index(struct array *v,INT32 index, struct svalue *s) |
{ |
#ifdef DEBUG |
if(index<0 || index>v->size) |
fatal("Illegal index in low level array set routine.\n"); |
#endif |
|
add_ref(v); |
check_destructed(s); |
|
v->type_field = (v->type_field & ~BIT_UNFINISHED) | 1 << s->type; |
assign_svalue( ITEM(v) + index, s); |
free_array(v); |
} |
|
|
void simple_set_index(struct array *a,struct svalue *ind,struct svalue *s) |
{ |
INT32 i; |
if(ind->type != T_INT) |
error("Index is not an integer.\n"); |
i=ind->u.integer; |
if(i<0) i+=a->size; |
if(i<0 || i>=a->size) error("Index out of range.\n"); |
array_set_index(a,i,s); |
} |
|
|
|
|
struct array *array_insert(struct array *v,struct svalue *s,INT32 index) |
{ |
#ifdef DEBUG |
if(index<0 || index>v->size) |
fatal("Illegal index in low level insert routine.\n"); |
#endif |
|
|
if(v->refs<=1 && v->malloced_size > v->size) |
{ |
MEMMOVE((char *)(ITEM(v)+index+1), |
(char *)(ITEM(v)+index), |
(v->size-index) * sizeof(struct svalue)); |
ITEM(v)[index].type=T_INT; |
#ifdef __CHECKER__ |
ITEM(v)[index].subtype=0; |
ITEM(v)[index].u.refs=0; |
#endif |
v->size++; |
}else{ |
struct array *ret; |
|
ret=allocate_array_no_init(v->size+1, (v->size >> 3) + 1); |
ret->type_field = v->type_field; |
|
MEMCPY(ITEM(ret), ITEM(v), sizeof(struct svalue) * index); |
MEMCPY(ITEM(ret)+index+1, ITEM(v)+index, sizeof(struct svalue) * (v->size-index)); |
ITEM(ret)[index].type=T_INT; |
#ifdef __CHECKER__ |
ITEM(ret)[index].subtype=0; |
ITEM(ret)[index].u.refs=0; |
#endif |
v->size=0; |
free_array(v); |
v=ret; |
} |
|
array_set_index(v,index,s); |
|
return v; |
} |
|
|
|
|
struct array *resize_array(struct array *a, INT32 size) |
{ |
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(a); |
#endif |
|
if(a->size == size) return a; |
if(size > a->size) |
{ |
|
|
if(a->malloced_size >= size) |
{ |
for(;a->size < size; a->size++) |
{ |
ITEM(a)[a->size].type=T_INT; |
ITEM(a)[a->size].subtype=NUMBER_NUMBER; |
ITEM(a)[a->size].u.integer=0; |
} |
a->type_field |= BIT_INT; |
return a; |
}else{ |
struct array *ret; |
ret=low_allocate_array(size, (size>>3)+1); |
MEMCPY(ITEM(ret),ITEM(a),sizeof(struct svalue)*a->size); |
ret->type_field = a->type_field | BIT_INT; |
a->size=0; |
free_array(a); |
return ret; |
} |
}else{ |
|
free_svalues(ITEM(a)+size, a->size - size, a->type_field); |
a->size = size; |
return a; |
} |
} |
|
|
|
|
struct array *array_shrink(struct array *v,INT32 size) |
{ |
struct array *a; |
|
#ifdef DEBUG |
if(v->refs>2) |
fatal("Array shrink on array with many references.\n"); |
|
if(size > v->size) |
fatal("Illegal argument to array_shrink.\n"); |
#endif |
|
if(size*2 < v->malloced_size + 4) |
{ |
a=allocate_array_no_init(size,0); |
a->type_field = v->type_field; |
|
free_svalues(ITEM(v) + size, v->size - size, v->type_field); |
MEMCPY(ITEM(a), ITEM(v), size*sizeof(struct svalue)); |
v->size=0; |
free_array(v); |
return a; |
}else{ |
free_svalues(ITEM(v) + size, v->size - size, v->type_field); |
v->size=size; |
return v; |
} |
} |
|
|
|
|
struct array *array_remove(struct array *v,INT32 index) |
{ |
struct array *a; |
|
#ifdef DEBUG |
if(v->refs>1) |
fatal("Array remove on array with many references.\n"); |
|
if(index<0 || index >= v->size) |
fatal("Illegal argument to array_remove.\n"); |
#endif |
|
array_free_index(v, index); |
if(v->size!=1 && |
v->size*2 + 4 < v->malloced_size ) |
{ |
a=allocate_array_no_init(v->size-1, 0); |
a->type_field = v->type_field; |
|
if(index>0) |
MEMCPY(ITEM(a), ITEM(v), index*sizeof(struct svalue)); |
if(v->size-index>1) |
MEMCPY(ITEM(a)+index, |
ITEM(v)+index+1, |
(v->size-index-1)*sizeof(struct svalue)); |
v->size=0; |
free_array(v); |
return a; |
}else{ |
if(v->size-index>1) |
{ |
MEMMOVE((char *)(ITEM(v)+index), |
(char *)(ITEM(v)+index+1), |
(v->size-index-1)*sizeof(struct svalue)); |
} |
v->size--; |
return v; |
} |
} |
|
|
|
|
|
INT32 array_search(struct array *v, struct svalue *s,INT32 start) |
{ |
INT32 e; |
#ifdef DEBUG |
if(start<0) |
fatal("Start of find_index is less than zero.\n"); |
#endif |
|
check_destructed(s); |
|
|
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(v); |
#endif |
if(v->type_field & (1 << s->type)) |
{ |
if(start) |
{ |
for(e=start;e<v->size;e++) |
if(is_eq(ITEM(v)+e,s)) return e; |
}else{ |
TYPE_FIELD t=0; |
for(e=0;e<v->size;e++) |
{ |
if(is_eq(ITEM(v)+e,s)) return e; |
t |= 1<<ITEM(v)[e].type; |
} |
v->type_field=t; |
} |
} |
return -1; |
} |
|
|
|
|
|
struct array *slice_array(struct array *v,INT32 start,INT32 end) |
{ |
struct array *a; |
|
#ifdef DEBUG |
if(start > end || end>v->size || start<0) |
fatal("Illegal arguments to slice_array()\n"); |
|
if(d_flag > 1) array_check_type_field(v); |
#endif |
|
if(start==0 && v->refs==1) |
{ |
add_ref(v); |
return array_shrink(v,end); |
} |
|
a=allocate_array_no_init(end-start,0); |
a->type_field = v->type_field; |
|
assign_svalues_no_free(ITEM(a), ITEM(v)+start, end-start, v->type_field); |
|
return a; |
} |
|
|
|
|
|
struct array *friendly_slice_array(struct array *v,INT32 start,INT32 end) |
{ |
struct array *a; |
|
#ifdef DEBUG |
if(start > end || end>v->size || start<0) |
fatal("Illegal arguments to slice_array()\n"); |
|
if(d_flag > 1) array_check_type_field(v); |
#endif |
|
a=allocate_array_no_init(end-start,0); |
a->type_field = v->type_field; |
|
assign_svalues_no_free(ITEM(a), ITEM(v)+start, end-start, v->type_field); |
|
return a; |
} |
|
|
|
|
struct array *copy_array(struct array *v) |
{ |
struct array *a; |
|
a=allocate_array_no_init(v->size, 0); |
a->type_field = v->type_field; |
|
assign_svalues_no_free(ITEM(a), ITEM(v), v->size, v->type_field); |
|
return a; |
} |
|
|
|
|
void check_array_for_destruct(struct array *v) |
{ |
int e; |
INT16 types; |
|
types = 0; |
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(v); |
#endif |
if(v->type_field & (BIT_OBJECT | BIT_FUNCTION)) |
{ |
for(e=0; e<v->size; e++) |
{ |
if((ITEM(v)[e].type == T_OBJECT || |
(ITEM(v)[e].type == T_FUNCTION && |
ITEM(v)[e].subtype!=FUNCTION_BUILTIN)) && |
(!ITEM(v)[e].u.object->prog)) |
{ |
free_svalue(ITEM(v)+e); |
ITEM(v)[e].type=T_INT; |
ITEM(v)[e].subtype=NUMBER_DESTRUCTED; |
ITEM(v)[e].u.integer=0; |
|
types |= BIT_INT; |
}else{ |
types |= 1<<ITEM(v)[e].type; |
} |
} |
v->type_field = types; |
} |
} |
|
|
|
|
|
|
INT32 array_find_destructed_object(struct array *v) |
{ |
INT32 e; |
TYPE_FIELD types; |
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(v); |
#endif |
if(v->type_field & (BIT_OBJECT | BIT_FUNCTION)) |
{ |
types=0; |
for(e=0; e<v->size; e++) |
{ |
if((ITEM(v)[e].type == T_OBJECT || |
(ITEM(v)[e].type == T_FUNCTION && |
ITEM(v)[e].subtype!=FUNCTION_BUILTIN)) && |
(!ITEM(v)[e].u.object->prog)) |
return e; |
types |= 1<<ITEM(v)[e].type; |
} |
v->type_field = types; |
} |
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(v); |
#endif |
return -1; |
} |
|
static struct svalue *current_array_p; |
static cmpfun current_cmpfun; |
|
static int internal_cmpfun(INT32 *a,INT32 *b) |
{ |
return current_cmpfun(current_array_p + *a, current_array_p + *b); |
} |
|
INT32 *get_order(struct array *v, cmpfun fun) |
{ |
INT32 e, *current_order; |
|
if(!v->size) return 0; |
|
current_cmpfun = fun; |
current_order=(INT32 *)xalloc(v->size * sizeof(INT32)); |
for(e=0; e<v->size; e++) current_order[e]=e; |
|
if(current_array_p) free((char *)current_array_p); |
current_array_p = ITEM(v); |
current_cmpfun = fun; |
fsort((char *)current_order, |
v->size, |
sizeof(INT32), |
(fsortfun)internal_cmpfun); |
|
current_array_p=0; |
return current_order; |
} |
|
static int set_svalue_cmpfun(struct svalue *a, struct svalue *b) |
{ |
INT32 tmp; |
if((tmp=(a->type - b->type))) return tmp; |
switch(a->type) |
{ |
case T_FLOAT: |
if(a->u.float_number < b->u.float_number) return -1; |
if(a->u.float_number > b->u.float_number) return 1; |
return 0; |
|
case T_FUNCTION: |
if(a->u.refs < b->u.refs) return -1; |
if(a->u.refs > b->u.refs) return 1; |
return a->subtype - b->subtype; |
|
case T_INT: |
if(a->u.integer < b->u.integer) return -1; |
if(a->u.integer > b->u.integer) return 1; |
return 0; |
|
default: |
if(a->u.refs < b->u.refs) return -1; |
if(a->u.refs > b->u.refs) return 1; |
return 0; |
} |
} |
|
static int switch_svalue_cmpfun(struct svalue *a, struct svalue *b) |
{ |
if(a->type != b->type) return a->type - b->type; |
switch(a->type) |
{ |
case T_INT: |
if(a->u.integer < b->u.integer) return -1; |
if(a->u.integer > b->u.integer) return 1; |
return 0; |
|
case T_FLOAT: |
if(a->u.float_number < b->u.float_number) return -1; |
if(a->u.float_number > b->u.float_number) return 1; |
return 0; |
|
case T_STRING: |
return my_strcmp(a->u.string, b->u.string); |
|
default: |
return set_svalue_cmpfun(a,b); |
} |
} |
|
static int alpha_svalue_cmpfun(struct svalue *a, struct svalue *b) |
{ |
if(a->type == b->type) |
{ |
switch(a->type) |
{ |
case T_INT: |
if(a->u.integer < b->u.integer) return -1; |
if(a->u.integer > b->u.integer) return 1; |
return 0; |
|
case T_FLOAT: |
if(a->u.float_number < b->u.float_number) return -1; |
if(a->u.float_number > b->u.float_number) return 1; |
return 0; |
|
case T_STRING: |
return my_strcmp(a->u.string, b->u.string); |
|
case T_ARRAY: |
if(a==b) return 0; |
if(!a->u.array->size) return -1; |
if(!b->u.array->size) return 1; |
return alpha_svalue_cmpfun(ITEM(a->u.array), ITEM(b->u.array)); |
|
default: |
return set_svalue_cmpfun(a,b); |
|
case T_OBJECT: |
break; |
} |
}else{ |
if(a->type!=T_OBJECT && b->type!=T_OBJECT) |
return a->type - b->type; |
} |
return is_gt(a,b); |
} |
|
void sort_array_destructively(struct array *v) |
{ |
if(!v->size) return; |
fsort((char *)ITEM(v), |
v->size, |
sizeof(struct svalue), |
(fsortfun)alpha_svalue_cmpfun); |
} |
|
|
|
|
|
|
INT32 *get_set_order(struct array *a) |
{ |
return get_order(a, set_svalue_cmpfun); |
} |
|
|
|
|
INT32 *get_switch_order(struct array *a) |
{ |
return get_order(a, switch_svalue_cmpfun); |
} |
|
|
|
|
|
INT32 *get_alpha_order(struct array *a) |
{ |
return get_order(a, alpha_svalue_cmpfun); |
} |
|
|
static INT32 low_lookup(struct array *v, |
struct svalue *s, |
cmpfun fun) |
{ |
INT32 a,b,c; |
int q; |
|
a=0; |
b=v->size; |
while(b > a) |
{ |
c=(a+b)/2; |
q=fun(ITEM(v)+c,s); |
|
if(q < 0) |
a=c+1; |
else if(q > 0) |
b=c; |
else |
return c; |
} |
if(a<v->size && fun(ITEM(v)+a,s)<0) a++; |
return ~a; |
} |
|
INT32 set_lookup(struct array *a, struct svalue *s) |
{ |
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(a); |
#endif |
|
if( (((2 << s->type) -1) & a->type_field) == 0) |
return -1; |
|
|
if( ((BIT_MIXED << s->type) & BIT_MIXED & a->type_field) == 0) |
return ~a->size; |
|
return low_lookup(a,s,set_svalue_cmpfun); |
} |
|
INT32 switch_lookup(struct array *a, struct svalue *s) |
{ |
|
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(a); |
#endif |
if( (((2 << s->type) -1) & a->type_field) == 0) |
return -1; |
|
|
if( ((BIT_MIXED << s->type) & BIT_MIXED & a->type_field) == 0) |
return ~a->size; |
|
return low_lookup(a,s,switch_svalue_cmpfun); |
} |
|
|
|
|
|
struct array *order_array(struct array *v, INT32 *order) |
{ |
reorder((char *)ITEM(v),v->size,sizeof(struct svalue),order); |
return v; |
} |
|
|
|
|
|
struct array *reorder_and_copy_array(struct array *v, INT32 *order) |
{ |
INT32 e; |
struct array *ret; |
ret=allocate_array_no_init(v->size, 0); |
ret->type_field = v->type_field; |
|
for(e=0;e<v->size;e++) |
assign_svalue_no_free(ITEM(ret)+e, ITEM(v)+order[e]); |
|
return ret; |
} |
|
|
void array_fix_type_field(struct array *v) |
{ |
int e; |
TYPE_FIELD t; |
|
t=0; |
|
if(v->flags & ARRAY_LVALUE) |
{ |
v->type_field=BIT_MIXED; |
return; |
} |
|
for(e=0; e<v->size; e++) t |= 1 << ITEM(v)[e].type; |
|
#ifdef DEBUG |
if(t & ~(v->type_field)) |
fatal("Type field out of order!\n"); |
#endif |
v->type_field = t; |
} |
|
#ifdef DEBUG |
|
void array_check_type_field(struct array *v) |
{ |
int e; |
TYPE_FIELD t; |
|
t=0; |
|
if(v->flags & ARRAY_LVALUE) |
return; |
|
for(e=0; e<v->size; e++) |
{ |
if(ITEM(v)[e].type > MAX_TYPE) |
fatal("Type is out of range.\n"); |
|
t |= 1 << ITEM(v)[e].type; |
} |
|
if(t & ~(v->type_field)) |
fatal("Type field out of order!\n"); |
} |
#endif |
|
struct array *compact_array(struct array *v) { return v; } |
|
|
|
|
|
union anything *low_array_get_item_ptr(struct array *a, |
INT32 ind, |
TYPE_T t) |
{ |
if(ITEM(a)[ind].type == t) return & (ITEM(a)[ind].u); |
return 0; |
} |
|
|
|
|
|
|
|
union anything *array_get_item_ptr(struct array *a, |
struct svalue *ind, |
TYPE_T t) |
{ |
INT32 i; |
if(ind->type != T_INT) |
error("Index is not an integer.\n"); |
i=ind->u.integer; |
if(i<0) i+=a->size; |
if(i<0 || i>=a->size) error("Index out of range.\n"); |
return low_array_get_item_ptr(a,i,t); |
} |
|
|
|
|
|
|
|
|
INT32 * merge(struct array *a,struct array *b,INT32 opcode) |
{ |
INT32 ap,bp,i,*ret,*ptr; |
|
ap=bp=0; |
#ifdef DEBUG |
if(d_flag > 1) |
{ |
array_check_type_field(a); |
array_check_type_field(b); |
} |
#endif |
if(!(a->type_field & b->type_field)) |
{ |
|
switch(opcode) |
{ |
case OP_AND: |
ret=(INT32 *)xalloc(sizeof(INT32)); |
*ret=0; |
return ret; |
|
case OP_SUB: |
ptr=ret=(INT32 *)xalloc(sizeof(INT32)*(a->size+1)); |
*(ptr++)=a->size; |
for(i=0;i<a->size;i++) *(ptr++)=i; |
return ret; |
} |
} |
|
ptr=ret=(INT32 *)xalloc(sizeof(INT32)*(a->size + b->size + 1)); |
ptr++; |
|
while(ap < a->size && bp < b->size) |
{ |
i=set_svalue_cmpfun(ITEM(a)+ap,ITEM(b)+bp); |
if(i < 0) |
i=opcode >> 8; |
else if(i > 0) |
i=opcode; |
else |
i=opcode >> 4; |
|
if(i & OP_A) *(ptr++)=ap; |
if(i & OP_B) *(ptr++)=~bp; |
if(i & OP_SKIP_A) ap++; |
if(i & OP_SKIP_B) bp++; |
} |
|
if((opcode >> 8) & OP_A) while(ap<a->size) *(ptr++)=ap++; |
if(opcode & OP_B) while(bp<b->size) *(ptr++)=~(bp++); |
|
*ret=(ptr-ret-1); |
|
return ret; |
} |
|
|
|
|
|
struct array *array_zip(struct array *a, struct array *b,INT32 *zipper) |
{ |
INT32 size,e; |
struct array *ret; |
size=zipper[0]; |
zipper++; |
|
ret=allocate_array_no_init(size,0); |
for(e=0; e<size; e++) |
{ |
if(*zipper >= 0) |
assign_svalue_no_free(ITEM(ret)+e, ITEM(a)+*zipper); |
else |
assign_svalue_no_free(ITEM(ret)+e, ITEM(b)+~*zipper); |
zipper++; |
} |
ret->type_field = a->type_field | b->type_field; |
return ret; |
} |
|
struct array *add_arrays(struct svalue *argp, INT32 args) |
{ |
INT32 e, size; |
struct array *v; |
|
for(size=e=0;e<args;e++) |
size+=argp[e].u.array->size; |
|
if(args && argp[0].u.array->refs==1) |
{ |
e=argp[0].u.array->size; |
v=resize_array(argp[0].u.array, size); |
argp[0].type=T_INT; |
size=e; |
e=1; |
}else{ |
v=allocate_array_no_init(size, 0); |
v->type_field=0; |
e=size=0; |
} |
|
for(; e<args; e++) |
{ |
v->type_field|=argp[e].u.array->type_field; |
assign_svalues_no_free(ITEM(v)+size, |
ITEM(argp[e].u.array), |
argp[e].u.array->size, |
argp[e].u.array->type_field); |
size+=argp[e].u.array->size; |
} |
|
return v; |
} |
|
int array_equal_p(struct array *a, struct array *b, struct processing *p) |
{ |
struct processing curr; |
INT32 e; |
|
if(a == b) return 1; |
if(a->size != b->size) return 0; |
if(!a->size) return 1; |
|
#ifdef DEBUG |
if(d_flag > 1) |
{ |
array_check_type_field(a); |
array_check_type_field(b); |
} |
#endif |
|
|
|
|
|
if(!(a->type_field & b->type_field) && |
!( (a->type_field | b->type_field) & BIT_OBJECT )) |
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; |
|
for(e=0; e<a->size; e++) |
if(!low_is_equal(ITEM(a)+e, ITEM(b)+e, &curr)) |
return 0; |
|
return 1; |
} |
|
static INT32 *ordera=0, *orderb=0; |
|
|
|
|
static int array_merge_fun(INT32 *a, INT32 *b) |
{ |
if(*a<0) |
{ |
if(*b<0) |
{ |
return orderb[~*a] - orderb[~*b]; |
}else{ |
return -1; |
} |
}else{ |
if(*b<0) |
{ |
return 1; |
}else{ |
return ordera[*a] - ordera[*b]; |
} |
} |
} |
|
|
|
|
|
|
struct array *merge_array_with_order(struct array *a, struct array *b,INT32 op) |
{ |
INT32 *zipper; |
struct array *tmpa,*tmpb,*ret; |
|
if(ordera) { free((char *)ordera); ordera=0; } |
if(orderb) { free((char *)orderb); orderb=0; } |
|
ordera=get_set_order(a); |
tmpa=reorder_and_copy_array(a,ordera); |
|
orderb=get_set_order(b); |
tmpb=reorder_and_copy_array(b,orderb); |
|
zipper=merge(tmpa,tmpb,op); |
|
fsort((char *)(zipper+1),*zipper,sizeof(INT32),(fsortfun)array_merge_fun); |
free((char *)ordera); |
free((char *)orderb); |
orderb=ordera=0; |
ret=array_zip(tmpa,tmpb,zipper); |
free_array(tmpa); |
free_array(tmpb); |
free((char *)zipper); |
return ret; |
} |
|
|
|
|
|
struct array *merge_array_without_order(struct array *a, |
struct array *b, |
INT32 op) |
{ |
INT32 *zipper; |
struct array *tmpa,*tmpb,*ret; |
|
if(ordera) { free((char *)ordera); ordera=0; } |
if(orderb) { free((char *)orderb); orderb=0; } |
|
ordera=get_set_order(a); |
tmpa=reorder_and_copy_array(a,ordera); |
free((char *)ordera); |
ordera=0; |
|
orderb=get_set_order(b); |
tmpb=reorder_and_copy_array(b,orderb); |
free((char *)orderb); |
orderb=0; |
|
zipper=merge(tmpa,tmpb,op); |
ret=array_zip(tmpa,tmpb,zipper); |
free_array(tmpa); |
free_array(tmpb); |
free((char *)zipper); |
return ret; |
} |
|
|
struct array *subtract_arrays(struct array *a, struct array *b) |
{ |
#ifdef DEBUG |
if(d_flag > 1) |
{ |
array_check_type_field(b); |
} |
#endif |
check_array_for_destruct(a); |
|
if(a->type_field & b->type_field) |
{ |
return merge_array_with_order(a, b, OP_SUB); |
}else{ |
if(a->refs == 1) |
{ |
add_ref(a); |
return a; |
} |
return slice_array(a,0,a->size); |
} |
} |
|
|
struct array *and_arrays(struct array *a, struct array *b) |
{ |
#ifdef DEBUG |
if(d_flag > 1) |
{ |
array_check_type_field(b); |
} |
#endif |
check_array_for_destruct(a); |
|
if(a->type_field & b->type_field) |
{ |
return merge_array_without_order(a, b, OP_AND); |
}else{ |
return allocate_array_no_init(0,0); |
} |
} |
|
int check_that_array_is_constant(struct array *a) |
{ |
array_fix_type_field(a); |
if(a->type_field & (BIT_FUNCTION | BIT_OBJECT)) |
return 0; |
return 1; |
} |
|
node *make_node_from_array(struct array *a) |
{ |
struct svalue s; |
INT32 e; |
|
array_fix_type_field(a); |
if(a->type_field == BIT_INT) |
{ |
for(e=0; e<a->size; e++) |
if(ITEM(a)[e].u.integer != 0) |
break; |
if(e == a->size) |
{ |
return mkefuncallnode("allocate",mkintnode(a->size)); |
} |
} |
if(check_that_array_is_constant(a)) |
{ |
s.type=T_ARRAY; |
s.subtype=0; |
s.u.array=a; |
return mkconstantsvaluenode(&s); |
}else{ |
node *ret=0; |
for(e=0; e<a->size; e++) |
ret=mknode(F_ARG_LIST,ret,mksvaluenode(ITEM(a)+e)); |
return mkefuncallnode("aggregate",ret); |
} |
} |
|
void push_array_items(struct array *a) |
{ |
check_stack(a->size); |
check_array_for_destruct(a); |
if(a->refs == 1) |
{ |
MEMCPY(sp,ITEM(a),sizeof(struct svalue)*a->size); |
sp += a->size; |
a->size=0; |
free_array(a); |
}else{ |
assign_svalues_no_free(sp, ITEM(a), a->size, a->type_field); |
sp += a->size; |
free_array(a); |
} |
} |
|
void describe_array_low(struct array *a, struct processing *p, int indent) |
{ |
INT32 e,d; |
indent += 2; |
|
for(e=0; e<a->size; e++) |
{ |
if(e) my_strcat(",\n"); |
for(d=0; d<indent; d++) my_putchar(' '); |
describe_svalue(ITEM(a)+e,indent,p); |
} |
} |
|
void simple_describe_array(struct array *a) |
{ |
char *s; |
init_buf(); |
describe_array_low(a,0,0); |
s=simple_free_buf(); |
fprintf(stderr,"({\n%s\n})\n",s); |
free(s); |
} |
|
void describe_index(struct array *a, |
int e, |
struct processing *p, |
int indent) |
{ |
describe_svalue(ITEM(a)+e, indent, p); |
} |
|
|
void describe_array(struct array *a,struct processing *p,int indent) |
{ |
struct processing doing; |
INT32 e; |
char buf[60]; |
if(! a->size) |
{ |
my_strcat("({ })"); |
return; |
} |
|
doing.next=p; |
doing.pointer_a=(void *)a; |
for(e=0;p;e++,p=p->next) |
{ |
if(p->pointer_a == (void *)a) |
{ |
sprintf(buf,"@%ld",(long)e); |
my_strcat(buf); |
return; |
} |
} |
|
sprintf(buf,"({ /* %ld elements */\n",(long)a->size); |
my_strcat(buf); |
describe_array_low(a,&doing,indent); |
my_putchar('\n'); |
for(e=2; e<indent; e++) my_putchar(' '); |
my_strcat("})"); |
} |
|
struct array *aggregate_array(INT32 args) |
{ |
struct array *a; |
|
a=allocate_array_no_init(args,0); |
MEMCPY((char *)ITEM(a),(char *)(sp-args),args*sizeof(struct svalue)); |
a->type_field=BIT_MIXED; |
sp-=args; |
return a; |
} |
|
struct array *append_array(struct array *a, struct svalue *s) |
{ |
a=resize_array(a,a->size+1); |
array_set_index(a, a->size-1, s); |
return a; |
} |
|
struct array *explode(struct pike_string *str, |
struct pike_string *del) |
{ |
INT32 e; |
struct array *ret; |
char *s, *end, *tmp; |
|
if(!str->len) |
{ |
return allocate_array_no_init(0,0); |
} |
if(!del->len) |
{ |
ret=allocate_array_no_init(str->len,0); |
for(e=0;e<str->len;e++) |
{ |
ITEM(ret)[e].type=T_STRING; |
ITEM(ret)[e].u.string=make_shared_binary_string(str->str+e,1); |
} |
}else{ |
struct mem_searcher searcher; |
|
s=str->str; |
end=s+str->len; |
|
ret=allocate_array(10); |
ret->size=0; |
|
init_memsearch(&searcher, del->str, del->len, str->len); |
|
while((tmp=memory_search(&searcher, s, end-s))) |
{ |
if(ret->size == ret->malloced_size) |
{ |
e=ret->size; |
ret=resize_array(ret, e * 2); |
ret->size=e; |
} |
|
ITEM(ret)[ret->size].u.string=make_shared_binary_string(s, tmp-s); |
ITEM(ret)[ret->size].type=T_STRING; |
ret->size++; |
|
s=tmp+del->len; |
} |
|
if(ret->size == ret->malloced_size) |
{ |
e=ret->size; |
ret=resize_array(ret, e * 2); |
ret->size=e; |
} |
|
ITEM(ret)[ret->size].u.string=make_shared_binary_string(s, end-s); |
ITEM(ret)[ret->size].type=T_STRING; |
ret->size++; |
} |
ret->type_field=BIT_STRING; |
return ret; |
} |
|
struct pike_string *implode(struct array *a,struct pike_string *del) |
{ |
INT32 len,e, inited; |
char *r; |
struct pike_string *ret,*tmp; |
|
len=0; |
|
for(e=0;e<a->size;e++) |
if(ITEM(a)[e].type==T_STRING) |
len+=ITEM(a)[e].u.string->len + del->len; |
if(len) len-=del->len; |
|
ret=begin_shared_string(len); |
r=ret->str; |
inited=0; |
for(e=0;e<a->size;e++) |
{ |
if(ITEM(a)[e].type==T_STRING) |
{ |
if(inited) |
{ |
MEMCPY(r,del->str,del->len); |
r+=del->len; |
} |
inited=1; |
tmp=ITEM(a)[e].u.string; |
MEMCPY(r,tmp->str,tmp->len); |
r+=tmp->len; |
len++; |
} |
} |
return end_shared_string(ret); |
} |
|
struct array *copy_array_recursively(struct array *a,struct processing *p) |
{ |
struct processing doing; |
struct array *ret; |
|
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(a); |
#endif |
|
doing.next=p; |
doing.pointer_a=(void *)a; |
for(;p;p=p->next) |
{ |
if(p->pointer_a == (void *)a) |
{ |
ret=(struct array *)p->pointer_b; |
add_ref(ret); |
return ret; |
} |
} |
|
ret=allocate_array_no_init(a->size,0); |
doing.pointer_b=(void *)ret; |
|
copy_svalues_recursively_no_free(ITEM(ret),ITEM(a),a->size,&doing); |
|
ret->type_field=a->type_field; |
return ret; |
} |
|
void apply_array(struct array *a, INT32 args) |
{ |
INT32 e; |
struct array *ret; |
INT32 argp; |
|
argp=sp-args - evaluator_stack; |
|
check_stack(a->size + args + 1); |
|
for(e=0;e<a->size;e++) |
{ |
assign_svalues_no_free(sp,evaluator_stack+argp,args,BIT_MIXED); |
sp+=args; |
apply_svalue(ITEM(a)+e,args); |
} |
ret=aggregate_array(a->size); |
pop_n_elems(args); |
push_array(ret); |
} |
|
struct array *reverse_array(struct array *a) |
{ |
INT32 e; |
struct array *ret; |
|
|
ret=allocate_array_no_init(a->size,0); |
for(e=0;e<a->size;e++) |
assign_svalue_no_free(ITEM(ret)+e,ITEM(a)+a->size+~e); |
return ret; |
} |
|
void array_replace(struct array *a, |
struct svalue *from, |
struct svalue *to) |
{ |
INT32 i = -1; |
|
while((i=array_search(a,from,i+1)) >= 0) array_set_index(a,i,to); |
} |
|
#ifdef DEBUG |
void check_array(struct array *a) |
{ |
INT32 e; |
|
if(a->next->prev != a) |
fatal("Array check: a->next->prev != a\n"); |
|
if(a->size > a->malloced_size) |
fatal("Array is larger than malloced block!\n"); |
|
if(a->refs <=0 ) |
fatal("Array has zero refs.\n"); |
|
for(e=0;e<a->size;e++) |
{ |
if(! ( (1 << ITEM(a)[e].type) & (a->type_field) )) |
fatal("Type field lies.\n"); |
|
check_svalue(ITEM(a)+e); |
} |
} |
|
void check_all_arrays(void) |
{ |
struct array *a; |
|
a=&empty_array; |
do |
{ |
check_array(a); |
|
a=a->next; |
if(!a) |
fatal("Null pointer in array list.\n"); |
} while (a != & empty_array); |
} |
#endif /* DEBUG */ |
|
|
void gc_mark_array_as_referenced(struct array *a) |
{ |
if(gc_mark(a)) |
if(a->type_field & BIT_COMPLEX) |
gc_mark_svalues(ITEM(a), a->size); |
} |
|
void gc_check_all_arrays(void) |
{ |
struct array *a; |
a=&empty_array; |
do |
{ |
#ifdef DEBUG |
if(d_flag > 1) array_check_type_field(a); |
#endif |
if(a->type_field & BIT_COMPLEX) |
{ |
TYPE_FIELD t; |
t=debug_gc_check_svalues(ITEM(a), a->size, T_ARRAY, a); |
|
|
|
|
|
if(!(a->type_field & BIT_UNFINISHED) || a->refs!=1) |
a->type_field = t; |
else |
a->type_field |= t; |
} |
|
a=a->next; |
} while (a != & empty_array); |
} |
|
|
void gc_mark_all_arrays(void) |
{ |
struct array *a; |
|
a=&empty_array; |
do |
{ |
if(gc_is_referenced(a)) |
gc_mark_array_as_referenced(a); |
|
a=a->next; |
} while (a != & empty_array); |
} |
|
void gc_free_all_unreferenced_arrays(void) |
{ |
struct array *a,*next; |
|
a=&empty_array; |
do |
{ |
if(gc_do_free(a)) |
{ |
add_ref(a); |
free_svalues(ITEM(a), a->size, a->type_field); |
a->size=0; |
|
if(!(next=a->next)) |
fatal("Null pointer in array list.\n"); |
|
free_array(a); |
a=next; |
}else{ |
a=a->next; |
} |
} while (a != & empty_array); |
} |
|
|
#ifdef DEBUG |
|
void debug_dump_type_field(TYPE_FIELD t) |
{ |
int e; |
for(e=0;e<=MAX_TYPE;e++) |
if(t & (1<<e)) |
fprintf(stderr," %s",get_name_of_type(e)); |
|
for(;e<16;e++) |
if(t & (1<<e)) |
fprintf(stderr," <%d>",e); |
} |
|
void debug_dump_array(struct array *a) |
{ |
fprintf(stderr,"Location=%p Refs=%d, next=%p, prev=%p, size=%d, malloced_size=%d\n", |
a, |
a->refs, |
a->next, |
a->prev, |
a->size, |
a->malloced_size); |
fprintf(stderr,"Type field = "); |
debug_dump_type_field(a->type_field); |
fprintf(stderr,"\n"); |
simple_describe_array(a); |
} |
#endif |
|
|
void zap_all_arrays(void) |
{ |
struct array *a,*next; |
|
a=&empty_array; |
do |
{ |
|
#if defined(DEBUG) && defined(DEBUG_MALLOC) |
if(verbose_debug_exit && a!=&empty_array) |
describe(a); |
#endif |
|
add_ref(a); |
free_svalues(ITEM(a), a->size, a->type_field); |
a->size=0; |
|
if(!(next=a->next)) |
fatal("Null pointer in array list.\n"); |
|
free_array(a); |
a=next; |
} while (a != & empty_array); |
} |
|
|
void count_memory_in_arrays(INT32 *num_, INT32 *size_) |
{ |
INT32 num=0, size=0; |
struct array *m; |
for(m=empty_array.next;m!=&empty_array;m=m->next) |
{ |
num++; |
size+=sizeof(struct array)+ |
sizeof(struct svalue) * (m->malloced_size - 1); |
} |
*num_=num; |
*size_=size; |
} |
|
struct array *explode_array(struct array *a, struct array *b) |
{ |
INT32 e,d,q,start; |
struct array *tmp; |
|
q=start=0; |
if(!a->size) |
{ |
return allocate_array_no_init(0,0); |
} |
if(b->size) |
{ |
for(e=0;e<=a->size - b->size;e++) |
{ |
for(d=0;d<b->size;d++) |
{ |
if(!is_eq(ITEM(a)+(e+d),ITEM(b)+d)) |
break; |
} |
if(d==b->size) |
{ |
check_stack(1); |
push_array(friendly_slice_array(a, start, e)); |
q++; |
e+=b->size-1; |
start=e+1; |
} |
} |
check_stack(1); |
push_array(friendly_slice_array(a, start, a->size)); |
q++; |
}else{ |
check_stack(a->size); |
for(e=0;e<a->size;e++) push_array(friendly_slice_array(a, e, e+1)); |
q=a->size; |
} |
tmp=aggregate_array(q); |
if(tmp->size) tmp->type_field=BIT_ARRAY; |
return tmp; |
} |
|
struct array *implode_array(struct array *a, struct array *b) |
{ |
INT32 e,size; |
struct array *ret; |
size=0; |
for(e=0;e<a->size;e++) |
{ |
if(ITEM(a)[e].type!=T_ARRAY) |
error("Implode array contains non-arrays.\n"); |
size+=ITEM(a)[e].u.array->size; |
} |
|
ret=allocate_array((a->size -1) * b->size + size); |
size=0; |
ret->type_field=0; |
for(e=0;e<a->size;e++) |
{ |
if(e) |
{ |
ret->type_field|=b->type_field; |
assign_svalues_no_free(ITEM(ret)+size, |
ITEM(b), |
b->size, |
b->type_field); |
size+=b->size; |
} |
ret->type_field|=ITEM(a)[e].u.array->type_field; |
assign_svalues_no_free(ITEM(ret)+size, |
ITEM(ITEM(a)[e].u.array), |
ITEM(a)[e].u.array->size, |
ITEM(a)[e].u.array->type_field); |
size+=ITEM(a)[e].u.array->size; |
} |
#ifdef DEBUG |
if(size != ret->size) |
fatal("Implode_array failed miserably\n"); |
#endif |
return ret; |
} |
|
|