carray 3.0.2 → 3.0.4

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
data/ext/ca_axis_group.c CHANGED
@@ -33,6 +33,7 @@
33
33
  --------------------------------------------------------------------------- */
34
34
 
35
35
  #include "carray.h"
36
+ #include "carray_internal.h" /* CA_EXTREMUM_REPLACES, ca_obj_extremum_replaces */
36
37
  #include "ca_kernel_iterator.h"
37
38
  #include <math.h>
38
39
 
@@ -64,8 +65,8 @@ group_op_code (VALUE vop)
64
65
  else if ( id == rb_intern("max_addr") ) return GR_MAXADDR;
65
66
  else if ( id == rb_intern("all") ) return GR_ALL;
66
67
  else if ( id == rb_intern("any") ) return GR_ANY;
67
- rb_raise(rb_eArgError, "axis_group_reduce: unsupported op :%s",
68
- rb_id2name(id));
68
+ rb_raise(rb_eArgError, "axis_group_reduce: unsupported op :%"PRIsVALUE,
69
+ rb_id2str(id));
69
70
  }
70
71
 
71
72
  /* ---- per-slab-element composite-code walk, templated on the load type ----
@@ -206,16 +207,16 @@ group_op_code (VALUE vop)
206
207
  only while nothing else has landed, the first number displaces it, and a
207
208
  group of nothing but NaN answers NaN (for a position, UNDEF). `v` is the
208
209
  widened load, so testing it for NaN is the same question for every source
209
- type and costs an integer body nothing. seen_num[] says whether a number
210
- has landed; cnt[] still says whether anything has. */
210
+ type and costs an integer body nothing. The replacement test is the
211
+ shared CA_EXTREMUM_REPLACES; the first member is taken whatever it is.
212
+ seen_num[] says whether a number has landed (the positions read it);
213
+ cnt[] says whether anything has. */
211
214
  #define GMINMAX(T, A, CMP) \
212
215
  do { \
213
216
  A *acc = (A *) co->ptr; \
214
217
  A av = (A) rv; \
215
- if ( v == v ) { \
216
- if ( ! seen_num[o] ) { acc[o] = av; seen_num[o] = 1; } \
217
- else if ( av CMP acc[o] ) acc[o] = av; \
218
- } else if ( cnt[o] == 0 ) acc[o] = av; \
218
+ if ( cnt[o] == 0 || CA_EXTREMUM_REPLACES(av, acc[o], CMP) ) acc[o] = av; \
219
+ if ( v == v ) seen_num[o] = 1; \
219
220
  cnt[o] += 1; \
220
221
  } while (0)
221
222
 
@@ -282,7 +283,7 @@ group_op_code (VALUE vop)
282
283
  #define GACC_XOR \
283
284
  ( ((boolean8_t *) co->ptr)[o] ^= (*(boolean8_t *)(p + gw_doff[e]) ? 1 : 0) )
284
285
 
285
- /* __axis_group_reduce__(group_axes, bundles, op) — group-reduces self along
286
+ /* __reduce_by_axis_groups__(group_axes, bundles, op) — group-reduces self along
286
287
  * the union of `group_axes` (ascending source-axis indices = the slab) into
287
288
  * composite groups described by `bundles`, preserving the band (= non-grouped)
288
289
  * axes. Internal: the Ruby surface is CAGroupIterator.
@@ -310,7 +311,7 @@ group_op_code (VALUE vop)
310
311
  Empty / all-masked groups follow the CArray zero-contribution contract: an
311
312
  identity-bearing op returns its identity (sum 0, prod 1, count 0, all true,
312
313
  any false), a ratio / extremum returns UNDEF. Sample variance / stddev:
313
- n == 0 UNDEF, n == 1 -> 0.0, n >= 2 the formula.
314
+ n < 2 UNDEF, n >= 2 the formula.
314
315
  */
315
316
  static VALUE
316
317
  rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
@@ -321,7 +322,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
321
322
  GetCArray(self, src);
322
323
 
323
324
  if ( src->ndim <= 0 ) {
324
- rb_raise(rb_eRuntimeError, "axis_group_reduce: scalar source");
325
+ rb_raise(rb_eArgError, "axis_group_reduce: scalar source");
325
326
  }
326
327
 
327
328
  /* --- group (slab) axes --- */
@@ -351,7 +352,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
351
352
  /* --- bundles: small per-group code tables (metadata, kept alive) --- */
352
353
  Check_Type(vbundles, T_ARRAY);
353
354
  int n_bundles = (int) RARRAY_LEN(vbundles);
354
- if ( n_bundles <= 0 || n_bundles > CA_RANK_MAX ) {
355
+ if ( n_bundles <= 0 || n_bundles > CA_RANK_MAX ) { /* rank-check: a count of key bundles */
355
356
  rb_raise(rb_eArgError, "axis_group_reduce: bad bundle count %d", n_bundles);
356
357
  }
357
358
  int32_t *bundle_codes[CA_RANK_MAX];
@@ -361,7 +362,8 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
361
362
  int bundle_slot[CA_RANK_MAX][CA_RANK_MAX];
362
363
  ca_size_t bundle_cstride[CA_RANK_MAX][CA_RANK_MAX];
363
364
  CArray *bundle_ca[CA_RANK_MAX];
364
- volatile VALUE keep = rb_ary_new(); /* GC-pin int32 code views */
365
+ volatile VALUE keep = rb_ary_new(); /* keeps the int32 code views alive */
366
+ volatile VALUE h_codes[CA_RANK_MAX]; /* holders of the copied code tables */
365
367
 
366
368
  ca_size_t K_total = 1;
367
369
  long consumed_total = 0;
@@ -384,20 +386,16 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
384
386
  and the end of the walk can raise -- a validation just below, a gather
385
387
  that cannot convert a cell, an object-lane callback into Ruby -- and a
386
388
  raise jumps over every detach, leaving the source materialised with
387
- nothing left to release it. The copy rides a temporary buffer that the
388
- unwind collects. */
389
+ nothing left to release it. The copy rides ALLOCV, a temporary buffer
390
+ that the unwind collects. Not a String: a String held only by `keep`
391
+ can be moved by compaction, taking the bytes under bundle_codes with
392
+ it. */
389
393
  VALUE v32 = rb_ca_wrap_readonly(vcodes, INT2NUM(CA_INT32));
390
394
  rb_ary_push((VALUE) keep, v32);
391
395
  GetCArray(v32, bundle_ca[bi]);
392
- {
393
- size_t nbytes = (size_t) bundle_ca[bi]->elements * sizeof(int32_t);
394
- VALUE vbuf = rb_str_tmp_new((long) nbytes);
395
- rb_ary_push((VALUE) keep, vbuf);
396
- ca_attach(bundle_ca[bi]);
397
- memcpy(RSTRING_PTR(vbuf), bundle_ca[bi]->ptr, nbytes);
398
- ca_detach(bundle_ca[bi]);
399
- bundle_codes[bi] = (int32_t *) RSTRING_PTR(vbuf);
400
- }
396
+ h_codes[bi] = 0;
397
+ bundle_codes[bi] = ALLOCV_N(int32_t, h_codes[bi], bundle_ca[bi]->elements);
398
+ ca_copy_data(bundle_ca[bi], (char *) bundle_codes[bi]);
401
399
 
402
400
  int nb = (int) RARRAY_LEN(vbaxes);
403
401
  if ( nb <= 0 || nb > src->ndim ) {
@@ -477,9 +475,9 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
477
475
  case CA_INT32: case CA_UINT32: case CA_INT64: case CA_UINT64:
478
476
  case CA_FLOAT32: case CA_FLOAT64: break;
479
477
  default:
480
- rb_raise(rb_eRuntimeError,
481
- "axis_group_reduce: unsupported source data_type %d",
482
- src->data_type);
478
+ rb_raise(rb_eCADataTypeError,
479
+ "axis_group: %"PRIsVALUE" over a group is not supported for data type %s",
480
+ rb_sym2str(vop), ca_type_name[src->data_type]);
483
481
  }
484
482
 
485
483
  /* output data type per op */
@@ -618,8 +616,8 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
618
616
  /* Empty / all-masked groups follow the same zero-contribution contract as
619
617
  CArray reductions (ERI, matching the categorical sibling): an identity-
620
618
  bearing op returns its identity (sum 0, prod 1, count 0, all true, any
621
- false), a ratio / extremum returns UNDEF. Sample variance/stddev: n==0
622
- UNDEF, n==1 -> 0.0 (the n=1 contract), n>=2 the formula. */
619
+ false), a ratio / extremum returns UNDEF. Sample variance/stddev: n<2
620
+ UNDEF (n-1 is zero), n>=2 the formula. */
623
621
  if ( op == GR_COUNT ) {
624
622
  int64_t *out = (int64_t *) co->ptr;
625
623
  for ( ca_size_t o = 0; o < nout; o++ ) out[o] = (int64_t) cnt[o];
@@ -664,8 +662,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
664
662
  break;
665
663
  case GR_VARIANCE:
666
664
  case GR_STDDEV:
667
- if ( cnt[o] == 0 ) { out[o] = 0.0; MARK_UNDEF(o); }
668
- else if ( cnt[o] == 1 ) { out[o] = 0.0; } /* n=1 contract */
665
+ if ( cnt[o] < 2 ) { out[o] = 0.0; MARK_UNDEF(o); }
669
666
  else { double var = sumsq[o] / ( (double) cnt[o] - 1.0 );
670
667
  out[o] = ( op == GR_STDDEV ) ? sqrt(var) : var; }
671
668
  break;
@@ -684,6 +681,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
684
681
  ALLOCV_END(h_prod); ALLOCV_END(h_seen); ALLOCV_END(h_xbuf);
685
682
  ALLOCV_END(h_nz); ALLOCV_END(h_mnaddr); ALLOCV_END(h_mxaddr);
686
683
  ALLOCV_END(h_band);
684
+ for ( int bi = 0; bi < n_bundles; bi++ ) ALLOCV_END(h_codes[bi]);
687
685
 
688
686
  RB_GC_GUARD(keep);
689
687
  return vout;
@@ -854,7 +852,9 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
854
852
  emits its own value: a per-group `seen` byte initialises the accumulator
855
853
  lazily on first hit — no sentinel like HUGE_VAL, which an integer data type could
856
854
  not represent. CMP is > for max, < for min: a later member replaces the
857
- running extremum when `rv CMP acc`. A cell masked within its group holds the
855
+ running extremum when CA_EXTREMUM_REPLACES (a NaN never does, and a
856
+ number displaces a leading NaN, as the core cummax / cummin and the
857
+ reduce twins above do). A cell masked within its group holds the
858
858
  current extremum once a member has been seen (output NOT masked, like sum);
859
859
  before any member the extremum is undefined so the cell stays UNDEF (the
860
860
  CArray reduction contract: empty max/min has no value — deliberately NOT the
@@ -895,7 +895,9 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
895
895
  } \
896
896
  T rv = *(T *)(p + sw_doff[e]); \
897
897
  if ( ! seen[code] ) { acce[code] = rv; seen[code] = 1; } \
898
- else if ( rv CMP acce[code] ) { acce[code] = rv; } \
898
+ else if ( CA_EXTREMUM_REPLACES(rv, acce[code], CMP) ) { \
899
+ acce[code] = rv; \
900
+ } \
899
901
  outp[addr] = acce[code]; \
900
902
  } \
901
903
  } \
@@ -933,19 +935,19 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
933
935
  both unmasked (matching core object cumsum / cumprod); cummax / cummin hold
934
936
  the running VALUE only once a member has been seen and stay UNDEF before that
935
937
  (no identity for arbitrary objects). GW_SKIP (excluded) stays UNDEF. accn /
936
- seen are reset at each band; acco carries the running VALUE. */
938
+ seen are reset at each band; acco carries the running VALUE.
939
+ Expanded only in group_scan_object_body, whose walk state is c->st. */
937
940
  #define GROUP_SCAN_OBJECT_WALK(EMIT, HOLD) \
938
941
  do { \
939
- ca_iter_state st; \
940
942
  char *p; \
941
943
  boolean8_t *m; \
942
944
  ca_size_t b = 0; \
943
945
  int ready = 0; \
944
- CA_FOR_EACH_SLAB(st, ca, axes, (int8_t) ngroup, CA_KERNEL_READ, p, m) { \
945
- ca_size_t SE = st.slab_elements; \
946
+ CA_FOR_EACH_SLAB(c->st, ca, axes, (int8_t) ngroup, CA_KERNEL_READ, p, m) {\
947
+ ca_size_t SE = c->st.slab_elements; \
946
948
  if ( SE > 0 ) { \
947
949
  if ( ! ready ) { \
948
- group_scan_build_plan(&st, m, n_bundles, bundle_codes, bundle_k, \
950
+ group_scan_build_plan(&c->st, m, n_bundles, bundle_codes, bundle_k,\
949
951
  bundle_placeval, bundle_nconsumed, \
950
952
  bundle_slot, bundle_cstride, ngroup, \
951
953
  grstride, sw_code, sw_doff, sw_moff, sw_addr);\
@@ -970,6 +972,137 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
970
972
  } \
971
973
  } while (0)
972
974
 
975
+ /* Marks output cell o UNDEF, creating the output mask on first use. Used
976
+ by the scan walks, in functions that hold the output as `co` and the mask
977
+ pointer as `omask`. */
978
+ #define MARK_OUT_UNDEF(o) do { \
979
+ if ( ! omask ) { \
980
+ ca_create_mask(co); \
981
+ omask = (boolean8_t *) co->mask->ptr; \
982
+ } \
983
+ omask[o] = 1; \
984
+ } while (0)
985
+
986
+ /* The CA_OBJECT lane of __scan_by_axis_groups__. Every cell calls into Ruby,
987
+ so the walk can raise part way; its state lives in the caller's frame, in
988
+ c->st, and ca_iter_ensure finishes it however this body leaves. The
989
+ buffers are ALLOCV-backed, so the unwind collects them. */
990
+ typedef struct {
991
+ ca_iter_state st;
992
+ CArray *ca;
993
+ CArray *co;
994
+ int op;
995
+ int8_t *axes;
996
+ long ngroup;
997
+ int n_bundles;
998
+ int32_t **bundle_codes;
999
+ ca_size_t *bundle_k;
1000
+ ca_size_t *bundle_placeval;
1001
+ int *bundle_nconsumed;
1002
+ int (*bundle_slot)[CA_RANK_MAX];
1003
+ ca_size_t (*bundle_cstride)[CA_RANK_MAX];
1004
+ ca_size_t *grstride;
1005
+ ca_size_t *band_addr;
1006
+ ca_size_t K_total;
1007
+ ca_size_t *sw_code;
1008
+ ca_size_t *sw_doff;
1009
+ ca_size_t *sw_moff;
1010
+ ca_size_t *sw_addr;
1011
+ ca_size_t *accn;
1012
+ char *seen;
1013
+ VALUE *acco;
1014
+ } group_scan_object_t;
1015
+
1016
+ static VALUE
1017
+ group_scan_object_body (VALUE arg)
1018
+ {
1019
+ group_scan_object_t *c = (group_scan_object_t *) arg;
1020
+ CArray *ca = c->ca;
1021
+ CArray *co = c->co;
1022
+ int op = c->op;
1023
+ int8_t *axes = c->axes;
1024
+ long ngroup = c->ngroup;
1025
+ int n_bundles = c->n_bundles;
1026
+ int32_t **bundle_codes = c->bundle_codes;
1027
+ ca_size_t *bundle_k = c->bundle_k;
1028
+ ca_size_t *bundle_placeval = c->bundle_placeval;
1029
+ int *bundle_nconsumed = c->bundle_nconsumed;
1030
+ int (*bundle_slot)[CA_RANK_MAX] = c->bundle_slot;
1031
+ ca_size_t (*bundle_cstride)[CA_RANK_MAX] = c->bundle_cstride;
1032
+ ca_size_t *grstride = c->grstride;
1033
+ ca_size_t *band_addr = c->band_addr;
1034
+ ca_size_t K_total = c->K_total;
1035
+ ca_size_t *sw_code = c->sw_code;
1036
+ ca_size_t *sw_doff = c->sw_doff;
1037
+ ca_size_t *sw_moff = c->sw_moff;
1038
+ ca_size_t *sw_addr = c->sw_addr;
1039
+ ca_size_t *accn = c->accn;
1040
+ char *seen = c->seen;
1041
+ VALUE *acco = c->acco;
1042
+ boolean8_t *omask = NULL;
1043
+
1044
+ if ( op == GS_CUMCOUNT ) { /* int64 1-based running count */
1045
+ int64_t *outi = (int64_t *) co->ptr;
1046
+ GROUP_SCAN_OBJECT_WALK(
1047
+ accn[code] += 1; outi[addr] = (int64_t) accn[code];,
1048
+ outi[addr] = (int64_t) accn[code];
1049
+ );
1050
+ }
1051
+ else { /* object running VALUE */
1052
+ VALUE *outo = (VALUE *) co->ptr;
1053
+ switch ( op ) {
1054
+ case GS_CUMSUM:
1055
+ /* Identity 0 (matching the core object cumsum): a group's acc is lazily
1056
+ seeded to 0 (Fixnum, so 0 + ev promotes to ev's class), so a cell
1057
+ masked before any present member holds 0 unmasked and an all-masked
1058
+ group yields 0 everywhere. seen doubles as the per-band init flag. */
1059
+ GROUP_SCAN_OBJECT_WALK(
1060
+ if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1061
+ acco[code] = rb_funcall(acco[code], rb_intern("+"), 1, ev);
1062
+ outo[addr] = acco[code];,
1063
+ if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1064
+ outo[addr] = acco[code];
1065
+ );
1066
+ break;
1067
+ case GS_CUMPROD:
1068
+ /* Identity 1, same lazy-init as cumsum. */
1069
+ GROUP_SCAN_OBJECT_WALK(
1070
+ if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1071
+ acco[code] = rb_funcall(acco[code], rb_intern("*"), 1, ev);
1072
+ outo[addr] = acco[code];,
1073
+ if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1074
+ outo[addr] = acco[code];
1075
+ );
1076
+ break;
1077
+ case GS_CUMMAX:
1078
+ /* No identity: seed from the first member, hold only once seen; a cell
1079
+ masked before any member stays UNDEF (empty-max contract). */
1080
+ GROUP_SCAN_OBJECT_WALK(
1081
+ if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1082
+ else if ( ca_obj_extremum_replaces(ev, acco[code], rb_intern(">")) ) {
1083
+ acco[code] = ev;
1084
+ }
1085
+ outo[addr] = acco[code];,
1086
+ if ( seen[code] ) { outo[addr] = acco[code]; }
1087
+ else { MARK_OUT_UNDEF(addr); }
1088
+ );
1089
+ break;
1090
+ case GS_CUMMIN:
1091
+ GROUP_SCAN_OBJECT_WALK(
1092
+ if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1093
+ else if ( ca_obj_extremum_replaces(ev, acco[code], rb_intern("<")) ) {
1094
+ acco[code] = ev;
1095
+ }
1096
+ outo[addr] = acco[code];,
1097
+ if ( seen[code] ) { outo[addr] = acco[code]; }
1098
+ else { MARK_OUT_UNDEF(addr); }
1099
+ );
1100
+ break;
1101
+ }
1102
+ }
1103
+ return Qnil;
1104
+ }
1105
+
973
1106
  static int
974
1107
  group_scan_op_code (VALUE vop)
975
1108
  {
@@ -979,12 +1112,12 @@ group_scan_op_code (VALUE vop)
979
1112
  else if ( id == rb_intern("cummax") ) return GS_CUMMAX;
980
1113
  else if ( id == rb_intern("cummin") ) return GS_CUMMIN;
981
1114
  else if ( id == rb_intern("cumprod") ) return GS_CUMPROD;
982
- rb_raise(rb_eArgError, "axis_group_scan: unsupported op :%s", rb_id2name(id));
1115
+ rb_raise(rb_eArgError, "axis_group_scan: unsupported op :%"PRIsVALUE, rb_id2str(id));
983
1116
  }
984
1117
 
985
- /* __axis_group_scan__(group_axes, bundles, op) — group-keyed segment scan of
1118
+ /* __scan_by_axis_groups__(group_axes, bundles, op) — group-keyed segment scan of
986
1119
  * self over the union of `group_axes` into composite groups described by
987
- * `bundles` (same argument shape as __axis_group_reduce__). Internal.
1120
+ * `bundles` (same argument shape as __reduce_by_axis_groups__). Internal.
988
1121
  *
989
1122
  * Unlike the reduce the grouped axes are not collapsed: the result is a new
990
1123
  * CArray of the same shape as self, each cell holding the running statistic of
@@ -1022,7 +1155,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1022
1155
  GetCArray(self, src);
1023
1156
 
1024
1157
  if ( src->ndim <= 0 ) {
1025
- rb_raise(rb_eRuntimeError, "axis_group_scan: scalar source");
1158
+ rb_raise(rb_eArgError, "axis_group_scan: scalar source");
1026
1159
  }
1027
1160
 
1028
1161
  /* --- group (slab) axes (same validation as reduce) --- */
@@ -1054,7 +1187,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1054
1187
  /* --- bundles: small per-group code tables (same as reduce) --- */
1055
1188
  Check_Type(vbundles, T_ARRAY);
1056
1189
  int n_bundles = (int) RARRAY_LEN(vbundles);
1057
- if ( n_bundles <= 0 || n_bundles > CA_RANK_MAX ) {
1190
+ if ( n_bundles <= 0 || n_bundles > CA_RANK_MAX ) { /* rank-check: a count of key bundles */
1058
1191
  rb_raise(rb_eArgError, "axis_group_scan: bad bundle count %d", n_bundles);
1059
1192
  }
1060
1193
  int32_t *bundle_codes[CA_RANK_MAX];
@@ -1065,6 +1198,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1065
1198
  ca_size_t bundle_cstride[CA_RANK_MAX][CA_RANK_MAX];
1066
1199
  CArray *bundle_ca[CA_RANK_MAX];
1067
1200
  volatile VALUE keep = rb_ary_new();
1201
+ volatile VALUE h_codes[CA_RANK_MAX];
1068
1202
 
1069
1203
  ca_size_t K_total = 1;
1070
1204
  long consumed_total = 0;
@@ -1087,20 +1221,16 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1087
1221
  and the end of the walk can raise -- a validation just below, a gather
1088
1222
  that cannot convert a cell, an object-lane callback into Ruby -- and a
1089
1223
  raise jumps over every detach, leaving the source materialised with
1090
- nothing left to release it. The copy rides a temporary buffer that the
1091
- unwind collects. */
1224
+ nothing left to release it. The copy rides ALLOCV, a temporary buffer
1225
+ that the unwind collects. Not a String: a String held only by `keep`
1226
+ can be moved by compaction, taking the bytes under bundle_codes with
1227
+ it. */
1092
1228
  VALUE v32 = rb_ca_wrap_readonly(vcodes, INT2NUM(CA_INT32));
1093
1229
  rb_ary_push((VALUE) keep, v32);
1094
1230
  GetCArray(v32, bundle_ca[bi]);
1095
- {
1096
- size_t nbytes = (size_t) bundle_ca[bi]->elements * sizeof(int32_t);
1097
- VALUE vbuf = rb_str_tmp_new((long) nbytes);
1098
- rb_ary_push((VALUE) keep, vbuf);
1099
- ca_attach(bundle_ca[bi]);
1100
- memcpy(RSTRING_PTR(vbuf), bundle_ca[bi]->ptr, nbytes);
1101
- ca_detach(bundle_ca[bi]);
1102
- bundle_codes[bi] = (int32_t *) RSTRING_PTR(vbuf);
1103
- }
1231
+ h_codes[bi] = 0;
1232
+ bundle_codes[bi] = ALLOCV_N(int32_t, h_codes[bi], bundle_ca[bi]->elements);
1233
+ ca_copy_data(bundle_ca[bi], (char *) bundle_codes[bi]);
1104
1234
 
1105
1235
  int nb = (int) RARRAY_LEN(vbaxes);
1106
1236
  if ( nb <= 0 || nb > src->ndim ) {
@@ -1160,7 +1290,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1160
1290
  case CA_INT32: case CA_UINT32: case CA_INT64: case CA_UINT64:
1161
1291
  case CA_FLOAT32: case CA_FLOAT64: case CA_OBJECT: break;
1162
1292
  default:
1163
- rb_raise(rb_eRuntimeError,
1293
+ rb_raise(rb_eCADataTypeError,
1164
1294
  "axis_group_scan: unsupported source data_type %d",
1165
1295
  src->data_type);
1166
1296
  }
@@ -1232,75 +1362,23 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1232
1362
  double acc_init = ( op == GS_CUMPROD ) ? 1.0 : 0.0;
1233
1363
 
1234
1364
  boolean8_t *omask = NULL;
1235
- #define MARK_OUT_UNDEF(o) do { \
1236
- if ( ! omask ) { \
1237
- ca_create_mask(co); \
1238
- omask = (boolean8_t *) co->mask->ptr; \
1239
- } \
1240
- omask[o] = 1; \
1241
- } while (0)
1242
1365
 
1243
1366
  if ( src->data_type == CA_OBJECT ) {
1244
- if ( op == GS_CUMCOUNT ) { /* int64 1-based running count */
1245
- int64_t *outi = (int64_t *) co->ptr;
1246
- GROUP_SCAN_OBJECT_WALK(
1247
- accn[code] += 1; outi[addr] = (int64_t) accn[code];,
1248
- outi[addr] = (int64_t) accn[code];
1249
- );
1250
- }
1251
- else { /* object running VALUE */
1252
- VALUE *outo = (VALUE *) co->ptr;
1367
+ group_scan_object_t c;
1368
+ if ( op != GS_CUMCOUNT ) {
1253
1369
  acco = ALLOCV_N(VALUE, h_acco, K_total);
1254
- switch ( op ) {
1255
- case GS_CUMSUM:
1256
- /* Identity 0 (matching the core object cumsum): a group's acc is lazily
1257
- seeded to 0 (Fixnum, so 0 + ev promotes to ev's class), so a cell
1258
- masked before any present member holds 0 unmasked and an all-masked
1259
- group yields 0 everywhere. seen doubles as the per-band init flag. */
1260
- GROUP_SCAN_OBJECT_WALK(
1261
- if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1262
- acco[code] = rb_funcall(acco[code], rb_intern("+"), 1, ev);
1263
- outo[addr] = acco[code];,
1264
- if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1265
- outo[addr] = acco[code];
1266
- );
1267
- break;
1268
- case GS_CUMPROD:
1269
- /* Identity 1, same lazy-init as cumsum. */
1270
- GROUP_SCAN_OBJECT_WALK(
1271
- if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1272
- acco[code] = rb_funcall(acco[code], rb_intern("*"), 1, ev);
1273
- outo[addr] = acco[code];,
1274
- if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1275
- outo[addr] = acco[code];
1276
- );
1277
- break;
1278
- case GS_CUMMAX:
1279
- /* No identity: seed from the first member, hold only once seen; a cell
1280
- masked before any member stays UNDEF (empty-max contract). */
1281
- GROUP_SCAN_OBJECT_WALK(
1282
- if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1283
- else if ( NUM2INT(rb_funcall(ev, rb_intern("<=>"), 1, acco[code])) > 0 ) {
1284
- acco[code] = ev;
1285
- }
1286
- outo[addr] = acco[code];,
1287
- if ( seen[code] ) { outo[addr] = acco[code]; }
1288
- else { MARK_OUT_UNDEF(addr); }
1289
- );
1290
- break;
1291
- case GS_CUMMIN:
1292
- GROUP_SCAN_OBJECT_WALK(
1293
- if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1294
- else if ( NUM2INT(rb_funcall(ev, rb_intern("<=>"), 1, acco[code])) < 0 ) {
1295
- acco[code] = ev;
1296
- }
1297
- outo[addr] = acco[code];,
1298
- if ( seen[code] ) { outo[addr] = acco[code]; }
1299
- else { MARK_OUT_UNDEF(addr); }
1300
- );
1301
- break;
1302
- }
1303
1370
  }
1371
+ c.ca = ca; c.co = co; c.op = op;
1372
+ c.axes = axes; c.ngroup = ngroup;
1373
+ c.n_bundles = n_bundles; c.bundle_codes = bundle_codes;
1374
+ c.bundle_k = bundle_k; c.bundle_placeval = bundle_placeval;
1375
+ c.bundle_nconsumed = bundle_nconsumed;
1376
+ c.bundle_slot = bundle_slot; c.bundle_cstride = bundle_cstride;
1377
+ c.grstride = grstride; c.band_addr = band_addr; c.K_total = K_total;
1378
+ c.sw_code = sw_code; c.sw_doff = sw_doff;
1379
+ c.sw_moff = sw_moff; c.sw_addr = sw_addr;
1380
+ c.accn = accn; c.seen = seen; c.acco = acco;
1381
+ ca_iter_ensure(1, &c.st, group_scan_object_body, (VALUE) &c);
1304
1382
  }
1305
1383
  else { /* native data type dispatch */
1306
1384
  switch ( op ) {
@@ -1330,11 +1408,11 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1330
1408
  break;
1331
1409
  }
1332
1410
  }
1333
- #undef MARK_OUT_UNDEF
1334
1411
 
1335
1412
  ALLOCV_END(h_band2); ALLOCV_END(h_code); ALLOCV_END(h_doff);
1336
1413
  ALLOCV_END(h_moff); ALLOCV_END(h_addr); ALLOCV_END(h_accd);
1337
1414
  ALLOCV_END(h_accn); ALLOCV_END(h_seen); ALLOCV_END(h_acco);
1415
+ for ( int bi = 0; bi < n_bundles; bi++ ) ALLOCV_END(h_codes[bi]);
1338
1416
 
1339
1417
  RB_GC_GUARD(keep);
1340
1418
  return vout;
@@ -1343,8 +1421,8 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1343
1421
  void
1344
1422
  Init_ca_axis_group (void)
1345
1423
  {
1346
- rb_define_method(rb_cCArray, "__axis_group_reduce__",
1424
+ rb_define_method(rb_cCArray, "__reduce_by_axis_groups__",
1347
1425
  rb_ca_axis_group_reduce, 3);
1348
- rb_define_method(rb_cCArray, "__axis_group_scan__",
1426
+ rb_define_method(rb_cCArray, "__scan_by_axis_groups__",
1349
1427
  rb_ca_axis_group_scan, 3);
1350
1428
  }
@@ -27,39 +27,56 @@
27
27
  /* vv kernel lookup */
28
28
  /* ------------------------------------------------------------------- */
29
29
 
30
+ /* The kernel table of each op id. The eager operators hold the tables
31
+ themselves; ca_binop_op_id_of_table maps one back to its op id, so that
32
+ both ask ca_op_raises_on_cell the same question. */
33
+ static ca_binop_func_t * const ca_binop_tables[CA_BINOP_COUNT] = {
34
+ [CA_BINOP_ADD] = ca_binop_add,
35
+ [CA_BINOP_SUB] = ca_binop_sub,
36
+ [CA_BINOP_MUL] = ca_binop_mul,
37
+ [CA_BINOP_DIV] = ca_binop_div,
38
+ [CA_BINOP_POW] = ca_binop_power,
39
+ [CA_BINOP_BIT_AND] = ca_binop_bit_and_i,
40
+ [CA_BINOP_BIT_OR] = ca_binop_bit_or_i,
41
+ [CA_BINOP_BIT_XOR] = ca_binop_bit_xor_i,
42
+ [CA_BINOP_BIT_LSHIFT]= ca_binop_bit_lshift,
43
+ [CA_BINOP_BIT_RSHIFT]= ca_binop_bit_rshift,
44
+ [CA_BINOP_MOD] = ca_binop_mod,
45
+ [CA_BINOP_QUO] = ca_binop_quo_i,
46
+ [CA_BINOP_RCP_MUL] = ca_binop_rcp_mul,
47
+ [CA_BINOP_IPOWER] = ca_binop_ipower,
48
+ [CA_BINOP_COPYSIGN] = ca_binop_copysign,
49
+ [CA_BINOP_LOGADDEXP] = ca_binop_logaddexp,
50
+ [CA_BINOP_NEXTAFTER] = ca_binop_nextafter,
51
+ [CA_BINOP_FMOD] = ca_binop_fmod,
52
+ [CA_BINOP_ATAN2] = ca_binop_atan2,
53
+ [CA_BINOP_HYPOT] = ca_binop_hypot,
54
+ [CA_BINOP_PMAX] = ca_binop_pmax,
55
+ [CA_BINOP_PMIN] = ca_binop_pmin,
56
+ [CA_BINOP_MAXIMUM] = ca_binop_maximum,
57
+ [CA_BINOP_MINIMUM] = ca_binop_minimum,
58
+ [CA_BINOP_AND] = ca_binop_and,
59
+ [CA_BINOP_OR] = ca_binop_or,
60
+ [CA_BINOP_XOR] = ca_binop_xor,
61
+ };
62
+
30
63
  ca_binop_func_t
31
64
  ca_binop_kernel_lookup_vv (uint16_t op_id, int8_t common_dt)
32
65
  {
33
- switch (op_id) {
34
- case CA_BINOP_ADD: return ca_binop_add [common_dt];
35
- case CA_BINOP_SUB: return ca_binop_sub [common_dt];
36
- case CA_BINOP_MUL: return ca_binop_mul [common_dt];
37
- case CA_BINOP_DIV: return ca_binop_div [common_dt];
38
- case CA_BINOP_POW: return ca_binop_power [common_dt];
39
- case CA_BINOP_BIT_AND: return ca_binop_bit_and_i [common_dt];
40
- case CA_BINOP_BIT_OR: return ca_binop_bit_or_i [common_dt];
41
- case CA_BINOP_BIT_XOR: return ca_binop_bit_xor_i [common_dt];
42
- case CA_BINOP_BIT_LSHIFT: return ca_binop_bit_lshift [common_dt];
43
- case CA_BINOP_BIT_RSHIFT: return ca_binop_bit_rshift [common_dt];
44
- case CA_BINOP_MOD: return ca_binop_mod [common_dt];
45
- case CA_BINOP_QUO: return ca_binop_quo_i [common_dt];
46
- case CA_BINOP_RCP_MUL: return ca_binop_rcp_mul [common_dt];
47
- case CA_BINOP_IPOWER: return ca_binop_ipower [common_dt];
48
- case CA_BINOP_COPYSIGN: return ca_binop_copysign [common_dt];
49
- case CA_BINOP_LOGADDEXP: return ca_binop_logaddexp [common_dt];
50
- case CA_BINOP_NEXTAFTER: return ca_binop_nextafter [common_dt];
51
- case CA_BINOP_FMOD: return ca_binop_fmod [common_dt];
52
- case CA_BINOP_ATAN2: return ca_binop_atan2 [common_dt];
53
- case CA_BINOP_HYPOT: return ca_binop_hypot [common_dt];
54
- case CA_BINOP_PMAX: return ca_binop_pmax [common_dt];
55
- case CA_BINOP_PMIN: return ca_binop_pmin [common_dt];
56
- case CA_BINOP_MAXIMUM: return ca_binop_maximum [common_dt];
57
- case CA_BINOP_MINIMUM: return ca_binop_minimum [common_dt];
58
- case CA_BINOP_AND: return ca_binop_and [common_dt];
59
- case CA_BINOP_OR: return ca_binop_or [common_dt];
60
- case CA_BINOP_XOR: return ca_binop_xor [common_dt];
61
- default: return NULL;
66
+ if ( op_id >= CA_BINOP_COUNT || ! ca_binop_tables[op_id] ) return NULL;
67
+ return ca_binop_tables[op_id][common_dt];
68
+ }
69
+
70
+ /* The op id whose kernel table is `table`, or -1 for a table no op id
71
+ names. */
72
+ int
73
+ ca_binop_op_id_of_table (ca_binop_func_t table[])
74
+ {
75
+ int op_id;
76
+ for ( op_id = 0; op_id < CA_BINOP_COUNT; op_id++ ) {
77
+ if ( ca_binop_tables[op_id] == table ) return op_id;
62
78
  }
79
+ return -1;
63
80
  }
64
81
 
65
82
  /* ------------------------------------------------------------------- */
@@ -99,26 +116,3 @@ ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
99
116
  if ( out_r_in_dt ) *out_r_in_dt = common;
100
117
  }
101
118
 
102
- /* ------------------------------------------------------------------- */
103
- /* trapping-op predicate */
104
- /* ------------------------------------------------------------------- */
105
-
106
- int
107
- ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
108
- {
109
- /* Integer DIV / MOD / QUO / FMOD can SIGFPE on a zero divisor. Float
110
- DIV returns NaN/Inf and does NOT trap, so it is not classified
111
- trapping. */
112
- int is_integer = ( common_dt >= CA_INT8 && common_dt <= CA_UINT64 );
113
- if ( ! is_integer ) return 0;
114
-
115
- switch (op_id) {
116
- case CA_BINOP_DIV:
117
- case CA_BINOP_MOD:
118
- case CA_BINOP_QUO:
119
- case CA_BINOP_FMOD:
120
- return 1;
121
- default:
122
- return 0;
123
- }
124
- }
@@ -147,6 +147,6 @@ void ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
147
147
  When trapping AND either operand has a mask, xfer_stride must pass
148
148
  a slab mask to the kernel so masked cells are skipped (otherwise
149
149
  masked-zero divisors crash with SIGFPE). See §3.4 rev3. */
150
- int ca_binop_is_trapping (uint16_t op_id, int8_t common_dt);
150
+ int ca_binop_op_id_of_table (ca_binop_func_t table[]);
151
151
 
152
152
  #endif /* CA_BINOP_DISPATCH_H */