carray 3.0.2 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_refer.c CHANGED
@@ -74,34 +74,51 @@ ca_refer_setup (CARefer *ca, CArray *parent,
74
74
  ca_size_t s;
75
75
  int8_t i;
76
76
 
77
- CA_CHECK_DATA_TYPE(data_type);
78
- CA_CHECK_RANK(ndim);
79
- CA_CHECK_DIM(ndim, dim);
80
- CA_CHECK_BYTES(data_type, bytes);
77
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
78
+ CA_CHECK_RANK_GIVEN(ndim);
79
+ CA_CHECK_DIM_GIVEN(ndim, dim);
80
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
81
81
 
82
+ /* An object cell is a VALUE the GC marks: reading other bytes as one
83
+ marks garbage, and reading one as bytes exposes an address. */
82
84
  if (ca_is_object_type(parent) && data_type != CA_OBJECT) {
83
- rb_raise(rb_eRuntimeError,
85
+ rb_raise(rb_eCADataTypeError,
84
86
  "object array can't be referred by other data type");
85
87
  }
88
+ if (! ca_is_object_type(parent) && data_type == CA_OBJECT) {
89
+ rb_raise(rb_eCADataTypeError,
90
+ "non-object array can't be referred as object data type");
91
+ }
92
+ /* A boolean cell holds 0 or 1, and a view that reads other bytes as
93
+ boolean cannot keep them so: the parent is written as what it is. */
94
+ if (data_type == CA_BOOLEAN && parent->data_type != CA_BOOLEAN) {
95
+ rb_raise(rb_eCADataTypeError,
96
+ "%s: a %s array can't be referred as boolean (its bytes need not "
97
+ "be 0 or 1); compare it instead, e.g. ne(0)",
98
+ ca_calling_method_name(), ca_type_name[parent->data_type]);
99
+ }
86
100
  if (parent->elements && bytes > parent_bytes * parent->elements) {
87
- rb_raise(rb_eRuntimeError, "bytes exceeds the data size of referent");
101
+ rb_raise(rb_eArgError, "bytes exceeds the data size of referent");
88
102
  }
89
103
  if (bytes < parent_bytes && parent_bytes % bytes != 0) {
90
- rb_raise(rb_eRuntimeError,
104
+ rb_raise(rb_eArgError,
91
105
  "bytes of reference array must be a multiple of that of referent");
92
106
  }
93
107
  if (bytes > parent_bytes && bytes % parent_bytes != 0) {
94
- rb_raise(rb_eRuntimeError,
108
+ rb_raise(rb_eArgError,
95
109
  "bytes of reference array must be a multiple of that of referent");
96
110
  }
97
111
  if (offset < 0) {
98
- rb_raise(rb_eRuntimeError, "negative offset is not permitted for CARefer");
112
+ rb_raise(rb_eArgError, "negative offset is not permitted for CARefer");
113
+ }
114
+ elements = ca_shape_elements(ndim, dim, bytes);
115
+ if (offset > parent->elements) {
116
+ rb_raise(rb_eArgError,
117
+ "data size of reference array must not exceed that of referent");
99
118
  }
100
- elements = 1;
101
- for (i = 0; i < ndim; i++) elements *= dim[i];
102
119
  if ((bytes * elements + parent_bytes * offset) >
103
120
  (parent_bytes * parent->elements)) {
104
- rb_raise(rb_eRuntimeError,
121
+ rb_raise(rb_eArgError,
105
122
  "data size of reference array must not exceed that of referent");
106
123
  }
107
124
 
@@ -114,14 +131,19 @@ ca_refer_setup (CARefer *ca, CArray *parent,
114
131
  /* base_offset is in bytes: `offset` is in parent-element units. */
115
132
  base_offset = offset * parent_bytes;
116
133
 
117
- /* CAREFUL: initialise mask0 before ca_stride_setup — the setup
118
- may dispatch to ca_refer_func_create_mask, which writes to
119
- mask0. Leaving it uninitialised risks freeing a garbage
120
- pointer during error unwind. */
134
+ /* ca == NULL asks for the checks above only, so that a constructor can
135
+ run them before it allocates. */
136
+ if ( ca == NULL ) {
137
+ return 0;
138
+ }
139
+
140
+ /* mask0 is written by ca_refer_func_create_mask when the constructor
141
+ takes the parent's mask, and freed on error unwind, so it starts
142
+ NULL. */
121
143
  ca->mask0 = NULL;
122
144
 
123
- ca_stride_setup((CAStride *) ca, CA_OBJ_REFER, parent,
124
- data_type, bytes, ndim, dim, strides, base_offset);
145
+ ca_stride_setup_view((CAStride *) ca, CA_OBJ_REFER, parent,
146
+ data_type, bytes, ndim, dim, strides, base_offset);
125
147
 
126
148
  if (ca_is_scalar(parent)) {
127
149
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -134,8 +156,11 @@ ca_refer_new (CArray *parent,
134
156
  int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
135
157
  ca_size_t offset)
136
158
  {
137
- CARefer *ca = (CARefer *) ca_array_alloc(CA_OBJ_REFER, ndim);
159
+ CARefer *ca;
160
+ ca_refer_setup(NULL, parent, data_type, ndim, dim, bytes, offset);
161
+ ca = (CARefer *) ca_array_alloc(CA_OBJ_REFER, ndim);
138
162
  ca_refer_setup(ca, parent, data_type, ndim, dim, bytes, offset);
163
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
139
164
  return ca;
140
165
  }
141
166
 
@@ -172,10 +197,7 @@ ca_refer_func_create_mask (void *ap)
172
197
  ca_size_t parent_bytes = ca->parent->bytes;
173
198
  ca_size_t parent_offset;
174
199
 
175
- ca_update_mask(ca->parent);
176
- if (! ca->parent->mask) {
177
- ca_create_mask(ca->parent);
178
- }
200
+ ca_create_mask(ca->parent);
179
201
 
180
202
  parent_offset = ca->base_offset / parent_bytes;
181
203
 
@@ -200,9 +222,12 @@ ca_refer_func_create_mask (void *ap)
200
222
  ca->mask0 =
201
223
  (CArray *) ca_repeat_new(ca->parent->mask, ca->parent->ndim + 1, count);
202
224
  ca_unset_flag(ca->mask0, CA_FLAG_READ_ONLY);
225
+ /* mask0 has ratio cells per parent element, so the offset is counted
226
+ in those. */
203
227
  ca->mask =
204
228
  (CArray *) ca_refer_new(ca->mask0,
205
- CA_BOOLEAN, ca->ndim, ca->dim, 0, parent_offset);
229
+ CA_BOOLEAN, ca->ndim, ca->dim, 0,
230
+ parent_offset * ratio);
206
231
  }
207
232
  else {
208
233
  /* Spanned reinterpret: ratio = bytes / parent_bytes parent
@@ -232,6 +257,7 @@ rb_ca_refer_initialize_copy (VALUE self, VALUE other)
232
257
  {
233
258
  CARefer *ca, *cs;
234
259
  TypedData_Get_Struct(self, CARefer, &carefer_data_type, ca);
260
+ ca_check_uninitialized(ca);
235
261
  TypedData_Get_Struct(other, CARefer, &carefer_data_type, cs);
236
262
  if ( ca_func[CA_OBJ_REFER].pool_init ) {
237
263
  ca_array_pool_alloc(ca, CA_OBJ_REFER, cs->ndim);
@@ -242,6 +268,7 @@ rb_ca_refer_initialize_copy (VALUE self, VALUE other)
242
268
  unusual mod-bytes alignments. */
243
269
  ca_refer_setup(ca, cs->parent, cs->data_type, cs->ndim, cs->dim,
244
270
  cs->bytes, cs->base_offset / cs->parent->bytes);
271
+ ca_view_inherit_mask((VALUE) ca);
245
272
  return self;
246
273
  }
247
274
 
@@ -275,6 +302,34 @@ rb_ca_refer_initialize_copy (VALUE self, VALUE other)
275
302
  * 2. Match ranges of parent axes to new axes so element products
276
303
  * agree. Inside each matched range, root_strides must be
277
304
  * inter-axis contiguous. */
305
+ /* Three properties of an array are answered by walking its C parent chain:
306
+ ca_is_value_array, ca_is_readonly and ca_is_mask_array. An array that is
307
+ built somewhere other than as a child of `src` -- a reshape that folds
308
+ onto the root, the copy that dup / clone makes -- does not have `src` on
309
+ that chain, so carry each property across from `src`. Without this a
310
+ reshape or a dup of x.value reads the mask of x again (and takes UNDEF
311
+ into it), and a reshape of a broadcast view becomes writable. */
312
+ void
313
+ ca_keep_chain_flags (CArray *view, CArray *src)
314
+ {
315
+ if ( ca_is_value_array(src) ) {
316
+ if ( view->mask ) {
317
+ ca_free(view->mask);
318
+ view->mask = NULL;
319
+ }
320
+ ca_set_flag(view, CA_FLAG_VALUE_ARRAY);
321
+ }
322
+ if ( ca_is_readonly(src) ) {
323
+ ca_set_flag(view, CA_FLAG_READ_ONLY);
324
+ if ( view->mask ) {
325
+ ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
326
+ }
327
+ }
328
+ if ( ca_is_mask_array(src) ) {
329
+ ca_set_flag(view, CA_FLAG_MASK_ARRAY);
330
+ }
331
+ }
332
+
278
333
  static int
279
334
  ca_reshape_try_strides (CArray *parent,
280
335
  const ca_size_t *new_dim,
@@ -401,8 +456,11 @@ ca_reshape_try_strides (CArray *parent,
401
456
  return 1;
402
457
  }
403
458
 
459
+ /* `refer` with its options given apart from argv, for callers in C that
460
+ build the options themselves (a Hash at the end of argv is read as
461
+ options only when the Ruby caller passed keywords). */
404
462
  static VALUE
405
- rb_ca_refer (int argc, VALUE *argv, VALUE self)
463
+ rb_ca_refer_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
406
464
  {
407
465
  volatile VALUE obj = Qnil;
408
466
  CArray *ca;
@@ -415,7 +473,7 @@ rb_ca_refer (int argc, VALUE *argv, VALUE self)
415
473
 
416
474
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
417
475
 
418
- if (argc == 0) {
476
+ if (argc == 0 && NIL_P(ropt)) {
419
477
  data_type = ca->data_type;
420
478
  bytes = ca->bytes;
421
479
  ndim = ca->ndim;
@@ -425,39 +483,57 @@ rb_ca_refer (int argc, VALUE *argv, VALUE self)
425
483
  rb_ca_set_parent(obj, self);
426
484
  }
427
485
  else {
428
- volatile VALUE rtype, rdim, ropt, rbytes = Qnil, roffset = Qnil;
429
- ropt = rb_pop_options(&argc, &argv);
486
+ volatile VALUE rtype, rdim, rbytes = Qnil, roffset = Qnil;
430
487
  rb_scan_args(argc, argv, "11", (VALUE *) &rtype, (VALUE *) &rdim);
431
488
  rb_scan_options(ropt, "bytes,offset", &rbytes, &roffset);
432
489
  if (NIL_P(rbytes)) rbytes = rb_ca_bytes(self);
433
490
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
434
491
  if (NIL_P(rdim)) {
435
492
  if (ca->bytes != bytes) {
436
- rb_raise(rb_eRuntimeError,
493
+ rb_raise(rb_eArgError,
437
494
  "specify dimension shape for different byte size");
438
495
  } else {
439
496
  rdim = rb_ca_dim(self);
440
497
  }
441
498
  }
442
499
  Check_Type(rdim, T_ARRAY);
500
+ CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
443
501
  ndim = RARRAY_LEN(rdim);
444
502
  for (i = 0; i < ndim; i++) dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
445
503
  if (! NIL_P(roffset)) offset = NUM2SIZE(roffset);
504
+ /* When rtype is a data_class the result is a record array. It is
505
+ built on the storage, never on a Face, so that a Face stays on top
506
+ of the chain: re-reading a record array as its own data_class lifts
507
+ it (keeping its class), any other data_class wraps a new CARecord. */
508
+ if ( rb_obj_is_data_class(rtype) ) {
509
+ volatile VALUE base = rb_ca_strip_face_value(self);
510
+ CArray *base_ca;
511
+ TypedData_Get_Struct(base, CArray, &carray_data_type, base_ca);
512
+ cr = ca_refer_new(base_ca, data_type, ndim, dim, bytes, offset);
513
+ obj = ca_wrap_struct(cr);
514
+ rb_ca_set_parent(obj, base);
515
+ if ( ca->obj_type == CA_OBJ_RECORD
516
+ && rb_ca_data_class(self) == rtype ) {
517
+ return ca_face_lift(obj, self);
518
+ }
519
+ return rb_funcall(rb_const_get(rb_cObject, rb_intern("CARecord")),
520
+ rb_intern("wrap"), 2, obj, rtype);
521
+ }
446
522
  cr = ca_refer_new((CArray *) ca, data_type, ndim, dim, bytes, offset);
447
523
  obj = ca_wrap_struct(cr);
448
524
  rb_ca_set_parent(obj, self);
449
- /* When rtype is a data_class, wrap the result in CARecord so
450
- the data_class is carried even if self is not itself a Face. */
451
- if ( rb_obj_is_data_class(rtype) ) {
452
- obj = rb_funcall(rb_const_get(rb_cObject, rb_intern("CARecord")),
453
- rb_intern("wrap"), 2, obj, rtype);
454
- return obj;
455
- }
456
525
  }
457
526
  CA_WRAPPER_LIFT(obj, self, ca);
458
527
  return obj;
459
528
  }
460
529
 
530
+ static VALUE
531
+ rb_ca_refer (int argc, VALUE *argv, VALUE self)
532
+ {
533
+ volatile VALUE ropt = rb_pop_options(&argc, &argv);
534
+ return rb_ca_refer_kw(argc, argv, ropt, self);
535
+ }
536
+
461
537
  VALUE
462
538
  rb_ca_refer_new (VALUE self,
463
539
  int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
@@ -483,7 +559,7 @@ rb_ca_refer_new (VALUE self,
483
559
  rb_ary_store(list, 2, ropt);
484
560
 
485
561
  {
486
- volatile VALUE obj = rb_ca_refer(3, (VALUE *) RARRAY_CONST_PTR(list), self);
562
+ volatile VALUE obj = rb_ca_refer_kw(2, (VALUE *) RARRAY_CONST_PTR(list), ropt, self);
487
563
  CArray *co;
488
564
 
489
565
  /* CAREFUL: this is the internal builder -- some fifteen call sites want
@@ -535,6 +611,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
535
611
  CARefer *cr;
536
612
  ca_size_t new_dim[CA_RANK_MAX];
537
613
  ca_size_t prod = 1;
614
+ int overflow = 0, zero = 0;
538
615
  int placeholder_idx = -1; /* axis with `-1` or `:~` infer placeholder */
539
616
  int i;
540
617
  volatile VALUE obj;
@@ -542,9 +619,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
542
619
 
543
620
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
544
621
 
545
- if (argc < 0 || argc > CA_RANK_MAX) {
546
- rb_raise(rb_eArgError, "reshape: invalid number of dims (%d)", argc);
547
- }
622
+ ca_check_rank_fits(argc, "reshape");
548
623
 
549
624
  /* Locate the (at most one) auto-infer placeholder. `-1` is the
550
625
  conventional spelling; `:~` is the unified auto-fill sigil
@@ -553,7 +628,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
553
628
  if ( (FIXNUM_P(argv[i]) && FIX2LONG(argv[i]) == -1)
554
629
  || argv[i] == sym_tilde ) {
555
630
  if (placeholder_idx >= 0) {
556
- rb_raise(rb_eRuntimeError,
631
+ rb_raise(rb_eArgError,
557
632
  "reshape: only one auto-infer placeholder (-1 / :~) allowed");
558
633
  }
559
634
  placeholder_idx = i;
@@ -578,7 +653,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
578
653
  src = (i < ca->ndim) ? i : ca->ndim - (argc - i);
579
654
  }
580
655
  if (src < 0 || src >= ca->ndim) {
581
- rb_raise(rb_eRuntimeError,
656
+ rb_raise(rb_eArgError,
582
657
  "reshape: nil at axis %d has no source dim", i);
583
658
  }
584
659
  new_dim[i] = ca->dim[src];
@@ -586,13 +661,27 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
586
661
  else {
587
662
  new_dim[i] = NUM2SIZE(argv[i]);
588
663
  }
589
- prod *= new_dim[i];
664
+ /* A product too large to count cannot equal the element count; an
665
+ extent of zero anywhere makes it zero whatever it overflowed to. */
666
+ if ( __builtin_mul_overflow(prod, new_dim[i], &prod) ) {
667
+ overflow = 1;
668
+ }
669
+ if ( new_dim[i] == 0 ) {
670
+ zero = 1;
671
+ }
672
+ }
673
+ if ( zero ) {
674
+ prod = 0;
675
+ }
676
+ else if ( overflow ) {
677
+ rb_raise(rb_eArgError,
678
+ "reshape: the shape has more elements than an array can hold");
590
679
  }
591
680
 
592
681
  /* Resolve placeholder dim from the leftover total. */
593
682
  if (placeholder_idx >= 0) {
594
683
  if (prod == 0 || ca->elements % prod != 0) {
595
- rb_raise(rb_eRuntimeError,
684
+ rb_raise(rb_eArgError,
596
685
  "reshape: cannot infer dim for `-1` placeholder");
597
686
  }
598
687
  new_dim[placeholder_idx] = ca->elements / prod;
@@ -604,7 +693,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
604
693
  a subset), and on non-contiguous parents the compose-fold
605
694
  path corrupts data outright — hence the raise. */
606
695
  if (prod != ca->elements) {
607
- rb_raise(rb_eRuntimeError,
696
+ rb_raise(rb_eArgError,
608
697
  "reshape: cannot reshape array of %lld elements into a shape "
609
698
  "of %lld elements (use -1 / :~ to infer a dim)",
610
699
  (long long) ca->elements, (long long) prod);
@@ -627,6 +716,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
627
716
  ca->data_type, ca->bytes,
628
717
  (int8_t) argc, new_dim,
629
718
  out_strides, out_base);
719
+ ca_keep_chain_flags((CArray *) cs, ca);
630
720
  obj = ca_wrap_struct(cs);
631
721
  rb_ca_set_parent(obj, self);
632
722
  CA_WRAPPER_LIFT(obj, self, ca);
@@ -664,6 +754,7 @@ rb_ca_flatten (VALUE self)
664
754
  CAStride *cs = ca_stride_new(CA_OBJ_STRIDE, out_root,
665
755
  ca->data_type, ca->bytes,
666
756
  1, dim, out_strides, out_base);
757
+ ca_keep_chain_flags((CArray *) cs, ca);
667
758
  obj = ca_wrap_struct(cs);
668
759
  rb_ca_set_parent(obj, self);
669
760
  CA_WRAPPER_LIFT(obj, self, ca);
@@ -691,7 +782,7 @@ rb_ca_flatten (VALUE self)
691
782
  before axis 0 twice -> [1, 1, 2, 3]
692
783
 
693
784
  Returns a CARefer view (zero-copy alias to +self+'s data, via reshape).
694
- Bound to the internal name __insert_axis_size1__; the user-facing
785
+ Bound to the private method insert_size_one_axes; the user-facing
695
786
  insert_axis (with the repeat: keyword) is the Ruby method in
696
787
  lib/carray/basics.rb, which builds on this primitive.
697
788
 
@@ -711,11 +802,7 @@ rb_ca_insert_axis (int argc, VALUE *argv, VALUE self)
711
802
 
712
803
  ndim = (int) ca->ndim;
713
804
  new_ndim = ndim + argc;
714
- if (new_ndim > CA_RANK_MAX) {
715
- rb_raise(rb_eArgError,
716
- "insert_axis: resulting ndim %d exceeds CA_RANK_MAX %d",
717
- new_ndim, CA_RANK_MAX);
718
- }
805
+ ca_check_rank_fits(new_ndim, "insert_axis");
719
806
 
720
807
  ngap = ndim + 1; /* gaps live in [0, ndim] (ndim = the end gap) */
721
808
 
@@ -725,12 +812,7 @@ rb_ca_insert_axis (int argc, VALUE *argv, VALUE self)
725
812
  gap_count[i] = 0;
726
813
  }
727
814
  for (i = 0; i < argc; i++) {
728
- int raw = NUM2INT(argv[i]);
729
- int g = (raw < 0) ? raw + ngap : raw;
730
- if (g < 0 || g >= ngap) {
731
- rb_raise(rb_eArgError,
732
- "insert_axis: axis %d out of range for ndim %d", raw, ndim);
733
- }
815
+ int g = ca_normalize_axis_arg(argv[i], ngap, "insert_axis");
734
816
  gap_count[g]++;
735
817
  }
736
818
 
@@ -774,7 +856,7 @@ Init_ca_obj_refer (void)
774
856
  /* The bare size-1 primitive. The user-facing `insert_axis` (with its
775
857
  `repeat:` keyword) is the Ruby method in lib/carray/basics.rb, which
776
858
  owns the name and calls this primitive. */
777
- rb_define_method(rb_cCArray, "__insert_axis_size1__", rb_ca_insert_axis, -1);
859
+ rb_define_private_method(rb_cCArray, "insert_size_one_axes", rb_ca_insert_axis, -1);
778
860
  rb_define_alloc_func(rb_cCARefer, rb_ca_refer_s_allocate);
779
861
  rb_define_method(rb_cCARefer, "initialize_copy",
780
862
  rb_ca_refer_initialize_copy, 1);
data/ext/ca_obj_remap.c CHANGED
@@ -7,9 +7,9 @@
7
7
  Constraints:
8
8
  - ref.dim == idx.dim (same shape, same ndim, per-axis dim match)
9
9
  - idx.data_type == CA_SIZE (caller responsible)
10
- - No public constructor — there is no `CArray#remap(idx)` or
11
- `CARemap.new` surface; the class is only reachable via internal
12
- helpers and the `ca[idx]` same-shape indexer fast path.
10
+ - No public constructor — there is no `CArray#remap(idx)` surface; a
11
+ view is built by internal helpers and the `ca[idx]` same-shape
12
+ indexer fast path. `dup` / `clone` copy an existing one.
13
13
  - The CARemap Ruby class IS rb_define_class'd: visibility lets users
14
14
  see "this view came from a same-shape gather" when they inspect
15
15
  `.class`. CA_OBJ_REMAP integer remains unexported as a Ruby
@@ -18,6 +18,7 @@
18
18
  ---------------------------------------------------------------------------- */
19
19
 
20
20
  #include "carray.h"
21
+ #include "carray_internal.h"
21
22
 
22
23
  typedef struct {
23
24
  int16_t obj_type;
@@ -128,6 +129,12 @@ ca_remap_setup (CARemap *ca, CArray *ref, CArray *idx)
128
129
  {
129
130
  ca_remap_check_constraints(ref, idx);
130
131
 
132
+ /* ca == NULL asks for the checks above only, so that a constructor can
133
+ run them before it allocates. */
134
+ if ( ca == NULL ) {
135
+ return 0;
136
+ }
137
+
131
138
  ca->obj_type = CA_OBJ_REMAP;
132
139
  ca->data_type = ref->data_type;
133
140
  ca->flags = 0;
@@ -146,9 +153,6 @@ ca_remap_setup (CARemap *ca, CArray *ref, CArray *idx)
146
153
  ca->nosync = 0;
147
154
  ca->idx = idx;
148
155
 
149
- if ( ca_has_mask(ref) ) {
150
- ca_create_mask(ca);
151
- }
152
156
 
153
157
  if ( ca_is_scalar(ref) ) {
154
158
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -160,8 +164,11 @@ ca_remap_setup (CARemap *ca, CArray *ref, CArray *idx)
160
164
  CARemap *
161
165
  ca_remap_new (CArray *ref, CArray *idx)
162
166
  {
163
- CARemap *ca = (CARemap *) ca_array_alloc(CA_OBJ_REMAP, ref->ndim);
167
+ CARemap *ca;
168
+ ca_remap_setup(NULL, ref, idx);
169
+ ca = (CARemap *) ca_array_alloc(CA_OBJ_REMAP, ref->ndim);
164
170
  ca_remap_setup(ca, ref, idx);
171
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
165
172
  return ca;
166
173
  }
167
174
 
@@ -210,15 +217,13 @@ static void
210
217
  ca_remap_func_allocate (void *ap)
211
218
  {
212
219
  CARemap *ca = (CARemap *) ap;
213
- ca->ptr = xmalloc(ca_length(ca));
220
+ ca->ptr = ca_alloc_cells((CArray *) ca);
214
221
  }
215
222
 
216
223
  static void
217
224
  ca_remap_func_attach (void *ap)
218
225
  {
219
- CARemap *ca = (CARemap *) ap;
220
- ca->ptr = xmalloc(ca_length(ca));
221
- ca_remap_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
226
+ ca_axis_view_attach_owned(ap);
222
227
  }
223
228
 
224
229
  static void
@@ -265,10 +270,7 @@ static void
265
270
  ca_remap_func_create_mask (void *ap)
266
271
  {
267
272
  CARemap *ca = (CARemap *) ap;
268
- ca_update_mask(ca->parent);
269
- if ( ! ca->parent->mask ) {
270
- ca_create_mask(ca->parent);
271
- }
273
+ ca_create_mask(ca->parent);
272
274
  /* Mask is a CARemap over (parent->mask, idx) — same shape, boolean. */
273
275
  ca->mask = (CArray *) ca_remap_new(ca->parent->mask, ca->idx);
274
276
  }
@@ -282,7 +284,7 @@ ca_remap_func_create_mask (void *ap)
282
284
  2. ca_xfer_addrs(ca->idx, n, addrs, paddrs, GET) — one batched
283
285
  read of the parent flat addresses through ca->idx's own
284
286
  xfer_addrs dispatcher (entity, view, view chain — all
285
- transparent).
287
+ transparent), each address then checked against the parent.
286
288
  3. ca_xfer_addrs(ca->parent, n, paddrs, data, dir) — one batched
287
289
  gather/scatter of the user payload against parent.
288
290
 
@@ -295,13 +297,20 @@ ca_remap_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
295
297
  {
296
298
  CARemap *ca = (CARemap *) ap;
297
299
  ca_size_t *paddrs;
300
+ ca_size_t i;
298
301
  volatile VALUE holder;
299
302
 
300
303
  if ( n == 0 ) return;
301
304
 
302
305
  paddrs = ALLOCV_N(ca_size_t, holder, n);
303
- ca_xfer_addrs(ca->idx, n, addrs, paddrs, CA_XFER_GET);
304
- ca_xfer_addrs(ca->parent, n, paddrs, data, dir);
306
+ ca_xfer_addrs(ca->idx, n, addrs, paddrs, CA_XFER_GET);
307
+ /* idx is read live, so its values are checked here, not at
308
+ construction: negative counts from the end, out of range raises
309
+ before the parent is touched. */
310
+ for ( i = 0; i < n; i++ ) {
311
+ CA_CHECK_INDEX(paddrs[i], ca->parent->elements);
312
+ }
313
+ ca_xfer_addrs(ca->parent, n, paddrs, data, dir);
305
314
  ALLOCV_END(holder);
306
315
  }
307
316
 
@@ -329,6 +338,7 @@ static void
329
338
  ca_remap_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
330
339
  ca_size_t *strides, void *data, int dir)
331
340
  {
341
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
332
342
  CARemap *ca = (CARemap *) ap;
333
343
  int8_t ndim = ca->ndim;
334
344
  ca_size_t native[CA_RANK_MAX], idx[CA_RANK_MAX];
@@ -431,8 +441,9 @@ rb_ca_remap_new (VALUE cary, VALUE rmapper)
431
441
  }
432
442
 
433
443
  /* Read-only accessor for the per-cell index CArray that defines this
434
- CARemap's mapping. Returns the same CArray VALUE the caller passed
435
- to ca[mapper] (= shared reference, not a copy). Companion to
444
+ CARemap's mapping: the array the view reads. For ca[mapper] it is a
445
+ copy of mapper taken at the call, so a later change to mapper does
446
+ not reach the view. Companion to
436
447
  CABlock#start / CAStride#strides / CAWindow#count etc. — the view
437
448
  hierarchy is preserved so each named view class exposes its own
438
449
  defining semantic state. */
@@ -443,18 +454,68 @@ rb_ca_remap_mapper (VALUE self)
443
454
  }
444
455
 
445
456
 
457
+ /* `dup` / `clone`. CARemap has no allocator (Ruby cannot build one), so
458
+ Object#dup cannot copy it; these build the copy the way the indexer
459
+ does: a new view over the same parent and the same index array. */
460
+ static VALUE
461
+ rb_ca_remap_dup (VALUE self)
462
+ {
463
+ volatile VALUE rmapper = rb_ivar_get(self, rb_intern("remap_idx"));
464
+ if ( NIL_P(rmapper) ) {
465
+ /* The mask of a CARemap (it holds no index array of its own): another
466
+ remap over the same parent mask and index. The array it is the mask
467
+ of keeps both alive, so the copy holds that array too. */
468
+ volatile VALUE obj;
469
+ CArray *ca, *cp;
470
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
471
+ cp = (CArray *) ca_remap_func_clone(ca);
472
+ ca_keep_chain_flags(cp, ca);
473
+ obj = TypedData_Wrap_Struct(rb_obj_class(self), &caremap_data_type, cp);
474
+ rb_ivar_set(obj, rb_intern("masked_array"),
475
+ rb_ivar_get(self, rb_intern("masked_array")));
476
+ return obj;
477
+ }
478
+ return rb_ca_remap_new(rb_ca_parent(self), rmapper);
479
+ }
480
+
481
+ static VALUE
482
+ rb_ca_remap_clone (int argc, VALUE *argv, VALUE self)
483
+ {
484
+ VALUE opts = Qnil, vfreeze = Qnil;
485
+ volatile VALUE obj;
486
+ rb_scan_args(argc, argv, "0:", &opts);
487
+ if ( ! NIL_P(opts) ) {
488
+ /* rb_get_kwargs refuses any key but freeze:, as Kernel#clone does. */
489
+ ID kw[1];
490
+ VALUE val[1];
491
+ kw[0] = rb_intern("freeze");
492
+ rb_get_kwargs(opts, kw, 0, 1, val);
493
+ if ( val[0] != Qundef ) {
494
+ vfreeze = val[0];
495
+ }
496
+ }
497
+ obj = rb_ca_remap_dup(self);
498
+ if ( RTEST(vfreeze) || ( NIL_P(vfreeze) && OBJ_FROZEN(self) ) ) {
499
+ rb_obj_freeze(obj);
500
+ }
501
+ return obj;
502
+ }
503
+
446
504
  void
447
505
  Init_ca_obj_remap (void)
448
506
  {
449
507
  /* CARemap is a proper Ruby class so users can see "this view is a
450
- per-element gather" on .class. No allocator, no initialize, no
451
- `new` reachable from Ruby — construction is C-internal only.
452
- CA_OBJ_REMAP integer remains unexported (it's an internal type
453
- tag, not user-meaningful). */
508
+ per-element gather" on .class. A view is built from C only (the
509
+ indexer and sort / partition): there is no allocator, and `dup` /
510
+ `clone` are defined here instead of going through one. CA_OBJ_REMAP
511
+ integer remains unexported (it's an internal type tag, not
512
+ user-meaningful). */
454
513
  rb_cCARemap = rb_define_class("CARemap", rb_cCAView);
455
514
  rb_cCARemapMask = rb_define_class("CARemapMask", rb_cCARemap);
456
515
  rb_undef_alloc_func(rb_cCARemap);
457
516
  rb_undef_alloc_func(rb_cCARemapMask);
517
+ rb_define_method(rb_cCARemap, "dup", rb_ca_remap_dup, 0);
518
+ rb_define_method(rb_cCARemap, "clone", rb_ca_remap_clone, -1);
458
519
 
459
520
  ca_remap_func.struct_size = sizeof(CARemap);
460
521
  ca_remap_func.pool_bytes = ca_remap_pool_bytes;