carray 2.0.0 → 3.0.0

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 (339) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -25
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +1 -1
  5. data/NEWS.md +3 -0
  6. data/README.md +128 -44
  7. data/carray.gemspec +22 -24
  8. data/ext/ca_array_pool.c +91 -0
  9. data/ext/ca_axis_descriptor.h +186 -0
  10. data/ext/ca_axis_dispatch.c +924 -0
  11. data/ext/ca_axis_group.c +1208 -0
  12. data/ext/ca_bincmp_dispatch.c +76 -0
  13. data/ext/ca_bincmp_dispatch.h +85 -0
  14. data/ext/ca_binop_dispatch.c +125 -0
  15. data/ext/ca_binop_dispatch.h +159 -0
  16. data/ext/ca_categorical_iterator.c +1375 -0
  17. data/ext/ca_compare.c +94 -0
  18. data/ext/ca_compare.h +26 -0
  19. data/ext/ca_composite_dispatch.c +414 -0
  20. data/ext/ca_composite_dispatch.h +116 -0
  21. data/ext/ca_for_buffer.h +96 -0
  22. data/ext/ca_for_each_element.h +241 -0
  23. data/ext/ca_group_iter.c +304 -0
  24. data/ext/ca_iter_substrate.h +325 -0
  25. data/ext/ca_kernel_iterator.c +4321 -0
  26. data/ext/ca_kernel_iterator.h +2603 -0
  27. data/ext/ca_moncmp_dispatch.c +37 -0
  28. data/ext/ca_moncmp_dispatch.h +62 -0
  29. data/ext/ca_monop_dispatch.c +200 -0
  30. data/ext/ca_monop_dispatch.h +235 -0
  31. data/ext/ca_obj_array.c +355 -359
  32. data/ext/ca_obj_bincmp.c +809 -0
  33. data/ext/ca_obj_binop.c +892 -0
  34. data/ext/ca_obj_bitarray.c +369 -164
  35. data/ext/ca_obj_bitfield.c +294 -234
  36. data/ext/ca_obj_block.c +189 -711
  37. data/ext/ca_obj_byte_swap.c +766 -0
  38. data/ext/ca_obj_const_string.c +965 -0
  39. data/ext/ca_obj_face.c +670 -0
  40. data/ext/ca_obj_face.h +247 -0
  41. data/ext/ca_obj_fake.c +228 -100
  42. data/ext/ca_obj_farray.c +54 -441
  43. data/ext/ca_obj_field.c +82 -529
  44. data/ext/ca_obj_fixlen_string.c +306 -0
  45. data/ext/ca_obj_grid.c +858 -440
  46. data/ext/ca_obj_meld.c +1034 -0
  47. data/ext/ca_obj_moncmp.c +569 -0
  48. data/ext/ca_obj_monop.c +1111 -0
  49. data/ext/ca_obj_object.c +774 -298
  50. data/ext/ca_obj_record.c +468 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +569 -459
  53. data/ext/ca_obj_remap.c +475 -0
  54. data/ext/ca_obj_repeat.c +92 -477
  55. data/ext/ca_obj_roll.c +616 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1296 -0
  58. data/ext/ca_obj_shift.c +230 -792
  59. data/ext/ca_obj_source.c +78 -0
  60. data/ext/ca_obj_stack.c +1173 -0
  61. data/ext/ca_obj_stride.c +2501 -0
  62. data/ext/ca_obj_string.c +268 -0
  63. data/ext/ca_obj_tile.c +614 -0
  64. data/ext/ca_obj_time.c +546 -0
  65. data/ext/ca_obj_timedelta.c +435 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +746 -0
  68. data/ext/ca_obj_unbound_repeat.c +208 -241
  69. data/ext/ca_obj_window.c +1131 -563
  70. data/ext/ca_op_byte_swap.c +175 -0
  71. data/ext/ca_op_ipower.c +319 -0
  72. data/ext/ca_op_powi.h +88 -0
  73. data/ext/ca_sort_kernels.h +132 -0
  74. data/ext/ca_sweep_engine.c +430 -0
  75. data/ext/ca_sweep_engine.h +157 -0
  76. data/ext/ca_transform_common.c +228 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +795 -402
  80. data/ext/carray_access.c +831 -711
  81. data/ext/carray_attribute.c +98 -330
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +283 -0
  84. data/ext/carray_call_cfunc.c +1360 -828
  85. data/ext/carray_call_cfunc.h +160 -0
  86. data/ext/carray_cast.c +1212 -301
  87. data/ext/carray_cast_func.rb +81 -40
  88. data/ext/carray_class.c +53 -63
  89. data/ext/carray_config.h +28 -0
  90. data/ext/carray_conversion.c +350 -346
  91. data/ext/carray_copy.c +156 -268
  92. data/ext/carray_core.c +1342 -199
  93. data/ext/carray_count.c +312 -0
  94. data/ext/carray_data_type.c +43 -19
  95. data/ext/carray_element.c +585 -213
  96. data/ext/carray_factorize.c +2542 -0
  97. data/ext/carray_generate.c +230 -559
  98. data/ext/carray_histogram.c +490 -0
  99. data/ext/carray_hold.c +228 -0
  100. data/ext/carray_index_classifier.c +1035 -0
  101. data/ext/carray_index_classifier.h +27 -0
  102. data/ext/carray_internal.h +120 -0
  103. data/ext/carray_kernels_bincmp.c +4445 -0
  104. data/ext/carray_kernels_binop.c +10979 -0
  105. data/ext/carray_kernels_init.c +36 -0
  106. data/ext/carray_kernels_map.c +3466 -0
  107. data/ext/carray_kernels_moncmp.c +2096 -0
  108. data/ext/carray_kernels_monop.c +18312 -0
  109. data/ext/carray_kernels_reduce_aggregate.c +25836 -0
  110. data/ext/carray_kernels_reduce_boolean.c +329 -0
  111. data/ext/carray_kernels_reduce_cumulative.c +14592 -0
  112. data/ext/carray_kernels_reduce_extreme.c +16947 -0
  113. data/ext/carray_kernels_reduce_variance.c +3909 -0
  114. data/ext/carray_kernels_scan.c +3692 -0
  115. data/ext/carray_kernels_search.c +32137 -0
  116. data/ext/carray_kernels_sort.c +10625 -0
  117. data/ext/carray_kernels_triop.c +1391 -0
  118. data/ext/carray_lazy.c +567 -0
  119. data/ext/carray_loop.c +88 -200
  120. data/ext/carray_mask.c +848 -154
  121. data/ext/carray_math_kernel.h +120 -0
  122. data/ext/carray_mathfunc.c +10 -241
  123. data/ext/carray_median_percentile.c +1257 -0
  124. data/ext/carray_memory_view.c +1625 -0
  125. data/ext/carray_operator.c +1526 -318
  126. data/ext/carray_order.c +664 -1394
  127. data/ext/carray_partition.c +416 -0
  128. data/ext/carray_random.c +518 -0
  129. data/ext/carray_scatter.c +357 -0
  130. data/ext/carray_slab.c +1219 -0
  131. data/ext/carray_slab.h +84 -0
  132. data/ext/carray_sort.c +829 -0
  133. data/ext/carray_sort_kernel.c +620 -0
  134. data/ext/carray_struct.c +695 -0
  135. data/ext/carray_test.c +343 -229
  136. data/ext/carray_undef.c +34 -17
  137. data/ext/carray_utils.c +175 -74
  138. data/ext/extconf.rb +216 -55
  139. data/ext/mk_call_cfunc.rb +480 -0
  140. data/ext/mkkernel.rb +8842 -0
  141. data/ext/ruby_carray.c +202 -101
  142. data/ext/version.h +4 -14
  143. data/ext/version.rb +5 -13
  144. data/lib/carray/arrow_tensor.rb +401 -0
  145. data/lib/carray/attribute.rb +166 -0
  146. data/lib/carray/autoload_carray.rb +220 -0
  147. data/lib/carray/autoload_method_extension.rb +44 -0
  148. data/lib/carray/axis_group.rb +711 -0
  149. data/lib/carray/basics.rb +481 -0
  150. data/lib/carray/bincount_nd.rb +358 -0
  151. data/lib/carray/block_iterator.rb +604 -0
  152. data/lib/carray/boolean_reduce.rb +109 -0
  153. data/lib/carray/categorical.rb +561 -0
  154. data/lib/carray/categorical_iterator.rb +1062 -0
  155. data/lib/carray/complex.rb +150 -0
  156. data/lib/carray/conditional.rb +216 -0
  157. data/lib/carray/const_string.rb +228 -0
  158. data/lib/carray/construct.rb +139 -328
  159. data/lib/carray/core_extensions.rb +240 -0
  160. data/lib/carray/data_type_extension.rb +233 -0
  161. data/lib/carray/fixlen_string.rb +95 -0
  162. data/lib/carray/frame/concat.rb +132 -0
  163. data/lib/carray/frame/convert.rb +95 -0
  164. data/lib/carray/frame/csv_parser.rb +211 -0
  165. data/lib/carray/frame/frame.rb +649 -0
  166. data/lib/carray/frame/group.rb +186 -0
  167. data/lib/carray/frame/io.rb +164 -0
  168. data/lib/carray/frame/join.rb +248 -0
  169. data/lib/carray/frame/records.rb +99 -0
  170. data/lib/carray/frame/sort.rb +113 -0
  171. data/lib/carray/frame/verbs.rb +299 -0
  172. data/lib/carray/frame.rb +16 -0
  173. data/lib/carray/histogram.rb +512 -0
  174. data/lib/carray/inspect.rb +37 -20
  175. data/lib/carray/iterator.rb +57 -349
  176. data/lib/carray/lazy.rb +889 -0
  177. data/lib/carray/mask_gap_fill.rb +200 -0
  178. data/lib/carray/math.rb +78 -342
  179. data/lib/carray/meld_reduce.rb +289 -0
  180. data/lib/carray/methods/align_addr.rb +116 -0
  181. data/lib/carray/methods/bin.rb +128 -0
  182. data/lib/carray/methods/bincount.rb +87 -0
  183. data/lib/carray/methods/bit_string.rb +92 -0
  184. data/lib/carray/methods/broadcast.rb +63 -0
  185. data/lib/carray/methods/choose.rb +39 -0
  186. data/lib/carray/methods/composition.rb +280 -0
  187. data/lib/carray/methods/gather_nd.rb +206 -0
  188. data/lib/carray/methods/index.rb +39 -0
  189. data/lib/carray/methods/insert_block.rb +99 -0
  190. data/lib/carray/methods/is_in.rb +141 -0
  191. data/lib/carray/methods/join.rb +90 -0
  192. data/lib/carray/methods/locate_addr.rb +47 -0
  193. data/lib/carray/methods/mask_duplicates.rb +41 -0
  194. data/lib/carray/methods/meshgrid.rb +91 -0
  195. data/lib/carray/methods/mode.rb +126 -0
  196. data/lib/carray/methods/nunique.rb +46 -0
  197. data/lib/carray/methods/resize.rb +56 -0
  198. data/lib/carray/methods/snap.rb +156 -0
  199. data/lib/carray/methods/string_format.rb +57 -0
  200. data/lib/carray/methods/unique.rb +47 -0
  201. data/lib/carray/methods/value_counts.rb +71 -0
  202. data/lib/carray/mkmf.rb +124 -101
  203. data/lib/carray/runtime.rb +108 -0
  204. data/lib/carray/serialize.rb +478 -167
  205. data/lib/carray/slab_iterator.rb +292 -0
  206. data/lib/carray/stack.rb +291 -0
  207. data/lib/carray/string.rb +56 -180
  208. data/lib/carray/string_operation_extension.rb +289 -0
  209. data/lib/carray/struct.rb +335 -323
  210. data/lib/carray/struct_builder.rb +697 -0
  211. data/lib/carray/table.rb +41 -2
  212. data/lib/carray/time.rb +2255 -38
  213. data/lib/carray/window_iterator.rb +655 -0
  214. data/lib/carray.rb +55 -57
  215. metadata +163 -130
  216. data/Rakefile +0 -51
  217. data/TODO.md +0 -18
  218. data/ext/ca_iter_block.c +0 -257
  219. data/ext/ca_iter_dimension.c +0 -299
  220. data/ext/ca_iter_window.c +0 -214
  221. data/ext/ca_obj_mapping.c +0 -644
  222. data/ext/carray_iterator.c +0 -641
  223. data/ext/carray_math.rb +0 -850
  224. data/ext/carray_numeric.c +0 -259
  225. data/ext/carray_sort_addr.c +0 -254
  226. data/ext/carray_stat.c +0 -2100
  227. data/ext/carray_stat_proc.rb +0 -1999
  228. data/ext/mkmath.rb +0 -741
  229. data/ext/ruby_ccomplex.c +0 -509
  230. data/ext/ruby_float_func.c +0 -86
  231. data/lib/carray/array.rb +0 -8
  232. data/lib/carray/autoload/autoload_base.rb +0 -19
  233. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  234. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  235. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  236. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  237. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  238. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  239. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  240. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  241. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  242. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  243. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  244. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  245. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  246. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  247. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  248. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  249. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  250. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  251. data/lib/carray/autoload.rb +0 -141
  252. data/lib/carray/basic.rb +0 -191
  253. data/lib/carray/broadcast.rb +0 -101
  254. data/lib/carray/compose.rb +0 -315
  255. data/lib/carray/convert.rb +0 -115
  256. data/lib/carray/info.rb +0 -110
  257. data/lib/carray/io/imagemagick.rb +0 -235
  258. data/lib/carray/mask.rb +0 -102
  259. data/lib/carray/math/histogram.rb +0 -177
  260. data/lib/carray/math/recurrence.rb +0 -93
  261. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  262. data/lib/carray/object/ca_obj_link.rb +0 -50
  263. data/lib/carray/object/ca_obj_pack.rb +0 -99
  264. data/lib/carray/obsolete.rb +0 -256
  265. data/lib/carray/ordering.rb +0 -181
  266. data/lib/carray/testing.rb +0 -51
  267. data/lib/carray/transform.rb +0 -109
  268. data/misc/Methods.ja.md +0 -182
  269. data/misc/NOTE +0 -51
  270. data/spec/Classes/CABitfield_spec.rb +0 -58
  271. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  272. data/spec/Classes/CABlock_spec.rb +0 -205
  273. data/spec/Classes/CAField_spec.rb +0 -39
  274. data/spec/Classes/CAGrid_spec.rb +0 -75
  275. data/spec/Classes/CAMap_spec.rb +0 -0
  276. data/spec/Classes/CAMapping_spec.rb +0 -105
  277. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  278. data/spec/Classes/CAObject_spec.rb +0 -33
  279. data/spec/Classes/CARefer_spec.rb +0 -93
  280. data/spec/Classes/CARepeat_spec.rb +0 -65
  281. data/spec/Classes/CASelect_spec.rb +0 -22
  282. data/spec/Classes/CAShift_spec.rb +0 -16
  283. data/spec/Classes/CAStruct_spec.rb +0 -71
  284. data/spec/Classes/CATranspose_spec.rb +0 -60
  285. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  286. data/spec/Classes/CAWindow_spec.rb +0 -54
  287. data/spec/Classes/CAWrap_spec.rb +0 -8
  288. data/spec/Classes/CArray_spec.rb +0 -184
  289. data/spec/Classes/CScalar_spec.rb +0 -55
  290. data/spec/Classes/ex1.rb +0 -46
  291. data/spec/Features/feature_130_spec.rb +0 -19
  292. data/spec/Features/feature_attributes_spec.rb +0 -280
  293. data/spec/Features/feature_boolean_spec.rb +0 -98
  294. data/spec/Features/feature_broadcast.rb +0 -116
  295. data/spec/Features/feature_cast_function.rb +0 -19
  296. data/spec/Features/feature_cast_spec.rb +0 -33
  297. data/spec/Features/feature_class_spec.rb +0 -84
  298. data/spec/Features/feature_complex_spec.rb +0 -42
  299. data/spec/Features/feature_composite_spec.rb +0 -124
  300. data/spec/Features/feature_convert_spec.rb +0 -46
  301. data/spec/Features/feature_copy_spec.rb +0 -123
  302. data/spec/Features/feature_creation_spec.rb +0 -84
  303. data/spec/Features/feature_element_spec.rb +0 -144
  304. data/spec/Features/feature_extream_spec.rb +0 -54
  305. data/spec/Features/feature_generate_spec.rb +0 -74
  306. data/spec/Features/feature_index_spec.rb +0 -69
  307. data/spec/Features/feature_mask_spec.rb +0 -580
  308. data/spec/Features/feature_math_spec.rb +0 -97
  309. data/spec/Features/feature_order_spec.rb +0 -146
  310. data/spec/Features/feature_ref_store_spec.rb +0 -209
  311. data/spec/Features/feature_serialization_spec.rb +0 -125
  312. data/spec/Features/feature_stat_spec.rb +0 -397
  313. data/spec/Features/feature_virtual_spec.rb +0 -48
  314. data/spec/Features/method_eq_spec.rb +0 -81
  315. data/spec/Features/method_is_nan_spec.rb +0 -12
  316. data/spec/Features/method_map_spec.rb +0 -54
  317. data/spec/Features/method_max_with.rb +0 -20
  318. data/spec/Features/method_min_with.rb +0 -19
  319. data/spec/Features/method_ne_spec.rb +0 -18
  320. data/spec/Features/method_project_spec.rb +0 -188
  321. data/spec/Features/method_ref_spec.rb +0 -27
  322. data/spec/Features/method_round_spec.rb +0 -11
  323. data/spec/Features/method_s_linspace_spec.rb +0 -48
  324. data/spec/Features/method_s_span_spec.rb +0 -14
  325. data/spec/Features/method_seq_spec.rb +0 -47
  326. data/spec/Features/method_sort_with.rb +0 -43
  327. data/spec/Features/method_sorted_with.rb +0 -29
  328. data/spec/Features/method_span_spec.rb +0 -42
  329. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  330. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  331. data/spec/spec_all.rb +0 -10
  332. data/utils/ca_ase.rb +0 -21
  333. data/utils/ca_methods.rb +0 -15
  334. data/utils/cast_checker.rb +0 -30
  335. data/utils/convert_test.rb +0 -73
  336. data/utils/extract_yard.rb +0 -22
  337. data/utils/guess_shape.rb +0 -76
  338. data/utils/monkey_patch_methods.rb +0 -62
  339. data/utils/remove_resource_fork.sh +0 -5
@@ -0,0 +1,809 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ Lazy binadic element-wise comparison view: holds (left, right,
4
+ op_id, eps) and materialises a boolean result on attach. Carries
5
+ CA_FLAG_READ_ONLY; there is no bang path and `[]=` raises.
6
+
7
+ Sibling of ca_obj_binop.c (element-wise arithmetic) and
8
+ ca_obj_moncmp.c (unary comparisons); dispatched by
9
+ ca_bincmp_kernel_lookup from ca_bincmp_dispatch.h.
10
+
11
+ Dispatch by data_type:
12
+ numeric (i8..f64, +complex) -> ca_bincmp_<op>_<dtype> kernel
13
+ boolean / fixlen / object -> not implemented (raise)
14
+
15
+ CAREFUL: the binop in-place trick (= pull left into the output
16
+ buffer) is structurally unavailable here — the output is
17
+ boolean8_t (1 byte per cell) while operands live at the common
18
+ data_type (typically 8 bytes at f64), so a pull-into-output would
19
+ overflow. xfer_stride therefore holds two operand-typed scratch
20
+ slabs and writes the boolean result directly to `data`.
21
+
22
+ Comparison ops never trap, so the kernel is called with m=NULL
23
+ (SIMD fast path). The output mask is computed by create_mask as
24
+ `left.mask | right.mask` and propagated through the standard
25
+ CArray mask machinery.
26
+
27
+ ---------------------------------------------------------------------------- */
28
+
29
+ #include "carray.h"
30
+ #include "carray_internal.h" /* ca_lazy_arena_* */
31
+ #include "ca_bincmp_dispatch.h"
32
+ #include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE */
33
+
34
+ extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
35
+ ca_size_t *target_dim);
36
+ extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
37
+ extern void *ca_lazy_arena_acquire (ca_size_t bytes);
38
+ extern void ca_lazy_arena_release (void *ptr);
39
+
40
+ int8_t CA_OBJ_BINCMP;
41
+ VALUE rb_cCABinCmp;
42
+
43
+ extern int8_t CA_OBJ_LAZY_MARKER;
44
+
45
+ /* ------------------------------------------------------------------- */
46
+ /* CABinCmp struct */
47
+ /* ------------------------------------------------------------------- */
48
+
49
+ typedef struct CABinCmp {
50
+ int16_t obj_type;
51
+ int8_t data_type; /* always CA_BOOLEAN */
52
+ int8_t ndim;
53
+ int32_t flags;
54
+ ca_size_t bytes; /* always 1 */
55
+ ca_size_t elements;
56
+ ca_size_t *dim;
57
+ char *ptr;
58
+ CArray *mask;
59
+ char *_pool; /* framework-managed pool buffer (NULL = legacy ALLOC_N path). */
60
+ CArray *parent; /* = left */
61
+ uint32_t attach;
62
+ uint8_t nosync;
63
+ /* CABinCmp-specific tail */
64
+ CArray *right;
65
+ uint16_t op_id;
66
+ uint8_t right_is_scalar;
67
+ int8_t common_dt; /* operand-data_type after promote (= cast
68
+ target of both left & right, also the
69
+ kernel lookup key) */
70
+ double eps; /* Runtime tolerance slot for IS_CLOSE /
71
+ IS_EQUIV; ignored for other ops. The
72
+ `eps` name is retained to keep the
73
+ `__eps__` Ruby accessor stable across
74
+ the dual purpose. */
75
+ } CABinCmp;
76
+
77
+ static size_t
78
+ ca_bincmp_dsize (const void *ap)
79
+ {
80
+ const CABinCmp *ca = (const CABinCmp *) ap;
81
+ return sizeof(CABinCmp) + ca->ndim * sizeof(ca_size_t);
82
+ }
83
+
84
+ /* Pool framework hooks: single ndim-sized tail (dim) in the _pool
85
+ buffer. See ca_array_pool.c for the shared alloc/free discipline. */
86
+ static size_t
87
+ ca_bincmp_pool_bytes (int8_t ndim)
88
+ {
89
+ ca_size_t n = (ndim > 0) ? ndim : 1;
90
+ return (size_t) n * sizeof(ca_size_t);
91
+ }
92
+
93
+ static void
94
+ ca_bincmp_pool_init (void *ap, int8_t ndim)
95
+ {
96
+ CABinCmp *ca = (CABinCmp *) ap;
97
+ ca->dim = (ca_size_t *) ca->_pool;
98
+ }
99
+
100
+ const rb_data_type_t cabincmp_data_type = {
101
+ .parent = &caview_data_type,
102
+ .wrap_struct_name = "CABinCmp",
103
+ .function = {
104
+ .dmark = ca_mark,
105
+ .dfree = ca_free,
106
+ .dsize = ca_bincmp_dsize,
107
+ .dcompact = NULL
108
+ },
109
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
110
+ };
111
+
112
+ /* ------------------------------------------------------------------- */
113
+ /* setup / new / free */
114
+ /* ------------------------------------------------------------------- */
115
+
116
+ static int
117
+ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
118
+ double eps)
119
+ {
120
+ ca->obj_type = CA_OBJ_BINCMP;
121
+ ca->data_type = CA_BOOLEAN; /* output is always boolean */
122
+ ca->flags = CA_FLAG_READ_ONLY;
123
+ ca->ndim = left->ndim;
124
+ ca->bytes = 1; /* boolean8_t */
125
+ ca->elements = left->elements;
126
+ ca->ptr = NULL;
127
+ ca->mask = NULL;
128
+ if ( ! ca->_pool ) {
129
+ ca->dim = ALLOC_N(ca_size_t, left->ndim);
130
+ }
131
+ ca->parent = left;
132
+ ca->attach = 0;
133
+ ca->nosync = 0;
134
+ ca->right = right;
135
+ ca->op_id = op_id;
136
+ ca->right_is_scalar = ( right->elements == 1 && left->elements > 1 ) ? 1 : 0;
137
+ /* Builder has already cast both operands to common data_type. */
138
+ ca->common_dt = left->data_type;
139
+ ca->eps = eps;
140
+
141
+ memcpy(ca->dim, left->dim, left->ndim * sizeof(ca_size_t));
142
+
143
+ if ( ca_has_mask(left) || ca_has_mask(right) ) {
144
+ ca_create_mask(ca);
145
+ }
146
+
147
+ if ( ca_is_scalar(left) && ca_is_scalar(right) ) {
148
+ ca_set_flag(ca, CA_FLAG_SCALAR);
149
+ }
150
+
151
+ return 0;
152
+ }
153
+
154
+ CABinCmp *
155
+ ca_bincmp_new (CArray *left, CArray *right, uint16_t op_id, double eps)
156
+ {
157
+ CABinCmp *ca = (CABinCmp *) ca_array_alloc(CA_OBJ_BINCMP, left->ndim);
158
+ ca_bincmp_setup(ca, left, right, op_id, eps);
159
+ return ca;
160
+ }
161
+
162
+ static void
163
+ free_ca_bincmp (void *ap)
164
+ {
165
+ CABinCmp *ca = (CABinCmp *) ap;
166
+ if ( ca != NULL ) {
167
+ ca_free(ca->mask);
168
+ if ( ca->_pool ) {
169
+ ca_array_free(ca); /* dim lives in _pool */
170
+ }
171
+ else {
172
+ xfree(ca->dim);
173
+ xfree(ca);
174
+ }
175
+ }
176
+ }
177
+
178
+ /* ------------------------------------------------------------------- */
179
+ /* operation function table */
180
+ /* ------------------------------------------------------------------- */
181
+
182
+ static void ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts,
183
+ ca_size_t *counts,
184
+ ca_size_t *strides,
185
+ void *data, int dir);
186
+
187
+ static void *
188
+ ca_bincmp_func_clone (void *ap)
189
+ {
190
+ CABinCmp *ca = (CABinCmp *) ap;
191
+ return ca_bincmp_new(ca->parent, ca->right, ca->op_id, ca->eps);
192
+ }
193
+
194
+ static void
195
+ ca_bincmp_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
196
+ {
197
+ CABinCmp *ca = (CABinCmp *) ap;
198
+ ca_size_t starts[CA_RANK_MAX];
199
+ ca_size_t counts[CA_RANK_MAX];
200
+ ca_size_t strides[CA_RANK_MAX];
201
+ int8_t k;
202
+
203
+ if ( dir != CA_XFER_GET ) {
204
+ rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_index PUT)");
205
+ }
206
+
207
+ for ( k = ca->ndim - 1; k >= 0; k-- ) {
208
+ starts[k] = idx[k];
209
+ counts[k] = 1;
210
+ strides[k] = 1; /* boolean8_t */
211
+ }
212
+ ca_bincmp_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
213
+ }
214
+
215
+ static void
216
+ ca_bincmp_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
217
+ void *data, int dir)
218
+ {
219
+ CABinCmp *ca = (CABinCmp *) ap;
220
+ ca_size_t i;
221
+ char *out = (char *) data;
222
+
223
+ if ( dir != CA_XFER_GET ) {
224
+ rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_addrs PUT)");
225
+ }
226
+
227
+ for ( i = 0; i < n; i++ ) {
228
+ ca_size_t idx[CA_RANK_MAX];
229
+ ca_addr2index((CArray *)ca, addrs[i], idx);
230
+ ca_bincmp_func_xfer_index(ca, idx, out + i, CA_XFER_GET);
231
+ }
232
+ }
233
+
234
+ /* Test / observability counters — bumped from the xfer_stride hot
235
+ path so specs can assert scratch acquisition and leaf in-place
236
+ hit rates without materialising the view. */
237
+ ca_size_t ca_bincmp_scratch_acquire_count = 0;
238
+ ca_size_t ca_bincmp_materialise_call_count = 0;
239
+ ca_size_t ca_bincmp_leaf_inplace_count = 0;
240
+
241
+ /* Leaf-operand in-place read eligibility. When the operand has a
242
+ valid contiguous backing buffer at the common data_type, we can
243
+ use operand->ptr + byte_offset directly, skipping the arena
244
+ acquire and the ca_xfer_stride pull.
245
+ *
246
+ * Eligible cases:
247
+ * - entity (CA_OBJ_ARRAY / CA_OBJ_SCALAR / CA_OBJ_ARRAY_WRAP) at
248
+ * the common data_type
249
+ * - already-attached view at the common data_type with a
250
+ * contiguous ptr
251
+ *
252
+ * The request must be a row-major slab over the operand (what
253
+ * xfer_all sends, which is the dominant to_ca path). */
254
+ static int
255
+ ca_bincmp_try_leaf_inplace (CArray *op, int8_t common_dt,
256
+ ca_size_t *starts, ca_size_t *counts,
257
+ ca_size_t expected_inner_byte_stride,
258
+ char **out_ptr)
259
+ {
260
+ ca_size_t row_strides[CA_RANK_MAX];
261
+ ca_size_t s, byte_off;
262
+ int8_t k;
263
+
264
+ if ( op->data_type != common_dt ) return 0;
265
+ if ( op->ptr == NULL ) return 0;
266
+ if ( op->bytes != expected_inner_byte_stride ) return 0;
267
+
268
+ /* Compute row-major byte offset from starts[]. We rely on the
269
+ caller (ca_xfer_all) providing row-major counts == op->dim or a
270
+ contig sub-region. byte_off = sum(starts[k] * row_stride_k)
271
+ where row_stride_k = product of dim[k+1..ndim-1] * bytes. */
272
+ s = op->bytes;
273
+ for ( k = op->ndim - 1; k >= 0; k-- ) {
274
+ row_strides[k] = s;
275
+ s *= op->dim[k];
276
+ }
277
+ byte_off = 0;
278
+ for ( k = 0; k < op->ndim; k++ ) {
279
+ /* require sub-region fits within parent dim (= no OOB) */
280
+ if ( starts[k] < 0 || starts[k] + counts[k] > op->dim[k] ) return 0;
281
+ byte_off += starts[k] * row_strides[k];
282
+ }
283
+
284
+ *out_ptr = op->ptr + byte_off;
285
+ return 1;
286
+ }
287
+
288
+ static void
289
+ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
290
+ ca_size_t *strides, void *data, int dir)
291
+ {
292
+ CABinCmp *bc = (CABinCmp *) ap;
293
+ ca_size_t slab_n;
294
+ int8_t k;
295
+ void *left_scratch, *right_scratch;
296
+ ca_size_t operand_bytes;
297
+ ca_size_t right_step;
298
+ int left_is_inplace = 0; /* skip release for leaf-opt path */
299
+ int right_is_inplace = 0;
300
+
301
+ if ( dir != CA_XFER_GET ) {
302
+ rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_stride PUT)");
303
+ }
304
+ ca_bincmp_materialise_call_count++;
305
+
306
+ slab_n = 1;
307
+ for ( k = 0; k < bc->ndim; k++ ) slab_n *= counts[k];
308
+
309
+ operand_bytes = ca_sizeof[bc->common_dt];
310
+
311
+ /* === 1. pull LEFT (leaf in-place read or arena scratch) === */
312
+ {
313
+ char *left_inplace = NULL;
314
+ if ( ca_bincmp_try_leaf_inplace(bc->parent, bc->common_dt,
315
+ starts, counts, operand_bytes,
316
+ &left_inplace) ) {
317
+ /* Leaf-opt path: use parent->ptr + byte_offset directly. */
318
+ left_scratch = left_inplace;
319
+ left_is_inplace = 1;
320
+ ca_bincmp_leaf_inplace_count++;
321
+ }
322
+ else {
323
+ ca_size_t left_strides[CA_RANK_MAX];
324
+ ca_size_t s = operand_bytes;
325
+ for ( k = bc->ndim - 1; k >= 0; k-- ) {
326
+ left_strides[k] = s;
327
+ s *= counts[k];
328
+ }
329
+ left_scratch = ca_lazy_arena_acquire(slab_n * operand_bytes);
330
+ ca_bincmp_scratch_acquire_count++;
331
+ ca_xfer_stride(bc->parent, starts, counts, left_strides, left_scratch,
332
+ CA_XFER_GET);
333
+ }
334
+ }
335
+
336
+ /* === 2. pull RIGHT (right_is_scalar + leaf-opt) === */
337
+ if ( bc->right_is_scalar ) {
338
+ /* CScalar right: pull the single value into a 1-cell scratch
339
+ and walk the kernel with right_step=0. Leaf-opt applies when
340
+ right is an entity-shaped CScalar at the common data_type;
341
+ the gain per call is small but the code path stays uniform
342
+ with the same-shape case. */
343
+ char *right_inplace = NULL;
344
+ ca_size_t one_starts[CA_RANK_MAX] = {0};
345
+ ca_size_t one_counts[CA_RANK_MAX];
346
+ for ( k = 0; k < bc->right->ndim; k++ ) one_counts[k] = 1;
347
+
348
+ if ( ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
349
+ one_starts, one_counts, operand_bytes,
350
+ &right_inplace) ) {
351
+ right_scratch = right_inplace;
352
+ right_is_inplace = 1;
353
+ ca_bincmp_leaf_inplace_count++;
354
+ }
355
+ else {
356
+ ca_size_t one_strides[CA_RANK_MAX];
357
+ for ( k = 0; k < bc->right->ndim; k++ ) one_strides[k] = operand_bytes;
358
+ right_scratch = ca_lazy_arena_acquire(operand_bytes);
359
+ ca_bincmp_scratch_acquire_count++;
360
+ ca_xfer_stride(bc->right, one_starts, one_counts, one_strides,
361
+ right_scratch, CA_XFER_GET);
362
+ }
363
+ right_step = 0;
364
+ }
365
+ else {
366
+ /* Same-shape right: full slab pull or leaf-opt. */
367
+ char *right_inplace = NULL;
368
+ if ( ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
369
+ starts, counts, operand_bytes,
370
+ &right_inplace) ) {
371
+ right_scratch = right_inplace;
372
+ right_is_inplace = 1;
373
+ ca_bincmp_leaf_inplace_count++;
374
+ }
375
+ else {
376
+ ca_size_t right_strides[CA_RANK_MAX];
377
+ ca_size_t s = operand_bytes;
378
+ for ( k = bc->ndim - 1; k >= 0; k-- ) {
379
+ right_strides[k] = s;
380
+ s *= counts[k];
381
+ }
382
+ right_scratch = ca_lazy_arena_acquire(slab_n * operand_bytes);
383
+ ca_bincmp_scratch_acquire_count++;
384
+ ca_xfer_stride(bc->right, starts, counts, right_strides, right_scratch,
385
+ CA_XFER_GET);
386
+ }
387
+ right_step = 1;
388
+ }
389
+
390
+ /* === 3. apply bincmp kernel ===
391
+ *
392
+ * Kernel signature (ext/carray.h):
393
+ * fn(n, m, ptr1, b1, i1, ptr2, b2, i2, ptr3, b3, i3)
394
+ *
395
+ * Per inspection of generated ca_bincmp_<op>_<data_type>, the `b*` args
396
+ * are declared but unused (kernel computes ptr + k*i*sizeof(T)). We
397
+ * pass 0 for the base arguments.
398
+ *
399
+ * Non-trapping: m=NULL (= SIMD fast path). Mask propagation handled
400
+ * by create_mask at view construction time.
401
+ */
402
+ {
403
+ ca_bincmp_func_t fn = ca_bincmp_kernel_lookup(bc->op_id, bc->common_dt);
404
+ if ( fn == NULL ) {
405
+ if ( ! right_is_inplace ) ca_lazy_arena_release(right_scratch);
406
+ if ( ! left_is_inplace ) ca_lazy_arena_release(left_scratch);
407
+ rb_raise(rb_eNotImpError,
408
+ "CABinCmp: kernel not implemented (op_id=%u data_type=%d)",
409
+ (unsigned) bc->op_id, (int) bc->common_dt);
410
+ }
411
+ fn(slab_n, NULL,
412
+ (char *) left_scratch, 0, 1,
413
+ (char *) right_scratch, 0, right_step,
414
+ (char *) data, 0, 1,
415
+ bc->eps); /* Runtime tolerance for IS_CLOSE / IS_EQUIV. */
416
+ }
417
+
418
+ if ( ! right_is_inplace ) ca_lazy_arena_release(right_scratch);
419
+ if ( ! left_is_inplace ) ca_lazy_arena_release(left_scratch);
420
+ }
421
+
422
+ static void
423
+ ca_bincmp_func_xfer_all (void *ap, void *data, int dir)
424
+ {
425
+ CABinCmp *ca = (CABinCmp *) ap;
426
+ ca_size_t starts[CA_RANK_MAX];
427
+ ca_size_t native[CA_RANK_MAX];
428
+ int8_t k;
429
+ ca_size_t s = 1; /* output stride = 1 byte */
430
+ for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
431
+ for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
432
+ ca_xfer_stride(ca, starts, ca->dim, native, data, dir);
433
+ }
434
+
435
+ static void
436
+ ca_bincmp_func_allocate (void *ap)
437
+ {
438
+ CABinCmp *ca = (CABinCmp *) ap;
439
+ ca->ptr = xmalloc(ca_length(ca));
440
+ }
441
+
442
+ static void
443
+ ca_bincmp_func_attach (void *ap)
444
+ {
445
+ /* CAREFUL: call the view-specific xfer_stride directly here,
446
+ not the public ca_xfer_stride dispatcher. The dispatcher's
447
+ self-memcpy fast path detects data == ca->ptr and returns
448
+ without materialising, so the freshly-allocated buffer would
449
+ still hold garbage. */
450
+ CABinCmp *ca = (CABinCmp *) ap;
451
+ ca_size_t starts[CA_RANK_MAX];
452
+ ca_size_t native[CA_RANK_MAX];
453
+ int8_t k;
454
+ ca_size_t s;
455
+
456
+ ca->ptr = xmalloc(ca_length(ca));
457
+
458
+ s = ca->bytes;
459
+ for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
460
+ for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
461
+ ca_bincmp_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
462
+ }
463
+
464
+ static void
465
+ ca_bincmp_func_sync (void *ap)
466
+ {
467
+ /* read-only */
468
+ }
469
+
470
+ static void
471
+ ca_bincmp_func_detach (void *ap)
472
+ {
473
+ CABinCmp *ca = (CABinCmp *) ap;
474
+ xfree(ca->ptr);
475
+ ca->ptr = NULL;
476
+ }
477
+
478
+ NORETURN(static void ca_bincmp_func_fill_data (void *ap, void *ptr));
479
+ static void
480
+ ca_bincmp_func_fill_data (void *ap, void *ptr)
481
+ {
482
+ rb_raise(rb_eRuntimeError, "CABinCmp is read-only (fill_data)");
483
+ }
484
+
485
+ /* mask = left.mask | right.mask, materialised as boolean8_t.
486
+ Mirrors CABinOp's create_mask policy. */
487
+ static void
488
+ ca_bincmp_func_create_mask (void *ap)
489
+ {
490
+ CABinCmp *bc = (CABinCmp *) ap;
491
+ CArray *l = bc->parent;
492
+ CArray *r = bc->right;
493
+ CArray *lm = NULL, *rm = NULL;
494
+ boolean8_t *dst;
495
+ ca_size_t i, n;
496
+ int has_l, has_r;
497
+
498
+ has_l = ca_has_mask(l);
499
+ has_r = ca_has_mask(r);
500
+ if ( ! has_l && ! has_r ) return;
501
+
502
+ if ( has_l ) lm = l->mask;
503
+ if ( has_r ) rm = r->mask;
504
+
505
+ bc->mask = (CArray *) carray_new(CA_BOOLEAN, bc->ndim, bc->dim, 0, NULL);
506
+ dst = (boolean8_t *) bc->mask->ptr;
507
+ n = bc->elements;
508
+
509
+ if ( has_l ) ca_attach(lm);
510
+ if ( has_r ) ca_attach(rm);
511
+
512
+ for ( i = 0; i < n; i++ ) {
513
+ boolean8_t a = has_l ? ((boolean8_t *) lm->ptr)[i] : 0;
514
+ boolean8_t b = 0;
515
+ if ( has_r ) {
516
+ ca_size_t ri = bc->right_is_scalar ? 0 : i;
517
+ b = ((boolean8_t *) rm->ptr)[ri];
518
+ }
519
+ dst[i] = (boolean8_t)( a | b );
520
+ }
521
+
522
+ if ( has_l ) ca_detach(lm);
523
+ if ( has_r ) ca_detach(rm);
524
+ }
525
+
526
+ ca_operation_function_t ca_bincmp_func = {
527
+ -1,
528
+ CA_VIEW_ARRAY,
529
+ free_ca_bincmp,
530
+ ca_bincmp_func_clone,
531
+ ca_bincmp_func_allocate,
532
+ ca_bincmp_func_attach,
533
+ ca_bincmp_func_sync,
534
+ ca_bincmp_func_detach,
535
+ ca_bincmp_func_fill_data,
536
+ ca_bincmp_func_create_mask,
537
+ ca_bincmp_func_xfer_index,
538
+ ca_bincmp_func_xfer_addrs,
539
+ NULL,
540
+ ca_bincmp_func_xfer_stride,
541
+ ca_bincmp_func_xfer_all,
542
+ };
543
+
544
+ /* ------------------------------------------------------------------- */
545
+ /* Public builder (= lib/carray/lazy.rb dispatch entry) */
546
+ /* ------------------------------------------------------------------- */
547
+
548
+ static VALUE
549
+ collapse_marker (VALUE cary)
550
+ {
551
+ CArray *ca;
552
+ if ( ! rb_obj_is_carray(cary) ) return cary;
553
+ TypedData_Get_Struct(cary, CArray, &carray_data_type, ca);
554
+ if ( ca->obj_type == CA_OBJ_LAZY_MARKER ) {
555
+ return rb_ca_parent(cary);
556
+ }
557
+ return cary;
558
+ }
559
+
560
+ static VALUE
561
+ rb_ca_bincmp_new (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
562
+ {
563
+ volatile VALUE obj;
564
+ CArray *l, *r;
565
+ CABinCmp *ca;
566
+ rb_check_carray_object(l_cary);
567
+ rb_check_carray_object(r_cary);
568
+ TypedData_Get_Struct(l_cary, CArray, &carray_data_type, l);
569
+ TypedData_Get_Struct(r_cary, CArray, &carray_data_type, r);
570
+ ca = ca_bincmp_new(l, r, op_id, eps);
571
+ obj = ca_wrap_struct(ca);
572
+ rb_ca_set_parent(obj, l_cary);
573
+ rb_ivar_set(obj, rb_intern("__bincmp_right__"), r_cary);
574
+ return obj;
575
+ }
576
+
577
+ VALUE
578
+ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
579
+ {
580
+ CArray *l, *r;
581
+ int8_t l_in_dt, r_in_dt;
582
+ volatile VALUE l_resolved, r_resolved;
583
+
584
+ l_resolved = collapse_marker(l_cary);
585
+ r_resolved = collapse_marker(r_cary);
586
+
587
+ /* Scalar wrap — same policy as CABinOp. */
588
+ if ( ! rb_obj_is_carray(l_resolved) ) {
589
+ rb_check_carray_object(r_resolved);
590
+ TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
591
+ l_resolved = ca_lazy_wrap_scalar(l_resolved, r);
592
+ }
593
+ if ( ! rb_obj_is_carray(r_resolved) ) {
594
+ rb_check_carray_object(l_resolved);
595
+ TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
596
+ r_resolved = ca_lazy_wrap_scalar(r_resolved, l);
597
+ }
598
+
599
+ TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
600
+ TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
601
+
602
+ /* Cast both operands to the common data_type. */
603
+ ca_bincmp_kernel_input_data_types(op_id, l->data_type, r->data_type,
604
+ &l_in_dt, &r_in_dt);
605
+
606
+ if ( l_in_dt != l->data_type ) {
607
+ VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + l_in_dt);
608
+ l_resolved = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
609
+ rb_intern("__build__"), 2,
610
+ l_resolved, cast_op);
611
+ TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
612
+ }
613
+ if ( r_in_dt != r->data_type ) {
614
+ VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + r_in_dt);
615
+ r_resolved = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
616
+ rb_intern("__build__"), 2,
617
+ r_resolved, cast_op);
618
+ TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
619
+ }
620
+
621
+ /* Broadcast — same size-1-expansion logic as CABinOp. */
622
+ ca_broadcast_pair(&l_resolved, &r_resolved);
623
+ TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
624
+ TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
625
+
626
+ if ( l->elements != r->elements ) {
627
+ if ( r->elements == 1 && l->elements > 1 ) {
628
+ /* CScalar right: handled via right_is_scalar */
629
+ }
630
+ else if ( l->elements == 1 && r->elements > 1 ) {
631
+ /* Comparison ops commute under negation (LT/GT/LE/GE flip to
632
+ their counterpart, EQ/NE are commutative), but here we
633
+ broadcast the left scalar up instead of swapping, so op_id
634
+ does not need a flip table. */
635
+ ca_size_t count[CA_RANK_MAX];
636
+ int8_t k;
637
+ if ( r->ndim > l->ndim ) {
638
+ for ( k = 0; k < r->ndim - 1; k++ ) count[k] = 1;
639
+ count[r->ndim - 1] = 0;
640
+ l_resolved = rb_ca_repeat_new(l_resolved, r->ndim, count);
641
+ TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
642
+ }
643
+ l_resolved = ca_broadcast_view(l_resolved, r->ndim, r->dim);
644
+ TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
645
+ }
646
+ else {
647
+ rb_raise(rb_eArgError,
648
+ "CABinCmp: shape mismatch (%lld vs %lld) — only same-"
649
+ "ndim size-1 broadcast is supported; cross-ndim "
650
+ "promotion is not adopted in CArray",
651
+ (long long) l->elements, (long long) r->elements);
652
+ }
653
+ }
654
+
655
+ return rb_ca_bincmp_new(l_resolved, r_resolved, op_id, eps);
656
+ }
657
+
658
+ static VALUE
659
+ rb_ca_bincmp_s_build (int argc, VALUE *argv, VALUE klass)
660
+ {
661
+ VALUE l_cary, r_cary, op_id_val, eps_val;
662
+ uint16_t op_id;
663
+ double eps = 0.0;
664
+ (void) klass;
665
+ rb_scan_args(argc, argv, "31", &l_cary, &r_cary, &op_id_val, &eps_val);
666
+ op_id = (uint16_t) NUM2UINT(op_id_val);
667
+ if ( argc >= 4 ) eps = NUM2DBL(eps_val);
668
+ return rb_ca_bincmp_build(l_cary, r_cary, op_id, eps);
669
+ }
670
+
671
+ static VALUE
672
+ rb_ca_bincmp_op_id (VALUE self)
673
+ {
674
+ CABinCmp *bc;
675
+ TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, bc);
676
+ return UINT2NUM(bc->op_id);
677
+ }
678
+
679
+ static VALUE
680
+ rb_ca_bincmp_right (VALUE self)
681
+ {
682
+ return rb_ivar_get(self, rb_intern("__bincmp_right__"));
683
+ }
684
+
685
+ static VALUE
686
+ rb_ca_bincmp_eps (VALUE self)
687
+ {
688
+ CABinCmp *bc;
689
+ TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, bc);
690
+ return rb_float_new(bc->eps);
691
+ }
692
+
693
+ static VALUE
694
+ rb_ca_bincmp_s_reset_scratch_counter (VALUE klass)
695
+ {
696
+ (void) klass;
697
+ ca_bincmp_scratch_acquire_count = 0;
698
+ return Qnil;
699
+ }
700
+
701
+ static VALUE
702
+ rb_ca_bincmp_s_scratch_count (VALUE klass)
703
+ {
704
+ (void) klass;
705
+ return SIZE2NUM(ca_bincmp_scratch_acquire_count);
706
+ }
707
+
708
+ static VALUE
709
+ rb_ca_bincmp_s_reset_materialise_counter (VALUE klass)
710
+ {
711
+ (void) klass;
712
+ ca_bincmp_materialise_call_count = 0;
713
+ return Qnil;
714
+ }
715
+
716
+ static VALUE
717
+ rb_ca_bincmp_s_materialise_count (VALUE klass)
718
+ {
719
+ (void) klass;
720
+ return SIZE2NUM(ca_bincmp_materialise_call_count);
721
+ }
722
+
723
+ static VALUE
724
+ rb_ca_bincmp_s_reset_leaf_inplace_counter (VALUE klass)
725
+ {
726
+ (void) klass;
727
+ ca_bincmp_leaf_inplace_count = 0;
728
+ return Qnil;
729
+ }
730
+
731
+ static VALUE
732
+ rb_ca_bincmp_s_leaf_inplace_count (VALUE klass)
733
+ {
734
+ (void) klass;
735
+ return SIZE2NUM(ca_bincmp_leaf_inplace_count);
736
+ }
737
+
738
+ static VALUE
739
+ rb_ca_bincmp_s_allocate (VALUE klass)
740
+ {
741
+ CABinCmp *ca;
742
+ return TypedData_Make_Struct(klass, CABinCmp, &cabincmp_data_type, ca);
743
+ }
744
+
745
+ static VALUE
746
+ rb_ca_bincmp_initialize_copy (VALUE self, VALUE other)
747
+ {
748
+ CABinCmp *ca, *cs;
749
+ TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, ca);
750
+ TypedData_Get_Struct(other, CABinCmp, &cabincmp_data_type, cs);
751
+ if ( ca_func[CA_OBJ_BINCMP].pool_init ) {
752
+ ca_array_pool_alloc(ca, CA_OBJ_BINCMP, cs->parent->ndim);
753
+ }
754
+ ca_bincmp_setup(ca, cs->parent, cs->right, cs->op_id, cs->eps);
755
+ return self;
756
+ }
757
+
758
+ void
759
+ Init_ca_obj_bincmp (void)
760
+ {
761
+ rb_cCABinCmp = rb_define_class("CABinCmp", rb_cCAView);
762
+
763
+ ca_bincmp_func.struct_size = sizeof(CABinCmp);
764
+ ca_bincmp_func.pool_bytes = ca_bincmp_pool_bytes;
765
+ ca_bincmp_func.pool_init = ca_bincmp_pool_init;
766
+
767
+ CA_OBJ_BINCMP = ca_install_obj_type(rb_cCABinCmp,
768
+ &cabincmp_data_type,
769
+ rb_cCArrayMask,
770
+ &carray_mask_data_type, &ca_bincmp_func, sizeof(ca_bincmp_func));
771
+ rb_define_const(rb_cObject, "CA_OBJ_BINCMP", INT2NUM(CA_OBJ_BINCMP));
772
+
773
+ /* op_id constants shared with lib/carray/lazy.rb. */
774
+ rb_define_const(rb_cCABinCmp, "OP_LT", INT2NUM(CA_BINCMP_LT));
775
+ rb_define_const(rb_cCABinCmp, "OP_GT", INT2NUM(CA_BINCMP_GT));
776
+ rb_define_const(rb_cCABinCmp, "OP_LE", INT2NUM(CA_BINCMP_LE));
777
+ rb_define_const(rb_cCABinCmp, "OP_GE", INT2NUM(CA_BINCMP_GE));
778
+ rb_define_const(rb_cCABinCmp, "OP_EQ", INT2NUM(CA_BINCMP_EQ));
779
+ rb_define_const(rb_cCABinCmp, "OP_NE", INT2NUM(CA_BINCMP_NE));
780
+ rb_define_const(rb_cCABinCmp, "OP_FEQ", INT2NUM(CA_BINCMP_FEQ));
781
+ rb_define_const(rb_cCABinCmp, "OP_IS_CLOSE", INT2NUM(CA_BINCMP_IS_CLOSE));
782
+ rb_define_const(rb_cCABinCmp, "OP_IS_EQUIV", INT2NUM(CA_BINCMP_IS_EQUIV));
783
+
784
+ rb_define_alloc_func(rb_cCABinCmp, rb_ca_bincmp_s_allocate);
785
+ rb_define_method(rb_cCABinCmp, "initialize_copy",
786
+ rb_ca_bincmp_initialize_copy, 1);
787
+
788
+ /* __build__(left, right, op_id [, eps]) */
789
+ rb_define_singleton_method(rb_cCABinCmp, "__build__",
790
+ rb_ca_bincmp_s_build, -1);
791
+
792
+ rb_define_method(rb_cCABinCmp, "__op_id__", rb_ca_bincmp_op_id, 0);
793
+ rb_define_method(rb_cCABinCmp, "__bincmp_right__",
794
+ rb_ca_bincmp_right, 0);
795
+ rb_define_method(rb_cCABinCmp, "__eps__", rb_ca_bincmp_eps, 0);
796
+
797
+ rb_define_singleton_method(rb_cCABinCmp, "__reset_scratch_counter__",
798
+ rb_ca_bincmp_s_reset_scratch_counter, 0);
799
+ rb_define_singleton_method(rb_cCABinCmp, "__scratch_count__",
800
+ rb_ca_bincmp_s_scratch_count, 0);
801
+ rb_define_singleton_method(rb_cCABinCmp, "__reset_materialise_counter__",
802
+ rb_ca_bincmp_s_reset_materialise_counter, 0);
803
+ rb_define_singleton_method(rb_cCABinCmp, "__materialise_count__",
804
+ rb_ca_bincmp_s_materialise_count, 0);
805
+ rb_define_singleton_method(rb_cCABinCmp, "__reset_leaf_inplace_counter__",
806
+ rb_ca_bincmp_s_reset_leaf_inplace_counter, 0);
807
+ rb_define_singleton_method(rb_cCABinCmp, "__leaf_inplace_count__",
808
+ rb_ca_bincmp_s_leaf_inplace_count, 0);
809
+ }