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"); }