carray 3.0.4 → 3.0.6

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.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +438 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_dispatch.c +19 -20
  7. data/ext/ca_axis_group.c +1 -1
  8. data/ext/ca_categorical_iterator.c +34 -27
  9. data/ext/ca_compare.c +4 -4
  10. data/ext/ca_composite_dispatch.c +9 -9
  11. data/ext/ca_kernel_iterator.c +122 -237
  12. data/ext/ca_kernel_iterator.h +522 -337
  13. data/ext/ca_obj_array.c +69 -19
  14. data/ext/ca_obj_bincmp.c +10 -1
  15. data/ext/ca_obj_binop.c +11 -1
  16. data/ext/ca_obj_bitarray.c +5 -1
  17. data/ext/ca_obj_bitfield.c +60 -43
  18. data/ext/ca_obj_byte_swap.c +4 -1
  19. data/ext/ca_obj_const_string.c +15 -3
  20. data/ext/ca_obj_face.c +44 -1
  21. data/ext/ca_obj_fake.c +3 -1
  22. data/ext/ca_obj_field.c +13 -3
  23. data/ext/ca_obj_grid.c +219 -17
  24. data/ext/ca_obj_meld.c +69 -113
  25. data/ext/ca_obj_moncmp.c +9 -1
  26. data/ext/ca_obj_monop.c +86 -12
  27. data/ext/ca_obj_object.c +118 -32
  28. data/ext/ca_obj_record.c +3 -0
  29. data/ext/ca_obj_reduce.c +19 -1
  30. data/ext/ca_obj_refer.c +80 -26
  31. data/ext/ca_obj_remap.c +69 -10
  32. data/ext/ca_obj_roll.c +27 -6
  33. data/ext/ca_obj_select.c +38 -6
  34. data/ext/ca_obj_select_axis.c +1 -0
  35. data/ext/ca_obj_shift.c +32 -7
  36. data/ext/ca_obj_stack.c +311 -111
  37. data/ext/ca_obj_stride.c +159 -64
  38. data/ext/ca_obj_string.c +27 -2
  39. data/ext/ca_obj_tile.c +28 -7
  40. data/ext/ca_obj_transpose.c +8 -4
  41. data/ext/ca_obj_triop.c +12 -1
  42. data/ext/ca_obj_window.c +80 -50
  43. data/ext/ca_op_ipower.c +12 -12
  44. data/ext/ca_sort_kernels.h +6 -3
  45. data/ext/caframe_csv_reader.c +1 -1
  46. data/ext/carray.h +35 -1
  47. data/ext/carray_access.c +43 -67
  48. data/ext/carray_address_basis.c +134 -0
  49. data/ext/carray_attribute.c +32 -0
  50. data/ext/carray_broadcast.c +3 -4
  51. data/ext/carray_build_flags.h +1 -1
  52. data/ext/carray_cast.c +251 -93
  53. data/ext/carray_cast_func.rb +56 -26
  54. data/ext/carray_conversion.c +11 -7
  55. data/ext/carray_core.c +814 -72
  56. data/ext/carray_count.c +6 -0
  57. data/ext/carray_element.c +22 -13
  58. data/ext/carray_factorize.c +20 -20
  59. data/ext/carray_generate.c +8 -2
  60. data/ext/carray_histogram.c +26 -4
  61. data/ext/carray_index_classifier.c +4 -4
  62. data/ext/carray_internal.h +159 -12
  63. data/ext/carray_kernels_bincmp.c +2174 -170
  64. data/ext/carray_kernels_binop.c +25653 -5487
  65. data/ext/carray_kernels_init.c +8 -8
  66. data/ext/carray_kernels_moncmp.c +96 -96
  67. data/ext/carray_kernels_monop.c +12253 -5235
  68. data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
  69. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  70. data/ext/carray_kernels_reduce_cumulative.c +2442 -882
  71. data/ext/carray_kernels_reduce_extreme.c +5658 -1661
  72. data/ext/carray_kernels_reduce_variance.c +2534 -402
  73. data/ext/carray_kernels_scan.c +368 -368
  74. data/ext/carray_kernels_search.c +4551 -604
  75. data/ext/carray_kernels_sort.c +659 -751
  76. data/ext/carray_kernels_triop.c +114 -114
  77. data/ext/carray_key_windows.c +4 -0
  78. data/ext/carray_lazy.c +47 -0
  79. data/ext/carray_loop.c +1 -1
  80. data/ext/carray_mask.c +175 -161
  81. data/ext/carray_median_percentile.c +4 -4
  82. data/ext/carray_memory_view.c +15 -9
  83. data/ext/carray_operator.c +152 -49
  84. data/ext/carray_order.c +230 -10
  85. data/ext/carray_random.c +22 -19
  86. data/ext/carray_scatter.c +24 -7
  87. data/ext/carray_slab.c +128 -29
  88. data/ext/carray_sort.c +224 -16
  89. data/ext/carray_sort_kernel.c +5 -7
  90. data/ext/carray_struct.c +35 -43
  91. data/ext/carray_test.c +74 -19
  92. data/ext/carray_time_text.c +6 -4
  93. data/ext/carray_utils.c +63 -21
  94. data/ext/extconf.rb +11 -0
  95. data/ext/mkkernel.rb +546 -199
  96. data/ext/ruby_carray.c +4 -1
  97. data/ext/version.h +4 -4
  98. data/lib/carray/attribute.rb +42 -5
  99. data/lib/carray/autoload_carray.rb +3 -3
  100. data/lib/carray/autoload_method_extension.rb +5 -3
  101. data/lib/carray/axis_group.rb +13 -7
  102. data/lib/carray/basics.rb +28 -8
  103. data/lib/carray/block_iterator.rb +17 -3
  104. data/lib/carray/categorical.rb +35 -23
  105. data/lib/carray/categorical_iterator.rb +8 -8
  106. data/lib/carray/complex.rb +2 -2
  107. data/lib/carray/conditional.rb +3 -2
  108. data/lib/carray/const_string.rb +10 -0
  109. data/lib/carray/data_type_extension.rb +8 -1
  110. data/lib/carray/fixlen_string.rb +41 -2
  111. data/lib/carray/frame/column_verbs.rb +48 -16
  112. data/lib/carray/frame/concat.rb +17 -3
  113. data/lib/carray/frame/convert.rb +19 -0
  114. data/lib/carray/frame/csv_parser.rb +32 -32
  115. data/lib/carray/frame/describe.rb +4 -2
  116. data/lib/carray/frame/frame.rb +405 -85
  117. data/lib/carray/frame/group.rb +777 -64
  118. data/lib/carray/frame/io.rb +212 -72
  119. data/lib/carray/frame/join.rb +146 -37
  120. data/lib/carray/frame/records.rb +3 -3
  121. data/lib/carray/frame/reshape.rb +89 -11
  122. data/lib/carray/frame/sort.rb +57 -9
  123. data/lib/carray/frame/verbs.rb +384 -49
  124. data/lib/carray/frame/windows.rb +44 -6
  125. data/lib/carray/fuse_source.rb +31 -2
  126. data/lib/carray/inspect.rb +7 -2
  127. data/lib/carray/iterator.rb +32 -0
  128. data/lib/carray/lazy.rb +52 -8
  129. data/lib/carray/mask_gap_fill.rb +37 -17
  130. data/lib/carray/meld_reduce.rb +1 -1
  131. data/lib/carray/methods/choose.rb +3 -2
  132. data/lib/carray/methods/is_in.rb +8 -1
  133. data/lib/carray/methods/meshgrid.rb +3 -1
  134. data/lib/carray/runtime.rb +47 -8
  135. data/lib/carray/segment_iterator.rb +35 -16
  136. data/lib/carray/serialize.rb +53 -19
  137. data/lib/carray/stack.rb +33 -18
  138. data/lib/carray/string.rb +8 -0
  139. data/lib/carray/string_operation_extension.rb +13 -5
  140. data/lib/carray/struct_builder.rb +5 -3
  141. data/lib/carray/time.rb +112 -68
  142. data/lib/carray/window_iterator.rb +16 -4
  143. data/yard-stubs/ca_obj_array.rb +26 -1
  144. data/yard-stubs/ca_obj_transpose.rb +5 -4
  145. data/yard-stubs/carray_attribute.rb +3 -1
  146. data/yard-stubs/carray_cast.rb +10 -5
  147. data/yard-stubs/carray_conversion.rb +13 -3
  148. data/yard-stubs/carray_element.rb +7 -6
  149. data/yard-stubs/carray_mask.rb +28 -4
  150. data/yard-stubs/carray_math.rb +45 -20
  151. data/yard-stubs/carray_memory_view.rb +7 -0
  152. data/yard-stubs/carray_order.rb +100 -4
  153. data/yard-stubs/carray_scatter.rb +7 -5
  154. data/yard-stubs/carray_test.rb +7 -4
  155. metadata +18 -4
@@ -218,7 +218,7 @@ ca_chunked_run_acquire (ca_chunked_run_t *run, int k)
218
218
  }
219
219
 
220
220
  static VALUE
221
- ca_chunked_run_body (VALUE arg)
221
+ ca_chunked_run_loop (VALUE arg)
222
222
  {
223
223
  ca_chunked_run_t *run = (ca_chunked_run_t *) arg;
224
224
  char *p[CA_CHUNKED_MAX_OPERANDS];
@@ -245,6 +245,15 @@ ca_chunked_run_body (VALUE arg)
245
245
  return Qnil;
246
246
  }
247
247
 
248
+ /* The object arrays among the operands are recorded as computed over
249
+ (ca_computing_run) while the run reads them. */
250
+ static VALUE
251
+ ca_chunked_run_body (VALUE arg)
252
+ {
253
+ ca_chunked_run_t *run = (ca_chunked_run_t *) arg;
254
+ return ca_computing_run(run->n_op, run->ca, ca_chunked_run_loop, arg);
255
+ }
256
+
248
257
  static VALUE
249
258
  ca_chunked_run_release (VALUE arg)
250
259
  {
@@ -450,13 +459,21 @@ typedef struct {
450
459
  int n;
451
460
  CArray **held;
452
461
  const char *mode; /* per held array: 'r' read, 'w' written in place */
462
+ CArray **ops; /* every operand, attached or gathered */
453
463
  } ca_op_guard_t;
454
464
 
465
+ static VALUE
466
+ ca_op_guard_run (VALUE varg)
467
+ {
468
+ ca_op_guard_t *g = (ca_op_guard_t *) varg;
469
+ return g->run(g->arg);
470
+ }
471
+
455
472
  static VALUE
456
473
  ca_op_guard_body (VALUE varg)
457
474
  {
458
475
  ca_op_guard_t *g = (ca_op_guard_t *) varg;
459
- g->run(g->arg);
476
+ ca_computing_run(g->n, g->ops, ca_op_guard_run, varg);
460
477
  g->done = 1;
461
478
  return Qnil;
462
479
  }
@@ -496,10 +513,13 @@ ca_op_guard_release (VALUE varg)
496
513
  }
497
514
 
498
515
  /* Runs the kernel packed in `call` with `held` attached; see above. NULL
499
- entries in held are skipped. */
516
+ entries in held are skipped. ops lists every operand the kernel reads
517
+ or writes, attached or gathered into a buffer, so that the object
518
+ arrays among them are recorded as computed over (ca_computing_run)
519
+ while the kernel runs; NULL means the operands are the held arrays. */
500
520
  static void
501
521
  ca_op_guarded (VALUE (*run)(VALUE), void *call,
502
- int n, CArray **held, const char *mode)
522
+ int n, CArray **held, const char *mode, CArray **ops)
503
523
  {
504
524
  ca_op_guard_t g;
505
525
  g.run = run;
@@ -508,6 +528,7 @@ ca_op_guarded (VALUE (*run)(VALUE), void *call,
508
528
  g.n = n;
509
529
  g.held = held;
510
530
  g.mode = mode;
531
+ g.ops = ops ? ops : held;
511
532
  rb_ensure(ca_op_guard_body, (VALUE) &g, ca_op_guard_release, (VALUE) &g);
512
533
  }
513
534
 
@@ -556,6 +577,13 @@ ca_mask_overlay_or_body (VALUE arg)
556
577
  Each operand other than a scalar has ca_out's number of elements
557
578
  (ArgumentError otherwise); at most 8 operands.
558
579
 
580
+ A bang operation's ca_out can share its root with an operand, so its
581
+ mask buffer may be the root's mask that a later operand's mask reads
582
+ (`r.fma!(m, r.flip(0))`). When more than one operand is read and one
583
+ of them shares ca_out's root, the operands' masks are folded into a
584
+ scratch first and ORed into ca_out's mask at the end, so every operand
585
+ is read before ca_out's mask changes.
586
+
559
587
  This gathers the full mask once; a per-chunk mask gather inside the
560
588
  chunked branch is a possible future optimisation. */
561
589
  void
@@ -563,7 +591,7 @@ ca_mask_overlay_safe (CArray *ca_out, int n, ...)
563
591
  {
564
592
  va_list ap;
565
593
  CArray *slist[8];
566
- int i, any_mask = 0;
594
+ int i, any_mask = 0, n_read = 0, shares = 0;
567
595
 
568
596
  if ( n < 0 || n > 8 ) {
569
597
  rb_raise(rb_eRuntimeError, "ca_mask_overlay_safe: n out of range");
@@ -589,23 +617,46 @@ ca_mask_overlay_safe (CArray *ca_out, int n, ...)
589
617
 
590
618
  if ( ! any_mask ) return;
591
619
 
620
+ for ( i = 0; i < n; i++ ) {
621
+ CArray *cs = slist[i];
622
+ if ( ! cs || cs == ca_out ) {
623
+ continue;
624
+ }
625
+ n_read++;
626
+ if ( ca_shares_root(ca_out, cs) ) {
627
+ shares = 1;
628
+ }
629
+ }
630
+
592
631
  ca_update_mask(ca_out);
593
632
  {
594
633
  int created_new = 0;
634
+ volatile VALUE hacc = 0;
635
+ boolean8_t *mout, *ma;
636
+ ca_size_t elements = ca_out->elements;
637
+
595
638
  if ( ! ca_out->mask ) {
596
639
  ca_create_mask(ca_out);
597
640
  created_new = 1;
598
641
  }
599
642
 
600
- boolean8_t *ma = (boolean8_t *) ca_out->mask->ptr;
601
- ca_size_t elements = ca_out->elements;
643
+ mout = (boolean8_t *) ca_out->mask->ptr;
644
+ if ( n_read > 1 && shares ) {
645
+ ma = ALLOCV_N(boolean8_t, hacc, elements);
646
+ memset(ma, 0, elements);
647
+ }
648
+ else {
649
+ ma = mout;
650
+ }
602
651
 
603
652
  /* Fresh mask → zero-init. Existing mask (= bang variant where
604
653
  ca_out IS one of the operands) → preserve as initial accumulator
605
654
  (= ca_out's own contribution is already in `ma`, OR in others).
606
655
  This is structurally equivalent to ca_copy_mask_overlay_n's
607
656
  behavior which OR'd into existing mask without clearing. */
608
- if ( created_new ) memset(ma, 0, elements);
657
+ if ( created_new ) {
658
+ memset(mout, 0, elements);
659
+ }
609
660
 
610
661
  for ( i = 0; i < n; i++ ) {
611
662
  CArray *cs = slist[i];
@@ -627,6 +678,14 @@ ca_mask_overlay_safe (CArray *ca_out, int n, ...)
627
678
  ca_lazy_arena_release_held, (VALUE) &o);
628
679
  }
629
680
  }
681
+
682
+ if ( ma != mout ) {
683
+ ca_size_t j;
684
+ for (j=0; j<elements; j++) {
685
+ mout[j] |= ma[j];
686
+ }
687
+ ALLOCV_END(hacc);
688
+ }
630
689
  }
631
690
  }
632
691
 
@@ -707,7 +766,7 @@ rb_ca_call_monop (VALUE self, ca_monop_func_t func[])
707
766
  ca_attach(ca1); /* window: the kernel runs through ca_op_guarded when it can raise */
708
767
  k.p1 = ca1->ptr; k.i1 = 1;
709
768
  if ( ca_monop_may_raise(func, ca1->data_type) ) {
710
- ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r");
769
+ ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r", NULL);
711
770
  }
712
771
  else {
713
772
  ca_monop_call((VALUE) &k);
@@ -724,7 +783,7 @@ rb_ca_call_monop (VALUE self, ca_monop_func_t func[])
724
783
  int strided_path_done = 0;
725
784
  {
726
785
  extern ca_operation_function_t ca_stride_func;
727
- if ( ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
786
+ if ( ca1->data_type != CA_OBJECT && ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
728
787
  CAStride *cs1 = (CAStride *) ca1;
729
788
  CArray *root1;
730
789
  ca_size_t strides1[CA_RANK_MAX];
@@ -804,10 +863,21 @@ rb_ca_call_monop (VALUE self, ca_monop_func_t func[])
804
863
  (void) h1;
805
864
  p1 = ALLOCV_N(char, h1, ca1->elements * ca1->bytes);
806
865
  ca_xfer_all(ca1, p1, CA_XFER_GET);
807
- func[ca1->data_type](ca1->elements,
808
- ( ca2->mask ) ? (boolean8_t *)ca2->mask->ptr : NULL,
809
- p1, 1,
810
- ca2->ptr, 1);
866
+ {
867
+ ca_monop_call_t k;
868
+ CArray *none[1] = { NULL };
869
+ k.f = func[ca1->data_type];
870
+ k.n = ca1->elements;
871
+ k.m = ( ca2->mask ) ? (boolean8_t *)ca2->mask->ptr : NULL;
872
+ k.p1 = p1; k.i1 = 1;
873
+ k.p2 = ca2->ptr; k.i2 = 1;
874
+ if ( ca_monop_may_raise(func, ca1->data_type) ) {
875
+ ca_op_guarded(ca_monop_call, &k, 1, none, "r", &ca1);
876
+ }
877
+ else {
878
+ ca_monop_call((VALUE) &k);
879
+ }
880
+ }
811
881
  ALLOCV_END(h1);
812
882
  }
813
883
  }
@@ -838,7 +908,7 @@ rb_ca_call_monop_bang (VALUE self, ca_monop_func_t func[])
838
908
  k.p1 = ca1->ptr; k.i1 = 1;
839
909
  k.p2 = ca1->ptr; k.i2 = 1;
840
910
  if ( ca_monop_may_raise(func, ca1->data_type) ) {
841
- ca_op_guarded(ca_monop_call, &k, 1, &ca1, "w");
911
+ ca_op_guarded(ca_monop_call, &k, 1, &ca1, "w", NULL);
842
912
  }
843
913
  else {
844
914
  ca_monop_call((VALUE) &k);
@@ -889,7 +959,7 @@ rb_ca_call_monop_typed (VALUE self, ca_monop_func_t func[],
889
959
  ca_attach(ca1); /* window: the kernel runs through ca_op_guarded when it can raise */
890
960
  k.p1 = ca1->ptr; k.i1 = 1;
891
961
  if ( ca_monop_may_raise(func, ca1->data_type) ) {
892
- ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r");
962
+ ca_op_guarded(ca_monop_call, &k, 1, &ca1, "r", NULL);
893
963
  }
894
964
  else {
895
965
  ca_monop_call((VALUE) &k);
@@ -903,7 +973,7 @@ rb_ca_call_monop_typed (VALUE self, ca_monop_func_t func[],
903
973
  int strided_path_done = 0;
904
974
  {
905
975
  extern ca_operation_function_t ca_stride_func;
906
- if ( ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
976
+ if ( ca1->data_type != CA_OBJECT && ca_func[ca1->obj_type].attach == ca_stride_func.attach ) {
907
977
  CAStride *cs1 = (CAStride *) ca1;
908
978
  CArray *root1;
909
979
  ca_size_t strides1[CA_RANK_MAX];
@@ -982,10 +1052,21 @@ rb_ca_call_monop_typed (VALUE self, ca_monop_func_t func[],
982
1052
  (void) h1;
983
1053
  p1 = ALLOCV_N(char, h1, ca1->elements * ca1->bytes);
984
1054
  ca_xfer_all(ca1, p1, CA_XFER_GET);
985
- func[ca1->data_type](ca1->elements,
986
- ( ca2->mask ) ? (boolean8_t *)ca2->mask->ptr : NULL,
987
- p1, 1,
988
- ca2->ptr, 1);
1055
+ {
1056
+ ca_monop_call_t k;
1057
+ CArray *none[1] = { NULL };
1058
+ k.f = func[ca1->data_type];
1059
+ k.n = ca1->elements;
1060
+ k.m = ( ca2->mask ) ? (boolean8_t *)ca2->mask->ptr : NULL;
1061
+ k.p1 = p1; k.i1 = 1;
1062
+ k.p2 = ca2->ptr; k.i2 = 1;
1063
+ if ( ca_monop_may_raise(func, ca1->data_type) ) {
1064
+ ca_op_guarded(ca_monop_call, &k, 1, none, "r", &ca1);
1065
+ }
1066
+ else {
1067
+ ca_monop_call((VALUE) &k);
1068
+ }
1069
+ }
989
1070
  ALLOCV_END(h1);
990
1071
  }
991
1072
  }
@@ -1286,7 +1367,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
1286
1367
  k.p2 = ca2->ptr; k.i2 = i2;
1287
1368
  if ( ca_binop_may_raise(func, ca1->data_type) ) {
1288
1369
  held[0] = ca1; held[1] = ca2;
1289
- ca_op_guarded(ca_binop_call, &k, 2, held, "rr");
1370
+ ca_op_guarded(ca_binop_call, &k, 2, held, "rr", NULL);
1290
1371
  }
1291
1372
  else {
1292
1373
  ca_binop_call((VALUE) &k);
@@ -1305,11 +1386,22 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
1305
1386
 
1306
1387
  p_shared = ALLOCV_N(char, h_shared, ca1->elements * ca1->bytes);
1307
1388
  ca_xfer_all(ca1, p_shared, CA_XFER_GET);
1308
- func[ca1->data_type](n_kernel,
1309
- ( ca3->mask ) ? (boolean8_t *) ca3->mask->ptr : NULL,
1310
- p_shared, i1,
1311
- p_shared, i2,
1312
- ca3->ptr, i3);
1389
+ {
1390
+ ca_binop_call_t k;
1391
+ CArray *none[2] = { NULL, NULL };
1392
+ k.f = func[ca1->data_type];
1393
+ k.n = n_kernel;
1394
+ k.m = ( ca3->mask ) ? (boolean8_t *) ca3->mask->ptr : NULL;
1395
+ k.p1 = p_shared; k.i1 = i1;
1396
+ k.p2 = p_shared; k.i2 = i2;
1397
+ k.p3 = ca3->ptr; k.i3 = i3;
1398
+ if ( ca_binop_may_raise(func, ca1->data_type) ) {
1399
+ ca_op_guarded(ca_binop_call, &k, 2, none, "rr", (CArray *[]){ ca1, ca2 });
1400
+ }
1401
+ else {
1402
+ ca_binop_call((VALUE) &k);
1403
+ }
1404
+ }
1313
1405
  ALLOCV_END(h_shared);
1314
1406
  }
1315
1407
  else {
@@ -1353,7 +1445,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
1353
1445
  fallback (dead on the success path) but fire for views outside the
1354
1446
  CAStride+entity family (CASelect / CAGrid / CAReduce
1355
1447
  etc.). */
1356
- if ( i1 == 1 && i2 == 1 && nonalias_arrays >= 1 ) {
1448
+ if ( dt != CA_OBJECT && i1 == 1 && i2 == 1 && nonalias_arrays >= 1 ) {
1357
1449
  extern ca_operation_function_t ca_stride_func;
1358
1450
  CArray *root1 = NULL, *root2 = NULL;
1359
1451
  ca_size_t strides1[CA_RANK_MAX], strides2[CA_RANK_MAX];
@@ -1473,7 +1565,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
1473
1565
  /* 1-shot ALLOCV path. At most 1 operand needs ALLOCV; the other is
1474
1566
  alias-direct. */
1475
1567
  volatile VALUE h1 = Qnil, h2 = Qnil;
1476
- char *p1, *p2;
1568
+ char *p1 = NULL, *p2 = NULL;
1477
1569
  int a1 = 0, a2 = 0;
1478
1570
  (void) h1; (void) h2;
1479
1571
 
@@ -1505,7 +1597,7 @@ rb_ca_call_binop (volatile VALUE self, volatile VALUE other,
1505
1597
  if ( ca_binop_may_raise(func, dt) ) {
1506
1598
  held[0] = a1 ? ca1 : NULL;
1507
1599
  held[1] = a2 ? ca2 : NULL;
1508
- ca_op_guarded(ca_binop_call, &k, 2, held, "rr");
1600
+ ca_op_guarded(ca_binop_call, &k, 2, held, "rr", (CArray *[]){ ca1, ca2 });
1509
1601
  }
1510
1602
  else {
1511
1603
  ca_binop_call((VALUE) &k);
@@ -1639,7 +1731,7 @@ rb_ca_call_binop_bang (VALUE self, VALUE other, ca_binop_func_t func[])
1639
1731
  if ( ca_binop_may_raise(func, ca1->data_type) ) {
1640
1732
  held[0] = ca1;
1641
1733
  held[1] = a2 ? ca2 : NULL;
1642
- ca_op_guarded(ca_binop_call, &k, 2, held, "wr");
1734
+ ca_op_guarded(ca_binop_call, &k, 2, held, "wr", (CArray *[]){ ca1, ca2 });
1643
1735
  }
1644
1736
  else {
1645
1737
  ca_binop_call((VALUE) &k);
@@ -1841,7 +1933,7 @@ rb_ca_call_triop (VALUE self, VALUE other2, VALUE other3,
1841
1933
 
1842
1934
  if ( !use_chunked ) {
1843
1935
  volatile VALUE h1 = Qnil, h2 = Qnil, h3 = Qnil;
1844
- char *p1, *p2, *p3;
1936
+ char *p1 = NULL, *p2 = NULL, *p3 = NULL;
1845
1937
  int attached1, attached2, attached3;
1846
1938
  (void) h1; (void) h2; (void) h3;
1847
1939
 
@@ -1866,7 +1958,7 @@ rb_ca_call_triop (VALUE self, VALUE other2, VALUE other3,
1866
1958
  held[0] = attached1 ? ca1 : NULL;
1867
1959
  held[1] = attached2 ? ca2 : NULL;
1868
1960
  held[2] = attached3 ? ca3 : NULL;
1869
- ca_op_guarded(ca_triop_call, &k, 3, held, "rrr");
1961
+ ca_op_guarded(ca_triop_call, &k, 3, held, "rrr", (CArray *[]){ ca1, ca2, ca3 });
1870
1962
  }
1871
1963
  else {
1872
1964
  ca_triop_call((VALUE) &k);
@@ -1984,7 +2076,7 @@ rb_ca_call_triop_bang (VALUE self, VALUE other2, VALUE other3,
1984
2076
 
1985
2077
  if ( !use_chunked ) {
1986
2078
  volatile VALUE h2 = Qnil, h3 = Qnil;
1987
- char *p2, *p3;
2079
+ char *p2 = NULL, *p3 = NULL;
1988
2080
  int attached2, attached3;
1989
2081
  ca_triop_call_t k;
1990
2082
  CArray *held[3];
@@ -2032,7 +2124,7 @@ rb_ca_call_triop_bang (VALUE self, VALUE other2, VALUE other3,
2032
2124
  held[0] = ca1;
2033
2125
  held[1] = attached2 ? ca2 : NULL;
2034
2126
  held[2] = attached3 ? ca3 : NULL;
2035
- ca_op_guarded(ca_triop_call, &k, 3, held, "wrr");
2127
+ ca_op_guarded(ca_triop_call, &k, 3, held, "wrr", (CArray *[]){ ca1, ca2, ca3 });
2036
2128
  }
2037
2129
  else {
2038
2130
  ca_triop_call((VALUE) &k);
@@ -2077,7 +2169,7 @@ rb_ca_call_triop_bang (VALUE self, VALUE other2, VALUE other3,
2077
2169
  ca_chunked_run_add(&run, ca3, s3);
2078
2170
  run.kernel = ca_triop_chunk_kernel;
2079
2171
  run.data = &d;
2080
- ca_op_guarded(ca_triop_bang_chunked, &run, 1, &ca1, "w");
2172
+ ca_op_guarded(ca_triop_bang_chunked, &run, 1, &ca1, "w", NULL);
2081
2173
  }
2082
2174
  }
2083
2175
  }
@@ -2129,7 +2221,7 @@ rb_ca_call_moncmp (VALUE self, ca_moncmp_func_t func[])
2129
2221
 
2130
2222
  {
2131
2223
  volatile VALUE h1 = Qnil;
2132
- char *p1;
2224
+ char *p1 = NULL;
2133
2225
  int attached1;
2134
2226
  (void) h1;
2135
2227
 
@@ -2141,8 +2233,9 @@ rb_ca_call_moncmp (VALUE self, ca_moncmp_func_t func[])
2141
2233
  k.m = ( ca2->mask ) ? (boolean8_t *) ca2->mask->ptr : NULL;
2142
2234
  k.p1 = p1; k.i1 = 1;
2143
2235
  k.p2 = (boolean8_t *) ca2->ptr; k.i2 = 1;
2144
- if ( attached1 && ca_moncmp_may_raise(func, ca1->data_type) ) {
2145
- ca_op_guarded(ca_moncmp_call, &k, 1, &ca1, "r");
2236
+ if ( ca_moncmp_may_raise(func, ca1->data_type) ) {
2237
+ CArray *none[1] = { NULL };
2238
+ ca_op_guarded(ca_moncmp_call, &k, 1, attached1 ? &ca1 : none, "r", &ca1);
2146
2239
  }
2147
2240
  else {
2148
2241
  ca_moncmp_call((VALUE) &k);
@@ -2431,12 +2524,23 @@ rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
2431
2524
  (void) h_shared;
2432
2525
  p_shared = ALLOCV_N(char, h_shared, ca1->elements * ca1->bytes);
2433
2526
  ca_xfer_all(ca1, p_shared, CA_XFER_GET);
2434
- func[ca1->data_type](n_kernel,
2435
- ( ca3->mask ) ? (boolean8_t *) ca3->mask->ptr : NULL,
2436
- p_shared, ca1->bytes, i1,
2437
- p_shared, ca2->bytes, i2,
2438
- ca3->ptr, ca3->bytes, i3,
2439
- tol);
2527
+ {
2528
+ ca_bincmp_call_t k;
2529
+ CArray *none[2] = { NULL, NULL };
2530
+ k.f = func[ca1->data_type];
2531
+ k.n = n_kernel;
2532
+ k.m = ( ca3->mask ) ? (boolean8_t *) ca3->mask->ptr : NULL;
2533
+ k.p1 = p_shared; k.b1 = ca1->bytes; k.i1 = i1;
2534
+ k.p2 = p_shared; k.b2 = ca2->bytes; k.i2 = i2;
2535
+ k.p3 = ca3->ptr; k.b3 = ca3->bytes; k.i3 = i3;
2536
+ k.tol = tol;
2537
+ if ( ca_bincmp_may_raise(func, ca1->data_type) ) {
2538
+ ca_op_guarded(ca_bincmp_call, &k, 2, none, "rr", (CArray *[]){ ca1, ca2 });
2539
+ }
2540
+ else {
2541
+ ca_bincmp_call((VALUE) &k);
2542
+ }
2543
+ }
2440
2544
  ALLOCV_END(h_shared);
2441
2545
  }
2442
2546
  else {
@@ -2452,7 +2556,7 @@ rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
2452
2556
 
2453
2557
  if ( !use_chunked ) {
2454
2558
  volatile VALUE h1 = Qnil, h2 = Qnil;
2455
- char *p1, *p2;
2559
+ char *p1 = NULL, *p2 = NULL;
2456
2560
  int attached1, attached2;
2457
2561
  (void) h1; (void) h2;
2458
2562
 
@@ -2470,11 +2574,10 @@ rb_ca_call_bincmp (volatile VALUE self, volatile VALUE other,
2470
2574
  k.p2 = p2; k.b2 = ca2->bytes; k.i2 = i2;
2471
2575
  k.p3 = ca3->ptr; k.b3 = ca3->bytes; k.i3 = i3;
2472
2576
  k.tol = tol;
2473
- if ( ( attached1 || attached2 ) &&
2474
- ca_bincmp_may_raise(func, ca1->data_type) ) {
2577
+ if ( ca_bincmp_may_raise(func, ca1->data_type) ) {
2475
2578
  held[0] = attached1 ? ca1 : NULL;
2476
2579
  held[1] = attached2 ? ca2 : NULL;
2477
- ca_op_guarded(ca_bincmp_call, &k, 2, held, "rr");
2580
+ ca_op_guarded(ca_bincmp_call, &k, 2, held, "rr", (CArray *[]){ ca1, ca2 });
2478
2581
  }
2479
2582
  else {
2480
2583
  ca_bincmp_call((VALUE) &k);