require "mknafunc" fname = "na_op.c" $> = open(fname,"w") upcast_ary = $upcast.collect{|i| ' {'+i.join(", ")+'}'}.join(",\n") print < #include "narray.h" #include "narray_local.h" /* isalpha(3) etc. */ #include const int na_upcast[NA_NTYPES][NA_NTYPES] = { #{upcast_ary} }; const int na_no_cast[NA_NTYPES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; const int na_cast_real[NA_NTYPES] = { 0, 1, 2, 3, 4, 5, 4, 5, 8 }; const int na_cast_comp[NA_NTYPES] = { 0, 6, 6, 6, 6, 7, 6, 7, 8 }; const int na_cast_round[NA_NTYPES] = { 0, 1, 2, 3, 3, 3, 6, 7, 8 }; const int na_cast_byte[NA_NTYPES] = { 0, 1, 1, 1, 1, 1, 1, 1, 1 }; static void TpErr(void) { rb_raise(rb_eTypeError,"illegal operation with this type"); } static int TpErrI(void) { rb_raise(rb_eTypeError,"illegal operation with this type"); return 0; } static void na_zerodiv() { rb_raise(rb_eZeroDivError, "divided by 0"); } static int notnanF(float *n) { return *n == *n; } static int notnanD(double *n) { return *n == *n; } EOM # # Set Fucs # data = [ [/[O]/,/[O]/, "*p1 = *p2;"], [/[O]/,/[BI]/, "*p1 = INT2FIX(*p2);"], [/[O]/,/[L]/, "*p1 = INT2NUM(*p2);"], [/[O]/,/[FD]/, "*p1 = rb_float_new(*p2);"], [/[O]/,/[XC]/, "*p1 = rb_complex_new(p2->r,p2->i);"], [/[BIL]/,/[O]/, "*p1 = NUM2INT(*p2);"], [/[FD]/,/[O]/, "*p1 = NUM2DBL(*p2);"], [/[XC]/,/[O]/, "p1->r = NUM2REAL(*p2); p1->i = NUM2IMAG(*p2);"], [/[BILFD]/,/[BILFD]/,"*p1 = *p2;"], [/[BILFD]/,/[XC]/, "*p1 = p2->r;"], [/[XC]/,/[BILFD]/, "p1->r = *p2; p1->i = 0;"], [/[XC]/,/[XC]/, "p1->r = p2->r; p1->i = p2->i;"] ] $func_body = "static void #name#CC(int n, char *p1, int i1, char *p2, int i2) { for (; n; n--) { OPERATION p1+=i1; p2+=i2; } } " mksetfuncs('Set','','',data) # # Unary Funcs # $func_body = "static void #name#C(int n, char *p1, int i1, char *p2, int i2) { for (; n; n--) { OPERATION p1+=i1; p2+=i2; } } " mkfuncs('Swp', $swap_types, $swap_types, [nil] + ["*p1 = *p2;"] + ["na_size16_t x; swap16(x,*p2); *p1 = x;"] + ["na_size32_t x; swap32(x,*p2); *p1 = x;"] + ["na_size32_t x; swap32(x,*p2); *p1 = x;"] + ["na_size64_t x; swap64(x,*p2); *p1 = x;"] + ["na_size64_t x; swap64c(x,*p2); *p1 = x;"] + ["na_size128_t x; swap128c(x,*p2); *p1 = x;"] + ["*p1 = *p2;"] ) print <r = -p2->r; p1->i = -p2->i;"]*2 + ["*p1 = rb_funcall(*p2,na_id_minus,0);"] ) mkfuncs('AddU', $data_types, $data_types, [nil] + ["*p1 += *p2;"]*5 + ["p1->r += p2->r; p1->i += p2->i;"]*2 + ["*p1 = rb_funcall(*p1,'+',1,*p2);"] ) mkfuncs('SbtU', $data_types, $data_types, [nil] + ["*p1 -= *p2;"]*5 + ["p1->r -= p2->r; p1->i -= p2->i;"]*2 + ["*p1 = rb_funcall(*p1,'-',1,*p2);"] ) mkfuncs('MulU', $data_types, $data_types, [nil] + ["*p1 *= *p2;"]*5 + ["type1 x = *p1; p1->r = x.r*p2->r - x.i*p2->i; p1->i = x.r*p2->i + x.i*p2->r;"]*2 + ["*p1 = rb_funcall(*p1,'*',1,*p2);"] ) mkfuncs('DivU', $data_types, $data_types, [nil] + ["if (*p2==0) {na_zerodiv();} *p1 /= *p2;"]*3 + ["*p1 /= *p2;"]*2 + ["type1 x = *p1; typef a = p2->r*p2->r + p2->i*p2->i; p1->r = (x.r*p2->r + x.i*p2->i)/a; p1->i = (x.i*p2->r - x.r*p2->i)/a;"]*2 + ["*p1 = rb_funcall(*p1,'/',1,*p2);"] ) # method: imag= mkfuncs('ImgSet',$data_types,$real_types, [nil]*6 + ["p1->i = *p2;"]*2 + [nil] ) mkfuncs('Floor',$int_types,$data_types,[nil] + ['copy']*3 + ["*p1 = floor(*p2);"]*2 + [nil]*3 ) mkfuncs('Ceil',$int_types,$data_types,[nil] + ['copy']*3 + ["*p1 = ceil(*p2);"]*2 + [nil]*3 ) mkfuncs('Round',$int_types,$data_types,[nil] + ['copy']*3 + # ["*p1 = floor(*p2+0.5);"]*2 + ["if (*p2 >= 0) *p1 = floor(*p2+0.5); else *p1 = ceil(*p2-0.5);"]*2 + [nil]*3 ) mkfuncs('Abs',$real_types,$data_types,[nil] + ["*p1 = *p2;"] + ["*p1 = (*p2<0) ? -*p2 : *p2;"]*4 + ["*p1 = hypot(p2->r, p2->i);"]*2 + ["*p1 = rb_funcall(*p2,na_id_abs,0);"] ) mkfuncs('Real',$real_types,$data_types,[nil] + ['copy']*7 + [nil] ) mkfuncs('Imag',$real_types,$data_types,[nil] + ["*p1 = 0;"]*5 + ["*p1 = p2->i;"]*2 + [nil] ) mkfuncs('Angl',$real_types,$data_types,[nil] + [nil]*5 + ["*p1 = atan2(p2->i,p2->r);"]*2 + [nil] ) mkfuncs('ImagMul',$comp_types,$data_types,[nil] + [nil]*3 + ["p1->r = 0; p1->i = *p2;"]*2 + ["p1->r = -p2->i; p1->i = p2->r;"]*2 + [nil] ) mkfuncs('Conj',$data_types,$data_types,[nil] + ['copy']*5 + ["p1->r = p2->r; p1->i = -p2->i;"]*2 + [nil] ) mkfuncs('Not', [$data_types[1]]*9, $data_types, [nil] + ["*p1 = (*p2==0) ? 1:0;"]*5 + ["*p1 = (p2->r==0 && p2->i==0) ? 1:0;"]*2 + ["*p1 = RTEST(*p2) ? 0:1;"] ) mkfuncs('BRv', $data_types, $data_types, [nil] + ["*p1 = ~(*p2);"]*3 + [nil]*4 + ["*p1 = rb_funcall(*p2,'~',0);"] ) mkfuncs('Min', $data_types, $data_types, [nil] + ["if (*p1>*p2) *p1=*p2;"]*3 + ["if (notnan#C((type1*)p2) && *p1>*p2) *p1=*p2;"]*2 + [nil]*2 + ["if (FIX2INT(rb_funcall(*p1,na_id_compare,1,*p2))>0) *p1=*p2;"] ) mkfuncs('Max', $data_types, $data_types, [nil] + ["if (*p1<*p2) *p1=*p2;"]*3 + ["if (notnan#C((type1*)p2) && *p1<*p2) *p1=*p2;"]*2 + [nil]*2 + ["if (FIX2INT(rb_funcall(*p1,na_id_compare,1,*p2))<0) *p1=*p2;"] ) mksortfuncs('Sort', $data_types, $data_types, [nil] + [" { if (*p1 > *p2) return 1; if (*p1 < *p2) return -1; return 0; }"]*5 + [nil]*2 + [" { VALUE r = rb_funcall(*p1, na_id_compare, 1, *p2); return NUM2INT(r); }"] ) mksortfuncs('SortIdx', $data_types, $data_types, [nil] + [" { if (**p1 > **p2) return 1; if (**p1 < **p2) return -1; return 0; }"]*5 + [nil]*2 + [" { VALUE r = rb_funcall(**p1, na_id_compare, 1, **p2); return NUM2INT(r); }"] ) # indgen $func_body = "static void #name#C(int n, char *p1, int i1, int p2, int i2) { for (; n; n--) { OPERATION p1+=i1; p2+=i2; } } " mkfuncs('IndGen',$data_types,[$data_types[3]]*8, [nil] + ["*p1 = p2;"]*5 + ["p1->r = p2; p1->i = 0;"]*2 + ["*p1 = INT2FIX(p2);"] ) $func_body = "static void #name#C(int n, char *p1, int i1, char *p2, int i2) { OPERATION } " mkfuncs('ToStr',['']+[$data_types[8]]*8,$data_types, [nil] + ["char buf[22]; for (; n; n--) { sprintf(buf,\"%i\",(int)*p2); *p1 = rb_str_new2(buf); p1+=i1; p2+=i2; }"]*3 + ["char buf[24]; for (; n; n--) { sprintf(buf,\"%.5g\",(double)*p2); *p1 = rb_str_new2(buf); p1+=i1; p2+=i2; }"] + ["char buf[24]; for (; n; n--) { sprintf(buf,\"%.8g\",(double)*p2); *p1 = rb_str_new2(buf); p1+=i1; p2+=i2; }"] + ["char buf[50]; for (; n; n--) { sprintf(buf,\"%.5g%+.5gi\",(double)p2->r,(double)p2->i); *p1 = rb_str_new2(buf); p1+=i1; p2+=i2; }"] + ["char buf[50]; for (; n; n--) { sprintf(buf,\"%.8g%+.8gi\",(double)p2->r,(double)p2->i); *p1 = rb_str_new2(buf); p1+=i1; p2+=i2; }"] + ["for (; n; n--) { *p1 = rb_obj_as_string(*p2); p1+=i1; p2+=i2; }"] ) print <r); na_str_append_fp(buf); b = buf+strlen(buf); sprintf(b,\"%+.4gi\",(double)p2->i); na_str_append_fp(b); strcat(buf,\"i\"); *p1 = rb_str_new2(buf);"] + ["char buf[50], *b; sprintf(buf,\"%.6g\",(double)p2->r); na_str_append_fp(buf); b = buf+strlen(buf); sprintf(b,\"%+.6g\",(double)p2->i); na_str_append_fp(b); strcat(buf,\"i\"); *p1 = rb_str_new2(buf);"] + ["*p1 = rb_inspect(*p2);"] ) # # Binary Funcs # =begin # Optimize experiment $func_body = "static void #name#C(int n, char *p1, int i1, char *p2, int i2, char *p3, int i3) { int i; if (i1==sizeof(type1) && i2==sizeof(type1) && i3==sizeof(type1)) { type1 *a1=p1, *a2=p2, *a3=p3; for (i=0; n; n--,i++) { *a1 = *a2 * *a3; a1++;a2++;a3++; } } else for (; n; n--) { OPERATION p1+=i1; p2+=i2; p3+=i3; } } " mkfuncs('MulB', $data_types, $data_types, [nil] + ["*p1 = *p2 * *p3;"]*5 + [nil]*3 ) =end $func_body = "static void #name#C(int n, char *p1, int i1, char *p2, int i2, char *p3, int i3) { for (; n; n--) { OPERATION p1+=i1; p2+=i2; p3+=i3; } } " mkfuncs('AddB', $data_types, $data_types, [nil] + ["*p1 = *p2 + *p3;"]*5 + ["p1->r = p2->r + p3->r; p1->i = p2->i + p3->i;"]*2 + ["*p1 = rb_funcall(*p2,'+',1,*p3);"] ) mkfuncs('SbtB', $data_types, $data_types, [nil] + ["*p1 = *p2 - *p3;"]*5 + ["p1->r = p2->r - p3->r; p1->i = p2->i - p3->i;"]*2 + ["*p1 = rb_funcall(*p2,'-',1,*p3);"] ) mkfuncs('MulB', $data_types, $data_types, [nil] + ["*p1 = *p2 * *p3;"]*5 + ["type1 x = *p2; p1->r = x.r*p3->r - x.i*p3->i; p1->i = x.r*p3->i + x.i*p3->r;"]*2 + ["*p1 = rb_funcall(*p2,'*',1,*p3);"] ) mkfuncs('DivB', $data_types, $data_types, [nil] + ["if (*p3==0) {na_zerodiv();}; *p1 = *p2 / *p3;"]*3 + ["*p1 = *p2 / *p3;"]*2 + ["type1 x = *p2; typef a = p3->r*p3->r + p3->i*p3->i; p1->r = (x.r*p3->r + x.i*p3->i)/a; p1->i = (x.i*p3->r - x.r*p3->i)/a;"]*2 + ["*p1 = rb_funcall(*p2,'/',1,*p3);"] ) mkfuncs('ModB', $data_types, $data_types, [nil] + ["*p1 = *p2 % *p3;"]*3 + ["*p1 = fmod(*p2, *p3);"]*2 + [nil]*2 + ["*p1 = rb_funcall(*p2,'%',1,*p3);"] ) mkfuncs('MulAdd', $data_types, $data_types, [nil] + ["*p1 += *p2 * *p3;"]*5 + ["type1 x = *p2; p1->r += x.r*p3->r - x.i*p3->i; p1->i += x.r*p3->i + x.i*p3->r;"]*2 + ["*p1 = rb_funcall(*p1,'+',1, rb_funcall(*p2,'*',1,*p3));"] ) mkfuncs('MulSbt', $data_types, $data_types, [nil] + ["*p1 -= *p2 * *p3;"]*5 + ["type1 x = *p2; p1->r -= x.r*p3->r - x.i*p3->i; p1->i -= x.r*p3->i + x.i*p3->r;"]*2 + ["*p1 = rb_funcall(*p1,'-',1, rb_funcall(*p2,'*',1,*p3));"] ) # # Bit operator # mkfuncs('BAn', $data_types, $data_types, [nil] + ["*p1 = *p2 & *p3;"]*3 + [nil]*4 + ["*p1 = rb_funcall(*p2,'&',1,*p3);"] ) mkfuncs('BOr', $data_types, $data_types, [nil] + ["*p1 = *p2 | *p3;"]*3 + [nil]*4 + ["*p1 = rb_funcall(*p2,'|',1,*p3);"] ) mkfuncs('BXo', $data_types, $data_types, [nil] + ["*p1 = *p2 ^ *p3;"]*3 + [nil]*4 + ["*p1 = rb_funcall(*p2,'^',1,*p3);"] ) # # Comparison # mkfuncs('Eql', [$data_types[1]]*9, $data_types, [nil] + ["*p1 = (*p2==*p3) ? 1:0;"]*5 + ["*p1 = (p2->r==p3->r) && (p2->i==p3->i) ? 1:0;"]*2 + ["*p1 = RTEST(rb_equal(*p2, *p3)) ? 1:0;"] ) mkfuncs('Cmp', [$data_types[1]]*9, $data_types, [nil] + ["if (*p2>*p3) *p1=1; else if (*p2<*p3) *p1=2; else *p1=0;"]*5 + [nil]*2 + ["int v = NUM2INT(rb_funcall(*p2,na_id_compare,1,*p3)); if (v>0) *p1=1; else if (v<0) *p1=2; else *p1=0;"] ) mkfuncs('And', [$data_types[1]]*9, $data_types, [nil] + ["*p1 = (*p2!=0 && *p3!=0) ? 1:0;"]*5 + ["*p1 = ((p2->r!=0||p2->i!=0) && (p3->r!=0||p3->i!=0)) ? 1:0;"]*2 + ["*p1 = (RTEST(*p2) && RTEST(*p3)) ? 1:0;"] ) mkfuncs('Or_', [$data_types[1]]*9, $data_types, [nil] + ["*p1 = (*p2!=0 || *p3!=0) ? 1:0;"]*5 + ["*p1 = ((p2->r!=0||p2->i!=0) || (p3->r!=0||p3->i!=0)) ? 1:0;"]*2 + ["*p1 = (RTEST(*p2) || RTEST(*p3)) ? 1:0;"] ) mkfuncs('Xor', [$data_types[1]]*9, $data_types, [nil] + ["*p1 = ((*p2!=0) == (*p3!=0)) ? 0:1;"]*5 + ["*p1 = ((p2->r!=0||p2->i!=0) == (p3->r!=0||p3->i!=0)) ? 0:1;"]*2 + ["*p1 = (RTEST(*p2) == RTEST(*p3)) ? 0:1;"] ) # # Atan2 # mkfuncs('atan2', $data_types, $data_types, [nil]*4 + ["*p1 = atan2(*p2, *p3);"]*2 + [nil]*3 ) # # Mask # $func_body = "static void #name#C(int n, char *p1, int i1, char *p2, int i2, char *p3, int i3) { for (; n; n--) { OPERATION } } " mkfuncs('RefMask',$data_types,$data_types, [nil] + ["if (*(u_int8_t*)p3) { *p1=*p2; p1+=i1; } p3+=i3; p2+=i2;"]*8 ) mkfuncs('SetMask',$data_types,$data_types, [nil] + ["if (*(u_int8_t*)p3) { *p1=*p2; p2+=i2; } p3+=i3; p1+=i1;"]*8 )