ecl/src/c/array.d

1024 lines
24 KiB
C

/* -*- mode: c; c-basic-offset: 8 -*- */
/*
array.c -- Array routines
*/
/*
Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
Copyright (c) 1990, Giuseppe Attardi.
Copyright (c) 2001, Juan Jose Garcia Ripoll.
ECL is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
See file '../Copyright' for full details.
*/
#include <limits.h>
#include <string.h>
#include <ecl/ecl.h>
static const cl_index ecl_aet_size[] = {
sizeof(cl_object), /* aet_object */
sizeof(float), /* aet_sf */
sizeof(double), /* aet_df */
0, /* aet_bit: cannot be handled with this code */
sizeof(cl_fixnum), /* aet_fix */
sizeof(cl_index), /* aet_index */
sizeof(uint8_t), /* aet_b8 */
sizeof(int8_t), /* aet_i8 */
#ifdef ECL_UNICODE
sizeof(cl_object), /* aet_ch */
#endif
sizeof(unsigned char) /* aet_bc */
};
static void displace (cl_object from, cl_object to, cl_object offset);
static void check_displaced (cl_object dlist, cl_object orig, cl_index newdim);
static void
FEbad_aet()
{
FEerror(
"A routine from ECL got an object with a bad array element type.\n"
"If you are running a standard copy of ECL, please report this bug.\n"
"If you are embedding ECL into an application, please ensure you\n"
"passed the right value to the array creation routines.\n",0);
}
static cl_object
ecl_out_of_bounds_error(cl_object fun, const char *place, cl_object value,
cl_object min, cl_object max)
{
cl_object type = cl_list(3, @'integer', min, max);
return ecl_type_error(fun, place, value, type);
}
cl_index
ecl_to_index(cl_object n)
{
switch (type_of(n)) {
case t_fixnum: {
cl_fixnum out = fix(n);
if (out < 0 || out >= ADIMLIM)
FEtype_error_index(Cnil, n);
return out;
}
case t_bignum:
FEtype_error_index(Cnil, n);
default:
FEtype_error_integer(n);
}
}
cl_object
cl_row_major_aref(cl_object x, cl_object indx)
{
cl_index j = fixnnint(indx);
@(return ecl_aref(x, j))
}
cl_object
si_row_major_aset(cl_object x, cl_object indx, cl_object val)
{
cl_index j = fixnnint(indx);
@(return ecl_aset(x, j, val))
}
@(defun aref (x &rest indx)
@ {
cl_index i, j;
cl_index r = narg - 1;
AGAIN:
switch (type_of(x)) {
case t_array:
if (r != x->array.rank)
FEerror("Wrong number of indices.", 0);
for (i = j = 0; i < r; i++) {
cl_index s =
ecl_fixnum_in_range(@'aref',"index",cl_va_arg(indx),
0, (cl_fixnum)x->array.dims[i]-1);
j = j*(x->array.dims[i]) + s;
}
break;
case t_vector:
#ifdef ECL_UNICODE
case t_string:
#endif
case t_base_string:
case t_bitvector:
if (r != 1)
FEerror("Wrong number of indices.", 0);
j = ecl_fixnum_in_range(@'aref',"index",cl_va_arg(indx),
0, (cl_fixnum)x->vector.dim-1);
break;
default:
x = ecl_type_error(@'aref',"argument",x,@'array');
goto AGAIN;
}
@(return ecl_aref(x, j));
} @)
cl_object
ecl_aref(cl_object x, cl_index index)
{
AGAIN:
if (index >= x->array.dim) {
cl_object i;
i = ecl_out_of_bounds_error(@'row-major-aref', "index",
MAKE_FIXNUM(index), MAKE_FIXNUM(0),
MAKE_FIXNUM(x->array.dim));
index = fix(i);
goto AGAIN;
}
switch ((cl_elttype)ecl_array_elttype(x)) {
case aet_object:
#ifdef ECL_UNICODE
case aet_ch:
#endif
return(x->array.self.t[index]);
case aet_bc:
return(CODE_CHAR(x->base_string.self[index]));
case aet_bit:
index += x->vector.offset;
if (x->vector.self.bit[index/CHAR_BIT] & (0200>>index%CHAR_BIT))
return(MAKE_FIXNUM(1));
else
return(MAKE_FIXNUM(0));
case aet_fix:
return ecl_make_integer(x->array.self.fix[index]);
case aet_index:
return ecl_make_unsigned_integer(x->array.self.index[index]);
case aet_sf:
return(ecl_make_singlefloat(x->array.self.sf[index]));
case aet_df:
return(ecl_make_doublefloat(x->array.self.df[index]));
case aet_b8:
return(MAKE_FIXNUM(x->array.self.b8[index]));
case aet_i8:
return(MAKE_FIXNUM(x->array.self.i8[index]));
default:
FEbad_aet();
}
}
cl_object
ecl_aref1(cl_object v, cl_index index)
{
AGAIN:
switch (type_of(v)) {
#ifdef ECL_UNICODE
case t_string:
#endif
case t_vector:
case t_bitvector:
return ecl_aref(v, index);
case t_base_string:
if (index >= v->base_string.dim) {
cl_object i;
i = ecl_out_of_bounds_error(@'row-major-aref',"index",
MAKE_FIXNUM(index),
MAKE_FIXNUM(0),
MAKE_FIXNUM(v->base_string.dim));
index = fix(i);
goto AGAIN;
}
return CODE_CHAR(v->base_string.self[index]);
default:
v = ecl_type_error(@'row-major-aref',"argument",v,@'vector');
goto AGAIN;
}
}
/*
Internal function for setting array elements:
(si:aset value array dim0 ... dimN)
*/
@(defun si::aset (v x &rest dims)
@ {
cl_index i, j;
cl_index r = narg - 2;
AGAIN:
switch (type_of(x)) {
case t_array:
if (r != x->array.rank)
FEerror("Wrong number of indices.", 0);
for (i = j = 0; i < r; i++) {
cl_index s =
ecl_fixnum_in_range(@'si::aset',"index",cl_va_arg(dims),
0, (cl_fixnum)x->array.dims[i]-1);
j = j*(x->array.dims[i]) + s;
}
break;
case t_vector:
#ifdef ECL_UNICODE
case t_string:
#endif
case t_base_string:
case t_bitvector:
if (r != 1)
FEerror("Wrong number of indices.", 0);
j = ecl_fixnum_in_range(@'si::aset',"index",cl_va_arg(dims),
0, (cl_fixnum)x->vector.dim - 1);
break;
default:
x = ecl_type_error(@'si::aset',"destination",v,@'array');
goto AGAIN;
}
@(return ecl_aset(x, j, v))
} @)
cl_object
ecl_aset(cl_object x, cl_index index, cl_object value)
{
if (index >= x->array.dim)
FEerror("The index, ~D, too large.", 1, MAKE_FIXNUM(index));
switch (ecl_array_elttype(x)) {
case aet_object:
#ifdef ECL_UNICODE
case aet_ch:
#endif
x->array.self.t[index] = value;
break;
case aet_bc:
/* INV: ecl_char_code() checks the type of `value' */
x->base_string.self[index] = ecl_char_code(value);
break;
case aet_bit: {
cl_fixnum i = ecl_fixnum_in_range(@'si::aset',"bit",value,0,1);
index += x->vector.offset;
if (i == 0)
x->vector.self.bit[index/CHAR_BIT] &= ~(0200>>index%CHAR_BIT);
else
x->vector.self.bit[index/CHAR_BIT] |= 0200>>index%CHAR_BIT;
break;
}
case aet_fix:
x->array.self.fix[index] = fixint(value);
break;
case aet_index:
x->array.self.index[index] = fixnnint(value);
break;
case aet_sf:
x->array.self.sf[index] = ecl_to_float(value);
break;
case aet_df:
x->array.self.df[index] = ecl_to_double(value);
break;
case aet_b8: {
uint8_t i = ecl_fixnum_in_range(@'si::aset',"byte",value,0,255);
x->array.self.b8[index] = i;
break;
}
case aet_i8: {
int8_t i = ecl_fixnum_in_range(@'si::aset',"byte",value,-128,127);
x->array.self.i8[index] = i;
break;
}
}
return(value);
}
cl_object
ecl_aset1(cl_object v, cl_index index, cl_object val)
{
AGAIN:
switch (type_of(v)) {
#ifdef ECL_UNICODE
case t_string:
#endif
case t_vector:
case t_bitvector:
return(ecl_aset(v, index, val));
case t_base_string:
while (index >= v->base_string.dim) {
cl_object i = ecl_out_of_bounds_error(@'si::row-major-aset',
"index",
MAKE_FIXNUM(index),
MAKE_FIXNUM(0),
MAKE_FIXNUM(v->base_string.dim));
index = fix(i);
}
/* INV: ecl_char_code() checks the type of `val' */
v->base_string.self[index] = ecl_char_code(val);
return(val);
default:
v = ecl_type_error(@'row-major-aref',"argument",v,@'vector');
goto AGAIN;
}
}
/*
Internal function for making arrays of more than one dimension:
(si:make-pure-array dimension-list element-type adjustable
displaced-to displaced-index-offset)
*/
cl_object
si_make_pure_array(cl_object etype, cl_object dims, cl_object adj,
cl_object fillp, cl_object displ, cl_object disploff)
{
cl_index r, s, i, j;
cl_object x;
if (FIXNUMP(dims)) {
return si_make_vector(etype, dims, adj, fillp, displ, disploff);
}
r = ecl_length(dims);
if (r >= ARANKLIM) {
FEerror("The array rank, ~R, is too large.", 1, MAKE_FIXNUM(r));
} else if (r == 1) {
return si_make_vector(etype, ECL_CONS_CAR(dims), adj, fillp,
displ, disploff);
} else if (!Null(fillp)) {
FEerror(":FILL-POINTER may not be specified for an array of rank ~D",
1, MAKE_FIXNUM(r));
}
x = cl_alloc_object(t_array);
x->array.displaced = Cnil;
x->array.self.t = NULL; /* for GC sake */
x->array.rank = r;
x->array.elttype = (short)ecl_symbol_to_elttype(etype);
x->array.dims = (cl_index *)cl_alloc_atomic_align(sizeof(cl_index)*r, sizeof(cl_index));
for (i = 0, s = 1; i < r; i++, dims = ECL_CONS_CDR(dims)) {
j = ecl_fixnum_in_range(@'make-array', "dimension",
ECL_CONS_CAR(dims), 0, ADIMLIM);
s *= (x->array.dims[i] = j);
if (s > ATOTLIM)
FEerror("The array total size, ~D, is too large.", 1, MAKE_FIXNUM(s));
}
x->array.dim = s;
x->array.adjustable = adj != Cnil;
if (Null(displ))
ecl_array_allocself(x);
else
displace(x, displ, disploff);
@(return x);
}
/*
Internal function for making vectors:
(si:make-vector element-type dimension adjustable fill-pointer
displaced-to displaced-index-offset)
*/
cl_object
si_make_vector(cl_object etype, cl_object dim, cl_object adj,
cl_object fillp, cl_object displ, cl_object disploff)
{
cl_index d, f;
cl_object x;
cl_elttype aet;
AGAIN:
aet = ecl_symbol_to_elttype(etype);
d = ecl_fixnum_in_range(@'make-array',"dimension",dim,0,ADIMLIM);
if (aet == aet_bc) {
x = cl_alloc_object(t_base_string);
} else if (aet == aet_bit) {
x = cl_alloc_object(t_bitvector);
#ifdef ECL_UNICODE
} else if (aet == aet_ch) {
x = cl_alloc_object(t_string);
#endif
} else {
x = cl_alloc_object(t_vector);
x->vector.elttype = (short)aet;
}
x->vector.self.t = NULL; /* for GC sake */
x->vector.displaced = Cnil;
x->vector.dim = d;
x->vector.adjustable = adj != Cnil;
if (Null(fillp)) {
x->vector.hasfillp = FALSE;
f = d;
} else if (fillp == Ct) {
x->vector.hasfillp = TRUE;
f = d;
} else if (FIXNUMP(fillp) && ((f = fix(fillp)) <= d) && (f >= 0)) {
x->vector.hasfillp = TRUE;
} else {
fillp = ecl_type_error(@'make-array',"fill pointer",fillp,
cl_list(3,@'or',cl_list(3,@'member',Cnil,Ct),
cl_list(3,@'integer',MAKE_FIXNUM(0),
dim)));
goto AGAIN;
}
x->vector.fillp = f;
if (Null(displ))
ecl_array_allocself(x);
else
displace(x, displ, disploff);
@(return x)
}
void
ecl_array_allocself(cl_object x)
{
cl_index i, d;
d = x->array.dim;
start_critical_section(); /* avoid losing elts */
switch (ecl_array_elttype(x)) {
/* assign self field only after it has been filled, for GC sake */
case aet_object: {
cl_object *elts;
elts = (cl_object *)cl_alloc_align(sizeof(cl_object)*d, sizeof(cl_object));
for (i = 0; i < d; i++)
elts[i] = Cnil;
x->array.self.t = elts;
break;
}
#ifdef ECL_UNICODE
case aet_ch: {
cl_object *elts;
elts = (cl_object *)cl_alloc_align(sizeof(cl_object)*d, sizeof(cl_object));
for (i = 0; i < d; i++)
elts[i] = CODE_CHAR(' ');
x->string.self = elts;
break;
}
#endif
case aet_bc: {
char *elts;
elts = (char *)cl_alloc_atomic(d+1);
for (i = 0; i < d; i++)
elts[i] = ' ';
elts[d] = '\0';
x->base_string.self = elts;
break;
}
case aet_bit: {
byte *elts;
d = (d+(CHAR_BIT-1))/CHAR_BIT;
elts = (byte *)cl_alloc_atomic(d);
for (i = 0; i < d; i++)
elts[i] = '\0';
x->vector.offset = 0;
x->vector.self.bit = elts;
break;
}
case aet_fix: {
cl_fixnum *elts;
elts = (cl_fixnum *)cl_alloc_atomic_align(sizeof(*elts)*d, sizeof(*elts));
for (i = 0; i < d; i++)
elts[i] = 0;
x->array.self.fix = elts;
break;
}
case aet_index: {
cl_fixnum *elts;
elts = (cl_fixnum *)cl_alloc_atomic_align(sizeof(*elts)*d, sizeof(*elts));
for (i = 0; i < d; i++)
elts[i] = 0;
x->array.self.fix = elts;
break;
}
case aet_sf: {
float *elts;
elts = (float *)cl_alloc_atomic_align(sizeof(*elts)*d, sizeof(*elts));
for (i = 0; i < d; i++)
elts[i] = 0.0;
x->array.self.sf = elts;
break;
}
case aet_df: {
double *elts;
elts = (double *)cl_alloc_atomic_align(sizeof(*elts)*d, sizeof(*elts));
for (i = 0; i < d; i++)
elts[i] = 0.0;
x->array.self.df = elts;
break;
}
case aet_b8: {
uint8_t *elts;
elts = (uint8_t *)cl_alloc_atomic_align(sizeof(*elts)*d, sizeof(*elts));
for (i = 0; i < d; i++)
elts[i] = 0;
x->array.self.b8 = elts;
break;
}
case aet_i8: {
int8_t *elts;
elts = (int8_t *)cl_alloc_atomic_align(sizeof(*elts)*d, sizeof(*elts));
for (i = 0; i < d; i++)
elts[i] = 0;
x->array.self.i8 = elts;
break;
}
}
end_critical_section();
}
cl_elttype
ecl_symbol_to_elttype(cl_object x)
{
BEGIN:
if (x == @'base-char')
return(aet_bc);
#ifdef ECL_UNICODE
if (x == @'character')
return(aet_ch);
#endif
else if (x == @'bit')
return(aet_bit);
else if (x == @'ext::cl-fixnum')
return(aet_fix);
else if (x == @'ext::cl-index')
return(aet_index);
else if (x == @'single-float' || x == @'short-float')
return(aet_sf);
else if (x == @'long-float' || x == @'double-float')
return(aet_df);
else if (x == @'ext::byte8')
return(aet_b8);
else if (x == @'ext::integer8')
return(aet_i8);
else if (x == @'t')
return(aet_object);
else if (x == Cnil) {
FEerror("ECL does not support arrays with element type NIL", 0);
}
x = cl_funcall(2, @'upgraded-array-element-type', x);
goto BEGIN;
}
cl_object
ecl_elttype_to_symbol(cl_elttype aet)
{
cl_object output;
switch (aet) {
case aet_object: output = Ct; break;
#ifdef ECL_UNICODE
case aet_ch: output = @'character'; break;
#endif
case aet_bc: output = @'base-char'; break;
case aet_bit: output = @'bit'; break;
case aet_fix: output = @'ext::cl-fixnum'; break;
case aet_index: output = @'ext::cl-index'; break;
case aet_sf: output = @'single-float'; break;
case aet_df: output = @'double-float'; break;
case aet_b8: output = @'ext::byte8'; break;
case aet_i8: output = @'ext::integer8'; break;
}
return output;
}
static void *
address_inc(void *address, cl_fixnum inc, cl_elttype elt_type)
{
union ecl_array_data aux;
aux.t = address;
switch (elt_type) {
#ifdef ECL_UNICODE
case aet_ch:
#endif
case aet_object:
return aux.t + inc;
case aet_fix:
return aux.fix + inc;
case aet_index:
return aux.fix + inc;
case aet_sf:
return aux.sf + inc;
case aet_bc:
return aux.ch + inc;
case aet_df:
return aux.df + inc;
case aet_b8:
return aux.b8 + inc;
case aet_i8:
return aux.i8 + inc;
default:
FEbad_aet();
}
}
static void *
array_address(cl_object x, cl_index inc)
{
return address_inc(x->array.self.t, inc, ecl_array_elttype(x));
}
cl_object
cl_array_element_type(cl_object a)
{
@(return ecl_elttype_to_symbol(ecl_array_elttype(a)))
}
/*
Displace(from, to, offset) displaces the from-array
to the to-array (the original array) by the specified offset.
It changes the a_displaced field of both arrays.
The field is a cons; the car of the from-array points to
the to-array and the cdr of the to-array is a list of arrays
displaced to the to-array, so the from-array is pushed to the
cdr of the to-array's array.displaced.
*/
static void
displace(cl_object from, cl_object to, cl_object offset)
{
cl_index j;
void *base;
cl_elttype totype, fromtype;
fromtype = ecl_array_elttype(from);
if (type_of(to) == t_foreign) {
if (fromtype == aet_bit || fromtype == aet_object) {
FEerror("Cannot displace arrays with element type T or BIT onto foreign data",0);
}
base = to->foreign.data;
j = ecl_fixnum_in_range(@'adjust-array',"array displacement", offset,
0, MOST_POSITIVE_FIXNUM);
from->array.displaced = to;
} else {
totype = ecl_array_elttype(to);
if (totype != fromtype)
FEerror("Cannot displace the array,~%\
because the element types don't match.", 0);
if (from->array.dim > to->array.dim)
FEerror("Cannot displace the array,~%\
because the total size of the to-array is too small.", 0);
j = ecl_fixnum_in_range(@'adjust-array',"array displacement",offset,
0, to->array.dim - from->array.dim);
from->array.displaced = ecl_list1(to);
if (Null(to->array.displaced))
to->array.displaced = ecl_list1(Cnil);
ECL_RPLACD(to->array.displaced, CONS(from, CDR(to->array.displaced)));
if (fromtype == aet_bit) {
j += to->vector.offset;
from->vector.offset = j%CHAR_BIT;
from->vector.self.bit = to->vector.self.bit + j/CHAR_BIT;
return;
}
base = to->array.self.t;
}
from->array.self.t = address_inc(base, j, fromtype);
}
cl_elttype
ecl_array_elttype(cl_object x)
{
switch(type_of(x)) {
case t_array:
case t_vector:
return((cl_elttype)x->array.elttype);
#ifdef ECL_UNICODE
case t_string:
return(aet_ch);
#endif
case t_base_string:
return(aet_bc);
case t_bitvector:
return(aet_bit);
default:
FEwrong_type_argument(@'array', x);
}
}
cl_object
cl_array_rank(cl_object a)
{
assert_type_array(a);
@(return ((type_of(a) == t_array) ? MAKE_FIXNUM(a->array.rank)
: MAKE_FIXNUM(1)))
}
cl_object
cl_array_dimension(cl_object a, cl_object index)
{
cl_index dim;
AGAIN:
switch (type_of(a)) {
case t_array: {
int i = ecl_fixnum_in_range(@'array-dimension',"dimension",index,
0,a->array.rank);
dim = a->array.dims[i];
break;
}
#ifdef ECL_UNICODE
case t_string:
#endif
case t_base_string:
case t_vector:
case t_bitvector:
ecl_fixnum_in_range(@'array-dimension',"dimension",index,0,0);
dim = a->vector.dim;
break;
default:
a = ecl_type_error(@'array-dimension',"argument",a,@'array');
goto AGAIN;
}
@(return MAKE_FIXNUM(dim))
}
cl_object
cl_array_total_size(cl_object a)
{
assert_type_array(a);
@(return MAKE_FIXNUM(a->array.dim))
}
cl_object
cl_adjustable_array_p(cl_object a)
{
assert_type_array(a);
@(return (a->array.adjustable ? Ct : Cnil))
}
/*
Internal function for checking if an array is displaced.
*/
cl_object
cl_array_displacement(cl_object a)
{
cl_object to_array;
cl_index offset;
assert_type_array(a);
to_array = a->array.displaced;
if (Null(to_array)) {
offset = 0;
} else if (Null(to_array = CAR(a->array.displaced))) {
offset = 0;
} else {
switch (ecl_array_elttype(a)) {
#ifdef ECL_UNICODE
case aet_ch:
#endif
case aet_object:
offset = a->array.self.t - to_array->array.self.t;
break;
case aet_bc:
offset = a->array.self.ch - to_array->array.self.ch;
break;
case aet_bit:
offset = a->array.self.bit - to_array->array.self.bit;
offset = offset * CHAR_BIT + a->array.offset
- to_array->array.offset;
break;
case aet_fix:
offset = a->array.self.fix - to_array->array.self.fix;
break;
case aet_index:
offset = a->array.self.fix - to_array->array.self.fix;
break;
case aet_sf:
offset = a->array.self.sf - to_array->array.self.sf;
break;
case aet_df:
offset = a->array.self.df - to_array->array.self.df;
break;
case aet_b8:
case aet_i8:
offset = a->array.self.b8 - to_array->array.self.b8;
break;
default:
FEbad_aet();
}
}
@(return to_array MAKE_FIXNUM(offset));
}
cl_object
cl_svref(cl_object x, cl_object index)
{
cl_index i;
while (type_of(x) != t_vector ||
x->vector.adjustable ||
x->vector.hasfillp ||
CAR(x->vector.displaced) != Cnil ||
(cl_elttype)x->vector.elttype != aet_object)
{
x = ecl_type_error(@'svref',"argument",x,@'simple-vector');
}
i = ecl_fixnum_in_range(@'svref',"index",index,0,(cl_fixnum)x->vector.dim-1);
@(return x->vector.self.t[i])
}
cl_object
si_svset(cl_object x, cl_object index, cl_object v)
{
cl_index i;
while (type_of(x) != t_vector ||
x->vector.adjustable ||
x->vector.hasfillp ||
CAR(x->vector.displaced) != Cnil ||
(cl_elttype)x->vector.elttype != aet_object)
{
x = ecl_type_error(@'si::svset',"argument",x,@'simple-vector');
}
i = ecl_fixnum_in_range(@'svref',"index",index,0,(cl_fixnum)x->vector.dim-1);
@(return (x->vector.self.t[i] = v))
}
cl_object
cl_array_has_fill_pointer_p(cl_object a)
{
cl_object r;
AGAIN:
switch (type_of(a)) {
case t_array:
r = Cnil; break;
case t_vector:
case t_bitvector:
#ifdef ECL_UNICODE
case t_string:
#endif
case t_base_string:
r = a->vector.hasfillp? Ct : Cnil;
break;
default:
a = ecl_type_error(@'array-has-fill-pointer-p',"argument",
a, @'array');
goto AGAIN;
}
@(return r)
}
cl_object
cl_fill_pointer(cl_object a)
{
assert_type_vector(a);
if (!a->vector.hasfillp) {
a = ecl_type_error(@'fill-pointer', "argument",
a, c_string_to_object("(AND VECTOR (SATISFIES ARRAY-HAS-FILL-POINTER-P))"));
}
@(return MAKE_FIXNUM(a->vector.fillp))
}
/*
Internal function for setting fill pointer.
*/
cl_object
si_fill_pointer_set(cl_object a, cl_object fp)
{
assert_type_vector(a);
AGAIN:
if (a->vector.hasfillp) {
a->vector.fillp =
ecl_fixnum_in_range(@'adjust-array',"fill pointer",fp,
0,a->vector.dim);
} else {
FEerror("The vector ~S has no fill pointer.", 1, a);
}
@(return fp)
}
/*
Internal function for replacing the contents of arrays:
(si:replace-array old-array new-array).
Used in ADJUST-ARRAY.
*/
cl_object
si_replace_array(cl_object olda, cl_object newa)
{
cl_object dlist;
if (type_of(olda) != type_of(newa)
|| (type_of(olda) == t_array && olda->array.rank != newa->array.rank))
goto CANNOT;
if (!olda->array.adjustable) {
/* When an array is not adjustable, we simply output the new array */
olda = newa;
goto OUTPUT;
}
for (dlist = CDR(olda->array.displaced); dlist != Cnil; dlist = CDR(dlist)) {
cl_object other_array = CAR(dlist);
cl_object offset;
cl_array_displacement(other_array);
offset = VALUES(1);
displace(other_array, newa, offset);
}
switch (type_of(olda)) {
case t_array:
case t_vector:
case t_bitvector:
olda->array = newa->array;
break;
#ifdef ECL_UNICODE
case t_string:
#endif
case t_base_string:
olda->base_string = newa->base_string;
break;
default:
CANNOT:
FEerror("Cannot replace the array ~S by the array ~S.",
2, olda, newa);
}
OUTPUT:
@(return olda)
}
void
ecl_copy_subarray(cl_object dest, cl_index i0, cl_object orig,
cl_index i1, cl_index l)
{
cl_elttype t = ecl_array_elttype(dest);
if (i0 + l > dest->array.dim) {
l = dest->array.dim - i0;
}
if (i1 + l > orig->array.dim) {
l = orig->array.dim - i1;
}
if (t != ecl_array_elttype(orig) || t == aet_bit) {
while (l--) {
ecl_aset(dest, i0++, ecl_aref(orig, i1++));
}
} else if (t >= 0 && t <= aet_last_type) {
cl_index elt_size = ecl_aet_size[t];
memcpy(dest->array.self.ch + i0 * elt_size,
orig->array.self.ch + i1 * elt_size,
l * elt_size);
} else {
FEbad_aet();
}
}
void
ecl_reverse_subarray(cl_object x, cl_index i0, cl_index i1)
{
cl_elttype t = ecl_array_elttype(x);
cl_index i, j;
if (x->array.dim == 0) {
return;
}
if (i1 >= x->array.dim) {
i1 = x->array.dim;
}
switch (t) {
#ifdef ECL_UNICODE
case aet_ch:
#endif
case aet_object:
case aet_fix:
case aet_index:
for (i = i0, j = i1-1; i < j; i++, --j) {
cl_object y = x->vector.self.t[i];
x->vector.self.t[i] = x->vector.self.t[j];
x->vector.self.t[j] = y;
}
break;
case aet_sf:
for (i = i0, j = i1-1; i < j; i++, --j) {
float y = x->array.self.sf[i];
x->array.self.sf[i] = x->array.self.sf[j];
x->array.self.sf[j] = y;
}
break;
case aet_df:
for (i = i0, j = i1-1; i < j; i++, --j) {
double y = x->array.self.df[i];
x->array.self.df[i] = x->array.self.df[j];
x->array.self.df[j] = y;
}
break;
case aet_b8:
for (i = i0, j = i1-1; i < j; i++, --j) {
uint8_t y = x->array.self.b8[i];
x->array.self.b8[i] = x->array.self.b8[j];
x->array.self.b8[j] = y;
}
break;
case aet_i8:
for (i = i0, j = i1-1; i < j; i++, --j) {
int8_t y = x->array.self.i8[i];
x->array.self.i8[i] = x->array.self.i8[j];
x->array.self.i8[j] = y;
}
break;
case aet_bc:
for (i = i0, j = i1-1; i < j; i++, --j) {
unsigned char y = x->array.self.ch[i];
x->array.self.ch[i] = x->array.self.ch[j];
x->array.self.ch[j] = y;
}
break;
case aet_bit:
for (i = i0 + x->vector.offset,
j = i1 + x->vector.offset - 1;
i < j;
i++, --j) {
int k = x->array.self.bit[i/CHAR_BIT]&(0200>>i%CHAR_BIT);
if (x->array.self.bit[j/CHAR_BIT]&(0200>>j%CHAR_BIT))
x->array.self.bit[i/CHAR_BIT]
|= 0200>>i%CHAR_BIT;
else
x->array.self.bit[i/CHAR_BIT]
&= ~(0200>>i%CHAR_BIT);
if (k)
x->array.self.bit[j/CHAR_BIT]
|= 0200>>j%CHAR_BIT;
else
x->array.self.bit[j/CHAR_BIT]
&= ~(0200>>j%CHAR_BIT);
}
break;
default:
FEbad_aet();
}
}