carray 3.0.1 → 3.0.3

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
@@ -12,12 +12,13 @@
12
12
  - single INDIRECT axis (boolean), other axes AP (nil/Integer/Range)
13
13
  - parent must be an entity CArray (no CAStride parent)
14
14
  - selector copied at construction (fully static, fragility-free)
15
- - selector must not have a mask (hard reject)
15
+ - a masked selector cell selects nothing (same rule as CASelect)
16
16
  - slab copy uses straightforward nested-loop memcpy (no SIMD fast paths)
17
17
 
18
18
  ---------------------------------------------------------------------------- */
19
19
 
20
20
  #include "carray.h"
21
+ #include "carray_internal.h" /* ca_select_snapshot */
21
22
 
22
23
  typedef struct {
23
24
  /* CAView prefix (mirrors carray.h ca_virtual layout) */
@@ -112,9 +113,11 @@ static int8_t CA_OBJ_SELECT_AXIS;
112
113
 
113
114
  /* Benchmark-only bypass flag: when non-zero, rb_ca_grid skips the
114
115
  CASelectAxis dispatch hook and falls through to the pre-CSA CAGrid path.
115
- Exposed to Ruby as CArray._csa_bypass=. Production code never touches it. */
116
+ Exposed to Ruby as CArray._csa_bypass= in development builds.
117
+ Production code never touches it. */
116
118
  int ca_csa_dispatch_bypass = 0;
117
119
 
120
+ #ifdef CARRAY_DEV_BUILD
118
121
  static VALUE
119
122
  rb_ca_s_csa_bypass_eq (VALUE klass, VALUE val)
120
123
  {
@@ -129,6 +132,7 @@ rb_ca_s_csa_bypass_p (VALUE klass)
129
132
  (void) klass;
130
133
  return ca_csa_dispatch_bypass ? Qtrue : Qfalse;
131
134
  }
135
+ #endif
132
136
 
133
137
  static VALUE rb_cCASelectAxis;
134
138
  static VALUE rb_cCASelectAxisMask;
@@ -175,22 +179,18 @@ ca_select_axis_setup (CASelectAxis *ca, CArray *parent, int8_t indirect_axis,
175
179
  (int) indirect_axis,
176
180
  (long long) parent->dim[indirect_axis]);
177
181
  }
178
- if ( ca_has_mask(selector) ) {
179
- rb_raise(rb_eArgError,
180
- "CASelectAxis: selector boolean array must not have a mask. "
181
- "Use `selector.strip_mask(false)` etc. to flatten first.");
182
- }
183
-
184
182
  /* Validate AP axes */
185
183
  for ( k = 0; k < ndim; k++ ) {
186
184
  if ( k == indirect_axis ) continue;
187
185
  if ( ap_step[k] == 0 ) {
188
186
  rb_raise(rb_eArgError, "CASelectAxis: ap_step[%d] is 0", (int) k);
189
187
  }
190
- if ( ap_count[k] <= 0 ) {
191
- rb_raise(rb_eArgError, "CASelectAxis: ap_count[%d] must be positive", (int) k);
188
+ if ( ap_count[k] < 0 ) {
189
+ rb_raise(rb_eArgError, "CASelectAxis: ap_count[%d] is negative", (int) k);
192
190
  }
193
- {
191
+ /* A zero count (an axis of length zero) selects no cells: the view is
192
+ empty and there is no first or last index to check. */
193
+ if ( ap_count[k] > 0 ) {
194
194
  ca_size_t start_v = ap_start[k];
195
195
  ca_size_t last_v = ap_start[k] + (ap_count[k] - 1) * ap_step[k];
196
196
  if ( start_v < 0 || start_v >= parent->dim[k] ) {
@@ -222,8 +222,9 @@ ca_select_axis_setup (CASelectAxis *ca, CArray *parent, int8_t indirect_axis,
222
222
 
223
223
  /* Copy selector (view owns its own copy; immune to external mutation).
224
224
  The selector is small (1 axis length), so the copy cost is acceptable,
225
- and it avoids the fragility CASelect has from live references. */
226
- ca->selector = ca_copy(selector);
225
+ and it avoids the fragility CASelect has from live references. A
226
+ masked selector cell selects nothing, as it does for CASelect. */
227
+ ca->selector = ca_select_snapshot(selector);
227
228
 
228
229
  /* Allocate dim and AP arrays (pool path: already wired by pool_init). */
229
230
  if ( ! ca->_pool ) {
@@ -548,6 +549,7 @@ static void
548
549
  ca_select_axis_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
549
550
  ca_size_t *strides, void *data, int dir)
550
551
  {
552
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
551
553
  CASelectAxis *ca = (CASelectAxis *) ap;
552
554
  CArray *parent = ca->parent;
553
555
  int8_t ndim = ca->ndim;
@@ -710,25 +712,34 @@ ca_select_axis_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
710
712
  }
711
713
  }
712
714
 
715
+ /* A parent with no memory to lend (ca_parent_lends_no_memory) is never
716
+ attached: the view owns its buffer, filled and drained through xfer_all,
717
+ which asks the parent for the selected cells only. The predicate asks
718
+ what the parent is, not whether it is attached now, so attach, sync and
719
+ detach all take the same branch. */
720
+
713
721
  static void
714
722
  ca_select_axis_func_allocate (void *ap)
715
723
  {
716
724
  CASelectAxis *ca = (CASelectAxis *) ap;
717
- ca_attach(ca->parent);
725
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
726
+ ca_attach(ca->parent);
727
+ }
718
728
  ca->ptr = xmalloc(ca_length(ca));
719
729
  }
720
730
 
721
- /* attach / sync / copy_data / sync_data / fill_data all go through the
722
- common descriptor engine. This file holds only describe_axes for
723
- translating CSA state into the shared descriptor; the engine in
724
- ext/ca_axis_dispatch.c does the rest. */
725
-
726
731
  static void
727
732
  ca_select_axis_func_attach (void *ap)
728
733
  {
729
734
  CASelectAxis *ca = (CASelectAxis *) ap;
730
735
  ca_axis_desc_t desc[CA_RANK_MAX];
731
736
  ca_size_t pdims[CA_RANK_MAX];
737
+
738
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
739
+ ca_axis_view_attach_owned(ca);
740
+ return;
741
+ }
742
+
732
743
  ca_attach(ca->parent);
733
744
  ca_select_axis_describe_axes(ca, desc, pdims);
734
745
  ca->ptr = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim,
@@ -741,6 +752,12 @@ ca_select_axis_func_sync (void *ap)
741
752
  CASelectAxis *ca = (CASelectAxis *) ap;
742
753
  ca_axis_desc_t desc[CA_RANK_MAX];
743
754
  ca_size_t pdims[CA_RANK_MAX];
755
+
756
+ if ( ca_parent_lends_no_memory(ca->parent) ) {
757
+ ca_axis_view_sync_owned(ca);
758
+ return;
759
+ }
760
+
744
761
  ca_select_axis_describe_axes(ca, desc, pdims);
745
762
  ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
746
763
  ca->elements, ca->ptr);
@@ -756,16 +773,16 @@ ca_select_axis_func_detach (void *ap)
756
773
  ca->ptr = NULL;
757
774
  }
758
775
  /* indices[] lives for the view's lifetime; freed in free_ca_select_axis. */
759
- ca_detach(ca->parent);
776
+ if ( ! ca_parent_lends_no_memory(ca->parent) ) {
777
+ ca_detach(ca->parent);
778
+ }
760
779
  }
761
780
 
762
- /* xfer_all: fast path on parent->ptr, with no silent transitive attach
763
- of the parent. A cold parent uses a proper 2-pass (materialise the
764
- parent into scratch, expose it as parent->ptr, run the fast path, then
765
- write scratch back for PUT). */
781
+ /* The transfer against parent->ptr, for ca_axis_view_xfer_all. */
766
782
  static void
767
- ca_select_axis_func_run_fast_path (CASelectAxis *ca, char *data, int dir)
783
+ ca_select_axis_func_run_fast_path (void *ap, char *data, int dir)
768
784
  {
785
+ CASelectAxis *ca = (CASelectAxis *) ap;
769
786
  ca_axis_desc_t desc[CA_RANK_MAX];
770
787
  ca_size_t pdims[CA_RANK_MAX];
771
788
  ca_select_axis_describe_axes(ca, desc, pdims);
@@ -781,27 +798,7 @@ ca_select_axis_func_run_fast_path (CASelectAxis *ca, char *data, int dir)
781
798
  static void
782
799
  ca_select_axis_func_xfer_all (void *ap, void *data, int dir)
783
800
  {
784
- CASelectAxis *ca = (CASelectAxis *) ap;
785
- if ( ca->parent->ptr ) {
786
- ca_select_axis_func_run_fast_path(ca, (char *) data, dir);
787
- return;
788
- }
789
- /* Proper 2-pass cold fallback. */
790
- {
791
- volatile VALUE holder;
792
- CArray *parent = ca->parent;
793
- ca_size_t plen = parent->elements * parent->bytes;
794
- char *parent_scratch = ALLOCV_N(char, holder, plen);
795
- char *parent_ptr_saved = parent->ptr;
796
- ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
797
- parent->ptr = parent_scratch;
798
- ca_select_axis_func_run_fast_path(ca, (char *) data, dir);
799
- if ( dir == CA_XFER_PUT ) {
800
- ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
801
- }
802
- parent->ptr = parent_ptr_saved;
803
- ALLOCV_END(holder);
804
- }
801
+ ca_axis_view_xfer_all(ap, ca_select_axis_func_run_fast_path, 1, data, dir);
805
802
  }
806
803
 
807
804
  static void
@@ -824,21 +821,17 @@ ca_select_axis_func_fill_data (void *ap, void *val)
824
821
  return;
825
822
  }
826
823
 
827
- ca_attach(ca->parent);
824
+ ca_attach(ca->parent); /* window: nothing raises inside */
828
825
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
829
826
  ca->elements, val);
830
- ca_sync(ca->parent);
831
- ca_detach(ca->parent);
827
+ ca_sync_detach(ca->parent);
832
828
  }
833
829
 
834
830
  static void
835
831
  ca_select_axis_func_create_mask (void *ap)
836
832
  {
837
833
  CASelectAxis *ca = (CASelectAxis *) ap;
838
- ca_update_mask(ca->parent);
839
- if ( ! ca->parent->mask ) {
840
- ca_create_mask(ca->parent);
841
- }
834
+ ca_create_mask(ca->parent);
842
835
  ca->mask = ca_select_axis_new(ca->parent->mask, ca->indirect_axis,
843
836
  ca->selector,
844
837
  ca->ap_start, ca->ap_count, ca->ap_step);
@@ -878,6 +871,7 @@ rb_ca_select_axis_initialize_copy (VALUE self, VALUE other)
878
871
  {
879
872
  CASelectAxis *ca, *cs;
880
873
  TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
874
+ ca_check_uninitialized(ca);
881
875
  TypedData_Get_Struct(other, CASelectAxis, &caselectaxis_data_type, cs);
882
876
  if ( ca_func[CA_OBJ_SELECT_AXIS].pool_init ) {
883
877
  ca_array_pool_alloc(ca, CA_OBJ_SELECT_AXIS, cs->parent->ndim);
@@ -887,6 +881,7 @@ rb_ca_select_axis_initialize_copy (VALUE self, VALUE other)
887
881
  return self;
888
882
  }
889
883
 
884
+ #ifdef CARRAY_DEV_BUILD
890
885
  /* Debug-only Ruby ctor:
891
886
  CASelectAxis._new_debug(parent, indirect_axis, selector,
892
887
  ap_start_arr, ap_count_arr, ap_step_arr)
@@ -937,6 +932,7 @@ rb_ca_select_axis_s_new_debug (VALUE klass, VALUE rparent, VALUE rindirect,
937
932
  rb_ivar_set(obj, rb_intern("_selector"), rselector);
938
933
  return obj;
939
934
  }
935
+ #endif
940
936
 
941
937
  /* ------------------------------------------------------------------- */
942
938
  /* Indexer dispatch hook: called from rb_ca_grid */
@@ -1188,7 +1184,7 @@ rb_ca_select_axis_dispatch_attach_debug (VALUE self)
1188
1184
  TypedData_Get_Struct(self, CASelectAxis, &caselectaxis_data_type, ca);
1189
1185
  ca_select_axis_describe_axes(ca, desc, pdims);
1190
1186
 
1191
- ca_attach(ca->parent);
1187
+ ca_attach(ca->parent); /* window: nothing raises inside */
1192
1188
  buf = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1193
1189
  ca->elements, NULL);
1194
1190
  ca_detach(ca->parent);
@@ -1222,11 +1218,10 @@ rb_ca_select_axis_dispatch_scatter_debug (VALUE self, VALUE in_str)
1222
1218
  ca_size_t pdims[CA_RANK_MAX];
1223
1219
  ca_select_axis_describe_axes(ca, desc, pdims);
1224
1220
 
1225
- ca_attach(ca->parent);
1221
+ ca_attach(ca->parent); /* window: nothing raises inside */
1226
1222
  ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1227
1223
  ca->elements, RSTRING_PTR(in_str));
1228
- ca_sync(ca->parent);
1229
- ca_detach(ca->parent);
1224
+ ca_sync_detach(ca->parent);
1230
1225
  return Qnil;
1231
1226
  }
1232
1227
 
@@ -1250,11 +1245,10 @@ rb_ca_select_axis_dispatch_fill_value_debug (VALUE self, VALUE val_str)
1250
1245
  ca_size_t pdims[CA_RANK_MAX];
1251
1246
  ca_select_axis_describe_axes(ca, desc, pdims);
1252
1247
 
1253
- ca_attach(ca->parent);
1248
+ ca_attach(ca->parent); /* window: nothing raises inside */
1254
1249
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1255
1250
  ca->elements, RSTRING_PTR(val_str));
1256
- ca_sync(ca->parent);
1257
- ca_detach(ca->parent);
1251
+ ca_sync_detach(ca->parent);
1258
1252
  return Qnil;
1259
1253
  }
1260
1254
  #endif /* CARRAY_DEV_BUILD */
@@ -1281,9 +1275,11 @@ Init_ca_obj_select_axis (void)
1281
1275
  rb_define_alloc_func(rb_cCASelectAxis, rb_ca_select_axis_s_allocate);
1282
1276
  rb_define_method(rb_cCASelectAxis, "initialize_copy",
1283
1277
  rb_ca_select_axis_initialize_copy, 1);
1278
+ #ifdef CARRAY_DEV_BUILD
1284
1279
  /* Debug-only ctor for testing; not part of the public API. */
1285
1280
  rb_define_singleton_method(rb_cCASelectAxis, "_new_debug",
1286
1281
  rb_ca_select_axis_s_new_debug, 6);
1282
+ #endif
1287
1283
 
1288
1284
  #ifdef CARRAY_DEV_BUILD
1289
1285
  /* debug accessors (dev-only, stripped in release).
@@ -1300,7 +1296,9 @@ Init_ca_obj_select_axis (void)
1300
1296
  rb_ca_select_axis_dispatch_fill_value_debug, 1);
1301
1297
  #endif
1302
1298
 
1299
+ #ifdef CARRAY_DEV_BUILD
1303
1300
  /* Benchmark-only bypass setter on CArray class. */
1304
1301
  rb_define_singleton_method(rb_cCArray, "_csa_bypass=", rb_ca_s_csa_bypass_eq, 1);
1305
1302
  rb_define_singleton_method(rb_cCArray, "_csa_bypass?", rb_ca_s_csa_bypass_p, 0);
1303
+ #endif
1306
1304
  }
data/ext/ca_obj_shift.c CHANGED
@@ -8,8 +8,8 @@
8
8
  sync_data / fill_data / ptr_at_* / fetch_index / store_index) are
9
9
  shared with CAWindow's per-axis bounds engine via the `ca_shift_func`
10
10
  table, which is built by copying `ca_window_func` and only overriding
11
- free / clone / create_mask so that CAShift-typed instances are produced
12
- on cloning and mask-projection.
11
+ clone, so that cloning produces a CAShift. create_mask is shared: it
12
+ gives the mask the view's own obj_type.
13
13
 
14
14
  User surface (CArray#shift) is documented in yard-stubs/ca_obj_shift.rb.
15
15
 
@@ -31,11 +31,13 @@ extern int ca_window_setup (CAWindow *ca, CArray *parent,
31
31
  (rb_data_type_t *) cast would write into .rodata and SIGBUS on macOS. */
32
32
  static size_t ca_shift_dsize (const void *ap);
33
33
 
34
+ extern void ca_window_mark (void *ap); /* ca_obj_window.c: marks the fill value */
35
+
34
36
  const rb_data_type_t cashift_data_type = {
35
- .parent = &caview_data_type,
37
+ .parent = &cawindow_data_type,
36
38
  .wrap_struct_name = "CAShift",
37
39
  .function = {
38
- .dmark = ca_mark,
40
+ .dmark = ca_window_mark,
39
41
  .dfree = ca_free,
40
42
  .dsize = ca_shift_dsize,
41
43
  .dcompact = NULL
@@ -44,7 +46,7 @@ const rb_data_type_t cashift_data_type = {
44
46
  };
45
47
 
46
48
  /* CAREFUL: mask TypedData uses ca_free_nop. The mask CArray is owned
47
- by the parent CAShift's `ca->mask` field and freed by free_ca_shift's
49
+ by the parent CAShift's `ca->mask` field and freed by the shared window free's
48
50
  ca_free(ca->mask). If the wrapped Ruby VALUE (from the `ca.mask`
49
51
  accessor / rb_ca_mask_array) also freed it, the result is a
50
52
  double-free that explodes under GC stress. */
@@ -105,10 +107,13 @@ ca_shift_setup (CAShift *ca, CArray *parent,
105
107
  /* Delegate to CAWindow setup. */
106
108
  ca_window_setup((CAWindow *) ca, parent, start, count, bounds, fill);
107
109
 
110
+ if ( ca == NULL ) { /* checks only, see ca_window_setup */
111
+ return 0;
112
+ }
113
+
108
114
  /* Override obj_type so dispatch (ca_func[obj_type]) lands on the
109
115
  CAShift-specific table (which differs from CAWindow only in
110
- free / clone / create_mask, all forwarding to a CAShift-typed
111
- result). */
116
+ clone). */
112
117
  ca->obj_type = CA_OBJ_SHIFT;
113
118
 
114
119
  return 0;
@@ -118,37 +123,13 @@ CAShift *
118
123
  ca_shift_new (CArray *parent, ca_size_t *shift, char *fill, int8_t *roll,
119
124
  int fill_mask)
120
125
  {
121
- CAShift *ca = (CAShift *) ca_array_alloc(CA_OBJ_SHIFT, parent->ndim);
126
+ CAShift *ca;
127
+ ca_shift_setup(NULL, parent, shift, fill, roll, fill_mask);
128
+ ca = (CAShift *) ca_array_alloc(CA_OBJ_SHIFT, parent->ndim);
122
129
  ca_shift_setup(ca, parent, shift, fill, roll, fill_mask);
123
130
  return ca;
124
131
  }
125
132
 
126
- /* Free: same fields as CAWindow (same struct). CAShift goes through
127
- ca_window_setup, so the same seven ndim-sized fields live in ca->_pool
128
- (fill stays separate). */
129
- static void
130
- free_ca_shift (void *ap)
131
- {
132
- CAShift *ca = (CAShift *) ap;
133
- if ( ca != NULL ) {
134
- ca_free(ca->mask);
135
- xfree(ca->fill); /* always separate (bytes-sized) */
136
- if ( ca->_pool ) {
137
- ca_array_free(ca);
138
- }
139
- else {
140
- xfree(ca->bounds);
141
- xfree(ca->start);
142
- xfree(ca->count);
143
- xfree(ca->size0);
144
- xfree(ca->embed_parent_start);
145
- xfree(ca->embed_count);
146
- xfree(ca->embed_output_offset);
147
- xfree(ca);
148
- }
149
- }
150
- }
151
-
152
133
  /* Clone: produce a CAShift (not CAWindow) by rebuilding via setup.
153
134
  Recover (shift[], roll[], fill_mask) from current (start[], bounds[]). */
154
135
  static void *
@@ -174,69 +155,6 @@ ca_shift_func_clone (void *ap)
174
155
  return ca_shift_new(ca->parent, shift, ca->fill, roll, fill_mask);
175
156
  }
176
157
 
177
- /* create_mask: produce a CAShift-typed mask (not CAWindow-typed).
178
- Following the original ca_shift_func_create_mask semantics:
179
- - Ensure parent has mask
180
- - Build mask sub-view using same shift/roll, fill = 1 if fill_mask
181
- else 0 (i.e. range-outside cells get masked when fill_mask was on,
182
- unmasked otherwise) */
183
- static void
184
- ca_shift_func_create_mask (void *ap)
185
- {
186
- CAShift *ca = (CAShift *) ap;
187
- ca_size_t shift[CA_RANK_MAX];
188
- int8_t roll[CA_RANK_MAX];
189
- boolean8_t fill_val;
190
- int fill_mask_was_on = 0;
191
- int8_t k;
192
-
193
- ca_update_mask(ca->parent);
194
- if ( ! ca->parent->mask ) {
195
- ca_create_mask(ca->parent);
196
- }
197
-
198
- for (k = 0; k < ca->ndim; k++) {
199
- shift[k] = -ca->start[k];
200
- if ( ca->bounds[k] == CA_BOUNDS_PERIODIC ) {
201
- roll[k] = 1;
202
- } else {
203
- roll[k] = 0;
204
- if ( ca->bounds[k] == CA_BOUNDS_MASK ) fill_mask_was_on = 1;
205
- }
206
- }
207
-
208
- /* If MASK policy was set, the mask sub-view should mark out-of-range
209
- cells as "masked" (fill value = 1). Otherwise out-of-range cells
210
- get the fill value (fill = 0) and aren't masked. */
211
- fill_val = fill_mask_was_on ? 1 : 0;
212
-
213
- /* Build the mask as CAShift with same shift/roll but using fill_mask=0
214
- (the mask itself shouldn't recursively create a mask) and fill = 0/1
215
- boolean. Bounds for mask: replace MASK→FILL so the mask values are
216
- written, not the mask's mask. */
217
- {
218
- /* Construct mask via direct ca_window_new with adjusted bounds. */
219
- uint8_t mbounds[CA_RANK_MAX];
220
- ca_size_t mstart[CA_RANK_MAX];
221
- ca_size_t mcount[CA_RANK_MAX];
222
- CAShift *m;
223
- CA_ASSUME(ca->ndim >= 0 && ca->ndim <= CA_RANK_MAX); /* bound loop over [CA_RANK_MAX] arrays */
224
- for (k = 0; k < ca->ndim; k++) {
225
- mstart[k] = ca->start[k];
226
- mcount[k] = ca->count[k];
227
- mbounds[k] = ( ca->bounds[k] == CA_BOUNDS_MASK )
228
- ? CA_BOUNDS_FILL : ca->bounds[k];
229
- }
230
- /* CAShift-typed mask: allocate, setup as CAWindow with adjusted
231
- bounds, bump obj_type. */
232
- m = (CAShift *) ca_array_alloc(CA_OBJ_SHIFT, ca->ndim);
233
- ca_window_setup((CAWindow *) m, ca->parent->mask,
234
- mstart, mcount, mbounds, (char *) &fill_val);
235
- m->obj_type = CA_OBJ_SHIFT;
236
- ca->mask = (CArray *) m;
237
- }
238
- (void) shift; (void) roll; /* recovered above but unused in this block */
239
- }
240
158
 
241
159
  /* ------------------------------------------------------------------- */
242
160
 
@@ -319,9 +237,12 @@ rb_ca_shift (int argc, VALUE *argv, VALUE self)
319
237
  fill_mask = 1;
320
238
  }
321
239
  else {
322
- rcs = rb_cscalar_new_with_value(ca->data_type, ca->bytes, rfval);
240
+ /* The fill is a value of the array (a struct, an instant for a Face):
241
+ rb_ca_obj2ptr writes it as one cell of the storage. */
242
+ rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
323
243
  TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cs);
324
244
  fill = cs->ptr;
245
+ rb_ca_obj2ptr(self, rfval, fill);
325
246
  }
326
247
 
327
248
  if ( NIL_P(rroll) ) {
@@ -366,6 +287,7 @@ rb_ca_shift_initialize_copy (VALUE self, VALUE other)
366
287
  int8_t k;
367
288
 
368
289
  TypedData_Get_Struct(self, CAShift, &cashift_data_type, ca);
290
+ ca_check_uninitialized(ca);
369
291
  TypedData_Get_Struct(other, CAShift, &cashift_data_type, cs);
370
292
 
371
293
  /* Recover shift/roll/fill_mask from cs (same scheme as clone). */
@@ -395,12 +317,10 @@ rb_ca_shift_initialize_copy (VALUE self, VALUE other)
395
317
  void
396
318
  Init_ca_obj_shift (void)
397
319
  {
398
- /* Build the CAShift op table by copying CAWindow's and overriding
399
- just the slots that need to produce CAShift-typed results. */
320
+ /* Build the CAShift op table by copying CAWindow's; only clone has to
321
+ rebuild a CAShift. */
400
322
  ca_shift_func = ca_window_func;
401
- ca_shift_func.free_object = free_ca_shift;
402
323
  ca_shift_func.clone = ca_shift_func_clone;
403
- ca_shift_func.create_mask = ca_shift_func_create_mask;
404
324
 
405
325
  rb_cCAShift = rb_define_class("CAShift", rb_cCAWindow);
406
326
  rb_cCAShiftMask = rb_define_class("CAShiftMask", rb_cCAShift);