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
@@ -1,23 +1,149 @@
1
1
  /* ---------------------------------------------------------------------------
2
2
 
3
- carray_conversion.c
3
+ Value conversion and binary serialization: to_a / convert / dump_binary /
4
+ to_s / load_binary. Ruby-facing docs live in
5
+ yard-stubs/carray_conversion.rb.
4
6
 
5
- This file is part of Ruby/CArray extension library.
6
-
7
- Copyright (C) 2005-2020 Hiroki Motoyoshi
7
+ Siblings:
8
+ carray_copy.c — CArray-to-CArray copy / template family
9
+ carray_element.c — element-level fetch/store (rb_ca_ptr2obj / obj2ptr)
10
+ carray_cast_func.c — dtype cast table used by rb_ca_ptr2obj
8
11
 
9
12
  ---------------------------------------------------------------------------- */
10
13
 
11
14
  #include "carray.h"
12
15
 
13
- #if RUBY_VERSION_CODE >= 190
14
16
  #include "ruby/io.h"
15
- #else
16
- #include "rubyio.h"
17
- #endif
18
17
 
18
+ /* to_a dispatch:
19
+ numeric / boolean dtype + entity or attach-able view -> fast path
20
+ (dtype-direct leaf loop over the attached contig buffer)
21
+ CA_OBJECT / CA_FIXLEN -> universal
22
+ (rb_ca_fetch_index per cell; ptr is VALUE or byte string, not
23
+ directly castable through the leaf switch)
24
+
25
+ Masked cells materialise as CA_UNDEF on both paths. */
26
+
27
+ /* Leaf macro: dtype-specialized inner loop. Produces `n` VALUE objects
28
+ from a contig ptr base + element width, storing into `dst` (Ruby Array). */
29
+ #define TO_A_LEAF_LOOP(T, TO_VALUE) do { \
30
+ const T *src = (const T *) base; \
31
+ for (li = 0; li < n; li++) { \
32
+ rb_ary_store(dst, li, TO_VALUE(src[li])); \
33
+ } \
34
+ } while (0)
35
+
36
+ #define TO_A_LEAF_LOOP_MASKED(T, TO_VALUE) do { \
37
+ const T *src = (const T *) base; \
38
+ for (li = 0; li < n; li++) { \
39
+ rb_ary_store(dst, li, mask[li] ? CA_UNDEF : TO_VALUE(src[li])); \
40
+ } \
41
+ } while (0)
42
+
43
+ #define TO_A_DISPATCH_LEAF(LOOP) do { \
44
+ ca_size_t li; \
45
+ switch ( dtype ) { \
46
+ case CA_FLOAT64: LOOP(double, rb_float_new); break; \
47
+ case CA_FLOAT32: LOOP(float, rb_float_new); break; \
48
+ case CA_INT64: LOOP(int64_t, LL2NUM); break; \
49
+ case CA_INT32: LOOP(int32_t, INT2NUM); break; \
50
+ case CA_INT16: LOOP(int16_t, INT2FIX); break; \
51
+ case CA_INT8: LOOP(int8_t, INT2FIX); break; \
52
+ case CA_UINT64: LOOP(uint64_t, ULL2NUM); break; \
53
+ case CA_UINT32: LOOP(uint32_t, UINT2NUM); break; \
54
+ case CA_UINT16: LOOP(uint16_t, INT2FIX); break; \
55
+ case CA_UINT8: LOOP(uint8_t, INT2FIX); break; \
56
+ case CA_BOOLEAN: \
57
+ /* Emit Ruby true/false. Consistent with the per-cell Ruby-land yield
58
+ family (a[i], each, each_with_addr, elem_fetch, CScalar value) which
59
+ all yield Qtrue/Qfalse since Part A. Numeric casts and serialize
60
+ paths keep the raw uint8 encoding via BOOL2OBJ (they do not go
61
+ through this leaf). */ \
62
+ { \
63
+ const uint8_t *src = (const uint8_t *) base; \
64
+ for (li = 0; li < n; li++) { \
65
+ rb_ary_store(dst, li, src[li] ? Qtrue : Qfalse); \
66
+ } \
67
+ } \
68
+ break; \
69
+ default: \
70
+ rb_bug("to_a fast path: unexpected dtype %d", dtype); \
71
+ } \
72
+ } while (0)
73
+
74
+ #define TO_A_DISPATCH_LEAF_MASKED(LOOP) do { \
75
+ ca_size_t li; \
76
+ switch ( dtype ) { \
77
+ case CA_FLOAT64: LOOP(double, rb_float_new); break; \
78
+ case CA_FLOAT32: LOOP(float, rb_float_new); break; \
79
+ case CA_INT64: LOOP(int64_t, LL2NUM); break; \
80
+ case CA_INT32: LOOP(int32_t, INT2NUM); break; \
81
+ case CA_INT16: LOOP(int16_t, INT2FIX); break; \
82
+ case CA_INT8: LOOP(int8_t, INT2FIX); break; \
83
+ case CA_UINT64: LOOP(uint64_t, ULL2NUM); break; \
84
+ case CA_UINT32: LOOP(uint32_t, UINT2NUM); break; \
85
+ case CA_UINT16: LOOP(uint16_t, INT2FIX); break; \
86
+ case CA_UINT8: LOOP(uint8_t, INT2FIX); break; \
87
+ case CA_BOOLEAN: \
88
+ /* Emit Ruby true/false, matching the unmasked leaf above. */ \
89
+ { \
90
+ const uint8_t *src = (const uint8_t *) base; \
91
+ for (li = 0; li < n; li++) { \
92
+ rb_ary_store(dst, li, mask[li] ? CA_UNDEF \
93
+ : (src[li] ? Qtrue : Qfalse)); \
94
+ } \
95
+ } \
96
+ break; \
97
+ default: \
98
+ rb_bug("to_a fast path masked: unexpected dtype %d", dtype); \
99
+ } \
100
+ } while (0)
101
+
102
+ /* Recursive multi-dim wrap: for non-leaf levels, allocate child Array and
103
+ recurse with adjusted base pointer. At leaf level, invoke dispatch.
104
+ `flat_base` is ca->ptr + cumulative byte offset for this slab. */
19
105
  static void
20
- rb_ca_to_a_loop (VALUE self, int32_t level, ca_size_t *idx, VALUE ary)
106
+ to_a_fast_recurse (CArray *ca, int32_t level, const char *base,
107
+ const boolean8_t *mask_base, VALUE dst,
108
+ int dtype, ca_size_t bytes, int has_mask)
109
+ {
110
+ ca_size_t i, n, slab_elements, slab_bytes;
111
+
112
+ if ( level == ca->ndim - 1 ) {
113
+ n = ca->dim[level];
114
+ if ( has_mask ) {
115
+ const boolean8_t *mask = mask_base;
116
+ TO_A_DISPATCH_LEAF_MASKED(TO_A_LEAF_LOOP_MASKED);
117
+ }
118
+ else {
119
+ TO_A_DISPATCH_LEAF(TO_A_LEAF_LOOP);
120
+ }
121
+ return;
122
+ }
123
+
124
+ /* Non-leaf: walk dim[level], for each i allocate child Array + recurse. */
125
+ n = ca->dim[level];
126
+ slab_elements = 1;
127
+ for (i = level + 1; i < ca->ndim; i++) {
128
+ slab_elements *= ca->dim[i];
129
+ }
130
+ slab_bytes = slab_elements * bytes;
131
+
132
+ for (i = 0; i < n; i++) {
133
+ volatile VALUE child = rb_ary_new2(ca->dim[level + 1]);
134
+ rb_ary_store(dst, i, child);
135
+ to_a_fast_recurse(ca, level + 1,
136
+ base + i * slab_bytes,
137
+ has_mask ? mask_base + i * slab_elements : NULL,
138
+ child, dtype, bytes, has_mask);
139
+ }
140
+ }
141
+
142
+ /* Universal fallback for CA_OBJECT / CA_FIXLEN, where ptr-direct cast
143
+ through the leaf switch is not safe. Walks every cell through
144
+ rb_ca_fetch_index; masked cells return CA_UNDEF via the fetcher. */
145
+ static void
146
+ rb_ca_to_a_loop_universal (VALUE self, int32_t level, ca_size_t *idx, VALUE ary)
21
147
  {
22
148
  volatile VALUE obj;
23
149
  CArray *ca;
@@ -35,79 +161,180 @@ rb_ca_to_a_loop (VALUE self, int32_t level, ca_size_t *idx, VALUE ary)
35
161
  for (i=0; i<ca->dim[level]; i++) {
36
162
  idx[level] = i;
37
163
  obj = rb_ary_new2(ca->dim[level+1]);
38
- rb_ca_to_a_loop(self, level+1, idx, obj);
164
+ rb_ca_to_a_loop_universal(self, level+1, idx, obj);
39
165
  rb_ary_store(ary, i, obj);
40
166
  }
41
167
  }
42
168
  }
43
169
 
44
- /*
45
- @overload to_a
46
-
47
- (Conversion)
48
- Converts the array to Ruby's array. For higher dimension,
49
- the array is nested ndim-1 times.
50
- */
51
-
170
+ /* CArray#to_a — return a nested Ruby Array holding self's element values.
171
+ *
172
+ * ndim-1 nesting: shape [2, 3] -> 2-element Array of 3-element Arrays.
173
+ * Masked cells become CA_UNDEF; the mask itself is not preserved on the
174
+ * result. ca_attach(self) supplies a contig row-major buffer for the
175
+ * fast path, so all view kinds land in the dtype-direct leaf loop when
176
+ * the dtype is numeric or boolean; CA_OBJECT / CA_FIXLEN fall through
177
+ * to the universal fetch_index walk. */
52
178
  VALUE
53
179
  rb_ca_to_a (VALUE self)
54
180
  {
55
181
  volatile VALUE ary;
56
182
  CArray *ca;
57
183
  ca_size_t idx[CA_RANK_MAX];
184
+ int dtype, fast_eligible;
185
+
58
186
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
59
- ary = rb_ary_new2(ca->dim[0]);
187
+ ary = rb_ca_is_empty(self) ? rb_ary_new() : rb_ary_new2(ca->dim[0]);
60
188
  ca_attach(ca);
61
- rb_ca_to_a_loop(self, 0, idx, ary);
189
+
190
+ /* After ca_attach, ca->ptr is a contig row-major buffer (alias for
191
+ contig views, materialised otherwise) and ca->mask matches, so the
192
+ fast path handles every view kind. CA_OBJECT / CA_FIXLEN stay on
193
+ the universal path because their ptr is VALUE / byte string and
194
+ the leaf switch cannot cast them directly.
195
+
196
+ A Face stays on it too, whatever its storage: the fast path reads the
197
+ storage buffer, and a Face means something else on its surface (an
198
+ Element, a label). Reading the buffer would hand back the storage of a
199
+ numeric-storage Face -- CATimedelta serials instead of CATimedelta
200
+ Elements -- while ca[i] / each / to_type(:object) all decode. The
201
+ universal loop goes through rb_ca_fetch_addr, which decodes. */
202
+ dtype = ca->data_type;
203
+ fast_eligible = (ca->elements > 0)
204
+ && ( ! ca_is_face(ca) )
205
+ && (dtype == CA_FLOAT64 || dtype == CA_FLOAT32
206
+ || dtype == CA_INT64 || dtype == CA_INT32
207
+ || dtype == CA_INT16 || dtype == CA_INT8
208
+ || dtype == CA_UINT64 || dtype == CA_UINT32
209
+ || dtype == CA_UINT16 || dtype == CA_UINT8
210
+ || dtype == CA_BOOLEAN);
211
+
212
+ if ( fast_eligible ) {
213
+ int has_mask = (ca->mask != NULL);
214
+ const boolean8_t *mask_base = has_mask
215
+ ? (const boolean8_t *) ca->mask->ptr : NULL;
216
+ to_a_fast_recurse(ca, 0, ca->ptr, mask_base, ary,
217
+ dtype, ca->bytes, has_mask);
218
+ }
219
+ else if ( ca->elements > 0 ) {
220
+ rb_ca_to_a_loop_universal(self, 0, idx, ary);
221
+ }
62
222
  ca_detach(ca);
63
223
  return ary;
64
224
  }
65
225
 
66
- /* @overload convert (data_type=nil, dim=nil) { |elem| ... }
67
-
68
- (Conversion)
69
- Returns new array which elements are caluculated
70
- in the iteration block. The output array is internally created
71
- using `CArray#template` to which the arguments is passed.
72
- */
73
-
226
+ #undef TO_A_LEAF_LOOP
227
+ #undef TO_A_LEAF_LOOP_MASKED
228
+ #undef TO_A_DISPATCH_LEAF
229
+ #undef TO_A_DISPATCH_LEAF_MASKED
230
+
231
+ /* CArray#convert(data_type=nil, bytes: nil) { |elem| ... } — map every cell
232
+ * through the block, into a new array whose dtype is chosen by argv via
233
+ * CArray#template (shape is inherited from self).
234
+ *
235
+ * Masked cells skip the block; if the block returns CA_UNDEF, the
236
+ * corresponding output cell is masked instead of stored. Both self
237
+ * and the template result are attached symmetrically (R3-compliant) so
238
+ * an overridden #template returning a view stays on the in-ptr path. */
74
239
  static VALUE
75
240
  rb_ca_convert (int argc, VALUE *argv, VALUE self)
76
241
  {
77
242
  volatile VALUE obj;
78
- CArray *ca;
79
- ca_size_t i;
243
+ CArray *ca, *co;
244
+ ca_size_t i, n, sbytes, dbytes;
245
+ int has_mask;
246
+ const boolean8_t *src_mask = NULL;
247
+ boolean8_t *dst_mask = NULL;
248
+ const char *src_ptr;
249
+ char *dst_ptr;
250
+
251
+ rb_need_block();
80
252
 
81
253
  obj = rb_apply(self, rb_intern("template"), rb_ary_new4(argc, argv));
82
254
 
83
255
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
256
+ TypedData_Get_Struct(obj, CArray, &carray_data_type, co);
257
+
258
+ n = ca->elements;
259
+ has_mask = ca_has_mask(ca);
260
+ sbytes = ca->bytes;
261
+ dbytes = co->bytes;
262
+
263
+ /* Attach every storage touched by ptr (self, obj, and either side's
264
+ mask) — parent → child order per the R4 attach protocol. */
84
265
  ca_attach(ca);
85
- if ( ca_has_mask(ca) ) {
86
- for (i=0; i<ca->elements; i++) {
87
- if ( ! ca->mask->ptr[i] ) {
88
- rb_ca_store_addr(obj, i, rb_yield(rb_ca_fetch_addr(self, i)));
266
+ ca_attach(co);
267
+ if ( has_mask ) {
268
+ ca_attach(ca->mask);
269
+ if ( ! co->mask ) {
270
+ ca_create_mask(co);
271
+ }
272
+ ca_attach(co->mask);
273
+ src_mask = (const boolean8_t *) ca->mask->ptr;
274
+ dst_mask = (boolean8_t *) co->mask->ptr;
275
+ memset(dst_mask, 0, (size_t) n);
276
+ }
277
+ src_ptr = ca->ptr;
278
+ dst_ptr = co->ptr;
279
+
280
+ if ( has_mask ) {
281
+ for (i = 0; i < n; i++) {
282
+ if ( ! src_mask[i] ) {
283
+ VALUE val = rb_ca_ptr2obj(self, (void *) (src_ptr + i * sbytes));
284
+ VALUE ret = rb_yield(val);
285
+ if ( ret == CA_UNDEF ) {
286
+ dst_mask[i] = 1;
287
+ }
288
+ else {
289
+ rb_ca_obj2ptr(obj, ret, dst_ptr + i * dbytes);
290
+ }
89
291
  }
90
292
  else {
91
- rb_ca_store_addr(obj, i, CA_UNDEF);
293
+ dst_mask[i] = 1;
92
294
  }
93
295
  }
94
296
  }
95
297
  else {
96
- for (i=0; i<ca->elements; i++) {
97
- rb_ca_store_addr(obj, i, rb_yield(rb_ca_fetch_addr(self, i)));
298
+ for (i = 0; i < n; i++) {
299
+ VALUE val = rb_ca_ptr2obj(self, (void *) (src_ptr + i * sbytes));
300
+ VALUE ret = rb_yield(val);
301
+ if ( ret == CA_UNDEF ) {
302
+ if ( ! co->mask ) {
303
+ ca_create_mask(co);
304
+ ca_attach(co->mask);
305
+ dst_mask = (boolean8_t *) co->mask->ptr;
306
+ memset(dst_mask, 0, (size_t) n);
307
+ }
308
+ dst_mask[i] = 1;
309
+ }
310
+ else {
311
+ rb_ca_obj2ptr(obj, ret, dst_ptr + i * dbytes);
312
+ }
98
313
  }
99
314
  }
315
+
316
+ if ( co->mask ) {
317
+ ca_sync(co->mask);
318
+ ca_detach(co->mask);
319
+ }
320
+ if ( has_mask ) {
321
+ ca_detach(ca->mask);
322
+ }
323
+ ca_sync(co);
324
+ ca_detach(co);
100
325
  ca_detach(ca);
101
326
 
102
327
  return obj;
103
328
  }
104
329
 
105
- /* @overload dump_binary
106
-
107
- (IO)
108
- Dumps the value array to the given IO stream
109
- */
110
-
330
+ /* CArray#dump_binary([io]) — write self's raw element bytes to io in
331
+ * row-major order.
332
+ *
333
+ * With no arg, returns a fresh binary String. A String arg is resized
334
+ * and overwritten in-place; a T_FILE writes through rb_io_bufwrite for
335
+ * entities (no Ruby String copy) or a scratch buffer for views; any
336
+ * other object must respond to #write. Rejects CA_OBJECT (data is
337
+ * VALUE, not portable). */
111
338
  static VALUE
112
339
  rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
113
340
  {
@@ -132,43 +359,39 @@ rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
132
359
 
133
360
  switch ( TYPE(io) ) {
134
361
  case T_STRING:
362
+ rb_check_frozen(io);
135
363
  if ( ca_length(ca) != RSTRING_LEN(io) ) {
136
364
  rb_str_resize(io, ca_length(ca));
137
365
  }
138
- ca_copy_data(ca, StringValuePtr(io));
139
- StringValuePtr(io)[ca_length(ca)] = '\0';
366
+ ca_copy_data(ca, RSTRING_PTR(io));
140
367
  break;
141
- #if RUBY_VERSION_CODE >= 190
142
368
  case T_FILE: {
143
- volatile VALUE str;
144
369
  rb_io_t *iop;
370
+ ca_size_t total = ca_length(ca);
145
371
  GetOpenFile(io, iop);
146
372
  rb_io_check_writable(iop);
147
- ca_attach(ca);
148
- str = rb_str_new(ca->ptr, ca->bytes*ca->elements);
149
- rb_io_write(io, str);
150
- ca_detach(ca);
151
- break;
152
- }
153
- #else
154
- case T_FILE: {
155
- OpenFile *iop;
156
- size_t total;
157
- GetOpenFile(io, iop);
158
- rb_io_check_writable(iop);
159
- ca_attach(ca);
160
- total = fwrite(ca->ptr, ca->bytes, ca->elements, iop->f);
161
- ca_detach(ca);
162
- if ( total < ca->elements ) {
163
- rb_raise(rb_eIOError, "I/O write error in CArray#dump_binary");
373
+ if ( ca_is_entity(ca) ) {
374
+ /* Owned ca->ptr: write through the IO buffer machinery so peak
375
+ stays at ca_length instead of doubling via a Ruby String. */
376
+ ssize_t n = rb_io_bufwrite(io, ca->ptr, (size_t) total);
377
+ if ( n < 0 || (ca_size_t) n != total ) {
378
+ rb_raise(rb_eRuntimeError,
379
+ "short write to IO (wrote %" PRId64 " bytes, expected %" PRId64 ")",
380
+ (ca_size_t) (n < 0 ? 0 : n), (ca_size_t) total);
381
+ }
382
+ }
383
+ else {
384
+ /* View: no chunked gather API, so materialise into one buffer. */
385
+ volatile VALUE buf = rb_str_new(NULL, total);
386
+ ca_copy_data(ca, RSTRING_PTR(buf));
387
+ rb_io_write(io, buf);
164
388
  }
165
389
  break;
166
390
  }
167
- #endif
168
391
  default:
169
392
  if ( rb_respond_to(io, rb_intern("write") ) ) {
170
393
  volatile VALUE buf = rb_str_new(NULL, ca_length(ca));
171
- ca_copy_data(ca, StringValuePtr(buf));
394
+ ca_copy_data(ca, RSTRING_PTR(buf));
172
395
  rb_funcall(io, rb_intern("write"), 1, buf);
173
396
  }
174
397
  else {
@@ -179,24 +402,21 @@ rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
179
402
  return io;
180
403
  }
181
404
 
182
- /* @overload to_s
183
-
184
- (Conversion)
185
- Dumps the value array to a string.
186
- */
187
-
405
+ /* CArray#to_s — equivalent to dump_binary with no argument. */
188
406
  static VALUE
189
407
  rb_ca_to_s (VALUE self)
190
408
  {
191
409
  return rb_ca_dump_binary(0, NULL, self);
192
410
  }
193
411
 
194
- /* @overload load_binary (io)
195
-
196
- (IO)
197
- Loads the value array from the given IO stream
198
- */
199
-
412
+ /* CArray#load_binary(io) — overwrite self's element bytes with ca_length
413
+ * bytes read from io in row-major order.
414
+ *
415
+ * A String arg of the exact length is used directly; anything else
416
+ * must respond to #read(n, buf). Entity targets read in 64 KiB
417
+ * chunks straight into ca->ptr (peak = ca_length + CHUNK); view
418
+ * targets buffer the full read and recurse via T_STRING because
419
+ * ca_sync_data scatters in one pass. */
200
420
  static VALUE
201
421
  rb_ca_load_binary (VALUE self, VALUE io)
202
422
  {
@@ -210,280 +430,73 @@ rb_ca_load_binary (VALUE self, VALUE io)
210
430
 
211
431
  switch ( TYPE(io) ) {
212
432
  case T_STRING:
213
- if ( ca_length(ca) > RSTRING_LEN(io) ) {
433
+ if ( ca_length(ca) != RSTRING_LEN(io) ) {
214
434
  rb_raise(rb_eRuntimeError,
215
- "data size mismatch (%lld for %lld)",
435
+ "data size mismatch (got %" PRId64 " bytes, expected %" PRId64 ")",
216
436
  (ca_size_t) RSTRING_LEN(io), (ca_size_t) ca_length(ca));
217
437
  }
218
- ca_allocate(ca);
219
- memcpy(ca->ptr, StringValuePtr(io), ca_length(ca));
220
- ca_sync(ca);
221
- ca_detach(ca);
438
+ ca_sync_data(ca, RSTRING_PTR(io));
222
439
  return self;
223
440
  break;
224
441
  default:
225
442
  if ( rb_respond_to(io, rb_intern("read") ) ) {
226
- volatile VALUE buf = rb_funcall(io, rb_intern("read"), 1, SIZE2NUM(ca_length(ca)));
227
- return rb_ca_load_binary(self, buf);
228
- }
229
- else {
230
- rb_raise(rb_eRuntimeError, "IO like object should have 'read' method");
231
- }
232
- }
233
-
234
- return self;
235
- }
236
-
237
- void *
238
- ca_to_cptr (void *ap)
239
- {
240
- CArray *ca = (CArray *) ap;
241
- void **ptr, **p, **r;
242
- char *q;
243
- ca_size_t offset[CA_RANK_MAX];
244
- ca_size_t count[CA_RANK_MAX];
245
- ca_size_t ptr_num;
246
- ca_size_t i, j;
247
-
248
- if ( ! ca_is_attached(ca) ) {
249
- rb_raise(rb_eRuntimeError, "[BUG] ca_to_cptr called for detached array");
250
- }
251
-
252
- if ( ca->ndim == 1 ) {
253
- rb_raise(rb_eRuntimeError, "[BUG] ca_to_cptr called for ndim-1 array");
254
- }
255
-
256
- offset[0] = 0;
257
- count[0] = ca->dim[0];
258
- ptr_num = count[0];
259
- for (i=1; i<ca->ndim-1; i++) {
260
- offset[i] = ptr_num;
261
- count[i] = count[i-1] * ca->dim[i];
262
- ptr_num += count[i];
263
- }
264
-
265
- ptr = malloc(sizeof(void*)*ptr_num);
266
-
267
- i = ca->ndim-2;
268
- p = ptr + offset[i];
269
- q = (char *)ca->ptr;
270
- for (j=0; j<count[i]; j++) {
271
- *p = (void*)q;
272
- p++; q += ca->dim[ca->ndim-1] * ca->bytes;
273
- }
274
-
275
- for (i=ca->ndim-3; i>=0; i--) {
276
- p = ptr + offset[i];
277
- r = ptr + offset[i+1];
278
- for (j=0; j<count[i]; j++) {
279
- *p = (void*)r;
280
- p++; r+=ca->dim[i+1];
281
- }
282
- }
283
-
284
- return ptr;
285
- }
286
-
287
-
288
- /* @overload str_format (*fmts)
289
-
290
- (Conversion)
291
- Creates object type array consist of string using the "::format" method.
292
- The Multiple format strings are given, they are applied cyclic in turn.
293
- */
294
-
295
-
296
- static VALUE
297
- rb_ca_format (int argc, VALUE *argv, VALUE self)
298
- {
299
- volatile VALUE obj, elem, val;
300
- CArray *ca;
301
- ca_size_t i, j;
302
- ID id_format = rb_intern("format");
303
-
304
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
305
-
306
- obj = rb_ca_template_with_type(self, INT2NUM(CA_OBJECT), INT2NUM(0));
307
-
308
- ca_attach(ca);
309
- if ( ca_has_mask(ca) ) {
310
- j = 0;
311
- for (i=0; i<ca->elements; i++) {
312
- val = CA_UNDEF;
313
- if ( ! ca->mask->ptr[i] ) {
314
- elem = rb_ca_fetch_addr(self, i);
315
- val = rb_funcall(elem, id_format, 2, argv[j], elem);
316
- }
317
- rb_ca_store_addr(obj, i, val);
318
- j++;
319
- j = j % argc; /* cyclic referencing of argv */
320
- }
321
- }
322
- else {
323
- j = 0;
324
- for (i=0; i<ca->elements; i++) {
325
- elem = rb_ca_fetch_addr(self, i);
326
- val = rb_funcall(elem, id_format, 2, argv[j], elem);
327
- rb_ca_store_addr(obj, i, val);
328
- j++;
329
- j = j % argc; /* cyclic referencing of argv */
330
- }
331
- }
332
- ca_detach(ca);
333
-
334
- return obj;
335
- }
336
-
337
-
338
- #include <time.h>
339
-
340
- #ifdef HAVE_STRPTIME
341
-
342
- /* @overload str_strptime (fmt)
343
-
344
- (Conversion)
345
- Creates object type array consist of Time objects
346
- which are created by 'Time.strptime' applied to the elements of the object.
347
- This method assumes all the elements of the objetct to be String.
348
- */
349
-
350
- static VALUE
351
- rb_ca_strptime (VALUE self, VALUE rfmt)
352
- {
353
- volatile VALUE obj, elem, val;
354
- CArray *ca;
355
- char *fmt;
356
- struct tm tmv;
357
- ca_size_t i;
358
-
359
- ca = ca_wrap_readonly(self, CA_OBJECT);
360
-
361
- if ( ! ca_is_object_type(ca) ) {
362
- rb_raise(rb_eRuntimeError, "strptime can be applied only to object type.");
363
- }
364
-
365
- Check_Type(rfmt, T_STRING);
366
- fmt = (char *) StringValuePtr(rfmt);
367
-
368
- obj = rb_ca_template(self);
369
-
370
- ca_attach(ca);
371
- if ( ca_has_mask(ca) ) {
372
- for (i=0; i<ca->elements; i++) {
373
- val = CA_UNDEF;
374
- if ( ! ca->mask->ptr[i] ) {
375
- elem = rb_ca_fetch_addr(self, i);
376
- if ( TYPE(elem) == T_STRING ) {
377
- memset(&tmv, 0, sizeof(struct tm));
378
- if ( strptime(StringValuePtr(elem), fmt, &tmv) ) {
379
- val = rb_time_new(mktime(&tmv), 0);
380
- }
443
+ ca_size_t total = ca_length(ca);
444
+ ID id_read = rb_intern("read");
445
+ if ( ca_is_entity(ca) ) {
446
+ /* Read straight into owned ca->ptr in CHUNK-sized slices. */
447
+ const ca_size_t CHUNK = 65536;
448
+ volatile VALUE scratch = rb_str_buf_new(CHUNK < total ? CHUNK : total);
449
+ ca_size_t off = 0;
450
+ ca_allocate(ca);
451
+ while ( off < total ) {
452
+ ca_size_t want = (total - off < CHUNK) ? (total - off) : CHUNK;
453
+ VALUE r = rb_funcall(io, id_read, 2, SIZE2NUM(want), scratch);
454
+ if ( NIL_P(r) || RSTRING_LEN(r) != want ) {
455
+ ca_detach(ca);
456
+ rb_raise(rb_eRuntimeError,
457
+ "short read from IO at offset %" PRId64 " "
458
+ "(got %" PRId64 " bytes, expected %" PRId64 ")",
459
+ (ca_size_t) off,
460
+ (ca_size_t) (NIL_P(r) ? 0 : RSTRING_LEN(r)),
461
+ (ca_size_t) want);
462
+ }
463
+ memcpy(ca->ptr + off, RSTRING_PTR(r), want);
464
+ off += want;
381
465
  }
466
+ ca_sync(ca);
467
+ ca_detach(ca);
382
468
  }
383
- rb_ca_store_addr(obj, i, val);
384
- }
385
- }
386
- else {
387
- for (i=0; i<ca->elements; i++) {
388
- val = CA_UNDEF;
389
- elem = rb_ca_fetch_addr(self, i);
390
- if ( TYPE(elem) == T_STRING ) {
391
- memset(&tmv, 0, sizeof(struct tm));
392
- if ( strptime(StringValuePtr(elem), fmt, &tmv) ) {
393
- val = rb_time_new(mktime(&tmv), 0);
394
- }
395
- }
396
- rb_ca_store_addr(obj, i, val);
397
- }
398
- }
399
- ca_detach(ca);
400
-
401
- return obj;
402
- }
403
-
404
- #endif
405
-
406
- /* @overload time_strftime (fmt)
407
-
408
- (Conversion)
409
- Creates object type array consist of strings
410
- which are created by 'Time#strftime' applied to the elements of the object.
411
- This method assumes all the elements of the objetct to be Time or DateTime.
412
- */
413
-
414
- static VALUE
415
- rb_ca_strftime (VALUE self, VALUE rfmt)
416
- {
417
- volatile VALUE obj, elem, val;
418
- CArray *ca;
419
- ca_size_t i;
420
- ID id_strftime = rb_intern("strftime");
421
-
422
- ca = ca_wrap_readonly(self, CA_OBJECT);
423
-
424
- if ( ! ca_is_object_type(ca) ) {
425
- rb_raise(rb_eRuntimeError, "strptime can be applied only to object type.");
426
- }
427
-
428
- obj = rb_ca_template(self);
429
-
430
- ca_attach(ca);
431
- if ( ca_has_mask(ca) ) {
432
- for (i=0; i<ca->elements; i++) {
433
- val = CA_UNDEF;
434
- if ( ! ca->mask->ptr[i] ) {
435
- elem = rb_ca_fetch_addr(self, i);
436
- val = rb_funcall(elem, id_strftime, 1, rfmt);
469
+ else {
470
+ /* ca_sync_data scatters in one pass, so buffer the full read
471
+ and recurse via T_STRING. */
472
+ volatile VALUE buf = rb_funcall(io, id_read, 1, SIZE2NUM(total));
473
+ if ( NIL_P(buf) || RSTRING_LEN(buf) != total ) {
474
+ rb_raise(rb_eRuntimeError,
475
+ "short read from IO (got %" PRId64 " bytes, expected %" PRId64 ")",
476
+ (ca_size_t) (NIL_P(buf) ? 0 : RSTRING_LEN(buf)),
477
+ (ca_size_t) total);
478
+ }
479
+ return rb_ca_load_binary(self, buf);
437
480
  }
438
- rb_ca_store_addr(obj, i, val);
481
+ return self;
439
482
  }
440
- }
441
- else {
442
- for (i=0; i<ca->elements; i++) {
443
- elem = rb_ca_fetch_addr(self, i);
444
- val = rb_funcall(elem, id_strftime, 1, rfmt);
445
- rb_ca_store_addr(obj, i, val);
483
+ else {
484
+ rb_raise(rb_eRuntimeError, "IO like object should have 'read' method");
446
485
  }
447
486
  }
448
- ca_detach(ca);
449
487
 
450
- return obj;
488
+ return self;
451
489
  }
452
490
 
453
- /* @private
454
-
455
- */
456
-
457
- static VALUE
458
- rb_test_ca_to_cptr (VALUE self)
459
- {
460
- CArray *ca;
461
- double ****a;
462
- int i, j, k, l;
463
-
464
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
465
-
466
- ca_attach(ca);
467
-
468
- a = ca_to_cptr(ca);
469
- for (i=0; i<ca->dim[0]; i++) {
470
- for (j=0; j<ca->dim[1]; j++) {
471
- for (k=0; k<ca->dim[2]; k++) {
472
- for (l=0; l<ca->dim[3]; l++) {
473
- printf("(%i, %i, %i, %i) -> %g\n", i, j, k, l, a[i][j][k][l]);
474
- }
475
- }
476
- }
477
- }
478
- free(a);
491
+ /* [MOVED] str_format (2.0-era per-element formatter) is replaced by the Ruby
492
+ CArray#format / CArray.format surface in lib/carray/methods/string_format.rb,
493
+ which yields a CAString. */
479
494
 
480
- ca_detach(ca);
481
-
482
- return Qnil;
483
- }
495
+ /* [MOVED] time-related conversion (str_strptime / time_strftime) is
496
+ subsumed by CATime (see lib/carray/time.rb). */
484
497
 
485
498
  void
486
- Init_carray_conversion ()
499
+ Init_carray_conversion (void)
487
500
  {
488
501
  rb_define_method(rb_cCArray, "to_a", rb_ca_to_a, 0);
489
502
  rb_define_method(rb_cCArray, "convert", rb_ca_convert, -1);
@@ -492,17 +505,8 @@ Init_carray_conversion ()
492
505
  rb_define_method(rb_cCArray, "to_s", rb_ca_to_s, 0);
493
506
  rb_define_method(rb_cCArray, "load_binary", rb_ca_load_binary, 1);
494
507
 
495
- /* DO NOT define CArray#to_ary, it makes trouble with various situations */
496
- /* rb_define_method(rb_cCArray, "to_ary", rb_ca_to_a, 0); */
497
-
498
- rb_define_method(rb_cCArray, "str_format", rb_ca_format, -1);
499
-
500
- #ifdef HAVE_STRPTIME
501
- rb_define_method(rb_cCArray, "str_strptime", rb_ca_strptime, 1);
502
- #endif
503
-
504
- rb_define_method(rb_cCArray, "time_strftime", rb_ca_strftime, 1);
505
-
506
- rb_define_method(rb_cCArray, "test_ca_to_cptr", rb_test_ca_to_cptr, 0);
507
-
508
+ /* CAREFUL: do not bind #to_ary implicit array coercion in Ruby core
509
+ (splat / multiple assignment / Array()) then triggers on any CArray
510
+ and disrupts unrelated call sites. */
511
+ /* rb_define_method(rb_cCArray, "to_ary", rb_ca_to_a, 0); */
508
512
  }