carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
data/ext/carray_slab.c CHANGED
@@ -28,8 +28,20 @@
28
28
  --------------------------------------------------------------------------- */
29
29
 
30
30
  #include "carray.h"
31
- #include "carray_internal.h" /* ca_attach_window, ca_calling_method_name, ca_axis_integer */
31
+ #include "carray_internal.h" /* ca_attach_window, ca_calling_method_name, ca_normalize_axis_arg */
32
32
  #include "carray_slab.h"
33
+ #include "ca_obj_face.h"
34
+
35
+ /* Promise 8 of the kernel iterator: a slab may be lent to Ruby as a view
36
+ onto the source's own memory only when the source is an entity and the
37
+ walk reads that memory in place (alias_ptr is src->ptr, not a scratch or
38
+ a root it gathered from). Any other slab is a copy, and a view built on
39
+ it would read memory the walk frees or reuses. */
40
+ static int
41
+ ca_slab_walk_reads_src_in_place (const ca_iter_state *it, CArray *src)
42
+ {
43
+ return ca_is_entity(src) && it->alias_ptr == src->ptr;
44
+ }
33
45
 
34
46
  /* Forward declarations: per-form loop bodies are defined later in this
35
47
  file and take a state pointer directly. */
@@ -66,21 +78,14 @@ ca_slab_parse_axes (ca_slab_iter_state_t *st, VALUE axis_arg, int8_t src_ndim)
66
78
  }
67
79
 
68
80
  n = (int) RARRAY_LEN(arr);
69
- if ( n < 1 || n > CA_RANK_MAX ) {
81
+ if ( n < 1 || n > CA_RANK_MAX ) { /* rank-check: a list of axes, no longer than the rank */
70
82
  rb_raise(rb_eArgError,
71
83
  "%s: axis count %d out of range [1..%d]",
72
84
  ca_calling_method_name(), n, CA_RANK_MAX);
73
85
  }
74
86
 
75
87
  for ( i = 0; i < n; i++ ) {
76
- int k = (int) ca_axis_integer(rb_ary_entry(arr, i), NULL);
77
- if ( k < 0 ) k += src_ndim;
78
- if ( k < 0 || k >= src_ndim ) {
79
- rb_raise(rb_eArgError,
80
- "%s: axis %d out of range for ndim %d",
81
- ca_calling_method_name(), NUM2INT(rb_ary_entry(arr, i)),
82
- src_ndim);
83
- }
88
+ int k = ca_normalize_axis_arg(rb_ary_entry(arr, i), src_ndim, NULL);
84
89
  for ( j = 0; j < i; j++ ) {
85
90
  if ( st->slab_axes[j] == (int8_t) k ) {
86
91
  rb_raise(rb_eArgError,
@@ -341,6 +346,26 @@ ca_slab_build_output_view (int8_t data_type, ca_size_t bytes,
341
346
  return TypedData_Wrap_Struct(rb_cCAWrap, &cawrap_data_type, cw);
342
347
  }
343
348
 
349
+ /* The array the slab views move onto when the walk ends (see
350
+ slab_state_release_views), made with the carrier and held by it. It is
351
+ made here rather than at the end: the end runs in an ensure, after the
352
+ block, and an allocation failing there would leave the walk open and
353
+ the views pointing into freed scratch. */
354
+ static void
355
+ ca_slab_prepare_backing (ca_slab_iter_state_t *st)
356
+ {
357
+ CArray *cw, *backing;
358
+ volatile VALUE bv;
359
+ TypedData_Get_Struct(st->carrier, CArray, &carray_data_type, cw);
360
+ bv = rb_carray_new(cw->data_type, cw->ndim, cw->dim, cw->bytes, NULL);
361
+ TypedData_Get_Struct(bv, CArray, &carray_data_type, backing);
362
+ if ( cw->mask ) {
363
+ ca_create_mask(backing);
364
+ }
365
+ rb_ivar_set(st->carrier, rb_intern("__slab_backing__"), bv);
366
+ RB_GC_GUARD(bv);
367
+ }
368
+
344
369
  /* Common setup of the input slab view for all 4 forms. Decides ALIAS
345
370
  vs SCRATCH from T1's slab_strides[0] vs src->bytes equality, builds
346
371
  the slab_view + (when SCRATCH) carrier in place. The mask travels
@@ -370,12 +395,13 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
370
395
  p_in via slab_strides into the scratch, present slab_view as
371
396
  a CAStride over the carrier with contig strides.
372
397
 
373
- Path (a) needs p_in to lie in src's own buffer, which holds only
374
- when src is an entity. Any other source -- a view, whose cells the
375
- iterator hands out from the root, a parent or its own scratch --
398
+ Path (a) needs p_in to lie in src's own buffer: src is an entity
399
+ and the iterator walks that buffer (alias_ptr is src->ptr, not a
400
+ scratch it gathered into). Any other source -- a view, whose cells
401
+ the iterator hands out from the root, a parent or its own scratch --
376
402
  takes path (b): the iterator describes every slab by p_in and
377
403
  slab_strides, whatever its mode. */
378
- int contig = ca_is_entity(src)
404
+ int contig = ca_slab_walk_reads_src_in_place(st->t1, src)
379
405
  && ca_slab_strides_are_row_major_contig(slab_ndim,
380
406
  st->t1->slab_dims,
381
407
  st->t1->slab_strides,
@@ -436,9 +462,10 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
436
462
  dim[0] = fiber_len;
437
463
  strides[0] = src->bytes;
438
464
  /* A window onto src only when the fiber lies in src's own buffer:
439
- an entity whose fiber is contiguous. A view's fiber comes from
440
- the root or the iterator's scratch, so it goes through a carrier. */
441
- in_alias = ca_is_entity(src) && (in_stride == src->bytes);
465
+ an entity the iterator walks in place, whose fiber is contiguous.
466
+ A view's fiber comes from the root or the iterator's scratch, so it
467
+ goes through a carrier. */
468
+ in_alias = ca_slab_walk_reads_src_in_place(st->t1, src) && (in_stride == src->bytes);
442
469
 
443
470
  if ( in_alias ) {
444
471
  /* ALIAS: parent = src. ca_stride_setup auto-creates slab_view->mask
@@ -458,6 +485,10 @@ ca_slab_setup_input_slab_view (ca_slab_iter_state_t *st, CArray *src,
458
485
  }
459
486
  }
460
487
 
488
+ if ( st->carrier != Qnil ) {
489
+ ca_slab_prepare_backing(st);
490
+ }
491
+
461
492
  /* The slab is a window onto the source when the fiber is contiguous and
462
493
  a copy in the iterator's scratch when it is not, so writing through it
463
494
  landed on one axis and vanished on the next. Nothing in the surface
@@ -494,8 +525,18 @@ ca_slab_advance_slab_view (ca_slab_iter_state_t *st,
494
525
  slab_cs->base_offset = (ca_size_t) (p_in - src->ptr);
495
526
  if ( slab_cs->mask != NULL ) {
496
527
  CAStride *mask_cs = (CAStride *) slab_cs->mask;
497
- mask_cs->ptr = (char *) m_in;
498
- mask_cs->base_offset = (ca_size_t) ((char *) m_in - src->mask->ptr);
528
+ if ( m_in != NULL ) {
529
+ mask_cs->ptr = (char *) m_in;
530
+ mask_cs->base_offset = (ca_size_t) ((char *) m_in - src->mask->ptr);
531
+ }
532
+ else {
533
+ /* The walk was opened on a source without a mask and the block
534
+ has given it one since: there is no mask cursor, so the slab's
535
+ mask reads the source's mask at the cell the data starts on. */
536
+ mask_cs->ptr = NULL;
537
+ mask_cs->base_offset = (ca_size_t) ((p_in - src->ptr) / src->bytes)
538
+ * src->mask->bytes;
539
+ }
499
540
  }
500
541
  } else if ( st->own_data_scratch != NULL ) {
501
542
  /* Non-contig multi-axis: K-D gather from src memory (via
@@ -515,7 +556,7 @@ ca_slab_advance_slab_view (ca_slab_iter_state_t *st,
515
556
  both slab_view and carrier at the iter's delivered addr. */
516
557
  slab_cs->ptr = p_in;
517
558
  carrier_cw->ptr = p_in;
518
- if ( slab_cs->mask != NULL ) {
559
+ if ( slab_cs->mask != NULL && m_in != NULL ) {
519
560
  CAStride *mask_cs = (CAStride *) slab_cs->mask;
520
561
  mask_cs->ptr = (char *) m_in;
521
562
  carrier_cw->mask->ptr = (char *) m_in;
@@ -626,10 +667,26 @@ ca_map_slab_cast_body (VALUE arg)
626
667
  return Qnil;
627
668
  }
628
669
 
670
+ /* What the block sees of the slab: the slab view itself, or, over a Face,
671
+ the slab view under that Face, as `a[...]` would give it. The slab
672
+ view is moved per slab in place, and the Face reads through it, so one
673
+ is built per walk. */
674
+ static VALUE
675
+ ca_slab_piece (ca_slab_iter_state_t *st)
676
+ {
677
+ CArray *src;
678
+ TypedData_Get_Struct(st->self, CArray, &carray_data_type, src);
679
+ if ( ! ca_is_face(src) ) {
680
+ return st->slab_view;
681
+ }
682
+ return ca_face_lift(st->slab_view, st->self);
683
+ }
684
+
629
685
  static VALUE
630
686
  ca_slab_run_map (ca_slab_iter_state_t *st)
631
687
  {
632
688
  CArray *src;
689
+ volatile VALUE piece;
633
690
  CArray *out;
634
691
  uint32_t flags_in;
635
692
  uint32_t flags_out;
@@ -715,6 +772,7 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
715
772
  TypedData_Get_Struct(st->output_slab_view, CAWrap,
716
773
  &cawrap_data_type, out_slab_cw);
717
774
 
775
+ piece = ca_slab_piece(st);
718
776
  while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) &&
719
777
  ca_iter_state_next_slab_axes(st->t1_out, &p_out, &m_out) ) {
720
778
  VALUE result;
@@ -732,7 +790,7 @@ ca_slab_run_map (ca_slab_iter_state_t *st)
732
790
  ? st->own_out_scratch : p_out;
733
791
  out_slab_cw->ptr = write_target;
734
792
 
735
- result = rb_yield(st->slab_view);
793
+ result = rb_yield(piece);
736
794
 
737
795
  /* Strict shape check. */
738
796
  if ( rb_obj_is_kind_of(result, rb_cCArray) ) {
@@ -827,7 +885,6 @@ ca_slab_reduce_setup (ca_slab_iter_state_t *st, CArray **out_src,
827
885
  ca_size_t *out_n)
828
886
  {
829
887
  CArray *src;
830
- CArray *out;
831
888
  ca_size_t fiber_len;
832
889
  ca_size_t out_dim[CA_RANK_MAX];
833
890
  int8_t out_ndim;
@@ -870,7 +927,6 @@ ca_slab_reduce_setup (ca_slab_iter_state_t *st, CArray **out_src,
870
927
 
871
928
  st->output = rb_carray_new(st->out_data_type, out_ndim, out_dim,
872
929
  st->out_bytes, NULL);
873
- TypedData_Get_Struct(st->output, CArray, &carray_data_type, out);
874
930
 
875
931
  /* FIBER_CONTIG is naxes==1 only (T1 substrate contract). Multi-axis
876
932
  omits the flag and uses bare CA_SLAB_AXES; T1 picks an in-src
@@ -898,10 +954,36 @@ ca_slab_reduce_setup (ca_slab_iter_state_t *st, CArray **out_src,
898
954
  /* Per-slab block form: block receives the slab CArray, returns a
899
955
  scalar; each scalar is cast into the corresponding output cell.
900
956
  (`init:` absent ⇒ this path) */
957
+ /* Write one reduced value into the reduction output. UNDEF from the
958
+ block masks the cell, as storing UNDEF into an array does; obj2ptr
959
+ would read it as 0. */
960
+ static void
961
+ ca_slab_store_reduced (ca_slab_iter_state_t *st, CArray *out,
962
+ ca_size_t out_idx, VALUE value, char *scratch)
963
+ {
964
+ char *dst = out->ptr + out_idx * st->out_bytes;
965
+ if ( value == CA_UNDEF ) {
966
+ if ( out->mask == NULL ) {
967
+ ca_create_mask(out);
968
+ }
969
+ ((boolean8_t *) out->mask->ptr)[out_idx] = 1;
970
+ if ( out->data_type == CA_OBJECT ) {
971
+ *(VALUE *) dst = INT2FIX(0);
972
+ }
973
+ else {
974
+ memset(dst, 0, st->out_bytes);
975
+ }
976
+ return;
977
+ }
978
+ rb_ca_obj2ptr(st->output, value, scratch);
979
+ memcpy(dst, scratch, st->out_bytes);
980
+ }
981
+
901
982
  static VALUE
902
983
  ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
903
984
  {
904
985
  CArray *src;
986
+ volatile VALUE piece;
905
987
  CArray *out;
906
988
  ca_size_t fiber_len;
907
989
  char *p_in;
@@ -927,13 +1009,14 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
927
1009
  scratch = (st->out_bytes <= (ca_size_t) sizeof(buf))
928
1010
  ? buf : ALLOCV_N(char, scratch_holder, st->out_bytes);
929
1011
 
1012
+ piece = ca_slab_piece(st);
930
1013
  while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
931
1014
  VALUE result;
932
1015
 
933
1016
  ca_slab_advance_slab_view(st, slab_cs, carrier_cw,
934
1017
  src, p_in, m_in, in_alias);
935
1018
 
936
- result = rb_yield(st->slab_view);
1019
+ result = rb_yield(piece);
937
1020
 
938
1021
  /* Strict scalar contract: block must return a scalar Ruby value
939
1022
  (Numeric / Object / etc.). A CArray is a
@@ -952,8 +1035,7 @@ ca_slab_run_reduce_slab (ca_slab_iter_state_t *st)
952
1035
  res->elements == 1 ? "" : "s");
953
1036
  }
954
1037
 
955
- rb_ca_obj2ptr(st->output, result, scratch);
956
- memcpy(out->ptr + out_idx * st->out_bytes, scratch, st->out_bytes);
1038
+ ca_slab_store_reduced(st, out, out_idx, result, scratch);
957
1039
  out_idx++;
958
1040
  }
959
1041
 
@@ -968,6 +1050,7 @@ static VALUE
968
1050
  ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
969
1051
  {
970
1052
  CArray *src;
1053
+ volatile VALUE piece;
971
1054
  CArray *out;
972
1055
  ca_size_t fiber_len;
973
1056
  char *p_in;
@@ -993,6 +1076,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
993
1076
  scratch = (st->out_bytes <= (ca_size_t) sizeof(buf))
994
1077
  ? buf : ALLOCV_N(char, scratch_holder, st->out_bytes);
995
1078
 
1079
+ piece = ca_slab_piece(st);
996
1080
  while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
997
1081
  VALUE acc;
998
1082
  ca_size_t i;
@@ -1010,7 +1094,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
1010
1094
  ca_size_t total = st->t1->slab_elements;
1011
1095
  for ( i = 0; i < total; i++ ) {
1012
1096
  VALUE x;
1013
- x = rb_ca_fetch_index(st->slab_view, kidx);
1097
+ x = rb_ca_fetch_index(piece, kidx);
1014
1098
  acc = rb_yield_values(2, acc, x);
1015
1099
  /* Increment kidx[] row-major. */
1016
1100
  for ( k = slab_cs->ndim - 1; k >= 0; k-- ) {
@@ -1021,8 +1105,7 @@ ca_slab_run_reduce_fiber (ca_slab_iter_state_t *st)
1021
1105
  (void) fiber_len;
1022
1106
  }
1023
1107
 
1024
- rb_ca_obj2ptr(st->output, acc, scratch);
1025
- memcpy(out->ptr + out_idx * st->out_bytes, scratch, st->out_bytes);
1108
+ ca_slab_store_reduced(st, out, out_idx, acc, scratch);
1026
1109
  out_idx++;
1027
1110
  }
1028
1111
 
@@ -1049,6 +1132,7 @@ static VALUE
1049
1132
  ca_slab_run_each (ca_slab_iter_state_t *st)
1050
1133
  {
1051
1134
  CArray *src;
1135
+ volatile VALUE piece;
1052
1136
  char *p_in;
1053
1137
  boolean8_t *m_in;
1054
1138
  CAStride *slab_cs;
@@ -1082,10 +1166,11 @@ ca_slab_run_each (ca_slab_iter_state_t *st)
1082
1166
  TypedData_Get_Struct(st->carrier, CAWrap, &cawrap_data_type, carrier_cw);
1083
1167
  }
1084
1168
 
1169
+ piece = ca_slab_piece(st);
1085
1170
  while ( ca_iter_state_next_slab_axes(st->t1, &p_in, &m_in) ) {
1086
1171
  ca_slab_advance_slab_view(st, slab_cs, carrier_cw,
1087
1172
  src, p_in, m_in, in_alias);
1088
- rb_yield(st->slab_view); /* return value discarded */
1173
+ rb_yield(piece); /* return value discarded */
1089
1174
  }
1090
1175
 
1091
1176
  return st->self;
@@ -1115,8 +1200,9 @@ slab_state_run_body (VALUE arg)
1115
1200
  as it has a ptr. Before the scratch they point into is freed, the
1116
1201
  input slab and its carrier are moved onto a copy of the last slab,
1117
1202
  held by the carrier, and the internal output view lets go of its
1118
- buffer. A slab that is a window onto the source itself points into
1119
- the source and needs nothing. */
1203
+ buffer. The copy is made into the array ca_slab_prepare_backing set
1204
+ aside, so nothing here allocates. A slab that is a window onto the
1205
+ source itself points into the source and needs nothing. */
1120
1206
  static void
1121
1207
  slab_state_release_views (ca_slab_iter_state_t *st)
1122
1208
  {
@@ -1133,12 +1219,12 @@ slab_state_release_views (ca_slab_iter_state_t *st)
1133
1219
  if ( cw->ptr == NULL ) {
1134
1220
  return;
1135
1221
  }
1136
- backing = ca_copy(cw);
1137
- bv = ca_wrap_struct(backing);
1138
- if ( cw->mask && ! backing->mask ) {
1139
- ca_create_mask(backing);
1222
+ bv = rb_ivar_get(st->carrier, rb_intern("__slab_backing__"));
1223
+ TypedData_Get_Struct(bv, CArray, &carray_data_type, backing);
1224
+ memcpy(backing->ptr, cw->ptr, (size_t) (cw->elements * cw->bytes));
1225
+ if ( cw->mask && cw->mask->ptr ) {
1226
+ memcpy(backing->mask->ptr, cw->mask->ptr, (size_t) cw->elements);
1140
1227
  }
1141
- rb_ivar_set(st->carrier, rb_intern("__slab_backing__"), bv);
1142
1228
  if ( cs->ptr ) {
1143
1229
  cs->ptr = backing->ptr;
1144
1230
  }