carray 2.0.1 → 3.0.1

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 (386) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -25
  3. data/CHANGELOG.md +338 -0
  4. data/{NEWS.md → CHANGELOG.v1.md} +3 -0
  5. data/LICENSE +1 -1
  6. data/README.md +120 -36
  7. data/carray.gemspec +32 -30
  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 +1244 -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 +124 -0
  15. data/ext/ca_binop_dispatch.h +152 -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 +239 -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 +4367 -0
  26. data/ext/ca_kernel_iterator.h +2596 -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 +839 -0
  33. data/ext/ca_obj_binop.c +948 -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 +967 -0
  39. data/ext/ca_obj_face.c +750 -0
  40. data/ext/ca_obj_face.h +279 -0
  41. data/ext/ca_obj_fake.c +239 -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 +308 -0
  45. data/ext/ca_obj_grid.c +866 -440
  46. data/ext/ca_obj_meld.c +1039 -0
  47. data/ext/ca_obj_moncmp.c +588 -0
  48. data/ext/ca_obj_monop.c +1123 -0
  49. data/ext/ca_obj_object.c +866 -296
  50. data/ext/ca_obj_record.c +470 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +593 -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 +624 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1306 -0
  58. data/ext/ca_obj_shift.c +231 -793
  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 +2584 -0
  62. data/ext/ca_obj_string.c +270 -0
  63. data/ext/ca_obj_tile.c +622 -0
  64. data/ext/ca_obj_time.c +548 -0
  65. data/ext/ca_obj_timedelta.c +437 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +785 -0
  68. data/ext/ca_obj_window.c +1202 -565
  69. data/ext/ca_op_byte_swap.c +175 -0
  70. data/ext/ca_op_cmplx64.h +123 -0
  71. data/ext/ca_op_ipower.c +316 -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 +473 -0
  75. data/ext/ca_sweep_engine.h +166 -0
  76. data/ext/ca_transform_common.c +235 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +810 -420
  80. data/ext/carray_access.c +873 -731
  81. data/ext/carray_attribute.c +98 -329
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +376 -0
  84. data/ext/carray_build_flags.h +3 -0
  85. data/ext/carray_call_cfunc.c +2897 -874
  86. data/ext/carray_call_cfunc.h +313 -0
  87. data/ext/carray_cast.c +1264 -315
  88. data/ext/carray_cast_func.rb +81 -40
  89. data/ext/carray_class.c +53 -63
  90. data/ext/carray_config.h +28 -0
  91. data/ext/carray_conversion.c +350 -346
  92. data/ext/carray_copy.c +168 -270
  93. data/ext/carray_core.c +1396 -206
  94. data/ext/carray_count.c +312 -0
  95. data/ext/carray_data_type.c +43 -19
  96. data/ext/carray_element.c +585 -213
  97. data/ext/carray_factorize.c +2542 -0
  98. data/ext/carray_generate.c +230 -559
  99. data/ext/carray_histogram.c +490 -0
  100. data/ext/carray_hold.c +228 -0
  101. data/ext/carray_index_classifier.c +1021 -0
  102. data/ext/carray_index_classifier.h +27 -0
  103. data/ext/carray_internal.h +136 -0
  104. data/ext/carray_kernels_bincmp.c +4446 -0
  105. data/ext/carray_kernels_binop.c +11001 -0
  106. data/ext/carray_kernels_init.c +1131 -0
  107. data/ext/carray_kernels_map.c +3467 -0
  108. data/ext/carray_kernels_moncmp.c +2097 -0
  109. data/ext/carray_kernels_monop.c +18313 -0
  110. data/ext/carray_kernels_reduce_aggregate.c +25837 -0
  111. data/ext/carray_kernels_reduce_boolean.c +330 -0
  112. data/ext/carray_kernels_reduce_cumulative.c +14593 -0
  113. data/ext/carray_kernels_reduce_extreme.c +16948 -0
  114. data/ext/carray_kernels_reduce_variance.c +3910 -0
  115. data/ext/carray_kernels_scan.c +3693 -0
  116. data/ext/carray_kernels_search.c +32138 -0
  117. data/ext/carray_kernels_sort.c +10626 -0
  118. data/ext/carray_kernels_triop.c +1392 -0
  119. data/ext/carray_lazy.c +737 -0
  120. data/ext/carray_loop.c +88 -200
  121. data/ext/carray_mask.c +853 -158
  122. data/ext/carray_math_kernel.h +120 -0
  123. data/ext/carray_mathfunc.c +10 -241
  124. data/ext/carray_median_percentile.c +1257 -0
  125. data/ext/carray_memory_view.c +1650 -0
  126. data/ext/carray_operator.c +1525 -320
  127. data/ext/carray_order.c +664 -1394
  128. data/ext/carray_partition.c +416 -0
  129. data/ext/carray_random.c +518 -0
  130. data/ext/carray_scatter.c +357 -0
  131. data/ext/carray_slab.c +1219 -0
  132. data/ext/carray_slab.h +84 -0
  133. data/ext/carray_sort.c +829 -0
  134. data/ext/carray_sort_kernel.c +620 -0
  135. data/ext/carray_struct.c +695 -0
  136. data/ext/carray_test.c +343 -229
  137. data/ext/carray_undef.c +34 -17
  138. data/ext/carray_utils.c +175 -74
  139. data/ext/extconf.rb +234 -55
  140. data/ext/mk_call_cfunc.rb +671 -0
  141. data/ext/mkkernel.rb +9096 -0
  142. data/ext/ruby_carray.c +211 -108
  143. data/ext/version.h +4 -14
  144. data/ext/version.rb +5 -13
  145. data/lib/carray/arrow_tensor.rb +401 -0
  146. data/lib/carray/attribute.rb +166 -0
  147. data/lib/carray/autoload_carray.rb +239 -0
  148. data/lib/carray/autoload_method_extension.rb +45 -0
  149. data/lib/carray/axis_group.rb +711 -0
  150. data/lib/carray/basics.rb +481 -0
  151. data/lib/carray/bincount_nd.rb +358 -0
  152. data/lib/carray/block_iterator.rb +614 -0
  153. data/lib/carray/boolean_reduce.rb +109 -0
  154. data/lib/carray/categorical.rb +561 -0
  155. data/lib/carray/categorical_iterator.rb +1084 -0
  156. data/lib/carray/complex.rb +150 -0
  157. data/lib/carray/conditional.rb +216 -0
  158. data/lib/carray/const_string.rb +228 -0
  159. data/lib/carray/construct.rb +160 -328
  160. data/lib/carray/core_extensions.rb +297 -0
  161. data/lib/carray/data_type_extension.rb +250 -0
  162. data/lib/carray/fixlen_string.rb +95 -0
  163. data/lib/carray/frame/concat.rb +132 -0
  164. data/lib/carray/frame/convert.rb +95 -0
  165. data/lib/carray/frame/csv_parser.rb +211 -0
  166. data/lib/carray/frame/frame.rb +642 -0
  167. data/lib/carray/frame/group.rb +186 -0
  168. data/lib/carray/frame/io.rb +321 -0
  169. data/lib/carray/frame/join.rb +248 -0
  170. data/lib/carray/frame/records.rb +99 -0
  171. data/lib/carray/frame/sort.rb +113 -0
  172. data/lib/carray/frame/verbs.rb +316 -0
  173. data/lib/carray/frame.rb +16 -0
  174. data/lib/carray/fuse_source.rb +123 -0
  175. data/lib/carray/fusion.rb +218 -0
  176. data/lib/carray/histogram.rb +512 -0
  177. data/lib/carray/inspect.rb +37 -26
  178. data/lib/carray/iterator.rb +58 -349
  179. data/lib/carray/lazy.rb +941 -0
  180. data/lib/carray/mask_gap_fill.rb +200 -0
  181. data/lib/carray/math.rb +78 -342
  182. data/lib/carray/meld_reduce.rb +289 -0
  183. data/lib/carray/methods/align_addr.rb +116 -0
  184. data/lib/carray/methods/bin.rb +128 -0
  185. data/lib/carray/methods/bincount.rb +87 -0
  186. data/lib/carray/methods/bit_string.rb +92 -0
  187. data/lib/carray/methods/broadcast.rb +63 -0
  188. data/lib/carray/methods/choose.rb +39 -0
  189. data/lib/carray/methods/composition.rb +280 -0
  190. data/lib/carray/methods/gather_nd.rb +206 -0
  191. data/lib/carray/methods/index.rb +39 -0
  192. data/lib/carray/methods/insert_block.rb +99 -0
  193. data/lib/carray/methods/is_in.rb +141 -0
  194. data/lib/carray/methods/join.rb +90 -0
  195. data/lib/carray/methods/locate_addr.rb +52 -0
  196. data/lib/carray/methods/mask_duplicates.rb +41 -0
  197. data/lib/carray/methods/meshgrid.rb +90 -0
  198. data/lib/carray/methods/mode.rb +126 -0
  199. data/lib/carray/methods/nunique.rb +46 -0
  200. data/lib/carray/methods/resize.rb +56 -0
  201. data/lib/carray/methods/snap.rb +161 -0
  202. data/lib/carray/methods/string_format.rb +57 -0
  203. data/lib/carray/methods/unique.rb +47 -0
  204. data/lib/carray/methods/value_counts.rb +71 -0
  205. data/lib/carray/mkmf.rb +124 -101
  206. data/lib/carray/runtime.rb +89 -0
  207. data/lib/carray/serialize.rb +478 -167
  208. data/lib/carray/slab_iterator.rb +305 -0
  209. data/lib/carray/stack.rb +291 -0
  210. data/lib/carray/string.rb +56 -180
  211. data/lib/carray/string_operation_extension.rb +289 -0
  212. data/lib/carray/struct.rb +335 -323
  213. data/lib/carray/struct_builder.rb +697 -0
  214. data/lib/carray/table.rb +41 -2
  215. data/lib/carray/time.rb +2654 -38
  216. data/lib/carray/window_iterator.rb +927 -0
  217. data/lib/carray.rb +55 -57
  218. data/yard-stubs/ca_obj_array.rb +385 -0
  219. data/yard-stubs/ca_obj_bitarray.rb +38 -0
  220. data/yard-stubs/ca_obj_bitfield.rb +43 -0
  221. data/yard-stubs/ca_obj_block.rb +73 -0
  222. data/yard-stubs/ca_obj_byte_swap.rb +56 -0
  223. data/yard-stubs/ca_obj_fake.rb +31 -0
  224. data/yard-stubs/ca_obj_farray.rb +32 -0
  225. data/yard-stubs/ca_obj_field.rb +45 -0
  226. data/yard-stubs/ca_obj_grid.rb +35 -0
  227. data/yard-stubs/ca_obj_refer.rb +72 -0
  228. data/yard-stubs/ca_obj_roll.rb +45 -0
  229. data/yard-stubs/ca_obj_shift.rb +43 -0
  230. data/yard-stubs/ca_obj_stride.rb +181 -0
  231. data/yard-stubs/ca_obj_tile.rb +29 -0
  232. data/yard-stubs/ca_obj_transpose.rb +40 -0
  233. data/yard-stubs/ca_obj_window.rb +49 -0
  234. data/yard-stubs/carray_access.rb +131 -0
  235. data/yard-stubs/carray_attribute.rb +246 -0
  236. data/yard-stubs/carray_broadcast.rb +37 -0
  237. data/yard-stubs/carray_cast.rb +489 -0
  238. data/yard-stubs/carray_class.rb +65 -0
  239. data/yard-stubs/carray_conversion.rb +76 -0
  240. data/yard-stubs/carray_copy.rb +79 -0
  241. data/yard-stubs/carray_core.rb +114 -0
  242. data/yard-stubs/carray_count.rb +79 -0
  243. data/yard-stubs/carray_element.rb +108 -0
  244. data/yard-stubs/carray_generate.rb +66 -0
  245. data/yard-stubs/carray_lazy.rb +23 -0
  246. data/yard-stubs/carray_loop.rb +140 -0
  247. data/yard-stubs/carray_mask.rb +259 -0
  248. data/yard-stubs/carray_math.rb +132 -0
  249. data/yard-stubs/carray_mathfunc.rb +45 -0
  250. data/yard-stubs/carray_median_percentile.rb +89 -0
  251. data/yard-stubs/carray_memory_view.rb +163 -0
  252. data/yard-stubs/carray_order.rb +312 -0
  253. data/yard-stubs/carray_random.rb +89 -0
  254. data/yard-stubs/carray_scatter.rb +106 -0
  255. data/yard-stubs/carray_slab.rb +57 -0
  256. data/yard-stubs/carray_sort.rb +163 -0
  257. data/yard-stubs/carray_test.rb +85 -0
  258. data/yard-stubs/carray_undef.rb +64 -0
  259. data/yard-stubs/carray_utils.rb +97 -0
  260. data/yard-stubs/ruby_carray.rb +193 -0
  261. metadata +220 -138
  262. data/Rakefile +0 -51
  263. data/TODO.md +0 -18
  264. data/ext/ca_iter_block.c +0 -257
  265. data/ext/ca_iter_dimension.c +0 -299
  266. data/ext/ca_iter_window.c +0 -214
  267. data/ext/ca_obj_mapping.c +0 -644
  268. data/ext/ca_obj_unbound_repeat.c +0 -529
  269. data/ext/carray_iterator.c +0 -641
  270. data/ext/carray_math.rb +0 -850
  271. data/ext/carray_numeric.c +0 -259
  272. data/ext/carray_sort_addr.c +0 -254
  273. data/ext/carray_stat.c +0 -2100
  274. data/ext/carray_stat_proc.rb +0 -1999
  275. data/ext/mkmath.rb +0 -741
  276. data/ext/ruby_ccomplex.c +0 -509
  277. data/ext/ruby_float_func.c +0 -86
  278. data/lib/carray/array.rb +0 -8
  279. data/lib/carray/autoload/autoload_base.rb +0 -19
  280. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  281. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  282. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  283. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  284. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  285. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  286. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  287. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  288. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  289. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  290. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  291. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  292. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  293. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  294. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  295. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  296. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  297. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  298. data/lib/carray/autoload.rb +0 -141
  299. data/lib/carray/basic.rb +0 -191
  300. data/lib/carray/broadcast.rb +0 -101
  301. data/lib/carray/compose.rb +0 -315
  302. data/lib/carray/convert.rb +0 -115
  303. data/lib/carray/info.rb +0 -110
  304. data/lib/carray/io/imagemagick.rb +0 -235
  305. data/lib/carray/mask.rb +0 -102
  306. data/lib/carray/math/histogram.rb +0 -177
  307. data/lib/carray/math/recurrence.rb +0 -93
  308. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  309. data/lib/carray/object/ca_obj_link.rb +0 -50
  310. data/lib/carray/object/ca_obj_pack.rb +0 -99
  311. data/lib/carray/obsolete.rb +0 -256
  312. data/lib/carray/ordering.rb +0 -181
  313. data/lib/carray/testing.rb +0 -51
  314. data/lib/carray/transform.rb +0 -109
  315. data/mailmap +0 -1
  316. data/misc/Methods.ja.md +0 -182
  317. data/misc/NOTE +0 -51
  318. data/spec/Classes/CABitfield_spec.rb +0 -58
  319. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  320. data/spec/Classes/CABlock_spec.rb +0 -205
  321. data/spec/Classes/CAField_spec.rb +0 -39
  322. data/spec/Classes/CAGrid_spec.rb +0 -75
  323. data/spec/Classes/CAMap_spec.rb +0 -0
  324. data/spec/Classes/CAMapping_spec.rb +0 -105
  325. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  326. data/spec/Classes/CAObject_spec.rb +0 -33
  327. data/spec/Classes/CARefer_spec.rb +0 -93
  328. data/spec/Classes/CARepeat_spec.rb +0 -65
  329. data/spec/Classes/CASelect_spec.rb +0 -22
  330. data/spec/Classes/CAShift_spec.rb +0 -16
  331. data/spec/Classes/CAStruct_spec.rb +0 -71
  332. data/spec/Classes/CATranspose_spec.rb +0 -60
  333. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  334. data/spec/Classes/CAWindow_spec.rb +0 -54
  335. data/spec/Classes/CAWrap_spec.rb +0 -8
  336. data/spec/Classes/CArray_spec.rb +0 -184
  337. data/spec/Classes/CScalar_spec.rb +0 -55
  338. data/spec/Features/feature_130_spec.rb +0 -19
  339. data/spec/Features/feature_attributes_spec.rb +0 -280
  340. data/spec/Features/feature_boolean_spec.rb +0 -98
  341. data/spec/Features/feature_broadcast.rb +0 -116
  342. data/spec/Features/feature_cast_function.rb +0 -19
  343. data/spec/Features/feature_cast_spec.rb +0 -33
  344. data/spec/Features/feature_class_spec.rb +0 -84
  345. data/spec/Features/feature_complex_spec.rb +0 -42
  346. data/spec/Features/feature_composite_spec.rb +0 -124
  347. data/spec/Features/feature_convert_spec.rb +0 -46
  348. data/spec/Features/feature_copy_spec.rb +0 -123
  349. data/spec/Features/feature_creation_spec.rb +0 -84
  350. data/spec/Features/feature_element_spec.rb +0 -144
  351. data/spec/Features/feature_extream_spec.rb +0 -54
  352. data/spec/Features/feature_generate_spec.rb +0 -74
  353. data/spec/Features/feature_index_spec.rb +0 -69
  354. data/spec/Features/feature_mask_spec.rb +0 -580
  355. data/spec/Features/feature_math_spec.rb +0 -97
  356. data/spec/Features/feature_order_spec.rb +0 -146
  357. data/spec/Features/feature_ref_store_spec.rb +0 -209
  358. data/spec/Features/feature_serialization_spec.rb +0 -125
  359. data/spec/Features/feature_stat_spec.rb +0 -397
  360. data/spec/Features/feature_virtual_spec.rb +0 -48
  361. data/spec/Features/method_eq_spec.rb +0 -81
  362. data/spec/Features/method_is_nan_spec.rb +0 -12
  363. data/spec/Features/method_map_spec.rb +0 -54
  364. data/spec/Features/method_max_with.rb +0 -20
  365. data/spec/Features/method_min_with.rb +0 -19
  366. data/spec/Features/method_ne_spec.rb +0 -18
  367. data/spec/Features/method_project_spec.rb +0 -188
  368. data/spec/Features/method_ref_spec.rb +0 -27
  369. data/spec/Features/method_round_spec.rb +0 -11
  370. data/spec/Features/method_s_linspace_spec.rb +0 -48
  371. data/spec/Features/method_s_span_spec.rb +0 -14
  372. data/spec/Features/method_seq_spec.rb +0 -47
  373. data/spec/Features/method_sort_with.rb +0 -43
  374. data/spec/Features/method_sorted_with.rb +0 -29
  375. data/spec/Features/method_span_spec.rb +0 -42
  376. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  377. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  378. data/spec/spec_all.rb +0 -10
  379. data/utils/ca_ase.rb +0 -21
  380. data/utils/ca_methods.rb +0 -15
  381. data/utils/cast_checker.rb +0 -30
  382. data/utils/convert_test.rb +0 -73
  383. data/utils/extract_yard.rb +0 -22
  384. data/utils/guess_shape.rb +0 -76
  385. data/utils/monkey_patch_methods.rb +0 -62
  386. data/utils/remove_resource_fork.sh +0 -5
data/ext/carray_cast.c CHANGED
@@ -1,14 +1,39 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
 
3
- carray_cast.c
4
-
5
- This file is part of Ruby/CArray extension library.
6
-
7
- Copyright (C) 2005-2025 Hiroki Motoyoshi
3
+ Cast surface (3 layers):
4
+
5
+ <type> `a.int32` etc., and the general `a.to_type(:int32)`.
6
+ Returns a fresh entity CArray of the target
7
+ data_type. Independent storage from `self`. (The
8
+ C functions are named rb_ca_to_<type>, but the
9
+ methods they register carry no `to_` prefix.)
10
+
11
+ as_<type> `a.as_int32` etc. Returns a writable CAMonOp view
12
+ that reinterprets `self` cell-by-cell at the target
13
+ data_type. No new storage.
14
+
15
+ CA_<TYPE>(data)
16
+ `CA_INT32(data)`, `CA_FLOAT64(data)`, ...,
17
+ `CA_OBJECT(data)`, `CA_FIXLEN(...)` — global
18
+ polymorphic cast functions (registered at file
19
+ bottom via rb_define_global_function). Coerce
20
+ `data` (Numeric / Array / CArray / Range /
21
+ String / nil / object responding to `to_ca` /
22
+ `to_a`) into a CArray of the target data_type,
23
+ dispatching on `data`'s Ruby class. Type-name
24
+ aliases (CA_BYTE / CA_INT / CA_FLOAT / CA_SIZE /
25
+ ...) reuse the canonical entry.
26
+
27
+ Sibling of ext/carray_data_type.c (type-tag class shells +
28
+ data_type id <-> class mapping); the CA_<TYPE>(data) functions
29
+ here pair with the typed classes registered there.
8
30
 
9
31
  ---------------------------------------------------------------------------- */
10
32
 
11
33
  #include "carray.h"
34
+ #include "ruby/memory_view.h"
35
+ #include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE for as_type routing */
36
+ #include "ca_obj_face.h" /* ca_strip_face for write path lift */
12
37
 
13
38
  boolean8_t
14
39
  OBJ2BOOL (VALUE v)
@@ -38,6 +63,36 @@ BOOL2OBJ (boolean8_t x)
38
63
  return ( x != 0 ) ? INT2NUM(1) : INT2NUM(0);
39
64
  }
40
65
 
66
+ /* Recognise an explicit non-finite float literal. `str` must already be
67
+ whitespace-stripped. The whole token is matched case-insensitively as an
68
+ exact match (not a prefix): only nan / inf / infinity with an optional
69
+ +/- sign map to a non-finite value. Returns 1 and sets *out on a match,
70
+ 0 otherwise -- so "nancy" / "info" / "inflation" fall through to the
71
+ numeric parser instead of being read as NaN/Infinity. */
72
+ static int
73
+ ca_str_nonfinite (const char *str, double *out)
74
+ {
75
+ if ( ! strcasecmp(str, "nan")
76
+ || ! strcasecmp(str, "+nan")
77
+ || ! strcasecmp(str, "-nan") ) {
78
+ *out = 0.0/0.0;
79
+ return 1;
80
+ }
81
+ else if ( ! strcasecmp(str, "inf")
82
+ || ! strcasecmp(str, "+inf")
83
+ || ! strcasecmp(str, "infinity")
84
+ || ! strcasecmp(str, "+infinity") ) {
85
+ *out = 1.0/0.0;
86
+ return 1;
87
+ }
88
+ else if ( ! strcasecmp(str, "-inf")
89
+ || ! strcasecmp(str, "-infinity") ) {
90
+ *out = -1.0/0.0;
91
+ return 1;
92
+ }
93
+ return 0;
94
+ }
95
+
41
96
  double
42
97
  OBJ2DBL (VALUE val)
43
98
  {
@@ -46,30 +101,160 @@ OBJ2DBL (VALUE val)
46
101
  return NUM2DBL(val);
47
102
  case T_NIL:
48
103
  return 0.0/0.0;
49
- /* rb_raise(rb_eTypeError, "no implicit conversion to float from nil"); */
50
- break;
51
104
  case T_STRING: {
105
+ double d;
52
106
  volatile VALUE rstr = rb_funcall(val, rb_intern("strip"), 0);
53
107
  char *str = StringValuePtr(rstr);
54
- if ( ! strncasecmp("nan", str, 3) ) {
55
- return 0.0/0.0;
108
+ if ( ca_str_nonfinite(str, &d) ) {
109
+ return d;
56
110
  }
57
- else if ( ! strncasecmp("inf", str, 3) ) {
58
- return 1.0/0.0;
111
+ return rb_cstr_to_dbl(str, 0);
112
+ }
113
+ default:
114
+ return NUM2DBL(rb_Float(val));
115
+ }
116
+ }
117
+
118
+ /* rb_protect bodies: Kernel#Float / Kernel#Integer applied to one value.
119
+ Used by the mask-aware object->numeric parsers below so a conversion
120
+ error is caught (and turned into a masked cell) rather than raised. */
121
+ static VALUE
122
+ ca_kernel_float (VALUE v)
123
+ {
124
+ return rb_Float(v);
125
+ }
126
+
127
+ static VALUE
128
+ ca_kernel_integer (VALUE v)
129
+ {
130
+ return rb_Integer(v);
131
+ }
132
+
133
+ /* Object -> double with parse-failure signalling. Returns 1 and sets *out
134
+ on success; returns 0 when the cell cannot be parsed, in which case the
135
+ caller writes UNDEF (mask) for that cell. nil and unparseable
136
+ strings/objects fail; already-numeric values and explicit nan/inf
137
+ literals succeed. Strictness mirrors Ruby Float() (whitespace strip,
138
+ "1e3" ok, ...) but a bad token masks instead of raising. */
139
+ int
140
+ ca_obj2dbl_ok (VALUE val, double *out)
141
+ {
142
+ if ( NIL_P(val) ) {
143
+ return 0;
144
+ }
145
+ if ( RB_FLOAT_TYPE_P(val) || RB_INTEGER_TYPE_P(val) ) {
146
+ *out = NUM2DBL(val);
147
+ return 1;
148
+ }
149
+ if ( RB_TYPE_P(val, T_STRING) ) {
150
+ volatile VALUE rstr = rb_funcall(val, rb_intern("strip"), 0);
151
+ if ( ca_str_nonfinite(StringValuePtr(rstr), out) ) {
152
+ return 1;
59
153
  }
60
- else if ( ! strncasecmp("-inf", str, 4) ) {
61
- return -1.0/0.0;
154
+ }
155
+ {
156
+ int state = 0;
157
+ volatile VALUE r = rb_protect(ca_kernel_float, val, &state);
158
+ if ( state ) {
159
+ rb_set_errinfo(Qnil);
160
+ return 0;
62
161
  }
63
- else if ( ! strncasecmp("infinity", str, 8) ) {
64
- return 1.0/0.0;
162
+ *out = NUM2DBL(r);
163
+ return 1;
164
+ }
165
+ }
166
+
167
+ /* Object -> integer with parse-failure signalling (int/long lane). Same
168
+ contract as ca_obj2dbl_ok: 1 + *out on success, 0 (mask) on failure.
169
+ Strictness mirrors Ruby Integer() -- a non-integer string ("1.5") fails
170
+ (no truncation), nil fails, "0xff"/"1_000" parse. A valid Integer that
171
+ overflows the widest C integer still raises (a domain error, not a parse
172
+ failure). */
173
+ int
174
+ rb_obj2long_ok (VALUE val, long *out)
175
+ {
176
+ if ( NIL_P(val) ) {
177
+ return 0;
178
+ }
179
+ if ( RB_TYPE_P(val, T_FIXNUM) ) {
180
+ *out = NUM2LONG(val);
181
+ return 1;
182
+ }
183
+ {
184
+ int state = 0;
185
+ volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
186
+ if ( state ) {
187
+ rb_set_errinfo(Qnil);
188
+ return 0;
65
189
  }
66
- else if ( ! strncasecmp("-infinity", str, 9) ) {
67
- return -1.0/0.0;
190
+ *out = NUM2LONG(r);
191
+ return 1;
192
+ }
193
+ }
194
+
195
+ int
196
+ rb_obj2ulong_ok (VALUE val, unsigned long *out)
197
+ {
198
+ if ( NIL_P(val) ) {
199
+ return 0;
200
+ }
201
+ if ( RB_TYPE_P(val, T_FIXNUM) ) {
202
+ *out = NUM2ULONG(val);
203
+ return 1;
204
+ }
205
+ {
206
+ int state = 0;
207
+ volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
208
+ if ( state ) {
209
+ rb_set_errinfo(Qnil);
210
+ return 0;
68
211
  }
69
- return rb_cstr_to_dbl(str, 0);
212
+ *out = NUM2ULONG(r);
213
+ return 1;
70
214
  }
71
- default:
72
- return NUM2DBL(rb_Float(val));
215
+ }
216
+
217
+ int
218
+ rb_obj2ll_ok (VALUE val, long long *out)
219
+ {
220
+ if ( NIL_P(val) ) {
221
+ return 0;
222
+ }
223
+ if ( RB_TYPE_P(val, T_FIXNUM) ) {
224
+ *out = NUM2LL(val);
225
+ return 1;
226
+ }
227
+ {
228
+ int state = 0;
229
+ volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
230
+ if ( state ) {
231
+ rb_set_errinfo(Qnil);
232
+ return 0;
233
+ }
234
+ *out = NUM2LL(r);
235
+ return 1;
236
+ }
237
+ }
238
+
239
+ int
240
+ rb_obj2ull_ok (VALUE val, unsigned long long *out)
241
+ {
242
+ if ( NIL_P(val) ) {
243
+ return 0;
244
+ }
245
+ if ( RB_TYPE_P(val, T_FIXNUM) ) {
246
+ *out = NUM2ULL(val);
247
+ return 1;
248
+ }
249
+ {
250
+ int state = 0;
251
+ volatile VALUE r = rb_protect(ca_kernel_integer, val, &state);
252
+ if ( state ) {
253
+ rb_set_errinfo(Qnil);
254
+ return 0;
255
+ }
256
+ *out = rb_num2ull(r);
257
+ return 1;
73
258
  }
74
259
  }
75
260
 
@@ -112,7 +297,7 @@ rb_obj2ll (VALUE val)
112
297
  case T_FIXNUM:
113
298
  return NUM2LONG(val);
114
299
  case T_NIL:
115
- rb_raise(rb_eTypeError, "no implicit conversion fron nil to integer");
300
+ rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
116
301
  break;
117
302
  default:
118
303
  return NUM2LL(rb_Integer(val));
@@ -133,6 +318,26 @@ rb_obj2ull (VALUE val)
133
318
  }
134
319
  }
135
320
 
321
+ /* Face has surface != storage; cast operates on the storage
322
+ * data_type, which lives at the parent chain bottom (the first
323
+ * non-Face ancestor). This predicate is defensive: stack-allocated
324
+ * dummy CArrays may have an uninitialised obj_type, so we additionally
325
+ * require obj_type to fall in the valid range before treating `ca`
326
+ * as a Face. */
327
+ static inline int
328
+ ca_face_safe_check (CArray *ca)
329
+ {
330
+ return ca && ca_is_face(ca)
331
+ && ca->obj_type >= 0 && ca->obj_type < CA_OBJ_TYPE_MAX;
332
+ }
333
+
334
+ static inline int8_t
335
+ ca_storage_type_of (CArray *ca)
336
+ {
337
+ while (ca_face_safe_check(ca)) ca = ((CAView *) ca)->parent;
338
+ return ca ? ca->data_type : CA_FIXLEN;
339
+ }
340
+
136
341
  void
137
342
  ca_cast_block (ca_size_t n, void *ap1, void *ptr1,
138
343
  void *ap2, void *ptr2)
@@ -140,7 +345,7 @@ ca_cast_block (ca_size_t n, void *ap1, void *ptr1,
140
345
  CArray *ca1 = (CArray *) ap1;
141
346
  CArray *ca2 = (CArray *) ap2;
142
347
  if ( n < 0 ) {
143
- rb_raise(rb_eRuntimeError,
348
+ rb_raise(rb_eRuntimeError,
144
349
  "[BUG] in ca_cast_block(): negative count");
145
350
  }
146
351
  ca_cast_func_table[ca1->data_type][ca2->data_type](n, ca1, ptr1, ca2, ptr2, NULL);
@@ -153,7 +358,7 @@ ca_cast_block_with_mask (ca_size_t n, void *ap1, void *ptr1,
153
358
  CArray *ca1 = (CArray *) ap1;
154
359
  CArray *ca2 = (CArray *) ap2;
155
360
  if ( n < 0 ) {
156
- rb_raise(rb_eRuntimeError,
361
+ rb_raise(rb_eRuntimeError,
157
362
  "[BUG] in ca_cast_block_with_mask(): negative count");
158
363
  }
159
364
  ca_cast_func_table[ca1->data_type][ca2->data_type](n, ca1, ptr1, ca2, ptr2, m);
@@ -225,12 +430,20 @@ ca_val2val (int8_t data_type1, void *ptr1, int8_t data_type2, void *ptr2)
225
430
 
226
431
  /* --------------------------------------------------------------------- */
227
432
 
433
+ /* Cast to CA_OBJECT for an array whose cells mean something other than their
434
+ storage bytes: a data_class array (CARecord / CAStruct) or a Face (CATime,
435
+ CAConstString, CACategorical, ...). Both decode per cell -- rb_ca_fetch_addr
436
+ goes through the data_class decode and CA_FACE_STORAGE_TO_SCALAR_IF_FACE --
437
+ so the object array holds the *surface* values (labels, not codes;
438
+ CATime::Element, not serials; the string, not the descriptor bytes). Reading
439
+ the storage instead is `.parent`, which stays available and explicit. Mask
440
+ and shape carry. */
228
441
  static VALUE
229
- rb_ca_data_class_to_object (VALUE self)
442
+ rb_ca_surface_to_object (VALUE self)
230
443
  {
231
444
  volatile VALUE obj;
232
445
  CArray *ca;
233
- int i;
446
+ ca_size_t i;
234
447
 
235
448
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
236
449
 
@@ -244,10 +457,71 @@ rb_ca_data_class_to_object (VALUE self)
244
457
  for (i=0; i<ca->elements; i++) {
245
458
  rb_ca_store_addr(obj, i, rb_ca_fetch_addr(self, i));
246
459
  }
247
-
460
+
248
461
  return obj;
249
462
  }
250
463
 
464
+ /* Cast a NonNumeric Face (= one whose surface declares CA_FIXLEN, so the
465
+ numeric kernel dispatch is gated off) to a type other than :object.
466
+
467
+ Reading the storage would hand back the bytes the surface exists to hide,
468
+ and there is no way for the core to guess how a surface becomes a number:
469
+ a fixed-point cell is its storage over a scale, a categorical cell is a
470
+ label, a time cell is not a number at all. So the Face declares it, with
471
+ #to_numeric returning a plain CArray of its values, and everything else is
472
+ an ordinary cast of that. A Face that declares nothing raises: it is the
473
+ Face saying "my values are not numbers", which is information, unlike an
474
+ array of UNDEF.
475
+
476
+ The projection is array-level on purpose. Going through the surface cell
477
+ by cell (to_type(:object) and Ruby #to_f) measured 449 ms against 1.45 ms
478
+ for the vectorised expression the author writes anyway (1M cells,
479
+ CAFixedPoint = parent.float64 / scale). */
480
+ static VALUE
481
+ rb_ca_face_numeric_projection (VALUE self, CArray *ca)
482
+ {
483
+ static ID id_to_numeric = 0;
484
+ VALUE num;
485
+ CArray *cn;
486
+
487
+ if ( id_to_numeric == 0 ) {
488
+ id_to_numeric = rb_intern("to_numeric");
489
+ }
490
+
491
+ if ( ! rb_respond_to(self, id_to_numeric) ) {
492
+ rb_raise(rb_eTypeError,
493
+ "%s declares no numeric conversion: define #to_numeric to say "
494
+ "how its values become numbers, or take the surface with "
495
+ "to_type(:object) / the storage with #parent",
496
+ rb_obj_classname(self));
497
+ }
498
+
499
+ num = rb_funcall(self, id_to_numeric, 0);
500
+
501
+ if ( ! rb_obj_is_carray(num) ) {
502
+ rb_raise(rb_eTypeError,
503
+ "%s#to_numeric must return a CArray (got %s)",
504
+ rb_obj_classname(self), rb_obj_classname(num));
505
+ }
506
+
507
+ TypedData_Get_Struct(num, CArray, &carray_data_type, cn);
508
+
509
+ if ( ca_is_face(cn) ) {
510
+ rb_raise(rb_eTypeError,
511
+ "%s#to_numeric must return a plain CArray, not a Face (got %s)",
512
+ rb_obj_classname(self), rb_obj_classname(num));
513
+ }
514
+
515
+ if ( cn->elements != ca->elements ) {
516
+ rb_raise(rb_eArgError,
517
+ "%s#to_numeric returned %lld elements, expected %lld",
518
+ rb_obj_classname(self),
519
+ (long long) cn->elements, (long long) ca->elements);
520
+ }
521
+
522
+ return num;
523
+ }
524
+
251
525
  static VALUE
252
526
  rb_ca_object_to_data_class (VALUE self, VALUE rtype, ca_size_t bytes)
253
527
  {
@@ -264,7 +538,6 @@ rb_ca_object_to_data_class (VALUE self, VALUE rtype, ca_size_t bytes)
264
538
  else {
265
539
  obj = rb_carray_new(CA_FIXLEN, ca->ndim, ca->dim, bytes, ca->mask);
266
540
  }
267
- rb_ca_data_type_import(obj, rtype);
268
541
 
269
542
  for (i=0; i<ca->elements; i++) {
270
543
  rval = rb_ca_fetch_addr(self, i);
@@ -279,11 +552,9 @@ rb_ca_object_to_data_class (VALUE self, VALUE rtype, ca_size_t bytes)
279
552
  return obj;
280
553
  }
281
554
 
282
- /* @overload to_type (data_type, bytes: nil)
283
-
284
- (Conversion) Returns an array of elements that are converted
285
- to the given data type from the object.
286
- */
555
+ /* CArray#to_type(data_type, bytes:) -- eager copy of self converted to
556
+ data_type (a new entity owning its storage). User doc lives in
557
+ yard-stubs/carray_cast.rb. */
287
558
 
288
559
  static VALUE
289
560
  rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
@@ -300,14 +571,24 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
300
571
 
301
572
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
302
573
 
303
- if ( rb_ca_has_data_class(self) && data_type == CA_OBJECT ) {
304
- return rb_ca_data_class_to_object(self);
574
+ if ( ( rb_ca_has_data_class(self) || ca_is_face(ca) ) && data_type == CA_OBJECT ) {
575
+ return rb_ca_surface_to_object(self);
305
576
  }
306
577
 
307
578
  if ( rb_ca_is_object_type(self) && rb_obj_is_data_class(rtype) ) {
308
579
  return rb_ca_object_to_data_class(self, rtype, bytes);
309
580
  }
310
581
 
582
+ /* NonNumeric Face (CA_FIXLEN surface = the numeric gate) to anything but
583
+ :object: the values come from the Face's own #to_numeric, and the
584
+ request is then served by an ordinary cast of that plain array. A
585
+ Numeric Face is not routed here -- its surface *is* its storage, so the
586
+ ordinary cast below is already right. */
587
+ if ( ca_is_face(ca) && ca->data_type == CA_FIXLEN ) {
588
+ return rb_ca_to_type_internal(argc, argv,
589
+ rb_ca_face_numeric_projection(self, ca));
590
+ }
591
+
311
592
  ca_update_mask(ca);
312
593
 
313
594
  if ( ca_is_scalar(ca) ) {
@@ -317,13 +598,45 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
317
598
  obj = rb_carray_new(data_type, ca->ndim, ca->dim, bytes, ca->mask);
318
599
  }
319
600
 
320
- rb_ca_data_type_import(obj, rtype);
321
601
 
322
602
  TypedData_Get_Struct(obj, CArray, &carray_data_type, cb);
323
603
 
324
604
  ca_attach(ca);
325
- if ( ca_has_mask(ca) ) {
326
- ca_cast_block_with_mask(cb->elements, ca, ca->ptr, cb, cb->ptr,
605
+ if ( ca->data_type == CA_OBJECT
606
+ && ( (data_type >= CA_INT8 && data_type <= CA_UINT64)
607
+ || data_type == CA_FLOAT32 || data_type == CA_FLOAT64 ) ) {
608
+ /* object -> int/float: give the cast a mask buffer so an unparseable
609
+ cell becomes UNDEF (see ext/carray_cast_func.rb). Cast into a
610
+ scratch mask seeded from the source mask, then attach it to the
611
+ output only if some cell ended up masked -- an all-valid cast keeps
612
+ the mask-less result the legacy path produced. */
613
+ ca_size_t ne = cb->elements;
614
+ ca_size_t i;
615
+ boolean8_t any = 0;
616
+ boolean8_t *scratch = ALLOC_N(boolean8_t, ne > 0 ? ne : 1);
617
+ if ( cb->mask ) {
618
+ memcpy(scratch, cb->mask->ptr, ne); /* copy of source mask */
619
+ }
620
+ else {
621
+ memset(scratch, 0, ne);
622
+ }
623
+ ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
624
+ for (i=0; i<ne; i++) {
625
+ if ( scratch[i] ) {
626
+ any = 1;
627
+ break;
628
+ }
629
+ }
630
+ if ( any ) {
631
+ if ( ! cb->mask ) {
632
+ ca_create_mask(cb);
633
+ }
634
+ memcpy(cb->mask->ptr, scratch, ne);
635
+ }
636
+ xfree(scratch);
637
+ }
638
+ else if ( ca_has_mask(ca) ) {
639
+ ca_cast_block_with_mask(cb->elements, ca, ca->ptr, cb, cb->ptr,
327
640
  (boolean8_t*)ca->mask->ptr);
328
641
  }
329
642
  else {
@@ -331,6 +644,13 @@ rb_ca_to_type_internal (int argc, VALUE *argv, VALUE self)
331
644
  }
332
645
  ca_detach(ca);
333
646
 
647
+ /* When rtype is a data_class (e.g. CAStruct subclass), wrap the
648
+ result in CARecord so the cast output carries data_class. */
649
+ if ( rb_obj_is_data_class(rtype) ) {
650
+ obj = rb_funcall(rb_const_get(rb_cObject, rb_intern("CARecord")),
651
+ rb_intern("wrap"), 2, obj, rtype);
652
+ }
653
+
334
654
  return obj;
335
655
  }
336
656
 
@@ -349,161 +669,97 @@ rb_ca_to_type (VALUE self, VALUE rtype, VALUE rbytes)
349
669
  return rb_ca_to_type_internal(1, &rcode, self); \
350
670
  }
351
671
 
352
- /* @overload fixlen (bytes:)
353
-
354
- (Conversion) Short-Hand of "CArray#to_type(:fixlen, bytes:)"
355
- */
672
+ /* CArray#fixlen(bytes:) -- short-hand of to_type(:fixlen, bytes:). */
356
673
 
357
674
  VALUE
358
675
  rb_ca_to_fixlen (int argc, VALUE *argv, VALUE self)
359
676
  {
360
677
  volatile VALUE ropt = rb_pop_options(&argc, &argv);
361
678
  VALUE list[2];
362
- // rb_scan_args(argc, argv, "0");
363
679
  list[0] = INT2NUM(CA_FIXLEN);
364
680
  list[1] = ropt;
365
681
  return rb_ca_to_type_internal(2, list, self);
366
682
  }
367
683
 
368
- /* @overload fixlen (bytes:)
369
-
370
- (Conversion) Short-Hand of "CArray#to_type(:boolean)"
371
- */
684
+ /* CArray#boolean -- short-hand of to_type(:boolean). */
372
685
  VALUE rb_ca_to_boolean (VALUE self)
373
686
  {
374
687
  rb_ca_to_type_method_body(CA_BOOLEAN);
375
688
  }
376
689
 
377
- /* @overload int8
378
-
379
- (Conversion) Short-Hand of "CArray#to_type(:int8)"
380
- */
690
+ /* CArray#int8 -- short-hand of to_type(:int8). */
381
691
  VALUE rb_ca_to_int8 (VALUE self)
382
692
  {
383
693
  rb_ca_to_type_method_body(CA_INT8);
384
694
  }
385
695
 
386
- /* @overload uint8
387
-
388
- (Conversion) Short-Hand of "CArray#to_type(:uint8)"
389
- */
696
+ /* CArray#uint8 -- short-hand of to_type(:uint8). */
390
697
  VALUE rb_ca_to_uint8 (VALUE self)
391
698
  {
392
699
  rb_ca_to_type_method_body(CA_UINT8);
393
700
  }
394
701
 
395
- /* @overload int16
396
-
397
- (Conversion) Short-Hand of "CArray#to_type(:int16)"
398
- */
702
+ /* CArray#int16 -- short-hand of to_type(:int16). */
399
703
  VALUE rb_ca_to_int16 (VALUE self)
400
704
  {
401
705
  rb_ca_to_type_method_body(CA_INT16);
402
706
  }
403
707
 
404
- /* @overload uint16
405
-
406
- (Conversion) Short-Hand of "CArray#to_type(:uint16)"
407
- */
708
+ /* CArray#uint16 -- short-hand of to_type(:uint16). */
408
709
  VALUE rb_ca_to_uint16 (VALUE self)
409
710
  {
410
711
  rb_ca_to_type_method_body(CA_UINT16);
411
712
  }
412
713
 
413
- /* @overload int32
414
-
415
- (Conversion) Short-Hand of "CArray#to_type(:int32)"
416
- */
714
+ /* CArray#int32 -- short-hand of to_type(:int32). */
417
715
  VALUE rb_ca_to_int32 (VALUE self)
418
716
  {
419
717
  rb_ca_to_type_method_body(CA_INT32);
420
718
  }
421
719
 
422
- /* @overload uint32
423
-
424
- (Conversion) Short-Hand of "CArray#to_type(:uint32)"
425
- */
720
+ /* CArray#uint32 -- short-hand of to_type(:uint32). */
426
721
  VALUE rb_ca_to_uint32 (VALUE self)
427
722
  {
428
723
  rb_ca_to_type_method_body(CA_UINT32);
429
724
  }
430
725
 
431
- /* @overload int64
432
-
433
- (Conversion) Short-Hand of "CArray#to_type(:int64)"
434
- */
726
+ /* CArray#int64 -- short-hand of to_type(:int64). */
435
727
  VALUE rb_ca_to_int64 (VALUE self)
436
728
  {
437
729
  rb_ca_to_type_method_body(CA_INT64);
438
730
  }
439
731
 
440
- /* @overload uint64
441
-
442
- (Conversion) Short-Hand of "CArray#to_type(:uint64)"
443
- */
732
+ /* CArray#uint64 -- short-hand of to_type(:uint64). */
444
733
  VALUE rb_ca_to_uint64 (VALUE self)
445
734
  {
446
735
  rb_ca_to_type_method_body(CA_UINT64);
447
736
  }
448
737
 
449
- /* @overload float32
450
-
451
- (Conversion) Short-Hand of "CArray#to_type(:float32)"
452
- */
738
+ /* CArray#float32 -- short-hand of to_type(:float32). */
453
739
  VALUE rb_ca_to_float32 (VALUE self)
454
740
  {
455
741
  rb_ca_to_type_method_body(CA_FLOAT32);
456
742
  }
457
743
 
458
- /* @overload float64
459
-
460
- (Conversion) Short-Hand of "CArray#to_type(:float64)"
461
- */
744
+ /* CArray#float64 -- short-hand of to_type(:float64). */
462
745
  VALUE rb_ca_to_float64 (VALUE self)
463
746
  {
464
747
  rb_ca_to_type_method_body(CA_FLOAT64);
465
748
  }
466
749
 
467
- /* @overload float128
468
-
469
- (Conversion) Short-Hand of "CArray#to_type(:float128)"
470
- */
471
- VALUE rb_ca_to_float128 (VALUE self)
472
- {
473
- rb_ca_to_type_method_body(CA_FLOAT128);
474
- }
475
-
476
- /* @overload cmplx64
477
-
478
- (Conversion) Short-Hand of "CArray#to_type(:cmplx64)"
479
- */
750
+ /* CArray#cmplx64 -- short-hand of to_type(:cmplx64). */
480
751
  VALUE rb_ca_to_cmplx64 (VALUE self)
481
752
  {
482
753
  rb_ca_to_type_method_body(CA_CMPLX64);
483
754
  }
484
755
 
485
- /* @overload cmplx128
486
-
487
- (Conversion) Short-Hand of "CArray#to_type(:cmplx128)"
488
- */
756
+ /* CArray#cmplx128 -- short-hand of to_type(:cmplx128). */
489
757
  VALUE rb_ca_to_cmplx128 (VALUE self)
490
758
  {
491
759
  rb_ca_to_type_method_body(CA_CMPLX128);
492
760
  }
493
761
 
494
- /* @overload cmplx256
495
-
496
- (Conversion) Short-Hand of "CArray#to_type(:cmplx256)"
497
- */
498
- VALUE rb_ca_to_cmplx256 (VALUE self)
499
- {
500
- rb_ca_to_type_method_body(CA_CMPLX256);
501
- }
502
-
503
- /* @overload object
504
-
505
- (Conversion) Short-Hand of "CArray#to_type(:object)"
506
- */
762
+ /* CArray#object -- short-hand of to_type(:object). */
507
763
  VALUE rb_ca_to_VALUE (VALUE self)
508
764
  {
509
765
  rb_ca_to_type_method_body(CA_OBJECT);
@@ -513,6 +769,77 @@ VALUE rb_ca_to_VALUE (VALUE self)
513
769
 
514
770
  /* CArray#as_type */
515
771
 
772
+ /* Forward declaration: CAMonOp builder (ext/ca_obj_monop.c). */
773
+ extern VALUE rb_ca_monop_build (VALUE cary, uint16_t op_id);
774
+
775
+ /* Forward declaration: clip kernel (ext/carray_kernels.c, generated). */
776
+ extern VALUE rb_ca_clip (VALUE self, VALUE lo, VALUE hi);
777
+
778
+ /* Which surface asked for a type-adapt view. A Face's cells do not mean
779
+ their storage bytes and there is no view that decodes them, so each
780
+ caller says what it does instead of reinterpreting the storage. */
781
+ enum {
782
+ CA_ADAPT_VIEW, /* as_type: the values are behind #to_type */
783
+ CA_ADAPT_READONLY, /* wrap_readonly: the eager conversion is the answer */
784
+ CA_ADAPT_WRITABLE /* wrap_writable: writes have nowhere to land */
785
+ };
786
+
787
+ /* Routes a type-adapt view request to CAMonOp(cast_<dt>) when the
788
+ target is a plain numeric data_type (NOT CA_FIXLEN, NOT CA_OBJECT,
789
+ and `rtype` is not a Class). Falls back to CAFake
790
+ (`rb_ca_fake_type`) for CA_FIXLEN sizing, CA_OBJECT, and class-rtype
791
+ data_class overlay cases.
792
+ Called by rb_ca_as_type_internal, rb_ca_wrap_readonly, and
793
+ rb_ca_wrap_writable in this file.
794
+
795
+ A Face whose surface is not its storage reaches neither: reinterpreting
796
+ the storage would hand back the bytes the surface exists to hide (the
797
+ serial instead of the time, the descriptor instead of the string).
798
+ wrap_readonly, which already returns entities for its non-CArray inputs,
799
+ answers with the eager conversion #to_type performs -- the surface values,
800
+ or the Face's own #to_numeric for a numeric target. as_type and
801
+ wrap_writable have no honest answer and say so. */
802
+ static VALUE
803
+ ca_type_adapt_view (VALUE obj, VALUE rtype, int8_t data_type, int mode)
804
+ {
805
+ CArray *ca;
806
+
807
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
808
+
809
+ /* Same split the eager cast makes: :object is the Face's surface for every
810
+ Face, and a NonNumeric Face (CA_FIXLEN surface) has no reading of its
811
+ storage as a number either. A Numeric Face falls through, because there
812
+ its surface *is* its storage and the ordinary cast below is right. */
813
+ if ( ca_is_face(ca) && ( data_type == CA_OBJECT
814
+ || ca->data_type == CA_FIXLEN ) ) {
815
+ VALUE args[1];
816
+ switch ( mode ) {
817
+ case CA_ADAPT_READONLY:
818
+ args[0] = rtype;
819
+ return rb_ca_to_type_internal(1, args, obj);
820
+ case CA_ADAPT_WRITABLE:
821
+ rb_raise(rb_eTypeError,
822
+ "%s has no writable view in another data_type: the writes "
823
+ "would land on the storage its surface hides -- wrap "
824
+ "#parent to reach that storage",
825
+ rb_obj_classname(obj));
826
+ default:
827
+ rb_raise(rb_eTypeError,
828
+ "%s has no view of its values in another data_type: "
829
+ "#to_type gives the values, #parent the raw storage",
830
+ rb_obj_classname(obj));
831
+ }
832
+ }
833
+
834
+ if ( data_type != CA_FIXLEN
835
+ && data_type != CA_OBJECT
836
+ && TYPE(rtype) != T_CLASS ) {
837
+ uint16_t cast_op_id = (uint16_t)(CA_MONOP_CAST_BASE + data_type);
838
+ return rb_ca_monop_build(obj, cast_op_id);
839
+ }
840
+ return rb_ca_fake_type(obj, rtype, Qnil);
841
+ }
842
+
516
843
  static VALUE
517
844
  rb_ca_as_type_internal (int argc, VALUE *argv, VALUE self)
518
845
  {
@@ -533,16 +860,23 @@ rb_ca_as_type_internal (int argc, VALUE *argv, VALUE self)
533
860
  }
534
861
  }
535
862
 
863
+ /* Natural-width cast: dispatch via helper (CAMonOp for numeric,
864
+ CAFake for CA_FIXLEN sizing / CA_OBJECT / class-rtype). */
865
+ if ( bytes == (ca_size_t) ca_sizeof[data_type] ) {
866
+ obj = ca_type_adapt_view(self, rtype, data_type, CA_ADAPT_VIEW);
867
+ return obj;
868
+ }
869
+
870
+ /* Byte-reinterpret variant (bytes != natural for non-FIXLEN, or
871
+ explicit fixlen sizing): CAFake. */
536
872
  obj = rb_ca_fake_type(self, rtype, rbytes);
537
- rb_ca_data_type_import(obj, rtype);
538
873
 
539
874
  return obj;
540
875
  }
541
876
 
542
- /* @overload as_type (data_type, bytes: nil)
543
-
544
- (Reference) Creates CAFake object of the given data type refers to the object.
545
- */
877
+ /* CArray#as_type(data_type, bytes:) -- CAFake view of self reinterpreted
878
+ as data_type (no copy; reads/writes cast on the fly through the shared
879
+ parent storage). User doc lives in yard-stubs/carray_cast.rb. */
546
880
 
547
881
  VALUE
548
882
  rb_ca_as_type (VALUE self, VALUE rtype, VALUE rbytes)
@@ -559,10 +893,7 @@ rb_ca_as_type (VALUE self, VALUE rtype, VALUE rbytes)
559
893
  return rb_ca_as_type_internal(1, &rcode, self); \
560
894
  }
561
895
 
562
- /* @overload as_fixlen (bytes: nil)
563
-
564
- (Reference) Short-Hand of `CArray#as_type(:fixlen, bytes: nil)`
565
- */
896
+ /* CArray#as_fixlen(bytes:) -- short-hand of as_type(:fixlen, bytes:). */
566
897
  VALUE
567
898
  rb_ca_as_fixlen (int argc, VALUE *argv, VALUE self)
568
899
  {
@@ -574,145 +905,97 @@ rb_ca_as_fixlen (int argc, VALUE *argv, VALUE self)
574
905
  return rb_ca_as_type_internal(2, list, self);
575
906
  }
576
907
 
577
- /* @overload as_boolean
578
-
579
- (Reference) Short-Hand of `CArray#as_type(:boolean)`
580
- */
908
+ /* CArray#as_boolean -- short-hand of as_type(:boolean). */
581
909
  VALUE rb_ca_as_boolean (VALUE self)
582
910
  {
583
911
  rb_ca_as_type_method_body(CA_BOOLEAN);
584
912
  }
585
913
 
586
- /* @overload as_int8
587
-
588
- (Reference) Short-Hand of `CArray#as_type(:int8)`
589
- */
914
+ /* CArray#as_int8 -- short-hand of as_type(:int8). */
590
915
  VALUE rb_ca_as_int8 (VALUE self)
591
916
  {
592
917
  rb_ca_as_type_method_body(CA_INT8);
593
918
  }
594
919
 
595
- /* @overload as_uint8
596
-
597
- (Reference) Short-Hand of `CArray#as_type(:uint8)`
598
- */
920
+ /* CArray#as_uint8 -- short-hand of as_type(:uint8). */
599
921
  VALUE rb_ca_as_uint8 (VALUE self)
600
922
  {
601
923
  rb_ca_as_type_method_body(CA_UINT8);
602
924
  }
603
925
 
604
- /* @overload as_int16
605
-
606
- (Reference) Short-Hand of `CArray#as_type(:int16)`
607
- */
926
+ /* CArray#as_int16 -- short-hand of as_type(:int16). */
608
927
  VALUE rb_ca_as_int16 (VALUE self)
609
928
  {
610
929
  rb_ca_as_type_method_body(CA_INT16);
611
930
  }
612
931
 
613
- /* @overload as_uint16
614
-
615
- (Reference) Short-Hand of `CArray#as_type(:uint16)`
616
- */
932
+ /* CArray#as_uint16 -- short-hand of as_type(:uint16). */
617
933
  VALUE rb_ca_as_uint16 (VALUE self)
618
934
  {
619
935
  rb_ca_as_type_method_body(CA_UINT16);
620
936
  }
621
937
 
622
- /* @overload as_int32
623
-
624
- (Reference) Short-Hand of `CArray#as_type(:int32)`
625
- */
938
+ /* CArray#as_int32 -- short-hand of as_type(:int32). */
626
939
  VALUE rb_ca_as_int32 (VALUE self)
627
940
  {
628
941
  rb_ca_as_type_method_body(CA_INT32);
629
942
  }
630
943
 
631
- /* @overload as_uint32
632
-
633
- (Reference) Short-Hand of `CArray#as_type(:uint32)`
634
- */
944
+ /* CArray#as_uint32 -- short-hand of as_type(:uint32). */
635
945
  VALUE rb_ca_as_uint32 (VALUE self)
636
946
  {
637
947
  rb_ca_as_type_method_body(CA_UINT32);
638
948
  }
639
949
 
640
- /* @overload as_int64
641
-
642
- (Reference) Short-Hand of `CArray#as_type(:int64)`
643
- */
950
+ /* CArray#as_int64 -- short-hand of as_type(:int64). */
644
951
  VALUE rb_ca_as_int64 (VALUE self)
645
952
  {
646
953
  rb_ca_as_type_method_body(CA_INT64);
647
954
  }
648
955
 
649
- /* @overload as_uint64
650
-
651
- (Reference) Short-Hand of `CArray#as_type(:uint64)`
652
- */
956
+ /* CArray#as_uint64 -- short-hand of as_type(:uint64). */
653
957
  VALUE rb_ca_as_uint64 (VALUE self)
654
958
  {
655
959
  rb_ca_as_type_method_body(CA_UINT64);
656
960
  }
657
961
 
658
- /* @overload as_float32
659
-
660
- (Reference) Short-Hand of `CArray#as_type(:float32)`
661
- */
962
+ /* CArray#as_float32 -- short-hand of as_type(:float32). */
662
963
  VALUE rb_ca_as_float32 (VALUE self)
663
964
  {
664
965
  rb_ca_as_type_method_body(CA_FLOAT32);
665
966
  }
666
967
 
667
- /* @overload as_float64
668
-
669
- (Reference) Short-Hand of `CArray#as_type(:float64)`
670
- */
968
+ /* CArray#as_float64 -- short-hand of as_type(:float64). */
671
969
  VALUE rb_ca_as_float64 (VALUE self)
672
970
  {
673
971
  rb_ca_as_type_method_body(CA_FLOAT64);
674
972
  }
675
973
 
676
- /* @overload as_float128
677
-
678
- (Reference) Short-Hand of `CArray#as_type(:float128)`
679
- */
974
+ /* CArray#as_float128 -- short-hand of as_type(:float128). */
680
975
  VALUE rb_ca_as_float128 (VALUE self)
681
976
  {
682
977
  rb_ca_as_type_method_body(CA_FLOAT128);
683
978
  }
684
979
 
685
- /* @overload as_cmplx64
686
-
687
- (Reference) Short-Hand of `CArray#as_type(:cmplx64)`
688
- */
980
+ /* CArray#as_cmplx64 -- short-hand of as_type(:cmplx64). */
689
981
  VALUE rb_ca_as_cmplx64 (VALUE self)
690
982
  {
691
983
  rb_ca_as_type_method_body(CA_CMPLX64);
692
984
  }
693
985
 
694
- /* @overload as_cmplx128
695
-
696
- (Reference) Short-Hand of `CArray#as_type(:cmplx128)`
697
- */
986
+ /* CArray#as_cmplx128 -- short-hand of as_type(:cmplx128). */
698
987
  VALUE rb_ca_as_cmplx128 (VALUE self)
699
988
  {
700
989
  rb_ca_as_type_method_body(CA_CMPLX128);
701
990
  }
702
991
 
703
- /* @overload as_cmplx256
704
-
705
- (Reference) Short-Hand of `CArray#as_type(:cmplx256)`
706
- */
992
+ /* CArray#as_cmplx256 -- short-hand of as_type(:cmplx256). */
707
993
  VALUE rb_ca_as_cmplx256 (VALUE self)
708
994
  {
709
995
  rb_ca_as_type_method_body(CA_CMPLX256);
710
996
  }
711
997
 
712
- /* @overload as_object
713
-
714
- (Reference) Short-Hand of `CArray#as_type(:object)`
715
- */
998
+ /* CArray#as_object -- short-hand of as_type(:object). */
716
999
  VALUE rb_ca_as_VALUE (VALUE self)
717
1000
  {
718
1001
  rb_ca_as_type_method_body(CA_OBJECT);
@@ -762,6 +1045,36 @@ rb_ca_ptr2obj (VALUE self, void *ptr)
762
1045
  }
763
1046
  }
764
1047
 
1048
+ /* Surface -> storage-domain conversion for a Face store (mirror of the
1049
+ storage_to_scalar read hook). Non-Face `ca` returns `obj` unchanged, so
1050
+ the non-Face store path is untouched. For a Face, the per-obj_type C
1051
+ table is consulted first (fast path); if none is registered, the Ruby
1052
+ `scalar_to_storage` method is called when defined. A Face that recognizes
1053
+ `obj` returns a storage-domain value (e.g. an Integer in its unit); a bare
1054
+ Integer / String falls through unchanged to the storage cast. */
1055
+ VALUE
1056
+ ca_face_scalar_to_storage (VALUE self, CArray *ca, VALUE obj)
1057
+ {
1058
+ ca_face_scalar_to_storage_fn fn;
1059
+ if ( ! ca_face_safe_check(ca) || obj == CA_UNDEF ) {
1060
+ return obj;
1061
+ }
1062
+ fn = ca_face_scalar_to_storage_table[ca->obj_type];
1063
+ if ( fn != NULL ) {
1064
+ return fn(self, obj);
1065
+ }
1066
+ else {
1067
+ static ID id_scalar_to_storage = 0;
1068
+ if ( id_scalar_to_storage == 0 ) {
1069
+ id_scalar_to_storage = rb_intern("scalar_to_storage");
1070
+ }
1071
+ if ( rb_respond_to(self, id_scalar_to_storage) ) {
1072
+ return rb_funcall(self, id_scalar_to_storage, 1, obj);
1073
+ }
1074
+ }
1075
+ return obj;
1076
+ }
1077
+
765
1078
  VALUE
766
1079
  rb_ca_obj2ptr (VALUE self, VALUE obj, void *ptr)
767
1080
  {
@@ -772,9 +1085,21 @@ rb_ca_obj2ptr (VALUE self, VALUE obj, void *ptr)
772
1085
  memset(ptr, 0, ca->bytes);
773
1086
  }
774
1087
  else {
775
- obj = ( ca_is_fixlen_type(ca) ) ? rb_ca_data_class_encode(self, obj) : obj;
1088
+ /* Face surfaces as FIXLEN but its storage is the parent chain
1089
+ bottom (e.g. int64); the obj -> bytes conversion must use the
1090
+ storage data_type, not the Face surface. */
1091
+ int8_t convert_type = ca->data_type;
1092
+ if ( ca_face_safe_check(ca) ) {
1093
+ /* Face write hook: turn a surface value object (Scalar / Time /
1094
+ DateTime) into a storage-domain value the cast below consumes. */
1095
+ obj = ca_face_scalar_to_storage(self, ca, obj);
1096
+ convert_type = ca_storage_type_of(ca);
1097
+ }
1098
+ if ( convert_type == CA_FIXLEN ) {
1099
+ obj = rb_ca_data_class_encode(self, obj);
1100
+ }
776
1101
  dummy.data_type = CA_OBJECT;
777
- ca_cast_func_table[CA_OBJECT][ca->data_type](1, &dummy, &obj, ca, ptr, NULL);
1102
+ ca_cast_func_table[CA_OBJECT][convert_type](1, &dummy, &obj, ca, ptr, NULL);
778
1103
  }
779
1104
  return Qnil;
780
1105
  }
@@ -798,7 +1123,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
798
1123
  data_type = rb_ca_guess_type(rtype);
799
1124
  }
800
1125
  if ( ca->data_type != data_type ) {
801
- obj = rb_ca_fake_type(obj, rtype, Qnil);
1126
+ obj = ca_type_adapt_view(obj, rtype, data_type, CA_ADAPT_WRITABLE);
802
1127
  }
803
1128
  }
804
1129
  else if ( NIL_P(obj) ) { /* obj == nil */
@@ -810,9 +1135,25 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
810
1135
  }
811
1136
  obj = rb_cscalar_new(data_type, 0, NULL);
812
1137
  }
813
- else if ( rb_respond_to(obj, rb_intern("ca")) ) { /* respond_to obj.ca */
814
- obj = rb_funcall(obj, rb_intern("ca"), 0);
1138
+ else if ( rb_respond_to(obj, rb_intern("to_ca")) ) { /* respond_to obj.to_ca */
1139
+ /* `writable: true` is the caller's half of the bargain: it says the
1140
+ result has to be one whose writes reach `obj`, and a to_ca that can
1141
+ only produce a copy raises rather than swallowing them. An object
1142
+ whose to_ca predates the keyword raises ArgumentError here, which is
1143
+ the honest report that it does not implement writable intake. */
1144
+ volatile VALUE kw = rb_hash_new();
1145
+ rb_hash_aset(kw, ID2SYM(rb_intern("writable")), Qtrue);
1146
+ obj = rb_funcallv_kw(obj, rb_intern("to_ca"), 1, (VALUE *) &kw,
1147
+ RB_PASS_KEYWORDS);
1148
+ if ( ! rb_obj_is_carray(obj) ) {
1149
+ volatile VALUE inspect = rb_inspect(CLASS_OF(arg));
1150
+ rb_raise(rb_eTypeError,
1151
+ "%s#to_ca did not return a CArray", StringValuePtr(inspect));
1152
+ }
815
1153
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1154
+ if ( ca_is_readonly(ca) ) {
1155
+ rb_raise(rb_eRuntimeError, "can't modify read-only carray");
1156
+ }
816
1157
  if ( NIL_P(rtype) ) {
817
1158
  data_type = ca->data_type;
818
1159
  }
@@ -820,7 +1161,26 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
820
1161
  data_type = rb_ca_guess_type(rtype);
821
1162
  }
822
1163
  if ( ca->data_type != data_type ) {
823
- obj = rb_ca_fake_type(obj, INT2NUM(data_type), Qnil);
1164
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1165
+ CA_ADAPT_WRITABLE);
1166
+ }
1167
+ }
1168
+ else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
1169
+ obj = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
1170
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1171
+ if ( ca_is_readonly(ca) ) {
1172
+ rb_raise(rb_eRuntimeError,
1173
+ "MemoryView source is read-only; can't wrap as writable");
1174
+ }
1175
+ if ( NIL_P(rtype) ) {
1176
+ data_type = ca->data_type;
1177
+ }
1178
+ else {
1179
+ data_type = rb_ca_guess_type(rtype);
1180
+ }
1181
+ if ( ca->data_type != data_type ) {
1182
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1183
+ CA_ADAPT_WRITABLE);
824
1184
  }
825
1185
  }
826
1186
  else {
@@ -833,10 +1193,9 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
833
1193
  return obj;
834
1194
  }
835
1195
 
836
- /* @overload wrap_writable (other, date_type = nil)
837
-
838
- [TBD]
839
- */
1196
+ /* CArray.wrap_writable(other, data_type = nil) -- singleton entry that
1197
+ scans (other, data_type) and delegates to rb_ca_wrap_writable.
1198
+ User doc lives in yard-stubs/carray_cast.rb. */
840
1199
 
841
1200
  static VALUE
842
1201
  rb_ca_s_wrap_writable (int argc, VALUE *argv, VALUE klass)
@@ -862,7 +1221,7 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
862
1221
  data_type = rb_ca_guess_type(rtype);
863
1222
  }
864
1223
  if ( ca->data_type != data_type ) {
865
- obj = rb_ca_fake_type(obj, rtype, Qnil);
1224
+ obj = ca_type_adapt_view(obj, rtype, data_type, CA_ADAPT_READONLY);
866
1225
  }
867
1226
  }
868
1227
  else if ( rb_obj_is_kind_of(obj, rb_cNumeric) ) { /* number */
@@ -884,7 +1243,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
884
1243
  data_type = rb_ca_guess_type(rtype);
885
1244
  }
886
1245
  if ( ca->data_type != data_type ) {
887
- obj = rb_ca_fake_type(obj, INT2NUM(data_type), Qnil);
1246
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1247
+ CA_ADAPT_READONLY);
888
1248
  }
889
1249
  }
890
1250
  else if ( TYPE(obj) == T_STRING ) { /* string */
@@ -898,14 +1258,12 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
898
1258
  obj = rb_cscalar_new_with_value(data_type, 0, obj);
899
1259
  }
900
1260
  else {
1261
+ CArray *ca_tmp;
901
1262
  volatile VALUE ref = obj;
902
- if ( ! RB_OBJ_FROZEN(ref) ) {
903
- ref = rb_obj_dup(ref);
904
- rb_obj_freeze(ref);
905
- }
906
1263
  ca_size_t dim = RSTRING_LEN(ref)/ca_sizeof[data_type];
907
- obj = rb_ca_wrap_new(data_type, 1, &dim, ca_sizeof[data_type], NULL, RSTRING_PTR(ref));
908
- rb_ivar_set(obj, rb_intern("referred_object"), ref);
1264
+ obj = rb_carray_new(data_type, 1, &dim, 0, NULL);
1265
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, ca_tmp);
1266
+ memcpy(ca_tmp->ptr, RSTRING_PTR(ref), dim * ca_sizeof[data_type]);
909
1267
  }
910
1268
  }
911
1269
  else if ( NIL_P(obj) ) { /* nil */
@@ -917,8 +1275,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
917
1275
  }
918
1276
  obj = rb_cscalar_new(data_type, 0, NULL);
919
1277
  }
920
- else if ( rb_respond_to(obj, rb_intern("ca")) ) {
921
- obj = rb_funcall(obj, rb_intern("ca"), 0);
1278
+ else if ( rb_respond_to(obj, rb_intern("to_ca")) ) {
1279
+ obj = rb_funcall(obj, rb_intern("to_ca"), 0);
922
1280
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
923
1281
  if ( NIL_P(rtype) ) {
924
1282
  data_type = ca->data_type;
@@ -927,11 +1285,12 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
927
1285
  data_type = rb_ca_guess_type(rtype);
928
1286
  }
929
1287
  if ( ca->data_type != data_type ) {
930
- obj = rb_ca_fake_type(obj, INT2NUM(data_type), Qnil);
1288
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1289
+ CA_ADAPT_READONLY);
931
1290
  }
932
1291
  }
933
- else if ( rb_respond_to(obj, rb_intern("to_ca")) ) {
934
- obj = rb_funcall(obj, rb_intern("to_ca"), 0);
1292
+ else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
1293
+ obj = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
935
1294
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
936
1295
  if ( NIL_P(rtype) ) {
937
1296
  data_type = ca->data_type;
@@ -940,7 +1299,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
940
1299
  data_type = rb_ca_guess_type(rtype);
941
1300
  }
942
1301
  if ( ca->data_type != data_type ) {
943
- obj = rb_ca_fake_type(obj, INT2NUM(data_type), Qnil);
1302
+ obj = ca_type_adapt_view(obj, INT2NUM(data_type), data_type,
1303
+ CA_ADAPT_READONLY);
944
1304
  }
945
1305
  }
946
1306
  else { /* object */
@@ -956,10 +1316,9 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
956
1316
  return obj;
957
1317
  }
958
1318
 
959
- /* @overload wrap_readonly (other, date_type = nil)
960
-
961
- [TBD]
962
- */
1319
+ /* CArray.wrap_readonly(other, data_type = nil) -- singleton entry that
1320
+ scans (other, data_type) and delegates to rb_ca_wrap_readonly.
1321
+ User doc lives in yard-stubs/carray_cast.rb. */
963
1322
 
964
1323
  static VALUE
965
1324
  rb_ca_s_wrap_readonly (int argc, VALUE *argv, VALUE klass)
@@ -995,7 +1354,7 @@ rb_ca_cast (volatile VALUE self)
995
1354
  break;
996
1355
  }
997
1356
  #ifdef HAVE_COMPLEX_H
998
- if ( rb_obj_is_kind_of(obj, rb_cCComplex) ) {
1357
+ if ( RB_TYPE_P(obj, T_COMPLEX) ) {
999
1358
  obj = rb_cscalar_new_with_value(CA_CMPLX128, 0, obj);
1000
1359
  break;
1001
1360
  }
@@ -1007,10 +1366,9 @@ rb_ca_cast (volatile VALUE self)
1007
1366
  return obj;
1008
1367
  }
1009
1368
 
1010
- /* @overload cast (value)
1011
-
1012
- [TBD]
1013
- */
1369
+ /* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
1370
+ returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
1371
+ User doc lives in yard-stubs/carray_cast.rb. */
1014
1372
 
1015
1373
  static VALUE
1016
1374
  rb_ca_s_cast (VALUE klass, VALUE val)
@@ -1026,11 +1384,31 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
1026
1384
  int self_is_object = 0;
1027
1385
  int other_is_object = 0;
1028
1386
 
1387
+ /* Promote MemoryView-aware operands to CArray (CAWrap or CAStride).
1388
+ Excludes T_STRING which has its own legacy interpretation. */
1389
+ if ( ! rb_obj_is_carray(*self) && TYPE(*self) != T_STRING &&
1390
+ rb_memory_view_available_p(*self) ) {
1391
+ *self = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, *self);
1392
+ }
1393
+ if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
1394
+ rb_memory_view_available_p(*other) ) {
1395
+ *other = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, *other);
1396
+ }
1397
+
1029
1398
  if ( ! rb_obj_is_carray(*self) ) {
1030
1399
  self_is_object = 1;
1031
1400
  if ( rb_ca_is_object_type(*other) ) {
1032
1401
  *self = rb_cscalar_new_with_value(CA_OBJECT, 0, *self);
1033
1402
  }
1403
+ #ifdef HAVE_COMPLEX_H
1404
+ /* A Complex scalar with a non-object non-complex CArray on the other
1405
+ side must wrap as CA_CMPLX128; falling into the float branch below
1406
+ would NUM2DBL(Complex) and raise. Downstream promotion lifts the
1407
+ other operand to cmplx128. */
1408
+ else if ( RB_TYPE_P(*self, T_COMPLEX) ) {
1409
+ *self = rb_cscalar_new_with_value(CA_CMPLX128, 0, *self);
1410
+ }
1411
+ #endif
1034
1412
  else if ( rb_ca_is_float_type(*other) ) {
1035
1413
  *self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
1036
1414
  }
@@ -1040,27 +1418,7 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
1040
1418
  }
1041
1419
  #endif
1042
1420
  else {
1043
- switch ( TYPE(*self) ) {
1044
- case T_FIXNUM:
1045
- *self = rb_cscalar_new_with_value(CA_INT64, 0, *self);
1046
- break;
1047
- case T_FLOAT:
1048
- *self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
1049
- break;
1050
- case T_TRUE:
1051
- case T_FALSE:
1052
- *self = rb_cscalar_new_with_value(CA_BOOLEAN, 0, *self);
1053
- break;
1054
- default:
1055
- #ifdef HAVE_COMPLEX_H
1056
- if ( rb_obj_is_kind_of(*self, rb_cCComplex) ) {
1057
- *self = rb_cscalar_new_with_value(CA_CMPLX128, 0, *self);
1058
- break;
1059
- }
1060
- #endif
1061
- *self = rb_cscalar_new_with_value(CA_OBJECT, 0, *self);
1062
- break;
1063
- }
1421
+ *self = rb_cscalar_new_with_value(ca_value_to_data_type(*self), 0, *self);
1064
1422
  }
1065
1423
  }
1066
1424
 
@@ -1070,6 +1428,15 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
1070
1428
  if ( rb_ca_is_object_type(*self) ) {
1071
1429
  *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
1072
1430
  }
1431
+ #ifdef HAVE_COMPLEX_H
1432
+ /* Symmetric to the self-branch above: Complex scalar wraps as
1433
+ cmplx128 regardless of the CArray operand's numeric width, so
1434
+ float64_array + Complex(0, 1) promotes rather than raising in
1435
+ NUM2DBL(Complex). */
1436
+ else if ( RB_TYPE_P(*other, T_COMPLEX) ) {
1437
+ *other = rb_cscalar_new_with_value(CA_CMPLX128, 0, *other);
1438
+ }
1439
+ #endif
1073
1440
  else if ( rb_ca_is_float_type(*self) ) {
1074
1441
  *other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
1075
1442
  }
@@ -1079,46 +1446,24 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
1079
1446
  }
1080
1447
  #endif
1081
1448
  else {
1082
- switch ( TYPE(*other) ) {
1083
- case T_FIXNUM:
1084
- case T_BIGNUM:
1085
- *other = rb_cscalar_new_with_value(CA_INT64, 0, *other);
1086
- break;
1087
- case T_FLOAT:
1088
- *other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
1089
- break;
1090
- case T_TRUE:
1091
- case T_FALSE:
1092
- *other = rb_cscalar_new_with_value(CA_BOOLEAN, 0, *other);
1093
- break;
1094
- default:
1095
- #ifdef HAVE_COMPLEX_H
1096
- if ( rb_obj_is_kind_of(*other, rb_cCComplex) ) {
1097
- *other = rb_cscalar_new_with_value(CA_CMPLX128, 0, *other);
1098
- break;
1099
- }
1100
- #endif
1101
- *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
1102
- break;
1103
- }
1449
+ *other = rb_cscalar_new_with_value(ca_value_to_data_type(*other), 0, *other);
1104
1450
  }
1105
1451
  }
1106
1452
 
1107
1453
  TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
1108
1454
  TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1109
1455
 
1110
- if ( ca->obj_type == CA_OBJ_UNBOUND_REPEAT ) {
1111
- *self = ca_ubrep_bind_with(*self, *other);
1112
- TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
1113
- }
1114
-
1115
- if ( cb->obj_type == CA_OBJ_UNBOUND_REPEAT ) {
1116
- *other = ca_ubrep_bind_with(*other, *self);
1117
- TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1118
- }
1456
+ /* Implicit size-1 broadcasting (case A only). No-op if either side
1457
+ is scalar, ndim differs, or shapes are already equal. If shapes
1458
+ are incompatible (neither side is 1 nor equal on some axis), also
1459
+ no-op — the downstream element-count check in ca_set_iterator
1460
+ raises with the existing message. */
1461
+ ca_broadcast_pair(self, other);
1462
+ TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
1463
+ TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1119
1464
 
1120
- if ( ca_is_scalar(ca) ^ ca_is_scalar(cb) ||
1121
- self_is_object ||
1465
+ if ( ca_is_scalar(ca) ^ ca_is_scalar(cb) ||
1466
+ self_is_object ||
1122
1467
  other_is_object ) {
1123
1468
  if ( other_is_object ||
1124
1469
  ( ( ! other_is_object ) && ca_is_scalar(cb) ) ) {
@@ -1167,10 +1512,10 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
1167
1512
  ca_type_name[cb->data_type]);
1168
1513
  }
1169
1514
 
1170
- /* @overload cast_self_or_other (other)
1171
-
1172
- [TBD]
1173
- */
1515
+ /* CArray.cast_self_or_other(self, other) — promote self and other
1516
+ * to a common data_type and return [self', other']. Wraps the
1517
+ * void rb_ca_cast_self_or_other above into a class method.
1518
+ */
1174
1519
 
1175
1520
  VALUE
1176
1521
  rb_ca_s_cast_self_or_other (VALUE klass, VALUE self, VALUE other)
@@ -1179,6 +1524,286 @@ rb_ca_s_cast_self_or_other (VALUE klass, VALUE self, VALUE other)
1179
1524
  return rb_assoc_new(self, other);
1180
1525
  }
1181
1526
 
1527
+ /* Extract a data_type code (0..CA_NTYPE-1) from an argument.
1528
+ Dispatch:
1529
+ - CArray instance -> its data_type
1530
+ - Symbol / String / Class -> data_type representation (name lookup)
1531
+ - other (Integer / Float / Complex / true / false / nil / Object)
1532
+ -> value semantic via ca_value_to_data_type
1533
+ (e.g. an Integer like `3` is interpreted
1534
+ as a value -> :int64, not as a data_type
1535
+ code). */
1536
+ static int8_t
1537
+ ca_arg_to_data_type (VALUE obj)
1538
+ {
1539
+ int8_t data_type;
1540
+ if ( rb_obj_is_carray(obj) ) {
1541
+ CArray *ca;
1542
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1543
+ data_type = ca->data_type;
1544
+ }
1545
+ else if ( TYPE(obj) == T_SYMBOL || TYPE(obj) == T_STRING ||
1546
+ TYPE(obj) == T_CLASS ) {
1547
+ data_type = rb_ca_guess_type(obj);
1548
+ }
1549
+ else if ( ( data_type = ca_mv_probe_data_type(obj) ) >= 0 ) {
1550
+ /* MemoryView producer -> its format's data_type (T_STRING excluded above,
1551
+ so a String never reaches here). data_type already assigned. */
1552
+ }
1553
+ else {
1554
+ data_type = ca_value_to_data_type(obj);
1555
+ }
1556
+ CA_CHECK_DATA_TYPE(data_type);
1557
+ if ( ! ca_valid[data_type] ) {
1558
+ rb_raise(rb_eArgError,
1559
+ "data type '%s' is not valid in this build",
1560
+ ca_type_name[data_type]);
1561
+ }
1562
+ return data_type;
1563
+ }
1564
+
1565
+ /* Infer a data_type code from a Ruby *value* (literal Numeric, true/false,
1566
+ Complex, etc.). See declaration in carray.h for the contract. */
1567
+ int8_t
1568
+ ca_value_to_data_type (VALUE obj)
1569
+ {
1570
+ switch ( TYPE(obj) ) {
1571
+ case T_FIXNUM:
1572
+ case T_BIGNUM: return CA_INT64;
1573
+ case T_FLOAT: return CA_FLOAT64;
1574
+ case T_TRUE:
1575
+ case T_FALSE: return CA_BOOLEAN;
1576
+ case T_NIL: return CA_OBJECT;
1577
+ default:
1578
+ #ifdef HAVE_COMPLEX_H
1579
+ if ( RB_TYPE_P(obj, T_COMPLEX) ) return CA_CMPLX128;
1580
+ #endif
1581
+ return CA_OBJECT;
1582
+ }
1583
+ }
1584
+
1585
+ /* Promote two data_type codes according to ca_cast_table.
1586
+ Returns the higher (= the type both can be cast to without loss
1587
+ under the table's policy). Raises if incompatible.
1588
+
1589
+ Externally callable so the lazy view layer (CABinOp constructor)
1590
+ can compute its output_data_type using the same single-source
1591
+ promotion rule as the eager binop path. */
1592
+ int8_t
1593
+ ca_promote_type (int8_t a, int8_t b)
1594
+ {
1595
+ int test;
1596
+ if ( a == b ) {
1597
+ return a;
1598
+ }
1599
+ test = ca_cast_table[a][b];
1600
+ if ( test == 0 ) {
1601
+ return b;
1602
+ }
1603
+ else if ( test > 0 ) {
1604
+ /* a should be cast to b */
1605
+ return b;
1606
+ }
1607
+ /* test < 0: try the other direction */
1608
+ test = ca_cast_table[b][a];
1609
+ if ( test > 0 ) {
1610
+ /* b should be cast to a */
1611
+ return a;
1612
+ }
1613
+ rb_raise(rb_eRuntimeError,
1614
+ "can't promote data_types '%s' and '%s' to a common type",
1615
+ ca_type_name[a], ca_type_name[b]);
1616
+ }
1617
+
1618
+ /* CArray.result_type(*args) -- common data_type each operand promotes to
1619
+ under ca_cast_table. Each arg is classified by ca_arg_to_data_type: a
1620
+ CArray / Symbol / String / Class gives a data_type representation, a
1621
+ Numeric / bool / nil / Object gives a value whose data_type is inferred.
1622
+ Folds pairwise via ca_promote_type; returns a Symbol. User doc (with
1623
+ the value-vs-code distinction and examples) lives in
1624
+ yard-stubs/carray_cast.rb. */
1625
+
1626
+ static VALUE
1627
+ rb_ca_s_result_type (int argc, VALUE *argv, VALUE klass)
1628
+ {
1629
+ int8_t cur;
1630
+ int i;
1631
+
1632
+ if ( argc < 1 ) {
1633
+ rb_raise(rb_eArgError, "result_type requires at least one argument");
1634
+ }
1635
+
1636
+ cur = ca_arg_to_data_type(argv[0]);
1637
+ for ( i = 1; i < argc; i++ ) {
1638
+ int8_t next = ca_arg_to_data_type(argv[i]);
1639
+ cur = ca_promote_type(cur, next);
1640
+ }
1641
+ /* Return Symbol for family consistency with
1642
+ CArray.value_to_data_type and ca.data_type. */
1643
+ return rb_ca_data_type_to_sym(cur);
1644
+ }
1645
+
1646
+ /* CArray.promote_list(list, data_type: nil) -- reconcile an Array of
1647
+ CArray instances into a uniformly-handleable representation (same Face
1648
+ class, or same primitive data_type) suitable for multi-parent
1649
+ constructors like CArray.stack. User doc lives in
1650
+ yard-stubs/carray_cast.rb; the dispatch branches are:
1651
+
1652
+ Auto-detect (data_type: nil):
1653
+ - All elements Face (= ca_is_face) and same Face class:
1654
+ - Reject if the class is not portable (= CAConstString)
1655
+ - Reject on pairwise state mismatch (= CATime with different units)
1656
+ - Otherwise pass through (= CAStack will lift)
1657
+ - All elements primitive: promote via result_type + wrap_readonly
1658
+ - Mixed Face + non-Face: reject (= ambiguous; user must strip Face
1659
+ manually with .parent if the storage-level layout is intended)
1660
+ - Heterogeneous Face classes: reject (= no semantics for mixing Faces)
1661
+
1662
+ Explicit data_type (Symbol):
1663
+ - All primitive elements: wrap_readonly to the requested type
1664
+ - Any Face element: reject (= Face cannot be coerced into a primitive
1665
+ without losing identity; the user must strip Face manually)
1666
+
1667
+ Explicit data_type (Class / non-Symbol):
1668
+ - Reject. Class-shaped targets (CARecord, Face subclasses, etc.) are
1669
+ not valid promotion destinations; use auto-detect or pass a primitive
1670
+ Symbol. Future work may relax this once Face-as-target promotion is
1671
+ designed.
1672
+
1673
+ Raises ArgumentError on empty list or any of the reject cases above. */
1674
+ static VALUE
1675
+ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
1676
+ {
1677
+ VALUE list, kwargs, data_type = Qnil;
1678
+ long n, i;
1679
+ int all_face = 1, any_face = 0, all_primitive = 1;
1680
+ VALUE face_class = Qnil;
1681
+ CArray *ref_face = NULL;
1682
+ int8_t common = -1;
1683
+
1684
+ rb_scan_args(argc, argv, "1:", &list, &kwargs);
1685
+ Check_Type(list, T_ARRAY);
1686
+ rb_scan_options(kwargs, "data_type", &data_type);
1687
+
1688
+ n = RARRAY_LEN(list);
1689
+ if ( n <= 0 ) {
1690
+ rb_raise(rb_eArgError, "promote_list: list must not be empty");
1691
+ }
1692
+
1693
+ /* Explicit data_type validation: reject Class / non-Symbol targets up
1694
+ front so the rest of the function only deals with `nil` or a
1695
+ primitive-shaped Symbol/String/Integer. */
1696
+ if ( ! NIL_P(data_type) ) {
1697
+ if ( RB_TYPE_P(data_type, T_CLASS) || RB_TYPE_P(data_type, T_MODULE) ) {
1698
+ rb_raise(rb_eArgError,
1699
+ "promote_list: data_type must be a primitive Symbol "
1700
+ "(Class targets are not supported; use auto-detect or "
1701
+ "strip Face manually)");
1702
+ }
1703
+ }
1704
+
1705
+ /* Classify each element: Face / primitive CArray. Detect Face-class
1706
+ homogeneity as we go. */
1707
+ for ( i = 0; i < n; i++ ) {
1708
+ VALUE elem = rb_ary_entry(list, i);
1709
+ CArray *ca;
1710
+ rb_check_carray_object(elem);
1711
+ TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
1712
+ if ( ca_is_face(ca) ) {
1713
+ any_face = 1;
1714
+ all_primitive = 0;
1715
+ if ( NIL_P(face_class) ) {
1716
+ face_class = rb_obj_class(elem);
1717
+ ref_face = ca;
1718
+ } else if ( rb_obj_class(elem) != face_class ) {
1719
+ all_face = 0; /* will be caught after the loop */
1720
+ } else if ( all_face ) {
1721
+ if ( ! ca_face_state_compatible(rb_ary_entry(list, 0), ref_face,
1722
+ elem, ca) ) {
1723
+ rb_raise(rb_eArgError,
1724
+ "promote_list: Face state mismatch across elements "
1725
+ "(= %s instance at index %ld differs from index 0)",
1726
+ rb_class2name(face_class), i);
1727
+ }
1728
+ }
1729
+ } else {
1730
+ all_face = 0;
1731
+ }
1732
+ }
1733
+
1734
+ /* Explicit data_type path: primitive Symbol, all elements must be
1735
+ primitive. Reject if any Face in list. */
1736
+ if ( ! NIL_P(data_type) ) {
1737
+ if ( any_face ) {
1738
+ rb_raise(rb_eArgError,
1739
+ "promote_list: data_type %s cannot be applied to a list "
1740
+ "containing Face elements (= Face cannot be coerced to "
1741
+ "a primitive without losing identity)",
1742
+ RSTRING_PTR(rb_inspect(data_type)));
1743
+ }
1744
+ {
1745
+ VALUE out = rb_ary_new_capa(n);
1746
+ static ID id_wrap_readonly = 0;
1747
+ if ( id_wrap_readonly == 0 ) id_wrap_readonly = rb_intern("wrap_readonly");
1748
+ for ( i = 0; i < n; i++ ) {
1749
+ VALUE coerced = rb_funcall(klass, id_wrap_readonly, 2,
1750
+ rb_ary_entry(list, i), data_type);
1751
+ rb_ary_push(out, coerced);
1752
+ }
1753
+ return out;
1754
+ }
1755
+ }
1756
+
1757
+ /* Auto-detect path. */
1758
+ if ( any_face && ! all_face ) {
1759
+ if ( all_primitive == 0 && any_face ) {
1760
+ /* Mixed: at least one Face and at least one non-Face,
1761
+ OR mixed Face classes. Both are rejected. */
1762
+ rb_raise(rb_eArgError,
1763
+ "promote_list: cannot mix Face and non-Face (or heterogeneous "
1764
+ "Face classes); pass a homogeneous Face list, or strip Face "
1765
+ "manually with .parent for the storage-level layout");
1766
+ }
1767
+ }
1768
+
1769
+ if ( all_face ) {
1770
+ /* Homogeneous Face: validate portability, then pass through. */
1771
+ if ( n > 1 && ! ca_face_state_portable(ref_face->obj_type, face_class) ) {
1772
+ rb_raise(rb_eArgError,
1773
+ "promote_list: %s state is not portable across multiple "
1774
+ "elements (= per-parent storage like CAConstString's buffer); "
1775
+ "strip Face manually with .parent for a storage-level list",
1776
+ rb_class2name(face_class));
1777
+ }
1778
+ /* Return a fresh Array so callers can mutate without aliasing. */
1779
+ {
1780
+ VALUE out = rb_ary_new_capa(n);
1781
+ for ( i = 0; i < n; i++ ) rb_ary_push(out, rb_ary_entry(list, i));
1782
+ return out;
1783
+ }
1784
+ }
1785
+
1786
+ /* All primitive: result_type to determine common data_type, then
1787
+ wrap_readonly each element. */
1788
+ common = ca_arg_to_data_type(rb_ary_entry(list, 0));
1789
+ for ( i = 1; i < n; i++ ) {
1790
+ int8_t next = ca_arg_to_data_type(rb_ary_entry(list, i));
1791
+ common = ca_promote_type(common, next);
1792
+ }
1793
+ {
1794
+ VALUE common_sym = rb_ca_data_type_to_sym(common);
1795
+ VALUE out = rb_ary_new_capa(n);
1796
+ static ID id_wrap_readonly = 0;
1797
+ if ( id_wrap_readonly == 0 ) id_wrap_readonly = rb_intern("wrap_readonly");
1798
+ for ( i = 0; i < n; i++ ) {
1799
+ VALUE coerced = rb_funcall(klass, id_wrap_readonly, 2,
1800
+ rb_ary_entry(list, i), common_sym);
1801
+ rb_ary_push(out, coerced);
1802
+ }
1803
+ return out;
1804
+ }
1805
+ }
1806
+
1182
1807
  void
1183
1808
  rb_ca_cast_other (VALUE *self, volatile VALUE *other)
1184
1809
  {
@@ -1188,6 +1813,13 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
1188
1813
 
1189
1814
  TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
1190
1815
 
1816
+ /* Promote MemoryView-aware operand to CArray (CAWrap or CAStride).
1817
+ Excludes T_STRING which has its own legacy interpretation. */
1818
+ if ( ! rb_obj_is_carray(*other) && TYPE(*other) != T_STRING &&
1819
+ rb_memory_view_available_p(*other) ) {
1820
+ *other = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, *other);
1821
+ }
1822
+
1191
1823
  if ( ! rb_obj_is_carray(*other) ) {
1192
1824
  if ( rb_ca_is_object_type(*self) ) {
1193
1825
  *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
@@ -1202,30 +1834,9 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
1202
1834
  }
1203
1835
  #endif
1204
1836
  else {
1205
- switch ( TYPE(*other) ) {
1206
- case T_FIXNUM:
1207
- case T_BIGNUM:
1208
- *other = rb_cscalar_new_with_value(CA_INT64, 0, *other);
1209
- break;
1210
- case T_FLOAT:
1211
- *other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
1212
- break;
1213
- case T_TRUE:
1214
- case T_FALSE:
1215
- *other = rb_cscalar_new_with_value(CA_BOOLEAN, 0, *other);
1216
- break;
1217
- default:
1218
- #ifdef HAVE_COMPLEX_H
1219
- if ( rb_obj_is_kind_of(*other, rb_cCComplex) ) {
1220
- *other = rb_cscalar_new_with_value(CA_CMPLX128, 0, *other);
1221
- break;
1222
- }
1223
- #endif
1224
- *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
1225
- break;
1226
- }
1837
+ *other = rb_cscalar_new_with_value(ca_value_to_data_type(*other), 0, *other);
1227
1838
  }
1228
-
1839
+
1229
1840
  TypedData_Get_Struct(*other, CScalar, &cscalar_data_type, cs);
1230
1841
 
1231
1842
  test0 = ca_cast_table2[cs->data_type][ca->data_type];
@@ -1238,11 +1849,6 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
1238
1849
 
1239
1850
  TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1240
1851
 
1241
- if ( cb->obj_type == CA_OBJ_UNBOUND_REPEAT ) {
1242
- *other = ca_ubrep_bind_with(*other, *self);
1243
- TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
1244
- }
1245
-
1246
1852
  test1 = ca_cast_table[cb->data_type][ca->data_type];
1247
1853
 
1248
1854
  if ( test1 == 0 ) {
@@ -1259,10 +1865,10 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
1259
1865
  ca_type_name[cb->data_type]);
1260
1866
  }
1261
1867
 
1262
- /* @overload cast_with (other)
1263
-
1264
- [TBD]
1265
- */
1868
+ /* CArray#cast_with(other) -- coerce self and other to a common
1869
+ representation via rb_ca_cast_self_or_other and return them as a
1870
+ two-element [self, other] array. User doc lives in
1871
+ yard-stubs/carray_cast.rb. */
1266
1872
 
1267
1873
  VALUE
1268
1874
  rb_ca_cast_with (VALUE self, VALUE other)
@@ -1276,8 +1882,289 @@ rb_ca_cast_with (VALUE self, VALUE other)
1276
1882
  return rb_assoc_new(self, other);
1277
1883
  }
1278
1884
 
1885
+ /* -----------------------------------------------------------------------
1886
+ clip_<type> family — clip into the target data type's representable
1887
+ range, then cast. Sugar for `clip(lo, hi).as_<type>`.
1888
+ ----------------------------------------------------------------------- */
1889
+
1890
+ #define CLIP_CAST_FUNC(name, lo_expr, hi_expr, cast_func) \
1891
+ static VALUE \
1892
+ rb_ca_##name (VALUE self) \
1893
+ { \
1894
+ return cast_func(rb_ca_clip(self, lo_expr, hi_expr)); \
1895
+ }
1896
+
1897
+ CLIP_CAST_FUNC(clip_int8, INT2NUM(-128), INT2NUM(127), rb_ca_as_int8)
1898
+ CLIP_CAST_FUNC(clip_int16, INT2NUM(-32768), INT2NUM(32767), rb_ca_as_int16)
1899
+ CLIP_CAST_FUNC(clip_int32, INT2NUM(-2147483648), INT2NUM(2147483647), rb_ca_as_int32)
1900
+ CLIP_CAST_FUNC(clip_int64, LL2NUM(-9223372036854775807-1), LL2NUM(9223372036854775807), rb_ca_as_int64)
1901
+ CLIP_CAST_FUNC(clip_uint8, INT2NUM(0), INT2NUM(255), rb_ca_as_uint8)
1902
+ CLIP_CAST_FUNC(clip_uint16, INT2NUM(0), INT2NUM(65535), rb_ca_as_uint16)
1903
+ CLIP_CAST_FUNC(clip_uint32, INT2NUM(0), UINT2NUM(4294967295U), rb_ca_as_uint32)
1904
+
1905
+ #undef CLIP_CAST_FUNC
1906
+
1907
+ /* CArray#clip_uint64 -- dedicated implementation.
1908
+
1909
+ UINT64_MAX (= 2^64-1) is not exactly representable in float64; the nearest
1910
+ double rounds up to 2^64. A generic clip-then-cast path therefore clamps
1911
+ an overflowing float source (e.g. 1e20) to 2^64 and the subsequent cast to
1912
+ uint64 wraps around to 0. For floating-point sources we take a saturating
1913
+ path: compare in float space against 2^64 (which IS representable) and
1914
+ saturate to UINT64_MAX above it and 0 below zero. Other source data types use
1915
+ the plain clip-then-cast path. */
1916
+ static VALUE
1917
+ rb_ca_clip_uint64 (VALUE self)
1918
+ {
1919
+ CArray *ca;
1920
+ GetCArray(self, ca);
1921
+ int dt = ca->data_type;
1922
+ if ( dt == CA_FLOAT32 || dt == CA_FLOAT64 ) {
1923
+ volatile VALUE vsrc = ( dt == CA_FLOAT64 ) ? self : rb_ca_as_float64(self);
1924
+ CArray *src;
1925
+ GetCArray(vsrc, src);
1926
+ volatile VALUE vout = rb_carray_new(CA_UINT64, ca->ndim, ca->dim, 0, NULL);
1927
+ CArray *out;
1928
+ GetCArray(vout, out);
1929
+ ca_attach(src);
1930
+ double *sp = (double *) src->ptr;
1931
+ uint64_t *op = (uint64_t *) out->ptr;
1932
+ ca_size_t n = ca->elements;
1933
+ const double LIMIT = 18446744073709551616.0; /* 2^64, exact in f64 */
1934
+ for ( ca_size_t i = 0; i < n; i++ ) {
1935
+ double v = sp[i];
1936
+ if ( v != v ) op[i] = 0; /* NaN -> 0 */
1937
+ else if ( v >= LIMIT ) op[i] = UINT64_MAX;
1938
+ else if ( v <= 0.0 ) op[i] = 0;
1939
+ else op[i] = (uint64_t) v;
1940
+ }
1941
+ ca_detach(src);
1942
+ if ( ca_has_mask(ca) ) {
1943
+ ca_copy_mask(out, ca);
1944
+ }
1945
+ return vout;
1946
+ }
1947
+ return rb_ca_as_uint64(rb_ca_clip(self, INT2NUM(0),
1948
+ ULL2NUM(18446744073709551615ULL)));
1949
+ }
1950
+
1951
+ /* ------------------------------------------------------------------------
1952
+ Global cast functions CA_INT32(data) ... CA_OBJECT(data) etc.
1953
+
1954
+ Polymorphic cast (NOT a fresh allocator): `data` is coerced into a CArray
1955
+ of the target data_type, dispatching on its Ruby class:
1956
+
1957
+ Array -> shape-guessed CArray, element-wise store (C fast path)
1958
+ CArray -> copy if same data_type, else #to_type (C fast path)
1959
+ nil -> empty CArray (C fast path)
1960
+ Range / String / Numeric / #to_ca responder (Ruby fallback)
1961
+
1962
+ The cold / Ruby-natural branches (arange arithmetic, the whitespace/`,`/`;`
1963
+ string parser, generic coercion) stay in Ruby as `CArray.__cast_rest__`
1964
+ (carray/basics.rb, eager-loaded). `type` is passed to the fallback as the
1965
+ data_type Symbol so the Ruby side keeps its original `type == CA_OBJECT`
1966
+ style comparisons.
1967
+ ------------------------------------------------------------------------ */
1968
+
1969
+ static ID id_new_cast = 0, id_guess_array_shape_cast = 0, id_cast_string = 0,
1970
+ id_to_ca_cast = 0, id_length_cast = 0,
1971
+ id_begin_cast = 0, id_end_cast = 0, id_to_a_cast = 0,
1972
+ id_exclude_end_p_cast = 0, id_abs_cast = 0, id_floor_cast = 0,
1973
+ id_op_minus = 0, id_op_div = 0, id_op_plus = 0,
1974
+ id_op_le = 0, id_op_eq = 0, id_op_uminus = 0;
1975
+
1976
+ /* Cross-type cast helper: v.to_type(sym) with no bytes (= in-file call to
1977
+ the #to_type implementation, no Ruby method dispatch). */
1978
+ static VALUE
1979
+ ca_cast_to_type1 (VALUE v, VALUE sym)
1980
+ {
1981
+ VALUE list[1];
1982
+ list[0] = sym;
1983
+ return rb_ca_to_type_internal(1, list, v);
1984
+ }
1985
+
1986
+ static VALUE
1987
+ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
1988
+ {
1989
+ VALUE v = ( argc >= 1 ) ? argv[0] : Qnil;
1990
+ VALUE sym = ID2SYM(ca_data_type_sym[data_type]);
1991
+
1992
+ if ( TYPE(v) == T_ARRAY ) {
1993
+ volatile VALUE shape, obj;
1994
+ shape = rb_funcall(rb_cCArray, id_guess_array_shape_cast, 1, v);
1995
+ obj = rb_funcall(rb_cCArray, id_new_cast, 2, sym, shape);
1996
+ rb_ca_store_all(obj, v);
1997
+ return obj;
1998
+ }
1999
+ else if ( RTEST(rb_obj_is_kind_of(v, rb_cCArray)) ) {
2000
+ CArray *ca;
2001
+ TypedData_Get_Struct(v, CArray, &carray_data_type, ca);
2002
+ if ( ca->data_type == data_type ) {
2003
+ return rb_ca_copy(v);
2004
+ }
2005
+ return ca_cast_to_type1(v, sym);
2006
+ }
2007
+ else if ( NIL_P(v) ) {
2008
+ ca_size_t dim0 = 0;
2009
+ return rb_carray_new(data_type, 1, &dim0, 0, NULL);
2010
+ }
2011
+ else if ( RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
2012
+ /* arange: n = ((end - begin).abs / step).floor (+1 unless exclude_end),
2013
+ then seq(begin, sign * step.abs). */
2014
+ volatile VALUE vbeg, vend, step, n;
2015
+ int sign;
2016
+ ca_size_t dn;
2017
+ VALUE obj, step_abs, signed_step;
2018
+
2019
+ vbeg = rb_funcall(v, id_begin_cast, 0);
2020
+ vend = rb_funcall(v, id_end_cast, 0);
2021
+ step = ( argc >= 2 ) ? argv[1] : Qnil;
2022
+ if ( RTEST(step) && RTEST(rb_funcall(step, id_op_eq, 1, INT2FIX(0))) ) {
2023
+ rb_raise(rb_eRuntimeError, "step should not be 0");
2024
+ }
2025
+ if ( data_type == CA_OBJECT && !RTEST(step) ) {
2026
+ VALUE va = rb_funcall(v, id_to_a_cast, 0); /* CA_OBJECT(v.to_a) */
2027
+ return ca_cast_impl(CA_OBJECT, 1, &va);
2028
+ }
2029
+ if ( !RTEST(step) ) step = INT2FIX(1);
2030
+ n = rb_funcall(vend, id_op_minus, 1, vbeg);
2031
+ n = rb_funcall(n, id_abs_cast, 0);
2032
+ n = rb_funcall(n, id_op_div, 1, step);
2033
+ n = rb_funcall(n, id_floor_cast, 0);
2034
+ if ( !RTEST(rb_funcall(v, id_exclude_end_p_cast, 0)) ) {
2035
+ n = rb_funcall(n, id_op_plus, 1, INT2FIX(1));
2036
+ }
2037
+ sign = RTEST(rb_funcall(vbeg, id_op_le, 1, vend)) ? 1 : -1;
2038
+ dn = NUM2SIZE(n);
2039
+ obj = rb_carray_new(data_type, 1, &dn, 0, NULL);
2040
+ step_abs = rb_funcall(step, id_abs_cast, 0);
2041
+ signed_step = ( sign == 1 ) ? step_abs : rb_funcall(step_abs, id_op_uminus, 0);
2042
+ return rb_ca_seq(obj, vbeg, signed_step);
2043
+ }
2044
+ else if ( TYPE(v) == T_STRING ) {
2045
+ /* The whitespace / `,` / `;` / `_`->UNDEF parser is far more natural in
2046
+ Ruby; only this branch stays there (carray/basics.rb). */
2047
+ return rb_funcall(rb_cCArray, id_cast_string, 2, sym, v);
2048
+ }
2049
+ else {
2050
+ /* Numeric / #to_ca responder */
2051
+ if ( rb_respond_to(v, id_to_ca_cast) ) {
2052
+ VALUE ca = rb_funcall(v, id_to_ca_cast, 0);
2053
+ CArray *cap;
2054
+ TypedData_Get_Struct(ca, CArray, &carray_data_type, cap);
2055
+ return ( cap->data_type == data_type ) ? ca : ca_cast_to_type1(ca, sym);
2056
+ }
2057
+ return rb_cscalar_new_with_value(data_type, 0, v);
2058
+ }
2059
+ }
2060
+
2061
+ #define DEFINE_CA_CAST(cfunc, dt) \
2062
+ static VALUE \
2063
+ cfunc (int argc, VALUE *argv, VALUE self) \
2064
+ { \
2065
+ return ca_cast_impl((dt), argc, argv); \
2066
+ }
2067
+
2068
+ DEFINE_CA_CAST(rb_ca_cast_boolean, CA_BOOLEAN)
2069
+ DEFINE_CA_CAST(rb_ca_cast_int8, CA_INT8)
2070
+ DEFINE_CA_CAST(rb_ca_cast_uint8, CA_UINT8)
2071
+ DEFINE_CA_CAST(rb_ca_cast_int16, CA_INT16)
2072
+ DEFINE_CA_CAST(rb_ca_cast_uint16, CA_UINT16)
2073
+ DEFINE_CA_CAST(rb_ca_cast_int32, CA_INT32)
2074
+ DEFINE_CA_CAST(rb_ca_cast_uint32, CA_UINT32)
2075
+ DEFINE_CA_CAST(rb_ca_cast_int64, CA_INT64)
2076
+ DEFINE_CA_CAST(rb_ca_cast_uint64, CA_UINT64)
2077
+ DEFINE_CA_CAST(rb_ca_cast_float32, CA_FLOAT32)
2078
+ DEFINE_CA_CAST(rb_ca_cast_float64, CA_FLOAT64)
2079
+ DEFINE_CA_CAST(rb_ca_cast_cmplx64, CA_CMPLX64)
2080
+ DEFINE_CA_CAST(rb_ca_cast_cmplx128, CA_CMPLX128)
2081
+ DEFINE_CA_CAST(rb_ca_cast_object, CA_OBJECT)
2082
+ DEFINE_CA_CAST(rb_ca_cast_size, CA_SIZE)
2083
+
2084
+ #undef DEFINE_CA_CAST
2085
+
2086
+ /* to_type(:fixlen, bytes: bytes_v) via in-file #to_type implementation. */
2087
+ static VALUE
2088
+ ca_cast_to_fixlen (VALUE v, VALUE fixlen_sym, VALUE bytes_v)
2089
+ {
2090
+ VALUE list[2], ropt;
2091
+ ropt = rb_hash_new();
2092
+ rb_hash_aset(ropt, ID2SYM(rb_intern("bytes")), bytes_v);
2093
+ list[0] = fixlen_sym;
2094
+ list[1] = ropt;
2095
+ return rb_ca_to_type_internal(2, list, v);
2096
+ }
2097
+
2098
+ /* CA_FIXLEN(data, bytes: N) -- fully in C (no String-regex branch to keep in
2099
+ Ruby, unlike the numeric casts).
2100
+ Array -> bytes defaults to max top-level element #length; new + store
2101
+ CArray -> copy if already fixlen, else #to_type(:fixlen, bytes:)
2102
+ nil -> empty fixlen (bytes 0 when omitted, matching the old default)
2103
+ other -> #to_ca coerce, else CScalar.new(:fixlen, bytes:) { data } */
2104
+ static VALUE
2105
+ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
2106
+ {
2107
+ VALUE v, opts = Qnil, bytes_v = Qnil;
2108
+ VALUE fixlen_sym = ID2SYM(ca_data_type_sym[CA_FIXLEN]);
2109
+
2110
+ rb_scan_args(argc, argv, "11", &v, &opts);
2111
+ rb_scan_options(opts, "bytes", &bytes_v);
2112
+
2113
+ if ( RTEST(rb_obj_is_kind_of(v, rb_cCArray)) ) {
2114
+ CArray *ca;
2115
+ TypedData_Get_Struct(v, CArray, &carray_data_type, ca);
2116
+ if ( ca->data_type == CA_FIXLEN ) {
2117
+ return rb_ca_copy(v);
2118
+ }
2119
+ return ca_cast_to_fixlen(v, fixlen_sym, bytes_v);
2120
+ }
2121
+ else if ( TYPE(v) == T_ARRAY ) {
2122
+ volatile VALUE shape;
2123
+ ca_size_t dim[CA_RANK_MAX];
2124
+ long ndim, i;
2125
+ ca_size_t bytes;
2126
+ VALUE obj;
2127
+ if ( NIL_P(bytes_v) ) {
2128
+ /* bytes = v.map{|s| s.length}.max (top-level #length, duck-typed) */
2129
+ long len = RARRAY_LEN(v);
2130
+ ca_size_t maxlen = 0;
2131
+ for ( i = 0; i < len; i++ ) {
2132
+ ca_size_t l = NUM2SIZE(rb_funcall(rb_ary_entry(v, i), id_length_cast, 0));
2133
+ if ( l > maxlen ) maxlen = l;
2134
+ }
2135
+ bytes = maxlen;
2136
+ } else {
2137
+ bytes = NUM2SIZE(bytes_v);
2138
+ }
2139
+ shape = rb_funcall(rb_cCArray, id_guess_array_shape_cast, 1, v);
2140
+ ndim = RARRAY_LEN(shape);
2141
+ for ( i = 0; i < ndim; i++ ) dim[i] = NUM2SIZE(rb_ary_entry(shape, i));
2142
+ obj = rb_carray_new(CA_FIXLEN, (int8_t) ndim, dim, bytes, NULL);
2143
+ rb_ca_store_all(obj, v);
2144
+ return obj;
2145
+ }
2146
+ else if ( NIL_P(v) ) {
2147
+ ca_size_t dim0 = 0;
2148
+ ca_size_t bytes = NIL_P(bytes_v) ? 0 : NUM2SIZE(bytes_v);
2149
+ return rb_carray_new(CA_FIXLEN, 1, &dim0, bytes, NULL);
2150
+ }
2151
+ else {
2152
+ if ( rb_respond_to(v, id_to_ca_cast) ) {
2153
+ VALUE ca = rb_funcall(v, id_to_ca_cast, 0);
2154
+ CArray *cap;
2155
+ TypedData_Get_Struct(ca, CArray, &carray_data_type, cap);
2156
+ return ( cap->data_type == CA_FIXLEN )
2157
+ ? ca : ca_cast_to_fixlen(ca, fixlen_sym, bytes_v);
2158
+ }
2159
+ {
2160
+ ca_size_t bytes = NIL_P(bytes_v) ? 0 : NUM2SIZE(bytes_v);
2161
+ return rb_cscalar_new_with_value(CA_FIXLEN, bytes, v);
2162
+ }
2163
+ }
2164
+ }
2165
+
1279
2166
  void
1280
- Init_carray_cast ()
2167
+ Init_carray_cast (void)
1281
2168
  {
1282
2169
  /* CArray data_type conversion */
1283
2170
 
@@ -1295,10 +2182,8 @@ Init_carray_cast ()
1295
2182
  rb_define_method(rb_cCArray, "uint64", rb_ca_to_uint64, 0);
1296
2183
  rb_define_method(rb_cCArray, "float32", rb_ca_to_float32, 0);
1297
2184
  rb_define_method(rb_cCArray, "float64", rb_ca_to_float64, 0);
1298
- rb_define_method(rb_cCArray, "float128", rb_ca_to_float128, 0);
1299
2185
  rb_define_method(rb_cCArray, "cmplx64", rb_ca_to_cmplx64, 0);
1300
2186
  rb_define_method(rb_cCArray, "cmplx128", rb_ca_to_cmplx128, 0);
1301
- rb_define_method(rb_cCArray, "cmplx256", rb_ca_to_cmplx256, 0);
1302
2187
  rb_define_method(rb_cCArray, "object", rb_ca_to_VALUE, 0);
1303
2188
 
1304
2189
  rb_define_alias(rb_cCArray, "byte", "uint8");
@@ -1345,7 +2230,71 @@ Init_carray_cast ()
1345
2230
  "cast", rb_ca_s_cast, 1);
1346
2231
  rb_define_singleton_method(rb_cCArray,
1347
2232
  "cast_self_or_other", rb_ca_s_cast_self_or_other, 2);
2233
+ rb_define_singleton_method(rb_cCArray,
2234
+ "result_type", rb_ca_s_result_type, -1);
2235
+
2236
+ rb_define_singleton_method(rb_cCArray,
2237
+ "promote_list", rb_ca_s_promote_list, -1);
2238
+
2239
+ /* Global polymorphic cast functions: CA_INT32(data), CA_FLOAT64(data),
2240
+ ... CA_OBJECT(data), CA_FIXLEN(...). Implementation is the
2241
+ ca_cast_impl family above; dispatch on `data`'s Ruby class.
2242
+ Type-name aliases (CA_BYTE / CA_SHORT / CA_INT / CA_FLOAT /
2243
+ CA_DOUBLE / CA_COMPLEX / CA_DCOMPLEX / CA_SIZE) reuse the same C
2244
+ function as their canonical data_type. Paired with the type-tag
2245
+ classes registered in ext/carray_data_type.c. */
2246
+ id_new_cast = rb_intern("new");
2247
+ id_guess_array_shape_cast = rb_intern("guess_array_shape");
2248
+ id_cast_string = rb_intern("__cast_string__");
2249
+ id_to_ca_cast = rb_intern("to_ca");
2250
+ id_length_cast = rb_intern("length");
2251
+ id_begin_cast = rb_intern("begin");
2252
+ id_end_cast = rb_intern("end");
2253
+ id_to_a_cast = rb_intern("to_a");
2254
+ id_exclude_end_p_cast = rb_intern("exclude_end?");
2255
+ id_abs_cast = rb_intern("abs");
2256
+ id_floor_cast = rb_intern("floor");
2257
+ id_op_minus = rb_intern("-");
2258
+ id_op_div = rb_intern("/");
2259
+ id_op_plus = rb_intern("+");
2260
+ id_op_le = rb_intern("<=");
2261
+ id_op_eq = rb_intern("==");
2262
+ id_op_uminus = rb_intern("-@");
2263
+
2264
+ rb_define_global_function("CA_BOOLEAN", rb_ca_cast_boolean, -1);
2265
+ rb_define_global_function("CA_INT8", rb_ca_cast_int8, -1);
2266
+ rb_define_global_function("CA_UINT8", rb_ca_cast_uint8, -1);
2267
+ rb_define_global_function("CA_INT16", rb_ca_cast_int16, -1);
2268
+ rb_define_global_function("CA_UINT16", rb_ca_cast_uint16, -1);
2269
+ rb_define_global_function("CA_INT32", rb_ca_cast_int32, -1);
2270
+ rb_define_global_function("CA_UINT32", rb_ca_cast_uint32, -1);
2271
+ rb_define_global_function("CA_INT64", rb_ca_cast_int64, -1);
2272
+ rb_define_global_function("CA_UINT64", rb_ca_cast_uint64, -1);
2273
+ rb_define_global_function("CA_FLOAT32", rb_ca_cast_float32, -1);
2274
+ rb_define_global_function("CA_FLOAT64", rb_ca_cast_float64, -1);
2275
+ rb_define_global_function("CA_CMPLX64", rb_ca_cast_cmplx64, -1);
2276
+ rb_define_global_function("CA_CMPLX128", rb_ca_cast_cmplx128, -1);
2277
+ rb_define_global_function("CA_OBJECT", rb_ca_cast_object, -1);
2278
+ /* type-name aliases */
2279
+ rb_define_global_function("CA_BYTE", rb_ca_cast_uint8, -1);
2280
+ rb_define_global_function("CA_SHORT", rb_ca_cast_int16, -1);
2281
+ rb_define_global_function("CA_INT", rb_ca_cast_int32, -1);
2282
+ rb_define_global_function("CA_FLOAT", rb_ca_cast_float32, -1);
2283
+ rb_define_global_function("CA_DOUBLE", rb_ca_cast_float64, -1);
2284
+ rb_define_global_function("CA_COMPLEX", rb_ca_cast_cmplx64, -1);
2285
+ rb_define_global_function("CA_DCOMPLEX", rb_ca_cast_cmplx128, -1);
2286
+ rb_define_global_function("CA_SIZE", rb_ca_cast_size, -1);
2287
+ rb_define_global_function("CA_FIXLEN", rb_ca_cast_fixlen, -1);
1348
2288
 
1349
2289
  rb_define_method(rb_cCArray, "cast_with", rb_ca_cast_with, 1);
2290
+
2291
+ rb_define_method(rb_cCArray, "clip_int8", rb_ca_clip_int8, 0);
2292
+ rb_define_method(rb_cCArray, "clip_int16", rb_ca_clip_int16, 0);
2293
+ rb_define_method(rb_cCArray, "clip_int32", rb_ca_clip_int32, 0);
2294
+ rb_define_method(rb_cCArray, "clip_int64", rb_ca_clip_int64, 0);
2295
+ rb_define_method(rb_cCArray, "clip_uint8", rb_ca_clip_uint8, 0);
2296
+ rb_define_method(rb_cCArray, "clip_uint16", rb_ca_clip_uint16, 0);
2297
+ rb_define_method(rb_cCArray, "clip_uint32", rb_ca_clip_uint32, 0);
2298
+ rb_define_method(rb_cCArray, "clip_uint64", rb_ca_clip_uint64, 0);
1350
2299
  }
1351
2300