carray 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -25
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +1 -1
  5. data/NEWS.md +3 -0
  6. data/README.md +128 -44
  7. data/carray.gemspec +22 -24
  8. data/ext/ca_array_pool.c +91 -0
  9. data/ext/ca_axis_descriptor.h +186 -0
  10. data/ext/ca_axis_dispatch.c +924 -0
  11. data/ext/ca_axis_group.c +1208 -0
  12. data/ext/ca_bincmp_dispatch.c +76 -0
  13. data/ext/ca_bincmp_dispatch.h +85 -0
  14. data/ext/ca_binop_dispatch.c +125 -0
  15. data/ext/ca_binop_dispatch.h +159 -0
  16. data/ext/ca_categorical_iterator.c +1375 -0
  17. data/ext/ca_compare.c +94 -0
  18. data/ext/ca_compare.h +26 -0
  19. data/ext/ca_composite_dispatch.c +414 -0
  20. data/ext/ca_composite_dispatch.h +116 -0
  21. data/ext/ca_for_buffer.h +96 -0
  22. data/ext/ca_for_each_element.h +241 -0
  23. data/ext/ca_group_iter.c +304 -0
  24. data/ext/ca_iter_substrate.h +325 -0
  25. data/ext/ca_kernel_iterator.c +4321 -0
  26. data/ext/ca_kernel_iterator.h +2603 -0
  27. data/ext/ca_moncmp_dispatch.c +37 -0
  28. data/ext/ca_moncmp_dispatch.h +62 -0
  29. data/ext/ca_monop_dispatch.c +200 -0
  30. data/ext/ca_monop_dispatch.h +235 -0
  31. data/ext/ca_obj_array.c +355 -359
  32. data/ext/ca_obj_bincmp.c +809 -0
  33. data/ext/ca_obj_binop.c +892 -0
  34. data/ext/ca_obj_bitarray.c +369 -164
  35. data/ext/ca_obj_bitfield.c +294 -234
  36. data/ext/ca_obj_block.c +189 -711
  37. data/ext/ca_obj_byte_swap.c +766 -0
  38. data/ext/ca_obj_const_string.c +965 -0
  39. data/ext/ca_obj_face.c +670 -0
  40. data/ext/ca_obj_face.h +247 -0
  41. data/ext/ca_obj_fake.c +228 -100
  42. data/ext/ca_obj_farray.c +54 -441
  43. data/ext/ca_obj_field.c +82 -529
  44. data/ext/ca_obj_fixlen_string.c +306 -0
  45. data/ext/ca_obj_grid.c +858 -440
  46. data/ext/ca_obj_meld.c +1034 -0
  47. data/ext/ca_obj_moncmp.c +569 -0
  48. data/ext/ca_obj_monop.c +1111 -0
  49. data/ext/ca_obj_object.c +774 -298
  50. data/ext/ca_obj_record.c +468 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +569 -459
  53. data/ext/ca_obj_remap.c +475 -0
  54. data/ext/ca_obj_repeat.c +92 -477
  55. data/ext/ca_obj_roll.c +616 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1296 -0
  58. data/ext/ca_obj_shift.c +230 -792
  59. data/ext/ca_obj_source.c +78 -0
  60. data/ext/ca_obj_stack.c +1173 -0
  61. data/ext/ca_obj_stride.c +2501 -0
  62. data/ext/ca_obj_string.c +268 -0
  63. data/ext/ca_obj_tile.c +614 -0
  64. data/ext/ca_obj_time.c +546 -0
  65. data/ext/ca_obj_timedelta.c +435 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +746 -0
  68. data/ext/ca_obj_unbound_repeat.c +208 -241
  69. data/ext/ca_obj_window.c +1131 -563
  70. data/ext/ca_op_byte_swap.c +175 -0
  71. data/ext/ca_op_ipower.c +319 -0
  72. data/ext/ca_op_powi.h +88 -0
  73. data/ext/ca_sort_kernels.h +132 -0
  74. data/ext/ca_sweep_engine.c +430 -0
  75. data/ext/ca_sweep_engine.h +157 -0
  76. data/ext/ca_transform_common.c +228 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +795 -402
  80. data/ext/carray_access.c +831 -711
  81. data/ext/carray_attribute.c +98 -330
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +283 -0
  84. data/ext/carray_call_cfunc.c +1360 -828
  85. data/ext/carray_call_cfunc.h +160 -0
  86. data/ext/carray_cast.c +1212 -301
  87. data/ext/carray_cast_func.rb +81 -40
  88. data/ext/carray_class.c +53 -63
  89. data/ext/carray_config.h +28 -0
  90. data/ext/carray_conversion.c +350 -346
  91. data/ext/carray_copy.c +156 -268
  92. data/ext/carray_core.c +1342 -199
  93. data/ext/carray_count.c +312 -0
  94. data/ext/carray_data_type.c +43 -19
  95. data/ext/carray_element.c +585 -213
  96. data/ext/carray_factorize.c +2542 -0
  97. data/ext/carray_generate.c +230 -559
  98. data/ext/carray_histogram.c +490 -0
  99. data/ext/carray_hold.c +228 -0
  100. data/ext/carray_index_classifier.c +1035 -0
  101. data/ext/carray_index_classifier.h +27 -0
  102. data/ext/carray_internal.h +120 -0
  103. data/ext/carray_kernels_bincmp.c +4445 -0
  104. data/ext/carray_kernels_binop.c +10979 -0
  105. data/ext/carray_kernels_init.c +36 -0
  106. data/ext/carray_kernels_map.c +3466 -0
  107. data/ext/carray_kernels_moncmp.c +2096 -0
  108. data/ext/carray_kernels_monop.c +18312 -0
  109. data/ext/carray_kernels_reduce_aggregate.c +25836 -0
  110. data/ext/carray_kernels_reduce_boolean.c +329 -0
  111. data/ext/carray_kernels_reduce_cumulative.c +14592 -0
  112. data/ext/carray_kernels_reduce_extreme.c +16947 -0
  113. data/ext/carray_kernels_reduce_variance.c +3909 -0
  114. data/ext/carray_kernels_scan.c +3692 -0
  115. data/ext/carray_kernels_search.c +32137 -0
  116. data/ext/carray_kernels_sort.c +10625 -0
  117. data/ext/carray_kernels_triop.c +1391 -0
  118. data/ext/carray_lazy.c +567 -0
  119. data/ext/carray_loop.c +88 -200
  120. data/ext/carray_mask.c +848 -154
  121. data/ext/carray_math_kernel.h +120 -0
  122. data/ext/carray_mathfunc.c +10 -241
  123. data/ext/carray_median_percentile.c +1257 -0
  124. data/ext/carray_memory_view.c +1625 -0
  125. data/ext/carray_operator.c +1526 -318
  126. data/ext/carray_order.c +664 -1394
  127. data/ext/carray_partition.c +416 -0
  128. data/ext/carray_random.c +518 -0
  129. data/ext/carray_scatter.c +357 -0
  130. data/ext/carray_slab.c +1219 -0
  131. data/ext/carray_slab.h +84 -0
  132. data/ext/carray_sort.c +829 -0
  133. data/ext/carray_sort_kernel.c +620 -0
  134. data/ext/carray_struct.c +695 -0
  135. data/ext/carray_test.c +343 -229
  136. data/ext/carray_undef.c +34 -17
  137. data/ext/carray_utils.c +175 -74
  138. data/ext/extconf.rb +216 -55
  139. data/ext/mk_call_cfunc.rb +480 -0
  140. data/ext/mkkernel.rb +8842 -0
  141. data/ext/ruby_carray.c +202 -101
  142. data/ext/version.h +4 -14
  143. data/ext/version.rb +5 -13
  144. data/lib/carray/arrow_tensor.rb +401 -0
  145. data/lib/carray/attribute.rb +166 -0
  146. data/lib/carray/autoload_carray.rb +220 -0
  147. data/lib/carray/autoload_method_extension.rb +44 -0
  148. data/lib/carray/axis_group.rb +711 -0
  149. data/lib/carray/basics.rb +481 -0
  150. data/lib/carray/bincount_nd.rb +358 -0
  151. data/lib/carray/block_iterator.rb +604 -0
  152. data/lib/carray/boolean_reduce.rb +109 -0
  153. data/lib/carray/categorical.rb +561 -0
  154. data/lib/carray/categorical_iterator.rb +1062 -0
  155. data/lib/carray/complex.rb +150 -0
  156. data/lib/carray/conditional.rb +216 -0
  157. data/lib/carray/const_string.rb +228 -0
  158. data/lib/carray/construct.rb +139 -328
  159. data/lib/carray/core_extensions.rb +240 -0
  160. data/lib/carray/data_type_extension.rb +233 -0
  161. data/lib/carray/fixlen_string.rb +95 -0
  162. data/lib/carray/frame/concat.rb +132 -0
  163. data/lib/carray/frame/convert.rb +95 -0
  164. data/lib/carray/frame/csv_parser.rb +211 -0
  165. data/lib/carray/frame/frame.rb +649 -0
  166. data/lib/carray/frame/group.rb +186 -0
  167. data/lib/carray/frame/io.rb +164 -0
  168. data/lib/carray/frame/join.rb +248 -0
  169. data/lib/carray/frame/records.rb +99 -0
  170. data/lib/carray/frame/sort.rb +113 -0
  171. data/lib/carray/frame/verbs.rb +299 -0
  172. data/lib/carray/frame.rb +16 -0
  173. data/lib/carray/histogram.rb +512 -0
  174. data/lib/carray/inspect.rb +37 -20
  175. data/lib/carray/iterator.rb +57 -349
  176. data/lib/carray/lazy.rb +889 -0
  177. data/lib/carray/mask_gap_fill.rb +200 -0
  178. data/lib/carray/math.rb +78 -342
  179. data/lib/carray/meld_reduce.rb +289 -0
  180. data/lib/carray/methods/align_addr.rb +116 -0
  181. data/lib/carray/methods/bin.rb +128 -0
  182. data/lib/carray/methods/bincount.rb +87 -0
  183. data/lib/carray/methods/bit_string.rb +92 -0
  184. data/lib/carray/methods/broadcast.rb +63 -0
  185. data/lib/carray/methods/choose.rb +39 -0
  186. data/lib/carray/methods/composition.rb +280 -0
  187. data/lib/carray/methods/gather_nd.rb +206 -0
  188. data/lib/carray/methods/index.rb +39 -0
  189. data/lib/carray/methods/insert_block.rb +99 -0
  190. data/lib/carray/methods/is_in.rb +141 -0
  191. data/lib/carray/methods/join.rb +90 -0
  192. data/lib/carray/methods/locate_addr.rb +47 -0
  193. data/lib/carray/methods/mask_duplicates.rb +41 -0
  194. data/lib/carray/methods/meshgrid.rb +91 -0
  195. data/lib/carray/methods/mode.rb +126 -0
  196. data/lib/carray/methods/nunique.rb +46 -0
  197. data/lib/carray/methods/resize.rb +56 -0
  198. data/lib/carray/methods/snap.rb +156 -0
  199. data/lib/carray/methods/string_format.rb +57 -0
  200. data/lib/carray/methods/unique.rb +47 -0
  201. data/lib/carray/methods/value_counts.rb +71 -0
  202. data/lib/carray/mkmf.rb +124 -101
  203. data/lib/carray/runtime.rb +108 -0
  204. data/lib/carray/serialize.rb +478 -167
  205. data/lib/carray/slab_iterator.rb +292 -0
  206. data/lib/carray/stack.rb +291 -0
  207. data/lib/carray/string.rb +56 -180
  208. data/lib/carray/string_operation_extension.rb +289 -0
  209. data/lib/carray/struct.rb +335 -323
  210. data/lib/carray/struct_builder.rb +697 -0
  211. data/lib/carray/table.rb +41 -2
  212. data/lib/carray/time.rb +2255 -38
  213. data/lib/carray/window_iterator.rb +655 -0
  214. data/lib/carray.rb +55 -57
  215. metadata +163 -130
  216. data/Rakefile +0 -51
  217. data/TODO.md +0 -18
  218. data/ext/ca_iter_block.c +0 -257
  219. data/ext/ca_iter_dimension.c +0 -299
  220. data/ext/ca_iter_window.c +0 -214
  221. data/ext/ca_obj_mapping.c +0 -644
  222. data/ext/carray_iterator.c +0 -641
  223. data/ext/carray_math.rb +0 -850
  224. data/ext/carray_numeric.c +0 -259
  225. data/ext/carray_sort_addr.c +0 -254
  226. data/ext/carray_stat.c +0 -2100
  227. data/ext/carray_stat_proc.rb +0 -1999
  228. data/ext/mkmath.rb +0 -741
  229. data/ext/ruby_ccomplex.c +0 -509
  230. data/ext/ruby_float_func.c +0 -86
  231. data/lib/carray/array.rb +0 -8
  232. data/lib/carray/autoload/autoload_base.rb +0 -19
  233. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  234. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  235. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  236. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  237. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  238. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  239. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  240. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  241. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  242. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  243. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  244. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  245. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  246. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  247. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  248. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  249. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  250. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  251. data/lib/carray/autoload.rb +0 -141
  252. data/lib/carray/basic.rb +0 -191
  253. data/lib/carray/broadcast.rb +0 -101
  254. data/lib/carray/compose.rb +0 -315
  255. data/lib/carray/convert.rb +0 -115
  256. data/lib/carray/info.rb +0 -110
  257. data/lib/carray/io/imagemagick.rb +0 -235
  258. data/lib/carray/mask.rb +0 -102
  259. data/lib/carray/math/histogram.rb +0 -177
  260. data/lib/carray/math/recurrence.rb +0 -93
  261. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  262. data/lib/carray/object/ca_obj_link.rb +0 -50
  263. data/lib/carray/object/ca_obj_pack.rb +0 -99
  264. data/lib/carray/obsolete.rb +0 -256
  265. data/lib/carray/ordering.rb +0 -181
  266. data/lib/carray/testing.rb +0 -51
  267. data/lib/carray/transform.rb +0 -109
  268. data/misc/Methods.ja.md +0 -182
  269. data/misc/NOTE +0 -51
  270. data/spec/Classes/CABitfield_spec.rb +0 -58
  271. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  272. data/spec/Classes/CABlock_spec.rb +0 -205
  273. data/spec/Classes/CAField_spec.rb +0 -39
  274. data/spec/Classes/CAGrid_spec.rb +0 -75
  275. data/spec/Classes/CAMap_spec.rb +0 -0
  276. data/spec/Classes/CAMapping_spec.rb +0 -105
  277. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  278. data/spec/Classes/CAObject_spec.rb +0 -33
  279. data/spec/Classes/CARefer_spec.rb +0 -93
  280. data/spec/Classes/CARepeat_spec.rb +0 -65
  281. data/spec/Classes/CASelect_spec.rb +0 -22
  282. data/spec/Classes/CAShift_spec.rb +0 -16
  283. data/spec/Classes/CAStruct_spec.rb +0 -71
  284. data/spec/Classes/CATranspose_spec.rb +0 -60
  285. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  286. data/spec/Classes/CAWindow_spec.rb +0 -54
  287. data/spec/Classes/CAWrap_spec.rb +0 -8
  288. data/spec/Classes/CArray_spec.rb +0 -184
  289. data/spec/Classes/CScalar_spec.rb +0 -55
  290. data/spec/Classes/ex1.rb +0 -46
  291. data/spec/Features/feature_130_spec.rb +0 -19
  292. data/spec/Features/feature_attributes_spec.rb +0 -280
  293. data/spec/Features/feature_boolean_spec.rb +0 -98
  294. data/spec/Features/feature_broadcast.rb +0 -116
  295. data/spec/Features/feature_cast_function.rb +0 -19
  296. data/spec/Features/feature_cast_spec.rb +0 -33
  297. data/spec/Features/feature_class_spec.rb +0 -84
  298. data/spec/Features/feature_complex_spec.rb +0 -42
  299. data/spec/Features/feature_composite_spec.rb +0 -124
  300. data/spec/Features/feature_convert_spec.rb +0 -46
  301. data/spec/Features/feature_copy_spec.rb +0 -123
  302. data/spec/Features/feature_creation_spec.rb +0 -84
  303. data/spec/Features/feature_element_spec.rb +0 -144
  304. data/spec/Features/feature_extream_spec.rb +0 -54
  305. data/spec/Features/feature_generate_spec.rb +0 -74
  306. data/spec/Features/feature_index_spec.rb +0 -69
  307. data/spec/Features/feature_mask_spec.rb +0 -580
  308. data/spec/Features/feature_math_spec.rb +0 -97
  309. data/spec/Features/feature_order_spec.rb +0 -146
  310. data/spec/Features/feature_ref_store_spec.rb +0 -209
  311. data/spec/Features/feature_serialization_spec.rb +0 -125
  312. data/spec/Features/feature_stat_spec.rb +0 -397
  313. data/spec/Features/feature_virtual_spec.rb +0 -48
  314. data/spec/Features/method_eq_spec.rb +0 -81
  315. data/spec/Features/method_is_nan_spec.rb +0 -12
  316. data/spec/Features/method_map_spec.rb +0 -54
  317. data/spec/Features/method_max_with.rb +0 -20
  318. data/spec/Features/method_min_with.rb +0 -19
  319. data/spec/Features/method_ne_spec.rb +0 -18
  320. data/spec/Features/method_project_spec.rb +0 -188
  321. data/spec/Features/method_ref_spec.rb +0 -27
  322. data/spec/Features/method_round_spec.rb +0 -11
  323. data/spec/Features/method_s_linspace_spec.rb +0 -48
  324. data/spec/Features/method_s_span_spec.rb +0 -14
  325. data/spec/Features/method_seq_spec.rb +0 -47
  326. data/spec/Features/method_sort_with.rb +0 -43
  327. data/spec/Features/method_sorted_with.rb +0 -29
  328. data/spec/Features/method_span_spec.rb +0 -42
  329. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  330. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  331. data/spec/spec_all.rb +0 -10
  332. data/utils/ca_ase.rb +0 -21
  333. data/utils/ca_methods.rb +0 -15
  334. data/utils/cast_checker.rb +0 -30
  335. data/utils/convert_test.rb +0 -73
  336. data/utils/extract_yard.rb +0 -22
  337. data/utils/guess_shape.rb +0 -76
  338. data/utils/monkey_patch_methods.rb +0 -62
  339. data/utils/remove_resource_fork.sh +0 -5
data/ext/carray_access.c CHANGED
@@ -1,22 +1,25 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
 
3
- carray_access.c
4
-
5
- This file is part of Ruby/CArray extension library.
6
-
7
- Copyright (C) 2005-2020 Hiroki Motoyoshi
3
+ The indexer: CArray#[] and #[]= plus their helpers (fill, addr2index,
4
+ index2addr, normalize_index, scan_index). Classifies an index spec via
5
+ rb_ca_scan_index (forwarded to ext/carray_index_classifier.c) and
6
+ dispatches each CA_REG_* case to the matching view constructor
7
+ (CABlock / CASelect / CAGrid / CARemap / CASlabIterator / ...).
8
8
 
9
9
  ---------------------------------------------------------------------------- */
10
10
 
11
11
  #include "carray.h"
12
+ #include "carray_internal.h" /* per-obj_type view constructors */
13
+ #include "ca_obj_face.h"
14
+ #include "carray_index_classifier.h" /* rb_ca_scan_index_v2 forward decl */
12
15
 
13
16
  static ID id_begin, id_end, id_excl_end;
14
17
  #define RANGE_BEG(r) (rb_funcall(r, id_begin, 0))
15
18
  #define RANGE_END(r) (rb_funcall(r, id_end, 0))
16
19
  #define RANGE_EXCL(r) (rb_funcall(r, id_excl_end, 0))
17
20
 
18
- static ID id_ca, id_to_ca;
19
- static VALUE sym_star, sym_perc;
21
+ static ID id_to_ca;
22
+ static VALUE sym_star, sym_perc, sym_under, sym_gt, sym_tilde;
20
23
  static VALUE S_CAInfo;
21
24
 
22
25
  VALUE
@@ -54,10 +57,10 @@ rb_ca_store_index (VALUE self, ca_size_t *idx, VALUE rval)
54
57
  ca_store_index(ca, idx, v);
55
58
  }
56
59
  else {
57
- char *v = malloc_with_check(ca->bytes);
60
+ char *v = xmalloc(ca->bytes);
58
61
  rb_ca_obj2ptr(self, rval, v);
59
62
  ca_store_index(ca, idx, v);
60
- free(v);
63
+ xfree(v);
61
64
  }
62
65
  }
63
66
 
@@ -82,10 +85,10 @@ rb_ca_fetch_index (VALUE self, ca_size_t *idx)
82
85
  out = rb_ca_ptr2obj(self, v);
83
86
  }
84
87
  else {
85
- char *v = malloc_with_check(ca->bytes);
88
+ char *v = xmalloc(ca->bytes);
86
89
  ca_fetch_index(ca, idx, v);
87
90
  out = rb_ca_ptr2obj(self, v);
88
- free(v);
91
+ xfree(v);
89
92
  }
90
93
 
91
94
  /* check if the element is masked */
@@ -98,6 +101,19 @@ rb_ca_fetch_index (VALUE self, ca_size_t *idx)
98
101
  }
99
102
  }
100
103
 
104
+ /* Face scalar decode (invoked if the subclass defines storage_to_scalar(raw)) */
105
+ CA_FACE_STORAGE_TO_SCALAR_IF_FACE(out, self, ca);
106
+
107
+ /* Boolean scalar access yields true/false, not Integer 0/1. Bulk paths
108
+ (to_a / cast / serialize via rb_ca_ptr2obj) keep 0/1. Gate on the raw
109
+ INT2FIX(0/1) so a boolean-storage Face that decoded to its own object is
110
+ left untouched; note INT2FIX(0) is truthy in Ruby, so map by value, not
111
+ by RTEST. */
112
+ if ( ca->data_type == CA_BOOLEAN &&
113
+ ( out == INT2FIX(0) || out == INT2FIX(1) ) ) {
114
+ out = ( out == INT2FIX(1) ) ? Qtrue : Qfalse;
115
+ }
116
+
101
117
  return out;
102
118
  }
103
119
 
@@ -134,10 +150,10 @@ rb_ca_store_addr (VALUE self, ca_size_t addr, VALUE rval)
134
150
  ca_store_addr(ca, addr, v);
135
151
  }
136
152
  else {
137
- char *v = malloc_with_check(ca->bytes);
153
+ char *v = xmalloc(ca->bytes);
138
154
  rb_ca_obj2ptr(self, rval, v);
139
155
  ca_store_addr(ca, addr, v);
140
- free(v);
156
+ xfree(v);
141
157
  }
142
158
  }
143
159
 
@@ -162,10 +178,10 @@ rb_ca_fetch_addr (VALUE self, ca_size_t addr)
162
178
  out = rb_ca_ptr2obj(self, v);
163
179
  }
164
180
  else {
165
- char *v = malloc_with_check(ca->bytes);
181
+ char *v = xmalloc(ca->bytes);
166
182
  ca_fetch_addr(ca, addr, v);
167
183
  out = rb_ca_ptr2obj(self, v);
168
- free(v);
184
+ xfree(v);
169
185
  }
170
186
 
171
187
  /* check if the element is masked */
@@ -178,18 +194,18 @@ rb_ca_fetch_addr (VALUE self, ca_size_t addr)
178
194
  }
179
195
  }
180
196
 
197
+ /* Face scalar decode */
198
+ CA_FACE_STORAGE_TO_SCALAR_IF_FACE(out, self, ca);
199
+
200
+ /* Boolean scalar access yields true/false (see rb_ca_fetch_index). */
201
+ if ( ca->data_type == CA_BOOLEAN &&
202
+ ( out == INT2FIX(0) || out == INT2FIX(1) ) ) {
203
+ out = ( out == INT2FIX(1) ) ? Qtrue : Qfalse;
204
+ }
205
+
181
206
  return out;
182
207
  }
183
208
 
184
- /* yard:
185
- class CArray
186
- def fill
187
- end
188
- def fill_copy
189
- end
190
- end
191
- */
192
-
193
209
  VALUE
194
210
  rb_ca_fill (VALUE self, VALUE rval)
195
211
  {
@@ -199,7 +215,7 @@ rb_ca_fill (VALUE self, VALUE rval)
199
215
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
200
216
 
201
217
  if ( ca_is_empty(ca) ) {
202
- return rval;
218
+ return self; /* empty = no-op fill; return self for chaining */
203
219
  }
204
220
 
205
221
  if ( rval == CA_UNDEF ) {
@@ -211,14 +227,14 @@ rb_ca_fill (VALUE self, VALUE rval)
211
227
  ca_fill(ca->mask, &one);
212
228
  }
213
229
  else {
214
- char *fval = malloc_with_check(ca->bytes);
230
+ char *fval = xmalloc(ca->bytes);
215
231
  boolean8_t zero = 0;
216
232
  rb_ca_obj2ptr(self, rval, fval);
217
233
  if ( ca_has_mask(ca) ) {
218
234
  ca_fill(ca->mask, &zero);
219
235
  }
220
236
  ca_fill(ca, fval);
221
- free(fval);
237
+ xfree(fval);
222
238
  }
223
239
 
224
240
  return self;
@@ -266,11 +282,6 @@ ary_guess_shape (VALUE ary, int level, int *max_level, ca_size_t *dim)
266
282
  }
267
283
  }
268
284
 
269
- /* yard:
270
- def CArray.guess_array_shape (arg)
271
- end
272
- */
273
-
274
285
  static VALUE
275
286
  rb_ca_s_guess_array_shape (VALUE self, VALUE ary)
276
287
  {
@@ -340,7 +351,7 @@ rb_ary_flatten_for_elements (VALUE ary, ca_size_t elements, void *ap)
340
351
  rb_raise(rb_eRuntimeError, "invalid shape array for conversion to carray");
341
352
  }
342
353
  else {
343
- VALUE out = rb_ary_new2(0);
354
+ volatile VALUE out = rb_ary_new2(0);
344
355
  int len = 0;
345
356
  ary_flatten_upto_level(ary, max_level, 0, out, &len);
346
357
  if ( len != elements ) {
@@ -366,7 +377,7 @@ rb_ary_flatten_for_elements (VALUE ary, ca_size_t elements, void *ap)
366
377
  }
367
378
 
368
379
  if ( same_shape ) {
369
- VALUE out = rb_ary_new2(0);
380
+ volatile VALUE out = rb_ary_new2(0);
370
381
  int len = 0;
371
382
  ary_flatten_upto_level(ary, ca->ndim-1, 0, out, &len);
372
383
 
@@ -388,7 +399,7 @@ rb_ary_flatten_for_elements (VALUE ary, ca_size_t elements, void *ap)
388
399
  }
389
400
 
390
401
  if ( level >= 0 ) {
391
- VALUE out = rb_ary_new2(0);
402
+ volatile VALUE out = rb_ary_new2(0);
392
403
  int len = 0;
393
404
  ary_flatten_upto_level(ary, level, 0, out, &len);
394
405
  if ( len != elements ) {
@@ -411,7 +422,7 @@ rb_ary_flatten_for_elements (VALUE ary, ca_size_t elements, void *ap)
411
422
  } \
412
423
  if ( index < 0 || index >= (dim) ) { \
413
424
  rb_raise(rb_eIndexError, \
414
- "index out of range at %i-dim ( %lld <=> 0..%lld )", \
425
+ "index out of range at %i-dim ( %" PRId64 " <=> 0..%" PRId64 " )", \
415
426
  i, (ca_size_t) index, (ca_size_t) (dim-1)); \
416
427
  }
417
428
 
@@ -419,522 +430,8 @@ void
419
430
  rb_ca_scan_index (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
420
431
  long argc, VALUE *argv, CAIndexInfo *info)
421
432
  {
422
- int32_t i;
423
-
424
- info->ndim = 0;
425
- info->select = NULL;
426
-
427
- if ( argc == 0 ) { /* ca[] -> CA_REG_ALL */
428
- info->type = CA_REG_ALL;
429
- return;
430
- }
431
-
432
- /* ca[:method, ...] -> CA_REG_METHOD_CALL
433
- ca[:i, ...] -> CA_REG_ITERATOR */
434
- if ( TYPE(argv[0]) == T_SYMBOL ) {
435
- const char *symstr = rb_id2name(SYM2ID(argv[0]));
436
- if ( strlen(symstr) > 1 ) { /* ca[:method, ...] -> CA_REG_METHOD_CALL */
437
- info->type = CA_REG_METHOD_CALL;
438
- info->symbol = argv[0];
439
- return;
440
- }
441
- }
442
-
443
- if ( argc == 1 ) {
444
-
445
- volatile VALUE arg = argv[0];
446
-
447
- if ( arg == Qfalse ) { /* ca[false] -> CA_REG_ALL */
448
- info->type = CA_REG_ALL;
449
- return;
450
- }
451
-
452
- if ( rb_obj_is_carray(arg) ) {
453
- CArray *cs;
454
- TypedData_Get_Struct(arg, CArray, &carray_data_type, cs);
455
- if ( ca_is_integer_type(cs) ) {
456
- #if 0
457
- if ( ca_ndim == 1 && cs->ndim == 1 ) { /* ca[g] -> CA_REG_GRID (1d) */
458
- info->type = CA_REG_GRID;
459
- }
460
- else { /* ca[m] -> CA_REG_MAPPER (2d...) */
461
- info->type = CA_REG_MAPPING;
462
- }
463
- #endif
464
- info->type = CA_REG_MAPPING;
465
- return;
466
- }
467
- else if ( ca_is_boolean_type(cs) ) {
468
- /* ca[selector] -> CA_REG_SELECT */
469
- if ( ca_elements != cs->elements ) {
470
- rb_raise(rb_eRuntimeError,
471
- "mismatch of # of elements ( %lld <=> %lld ) in reference by selection",
472
- (ca_size_t) cs->elements, (ca_size_t) ca_elements);
473
- }
474
- info->type = CA_REG_SELECT;
475
- info->select = cs;
476
- return;
477
- }
478
- else {
479
- rb_raise(rb_eIndexError,
480
- "data_type %s is invalid for reference by selection/mapping" \
481
- "(should be boolean or integer)",
482
- ca_type_name[cs->data_type]);
483
- }
484
- }
485
-
486
- if ( TYPE(arg) == T_STRING ) {
487
- if ( StringValuePtr(arg)[0] == '@' ) { /* ca["@name"] -> CA_REG_ATTRIBUTE */
488
- info->type = CA_REG_ATTRIBUTE;
489
- info->symbol = rb_str_new2(StringValuePtr(arg)+1);
490
- }
491
- else { /* ca["field"] -> CA_REG_MEMBER */
492
- info->type = CA_REG_MEMBER;
493
- info->symbol = ID2SYM(rb_intern(StringValuePtr(arg)));
494
- }
495
- return;
496
- }
497
-
498
- if ( arg == sym_star ) { /* ca[:*] -> CA_REG_UNBOUND_REPEAT */
499
- info->type = CA_REG_UNBOUND_REPEAT;
500
- return;
501
- }
502
-
503
- if ( ca_ndim > 1 ) { /* ca.ndim > 1 */
504
- if ( rb_obj_is_kind_of(arg, rb_cInteger) ) { /* ca[n] -> CA_REG_ADDRESS */
505
- ca_size_t addr;
506
- info->type = CA_REG_ADDRESS;
507
- info->ndim = 1;
508
- addr = NUM2SIZE(arg);
509
- if ( info->range_check ) {
510
- CA_CHECK_INDEX(addr, ca_elements);
511
- }
512
- info->index[0].scalar = addr;
513
- return;
514
- }
515
- else if ( arg == Qnil ) {
516
- info->type = CA_REG_FLATTEN;
517
- return;
518
- }
519
- else { /* ca[i..j] -> CA_REG_ADDRESS_COMPLEX */
520
- info->type = CA_REG_ADDRESS_COMPLEX;
521
- return;
522
- }
523
- }
524
- }
525
-
526
- /* continue to next section */
527
-
528
- if ( argc >= 1 ) {
529
- int8_t is_point = 0, is_all = 0, is_iterator = 0, is_repeat=0, is_grid=0;
530
- int8_t has_rubber = 0;
531
- int32_t *index_type = info->index_type;
532
- CAIndex *index = info->index;
533
-
534
- for (i=0; i<argc; i++) {
535
- if ( argv[i] == sym_perc ) {
536
- is_repeat = 1;
537
- goto loop_exit; /* ca[--,:%,--] -> CA_REG_REPEAT */
538
- }
539
-
540
- if ( argv[i] == sym_star ) {
541
- is_repeat = 2;
542
- goto loop_exit; /* ca[--,:*,--] -> CA_REG_UNBOUND_REPEAT */
543
- }
544
-
545
- if ( argv[i] == Qfalse ) { /* ca[--,false,--] (rubber dimension) */
546
- has_rubber = 1;
547
- if ( argc > ca_ndim + 1 ) {
548
- rb_raise(rb_eIndexError,
549
- "index specification exceeds the ndim of carray (%i)",
550
- ca_ndim);
551
- }
552
- }
553
- }
554
-
555
- if ( ! has_rubber && ca_ndim != argc ) {
556
- rb_raise(rb_eIndexError,
557
- "number of indices exceeds the ndim of carray (%i > %i)",
558
- (int) argc, ca_ndim);
559
- }
560
-
561
- info->ndim = argc;
562
-
563
- for (i=0; i<argc; i++) {
564
- volatile VALUE arg = argv[i];
565
-
566
- retry:
567
-
568
- if ( rb_obj_is_kind_of(arg, rb_cInteger) ) { /* ca[--,i,--] */
569
- ca_size_t scalar;
570
- index_type[i] = CA_IDX_SCALAR;
571
- scalar = NUM2SIZE(arg);
572
- if ( info->range_check ) {
573
- CA_CHECK_INDEX_AT(scalar, ca_dim[i], i);
574
- }
575
- index[i].scalar = scalar;
576
- }
577
- else if ( NIL_P(arg) ) { /* ca[--,nil,--] */
578
- index_type[i] = CA_IDX_ALL;
579
- }
580
- else if ( arg == Qfalse ) { /* ca[--,false,--] */
581
- int8_t rndim = ca_ndim - argc + 1;
582
- int8_t j;
583
- for (j=0; j<rndim; j++) {
584
- index_type[i+j] = CA_IDX_ALL;
585
- }
586
- i += rndim-1;
587
- argv -= rndim-1;
588
- argc = ca_ndim;
589
- info->ndim = ca_ndim;
590
- }
591
- else if ( rb_obj_is_kind_of(arg, rb_cRange) ) { /* ca[--,i..j,--] */
592
- ca_size_t start, last, excl, count, step;
593
- volatile VALUE iv_beg, iv_end, iv_excl;
594
- iv_beg = RANGE_BEG(arg);
595
- iv_end = RANGE_END(arg);
596
- iv_excl = RANGE_EXCL(arg);
597
- index_type[i] = CA_IDX_BLOCK; /* convert to block */
598
- if ( NIL_P(iv_beg) ) {
599
- start = 0;
600
- }
601
- else {
602
- start = NUM2SIZE(iv_beg);
603
- }
604
- if ( NIL_P(iv_end) ) {
605
- last = -1;
606
- }
607
- else {
608
- last = NUM2SIZE(iv_end);
609
- }
610
- excl = RTEST(iv_excl);
611
-
612
- if ( info->range_check ) {
613
- CA_CHECK_INDEX_AT(start, ca_dim[i], i);
614
- }
615
-
616
- if ( last < 0 ) { /* don't use CA_CHECK_INDEX for excl */
617
- last += ca_dim[i];
618
- }
619
- if ( excl && ( start == last ) ) {
620
- index[i].block.start = start;
621
- index[i].block.count = 0;
622
- index[i].block.step = 1;
623
- }
624
- else {
625
- if ( excl ) {
626
- last += ( (last>=start) ? -1 : 1 );
627
- }
628
- if ( info->range_check ) {
629
- if ( last < 0 || last >= ca_dim[i] ) {
630
- rb_raise(rb_eIndexError,
631
- "index %lld is out of range (0..%lld) at %i-dim",
632
- (ca_size_t) last, (ca_size_t) (ca_dim[i]-1), i);
633
- }
634
- }
635
- index[i].block.start = start;
636
- index[i].block.count = count = llabs(last - start) + 1;
637
- index[i].block.step = step = ( last >= start ) ? 1 : -1;
638
- }
639
- }
640
- #ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
641
- else if ( rb_obj_is_kind_of(arg, rb_cArithSeq) ) { /* ca[--,ArithSeq,--]*/
642
- ca_size_t start, last, excl, count, step, bound;
643
- volatile VALUE iv_beg, iv_end, iv_excl;
644
- rb_arithmetic_sequence_components_t x;
645
- rb_arithmetic_sequence_extract(arg, &x);
646
- iv_beg = x.begin;
647
- iv_end = x.end;
648
- iv_excl = x.exclude_end;
649
- step = NUM2SIZE(x.step);
650
- if ( NIL_P(iv_beg) ) {
651
- start = 0;
652
- }
653
- else {
654
- start = NUM2SIZE(iv_beg);
655
- }
656
- if ( NIL_P(iv_end) ) {
657
- last = -1;
658
- }
659
- else {
660
- last = NUM2SIZE(iv_end);
661
- }
662
- excl = RTEST(iv_excl);
663
- if ( step == 0 ) {
664
- rb_raise(rb_eRuntimeError,
665
- "step in index equals to 0 in block reference");
666
- }
667
- index_type[i] = CA_IDX_BLOCK;
668
- CA_CHECK_INDEX_AT(start, ca_dim[i], i);
669
- if ( last < 0 ) {
670
- last += ca_dim[i];
671
- }
672
- if ( excl && ( start == last ) ) {
673
- index[i].block.start = start;
674
- index[i].block.count = 0;
675
- index[i].block.step = 1;
676
- }
677
- else {
678
- if ( excl ) {
679
- last += ( (last>=start) ? -1 : 1 );
680
- }
681
- if ( last < 0 || last >= ca_dim[i] ) {
682
- rb_raise(rb_eIndexError,
683
- "index %lld is out of range (0..%lld) at %i-dim",
684
- (ca_size_t) last, (ca_size_t) (ca_dim[i]-1), i);
685
- }
686
- if ( (last - start) * step < 0 ) {
687
- count = 1;
688
- }
689
- else {
690
- count = llabs(last - start)/llabs(step) + 1;
691
- }
692
- bound = start + (count - 1)*step;
693
- CA_CHECK_INDEX_AT(bound, ca_dim[i], i);
694
- index[i].block.start = start;
695
- index[i].block.count = count;
696
- index[i].block.step = step;
697
- }
698
- }
699
- #endif
700
- else if ( TYPE(arg) == T_ARRAY ) { /* ca[--,[array],--] */
701
- if ( RARRAY_LEN(arg) == 1 ) {
702
- VALUE arg0 = rb_ary_entry(arg, 0);
703
- if ( NIL_P(arg0) ) { /* ca[--,[nil],--]*/
704
- index_type[i] = CA_IDX_ALL;
705
- }
706
- else if ( rb_obj_is_kind_of(arg0, rb_cRange) ) {
707
- /* ca[--,[i..j],--] */
708
- arg = arg0;
709
- goto retry;
710
- }
711
- else { /* ca[--,[i],--]*/
712
- ca_size_t start;
713
- start = NUM2SIZE(arg0);
714
- CA_CHECK_INDEX_AT(start, ca_dim[i], i);
715
- index_type[i] = CA_IDX_BLOCK;
716
- index[i].block.start = start;
717
- index[i].block.count = 1;
718
- index[i].block.step = 1;
719
- }
720
- }
721
- else if ( RARRAY_LEN(arg) == 2 ) {
722
- VALUE arg0 = rb_ary_entry(arg, 0);
723
- VALUE arg1 = rb_ary_entry(arg, 1);
724
- if ( NIL_P(arg0) ) { /* ca[--,[nil,k],--]*/
725
- ca_size_t start, last, count, step, bound;
726
- step = NUM2SIZE(arg1);
727
- if ( step == 0 ) {
728
- rb_raise(rb_eRuntimeError,
729
- "step in index equals to 0 in block reference");
730
- }
731
- start = 0;
732
- last = ca_dim[i]-1;
733
- if ( step < 0 ) {
734
- count = 1;
735
- }
736
- else {
737
- count = last/step + 1;
738
- }
739
- bound = start + (count - 1)*step;
740
- CA_CHECK_INDEX_AT(bound, ca_dim[i], i);
741
- index_type[i] = CA_IDX_BLOCK;
742
- index[i].block.start = start;
743
- index[i].block.count = count;
744
- index[i].block.step = step;
745
- }
746
- else if ( rb_obj_is_kind_of(arg0, rb_cRange) ) { /* ca[--,[i..j,k],--]*/
747
- ca_size_t start, last, excl, count, step, bound;
748
- volatile VALUE iv_beg, iv_end, iv_excl;
749
- iv_beg = RANGE_BEG(arg0);
750
- iv_end = RANGE_END(arg0);
751
- iv_excl = RANGE_EXCL(arg0);
752
- if ( NIL_P(iv_beg) ) {
753
- start = 0;
754
- }
755
- else {
756
- start = NUM2SIZE(iv_beg);
757
- }
758
- if ( NIL_P(iv_end) ) {
759
- last = -1;
760
- }
761
- else {
762
- last = NUM2SIZE(iv_end);
763
- }
764
- excl = RTEST(iv_excl);
765
- step = NUM2SIZE(arg1);
766
- if ( step == 0 ) {
767
- rb_raise(rb_eRuntimeError,
768
- "step in index equals to 0 in block reference");
769
- }
770
- index_type[i] = CA_IDX_BLOCK;
771
- CA_CHECK_INDEX_AT(start, ca_dim[i], i);
772
- if ( last < 0 ) {
773
- last += ca_dim[i];
774
- }
775
- if ( excl && ( start == last ) ) {
776
- index[i].block.start = start;
777
- index[i].block.count = 0;
778
- index[i].block.step = 1;
779
- }
780
- else {
781
- if ( excl ) {
782
- last += ( (last>=start) ? -1 : 1 );
783
- }
784
- if ( last < 0 || last >= ca_dim[i] ) {
785
- rb_raise(rb_eIndexError,
786
- "index %lld is out of range (0..%lld) at %i-dim",
787
- (ca_size_t) last, (ca_size_t) (ca_dim[i]-1), i);
788
- }
789
- if ( (last - start) * step < 0 ) {
790
- count = 1;
791
- }
792
- else {
793
- count = llabs(last - start)/llabs(step) + 1;
794
- }
795
- bound = start + (count - 1)*step;
796
- CA_CHECK_INDEX_AT(bound, ca_dim[i], i);
797
- index[i].block.start = start;
798
- index[i].block.count = count;
799
- index[i].block.step = step;
800
- }
801
- }
802
- else { /* ca[--,[i,j],--]*/
803
- ca_size_t start, count, bound;
804
- start = NUM2SIZE(arg0);
805
- count = NUM2SIZE(arg1);
806
- bound = start + (count - 1);
807
- CA_CHECK_INDEX_AT(start, ca_dim[i], i);
808
- CA_CHECK_INDEX_AT(bound, ca_dim[i], i);
809
- index_type[i] = CA_IDX_BLOCK;
810
- index[i].block.start = start;
811
- index[i].block.count = count;
812
- index[i].block.step = 1;
813
- }
814
- }
815
- else if ( RARRAY_LEN(arg) == 3 ) { /* ca[--,[i,j,k],--]*/
816
- ca_size_t start, count, step, bound;
817
- start = NUM2SIZE(rb_ary_entry(arg, 0));
818
- count = NUM2SIZE(rb_ary_entry(arg, 1));
819
- step = NUM2SIZE(rb_ary_entry(arg, 2));
820
- if ( step == 0 ) {
821
- rb_raise(rb_eRuntimeError,
822
- "step in index equals to 0 in block reference");
823
- }
824
- bound = start + (count - 1)*step;
825
- CA_CHECK_INDEX_AT(start, ca_dim[i], i);
826
- CA_CHECK_INDEX_AT(bound, ca_dim[i], i);
827
- index_type[i] = CA_IDX_BLOCK;
828
- index[i].block.start = start;
829
- index[i].block.count = count;
830
- index[i].block.step = step;
831
- }
832
- else {
833
- rb_raise(rb_eIndexError,
834
- "invalid form of index range at %i-dim "\
835
- "(should be [start[,count[,step]]], [range, step])",
836
- i);
837
- }
838
- }
839
- else if ( rb_obj_is_kind_of(arg, rb_cSymbol) ) { /* ca[--,:i,--] */
840
- if ( strlen(rb_id2name(SYM2ID(arg))) != 1 ) {
841
- rb_raise(rb_eIndexError,
842
- "symbol :%s is invalid as the index for dimension iterator "\
843
- "(should be :a, :b, ... :z)",
844
- rb_id2name(SYM2ID(arg)));
845
- }
846
- index_type[i] = CA_IDX_SYMBOL;
847
- index[i].symbol.id = SYM2ID(arg);
848
- index[i].symbol.spec = Qnil;
849
- }
850
- else if ( rb_obj_is_carray(arg) ) { /* ca[--,ca,--] */
851
- CArray *ci;
852
- TypedData_Get_Struct(arg, CArray, &carray_data_type, ci);
853
- if ( ca_is_boolean_type(ci) || ca_is_integer_type(ci) ) {
854
- is_grid = 1;
855
- goto loop_exit;
856
- }
857
- else {
858
- rb_raise(rb_eIndexError,
859
- "data_type %s is invalid for reference by gridding at %i-dim "\
860
- "(should be boolean or integer)",
861
- ca_type_name[ci->data_type], i);
862
- }
863
- }
864
- else {
865
- VALUE inspect = rb_inspect(arg);
866
- rb_raise(rb_eIndexError,
867
- "object '%s' is invalid for the index for reference at %i-dim",
868
- StringValuePtr(inspect), i);
869
- }
870
- }
871
-
872
- if ( ca_ndim != info->ndim ) {
873
- rb_raise(rb_eIndexError,
874
- "number of indices does not equal to the ndim (%i != %i)",
875
- info->ndim, ca_ndim);
876
- }
877
-
878
- is_point = 1;
879
- is_all = 1;
880
- is_iterator = 0;
881
- is_grid = 0;
882
-
883
- for (i=0; i<info->ndim; i++) {
884
- switch ( info->index_type[i] ) {
885
- case CA_IDX_SCALAR:
886
- is_all = 0;
887
- continue;
888
- case CA_IDX_ALL:
889
- is_point = 0;
890
- continue;
891
- case CA_IDX_SYMBOL:
892
- is_iterator = 1;
893
- goto loop_exit;
894
- default:
895
- is_point = 0;
896
- is_all = 0;
897
- }
898
- }
899
-
900
- loop_exit:
901
-
902
- if ( is_repeat == 1 ) {
903
- info->type = CA_REG_REPEAT;
904
- }
905
- else if ( is_repeat == 2 ) {
906
- info->type = CA_REG_UNBOUND_REPEAT;
907
- }
908
- else if ( is_grid ) {
909
- info->type = CA_REG_GRID;
910
- }
911
- else if ( is_iterator ) {
912
- info->type = CA_REG_ITERATOR;
913
- }
914
- else if ( is_point ) {
915
- info->type = CA_REG_POINT;
916
- }
917
- else if ( is_all ) {
918
- info->type = CA_REG_BLOCK;
919
- }
920
- else {
921
- info->type = CA_REG_BLOCK;
922
- }
923
-
924
- if ( info->type == CA_REG_ITERATOR ) {
925
- for (i=0; i<info->ndim; i++) {
926
- if ( info->index_type[i] == CA_IDX_SCALAR ) {
927
- ca_size_t start = info->index[i].scalar;
928
- info->index_type[i] = CA_IDX_BLOCK;
929
- info->index[i].block.start = start;
930
- info->index[i].block.step = 1;
931
- info->index[i].block.count = 1;
932
- }
933
- }
934
- }
935
-
936
- return;
937
- }
433
+ /* Forwards to the v2 classifier in ext/carray_index_classifier.c. */
434
+ rb_ca_scan_index_v2(ca_ndim, ca_dim, ca_elements, argc, argv, info);
938
435
  }
939
436
 
940
437
  /* ----------------------------------------------------------------------- */
@@ -942,9 +439,7 @@ rb_ca_scan_index (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
942
439
  static VALUE
943
440
  rb_ca_ref_address (VALUE self, CAIndexInfo *info)
944
441
  {
945
- CArray *ca;
946
442
  ca_size_t addr;
947
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
948
443
  addr = info->index[0].scalar;
949
444
  return rb_ca_fetch_addr(self, addr);
950
445
  }
@@ -952,9 +447,7 @@ rb_ca_ref_address (VALUE self, CAIndexInfo *info)
952
447
  static VALUE
953
448
  rb_ca_store_address (VALUE self, CAIndexInfo *info, volatile VALUE rval)
954
449
  {
955
- CArray *ca;
956
450
  ca_size_t addr;
957
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
958
451
  addr = info->index[0].scalar;
959
452
  if ( rb_obj_is_cscalar(rval) ) {
960
453
  rval = rb_ca_fetch_addr(rval, 0);
@@ -1029,29 +522,47 @@ rb_ca_store_all (VALUE self, VALUE rval)
1029
522
 
1030
523
  if ( ca->elements != cv->elements ) {
1031
524
  rb_raise(rb_eRuntimeError,
1032
- "mismatch in data size (%lld <-> %lld) for storing to carray",
525
+ "mismatch in data size (%" PRId64 " <-> %" PRId64 ") for storing to carray",
1033
526
  (ca_size_t) ca->elements, (ca_size_t) cv->elements);
1034
527
  }
1035
528
 
1036
- ca_attach(cv);
1037
- if ( ca->data_type != cv->data_type ) {
1038
- ca_allocate(ca);
1039
- ca_copy_mask_overwrite(ca, ca->elements, 1, cv);
1040
- if ( ca->mask ) {
1041
- ca_cast_block_with_mask(ca->elements, cv, cv->ptr, ca, ca->ptr,
1042
- (boolean8_t*)ca->mask->ptr);
529
+ /* Source delivery via ca_xfer_all into a local scratch instead of
530
+ ca_attach(cv). This routes through ca_*_func_xfer_all's per-region
531
+ partial-materialise path, avoiding a ca_attach(root) silent
532
+ transitive attach. When cv composes through a view root (CAFake /
533
+ CAByteSwap / CAGrid / etc.), attaching the root would materialise
534
+ the whole root (size = root->elements * root->bytes), producing a
535
+ catastrophic slowdown for size-gap cases like
536
+ big_virtual[100..200] = big_virtual[100..200].flip(0). The scratch
537
+ here is sized for cv only (cv->elements * cv->bytes), so the cost
538
+ scales with the view, not the root. (The dst-side ca_sync_data is
539
+ already an xfer_all PUT.) */
540
+ {
541
+ volatile VALUE scratch_holder;
542
+ ca_size_t cv_bytes = cv->bytes * cv->elements;
543
+ char *scratch = ALLOCV_N(char, scratch_holder, cv_bytes);
544
+ ca_xfer_all(cv, scratch, CA_XFER_GET);
545
+
546
+ if ( ca->data_type != cv->data_type ) {
547
+ ca_allocate(ca);
548
+ ca_copy_mask_overwrite(ca, ca->elements, 1, cv);
549
+ if ( ca->mask ) {
550
+ ca_cast_block_with_mask(ca->elements, cv, scratch, ca, ca->ptr,
551
+ (boolean8_t*)ca->mask->ptr);
552
+ }
553
+ else {
554
+ ca_cast_block(ca->elements, cv, scratch, ca, ca->ptr);
555
+ }
556
+ ca_sync(ca);
557
+ ca_detach(ca);
1043
558
  }
1044
559
  else {
1045
- ca_cast_block(ca->elements, cv, cv->ptr, ca, ca->ptr);
560
+ ca_copy_mask_overwrite(ca, ca->elements, 1, cv);
561
+ ca_sync_data(ca, scratch);
1046
562
  }
1047
- ca_sync(ca);
1048
- ca_detach(ca);
1049
- }
1050
- else {
1051
- ca_copy_mask_overwrite(ca, ca->elements, 1, cv);
1052
- ca_sync_data(ca, cv->ptr);
563
+
564
+ ALLOCV_END(scratch_holder);
1053
565
  }
1054
- ca_detach(cv);
1055
566
  }
1056
567
  else if ( TYPE(rval) == T_ARRAY ) {
1057
568
  volatile VALUE list =
@@ -1064,6 +575,8 @@ rb_ca_store_all (VALUE self, VALUE rval)
1064
575
  else {
1065
576
  int has_mask = 0;
1066
577
  CArray ico;
578
+ /* ca_cast_block reads ca_is_face(ca1), so flags must be 0-initialised. */
579
+ memset(&ico, 0, sizeof(CArray));
1067
580
  ico.data_type = CA_OBJECT;
1068
581
  ico.bytes = ca_sizeof[CA_OBJECT];
1069
582
  for (i=0; i<ca->elements; i++) {
@@ -1073,34 +586,56 @@ rb_ca_store_all (VALUE self, VALUE rval)
1073
586
  break;
1074
587
  }
1075
588
  }
1076
- ca_allocate(ca);
1077
- if ( has_mask ) {
1078
- boolean8_t *m;
1079
- m = (boolean8_t *)ca->mask->ptr;
1080
- for (i=0; i<ca->elements; i++) {
1081
- if ( rb_ary_entry(list,i) == CA_UNDEF ) {
1082
- *m = 1;
589
+ /* Use ca_allocate() instead of ca_attach() here because rb_ca_store_all()
590
+ overwrites ALL elements of the array from a Ruby Array. There is no need
591
+ to copy parent data (which ca_attach would do), since every element will
592
+ be replaced. Mask handling is also safe: ca_create_mask() above and
593
+ ca_copy_mask_overwrite() handle mask allocation and propagation internally,
594
+ so ca_allocate()'s simpler path (no parent data copy) is sufficient. */
595
+ ca_allocate(ca);
596
+ {
597
+ /* Face has surface != storage; the cast runs in the storage
598
+ data_type. Passing ca directly makes the cast table see FIXLEN
599
+ and report non-implemented, so pass a shadow CArray (storage
600
+ data_type, ptr aliased to ca). */
601
+ CArray shadow;
602
+ CArray *cast_target = ca;
603
+ memset(&shadow, 0, sizeof(CArray));
604
+ if ( ca_is_face(ca) ) {
605
+ CArray *root = ca;
606
+ while (root && ca_is_face(root)) root = ((CAView *) root)->parent;
607
+ if (root) {
608
+ shadow.data_type = root->data_type;
609
+ shadow.bytes = ca->bytes;
610
+ shadow.elements = ca->elements;
611
+ shadow.ptr = ca->ptr;
612
+ cast_target = &shadow;
1083
613
  }
1084
- else {
1085
- *m = 0;
614
+ }
615
+ if ( has_mask ) {
616
+ boolean8_t *m;
617
+ m = (boolean8_t *)ca->mask->ptr;
618
+ for (i=0; i<ca->elements; i++) {
619
+ if ( rb_ary_entry(list,i) == CA_UNDEF ) {
620
+ *m = 1;
621
+ }
622
+ else {
623
+ *m = 0;
624
+ }
625
+ m++;
1086
626
  }
1087
- m++;
627
+ ca_cast_block_with_mask(ca->elements, &ico, (VALUE *)RARRAY_CONST_PTR(list),
628
+ cast_target, ca->ptr,
629
+ (boolean8_t*)ca->mask->ptr);
630
+ }
631
+ else {
632
+ ca_cast_block(ca->elements, &ico, (VALUE *)RARRAY_CONST_PTR(list), cast_target, ca->ptr);
1088
633
  }
1089
- ca_cast_block_with_mask(ca->elements, &ico, RARRAY_PTR(list),
1090
- ca, ca->ptr,
1091
- (boolean8_t*)ca->mask->ptr);
1092
- }
1093
- else {
1094
- ca_cast_block(ca->elements, &ico, RARRAY_PTR(list), ca, ca->ptr);
1095
634
  }
1096
635
  ca_sync(ca);
1097
636
  ca_detach(ca);
1098
637
  }
1099
638
  }
1100
- else if ( rb_respond_to(rval, id_ca) ) {
1101
- rval = rb_funcall(rval, id_ca, 0);
1102
- goto retry;
1103
- }
1104
639
  else if ( rb_respond_to(rval, id_to_ca) ) {
1105
640
  rval = rb_funcall(rval, id_to_ca, 0);
1106
641
  goto retry;
@@ -1267,7 +802,22 @@ rb_ca_ref_block (VALUE self, CAIndexInfo *info)
1267
802
  dim, start, step, count, &offset);
1268
803
  }
1269
804
 
1270
- return rb_ca_block_new(refer, ndim, dim, start, step, count, offset);
805
+ {
806
+ volatile VALUE blk;
807
+ blk = rb_ca_block_new(refer, ndim, dim, start, step, count, offset);
808
+ /* The block inherits the Face source's FIXLEN surface; rewrite its
809
+ data_type to the storage data_type (chain bottom) so the write path
810
+ casts in the storage type. */
811
+ if ( ca_is_face(ca) ) {
812
+ CArray *blk_ca, *root = ca;
813
+ TypedData_Get_Struct(blk, CArray, &carray_data_type, blk_ca);
814
+ while (root && ca_is_face(root)) root = ((CAView *) root)->parent;
815
+ if (root && root->data_type != blk_ca->data_type) {
816
+ blk_ca->data_type = root->data_type;
817
+ }
818
+ }
819
+ return blk;
820
+ }
1271
821
  }
1272
822
 
1273
823
  static VALUE
@@ -1281,12 +831,120 @@ rb_ca_refer_new_flatten (VALUE self)
1281
831
  return rb_ca_refer_new(self, ca->data_type, 1, &dim0, ca->bytes, 0);
1282
832
  }
1283
833
 
1284
- /* yard:
1285
- class CArray
1286
- def [] (*spec)
1287
- end
1288
- end
1289
- */
834
+ /* CARemap routing: when self and mapper have identical shape AND
835
+ mapper's data_type is CA_SIZE, take the same-shape per-element gather
836
+ fast path. Defined in ca_obj_remap.c. */
837
+ extern VALUE rb_ca_remap_new (VALUE cary, VALUE rmapper);
838
+
839
+ /* a[mapper] is semantically equivalent to
840
+ a.flatten[mapper.flatten].reshape(*mapper.dim).
841
+
842
+ Two routes:
843
+ (a) Same-shape + CA_SIZE mapper -> CARemap view (fast path, avoids
844
+ building the flatten/gather/reshape chain).
845
+ (b) Otherwise -> normalize chain (a.flatten[mapper.flatten]
846
+ .reshape). A 1-D mapper is already routed to CAGrid upstream.
847
+
848
+ Both routes raise on a masked mapper. */
849
+ static VALUE
850
+ rb_ca_fancy_index_chain (VALUE self, VALUE rmapper)
851
+ {
852
+ CArray *ca, *cm;
853
+ volatile VALUE flat_self, flat_mapper, gridded, result;
854
+ VALUE grid_argv[1];
855
+ int i;
856
+
857
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
858
+ TypedData_Get_Struct(rmapper, CArray, &carray_data_type, cm);
859
+
860
+ if ( ca_is_any_masked(cm) ) {
861
+ rb_raise(rb_eArgError, "mapper in ca[mapper] should not be masked");
862
+ }
863
+
864
+ /* (a) same-shape fast path: ndim + per-axis dim + CA_SIZE data_type. */
865
+ if ( cm->data_type == CA_SIZE
866
+ && cm->ndim == ca->ndim
867
+ && memcmp(cm->dim, ca->dim, ca->ndim * sizeof(ca_size_t)) == 0 ) {
868
+ return rb_ca_remap_new(self, rmapper);
869
+ }
870
+
871
+ /* (b) Normalize chain fallback. */
872
+ flat_self = rb_ca_refer_new_flatten(self);
873
+ flat_mapper = (cm->ndim == 1) ? rmapper : rb_ca_flatten(rmapper);
874
+ grid_argv[0] = flat_mapper;
875
+ gridded = rb_ca_grid(1, grid_argv, flat_self);
876
+
877
+ if ( cm->ndim == 1 ) {
878
+ result = gridded;
879
+ }
880
+ else {
881
+ VALUE *dim_argv = ALLOCA_N(VALUE, cm->ndim);
882
+ for (i = 0; i < cm->ndim; i++) {
883
+ dim_argv[i] = SIZE2NUM(cm->dim[i]);
884
+ }
885
+ result = rb_ca_reshape(cm->ndim, dim_argv, gridded);
886
+ }
887
+ return result;
888
+ }
889
+
890
+ /* The CAMapping class is gone; rb_ca_mapping_new and rb_ca_mapping build
891
+ the normalize chain via rb_ca_fancy_index_chain. The public C API
892
+ signatures are preserved so external ext gems keep linking; the runtime
893
+ class of the returned VALUE is CARefer (chain outermost), not CAMapping. */
894
+
895
+ VALUE
896
+ rb_ca_mapping_new (VALUE cary, CArray *mapper)
897
+ {
898
+ CArray *m_copy = ca_copy(mapper);
899
+ volatile VALUE rmapper = ca_wrap_struct(m_copy);
900
+ return rb_ca_fancy_index_chain(cary, rmapper);
901
+ }
902
+
903
+ VALUE
904
+ rb_ca_mapping (int argc, VALUE *argv, VALUE self)
905
+ {
906
+ volatile VALUE rmapper;
907
+ rb_scan_args(argc, argv, "1", (VALUE *) &rmapper);
908
+ rb_check_carray_object(rmapper);
909
+ return rb_ca_fancy_index_chain(self, rmapper);
910
+ }
911
+
912
+ /* ------------------------------------------------------------------- */
913
+ /* newaxis (:_) sugar. `:_` inserts a size-1 axis at its position.
914
+ Strategy: strip `:_`, fetch the remaining per-axis indices into a base
915
+ view, then reshape the base inserting size-1 axes. reshape inherits
916
+ the optimal view class (CAStride for stride bases, CARefer for fancy
917
+ bases). */
918
+
919
+ static int
920
+ ca_argv_has_newaxis (int argc, VALUE *argv)
921
+ {
922
+ int i;
923
+ for (i = 0; i < argc; i++) {
924
+ if ( argv[i] == sym_under ) return 1;
925
+ }
926
+ return 0;
927
+ }
928
+
929
+ static int
930
+ ca_argv_has_slab_sigil (int argc, VALUE *argv)
931
+ {
932
+ int i;
933
+ for (i = 0; i < argc; i++) {
934
+ if ( argv[i] == sym_gt ) return 1;
935
+ }
936
+ return 0;
937
+ }
938
+
939
+ static VALUE rb_ca_fetch_newaxis (int argc, VALUE *argv, VALUE self,
940
+ CArray *ca);
941
+ static VALUE rb_ca_slab_iter_new (VALUE self, CAIndexInfo *info);
942
+ static VALUE rb_ca_fetch_slab_sigil (int argc, VALUE *argv, VALUE self);
943
+
944
+ /* axis-group apply (ext/ca_group_iter.c): type gate that routes a
945
+ CACategorical/AxisGroup index to the group path. */
946
+ int ca_argv_has_group (int argc, VALUE *argv);
947
+ VALUE rb_ca_fetch_group (int argc, VALUE *argv, VALUE self);
1290
948
 
1291
949
  static VALUE
1292
950
  rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
@@ -1299,6 +957,29 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
1299
957
 
1300
958
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1301
959
 
960
+ /* newaxis (:_) interception (cheap pointer scan; zero overhead beyond
961
+ the loop when no :_ is present). */
962
+ if ( ca_argv_has_newaxis(argc, argv) ) {
963
+ return rb_ca_fetch_newaxis(argc, argv, self, ca);
964
+ }
965
+
966
+ /* slab sigil (:>) interception. Pre-strip :> -> nil and Integer ->
967
+ length-1 Range so mask / fancy outer slots route through the regular
968
+ dispatch (CA_REG_SELECT / CA_REG_GRID / CA_REG_MAPPING) before being
969
+ wrapped in CASlabIterator. */
970
+ if ( ca_argv_has_slab_sigil(argc, argv) ) {
971
+ return rb_ca_fetch_slab_sigil(argc, argv, self);
972
+ }
973
+
974
+ /* Axis-group type gate: a CACategorical/AxisGroup index routes to the
975
+ group apply path (CAGroupIterator); plain int-array indices fall
976
+ through to the regular selection dispatch below. The scan short-circuits
977
+ when the surface classes have not been loaded, so a normal index pays
978
+ nothing. */
979
+ if ( ca_argv_has_group(argc, argv) ) {
980
+ return rb_ca_fetch_group(argc, argv, self);
981
+ }
982
+
1302
983
  info.range_check = 1;
1303
984
  rb_ca_scan_index(ca->ndim, ca->dim, ca->elements, argc, argv, &info);
1304
985
 
@@ -1325,7 +1006,7 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
1325
1006
  obj = rb_ca_select_new(self, argv[0]);
1326
1007
  break;
1327
1008
  case CA_REG_ITERATOR:
1328
- obj = rb_dim_iter_new(self, &info);
1009
+ obj = rb_ca_slab_iter_new(self, &info);
1329
1010
  break;
1330
1011
  case CA_REG_REPEAT:
1331
1012
  obj = rb_ca_repeat(argc, argv, self);
@@ -1334,7 +1015,7 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
1334
1015
  obj = rb_funcall2(self, rb_intern("unbound_repeat"), (int) argc, argv);
1335
1016
  break;
1336
1017
  case CA_REG_MAPPING:
1337
- obj = rb_ca_mapping(argc, argv, self);
1018
+ obj = rb_ca_fancy_index_chain(self, argv[0]);
1338
1019
  break;
1339
1020
  case CA_REG_GRID:
1340
1021
  obj = rb_ca_grid(argc, argv, self);
@@ -1348,11 +1029,14 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
1348
1029
  case CA_REG_MEMBER: {
1349
1030
  volatile VALUE data_class = rb_ca_data_class(self);
1350
1031
  if ( ! NIL_P(data_class) ) {
1351
- obj = rb_ca_field_as_member(self, info.symbol);
1352
- break;
1032
+ /* Field projection strips Face and returns a CAField on the parent
1033
+ (= a different data_type). Do not re-wrap with Face (CARecord
1034
+ wraps structs only; a field view like float64 is not a CARecord).
1035
+ Early-return to bypass the trailing ca_face_lift. */
1036
+ return rb_ca_face_field(self, info.symbol);
1353
1037
  }
1354
1038
  else {
1355
- rb_raise(rb_eIndexError,
1039
+ rb_raise(rb_eIndexError,
1356
1040
  "can't refer member of carray doesn't have data_class");
1357
1041
  }
1358
1042
  break;
@@ -1365,9 +1049,222 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
1365
1049
  default:
1366
1050
  rb_raise(rb_eIndexError, "invalid index specified");
1367
1051
  }
1052
+
1053
+ /* Face lift at the read touch point: if `self` is a Face, re-wrap the
1054
+ view result as a Face (ca_face_lift). Guards: lift only when the result
1055
+ is a CArray instance (excludes Hash / iterator / scalar), and only when
1056
+ it is not ALREADY a Face -- some builders (select / repeat / ...) lift
1057
+ their own result, so re-lifting here would double-wrap and leave `.parent`
1058
+ pointing at a Face instead of the storage. */
1059
+ if ( ca_is_face(ca) && rb_obj_is_kind_of(obj, rb_cCArray) ) {
1060
+ CArray *obj_ca;
1061
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, obj_ca);
1062
+ if ( ! ca_is_face(obj_ca) ) {
1063
+ obj = ca_face_lift(obj, self);
1064
+ }
1065
+ }
1066
+
1368
1067
  return obj;
1369
1068
  }
1370
1069
 
1070
+ /* newaxis (:_) implementation (reshape). See the forward decl + the
1071
+ interception hook in rb_ca_fetch_method. Pre-condition: argv contains
1072
+ at least one sym_under. */
1073
+ static VALUE
1074
+ rb_ca_fetch_newaxis (int argc, VALUE *argv, VALUE self, CArray *ca)
1075
+ {
1076
+ int i;
1077
+ int nclean = 0;
1078
+ VALUE clean[CA_RANK_MAX];
1079
+ volatile VALUE base;
1080
+ ca_size_t final_dims[CA_RANK_MAX];
1081
+ int nfinal = 0;
1082
+ int base_cursor;
1083
+ CArray *cb;
1084
+ VALUE dim_argv[CA_RANK_MAX];
1085
+
1086
+ /* Build clean argv (strip :_); reject disjoint sigils + rubber dim. */
1087
+ for (i = 0; i < argc; i++) {
1088
+ VALUE a = argv[i];
1089
+ if ( a == sym_under ) continue;
1090
+ if ( a == sym_gt || a == sym_star || a == sym_perc
1091
+ || a == Qfalse || a == sym_tilde ) {
1092
+ rb_raise(rb_eIndexError,
1093
+ "newaxis (:_) cannot be combined with :>, :*, :%%, "
1094
+ "or rubber dim (false / :~)");
1095
+ }
1096
+ if ( nclean >= CA_RANK_MAX ) {
1097
+ rb_raise(rb_eIndexError, "too many indices");
1098
+ }
1099
+ clean[nclean++] = a;
1100
+ }
1101
+
1102
+ /* newaxis requires full per-axis indexing (CArray uses flat addressing
1103
+ for partial indices, which is incoherent with axis-position newaxis). */
1104
+ if ( nclean != ca->ndim ) {
1105
+ rb_raise(rb_eIndexError,
1106
+ "newaxis (:_) requires full per-axis indexing "
1107
+ "(got %d non-:_ indices for ndim %d)",
1108
+ nclean, (int) ca->ndim);
1109
+ }
1110
+
1111
+ base = rb_ca_fetch_method(nclean, clean, self);
1112
+
1113
+ /* Degenerate: all real axes scalar -> base is a scalar element, not a
1114
+ CArray. Out of scope (rare + degenerate); user indexes the element
1115
+ and reshapes explicitly. IndexError keeps it catchable + consistent
1116
+ with the other newaxis rejects. */
1117
+ if ( ! rb_obj_is_kind_of(base, rb_cCArray) ) {
1118
+ rb_raise(rb_eIndexError,
1119
+ "newaxis (:_) needs at least one non-scalar axis "
1120
+ "(all-scalar indexing yields a single element)");
1121
+ }
1122
+
1123
+ TypedData_Get_Struct(base, CArray, &carray_data_type, cb);
1124
+
1125
+ /* Reconstruct final shape: walk original argv. :_ -> size-1, scalar
1126
+ (Integer) -> dropped (skip), else -> base.dim[cursor]. */
1127
+ base_cursor = 0;
1128
+ for (i = 0; i < argc; i++) {
1129
+ VALUE a = argv[i];
1130
+ if ( a == sym_under ) {
1131
+ final_dims[nfinal++] = 1;
1132
+ }
1133
+ else if ( FIXNUM_P(a) || RB_TYPE_P(a, T_BIGNUM) ) {
1134
+ /* scalar index -> axis dropped in base; contributes no output axis */
1135
+ }
1136
+ else {
1137
+ if ( base_cursor >= cb->ndim ) {
1138
+ rb_raise(rb_eIndexError, "newaxis: base axis count mismatch");
1139
+ }
1140
+ final_dims[nfinal++] = cb->dim[base_cursor++];
1141
+ }
1142
+ }
1143
+ if ( base_cursor != cb->ndim ) {
1144
+ rb_raise(rb_eIndexError, "newaxis: base axis count mismatch");
1145
+ }
1146
+
1147
+ for (i = 0; i < nfinal; i++) {
1148
+ dim_argv[i] = SIZE2NUM(final_dims[i]);
1149
+ }
1150
+ return rb_ca_reshape(nfinal, dim_argv, base);
1151
+ }
1152
+
1153
+ /* Build a CASlabIterator from a classified ITERATOR index. The
1154
+ `:>` axes (CA_IDX_SYMBOL) become the slab axes; they are converted to
1155
+ CA_IDX_ALL so rb_ca_ref_block yields the sliced base view keeping all
1156
+ axes (scalars are already length-1 BLOCKs via the finalize_reg post-
1157
+ pass). CASlabIterator delegates to each_slab / map_slab / reduce_slab. */
1158
+ static VALUE
1159
+ rb_ca_slab_iter_new (VALUE self, CAIndexInfo *info)
1160
+ {
1161
+ volatile VALUE slab_axes = rb_ary_new();
1162
+ volatile VALUE base;
1163
+ volatile VALUE klass;
1164
+ int i;
1165
+
1166
+ for (i = 0; i < info->ndim; i++) {
1167
+ if ( info->index_type[i] == CA_IDX_SYMBOL ) {
1168
+ rb_ary_push(slab_axes, INT2NUM(i));
1169
+ info->index_type[i] = CA_IDX_ALL; /* :> axis -> full range */
1170
+ }
1171
+ }
1172
+
1173
+ base = rb_ca_ref_block(self, info);
1174
+ klass = rb_const_get(rb_cObject, rb_intern("CASlabIterator"));
1175
+ return rb_funcall(klass, rb_intern("new"), 2, base, slab_axes);
1176
+ }
1177
+
1178
+ /* Slab sigil dispatcher that supports any outer-slot index type
1179
+ (Integer / Range / nil / boolean mask / CArray / Symbol-method etc.).
1180
+ Strategy: expand rubber dim (false / :~) if present so :> positions
1181
+ align with the post-expansion ndim, replace :> with nil (full axis),
1182
+ promote Integer to length-1 Range so the base view preserves ndim,
1183
+ recurse through the regular indexer dispatch to build the base
1184
+ reference (CABlock / CASelectAxis / CAGrid / CAMapping / ...), then
1185
+ wrap in CASlabIterator with the recorded slab_axes positions. */
1186
+ static VALUE
1187
+ rb_ca_fetch_slab_sigil (int argc, VALUE *argv, VALUE self)
1188
+ {
1189
+ VALUE expanded[CA_RANK_MAX];
1190
+ VALUE clean[CA_RANK_MAX];
1191
+ volatile VALUE slab_axes = rb_ary_new();
1192
+ volatile VALUE base;
1193
+ volatile VALUE klass;
1194
+ CArray *ca;
1195
+ int i, j;
1196
+ int eargc;
1197
+ VALUE *eargv;
1198
+ int rubber_pos = -1;
1199
+
1200
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1201
+
1202
+ /* Rubber-dim expansion (mirrors ca_classifier_expand_rubber_dim).
1203
+ Only the first rubber marker is honoured; later ones are left for
1204
+ the regular classifier to reject downstream. */
1205
+ for (i = 0; i < argc; i++) {
1206
+ if ( argv[i] == Qfalse || argv[i] == sym_tilde ) {
1207
+ rubber_pos = i;
1208
+ break;
1209
+ }
1210
+ }
1211
+ if ( rubber_pos < 0 ) {
1212
+ eargc = argc;
1213
+ eargv = argv;
1214
+ }
1215
+ else {
1216
+ int rndim;
1217
+ if ( argc > ca->ndim + 1 ) {
1218
+ rb_raise(rb_eIndexError,
1219
+ "index specification exceeds the ndim of carray (%i)",
1220
+ ca->ndim);
1221
+ }
1222
+ rndim = ca->ndim - argc + 1;
1223
+ if ( rndim < 0 ) rndim = 0;
1224
+ j = 0;
1225
+ for (i = 0; i < argc; i++) {
1226
+ if ( i == rubber_pos ) {
1227
+ int k;
1228
+ for (k = 0; k < rndim; k++) expanded[j++] = Qnil;
1229
+ }
1230
+ else {
1231
+ expanded[j++] = argv[i];
1232
+ }
1233
+ }
1234
+ eargc = j;
1235
+ eargv = expanded;
1236
+ }
1237
+
1238
+ if ( eargc > CA_RANK_MAX ) {
1239
+ rb_raise(rb_eIndexError, "too many indices");
1240
+ }
1241
+
1242
+ for (i = 0; i < eargc; i++) {
1243
+ VALUE a = eargv[i];
1244
+ if ( a == sym_gt ) {
1245
+ rb_ary_push(slab_axes, INT2NUM(i));
1246
+ clean[i] = Qnil;
1247
+ }
1248
+ else if ( FIXNUM_P(a) || RB_TYPE_P(a, T_BIGNUM) ) {
1249
+ /* Promote Integer to length-1 Range so the recursed view keeps
1250
+ the axis (matches the existing :> dispatcher semantics where
1251
+ scalars become length-1 BLOCKs via finalize_reg). */
1252
+ clean[i] = rb_range_new(a, a, 0);
1253
+ }
1254
+ else {
1255
+ clean[i] = a;
1256
+ }
1257
+ }
1258
+
1259
+ base = rb_ca_fetch_method(eargc, clean, self);
1260
+ if ( ! rb_obj_is_kind_of(base, rb_cCArray) ) {
1261
+ rb_raise(rb_eIndexError,
1262
+ "slab sigil (:>) requires the base view to be a CArray");
1263
+ }
1264
+ klass = rb_const_get(rb_cObject, rb_intern("CASlabIterator"));
1265
+ return rb_funcall(klass, rb_intern("new"), 2, base, slab_axes);
1266
+ }
1267
+
1371
1268
  static VALUE
1372
1269
  rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
1373
1270
  {
@@ -1403,7 +1300,7 @@ rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
1403
1300
  obj = rb_ca_select_new(self, argv[0]);
1404
1301
  break;
1405
1302
  case CA_REG_ITERATOR:
1406
- obj = rb_dim_iter_new(self, &info);
1303
+ obj = rb_ca_slab_iter_new(self, &info);
1407
1304
  break;
1408
1305
  case CA_REG_REPEAT:
1409
1306
  obj = rb_ca_repeat(argc, argv, self);
@@ -1412,7 +1309,7 @@ rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
1412
1309
  obj = rb_funcall2(self, rb_intern("unbound_repeat"), (int) argc, argv);
1413
1310
  break;
1414
1311
  case CA_REG_MAPPING:
1415
- obj = rb_ca_mapping(argc, argv, self);
1312
+ obj = rb_ca_fancy_index_chain(self, argv[0]);
1416
1313
  break;
1417
1314
  case CA_REG_GRID:
1418
1315
  obj = rb_ca_grid(argc, argv, self);
@@ -1426,7 +1323,7 @@ rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
1426
1323
  case CA_REG_MEMBER: {
1427
1324
  volatile VALUE data_class = rb_ca_data_class(self);
1428
1325
  if ( ! NIL_P(data_class) ) {
1429
- obj = rb_ca_field_as_member(self, info.symbol);
1326
+ obj = rb_ca_face_field(self, info.symbol);
1430
1327
  break;
1431
1328
  }
1432
1329
  else {
@@ -1447,12 +1344,67 @@ rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
1447
1344
  return obj;
1448
1345
  }
1449
1346
 
1450
- /* yard:
1451
- class CArray
1452
- def []= (*spec)
1453
- end
1454
- end
1455
- */
1347
+ /* Recursively convert a store rvalue's surface value objects into
1348
+ storage-domain values for a Face `self`, applied at the Ruby `[]=` entry
1349
+ before any store-side view (block / newaxis / grid / ...) is built. The
1350
+ store-side view is stripped to the storage data_type, so the Face is only
1351
+ visible here at the top of the dispatch; converting now lets every view
1352
+ path store a Face surface scalar correctly.
1353
+
1354
+ - a Face CArray rvalue is reconciled to self's storage via to_comparable
1355
+ (unit-safe: cross-group / non-exact raises), so a same-Face bulk store
1356
+ (t[0..1] = t[1..2]) becomes a storage int64 xfer. A non-Face CArray
1357
+ (e.g. datetime[0..1] = plain_int64_array) passes through unchanged --
1358
+ the documented raw-storage escape -- but it has to be raw *storage*: an
1359
+ integer-storage Face takes integer cells only. The scalar path already
1360
+ refuses a bare Float there (to_comparable does not recognise it) instead
1361
+ of letting the storage cast truncate it, and the bulk path must not be
1362
+ the looser door.
1363
+ - an Array is mapped structure-preserving (leaves converted),
1364
+ - a scalar goes through the write hook (ca_face_scalar_to_storage), which
1365
+ leaves a bare Integer / String unchanged.
1366
+
1367
+ Idempotent: an already-converted Integer passes through, so re-running on
1368
+ a `goto retry` iteration is harmless. */
1369
+ static VALUE
1370
+ ca_face_convert_store_rval (VALUE self, CArray *ca, VALUE val)
1371
+ {
1372
+ if ( rb_obj_is_carray(val) ) {
1373
+ CArray *cval;
1374
+ GetCArray(val, cval);
1375
+ /* Face RHS: reconcile to self's unit and descend to storage. Mirror of
1376
+ the scalar path (ca_face_scalar_to_storage) for a bulk CArray source.
1377
+ Guarded on self having to_comparable so a Face without a reconcile
1378
+ algebra (e.g. a fixlen-storage Face, whose same-storage store already
1379
+ takes the storage xfer branch) is left to the existing store path. */
1380
+ if ( ca_is_face(cval) && rb_respond_to(self, rb_intern("to_comparable")) ) {
1381
+ volatile VALUE reconciled = rb_funcall(self, rb_intern("to_comparable"),
1382
+ 1, val);
1383
+ return rb_funcall(reconciled, rb_intern("parent"), 0);
1384
+ }
1385
+ /* Bare storage escape, integer storage: integer cells only (see above). */
1386
+ {
1387
+ CArray *storage = ca_strip_face(ca);
1388
+ if ( storage && ca_is_integer_type(storage) && ! ca_is_integer_type(cval) ) {
1389
+ rb_raise(rb_eTypeError,
1390
+ "%s cannot store a bare %s array as raw storage "
1391
+ "(use ca.parent to write the %s storage directly)",
1392
+ rb_obj_classname(self), ca_type_name[cval->data_type],
1393
+ ca_type_name[storage->data_type]);
1394
+ }
1395
+ }
1396
+ return val;
1397
+ }
1398
+ if ( TYPE(val) == T_ARRAY ) {
1399
+ long i, n = RARRAY_LEN(val);
1400
+ volatile VALUE out = rb_ary_new2(n);
1401
+ for (i = 0; i < n; i++) {
1402
+ rb_ary_push(out, ca_face_convert_store_rval(self, ca, rb_ary_entry(val, i)));
1403
+ }
1404
+ return out;
1405
+ }
1406
+ return ca_face_scalar_to_storage(self, ca, val);
1407
+ }
1456
1408
 
1457
1409
  static VALUE
1458
1410
  rb_ca_store_method (int argc, VALUE *argv, VALUE self)
@@ -1470,6 +1422,31 @@ rb_ca_store_method (int argc, VALUE *argv, VALUE self)
1470
1422
 
1471
1423
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1472
1424
 
1425
+ /* Face store: bring a surface value object (Scalar / Time / DateTime) into
1426
+ the storage domain while self is still the Face. Store-side views strip
1427
+ the Face to storage, so this is the only point that sees it. */
1428
+ if ( ca_is_face(ca) ) {
1429
+ rval = ca_face_convert_store_rval(self, ca, rval);
1430
+ }
1431
+
1432
+ /* newaxis (:_) interception on store. Build the newaxis view (a
1433
+ writable reshape aliasing self), then assign rval into the whole view
1434
+ (writes propagate to self). */
1435
+ if ( ca_argv_has_newaxis(argc, argv) ) {
1436
+ volatile VALUE view = rb_ca_fetch_newaxis(argc, argv, self, ca);
1437
+ rb_ca_store_all(view, rval);
1438
+ return rval;
1439
+ }
1440
+
1441
+ /* slab sigil on store is rejected regardless of outer-slot type. Catch
1442
+ :> before scan_index so mask/fancy outer slots get the same "not
1443
+ supported" message instead of a misleading TypeError. */
1444
+ if ( ca_argv_has_slab_sigil(argc, argv) ) {
1445
+ rb_raise(rb_eIndexError,
1446
+ "assignment through a slab iterator (:>) is not supported "
1447
+ "(use a block index, e.g. ca[range, nil] = val, or each_slab)");
1448
+ }
1449
+
1473
1450
  info.range_check = 1;
1474
1451
  rb_ca_scan_index(ca->ndim, ca->dim, ca->elements, argc, argv, &info);
1475
1452
 
@@ -1502,8 +1479,11 @@ rb_ca_store_method (int argc, VALUE *argv, VALUE self)
1502
1479
  break;
1503
1480
  }
1504
1481
  case CA_REG_ITERATOR: {
1505
- obj = rb_dim_iter_new(self, &info);
1506
- obj = rb_funcall(obj, rb_intern("asign!"), 1, rval);
1482
+ /* assignment through a slab iterator (:>) is not supported.
1483
+ Use a block index (ca[range, nil] = val) or each_slab/map_slab. */
1484
+ rb_raise(rb_eIndexError,
1485
+ "assignment through a slab iterator (:>) is not supported "
1486
+ "(use a block index, e.g. ca[range, nil] = val, or each_slab)");
1507
1487
  break;
1508
1488
  }
1509
1489
  case CA_REG_REPEAT: {
@@ -1516,7 +1496,7 @@ rb_ca_store_method (int argc, VALUE *argv, VALUE self)
1516
1496
  obj = rb_ca_store_all(obj, rval);
1517
1497
  break;
1518
1498
  case CA_REG_MAPPING: {
1519
- obj = rb_ca_mapping(argc, argv, self);
1499
+ obj = rb_ca_fancy_index_chain(self, argv[0]);
1520
1500
  obj = rb_ca_store_all(obj, rval);
1521
1501
  break;
1522
1502
  }
@@ -1537,7 +1517,7 @@ rb_ca_store_method (int argc, VALUE *argv, VALUE self)
1537
1517
  case CA_REG_MEMBER: {
1538
1518
  volatile VALUE data_class = rb_ca_data_class(self);
1539
1519
  if ( ! NIL_P(data_class) ) {
1540
- obj = rb_ca_field_as_member(self, info.symbol);
1520
+ obj = rb_ca_face_field(self, info.symbol);
1541
1521
  obj = rb_ca_store_all(obj, rval);
1542
1522
  }
1543
1523
  else {
@@ -1552,6 +1532,7 @@ rb_ca_store_method (int argc, VALUE *argv, VALUE self)
1552
1532
  break;
1553
1533
  }
1554
1534
  }
1535
+
1555
1536
  return obj;
1556
1537
  }
1557
1538
 
@@ -1560,7 +1541,7 @@ rb_ca_fetch (VALUE self, VALUE index)
1560
1541
  {
1561
1542
  switch ( TYPE(index) ) {
1562
1543
  case T_ARRAY:
1563
- return rb_ca_fetch_method((int) RARRAY_LEN(index), RARRAY_PTR(index), self);
1544
+ return rb_ca_fetch_method((int) RARRAY_LEN(index), (VALUE *)RARRAY_CONST_PTR(index), self);
1564
1545
  default:
1565
1546
  return rb_ca_fetch_method(1, &index, self);
1566
1547
  }
@@ -1579,7 +1560,7 @@ rb_ca_store (VALUE self, VALUE index, VALUE rval)
1579
1560
  case T_ARRAY:
1580
1561
  index = rb_obj_clone(index);
1581
1562
  rb_ary_push(index, rval);
1582
- return rb_ca_store_method((int)RARRAY_LEN(index), RARRAY_PTR(index), self);
1563
+ return rb_ca_store_method((int)RARRAY_LEN(index), (VALUE *)RARRAY_CONST_PTR(index), self);
1583
1564
  default: {
1584
1565
  VALUE rindex[2] = { index, rval };
1585
1566
  return rb_ca_store_method(2, rindex, self);
@@ -1590,16 +1571,11 @@ rb_ca_store (VALUE self, VALUE index, VALUE rval)
1590
1571
  VALUE
1591
1572
  rb_ca_store2 (VALUE self, int n, VALUE *rindex, VALUE rval)
1592
1573
  {
1593
- VALUE index = rb_ary_new4(n, rindex);
1574
+ volatile VALUE index = rb_ary_new4(n, rindex);
1594
1575
  rb_ary_push(index, rval);
1595
- return rb_ca_store_method((int)RARRAY_LEN(index), RARRAY_PTR(index), self);
1576
+ return rb_ca_store_method((int)RARRAY_LEN(index), (VALUE *)RARRAY_CONST_PTR(index), self);
1596
1577
  }
1597
1578
 
1598
- /* yard:
1599
- def CArray.scan_index(dim, idx)
1600
- end
1601
- */
1602
-
1603
1579
  static VALUE
1604
1580
  rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
1605
1581
  {
@@ -1625,7 +1601,7 @@ rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
1625
1601
 
1626
1602
  info.range_check = 1;
1627
1603
  rb_ca_scan_index(ndim, dim, elements,
1628
- RARRAY_LEN(ridx), RARRAY_PTR(ridx), &info);
1604
+ RARRAY_LEN(ridx), (VALUE *)RARRAY_CONST_PTR(ridx), &info);
1629
1605
 
1630
1606
  rtype = INT2NUM(info.type);
1631
1607
  rindex = rb_ary_new2(info.ndim);
@@ -1704,13 +1680,6 @@ rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
1704
1680
  return rb_struct_new(S_CAInfo, rtype, rindex);
1705
1681
  }
1706
1682
 
1707
- /* yard:
1708
- class CArray
1709
- def normalize_index (idx)
1710
- end
1711
- end
1712
- */
1713
-
1714
1683
  static VALUE
1715
1684
  rb_ca_normalize_index (VALUE self, VALUE ridx)
1716
1685
  {
@@ -1724,7 +1693,7 @@ rb_ca_normalize_index (VALUE self, VALUE ridx)
1724
1693
 
1725
1694
  info.range_check = 1;
1726
1695
  rb_ca_scan_index(ca->ndim, ca->dim, ca->elements,
1727
- RARRAY_LEN(ridx), RARRAY_PTR(ridx), &info);
1696
+ RARRAY_LEN(ridx), (VALUE *)RARRAY_CONST_PTR(ridx), &info);
1728
1697
 
1729
1698
  switch ( info.type ) {
1730
1699
  case CA_REG_ALL:
@@ -1777,78 +1746,153 @@ rb_ca_normalize_index (VALUE self, VALUE ridx)
1777
1746
 
1778
1747
  /* ------------------------------------------------------------------- */
1779
1748
 
1780
- /* yard:
1781
- class CArray
1782
- # converts addr to index
1783
- def addr2index (addr)
1784
- end
1785
- end
1786
- */
1749
+ /* ------------------------------------------------------------------- */
1750
+ /* addr <-> index conversion primitives.
1751
+ *
1752
+ * Two dispatch axes:
1753
+ * (a) instance form (uses self.shape) vs class form (`shape:` kwarg)
1754
+ * (b) scalar input vs CArray input (per method)
1755
+ *
1756
+ * The four Ruby entry points (rb_ca_{addr2index,index2addr},
1757
+ * rb_ca_s_{addr2index,index2addr}) all funnel into the two _do helpers
1758
+ * below, which take an already-resolved (ndim, dim[], elements) triple.
1759
+ */
1787
1760
 
1788
- VALUE
1789
- rb_ca_addr2index (VALUE self, VALUE raddr)
1761
+ static void
1762
+ parse_shape_kwarg (VALUE rshape, int *out_ndim, ca_size_t *dim,
1763
+ ca_size_t *out_elements)
1764
+ {
1765
+ int i, ndim;
1766
+ ca_size_t elements = 1;
1767
+
1768
+ Check_Type(rshape, T_ARRAY);
1769
+ ndim = (int) RARRAY_LEN(rshape);
1770
+ if ( ndim < 1 || ndim > CA_RANK_MAX ) {
1771
+ rb_raise(rb_eArgError, "invalid shape ndim %d (must be 1..%d)",
1772
+ ndim, CA_RANK_MAX);
1773
+ }
1774
+ for (i = 0; i < ndim; i++) {
1775
+ dim[i] = NUM2SIZE(rb_ary_entry(rshape, i));
1776
+ if ( dim[i] < 0 ) {
1777
+ rb_raise(rb_eArgError, "negative dim %" PRId64 " at axis %d",
1778
+ (ca_size_t) dim[i], i);
1779
+ }
1780
+ elements *= dim[i];
1781
+ }
1782
+ *out_ndim = ndim;
1783
+ *out_elements = elements;
1784
+ }
1785
+
1786
+ static VALUE
1787
+ addr2index_do (int ndim, ca_size_t *dim, ca_size_t elements, VALUE raddr)
1790
1788
  {
1791
1789
  volatile VALUE out;
1792
- CArray *ca;
1793
- ca_size_t *dim;
1794
- ca_size_t addr;
1795
1790
  int i;
1796
1791
 
1797
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1792
+ /* Scalar path (Integer input): returns Ruby Array of N Integers.
1793
+ * Preserves legacy shape for callers like `i, j = ca.addr2index(k)`. */
1794
+ if ( rb_obj_is_kind_of(raddr, rb_cInteger) ) {
1795
+ ca_size_t addr = NUM2SIZE(raddr);
1796
+ if ( addr < 0 || addr >= elements ) {
1797
+ rb_raise(rb_eArgError,
1798
+ "address %" PRId64 " is out of range (0..%" PRId64 ")",
1799
+ (ca_size_t) addr, (ca_size_t) (elements - 1));
1800
+ }
1801
+ out = rb_ary_new2(ndim);
1802
+ for (i = ndim - 1; i >= 0; i--) {
1803
+ rb_ary_store(out, i, SIZE2NUM(addr % dim[i]));
1804
+ addr /= dim[i];
1805
+ }
1806
+ return out;
1807
+ }
1808
+
1809
+ /* Vector path (CArray input): returns Ruby Array of N CArrays,
1810
+ * each with the same shape as the input; mask propagated. */
1811
+ {
1812
+ CArray *cin, *co[CA_RANK_MAX];
1813
+ ca_size_t *p_out[CA_RANK_MAX];
1814
+ boolean8_t *m;
1815
+ ca_size_t j, n;
1816
+ volatile VALUE objs[CA_RANK_MAX];
1817
+
1818
+ cin = ca_wrap_readonly(raddr, CA_SIZE);
1819
+ ca_attach(cin);
1820
+
1821
+ out = rb_ary_new2(ndim);
1822
+ for (i = 0; i < ndim; i++) {
1823
+ objs[i] = rb_carray_new(CA_SIZE, cin->ndim, cin->dim, 0, NULL);
1824
+ TypedData_Get_Struct(objs[i], CArray, &carray_data_type, co[i]);
1825
+ p_out[i] = (ca_size_t *) co[i]->ptr;
1826
+ rb_ary_store(out, i, objs[i]);
1827
+ }
1828
+
1829
+ m = cin->mask ? (boolean8_t *) cin->mask->ptr : NULL;
1830
+ if ( m ) {
1831
+ for (i = 0; i < ndim; i++) {
1832
+ ca_create_mask(co[i]);
1833
+ memcpy(co[i]->mask->ptr, m, cin->elements);
1834
+ }
1835
+ }
1798
1836
 
1799
- addr = NUM2SIZE(raddr);
1800
- if ( addr < 0 || addr >= ca->elements ) {
1801
- rb_raise(rb_eArgError,
1802
- "address %lld is out of range (0..%lld)",
1803
- (ca_size_t) addr, (ca_size_t) (ca->elements-1));
1804
- }
1805
- dim = ca->dim;
1806
- out = rb_ary_new2(ca->ndim);
1807
- for (i=ca->ndim-1; i>=0; i--) { /* in descending order */
1808
- rb_ary_store(out, i, SIZE2NUM(addr % dim[i]));
1809
- addr /= dim[i];
1810
- }
1837
+ n = cin->elements;
1838
+ {
1839
+ ca_size_t *src = (ca_size_t *) cin->ptr;
1840
+ ca_size_t addr;
1841
+ int k;
1842
+ for (j = 0; j < n; j++) {
1843
+ if ( m && m[j] ) {
1844
+ for (k = 0; k < ndim; k++) { p_out[k][j] = 0; }
1845
+ continue;
1846
+ }
1847
+ addr = src[j];
1848
+ if ( addr < 0 || addr >= elements ) {
1849
+ ca_detach(cin);
1850
+ rb_raise(rb_eArgError,
1851
+ "address %" PRId64 " is out of range (0..%" PRId64 ")",
1852
+ (ca_size_t) addr, (ca_size_t) (elements - 1));
1853
+ }
1854
+ for (k = ndim - 1; k >= 0; k--) {
1855
+ p_out[k][j] = addr % dim[k];
1856
+ addr /= dim[k];
1857
+ }
1858
+ }
1859
+ }
1811
1860
 
1812
- return out;
1861
+ ca_detach(cin);
1862
+ return out;
1863
+ }
1813
1864
  }
1814
1865
 
1815
- /* yard:
1816
- class CArray
1817
- def index2addr (*index)
1818
- end
1819
- end
1820
- */
1821
-
1822
- VALUE
1823
- rb_ca_index2addr (int argc, VALUE *argv, VALUE self)
1866
+ static VALUE
1867
+ index2addr_do (int ndim, ca_size_t *dim, int argc, VALUE *argv)
1824
1868
  {
1825
1869
  volatile VALUE obj;
1826
- CArray *ca, *co, *cidx[CA_RANK_MAX];
1870
+ CArray *co, *cidx[CA_RANK_MAX];
1827
1871
  ca_size_t *q, *p[CA_RANK_MAX], s[CA_RANK_MAX];
1828
- ca_size_t *dim;
1829
- ca_size_t addr, elements = 0;
1830
- int8_t i;
1831
- ca_size_t k, n;
1872
+ ca_size_t addr, k, n;
1832
1873
  boolean8_t *m;
1833
- int all_number = 1;
1874
+ int i, all_number = 1;
1875
+ int out_ndim = 1;
1876
+ ca_size_t out_dim[CA_RANK_MAX];
1877
+ ca_size_t out_elements = 1;
1878
+ int shape_from = -1;
1834
1879
 
1835
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1836
-
1837
- if ( argc != ca->ndim ) {
1838
- rb_raise(rb_eRuntimeError, "invalid ndim of index");
1880
+ if ( argc != ndim ) {
1881
+ rb_raise(rb_eArgError,
1882
+ "wrong number of indices (%d for %d)", argc, ndim);
1839
1883
  }
1840
1884
 
1841
- for (i=0; i<ca->ndim; i++) {
1885
+ for (i = 0; i < ndim; i++) {
1842
1886
  if ( ! rb_obj_is_kind_of(argv[i], rb_cInteger) ) {
1843
1887
  all_number = 0;
1844
1888
  break;
1845
1889
  }
1846
1890
  }
1847
1891
 
1892
+ /* All-scalar path: returns single Integer (unchanged). */
1848
1893
  if ( all_number ) {
1849
- dim = ca->dim;
1850
1894
  addr = 0;
1851
- for (i=0; i<ca->ndim; i++) {
1895
+ for (i = 0; i < ndim; i++) {
1852
1896
  k = NUM2SIZE(argv[i]);
1853
1897
  CA_CHECK_INDEX(k, dim[i]);
1854
1898
  addr = dim[i] * addr + k;
@@ -1856,62 +1900,77 @@ rb_ca_index2addr (int argc, VALUE *argv, VALUE self)
1856
1900
  return SIZE2NUM(addr);
1857
1901
  }
1858
1902
 
1859
- elements = 1;
1860
- for (i=0; i<ca->ndim; i++) {
1903
+ /* Vector path: wrap each arg as CA_SIZE view. Output shape follows
1904
+ * the first non-scalar CArray input; other non-scalar inputs must
1905
+ * match that shape. */
1906
+ for (i = 0; i < ndim; i++) {
1861
1907
  cidx[i] = ca_wrap_readonly(argv[i], CA_SIZE);
1862
1908
  if ( ! ca_is_scalar(cidx[i]) ) {
1863
- if ( elements == 1 ) {
1864
- elements = cidx[i]->elements;
1909
+ if ( shape_from < 0 ) {
1910
+ shape_from = i;
1911
+ out_ndim = cidx[i]->ndim;
1912
+ memcpy(out_dim, cidx[i]->dim, sizeof(ca_size_t) * out_ndim);
1913
+ out_elements = cidx[i]->elements;
1865
1914
  }
1866
- else if ( elements != cidx[i]->elements ) {
1867
- rb_raise(rb_eRuntimeError, "mismatch in # of elements");
1915
+ else {
1916
+ int j;
1917
+ if ( cidx[i]->ndim != out_ndim
1918
+ || cidx[i]->elements != out_elements ) {
1919
+ rb_raise(rb_eArgError,
1920
+ "shape mismatch: axis %d has shape ndim=%d elements=%"
1921
+ PRId64 ", expected ndim=%d elements=%" PRId64,
1922
+ i, cidx[i]->ndim, (ca_size_t) cidx[i]->elements,
1923
+ out_ndim, (ca_size_t) out_elements);
1924
+ }
1925
+ for (j = 0; j < out_ndim; j++) {
1926
+ if ( cidx[i]->dim[j] != out_dim[j] ) {
1927
+ rb_raise(rb_eArgError,
1928
+ "shape mismatch at axis %d dim %d", i, j);
1929
+ }
1930
+ }
1868
1931
  }
1869
1932
  }
1870
1933
  }
1871
1934
 
1872
- for (i=0; i<ca->ndim; i++) {
1935
+ for (i = 0; i < ndim; i++) {
1873
1936
  ca_attach(cidx[i]);
1874
1937
  ca_set_iterator(1, cidx[i], &p[i], &s[i]);
1875
1938
  }
1876
1939
 
1877
- obj = rb_carray_new(CA_SIZE, 1, &elements, 0, NULL);
1940
+ obj = rb_carray_new(CA_SIZE, out_ndim, out_dim, 0, NULL);
1878
1941
  TypedData_Get_Struct(obj, CArray, &carray_data_type, co);
1879
1942
 
1880
1943
  q = (ca_size_t *) co->ptr;
1881
1944
 
1882
- ca_copy_mask_overwrite_n(co, elements, ca->ndim, cidx);
1945
+ ca_copy_mask_overwrite_n(co, out_elements, ndim, cidx);
1883
1946
  m = ( co->mask ) ? (boolean8_t *) co->mask->ptr : NULL;
1884
1947
 
1885
- dim = ca->dim;
1886
-
1887
1948
  if ( m ) {
1888
- n = elements;
1949
+ n = out_elements;
1889
1950
  while ( n-- ) {
1890
- if ( !*m ) {
1951
+ if ( ! *m ) {
1891
1952
  addr = 0;
1892
- for (i=0; i<ca->ndim; i++) {
1953
+ for (i = 0; i < ndim; i++) {
1893
1954
  k = *(p[i]);
1894
- p[i]+=s[i];
1955
+ p[i] += s[i];
1895
1956
  CA_CHECK_INDEX(k, dim[i]);
1896
1957
  addr = dim[i] * addr + k;
1897
1958
  }
1898
1959
  *q = addr;
1899
1960
  }
1900
1961
  else {
1901
- for (i=0; i<ca->ndim; i++) {
1902
- p[i]+=s[i];
1903
- }
1962
+ for (i = 0; i < ndim; i++) { p[i] += s[i]; }
1904
1963
  }
1905
1964
  m++; q++;
1906
1965
  }
1907
1966
  }
1908
1967
  else {
1909
- n = elements;
1968
+ n = out_elements;
1910
1969
  while ( n-- ) {
1911
1970
  addr = 0;
1912
- for (i=0; i<ca->ndim; i++) {
1971
+ for (i = 0; i < ndim; i++) {
1913
1972
  k = *(p[i]);
1914
- p[i]+=s[i];
1973
+ p[i] += s[i];
1915
1974
  CA_CHECK_INDEX(k, dim[i]);
1916
1975
  addr = dim[i] * addr + k;
1917
1976
  }
@@ -1920,26 +1979,84 @@ rb_ca_index2addr (int argc, VALUE *argv, VALUE self)
1920
1979
  }
1921
1980
  }
1922
1981
 
1923
- for (i=0; i<ca->ndim; i++) {
1924
- ca_detach(cidx[i]);
1925
- }
1982
+ for (i = 0; i < ndim; i++) { ca_detach(cidx[i]); }
1926
1983
 
1927
1984
  return obj;
1928
1985
  }
1929
1986
 
1987
+ VALUE
1988
+ rb_ca_addr2index (VALUE self, VALUE raddr)
1989
+ {
1990
+ CArray *ca;
1991
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1992
+ return addr2index_do(ca->ndim, ca->dim, ca->elements, raddr);
1993
+ }
1994
+
1995
+ VALUE
1996
+ rb_ca_index2addr (int argc, VALUE *argv, VALUE self)
1997
+ {
1998
+ CArray *ca;
1999
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
2000
+ return index2addr_do(ca->ndim, ca->dim, argc, argv);
2001
+ }
2002
+
2003
+ /* CArray.addr2index(addr, shape: [...]) */
2004
+ static VALUE
2005
+ rb_ca_s_addr2index (int argc, VALUE *argv, VALUE klass)
2006
+ {
2007
+ VALUE raddr, opts;
2008
+ ID kw_ids[1];
2009
+ VALUE kw_vals[1];
2010
+ int ndim;
2011
+ ca_size_t dim[CA_RANK_MAX];
2012
+ ca_size_t elements;
2013
+
2014
+ kw_ids[0] = rb_intern("shape");
2015
+ rb_scan_args(argc, argv, "1:", &raddr, &opts);
2016
+ if ( NIL_P(opts) ) {
2017
+ rb_raise(rb_eArgError, "missing keyword: shape");
2018
+ }
2019
+ rb_get_kwargs(opts, kw_ids, 1, 0, kw_vals);
2020
+ parse_shape_kwarg(kw_vals[0], &ndim, dim, &elements);
2021
+ return addr2index_do(ndim, dim, elements, raddr);
2022
+ }
2023
+
2024
+ /* CArray.index2addr(*index, shape: [...]) */
2025
+ static VALUE
2026
+ rb_ca_s_index2addr (int argc, VALUE *argv, VALUE klass)
2027
+ {
2028
+ VALUE rest, opts;
2029
+ ID kw_ids[1];
2030
+ VALUE kw_vals[1];
2031
+ int ndim;
2032
+ ca_size_t dim[CA_RANK_MAX];
2033
+ ca_size_t elements;
2034
+
2035
+ kw_ids[0] = rb_intern("shape");
2036
+ rb_scan_args(argc, argv, "*:", &rest, &opts);
2037
+ if ( NIL_P(opts) ) {
2038
+ rb_raise(rb_eArgError, "missing keyword: shape");
2039
+ }
2040
+ rb_get_kwargs(opts, kw_ids, 1, 0, kw_vals);
2041
+ parse_shape_kwarg(kw_vals[0], &ndim, dim, &elements);
2042
+ return index2addr_do(ndim, dim, (int) RARRAY_LEN(rest), RARRAY_PTR(rest));
2043
+ }
2044
+
1930
2045
 
1931
2046
  void
1932
- Init_carray_access ()
2047
+ Init_carray_access (void)
1933
2048
  {
1934
2049
 
1935
2050
  id_begin = rb_intern("begin");
1936
2051
  id_end = rb_intern("end");
1937
2052
  id_excl_end = rb_intern("exclude_end?");
1938
2053
 
1939
- id_ca = rb_intern("ca");
1940
2054
  id_to_ca = rb_intern("to_ca");
1941
- sym_star = ID2SYM(rb_intern("*"));
1942
- sym_perc = ID2SYM(rb_intern("%"));
2055
+ sym_star = ID2SYM(rb_intern("*"));
2056
+ sym_perc = ID2SYM(rb_intern("%"));
2057
+ sym_under = ID2SYM(rb_intern("_"));
2058
+ sym_gt = ID2SYM(rb_intern(">"));
2059
+ sym_tilde = ID2SYM(rb_intern("~"));
1943
2060
 
1944
2061
  rb_define_method(rb_cCArray, "[]", rb_ca_fetch_method, -1);
1945
2062
  rb_define_method(rb_cCArray, "[]=", rb_ca_store_method, -1);
@@ -1959,6 +2076,9 @@ Init_carray_access ()
1959
2076
  rb_define_method(rb_cCArray, "index2addr", rb_ca_index2addr, -1);
1960
2077
  rb_define_method(rb_cCArray, "addr2index", rb_ca_addr2index, 1);
1961
2078
 
2079
+ rb_define_singleton_method(rb_cCArray, "addr2index", rb_ca_s_addr2index, -1);
2080
+ rb_define_singleton_method(rb_cCArray, "index2addr", rb_ca_s_index2addr, -1);
2081
+
1962
2082
  rb_define_const(rb_cObject, "CA_REG_NONE", INT2NUM(CA_REG_NONE));
1963
2083
  rb_define_const(rb_cObject, "CA_REG_ALL", INT2NUM(CA_REG_ALL));
1964
2084
  rb_define_const(rb_cObject, "CA_REG_ADDRESS", INT2NUM(CA_REG_ADDRESS));