narray-nmatrix 0.6.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }