5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
struct array empty_array=
{
1,
&empty_array,
&empty_array,
0,
0,
0,
T_MIXED,
0,
};
struct array *allocate_array_no_init(INT32 size,INT32 extra_space,TYPE_T type)
{
struct array *v;
if(size == 0 && type == T_MIXED)
{
empty_array.refs++;
return &empty_array;
}
if(type == T_FUNCTION || type == T_MIXED)
{
v=(struct array *)malloc(sizeof(struct array_of_svalues)+
(size+extra_space-1)*sizeof(struct svalue));
if(!v)
error("Couldn't allocate array, out of memory.\n");
v->array_type=T_MIXED;
v->type_field=BIT_MIXED;
}else{
v=(struct array *)malloc(sizeof(struct array_of_short_svalues)+
(size+extra_space-1)*sizeof(union anything));
if(!v)
error("Couldn't allocate array, out of memory.\n");
v->array_type=type;
v->type_field=BIT_INT | (1 << type);
}
v->malloced_size=size+extra_space;
v->size=size;
v->flags=0;
v->refs=1;
v->prev=&empty_array;
v->next=empty_array.next;
empty_array.next=v;
v->next->prev=v;
return v;
}
struct array *allocate_array(INT32 size,TYPE_T type)
{
INT32 e;
struct array *a;
a=allocate_array_no_init(size,0,type);
if(a->array_type==T_MIXED)
{
for(e=0;e<a->size;e++)
{
ITEM(a)[e].type=T_INT;
ITEM(a)[e].subtype=NUMBER_NUMBER;
ITEM(a)[e].u.integer=0;
}
}else{
MEMSET((char *)SHORT_ITEM(a),0,sizeof(union anything)*a->size);
}
return a;
}
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);
}
void really_free_array(struct array *v)
{
#ifdef DEBUG
if(v == & empty_array)
fatal("Tried to free the empty_array.\n");
#endif
if(v->array_type == T_MIXED)
{
free_svalues(ITEM(v), v->size);
}else{
free_short_svalues(SHORT_ITEM(v), v->size, v->array_type);
}
array_free_no_free(v);
}
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
if(v->array_type == T_MIXED)
{
assign_svalue_no_free(s, ITEM(v) + index);
}else{
assign_from_short_svalue_no_free(s, SHORT_ITEM(v) + index, v->array_type);
}
}
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
v->refs++;
if(v->array_type == T_MIXED)
{
assign_svalue(s, ITEM(v) + index);
}else{
free_svalue(s);
assign_from_short_svalue_no_free(s, SHORT_ITEM(v) + index, v->array_type);
}
free_array(v);
}
void simple_array_index(struct svalue *s,struct array *a,struct svalue *ind)
{
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_index(s,a,i);
}
void simple_array_index_no_free(struct svalue *s,struct array *a,struct svalue *ind)
{
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_index_no_free(s,a,i);
}
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
if(v->array_type == T_MIXED)
{
free_svalue(ITEM(v) + index);
}else{
free_short_svalue(SHORT_ITEM(v) + index, v->array_type);
}
}
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
v->refs++;
check_destructed(s);
if(v->array_type == T_MIXED)
{
v->type_field |= 1 << s->type;
assign_svalue( ITEM(v) + index, s);
}else if(IS_ZERO(s)){
v->type_field |= BIT_INT;
SHORT_ITEM(v)[index].refs=0;
}else if(v->array_type == s->type){
assign_to_short_svalue( SHORT_ITEM(v)+index, v->array_type, s);
}else{
free_array(v);
error("Wrong type in array assignment (%s != %s)\n",
get_name_of_type(v->array_type),
get_name_of_type(s->type));
}
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)
{
if(v->array_type == T_MIXED)
{
MEMMOVE((char *)(ITEM(v)+index+1),
(char *)(ITEM(v)+index),
(v->size-index) * sizeof(struct svalue));
ITEM(v)[index].type=T_INT;
}else{
MEMMOVE((char *)(SHORT_ITEM(v)+index+1),
(char *)(SHORT_ITEM(v)+index),
(v->size-index) * sizeof(union anything));
SHORT_ITEM(v)[index].refs=0;
}
v->size++;
}else{
struct array *ret;
ret=allocate_array_no_init(v->size+1, (v->size >> 3) + 1, v->array_type);
ret->type_field = v->type_field;
if(v->array_type == T_MIXED)
{
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;
}else{
MEMCPY(SHORT_ITEM(ret), SHORT_ITEM(v), sizeof(union anything) * index);
MEMCPY(SHORT_ITEM(ret)+index+1,
SHORT_ITEM(v)+index,
sizeof(union anything) * (v->size-index));
SHORT_ITEM(ret)[index].refs=0;
}
v->size=0;
free_array(v);
v=ret;
}
array_set_index(v,index,s);
return v;
}
static struct array *resize_array(struct array *a, INT32 size)
{
if(a->size == size) return a;
if(size > a->size)
{
if(a->malloced_size >= size)
{
if(a->array_type == T_MIXED)
{
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;
}
}else{
MEMSET(SHORT_ITEM(a)+a->size,
0,
sizeof(union anything)*(size-a->size));
a->size=size;
}
return a;
}else{
struct array *ret;
ret=allocate_array_no_init(size, (size>>3)+1, a->array_type);
if(a->array_type == T_MIXED)
{
MEMCPY(ITEM(ret),ITEM(a),sizeof(struct svalue)*a->size);
}else{
MEMCPY(SHORT_ITEM(ret),SHORT_ITEM(a),sizeof(union anything)*a->size);
}
a->size=0;
free_array(a);
return ret;
}
}else{
if(a->array_type == T_MIXED)
{
free_svalues(ITEM(a)+size, a->size - size);
}else{
free_short_svalues(SHORT_ITEM(a)+size, a->size - size, a->array_type);
}
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,v->array_type);
a->type_field = v->type_field;
if(v->array_type == T_MIXED)
{
free_svalues(ITEM(v) + size, v->size - size);
MEMCPY(ITEM(a), ITEM(v), size*sizeof(struct svalue));
}else{
free_short_svalues(SHORT_ITEM(v) + size, v->size - size, v->array_type);
MEMCPY(ITEM(a), ITEM(v), size*sizeof(union anything));
}
v->size=0;
free_array(v);
return a;
}else{
if(v->array_type == T_MIXED)
{
free_svalues(ITEM(v) + size, v->size - size);
}else{
free_short_svalues(SHORT_ITEM(v) + size, v->size - size, v->array_type);
}
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, v->array_type);
a->type_field = v->type_field;
if(v->array_type == T_MIXED)
{
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));
}else{
if(index>0)
MEMCPY(SHORT_ITEM(a), SHORT_ITEM(v), index*sizeof(struct svalue));
if(v->size-index>1)
MEMCPY(SHORT_ITEM(a)+index,
SHORT_ITEM(v)+index+1,
(v->size-index-1)*sizeof(union anything));
}
v->size=0;
free_array(v);
return a;
}else{
if(v->size-index>1)
{
if(v->array_type == T_MIXED)
{
MEMMOVE((char *)(ITEM(v)+index),
(char *)(ITEM(v)+index+1),
(v->size-index-1)*sizeof(struct svalue));
}else{
MEMMOVE((char *)(SHORT_ITEM(v)+index),
(char *)(SHORT_ITEM(v)+index+1),
(v->size-index-1)*sizeof(union anything));
}
}
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);
if(v->type_field & (1 << s->type))
{
if(v->array_type == T_MIXED)
{
TYPE_FIELD t=0;
for(e=start;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;
}else{
if(v->array_type == T_FLOAT)
{
if(s->type == T_FLOAT)
for(e=start;e<v->size;e++)
if(SHORT_ITEM(v)[e].float_number == s->u.float_number)
return e;
return -1;
}
if(v->array_type == s->type)
{
for(e=start;e<v->size;e++)
if(SHORT_ITEM(v)[e].refs == s->u.refs)
return e;
return -1;
}
if(IS_ZERO(s))
for(e=start;e<v->size;e++)
if(!SHORT_ITEM(v)[e].refs)
return e;
return -1;
}
}
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");
#endif
if(start==0 && v->refs==1)
{
v->refs++;
return array_shrink(v,end);
}
a=allocate_array_no_init(end-start,0,v->array_type);
a->type_field = v->type_field;
if(v->array_type == T_MIXED)
{
assign_svalues_no_free(ITEM(a), ITEM(v)+start, end-start);
}else{
assign_short_svalues_no_free(SHORT_ITEM(a),
SHORT_ITEM(v)+start,
v->array_type,
end-start);
}
return a;
}
struct array *copy_array(struct array *v)
{
struct array *a;
a=allocate_array_no_init(v->size, 0, v->array_type);
a->type_field = v->type_field;
if(v->array_type == T_MIXED)
{
assign_svalues_no_free(ITEM(a), ITEM(v), v->size);
}else{
assign_short_svalues_no_free(SHORT_ITEM(a),
SHORT_ITEM(v),
v->array_type,
v->size);
}
return a;
}
void check_array_for_destruct(struct array *v)
{
int e;
INT16 types;
types = 0;
if(v->type_field & (BIT_OBJECT | BIT_FUNCTION))
{
if(v->array_type == T_MIXED)
{
for(e=0; e<v->size; e++)
{
if((ITEM(v)[e].type == T_OBJECT ||
(ITEM(v)[e].type == T_FUNCTION && ITEM(v)[e].subtype!=-1)) &&
(!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;
}
}
}else{
for(e=0; e<v->size; e++)
{
if(!SHORT_ITEM(v)[e].object)
{
types |= BIT_INT;
}
else if(!SHORT_ITEM(v)[e].object->prog)
{
free_short_svalue(SHORT_ITEM(v)+e,v->array_type);
SHORT_ITEM(v)[e].refs=0;
types |= BIT_INT;
}
}
}
v->type_field = types;
}
}
INT32 array_find_destructed_object(struct array *v)
{
INT32 e;
TYPE_FIELD types;
if(v->type_field & (BIT_OBJECT | BIT_FUNCTION))
{
if(v->array_type == T_MIXED)
{
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!=-1)) &&
(!ITEM(v)[e].u.object->prog))
return e;
types |= 1<<ITEM(v)[e].type;
}
}else{
types=1<<(v->array_type);
for(e=0; e<v->size; e++)
{
if(SHORT_ITEM(v)[e].object)
{
if(!SHORT_ITEM(v)[e].object->prog)
return e;
}else{
types |= BIT_INT;
}
}
}
v->type_field = types;
}
return -1;
}
static short_cmpfun current_short_cmpfun;
static union anything *current_short_array_p;
static int internal_short_cmpfun(INT32 *a,INT32 *b)
{
return current_short_cmpfun(current_short_array_p + *a,
current_short_array_p + *b);
}
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,cmpfun_getter backfun)
{
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(v->array_type == T_MIXED)
{
current_array_p = ITEM(v);
current_cmpfun = fun;
fsort((char *)current_order,
v->size,
sizeof(INT32),
(fsortfun)internal_cmpfun);
}else{
current_short_array_p = SHORT_ITEM(v);
current_short_cmpfun = backfun(v->array_type);
fsort((char *)current_order,
v->size,
sizeof(INT32),
(fsortfun)internal_short_cmpfun);
}
return current_order;
}
static int set_svalue_cmpfun(struct svalue *a, struct svalue *b)
{
INT32 tmp;
if(tmp=(a->type - b->type)) return tmp;
#ifdef NORMALIZED_FLOATS
if(tmp=(a->u.integer - b->u.integer)) return tmp;
if(a->type == T_FUNCTION ) return a->subtype - b->subtype;
return 0;
#else
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(tmp=(a->u.integer - b->u.integer)) return tmp;
return a->subtype - b->subtype;
default:
return a->u.integer - b->u.integer;
}
#endif
}
static int set_anything_cmpfun(union anything *a, union anything *b)
{
return a->integer - b->integer;
}
static int set_anything_cmpfun_float(union anything *a, union anything *b)
{
if(a->float_number < b->float_number) return -1;
if(a->float_number > b->float_number) return 1;
return 0;
}
#ifdef NORMALIZED_FLOATS
static short_cmpfun get_set_cmpfun(TYPE_T t)
{
return set_anything_cmpfun;
}
#else
static short_cmpfun get_set_cmpfun(TYPE_T t)
{
if(t == T_FLOAT) return set_anything_cmpfun_float;
return set_anything_cmpfun;
}
#endif
static int switch_anything_cmpfun_string(union anything *a, union anything *b)
{
return my_strcmp(a->string, b->string);
}
static short_cmpfun get_switch_cmpfun(TYPE_T t)
{
switch(t)
{
case T_INT: return set_anything_cmpfun;
case T_FLOAT:
return set_anything_cmpfun_float;
case T_STRING:
return switch_anything_cmpfun_string;
default:
error("Illegal type in switch.\n");
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:
return a->u.integer - b->u.integer;
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);
}
}
INT32 *get_set_order(struct array *a)
{
return get_order(a, set_svalue_cmpfun, get_set_cmpfun);
}
INT32 *get_switch_order(struct array *a)
{
return get_order(a, switch_svalue_cmpfun, get_switch_cmpfun);
}
static INT32 low_lookup(struct array *v,
struct svalue *s,
cmpfun fun,
cmpfun_getter backfun)
{
INT32 a,b,c;
int q;
if(v->array_type == T_MIXED)
{
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;
}else if(s->type == v->array_type){
short_cmpfun fun;
fun=backfun(s->type);
a=0;
b=v->size;
while(b > a)
{
c=(a+b)/2;
q=fun(SHORT_ITEM(v)+c,&s->u);
if(q < 0)
a=c+1;
else if(q > 0)
b=c;
else
return c;
}
if(a<v->size && fun(SHORT_ITEM(v)+a,&s->u)<0) a++;
return ~a;
}else{
if(s->type < v->array_type) return -1;
return ~v->size;
}
}
INT32 set_lookup(struct array *a, struct svalue *s)
{
return low_lookup(a,s,set_svalue_cmpfun,get_set_cmpfun);
}
INT32 switch_lookup(struct array *a, struct svalue *s)
{
return low_lookup(a,s,switch_svalue_cmpfun,get_switch_cmpfun);
}
struct array *order_array(struct array *v, INT32 *order)
{
if(v->array_type == T_MIXED)
reorder((char *)ITEM(v),v->size,sizeof(struct svalue),order);
else
reorder((char *)SHORT_ITEM(v),v->size,sizeof(union anything),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, v->array_type);
ret->type_field = v->type_field;
if(v->array_type == T_MIXED)
{
for(e=0;e<v->size;e++)
assign_svalue_no_free(ITEM(ret)+e, ITEM(v)+order[e]);
}else{
for(e=0;e<v->size;e++)
assign_short_svalue_no_free(SHORT_ITEM(ret)+e,
SHORT_ITEM(v)+order[e],
v->array_type);
}
return ret;
}
void array_fix_type_field(struct array *v)
{
int e;
TYPE_FIELD t;
t=0;
switch(v->array_type)
{
case T_MIXED:
for(e=0; e<v->size; e++) t |= 1 << ITEM(v)[e].type;
break;
case T_INT:
case T_FLOAT:
t=1 << v->array_type;
break;
default:
v->type_field=1 << v->array_type;
for(e=0; e<v->size; e++)
{
if(! SHORT_ITEM(v)[e].refs)
{
t |= 1 << T_INT;
break;
}
}
}
v->type_field = t;
}
struct array *compact_array(struct array *v)
{
INT32 e;
struct array *ret;
if(v->array_type != T_MIXED) return v;
if(!v->size) return v;
array_fix_type_field(v);
switch(v->type_field)
{
case BIT_INT | BIT_STRING:
case BIT_INT | BIT_ARRAY:
case BIT_INT | BIT_MAPPING:
case BIT_INT | BIT_LIST:
case BIT_INT | BIT_OBJECT:
case BIT_INT | BIT_PROGRAM:
for(e=0; e<v->size; e++)
if(ITEM(v)[e].type == T_INT)
if(ITEM(v)[e].u.integer != 0)
return v;
case BIT_INT:
case BIT_FLOAT:
case BIT_STRING:
case BIT_ARRAY:
case BIT_MAPPING:
case BIT_LIST:
case BIT_OBJECT:
case BIT_PROGRAM:
ret=allocate_array_no_init(v->size, 0, ITEM(v)[0].type);
for(e=0; e<v->size; e++)
assign_to_short_svalue_no_free(SHORT_ITEM(ret)+e,
ITEM(v)[e].type,
ITEM(v)+e);
free_array(v);
return ret;
default:
return v;
}
}
union anything *low_array_get_item_ptr(struct array *a,
INT32 ind,
TYPE_T t)
{
if(a->array_type == T_MIXED)
{
if(ITEM(a)[ind].type == t)
return & (ITEM(a)[ind].u);
}else if(a->array_type == t){
return SHORT_ITEM(a)+ind;
}
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;
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++;
if(a->array_type == T_MIXED && b->array_type == T_MIXED)
{
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++;
}
}else if(a->array_type == b->array_type)
{
short_cmpfun short_alist_cmp;
short_alist_cmp=get_set_cmpfun(a->array_type);
while(ap < a->size && bp < b->size)
{
i=short_alist_cmp(SHORT_ITEM(a)+ap,SHORT_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++;
}
}else{
struct svalue sa,sb;
while(ap < a->size && bp < b->size)
{
if(a->array_type == T_MIXED)
{
sa=ITEM(a)[ap];
}else{
sa.u = SHORT_ITEM(a)[ap];
if(!sa.u.refs )
{
if( (sa.type=a->array_type) != T_FLOAT) sa.type=T_INT;
}else{
sa.type=a->array_type;
}
}
if(b->array_type == T_MIXED)
{
sb=ITEM(b)[bp];
}else{
sb.u=SHORT_ITEM(b)[bp];
if(!sb.u.refs)
{
if( (sb.type=b->array_type) != T_FLOAT) sb.type=T_INT;
}else{
sb.type=b->array_type;
}
}
i=set_svalue_cmpfun(&sa, &sb);
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++;
if(a->array_type == T_MIXED && b->array_type == T_MIXED)
{
ret=allocate_array_no_init(size,0, T_MIXED);
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++;
}
}else if(a->array_type == b->array_type)
{
ret=allocate_array_no_init(size, 0, a->array_type);
for(e=0; e<size; e++)
{
if(*zipper >= 0)
{
assign_short_svalue_no_free(SHORT_ITEM(ret)+e,
SHORT_ITEM(a)+*zipper,
a->array_type);
}else{
assign_short_svalue_no_free(SHORT_ITEM(ret)+e,
SHORT_ITEM(b)+~*zipper,
b->array_type);
}
zipper++;
}
}else{
ret=allocate_array_no_init(size, 0, T_MIXED);
for(e=0; e<size; e++)
{
if(*zipper >= 0)
{
if(a->array_type == T_MIXED)
{
assign_svalue_no_free(ITEM(ret)+e, ITEM(a)+*zipper);
}else{
assign_from_short_svalue_no_free(ITEM(ret)+e,
SHORT_ITEM(a)+*zipper,
a->array_type);
}
}else{
if(b->array_type == T_MIXED)
{
assign_svalue(ITEM(ret)+e, ITEM(a)+*zipper);
}else{
assign_from_short_svalue_no_free(ITEM(ret)+e,
SHORT_ITEM(b)+~*zipper,
b->array_type);
}
}
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;
TYPE_T array_type;
array_type=args ? argp[0].u.array->array_type : T_MIXED;
for(size=e=0; e<args; e++)
{
check_array_for_destruct(argp[e].u.array);
size+=argp[e].u.array->size;
if(array_type != argp[e].u.array->array_type)
array_type=T_MIXED;
}
if(args &&
argp[0].u.array->refs==1 &&
argp[0].u.array->array_type == array_type)
{
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, array_type);
v->type_field=0;
e=size=0;
}
if(array_type == T_MIXED)
{
for(; e<args; e++)
{
v->type_field|=argp[e].u.array->type_field;
if(argp[e].u.array->array_type == T_MIXED)
{
assign_svalues_no_free(ITEM(v)+size,
ITEM(argp[e].u.array),
argp[e].u.array->size);
}else{
assign_from_short_svalues_no_free(ITEM(v)+size,
SHORT_ITEM(argp[e].u.array),
argp[e].u.array->array_type,
argp[e].u.array->size);
}
size+=argp[e].u.array->size;
}
}else{
for(;e<args;e++)
{
v->type_field |= argp[e].u.array->type_field;
assign_short_svalues_no_free(SHORT_ITEM(v)+size,
SHORT_ITEM(argp[e].u.array),
argp[e].u.array->array_type,
argp[e].u.array->size);
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;
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;
if(a->array_type == T_MIXED && b->array_type==T_MIXED)
{
for(e=0; e<a->size; e++)
if(!low_is_equal(ITEM(a)+e, ITEM(b)+e, &curr))
return 0;
}else{
for(e=0; e<a->size; e++)
{
struct svalue sa,sb;
if(a->array_type == T_MIXED)
{
sa=ITEM(a)[e];
}else{
sa.u=SHORT_ITEM(a)[e];
if(!sa.u.refs)
{
if( (sa.type=a->array_type) != T_FLOAT) sa.type=T_INT;
}else{
sa.type=a->array_type;
}
}
if(b->array_type == T_MIXED)
{
sb=ITEM(b)[e];
}else{
sb.u=SHORT_ITEM(b)[e];
if(!sb.u.refs)
{
if( (sb.type=b->array_type) != T_FLOAT) sb.type=T_INT;
}else{
sb.type=b->array_type;
}
}
if(!low_is_equal(&sa, &sb, &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)
{
if(a->type_field & b->type_field)
{
return merge_array_with_order(a, b, OP_SUB);
}else{
if(a->refs == 1)
{
a->refs++;
return a;
}
return slice_array(a,0,a->size);
}
}
struct array *and_arrays(struct array *a, struct array *b)
{
if(a->type_field & b->type_field)
{
return merge_array_without_order(a, b, OP_AND);
}else{
return allocate_array_no_init(0,0,T_MIXED);
}
}
int check_that_array_is_constant(struct array *a)
{
array_fix_type_field(a);
if(a->type_field & ((1 << T_FUNCTION) | (1 << T_OBJECT)))
return 0;
return 1;
}
node *make_node_from_array(struct array *a)
{
struct svalue s;
char *str;
INT32 e;
array_fix_type_field(a);
if(a->type_field == (1 << T_INT))
{
if(a->array_type == T_MIXED)
{
for(e=0; e<a->size; e++)
if(ITEM(a)[e].u.integer != 0)
break;
if(e == a->size)
{
return mkefuncallnode("allocate",
mknode(F_ARG_LIST,
mkintnode(a->size),
mkstrnode(make_shared_string("mixed"))
));
}
}else{
e=a->size;
switch(a->array_type)
{
case T_INT:
str="int";
for(e=0; e<a->size; e++)
if(SHORT_ITEM(a)[e].integer != 0)
break;
break;
case T_FLOAT: str="float"; break;
case T_STRING: str="string"; break;
case T_ARRAY: str="array"; break;
case T_LIST: str="list"; break;
case T_MAPPING: str="mapping"; break;
case T_OBJECT: str="object"; break;
case T_FUNCTION: str="function"; break;
case T_PROGRAM: str="program"; break;
default: str="mixed";
}
if(e==a->size)
{
return mkefuncallnode("allocate",
mknode(F_ARG_LIST,
mkintnode(a->size),
mkstrnode(make_shared_string(str))
));
}
}
}
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;
if(a->array_type == T_MIXED)
{
for(e=0; e<a->size; e++)
ret=mknode(F_ARG_LIST,ret,mksvaluenode(ITEM(a)+e));
}else{
s.type=a->array_type;
s.subtype=0;
for(e=0; e<a->size; e++)
{
s.u=SHORT_ITEM(a)[e];
if(s.u.refs)
{
ret=mknode(F_ARG_LIST,ret,mksvaluenode(&s));
}else{
ret=mknode(F_ARG_LIST,ret,mkintnode(0));
}
}
}
return mkefuncallnode("aggregate",ret);
}
}
void push_array_items(struct array *a)
{
if(sp + a->size >= &evaluator_stack[EVALUATOR_STACK_SIZE])
error("Array does not fit on stack.\n");
check_array_for_destruct(a);
if(a->array_type == T_MIXED)
{
if(a->refs == 1)
{
MEMCPY(sp,ITEM(a),sizeof(struct svalue)*a->size);
sp += a->size;
a->size=0;
free_array(a);
return;
}else{
assign_svalues_no_free(sp, ITEM(a), a->size);
}
}else{
assign_from_short_svalues_no_free(sp, SHORT_ITEM(a), a->array_type, a->size);
}
sp += a->size;
free_array(a);
}
void describe_array_low(struct array *a, struct processing *p, int indent)
{
INT32 e,d;
indent += 2;
if(a->array_type == T_MIXED)
{
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);
}
}else{
struct svalue s;
for(e=0; e<a->size; e++)
{
if(e) my_strcat(",\n");
for(d=0; d<indent; d++) my_putchar(' ');
if(SHORT_ITEM(a)[e].refs)
{
s.type=a->array_type;
s.u=SHORT_ITEM(a)[e];
}else{
s.type=T_INT;
s.subtype=NUMBER_NUMBER;
s.u.integer=0;
}
describe_svalue(&s, 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)
{
if(a->array_type == T_MIXED)
{
describe_svalue(ITEM(a)+e, indent, p);
}else{
struct svalue s;
if(SHORT_ITEM(a)[e].refs)
{
s.type=a->array_type;
s.u=SHORT_ITEM(a)[e];
}else{
s.type=T_INT;
s.subtype=NUMBER_NUMBER;
s.u.integer=0;
}
describe_svalue(&s, indent, p);
}
}
void describe_array(struct array *a,struct processing *p,int indent)
{
struct processing doing;
INT32 e;
char buf[40];
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)
{
|