numru-narray 1.0.0

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