ext/numo/narray/array.c in numo-narray-0.9.0.4 vs ext/numo/narray/array.c in numo-narray-0.9.0.5
- old
+ new
@@ -1,15 +1,14 @@
/*
array.c
Numerical Array Extension for Ruby
- (C) Copyright 1999-2016 by Masahiro TANAKA
+ (C) Copyright 1999-2017 by Masahiro TANAKA
*/
#include <ruby.h>
#include "numo/narray.h"
-//#include "narray_local.h"
-/* Multi-Dimensional Array Investigation */
+// mdai: Multi-Dimensional Array Investigation
typedef struct {
size_t shape;
VALUE val;
} na_mdai_item_t;
@@ -23,10 +22,57 @@
// Order of Ruby object.
enum { NA_NONE, NA_BIT, NA_INT32, NA_INT64, NA_RATIONAL,
NA_DFLOAT, NA_DCOMPLEX, NA_ROBJ, NA_NTYPES };
+static ID id_begin;
+static ID id_end;
+static ID id_step;
+static ID id_abs;
+static ID id_cast;
+static ID id_le;
+static ID id_Complex;
+
+typedef struct {
+ int ndim;
+ size_t *shape;
+ VALUE dtype;
+} na_compose_t;
+
+static size_t
+na_compose_memsize(const void *ptr)
+{
+ const na_compose_t *nc = (const na_compose_t*)ptr;
+
+ return sizeof(na_compose_t) + nc->ndim * sizeof(size_t);
+}
+
+static void
+na_compose_free(void *ptr)
+{
+ na_compose_t *nc = (na_compose_t*)ptr;
+
+ if (nc->shape)
+ xfree(nc->shape);
+ xfree(nc);
+}
+
+static void
+na_compose_gc_mark(void* nc)
+{
+ rb_gc_mark(((na_compose_t*)nc)->dtype);
+}
+
+static const rb_data_type_t compose_data_type = {
+ "Numo::NArray/compose",
+ {na_compose_gc_mark, na_compose_free, na_compose_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+};
+
+#define WrapCompose(p) TypedData_Wrap_Struct(rb_cData, &compose_data_type, (void*)(p));
+#define GetCompose(v,p) TypedData_Get_Struct(v, na_compose_t, &compose_data_type, p)
+
static VALUE
na_object_type(int type, VALUE v)
{
static VALUE int32_max = Qnil;
if (NIL_P(int32_max))
@@ -45,12 +91,12 @@
if (type<NA_INT32)
return NA_INT32;
return type;
case T_BIGNUM:
if (type<NA_INT64) {
- v = rb_funcall(v,rb_intern("abs"),0);
- if (RTEST(rb_funcall(v,rb_intern("<="),1,int32_max))) {
+ v = rb_funcall(v,id_abs,0);
+ if (RTEST(rb_funcall(v,id_le,1,int32_max))) {
if (type<NA_INT32)
return NA_INT32;
} else {
return NA_INT64;
}
@@ -76,12 +122,12 @@
return type;
#else
case T_FIXNUM:
case T_BIGNUM:
if (type<NA_INT64) {
- v = rb_funcall(v,rb_intern("abs"),0);
- if (RTEST(rb_funcall(v,rb_intern("<="),1,int32_max))) {
+ v = rb_funcall(v,id_abs,0);
+ if (RTEST(rb_funcall(v,id_le,1,int32_max))) {
if (type<NA_INT32)
return NA_INT32;
} else {
return NA_INT64;
}
@@ -96,36 +142,36 @@
case T_NIL:
return type;
default:
- if (CLASS_OF(v) == rb_const_get( rb_cObject, rb_intern("Complex") )) {
+ if (CLASS_OF(v) == rb_const_get( rb_cObject, id_Complex )) {
return NA_DCOMPLEX;
}
}
return NA_ROBJ;
}
#define MDAI_ATTR_TYPE(tp,v,attr) \
- {tp = na_object_type(tp,rb_funcall(v,rb_intern(attr),0));}
+ {tp = na_object_type(tp,rb_funcall(v,id_##attr,0));}
void na_mdai_object_type(na_mdai_t *mdai, VALUE v)
{
if (IsNArray(v)) {
if (NIL_P(mdai->na_type)) {
mdai->na_type = CLASS_OF(v);
} else {
mdai->na_type = na_upcast(CLASS_OF(v), mdai->na_type);
}
} else if (rb_obj_is_kind_of(v, rb_cRange)) {
- MDAI_ATTR_TYPE(mdai->type,v,"begin");
- MDAI_ATTR_TYPE(mdai->type,v,"end");
+ MDAI_ATTR_TYPE(mdai->type,v,begin);
+ MDAI_ATTR_TYPE(mdai->type,v,end);
} else if (rb_obj_is_kind_of(v, na_cStep)) {
- MDAI_ATTR_TYPE(mdai->type,v,"begin");
- MDAI_ATTR_TYPE(mdai->type,v,"end");
- MDAI_ATTR_TYPE(mdai->type,v,"step");
+ MDAI_ATTR_TYPE(mdai->type,v,begin);
+ MDAI_ATTR_TYPE(mdai->type,v,end);
+ MDAI_ATTR_TYPE(mdai->type,v,step);
} else {
mdai->type = na_object_type(mdai->type,v);
}
}
@@ -164,12 +210,13 @@
mdai->item[i].val = Qnil;
}
}
static void
-na_mdai_free(na_mdai_t *mdai)
+na_mdai_free(void *ptr)
{
+ na_mdai_t *mdai = (na_mdai_t*)ptr;
xfree(mdai->item);
xfree(mdai);
}
@@ -253,19 +300,13 @@
nc->shape = NULL;
nc->dtype = Qnil;
if (ndim>0) {
// Shape
- //shape = ALLOC_N(size_t,i);
- //for (i=0; i<*ndim; i++) {
- // shape[i] = mdai->item[i].shape;
- //}
nc->shape = shape = ALLOC_N(size_t,ndim);
for (i=0; i<ndim; i++) {
shape[i] = mdai->item[i].shape;
- //printf("shape[%d]=%d\n",i,shape[i]);
- //rb_ary_push( shape, SIZET2NUM(mdai->item[i].shape) );
}
// DataType
switch(mdai->type) {
case NA_BIT:
@@ -299,25 +340,46 @@
nc->dtype = tp;
}
}
+static size_t
+na_mdai_memsize(const void *ptr)
+{
+ const na_mdai_t *mdai = (const na_mdai_t*)ptr;
+
+ return sizeof(na_mdai_t) + mdai->capa * sizeof(na_mdai_item_t);
+}
+
+static const rb_data_type_t mdai_data_type = {
+ "Numo::NArray/mdai",
+ {NULL, na_mdai_free, na_mdai_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
+};
+
VALUE
na_ary_composition(VALUE ary)
{
volatile VALUE vmdai, vnc;
na_mdai_t *mdai;
na_compose_t *nc;
int j;
nc = ALLOC(na_compose_t);
- vnc = Data_Wrap_Struct(rb_cData, 0, -1, nc);
+ vnc = WrapCompose(nc);
if (TYPE(ary) == T_ARRAY) {
mdai = na_mdai_alloc(ary);
- vmdai = Data_Wrap_Struct(rb_cData, 0, na_mdai_free, mdai);
- na_mdai_investigate(mdai, 1);
- na_mdai_result(mdai, nc);
+ vmdai = TypedData_Wrap_Struct(rb_cData, &mdai_data_type, (void*)mdai);
+ if ( na_mdai_investigate(mdai, 1) ) {
+ // empty
+ nc->ndim = 1;
+ nc->shape = ALLOC_N(size_t, 1);
+ nc->shape[0] = 0;
+ nc->dtype = Qnil;
+ } else {
+ na_mdai_result(mdai, nc);
+ }
rb_gc_force_recycle(vmdai);
} else if (IsNArray(ary)) {
narray_t *na;
GetNArray(ary,na);
nc->ndim = na->ndim;
@@ -331,43 +393,109 @@
}
return vnc;
}
+static void
+na_ary_composition2(VALUE ary, VALUE *type, VALUE *shape)
+{
+ VALUE vnc, dshape;
+ na_compose_t *nc;
+ int i;
+
+ // investigate MD-Array
+ vnc = na_ary_composition(ary);
+ GetCompose(vnc,nc);
+ dshape = rb_ary_new2(nc->ndim);
+ for (i=0; i<nc->ndim; i++) {
+ rb_ary_push(dshape, SIZET2NUM(nc->shape[i]));
+ }
+ if (shape) {*shape = dshape;}
+ if (type) {*type = nc->dtype;}
+ RB_GC_GUARD(vnc);
+}
+
static VALUE
na_s_array_shape(VALUE mod, VALUE ary)
{
- volatile VALUE vnc;
VALUE shape;
- na_compose_t *nc;
- int i;
if (TYPE(ary)!=T_ARRAY) {
// 0-dimension
return rb_ary_new();
}
- // investigate MD-Array
- vnc = na_ary_composition(ary);
- Data_Get_Struct(vnc, na_compose_t, nc);
- shape = rb_ary_new2(nc->ndim);
- for (i=0; i<nc->ndim; i++) {
- rb_ary_push( shape, SIZET2NUM(nc->shape[i]) );
- }
+ na_ary_composition2(ary, 0, &shape);
return shape;
}
+static inline void
+check_subclass_of_narray(VALUE dtype) {
+ if (RTEST(rb_obj_is_kind_of(dtype, rb_cClass))) {
+ if (RTEST(rb_funcall(dtype, id_le, 1, cNArray))) {
+ return;
+ }
+ }
+ rb_raise(nary_eCastError, "cannot convert to NArray");
+}
+
+/*
+ Generate new unallocated NArray instance with shape and type defined from obj.
+ Numo::NArray.new_like(obj) returns instance whose type is defined from obj.
+ Numo::DFloat.new_like(obj) returns DFloat instance.
+
+ @overload new_like(obj)
+ @param [Numeric,Array,Numo::NArray] obj
+ @return [Numo::NArray]
+ @example
+ Numo::NArray.new_like([[1,2,3],[4,5,6]])
+ => Numo::Int32#shape=[2,3](empty)
+ Numo::DFloat.new_like([[1,2],[3,4]])
+ => Numo::DFloat#shape=[2,2](empty)
+ Numo::NArray.new_like([1,2i,3])
+ => Numo::DComplex#shape=[3](empty)
+*/
VALUE
+na_s_new_like(VALUE type, VALUE obj)
+{
+ VALUE vnc, newary;
+ na_compose_t *nc;
+
+ if (RTEST(rb_obj_is_kind_of(obj,rb_cNumeric))) {
+ // investigate type
+ if (type == cNArray) {
+ vnc = na_ary_composition(rb_ary_new3(1,obj));
+ GetCompose(vnc,nc);
+ type = nc->dtype;
+ }
+ check_subclass_of_narray(type);
+ newary = nary_new(type, 0, 0);
+ } else {
+ // investigate MD-Array
+ vnc = na_ary_composition(obj);
+ GetCompose(vnc,nc);
+ if (type == cNArray) {
+ type = nc->dtype;
+ }
+ check_subclass_of_narray(type);
+ newary = nary_new(type, nc->ndim, nc->shape);
+ }
+ RB_GC_GUARD(vnc);
+ return newary;
+}
+
+
+VALUE
na_ary_composition_dtype(VALUE ary)
{
volatile VALUE vnc;
na_compose_t *nc;
switch(TYPE(ary)) {
case T_ARRAY:
vnc = na_ary_composition(ary);
- Data_Get_Struct(vnc, na_compose_t, nc);
+ GetCompose(vnc,nc);
return nc->dtype;
}
return CLASS_OF(ary);
}
@@ -377,10 +505,11 @@
return na_ary_composition_dtype(ary);
}
+
/*
Generate NArray object. NArray datatype is automatically selected.
@overload [](elements)
@param [Numeric,Array] elements
@return [NArray]
@@ -391,20 +520,13 @@
VALUE dtype=Qnil;
if (TYPE(ary)!=T_ARRAY) {
rb_bug("Argument is not array");
}
-
dtype = na_ary_composition_dtype(ary);
-
- if (RTEST(rb_obj_is_kind_of(dtype,rb_cClass))) {
- if (RTEST(rb_funcall(dtype,rb_intern("<="),1,cNArray))) {
- return rb_funcall(dtype,rb_intern("cast"),1,ary);
- }
- }
- rb_raise(nary_eCastError, "cannot convert to NArray");
- return Qnil;
+ check_subclass_of_narray(dtype);
+ return rb_funcall(dtype, id_cast, 1, ary);
}
VALUE
nst_check_compatibility(VALUE self, VALUE ary);
@@ -495,14 +617,14 @@
na_mdai_t *mdai;
na_compose_t *nc;
mdai = na_mdai_alloc(ary);
mdai->na_type = nstruct;
- vmdai = Data_Wrap_Struct(rb_cData, 0, na_mdai_free, mdai);
+ vmdai = TypedData_Wrap_Struct(rb_cData, &mdai_data_type, (void*)mdai);
na_mdai_for_struct(mdai, 0);
nc = ALLOC(na_compose_t);
- vnc = Data_Wrap_Struct(rb_cData, 0, -1, nc);
+ vnc = WrapCompose(nc);
na_mdai_result(mdai, nc);
//fprintf(stderr,"nc->ndim=%d\n",nc->ndim);
rb_gc_force_recycle(vmdai);
return vnc;
}
@@ -513,8 +635,17 @@
Init_nary_array()
{
//rb_define_singleton_method(cNArray, "mdai", na_mdai, 1);
rb_define_singleton_method(cNArray, "array_shape", na_s_array_shape, 1);
rb_define_singleton_method(cNArray, "array_type", na_s_array_type, 1);
+ rb_define_singleton_method(cNArray, "new_like", na_s_new_like, 1);
rb_define_singleton_method(cNArray, "[]", nary_s_bracket, -2);
+
+ id_begin = rb_intern("begin");
+ id_end = rb_intern("end");
+ id_step = rb_intern("step");
+ id_cast = rb_intern("cast");
+ id_abs = rb_intern("abs");
+ id_le = rb_intern("<=");
+ id_Complex = rb_intern("Complex");
}