narray-nmatrix 0.6.1.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1011 @@
1
+ /*
2
+ na_index.c
3
+ Numerical Array Extention for Ruby
4
+ (C) Copyright 1999-2008 by Masahiro TANAKA
5
+
6
+ This program is free software.
7
+ You can distribute/modify this program
8
+ under the same terms as Ruby itself.
9
+ NO WARRANTY.
10
+ */
11
+ #include <ruby.h>
12
+ #include "narray.h"
13
+ #include "narray_local.h"
14
+
15
+ #define EXCL(r) (RTEST(rb_funcall((r),na_id_exclude_end,0)))
16
+
17
+ static int
18
+ na_index_range(VALUE obj, int size, struct slice *sl)
19
+ {
20
+ int beg,end,len,step;
21
+ VALUE vbeg, vend;
22
+
23
+ sl->idx = NULL;
24
+
25
+ /* Beginning */
26
+ vbeg = rb_funcall(obj, na_id_beg, 0);
27
+ if (vbeg==Qnil) /* First is nil */
28
+ beg = 0;
29
+ else
30
+ beg = NUM2INT(vbeg);
31
+ if (beg<0) beg += size;
32
+
33
+ /* End */
34
+ vend = rb_funcall(obj, na_id_end, 0);
35
+ if (vend==Qnil) { /* Last is nil */
36
+ sl->beg = beg;
37
+ sl->step = 1;
38
+ return sl->n = 0;
39
+ }
40
+ else
41
+ end = NUM2INT(vend);
42
+ if (end<0) end += size;
43
+
44
+ /* length */
45
+ len = end-beg;
46
+
47
+ /* direction */
48
+ if (len>0) {
49
+ step = 1;
50
+ if (EXCL(obj)) --end; else ++len;
51
+ }
52
+ else if (len<0) {
53
+ len = -len;
54
+ step = -1;
55
+ if (EXCL(obj)) ++end; else ++len;
56
+ }
57
+ else /*if(len==0)*/ {
58
+ if (EXCL(obj))
59
+ rb_raise(rb_eIndexError, "empty range");
60
+ else {
61
+ ++len;
62
+ step = 1; /* or 0 ? depend on whether removing rank */
63
+ }
64
+ }
65
+
66
+ if ( beg<0 || beg>=size || end<0 || end>=size )
67
+ rb_raise(rb_eIndexError, "index out of range");
68
+
69
+ sl->n = len;
70
+ sl->beg = beg;
71
+ sl->step = step;
72
+ return len;
73
+ }
74
+
75
+
76
+ static int
77
+ na_index_scalar(int idx, int size, struct slice *sl)
78
+ {
79
+ if (idx<0) idx+=size;
80
+ if (idx<0 || idx>=size)
81
+ rb_raise(rb_eIndexError, "index out of range");
82
+ sl->n = 1;
83
+ sl->beg = idx;
84
+ sl->step = 0;
85
+ sl->idx = NULL;
86
+ return 1;
87
+ }
88
+
89
+
90
+ static int
91
+ na_ary_to_index(struct NARRAY *a1, int size, struct slice *s)
92
+ {
93
+ int i;
94
+ na_index_t idx, *p;
95
+
96
+ /* Empty Array */
97
+ if (a1->total==0) {
98
+ s->n = 0;
99
+ s->beg = 0;
100
+ s->step = 1;
101
+ s->idx = NULL;
102
+ }
103
+ else
104
+ /* single element */
105
+ if (a1->total==1) {
106
+ SetFuncs[NA_LINT][a1->type](1, &idx, 0, a1->ptr, 0);
107
+ if ( idx<0 ) idx += size;
108
+ if ( idx<0 || idx>=size )
109
+ rb_raise(rb_eIndexError, "index %i out of range %i", idx, size);
110
+ s->n = 1;
111
+ s->beg = idx;
112
+ s->step = 1;
113
+ s->idx = NULL;
114
+ }
115
+ else {
116
+ /* Copy index array */
117
+ s->n = a1->total;
118
+ s->step = 1;
119
+ s->idx = p = ALLOC_N(na_index_t, a1->total);
120
+ SetFuncs[NA_LINT][a1->type]( s->n,
121
+ s->idx, na_sizeof[NA_LINT],
122
+ a1->ptr, na_sizeof[a1->type] );
123
+ for ( i=a1->total; i>0; --i ) {
124
+ if ( *p<0 ) *p += size;
125
+ if ( *p<0 || *p>=size )
126
+ rb_raise(rb_eIndexError, "index %i out of range %i", *p, size);
127
+ ++p;
128
+ }
129
+ s->beg = s->idx[0];
130
+ }
131
+
132
+ return s->n;
133
+ }
134
+
135
+
136
+ static struct NARRAY *
137
+ na_flatten_temporarily(struct NARRAY *dst, struct NARRAY *src)
138
+ {
139
+ /* Not normal construction !! Do not wrap as object ! */
140
+ dst->shape = &(dst->total);
141
+ dst->rank = 1;
142
+ dst->total = src->total;
143
+ dst->type = src->type;
144
+ dst->ptr = src->ptr;
145
+ dst->ref = src->ref;
146
+ return dst;
147
+ }
148
+ #define na_flatten_temp(ary) \
149
+ {ary = na_flatten_temporarily(ALLOCA_N(struct NARRAY,1), ary);}
150
+
151
+
152
+ /* free index memory */
153
+ static void na_free_slice_index(struct slice *s, int n)
154
+ {
155
+ while (n-->0)
156
+ if (s[n].idx != NULL) xfree(s[n].idx);
157
+ }
158
+
159
+
160
+ static int na_index_test(volatile VALUE idx, int shape, struct slice *sl)
161
+ {
162
+ int size;
163
+ struct NARRAY *na;
164
+
165
+ switch(TYPE(idx)) {
166
+
167
+ case T_FIXNUM:
168
+ /* scalar slice */
169
+ na_index_scalar(FIX2LONG(idx),shape,sl);
170
+ return 1;
171
+
172
+ case T_FLOAT:
173
+ /* scalar slice */
174
+ na_index_scalar(NUM2LONG(idx),shape,sl);
175
+ return 1;
176
+
177
+ case T_NIL:
178
+ case T_TRUE:
179
+ /* entire slice */
180
+ sl->n = shape;
181
+ sl->beg = 0;
182
+ sl->step = 1;
183
+ sl->idx = NULL;
184
+ return shape;
185
+
186
+ case T_ARRAY:
187
+ /* Array Index */
188
+ idx = na_cast_object(idx,NA_LINT);
189
+ GetNArray(idx,na);
190
+ size = na_ary_to_index(na,shape,sl);
191
+ return size;
192
+
193
+ default:
194
+ /* Range object */
195
+ if (rb_obj_is_kind_of(idx, rb_cRange)) {
196
+ size = na_index_range(idx,shape,sl);
197
+ }
198
+ else
199
+ /* NArray index */
200
+ if (NA_IsNArray(idx)) {
201
+ GetNArray(idx,na);
202
+ size = na_ary_to_index(na,shape,sl);
203
+ }
204
+ else
205
+ /* NO ALLOWED */
206
+ if (TYPE(idx)==T_BIGNUM) {
207
+ rb_raise(rb_eIndexError, "BigNum is not allowed");
208
+ }
209
+ else
210
+ rb_raise(rb_eIndexError, "not allowed type");
211
+ }
212
+ return size;
213
+ }
214
+
215
+
216
+ static int
217
+ na_index_analysis(int nidx, VALUE *idx, struct NARRAY *ary, struct slice *sl)
218
+ {
219
+ int i, j, k, total=1, size;
220
+ int multi_ellip=0;
221
+
222
+ for (i=j=0; i<nidx; ++i) {
223
+ if (TYPE(idx[i])==T_FALSE) {
224
+ if (multi_ellip!=0)
225
+ rb_raise(rb_eIndexError, "multiple ellipsis-dimension is not allowd");
226
+ for (k=ary->rank-nidx+1; k>0; --k,++j) {
227
+ size = na_index_test( Qtrue, ary->shape[j], &sl[j] );
228
+ if (size != 1)
229
+ total *= size;
230
+ }
231
+ multi_ellip = 1;
232
+ } else {
233
+ if (j < ary->rank) {
234
+ size = na_index_test( idx[i], ary->shape[j], &sl[j] );
235
+ if (size != 1)
236
+ total *= size;
237
+ }
238
+ ++j;
239
+ }
240
+ }
241
+ if (j != ary->rank)
242
+ rb_raise(rb_eIndexError, "# of index=%i != ary.dim=%i", j, ary->rank);
243
+
244
+ return total;
245
+ }
246
+
247
+
248
+ /* -------------------- Class Dimension -------------------- */
249
+ int
250
+ na_shrink_class(int class_dim, int *shrink)
251
+ {
252
+ int i;
253
+
254
+ for (i=0; i<class_dim; ++i) {
255
+ if (shrink[i]==0) /* non-trim dimention */
256
+ return 0;
257
+ }
258
+ return 1; /* all trim */
259
+ }
260
+
261
+
262
+ /* remove single-element rank */
263
+ VALUE
264
+ na_shrink_rank(VALUE obj, int class_dim, int *shrink)
265
+ {
266
+ int i, j;
267
+ struct NARRAY *ary;
268
+
269
+ GetNArray(obj,ary);
270
+
271
+ if (ary->rank < class_dim)
272
+ return obj;
273
+
274
+ for (j=i=0; i<class_dim; ++i) {
275
+ if (ary->shape[i]!=1 || shrink[i]==0) /* not trim */
276
+ ++j;
277
+ }
278
+
279
+ if (j>0) /* if non-trim dimensions exist, */
280
+ j = class_dim; /* then do not trim class_dimension. */
281
+ /* if (j==0) then all trim. */
282
+
283
+ for (i=class_dim; i<ary->rank; ++i) {
284
+ if (ary->shape[i]!=1 || shrink[i]==0) { /* not trim */
285
+ if (i>j) ary->shape[j] = ary->shape[i];
286
+ ++j;
287
+ }
288
+ }
289
+ ary->rank = j;
290
+
291
+ if (j==0 && ary->total==1) {
292
+ SetFuncs[NA_ROBJ][ary->type](1, &obj, 0, ary->ptr, 0);
293
+ }
294
+ return obj;
295
+ }
296
+
297
+
298
+ /* ------------------- bracket methods ------------------ */
299
+ /*
300
+ [] -- Reference method
301
+ */
302
+
303
+ static VALUE
304
+ na_aref_slice(struct NARRAY *a2, struct slice *s2, VALUE klass, int flag)
305
+ {
306
+ int i, ndim, class_dim, *shape, *shrink;
307
+ VALUE extr;
308
+ struct NARRAY *a1;
309
+ struct slice *s1;
310
+
311
+ ndim = a2->rank;
312
+ shape = ALLOCA_N(int,ndim);
313
+ shrink = ALLOCA_N(int,ndim);
314
+
315
+ for (i=0; i<ndim; ++i) {
316
+ shape[i] = s2[i].n;
317
+ if (shape[i]==1 && s2[i].step==0) /* shrink? */
318
+ shrink[i] = 1;
319
+ else
320
+ shrink[i] = 0;
321
+ }
322
+
323
+ class_dim = na_class_dim(klass);
324
+
325
+ if (ndim < class_dim)
326
+ rb_raise(rb_eRuntimeError,
327
+ "dimension(%i) is smaller than CLASS_DIMENSION(%i)",
328
+ ndim, class_dim);
329
+
330
+ if ((!flag) && class_dim>0 && na_shrink_class(class_dim,shrink))
331
+ klass = cNArray;
332
+
333
+ extr = na_make_object( a2->type, ndim, shape, klass );
334
+ GetNArray(extr,a1);
335
+
336
+ s1 = ALLOC_N(struct slice, ndim+1);
337
+ na_set_slice_1obj(ndim,s1,a1->shape);
338
+
339
+ na_init_slice( s1, ndim, shape, na_sizeof[a2->type] );
340
+ na_init_slice( s2, ndim, a2->shape, na_sizeof[a2->type] );
341
+ na_loop_index_ref( a1, a2, s1, s2, SetFuncs[a2->type][a2->type] );
342
+
343
+ xfree(s1);
344
+ if (!flag)
345
+ extr = na_shrink_rank(extr,class_dim,shrink);
346
+
347
+ return extr;
348
+ }
349
+
350
+
351
+
352
+ static VALUE
353
+ na_aref_single_dim_array(VALUE self, volatile VALUE vidx)
354
+ {
355
+ int total;
356
+ struct NARRAY *a1, *a2, *aidx;
357
+ struct slice *s1, *s2;
358
+ VALUE v;
359
+
360
+ GetNArray( self, a1 );
361
+ vidx = na_cast_object( vidx, NA_LINT );
362
+ GetNArray(vidx,aidx);
363
+
364
+ /* make Slice from index */
365
+ s1 = ALLOCA_N(struct slice, 2);
366
+ total = na_ary_to_index( aidx, a1->total, s1 );
367
+
368
+ if (total==0) {
369
+ return na_make_empty(a1->type,cNArray);
370
+ }
371
+ else {
372
+ /* create New NArray & 1-dimentionize */
373
+ v = na_make_object( a1->type, aidx->rank, aidx->shape, CLASS_OF(vidx) );
374
+ GetNArray(v,a2);
375
+ if (a2->rank>1) na_flatten_temp(a2);
376
+ if (a1->rank>1) na_flatten_temp(a1);
377
+
378
+ /* Slice for Destination array */
379
+ s2 = ALLOCA_N(struct slice, 2);
380
+ na_set_slice_1obj(1,s2,a2->shape);
381
+
382
+ /* Iteration */
383
+ na_init_slice( s2, 1, a2->shape, na_sizeof[a1->type] );
384
+ na_init_slice( s1, 1, a1->shape, na_sizeof[a1->type] );
385
+ na_loop_index_ref( a2, a1, s2, s1, SetFuncs[a1->type][a1->type] );
386
+ }
387
+
388
+ na_free_slice_index(s1,1);
389
+ return v;
390
+ }
391
+
392
+
393
+ static VALUE
394
+ na_aref_single_dim(VALUE self, VALUE idx, int flag)
395
+ {
396
+ int size;
397
+ VALUE v;
398
+ struct NARRAY *ary, *arynew;
399
+ struct slice *sl;
400
+
401
+ GetNArray(self,ary);
402
+
403
+ sl = ALLOCA_N(struct slice, 2);
404
+ size = na_index_test(idx, ary->total, sl);
405
+
406
+ if ( size == 1 ) {
407
+ if (flag || sl->step!=0) {
408
+ /* single-element NArray */
409
+ v = na_make_object(ary->type,1,&size,cNArray);
410
+ GetNArray(v,arynew);
411
+ SetFuncs[ary->type][ary->type](1, arynew->ptr,0, NA_PTR(ary,sl->beg),0);
412
+ } else {
413
+ SetFuncs[NA_ROBJ][ary->type](1, &v,0, NA_PTR(ary,sl->beg),0);
414
+ }
415
+ }
416
+ else
417
+ if ( size > 1 ) {
418
+ if ( ary->rank > 1 ) /* 1-dimensional serial index */
419
+ na_flatten_temp(ary);
420
+ v = na_aref_slice(ary, sl, CLASS_OF(self), flag);
421
+ }
422
+ else /* size < 1 */ {
423
+ v = na_make_empty(ary->type,cNArray);
424
+ }
425
+ /* na_free_slice_index(sl,1); free index memory */
426
+ return v;
427
+ }
428
+
429
+
430
+ static VALUE
431
+ na_aref_multi_dim_single_elm(VALUE self, struct slice *sl, int flag)
432
+ {
433
+ int i, rank, pos, *shape;
434
+ struct NARRAY *ary, *arynew;
435
+ VALUE v;
436
+
437
+ ary = (struct NARRAY *)DATA_PTR(self); /* type is already checked */
438
+
439
+ /* check rank-shrink; whether return NArray or Element */
440
+ if (flag==0) {
441
+ rank = 0; /* [] */
442
+ for ( i=ary->rank; (i--)>0; ) {
443
+ if (sl[i].step!=0) ++rank;
444
+ }
445
+ }
446
+ else {
447
+ rank = ary->rank; /* slice() */
448
+ }
449
+ /* get position */
450
+ pos = 0;
451
+ for ( i=ary->rank; i-->0; ) {
452
+ pos = pos * ary->shape[i] + sl[i].beg;
453
+ }
454
+ if (rank==0) {
455
+ SetFuncs[NA_ROBJ][ary->type](1, &v, 0, NA_PTR(ary,pos), 0);
456
+ } else {
457
+ VALUE klass;
458
+ int class_dim;
459
+ klass = CLASS_OF(self);
460
+ class_dim = na_class_dim(klass);
461
+ if (rank < class_dim) rank = class_dim;
462
+ shape = ALLOCA_N(int, rank);
463
+ for (i=0;i<rank;++i) shape[i]=1;
464
+ v = na_make_object(ary->type,rank,shape,klass);
465
+ GetNArray(v,arynew);
466
+ SetFuncs[ary->type][ary->type](1, arynew->ptr, 0, NA_PTR(ary,pos), 0);
467
+ }
468
+ return v;
469
+ }
470
+
471
+
472
+ static VALUE
473
+ na_aref_multi_dim(VALUE self, int nidx, VALUE *idx, int flag)
474
+ {
475
+ VALUE v;
476
+ int size;
477
+ struct NARRAY *ary;
478
+ struct slice *sl;
479
+
480
+ GetNArray(self,ary);
481
+
482
+ if (ary->rank==0)
483
+ rb_raise(rb_eIndexError, "Cannot extract from Empty NArray");
484
+
485
+ /* make Slice */
486
+ sl = ALLOC_N(struct slice, ary->rank+1);
487
+ size = na_index_analysis(nidx, idx, ary, sl);
488
+
489
+ if ( size == 1 ) { /* return Single Element */
490
+ v = na_aref_multi_dim_single_elm(self, sl, flag);
491
+ }
492
+ else
493
+ if ( size > 1 ) {
494
+ v = na_aref_slice(ary, sl, CLASS_OF(self), flag);
495
+ }
496
+ else /* size < 1 */ {
497
+ v = na_make_empty(ary->type,cNArray);
498
+ }
499
+ na_free_slice_index(sl,ary->rank); /* free index memory */
500
+ xfree(sl);
501
+ return v;
502
+ }
503
+
504
+
505
+ /* vvv mask vvv */
506
+ static int
507
+ na_count_true_body(VALUE self)
508
+ {
509
+ struct NARRAY *ary;
510
+ int n, count=0;
511
+ u_int8_t *ptr;
512
+
513
+ GetNArray(self,ary);
514
+
515
+ if ( ary->type == NA_BYTE ) {
516
+ ptr = (u_int8_t *)ary->ptr;
517
+ n = ary->total;
518
+ for (; n; --n) {
519
+ if (*ptr++) ++count;
520
+ }
521
+ } else
522
+ rb_raise(rb_eTypeError,"cannot count_true NArray except BYTE type");
523
+ return count;
524
+ }
525
+
526
+ /*
527
+ * call-seq:
528
+ * narray.count_true -> int
529
+ *
530
+ * Returns the number of true (non-zero) in narray
531
+ */
532
+ VALUE
533
+ na_count_true(VALUE self)
534
+ {
535
+ return( INT2NUM(na_count_true_body(self)) );
536
+ }
537
+
538
+ static int
539
+ na_count_false_body(VALUE self)
540
+ {
541
+ struct NARRAY *ary;
542
+ int n, count=0;
543
+ u_int8_t *ptr;
544
+
545
+ GetNArray(self,ary);
546
+
547
+ if ( ary->type == NA_BYTE ) {
548
+ ptr = (u_int8_t *)ary->ptr;
549
+ n = ary->total;
550
+ for (; n; --n) {
551
+ if (!*ptr++) ++count;
552
+ }
553
+ } else
554
+ rb_raise(rb_eTypeError,"cannot count_false NArray except BYTE type");
555
+ return count;
556
+ }
557
+
558
+ /*
559
+ * call-seq:
560
+ * narray.count_false -> int
561
+ *
562
+ * Returns the number of false (zero-value) in narray
563
+ */
564
+ VALUE
565
+ na_count_false(VALUE self)
566
+ {
567
+ return( INT2NUM(na_count_false_body(self)) );
568
+ }
569
+
570
+ /* :nodoc: */
571
+ VALUE
572
+ na_aref_mask(VALUE self, VALUE mask)
573
+ {
574
+ int total, i;
575
+ struct NARRAY *a1, *am, *a2;
576
+ VALUE v;
577
+
578
+ GetNArray( self, a1 );
579
+ GetNArray( mask, am );
580
+
581
+ if (a1->total != am->total)
582
+ rb_raise(rb_eTypeError,"self.size(=%i) != mask.size(=%i)",
583
+ a1->total, am->total);
584
+ if (a1->rank != am->rank)
585
+ rb_raise(rb_eTypeError,"self.rank(=%i) != mask.rank(=%i)",
586
+ a1->rank, am->rank);
587
+ for (i=0; i<a1->rank; ++i)
588
+ if (a1->shape[i] != am->shape[i])
589
+ rb_raise(rb_eTypeError,"self.shape[%i](=%i) != mask.shape[%i](=%i)",
590
+ i, a1->shape[i], i, am->shape[i]);
591
+
592
+ total = na_count_true_body(mask);
593
+
594
+ v = na_make_object( a1->type, 1, &total, CLASS_OF(self) );
595
+ GetNArray(v,a2);
596
+
597
+ RefMaskFuncs[a1->type]
598
+ ( a1->total, a2->ptr, na_sizeof[a2->type], a1->ptr,
599
+ na_sizeof[a1->type], am->ptr, 1 );
600
+
601
+ return(v);
602
+ }
603
+
604
+ /* ^^^ mask ^^^ */
605
+
606
+
607
+ /* method: [](idx1,idx2,...,idxN) */
608
+ static VALUE
609
+ na_aref_body(int nidx, VALUE *idx, VALUE self, int flag)
610
+ {
611
+ if (nidx==0) {
612
+ return na_clone(self);
613
+ }
614
+ if (nidx==1) {
615
+ if ( NA_IsNArray(idx[0]) ) {
616
+ if( NA_TYPE(idx[0]) == NA_BYTE ) /* then supposed to be a mask */
617
+ return na_aref_mask(self, idx[0]);
618
+ }
619
+ if ( na_class_dim(CLASS_OF(self)) != 1 ) {
620
+ if ( NA_IsArray(idx[0]) ) /* Array Index ? */
621
+ return na_aref_single_dim_array( self, idx[0] );
622
+ else
623
+ return na_aref_single_dim( self, idx[0], flag );
624
+ }
625
+ }
626
+ /* if (nidx>1) */
627
+ return na_aref_multi_dim( self, nidx, idx, flag );
628
+ }
629
+
630
+ /* method: [](idx1,idx2,...,idxN) */
631
+ VALUE na_aref(int argc, VALUE *argv, VALUE self)
632
+ { return na_aref_body(argc, argv, self, 0); }
633
+
634
+ /* method: slice(idx1,idx2,...,idxN) */
635
+ VALUE na_slice(int argc, VALUE *argv, VALUE self)
636
+ { return na_aref_body(argc, argv, self, 1); }
637
+
638
+
639
+
640
+ /*
641
+ []= -- Set elements to specified indices
642
+ */
643
+
644
+ /* make slice for array-set: a[0..-1,1..2] = 1 */
645
+ static void
646
+ na_make_slice_aset_fill(int rank, struct NARRAY *src_ary,
647
+ struct slice *src_slc, int *src_shape,
648
+ struct slice *dst_slc)
649
+ {
650
+ int i;
651
+
652
+ for (i=0; i<rank; ++i) {
653
+ src_shape[i] = 1; /* all 1 */
654
+ if ( (src_slc[i].n = dst_slc[i].n) < 1 )
655
+ rb_raise(rb_eIndexError, "dst_slice[%i].n=%i ???", i, dst_slc[i].n);
656
+ src_slc[i].beg = 0;
657
+ src_slc[i].idx = NULL;
658
+ src_slc[i].step = 0;
659
+ }
660
+ }
661
+
662
+
663
+ /* make slice for array-set */
664
+ static void
665
+ na_make_slice_aset(struct NARRAY *dst, struct NARRAY *src,
666
+ struct slice *s1, struct slice *s2, int *src_shape)
667
+ {
668
+ int i, j, idx_end;
669
+
670
+ /* count range index */
671
+ for (j=i=0; i<dst->rank; ++i) {
672
+
673
+ if ( s1[i].step !=0 ) { /* Range index */
674
+
675
+ /* rank check */
676
+ if ( j >= src->rank )
677
+ rb_raise(rb_eIndexError, "dst.range-dim=%i > src.dim=%i",
678
+ j+1, src->rank);
679
+
680
+ if ( s1[i].n == 0 ) {
681
+ /* Size is NOT specified:
682
+ a[0..nil] = other_array
683
+ a[0] = other_array
684
+ */
685
+ s1[i].n = src->shape[j];
686
+
687
+ idx_end = s1[i].beg + (s1[i].n-1) * s1[i].step;
688
+ if ( idx_end < 0 || idx_end >= dst->shape[i] )
689
+ rb_raise(rb_eIndexError, "end-index=%i is out of dst.shape[%i]=%i",
690
+ idx_end, i, dst->shape[i]);
691
+
692
+ } else
693
+ /* Size is specified:
694
+ a[0..10] = other
695
+ */
696
+ if ( src->shape[j] >1 && s1[i].n != src->shape[j] ) {
697
+ rb_raise(rb_eIndexError, "dst.shape[%i]=%i != src.shape[%i]=%i",
698
+ i, s1[i].n, j, src->shape[j]);
699
+ }
700
+ /* copy source shape */
701
+ src_shape[i] = src->shape[j++];
702
+
703
+ }
704
+ else /* if ( s1[i].n==1 )
705
+ Scalar index:
706
+ a[0, 0..-1] = other --- first rank is skipped.
707
+ */
708
+ src_shape[i] = 1; /* insert dummy rank */
709
+
710
+ s2[i].beg = 0;
711
+ s2[i].idx = NULL;
712
+ s2[i].n = s1[i].n; /* repeate number is same as a1 index */
713
+
714
+ if ( s1[i].n >1 && src_shape[i]==1 ) /* Extensible index */
715
+ s2[i].step = 0;
716
+ else
717
+ s2[i].step = 1;
718
+ }
719
+
720
+ /* rank check */
721
+ if ( j != src->rank )
722
+ rb_raise(rb_eIndexError, "dst.range-dim=%i < src.dim=%i", j, src->rank);
723
+ }
724
+
725
+
726
+
727
+ /* Iterate with bifinc, src has extensible index */
728
+ void
729
+ na_aset_slice(struct NARRAY *dst, struct NARRAY *src, struct slice *dst_slc)
730
+ {
731
+ int rank = dst->rank;
732
+ int *src_shape;
733
+ struct slice *src_slc;
734
+
735
+ /* rank check */
736
+ if (rank < src->rank)
737
+ rb_raise(rb_eIndexError, "%i dst.ranks < %i src.ranks", rank, src->rank);
738
+ if (src->rank == 0)
739
+ rb_raise(rb_eIndexError, "cannot store empty array");
740
+
741
+ /* extend rank */
742
+ src_shape = ALLOCA_N(int, rank);
743
+ src_slc = ALLOC_N(struct slice, rank+1);
744
+
745
+ if (src->total==1)
746
+ na_make_slice_aset_fill( rank, src, src_slc, src_shape, dst_slc );
747
+ else
748
+ na_make_slice_aset( dst, src, dst_slc, src_slc, src_shape );
749
+
750
+ /* Iteration */
751
+ na_init_slice( dst_slc, rank, dst->shape, na_sizeof[dst->type] );
752
+ na_init_slice( src_slc, rank, src_shape, na_sizeof[src->type] );
753
+ na_loop_general( dst,src, dst_slc,src_slc, SetFuncs[dst->type][src->type] );
754
+ xfree(src_slc);
755
+ }
756
+
757
+
758
+ static void
759
+ na_aset_array_index( VALUE self, volatile VALUE idx, volatile VALUE val )
760
+ {
761
+ int i, total;
762
+ struct NARRAY *aidx, *src, *dst;
763
+ struct slice *sl;
764
+
765
+ GetNArray(self,dst);
766
+ idx = na_cast_object(idx,NA_LINT);
767
+ GetNArray(idx,aidx);
768
+ val = na_cast_unless_narray(val,dst->type);
769
+ GetNArray(val,src);
770
+
771
+ /* empty index -- do nothing */
772
+ if (aidx->total==0 && (src->total==0 || src->total==1))
773
+ return;
774
+
775
+ /* check rank */
776
+ if (aidx->rank != src->rank)
777
+ rb_raise( rb_eIndexError, "idx.rank=%i != src.rank=%i",
778
+ aidx->rank, src->rank );
779
+ /* check shape */
780
+ for (i=0;i<src->rank;++i)
781
+ if (aidx->shape[i] != src->shape[i] && src->shape[i] != 1)
782
+ rb_raise( rb_eIndexError, "idx.shape[%i]=%i != src.shape[%i]=%i",
783
+ i, aidx->shape[i], i, src->shape[i] );
784
+
785
+ /* make Slice from index */
786
+ sl = ALLOCA_N(struct slice,2);
787
+ total = na_ary_to_index( NA_STRUCT(idx), dst->total, sl );
788
+
789
+ /* 1-dimensionize */
790
+ if (dst->rank > 1) {
791
+ na_flatten_temp(dst);
792
+ }
793
+ if (src->rank > 1) {
794
+ na_flatten_temp(src);
795
+ }
796
+
797
+ na_aset_slice( dst, src, sl );
798
+ na_free_slice_index( sl, 1 ); /* free index memory */
799
+ }
800
+
801
+
802
+ static void
803
+ na_aset_single_dim(VALUE self, VALUE idx, volatile VALUE val)
804
+ {
805
+ int size;
806
+ struct NARRAY *src, *dst;
807
+ struct slice *sl;
808
+
809
+ GetNArray(self,dst);
810
+ if (dst->total==0)
811
+ rb_raise(rb_eRuntimeError, "cannot set value to empty array");
812
+
813
+ sl = ALLOCA_N(struct slice, 2);
814
+ size = na_index_test(idx, dst->total, sl);
815
+
816
+ if ( size == 1 ) {
817
+ if (NA_IsNArray(val)) {
818
+ GetNArray(val,src);
819
+ if ( src->total == 1 ) {
820
+ SetFuncs[dst->type][src->type](1, NA_PTR(dst,sl->beg),0, src->ptr,0);
821
+ return;
822
+ }
823
+ }
824
+ else if (TYPE(val)!=T_ARRAY) {
825
+ /* Storing single element:
826
+ a[1] = 1
827
+ */
828
+ SetFuncs[dst->type][NA_ROBJ](1, NA_PTR(dst,sl->beg),0, &val,0);
829
+ return;
830
+ }
831
+ /* Beginning index:
832
+ a[1] = [1,2,3]
833
+ */
834
+ sl[0].n = 0;
835
+ sl[0].step = 1;
836
+ }
837
+ else if ( size == 0 ) return; /* Empty index */
838
+
839
+ if ( dst->rank > 1 ) { /* 1-dimensionize */
840
+ na_flatten_temp(dst);
841
+ }
842
+ val = na_cast_unless_narray(val,dst->type);
843
+ GetNArray(val,src);
844
+ na_aset_slice( dst, src, sl );
845
+
846
+ na_free_slice_index(sl,1); /* free index memory */
847
+ }
848
+
849
+
850
+ static void
851
+ na_aset_multi_dim(VALUE self, int nidx, VALUE *idx, volatile VALUE val)
852
+ {
853
+ int i, pos, size;
854
+ struct NARRAY *dst, *src;
855
+ struct slice *sl;
856
+
857
+ GetNArray(self,dst);
858
+ if (dst->total==0)
859
+ rb_raise(rb_eRuntimeError, "cannot set value to empty array");
860
+
861
+ /* make Slice from index-argv */
862
+ sl = ALLOC_N(struct slice, dst->rank+1);
863
+ size = na_index_analysis( nidx, idx, dst, sl );
864
+
865
+ if ( size == 0 ) { xfree(sl); return; } /* Empty index */
866
+ if ( size == 1 ) {
867
+ if (NA_IsArray(val)) {
868
+ /* Beginning index:
869
+ a[2,3,4] = other
870
+ */
871
+ val = na_cast_unless_narray(val,dst->type);
872
+ GetNArray(val,src);
873
+ if (src->total > 1)
874
+ for( i=0; i<src->rank; ++i ) {
875
+ sl[i].n = 0;
876
+ sl[i].step = 1;
877
+ }
878
+ }
879
+ else {
880
+ /* Single Element:
881
+ a[2,3,4] = 5
882
+ */
883
+ for ( pos=0, i=dst->rank; i-->0; )
884
+ pos = pos * dst->shape[i] + sl[i].beg;
885
+ SetFuncs[dst->type][NA_ROBJ](1, NA_PTR(dst,pos), 0, &val, 0 );
886
+ xfree(sl);
887
+ return;
888
+ }
889
+ }
890
+ else
891
+ val = na_cast_unless_narray(val,dst->type);
892
+ GetNArray(val,src);
893
+
894
+ /* if ( size>1 ) */
895
+ /* Range index:
896
+ a[0..9,0] = other
897
+ */
898
+ na_aset_slice( dst, src, sl );
899
+
900
+ na_free_slice_index(sl,nidx); /* free index memory */
901
+ xfree(sl);
902
+ }
903
+
904
+
905
+
906
+ static void
907
+ na_aset_fill(VALUE self, volatile VALUE val)
908
+ {
909
+ struct NARRAY *dst, *src;
910
+ struct slice *sl;
911
+
912
+ GetNArray(self,dst);
913
+ if (dst->total==0)
914
+ rb_raise(rb_eRuntimeError, "cannot set value to empty array");
915
+
916
+ if ( NA_IsArray(val) ) { /* store Array? */
917
+ sl = ALLOC_N(struct slice, dst->rank+1);
918
+ na_set_slice_1obj(dst->rank,sl,dst->shape);
919
+
920
+ val = na_cast_unless_narray(val,dst->type);
921
+ GetNArray(val,src);
922
+ na_aset_slice( dst, src, sl );
923
+ xfree(sl);
924
+ }
925
+ else {
926
+ na_fill( self, val ); /* Simple filling */
927
+ }
928
+ }
929
+
930
+
931
+ /* --- mask --- */
932
+ void
933
+ na_aset_mask(VALUE self, VALUE mask, VALUE val)
934
+ {
935
+ int size, step, i;
936
+ struct NARRAY *a1, *am, *a2;
937
+
938
+ GetNArray( self, a1 );
939
+ GetNArray( mask, am );
940
+
941
+ if (a1->total != am->total)
942
+ rb_raise(rb_eTypeError,"self.size(=%i) != mask.size(=%i)",
943
+ a1->total, am->total);
944
+ if (a1->rank != am->rank)
945
+ rb_raise(rb_eTypeError,"self.rank(=%i) != mask.rank(=%i)",
946
+ a1->rank, am->rank);
947
+ for (i=0; i<a1->rank; ++i)
948
+ if (a1->shape[i] != am->shape[i])
949
+ rb_raise(rb_eTypeError,"self.shape[%i](=%i) != mask.shape[%i](=%i)",
950
+ i, a1->shape[i], i, am->shape[i]);
951
+
952
+ size = na_count_true_body(mask);
953
+
954
+ val = na_cast_object(val,a1->type);
955
+ GetNArray( val, a2 );
956
+ if (a2->total == 1) {
957
+ step = 0;
958
+ } else if (a2->total == size) {
959
+ step = na_sizeof[a2->type];
960
+ } else {
961
+ rb_raise(rb_eTypeError,"val.length != mask.count_true");
962
+ }
963
+
964
+ SetMaskFuncs[a1->type]
965
+ ( a1->total, a1->ptr, na_sizeof[a1->type],
966
+ a2->ptr, step, am->ptr, 1 );
967
+ }
968
+
969
+ /* method: []=(idx1,idx2,...,idxN,val) */
970
+ VALUE
971
+ na_aset(int nidx, VALUE *idx, VALUE self)
972
+ {
973
+ --nidx;
974
+
975
+ if (nidx==0) {
976
+ na_aset_fill( self, idx[0] );
977
+ }
978
+ else
979
+ if (nidx==1) {
980
+ if ( NA_IsNArray(idx[0]) ) {
981
+ if( NA_TYPE(idx[0]) == NA_BYTE ) { /* then supposed to be a mask */
982
+ na_aset_mask(self, idx[0], idx[1]);
983
+ return(idx[1]);
984
+ }
985
+ }
986
+ if ( NA_IsArray(idx[0]) ) /* Array Index ? */
987
+ na_aset_array_index( self, idx[0], idx[1] );
988
+ else
989
+ na_aset_single_dim( self, idx[0], idx[1] );
990
+ }
991
+ else
992
+ if (nidx>1) {
993
+ na_aset_multi_dim( self, nidx, idx, idx[nidx] );
994
+ }
995
+ else /* if (nidx<0) */
996
+ rb_raise( rb_eArgError, "No value specified" );
997
+
998
+ return idx[nidx];
999
+ }
1000
+
1001
+
1002
+ void Init_na_index() {
1003
+ /* slice */
1004
+ rb_define_method(cNArray, "[]", na_aref,-1);
1005
+ rb_define_method(cNArray, "[]=", na_aset,-1);
1006
+ rb_define_method(cNArray, "slice", na_slice,-1);
1007
+ /* mask */
1008
+ rb_define_method(cNArray, "count_false", na_count_false, 0);
1009
+ rb_define_method(cNArray, "count_true", na_count_true, 0);
1010
+ rb_define_method(cNArray, "mask", na_aref_mask, 1);
1011
+ }