ext/numo/narray/index.c in numo-narray-0.9.0.3 vs ext/numo/narray/index.c in numo-narray-0.9.0.4
- old
+ new
@@ -1,14 +1,9 @@
/*
index.c
Numerical Array Extension for Ruby
(C) Copyright 1999-2016 by Masahiro TANAKA
-
- This program is free software.
- You can distribute/modify this program
- under the same terms as Ruby itself.
- NO WARRANTY.
*/
//#define NARRAY_C
#include <string.h>
#include <ruby.h>
@@ -19,10 +14,28 @@
#define cIndex numo_cInt64
#elif SIZEOF_VOIDP == 4
#define cIndex numo_cInt32
#endif
+// from ruby/enumerator.c
+struct enumerator {
+ VALUE obj;
+ ID meth;
+ VALUE args;
+ // use only above in this source
+ VALUE fib;
+ VALUE dst;
+ VALUE lookahead;
+ VALUE feedvalue;
+ VALUE stop_exc;
+ VALUE size;
+ // incompatible below depending on ruby version
+ //VALUE procs; // ruby 2.4
+ //rb_enumerator_size_func *size_fn; // ruby 2.1-2.4
+ //VALUE (*size_fn)(ANYARGS); // ruby 2.0
+};
+
// note: the memory refed by this pointer is not freed and causes memroy leak.
typedef struct {
size_t n; // the number of elements of the dimesnion
size_t beg; // the starting point in the dimension
ssize_t step; // the step size of the dimension
@@ -56,55 +69,16 @@
static VALUE sym_reverse;
static VALUE sym_plus;
static VALUE sym_sum;
static VALUE sym_tilde;
static VALUE sym_rest;
-static VALUE id_beg;
-static VALUE id_end;
-static VALUE id_exclude_end;
+static ID id_beg;
+static ID id_end;
+static ID id_exclude_end;
+static ID id_each, id_step;
-static int
-na_index_preprocess(VALUE args, int na_ndim)
-{
- int i;
- int count_new=0, count_rest=0;
- int count_other_indices;
- int nidx = RARRAY_LEN(args);
- VALUE a;
- for (i=0; i<nidx; i++) {
- a = rb_ary_entry(args, i);
-
- if (a==sym_new || a==sym_minus) {
- RARRAY_ASET(args, i, sym_new);
- count_new++;
- } else if (a==sym_rest || a==sym_tilde || a==Qfalse) {
- RARRAY_ASET(args, i, Qfalse);
- count_rest++;
- }
- }
-
- count_other_indices = nidx - count_new - count_rest;
-
- if (count_rest>1) {
- rb_raise(rb_eIndexError,"multiple rest-dimension is not allowd");
- }
- else if (count_rest==0) {
- // if (!(count_new==0 && nidx==1) && ..
- if (count_other_indices != 1 && count_other_indices != na_ndim)
- rb_raise(rb_eIndexError,"# of index(=%i) should be one or "
- "equal to narray.ndim(=%i)",count_rest,na_ndim);
- }
- else if (count_rest==1) {
- if (count_other_indices >= na_ndim)
- rb_raise(rb_eIndexError,"# of index(=%i) >= narray.ndim(=%i) with :rest",
- count_other_indices,na_ndim);
- }
- return count_new;
-}
-
-
void
na_index_set_step(na_index_arg_t *q, int i, size_t n, size_t beg, ssize_t step)
{
q->n = n;
q->beg = beg;
@@ -112,11 +86,10 @@
q->idx = NULL;
q->reduce = 0;
q->orig_dim = i;
}
-
void
na_index_set_scalar(na_index_arg_t *q, int i, ssize_t size, ssize_t x)
{
if (x < -size || x >= size)
rb_raise(rb_eRangeError,
@@ -165,30 +138,36 @@
na_parse_narray_index(VALUE a, int orig_dim, ssize_t size, na_index_arg_t *q)
{
VALUE idx;
narray_t *na;
narray_data_t *nidx;
+ size_t k, n;
+ ssize_t *nidxp;
GetNArray(a,na);
if (NA_NDIM(na) != 1) {
rb_raise(rb_eIndexError, "should be 1-d NArray");
}
- idx = rb_narray_new(cIndex,1,&NA_SIZE(na));
+ n = NA_SIZE(na);
+ idx = rb_narray_new(cIndex,1,&n);
na_store(idx,a);
GetNArrayData(idx,nidx);
- q->idx = (size_t*)nidx->ptr;
- nidx->ptr = NULL;
- q->n = na->size;
+ nidxp = (ssize_t*)nidx->ptr;
+ q->idx = ALLOC_N(size_t, n);
+ for (k=0; k<n; k++) {
+ q->idx[k] = na_range_check(nidxp[k], size, orig_dim);
+ }
+ q->n = n;
q->beg = 0;
q->step = 1;
q->reduce = 0;
q->orig_dim = orig_dim;
}
static void
-na_parse_range(VALUE range, int orig_dim, ssize_t size, na_index_arg_t *q)
+na_parse_range(VALUE range, ssize_t step, int orig_dim, ssize_t size, na_index_arg_t *q)
{
int n;
ssize_t beg, end;
beg = NUM2LONG(rb_funcall(range,id_beg,0));
@@ -208,16 +187,50 @@
end < -size || end >= size) {
rb_raise(rb_eRangeError,
"beg=%"SZF"d,end=%"SZF"d is out of array size (%"SZF"d)",
beg, end, size);
}
- n = end-beg+1;
+ n = (end-beg)/step+1;
if (n<0) n=0;
- na_index_set_step(q,orig_dim,n,beg,1);
+ na_index_set_step(q,orig_dim,n,beg,step);
}
+static void
+na_parse_enumerator(VALUE enum_obj, int orig_dim, ssize_t size, na_index_arg_t *q)
+{
+ int len;
+ ssize_t step;
+ struct enumerator *e;
+
+ if (!RB_TYPE_P(enum_obj, T_DATA)) {
+ rb_raise(rb_eTypeError,"wrong argument type (not T_DATA)");
+ }
+ e = (struct enumerator *)DATA_PTR(enum_obj);
+
+ if (rb_obj_is_kind_of(e->obj, rb_cRange)) {
+ if (e->meth == id_each) {
+ na_parse_range(e->obj, 1, orig_dim, size, q);
+ }
+ else if (e->meth == id_step) {
+ if (TYPE(e->args) != T_ARRAY) {
+ rb_raise(rb_eArgError,"no argument for step");
+ }
+ len = RARRAY_LEN(e->args);
+ if (len != 1) {
+ rb_raise(rb_eArgError,"invalid number of step argument (1 for %d)",len);
+ }
+ step = NUM2SSIZET(RARRAY_AREF(e->args,0));
+ na_parse_range(e->obj, step, orig_dim, size, q);
+ } else {
+ rb_raise(rb_eTypeError,"unknown Range method: %s",rb_id2name(e->meth));
+ }
+ } else {
+ rb_raise(rb_eTypeError,"not Range object");
+ }
+}
+
// Analyze *a* which is *i*-th index object and store the information to q
//
// a: a ruby object of i-th index
// size: size of i-th dimension of original NArray
// i: parse i-th index
@@ -266,12 +279,15 @@
na_parse_array(a, i, size, q);
break;
default:
if (rb_obj_is_kind_of(a, rb_cRange)) {
- na_parse_range(a, i, size, q);
+ na_parse_range(a, 1, i, size, q);
}
+ else if (rb_obj_is_kind_of(a, rb_cEnumerator)) {
+ na_parse_enumerator(a, i, size, q);
+ }
else if (rb_obj_is_kind_of(a, na_cStep)) {
ssize_t beg, step, n;
nary_step_array_index(a, size, (size_t*)(&n), &beg, &step);
na_index_set_step(q,i,n,beg,step);
}
@@ -295,13 +311,14 @@
nidx = RARRAY_LEN(args);
for (i=j=k=0; i<nidx; i++) {
v = RARRAY_AREF(args,i);
- // rest dimension
+ // rest (ellipsis) dimension
if (v==Qfalse) {
for (l = ndim - (nidx-1); l>0; l--) {
+ //printf("i=%d j=%d k=%d l=%d ndim=%d nidx=%d\n",i,j,k,l,ndim,nidx);
na_index_parse_each(Qtrue, na->shape[k], k, &q[j]);
if (q[j].n > 1) {
total *= q[j].n;
}
j++;
@@ -553,12 +570,13 @@
case NARRAY_FILEMAP_T:
na_index_aref_nadata((narray_data_t *)na1,na2,q,na_get_elmsz(self),ndim,keep_dim);
na2->data = self;
break;
case NARRAY_VIEW_T:
- na_index_aref_naview((narray_view_t *)na1,na2,q,ndim,keep_dim);
+ na2->offset = ((narray_view_t *)na1)->offset;
na2->data = ((narray_view_t *)na1)->data;
+ na_index_aref_naview((narray_view_t *)na1,na2,q,ndim,keep_dim);
break;
}
if (store) {
na_get_pointer_for_write(store); // allocate memory
na_store(na_flatten_dim(store,0),view);
@@ -578,30 +596,25 @@
xfree(data->q);
return Qnil;
}
VALUE
-na_aref_md(int argc, VALUE *argv, VALUE self, int keep_dim)
+na_aref_md(int argc, VALUE *argv, VALUE self, int keep_dim, int result_nd)
{
VALUE args; // should be GC protected
narray_t *na1;
- int count_new, ndim;
na_aref_md_data_t data;
VALUE store = 0;
VALUE idx;
narray_t *nidx;
GetNArray(self,na1);
- //printf("argc=%d\n",argc);
-
args = rb_ary_new4(argc,argv);
- count_new = na_index_preprocess(args, na1->ndim);
-
- if (RARRAY_LEN(args)==1) {
- idx = RARRAY_AREF(args,0);
+ if (argc == 1 && result_nd == 1) {
+ idx = argv[0];
if (rb_obj_is_kind_of(idx, rb_cArray)) {
idx = rb_apply(numo_cNArray,rb_intern("[]"),idx);
}
if (rb_obj_is_kind_of(idx, numo_cNArray)) {
GetNArray(idx,nidx);
@@ -610,32 +623,31 @@
idx = na_flatten(idx);
RARRAY_ASET(args,0,idx);
}
}
// flatten should be done only for narray-view with non-uniform stride.
- self = na_flatten(self);
- GetNArray(self,na1);
+ if (na1->ndim > 1) {
+ self = na_flatten(self);
+ GetNArray(self,na1);
+ }
}
- ndim = na1->ndim + count_new;
data.args = args;
data.self = self;
data.store = store;
- data.ndim = ndim;
- data.q = na_allocate_index_args(ndim);
+ data.ndim = result_nd;
+ data.q = na_allocate_index_args(result_nd);
data.na1 = na1;
data.keep_dim = keep_dim;
return rb_ensure(na_aref_md_protected, (VALUE)&data, na_aref_md_ensure, (VALUE)&data);
}
-
-
/* method: [](idx1,idx2,...,idxN) */
VALUE
-na_aref_main(int nidx, VALUE *idx, VALUE self, int keep_dim)
+na_aref_main(int nidx, VALUE *idx, VALUE self, int keep_dim, int nd)
{
na_index_arg_to_internal_order(nidx, idx, self);
if (nidx==0) {
return rb_funcall(self,rb_intern("copy"),0);
@@ -643,122 +655,115 @@
if (nidx==1) {
if (CLASS_OF(*idx)==numo_cBit) {
return rb_funcall(*idx,rb_intern("mask"),1,self);
}
}
- return na_aref_md(nidx, idx, self, keep_dim);
+ return na_aref_md(nidx, idx, self, keep_dim, nd);
}
-/* method: [](idx1,idx2,...,idxN) */
-static VALUE na_aref(int argc, VALUE *argv, VALUE self)
-{
- VALUE view;
- view = na_aref_main(argc, argv, self, 0);
- return rb_funcall(view, rb_intern("extract"), 0);
-}
-
-
/* method: slice(idx1,idx2,...,idxN) */
static VALUE na_slice(int argc, VALUE *argv, VALUE self)
{
- return na_aref_main(argc, argv, self, 1);
-}
+ int nd;
+ size_t pos;
-
-
-
-/* method: []=(idx1,idx2,...,idxN,val) */
-static VALUE
-na_aset(int argc, VALUE *argv, VALUE self)
-{
- VALUE a;
- argc--;
-
- if (argc==0)
- na_store(self, argv[argc]);
- else {
- a = na_aref_main(argc, argv, self, 0);
- na_store(a, argv[argc]);
- }
- return argv[argc];
+ nd = na_get_result_dimension(self, argc, argv, 0, &pos);
+ return na_aref_main(argc, argv, self, 1, nd);
}
-// convert reduce dims to 0-th element
-// for initialization of min/max func
-// ['*,+,*'] -> [true,0,true]
-VALUE nary_init_accum_aref0(VALUE self, VALUE reduce)
+static int
+check_index_count(int argc, int na_ndim, int count_new, int count_rest)
{
- narray_t *na;
- VALUE a;
- ID id_bra;
- unsigned long m;
- int i, ndim;
+ int result_nd = na_ndim + count_new;
- GetNArray(self,na);
- ndim = na->ndim;
- a = rb_ary_new();
- if (FIXNUM_P(reduce)) {
- m = NUM2ULONG(reduce);
- if (m==0)
- for (i=0; i<ndim; i++)
- rb_ary_push(a,INT2FIX(0));
- else
- for (i=0; i<ndim; i++)
- if ((m>>i) & 1u)
- rb_ary_push(a,INT2FIX(0));
- else
- rb_ary_push(a,Qtrue);
- } else {
- id_bra = rb_intern("[]");
- for (i=0; i<ndim; i++)
- if (rb_funcall(reduce,id_bra,1,INT2FIX(i)) == INT2FIX(1))
- rb_ary_push(a,INT2FIX(0));
- else
- rb_ary_push(a,Qtrue);
+ switch(count_rest) {
+ case 0:
+ if (count_new == 0 && argc == 1) return 1;
+ if (argc == result_nd) return result_nd;
+ rb_raise(rb_eIndexError,"# of index(=%i) should be "
+ "equal to ndim(=%i)",argc,na_ndim);
+ break;
+ case 1:
+ if (argc-1 <= result_nd) return result_nd;
+ rb_raise(rb_eIndexError,"# of index(=%i) > ndim(=%i) with :rest",
+ argc,na_ndim);
+ break;
}
- return na_aref_md(RARRAY_LEN(a), RARRAY_PTR(a), self, 0);
+ return -1;
}
-
-ssize_t
-na_get_scalar_position(VALUE self, int argc, VALUE *argv, ssize_t stride)
+int
+na_get_result_dimension(VALUE self, int argc, VALUE *argv, ssize_t stride, size_t *pos_idx)
{
- int i;
+ int i, j;
+ int count_new=0;
+ int count_rest=0;
+ int count_else=0;
ssize_t x, s, m, pos, *idx;
narray_t *na;
narray_view_t *nv;
stridx_t sdx;
+ VALUE a;
GetNArray(self,na);
if (na->size == 0) {
rb_raise(rb_eRuntimeError, "cannot get index of empty array");
return -1;
}
- if (argc != 1 && argc != na->ndim) {
- return -1;
- }
idx = ALLOCA_N(ssize_t, argc);
- for (i=0; i<argc; i++) {
- switch(TYPE(argv[i])) {
+ for (i=j=0; i<argc; i++) {
+ a = argv[i];
+ switch(TYPE(a)) {
case T_FIXNUM:
- idx[i] = FIX2LONG(argv[i]);
+ idx[j++] = FIX2LONG(a);
break;
case T_BIGNUM:
case T_FLOAT:
- idx[i] = NUM2SSIZET(argv[i]);
+ idx[j++] = NUM2SSIZET(a);
break;
+ case T_FALSE:
+ case T_SYMBOL:
+ if (a==sym_rest || a==sym_tilde || a==Qfalse) {
+ argv[i] = Qfalse;
+ count_rest++;
+ break;
+ } else if (a==sym_new || a==sym_minus) {
+ argv[i] = sym_new;
+ count_new++;
+ }
+ // not break
default:
- return -1;
+ count_else++;
}
}
+
+ if (count_rest > 1) {
+ rb_raise(rb_eIndexError,"multiple rest-dimension is not allowd");
+ }
+ if (count_else != 0) {
+ return check_index_count(argc, na->ndim, count_new, count_rest);
+ }
+
switch(na->type) {
case NARRAY_VIEW_T:
GetNArrayView(self,nv);
pos = nv->offset;
- if (argc==1) {
+ if (j == na->ndim) {
+ for (i=j-1; i>=0; i--) {
+ x = na_range_check(idx[i], na->shape[i], i);
+ sdx = nv->stridx[i];
+ if (SDX_IS_INDEX(sdx)) {
+ pos += SDX_GET_INDEX(sdx)[x];
+ } else {
+ pos += SDX_GET_STRIDE(sdx)*x;
+ }
+ }
+ *pos_idx = pos;
+ }
+ else if (argc==1 && j==1) {
x = na_range_check(idx[0], na->size, 0);
for (i=na->ndim-1; i>=0; i--) {
s = na->shape[i];
m = x % s;
x = x / s;
@@ -767,48 +772,43 @@
pos += SDX_GET_INDEX(sdx)[m];
} else {
pos += SDX_GET_STRIDE(sdx)*m;
}
}
+ *pos_idx = pos;
} else {
- for (i=argc-1; i>=0; i--) {
- x = na_range_check(idx[i], na->shape[i], i);
- sdx = nv->stridx[i];
- if (SDX_IS_INDEX(sdx)) {
- pos += SDX_GET_INDEX(sdx)[x];
- } else {
- pos += SDX_GET_STRIDE(sdx)*x;
- }
- }
+ return check_index_count(argc, na->ndim, count_new, count_rest);
}
break;
default:
if (!stride) {
stride = na_get_elmsz(self);
}
- if (argc==1) {
+ if (argc==1 && j==1) {
x = na_range_check(idx[0], na->size, 0);
- pos = stride*x;
- } else {
+ *pos_idx = stride * x;
+ }
+ else if (j == na->ndim) {
pos = 0;
- for (i=argc-1; i>=0; i--) {
+ for (i=j-1; i>=0; i--) {
x = na_range_check(idx[i], na->shape[i], i);
- pos += stride*x;
+ pos += stride * x;
stride *= na->shape[i];
}
+ *pos_idx = pos;
+ } else {
+ return check_index_count(argc, na->ndim, count_new, count_rest);
}
}
- return pos;
+ return 0;
}
void
Init_nary_index()
{
- rb_define_method(cNArray, "[]", na_aref, -1);
rb_define_method(cNArray, "slice", na_slice, -1);
- rb_define_method(cNArray, "[]=", na_aset, -1);
sym_ast = ID2SYM(rb_intern("*"));
sym_all = ID2SYM(rb_intern("all"));
sym_minus = ID2SYM(rb_intern("-"));
sym_new = ID2SYM(rb_intern("new"));
@@ -819,6 +819,8 @@
sym_tilde = ID2SYM(rb_intern("~"));
sym_rest = ID2SYM(rb_intern("rest"));
id_beg = rb_intern("begin");
id_end = rb_intern("end");
id_exclude_end = rb_intern("exclude_end?");
+ id_each = rb_intern("each");
+ id_step = rb_intern("step");
}