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_array.c CHANGED
@@ -9,6 +9,7 @@
9
9
  ---------------------------------------------------------------------------- */
10
10
 
11
11
  #include "carray.h"
12
+ #include "carray_internal.h"
12
13
 
13
14
  /* -------------------------------------------------------------------- */
14
15
 
@@ -60,7 +61,10 @@ const rb_data_type_t carray_data_type = {
60
61
  .dsize = ca_dsize,
61
62
  .dcompact = NULL
62
63
  },
63
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
64
+ /* A frozen entity is shared between Ractors: reading it writes nothing
65
+ to its struct (an entity takes no attach count), so each Ractor makes
66
+ its own views of it. */
67
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
64
68
  };
65
69
 
66
70
  const rb_data_type_t cawrap_data_type = {
@@ -84,7 +88,10 @@ const rb_data_type_t cscalar_data_type = {
84
88
  .dsize = ca_dsize,
85
89
  .dcompact = NULL
86
90
  },
87
- .flags = RUBY_TYPED_FREE_IMMEDIATELY
91
+ /* A frozen entity is shared between Ractors: reading it writes nothing
92
+ to its struct (an entity takes no attach count), so each Ractor makes
93
+ its own views of it. */
94
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE
88
95
  };
89
96
 
90
97
  const rb_data_type_t caview_data_type = {
@@ -137,31 +144,16 @@ carray_setup_i (CArray *ca,
137
144
  CArray *mask, int allocate, int use_calloc, char *adopt_ptr)
138
145
  {
139
146
  ca_size_t elements;
140
- double length;
141
147
  int8_t i;
142
148
  ca_size_t k;
143
149
 
144
150
  /* check arguments */
145
- CA_CHECK_DATA_TYPE(data_type);
146
- CA_CHECK_RANK(ndim);
147
- CA_CHECK_DIM(ndim, dim);
148
- CA_CHECK_BYTES(data_type, bytes);
149
-
150
- /* calculate total byte length using double to detect overflow */
151
- length = bytes;
152
- for (i=0; i<ndim; i++) {
153
- length *= dim[i];
154
- }
151
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
152
+ CA_CHECK_RANK_GIVEN(ndim);
153
+ CA_CHECK_DIM_GIVEN(ndim, dim);
154
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
155
155
 
156
- if ( length > CA_LENGTH_MAX ) {
157
- rb_raise(rb_eRuntimeError, "too large byte length");
158
- }
159
-
160
- /* calculate total number of elements (safe after length check above) */
161
- elements = 1;
162
- for (i=0; i<ndim; i++) {
163
- elements *= dim[i];
164
- }
156
+ elements = ca_shape_elements(ndim, dim, bytes);
165
157
 
166
158
  /* An adopted buffer produces an owning entity (CA_OBJ_ARRAY), not a
167
159
  wrap: free_carray xfree()s ca->ptr, so the caller's buffer must be
@@ -173,6 +165,12 @@ carray_setup_i (CArray *ca,
173
165
  "cannot adopt a raw buffer as a CA_OBJECT array");
174
166
  }
175
167
 
168
+ /* ca == NULL asks for the checks above only, so that a constructor can
169
+ run them before it allocates. */
170
+ if ( ca == NULL ) {
171
+ return 0;
172
+ }
173
+
176
174
  /* set values to the struct members */
177
175
  if ( allocate || adopt_ptr ) {
178
176
  ca->obj_type = CA_OBJ_ARRAY;
@@ -198,16 +196,14 @@ carray_setup_i (CArray *ca,
198
196
 
199
197
  /* allocate memory for entity */
200
198
  if ( use_calloc ) {
201
- /* ca->ptr = ALLOC_N(char, elements * bytes); */
202
- ca->ptr = xmalloc(elements * bytes);
199
+ ca->ptr = xmalloc(elements * bytes); /* cells: set to 0 below */
203
200
  MEMZERO(ca->ptr, char, elements * bytes);
204
201
  }
205
202
  else {
206
- /* ca->ptr = ALLOC_N(char, elements * bytes); */
207
- ca->ptr = xmalloc(elements * bytes);
203
+ ca->ptr = xmalloc(elements * bytes); /* cells: set to 0 below */
208
204
  }
209
205
 
210
- /* initialize elements with Qnil for CA_OBJECT data_type */
206
+ /* an object array starts with every cell 0 */
211
207
  if ( allocate && data_type == CA_OBJECT ) {
212
208
  volatile VALUE zero = SIZE2NUM(0);
213
209
  VALUE *p = (VALUE *) ca->ptr;
@@ -223,6 +219,7 @@ carray_setup_i (CArray *ca,
223
219
 
224
220
  ca->mask = NULL;
225
221
  if ( mask ) {
222
+ /* mask: only initialize_copy passes one, on a struct Ruby owns */
226
223
  ca_setup_mask(ca, mask);
227
224
  }
228
225
 
@@ -251,9 +248,12 @@ ca_wrap_setup (CArray *ca,
251
248
  int ret;
252
249
 
253
250
  ret = carray_setup_i(ca, data_type, ndim, dim, bytes, mask, 0, 0, NULL);
254
- if ( (!ptr) && (ca->elements != 0) ) {
251
+ if ( (!ptr) && ca_shape_elements(ndim, dim, bytes) != 0 ) {
255
252
  rb_raise(rb_eRuntimeError, "wrapping NULL pointer with an non-empty array");
256
253
  }
254
+ if ( ca == NULL ) { /* checks only */
255
+ return ret;
256
+ }
257
257
  ca->ptr = ptr;
258
258
  return ret;
259
259
  }
@@ -266,26 +266,55 @@ ca_wrap_setup_null (CArray *ca,
266
266
  int ret;
267
267
 
268
268
  ret = carray_setup_i(ca, data_type, ndim, dim, bytes, mask, 0, 0, NULL);
269
- ca->ptr = NULL;
269
+ if ( ca != NULL ) {
270
+ ca->ptr = NULL;
271
+ }
270
272
  return ret;
271
273
  }
272
274
 
275
+ static VALUE
276
+ carray_new_copy_mask (VALUE arg)
277
+ {
278
+ void **a = (void **) arg;
279
+ ca_setup_mask((CArray *) a[0], (CArray *) a[1]);
280
+ return Qnil;
281
+ }
282
+
283
+ /* Reading the mask to copy can call Ruby (a CAObject's mask hooks) and
284
+ raise, while the new array belongs to no Ruby object yet. The array is
285
+ built without it, and the mask is copied in under ca_fill_or_free. */
286
+ static CArray *
287
+ carray_new_with_mask (CArray *ca, CArray *mask)
288
+ {
289
+ if ( mask ) {
290
+ void *a[2];
291
+ a[0] = ca;
292
+ a[1] = mask;
293
+ ca_fill_or_free(ca, carray_new_copy_mask, (VALUE) a);
294
+ }
295
+ return ca;
296
+ }
297
+
273
298
  CArray *
274
299
  carray_new (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
275
300
  CArray *mask)
276
301
  {
277
- CArray *ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
278
- carray_setup(ca, data_type, ndim, dim, bytes, mask);
279
- return ca;
302
+ CArray *ca;
303
+ carray_setup(NULL, data_type, ndim, dim, bytes, NULL);
304
+ ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
305
+ carray_setup(ca, data_type, ndim, dim, bytes, NULL);
306
+ return carray_new_with_mask(ca, mask);
280
307
  }
281
308
 
282
309
  CArray *
283
310
  carray_new_safe (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
284
311
  CArray *mask)
285
312
  {
286
- CArray *ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
287
- carray_safe_setup(ca, data_type, ndim, dim, bytes, mask);
288
- return ca;
313
+ CArray *ca;
314
+ carray_safe_setup(NULL, data_type, ndim, dim, bytes, NULL);
315
+ ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
316
+ carray_safe_setup(ca, data_type, ndim, dim, bytes, NULL);
317
+ return carray_new_with_mask(ca, mask);
289
318
  }
290
319
 
291
320
  /* Create an entity that adopts a caller-provided data buffer instead of
@@ -301,6 +330,7 @@ carray_new_adopt (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes
301
330
  if ( ! ptr ) {
302
331
  rb_raise(rb_eRuntimeError, "carray_new_adopt: NULL data pointer");
303
332
  }
333
+ carray_setup_i(NULL, data_type, ndim, dim, bytes, NULL, 0, 0, ptr);
304
334
  ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
305
335
  carray_setup_i(ca, data_type, ndim, dim, bytes, NULL, 0, 0, ptr);
306
336
  return ca;
@@ -310,18 +340,22 @@ CAWrap *
310
340
  ca_wrap_new (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
311
341
  CArray *mask, char *ptr)
312
342
  {
313
- CAWrap *ca = (CAWrap *) ca_array_alloc(CA_OBJ_ARRAY_WRAP, ndim);
314
- ca_wrap_setup(ca, data_type, ndim, dim, bytes, mask, ptr);
315
- return ca;
343
+ CAWrap *ca;
344
+ ca_wrap_setup(NULL, data_type, ndim, dim, bytes, NULL, ptr);
345
+ ca = (CAWrap *) ca_array_alloc(CA_OBJ_ARRAY_WRAP, ndim);
346
+ ca_wrap_setup(ca, data_type, ndim, dim, bytes, NULL, ptr);
347
+ return (CAWrap *) carray_new_with_mask((CArray *) ca, mask);
316
348
  }
317
349
 
318
350
  CAWrap *
319
351
  ca_wrap_new_null (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
320
352
  CArray *mask)
321
353
  {
322
- CAWrap *ca = (CAWrap *) ca_array_alloc(CA_OBJ_ARRAY_WRAP, ndim);
323
- ca_wrap_setup_null(ca, data_type, ndim, dim, bytes, mask);
324
- return ca;
354
+ CAWrap *ca;
355
+ ca_wrap_setup_null(NULL, data_type, ndim, dim, bytes, NULL);
356
+ ca = (CAWrap *) ca_array_alloc(CA_OBJ_ARRAY_WRAP, ndim);
357
+ ca_wrap_setup_null(ca, data_type, ndim, dim, bytes, NULL);
358
+ return (CAWrap *) carray_new_with_mask((CArray *) ca, mask);
325
359
  }
326
360
 
327
361
  void
@@ -364,8 +398,14 @@ static int
364
398
  cscalar_setup (CScalar *ca,
365
399
  int8_t data_type, ca_size_t bytes, CArray *mask)
366
400
  {
367
- CA_CHECK_DATA_TYPE(data_type);
368
- CA_CHECK_BYTES(data_type, bytes);
401
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
402
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
403
+
404
+ /* ca == NULL asks for the checks above only, so that a constructor can
405
+ run them before it allocates. */
406
+ if ( ca == NULL ) {
407
+ return 0;
408
+ }
369
409
 
370
410
  ca->obj_type = CA_OBJ_SCALAR;
371
411
  ca->data_type = data_type;
@@ -374,7 +414,7 @@ cscalar_setup (CScalar *ca,
374
414
  ca->bytes = bytes;
375
415
  ca->elements = 1;
376
416
  ca->dim = &(ca->_dim);
377
- ca->ptr = xmalloc(bytes);
417
+ ca->ptr = xmalloc(bytes); /* cells: the one cell is set to 0 below */
378
418
  ca->mask = NULL;
379
419
 
380
420
  ca->dim[0] = 1;
@@ -387,6 +427,7 @@ cscalar_setup (CScalar *ca,
387
427
  }
388
428
 
389
429
  if ( mask ) {
430
+ /* mask: the constructors pass none (carray_new_with_mask copies it) */
390
431
  ca_setup_mask((CArray *)ca, mask);
391
432
  }
392
433
 
@@ -402,9 +443,11 @@ cscalar_setup (CScalar *ca,
402
443
  CScalar *
403
444
  cscalar_new (int8_t data_type, ca_size_t bytes, CArray *mask)
404
445
  {
405
- CScalar *ca = ALLOC(CScalar);
406
- cscalar_setup(ca, data_type, bytes, mask);
407
- return ca;
446
+ CScalar *ca;
447
+ cscalar_setup(NULL, data_type, bytes, NULL);
448
+ ca = ALLOC(CScalar);
449
+ cscalar_setup(ca, data_type, bytes, NULL);
450
+ return (CScalar *) carray_new_with_mask((CArray *) ca, mask);
408
451
  }
409
452
 
410
453
  /*
@@ -414,7 +457,9 @@ cscalar_new (int8_t data_type, ca_size_t bytes, CArray *mask)
414
457
  CScalar *
415
458
  cscalar_new2 (int8_t data_type, ca_size_t bytes, char *val)
416
459
  {
417
- CScalar *ca = ALLOC(CScalar);
460
+ CScalar *ca;
461
+ cscalar_setup(NULL, data_type, bytes, NULL);
462
+ ca = ALLOC(CScalar);
418
463
  cscalar_setup(ca, data_type, bytes, NULL);
419
464
  memcpy(ca->ptr, val, ca->bytes);
420
465
  return ca;
@@ -583,6 +628,8 @@ ca_fill_stride_buffer (char *dst, ca_size_t bytes, ca_size_t base, int8_t ndim,
583
628
  ca_size_t inner_count, inner_step;
584
629
  int8_t outer_ndim, k;
585
630
 
631
+ if ( ca_region_is_empty(ndim, counts) ) return;
632
+
586
633
  if ( ndim <= 0 ) {
587
634
  memcpy(dst + base * bytes, ptr, bytes);
588
635
  return;
@@ -593,6 +640,7 @@ ca_fill_stride_buffer (char *dst, ca_size_t bytes, ca_size_t base, int8_t ndim,
593
640
  outer_ndim = ndim - 1;
594
641
 
595
642
  for ( k = 0; k < outer_ndim; k++ ) idx[k] = 0;
643
+ /* empty: the function returns on an empty region at its entry */
596
644
  while ( 1 ) {
597
645
  ca_size_t addr = base;
598
646
  char *p;
@@ -826,7 +874,7 @@ rb_ca_s_allocate (VALUE klass)
826
874
  }
827
875
 
828
876
  /* Reads the (data_type, dim, bytes: nil) argument list that CArray.new
829
- and CArray.__empty__ share. The two differ only in whether the buffer
877
+ and CArray.empty_of_data_type share. The two differ only in whether the buffer
830
878
  is filled, so the rule for reading their arguments -- the optional
831
879
  bytes for a fixlen, the refusal of a Class, the guess of the data type,
832
880
  the demand that dim be an Array -- is written once here. */
@@ -857,6 +905,7 @@ ca_scan_construct_args (int argc, VALUE *argv, int8_t *data_type,
857
905
  rb_ca_guess_type_and_bytes(rtype, rbytes, data_type, bytes);
858
906
 
859
907
  Check_Type(rdim, T_ARRAY);
908
+ CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
860
909
  *ndim = RARRAY_LEN(rdim);
861
910
  for (i=0; i<*ndim; i++) {
862
911
  dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
@@ -886,6 +935,10 @@ rb_ca_initialize (int argc, VALUE *argv, VALUE self)
886
935
  ca_scan_construct_args(argc, argv, &data_type, &bytes, &ndim, dim);
887
936
 
888
937
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
938
+ ca_check_uninitialized(ca);
939
+ /* Checks first: a rejected argument leaves the struct as allocated, so
940
+ it takes no pool and can be initialized again. */
941
+ carray_safe_setup(NULL, data_type, ndim, dim, bytes, NULL);
889
942
  if ( ca_func[CA_OBJ_ARRAY].pool_init ) {
890
943
  ca_array_pool_alloc(ca, CA_OBJ_ARRAY, ndim);
891
944
  }
@@ -904,18 +957,20 @@ rb_ca_initialize (int argc, VALUE *argv, VALUE self)
904
957
  with the multi-dimensional subscript yielded as individual
905
958
  integer arguments, so |i|, |i,j|, |i,j,k| all work uniformly
906
959
  across ranks. Block forms that want the whole subscript as
907
- an Array should write |*idx|. */
908
- if ( rb_proc_arity(rb_block_proc()) == 0 ) {
960
+ an Array should write |*idx|.
961
+ An array of no cells calls neither, as Array.new(0) { ... } does
962
+ not. */
963
+ if ( ca->elements == 0 ) {
964
+ ;
965
+ }
966
+ else if ( rb_proc_arity(rb_block_proc()) == 0 ) {
909
967
  volatile VALUE rval = rb_yield_values2(0, NULL);
910
968
  rb_ca_store_all(self, rval);
911
969
  }
912
970
  else if ( ca->ndim > 0 ) {
913
971
  ca_size_t idx[CA_RANK_MAX];
914
972
  volatile VALUE ridx = rb_ary_new2(ca->ndim);
915
- ca_attach(ca);
916
973
  rb_ca_index_walk(self, ca, 0, idx, ridx, CA_LOOP_STORE);
917
- ca_sync(ca);
918
- ca_detach(ca);
919
974
  }
920
975
  else {
921
976
  /* 0-D safety net (rare from CArray.new path): yield no args. */
@@ -1109,6 +1164,7 @@ rb_ca_initialize_copy (VALUE self, VALUE other)
1109
1164
  rb_call_super(1, &other);
1110
1165
 
1111
1166
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1167
+ ca_check_uninitialized(ca);
1112
1168
  TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
1113
1169
 
1114
1170
  ca_update_mask(cs);
@@ -1117,11 +1173,114 @@ rb_ca_initialize_copy (VALUE self, VALUE other)
1117
1173
  }
1118
1174
  carray_setup(ca, cs->data_type, cs->ndim, cs->dim, cs->bytes, cs->mask);
1119
1175
 
1120
- memcpy(ca->ptr, cs->ptr, ca_length(cs));
1176
+ if ( cs->ptr ) {
1177
+ memcpy(ca->ptr, cs->ptr, ca_length(cs));
1178
+ }
1179
+ else {
1180
+ /* An entity cold at rest (a CAObject's mask, a source) is read
1181
+ through its slots. */
1182
+ ca_copy_data(cs, ca->ptr);
1183
+ }
1184
+
1185
+ return self;
1186
+ }
1187
+
1188
+ /* dup and clone go through here before each class's initialize_copy. A
1189
+ view's copy is another view onto the same parent (Ruby's shallow copy),
1190
+ rebuilt by that class from the parent, so what the original was told
1191
+ about itself -- that it is a value array, read-only, a mask -- has to be
1192
+ carried across here, once for every class. An entity's copy owns new
1193
+ memory, so it is not a value array and its writability is its own, but
1194
+ a copy of a mask is still a mask (its class, CArrayMask, says so) and
1195
+ can no more hold a mask of its own than the original. */
1196
+ static void
1197
+ ca_dup_keep_state (VALUE self, VALUE other)
1198
+ {
1199
+ CArray *ca, *cs;
1200
+ if ( ! rb_obj_is_kind_of(other, rb_cCArray) ) {
1201
+ return;
1202
+ }
1203
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1204
+ TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
1205
+ if ( ca_is_view(cs) ) {
1206
+ ca_keep_chain_flags(ca, cs);
1207
+ }
1208
+ else if ( ca_is_mask_array(cs) ) {
1209
+ ca_set_flag(ca, CA_FLAG_MASK_ARRAY);
1210
+ }
1211
+ }
1121
1212
 
1213
+ static VALUE
1214
+ rb_ca_initialize_dup (VALUE self, VALUE other)
1215
+ {
1216
+ rb_call_super(1, &other);
1217
+ ca_dup_keep_state(self, other);
1218
+ rb_ca_own_attr(self);
1122
1219
  return self;
1123
1220
  }
1124
1221
 
1222
+ /* clone freezes its result without calling #freeze, so the read-only flag
1223
+ that CArray#freeze sets would be missing: the copy refuses writes as
1224
+ frozen but answers read_only? false. Set it here when the result is
1225
+ going to be frozen (freeze: true, or freeze: omitted and the original
1226
+ frozen). */
1227
+ static VALUE
1228
+ rb_ca_initialize_clone (int argc, VALUE *argv, VALUE self)
1229
+ {
1230
+ VALUE orig, opts, vfreeze = Qnil;
1231
+ int will_freeze;
1232
+
1233
+ rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1234
+ rb_scan_args(argc, argv, "1:", &orig, &opts);
1235
+ ca_dup_keep_state(self, orig);
1236
+ rb_ca_own_attr(self);
1237
+
1238
+ if ( ! NIL_P(opts) ) {
1239
+ vfreeze = rb_hash_lookup2(opts, ID2SYM(rb_intern("freeze")), Qnil);
1240
+ }
1241
+ will_freeze = NIL_P(vfreeze) ? OBJ_FROZEN(orig) : RTEST(vfreeze);
1242
+ if ( will_freeze ) {
1243
+ CArray *ca;
1244
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1245
+ ca_set_flag(ca, CA_FLAG_READ_ONLY);
1246
+ }
1247
+ return self;
1248
+ }
1249
+
1250
+ /* A wrap borrows memory it does not own. Object#dup would give the copy
1251
+ the wrap's class over memory the copy owns, so a subclass that names what
1252
+ it borrows (a libvips image's pixels) would name an array that borrows
1253
+ nothing. The copy is a plain CArray, as #copy is: the name goes with
1254
+ what is borrowed. */
1255
+ static VALUE
1256
+ rb_ca_wrap_dup (VALUE self)
1257
+ {
1258
+ return rb_ca_copy(self);
1259
+ }
1260
+
1261
+ static VALUE
1262
+ rb_ca_wrap_clone (int argc, VALUE *argv, VALUE self)
1263
+ {
1264
+ VALUE opt = Qnil, rfreeze = Qnil;
1265
+ volatile VALUE obj;
1266
+ rb_scan_args(argc, argv, "0:", &opt);
1267
+ if ( ! NIL_P(opt) ) {
1268
+ /* rb_get_kwargs refuses any key but freeze:, as Kernel#clone does. */
1269
+ ID kw[1];
1270
+ VALUE val[1];
1271
+ kw[0] = rb_intern("freeze");
1272
+ rb_get_kwargs(opt, kw, 0, 1, val);
1273
+ if ( val[0] != Qundef ) {
1274
+ rfreeze = val[0];
1275
+ }
1276
+ }
1277
+ obj = rb_ca_copy(self);
1278
+ if ( RTEST(rfreeze) || ( NIL_P(rfreeze) && OBJ_FROZEN(self) ) ) {
1279
+ rb_obj_freeze(obj);
1280
+ }
1281
+ return obj;
1282
+ }
1283
+
1125
1284
  /* @overload wrap (data_type, dim, bytes=0) { target }
1126
1285
 
1127
1286
  [TBD] (Construction)
@@ -1144,6 +1303,7 @@ rb_ca_s_wrap (int argc, VALUE *argv, VALUE self)
1144
1303
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
1145
1304
 
1146
1305
  Check_Type(rdim, T_ARRAY);
1306
+ CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
1147
1307
  ndim = RARRAY_LEN(rdim);
1148
1308
  for (i=0; i<ndim; i++) {
1149
1309
  dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
@@ -1212,6 +1372,7 @@ rb_cs_initialize (int argc, VALUE *argv, VALUE self)
1212
1372
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
1213
1373
 
1214
1374
  TypedData_Get_Struct(self, CScalar, &cscalar_data_type, ca);
1375
+ ca_check_uninitialized(ca);
1215
1376
  cscalar_setup(ca, data_type, bytes, NULL);
1216
1377
 
1217
1378
  if ( rb_block_given_p() ) {
@@ -1405,6 +1566,7 @@ rb_cs_initialize_copy (VALUE self, VALUE other)
1405
1566
  CScalar *ca, *cs;
1406
1567
 
1407
1568
  TypedData_Get_Struct(self, CScalar, &cscalar_data_type, ca);
1569
+ ca_check_uninitialized(ca);
1408
1570
  TypedData_Get_Struct(other, CScalar, &cscalar_data_type, cs);
1409
1571
 
1410
1572
  cscalar_setup(ca, cs->data_type, cs->bytes, NULL);
@@ -1447,6 +1609,7 @@ rb_ca_s_alloc_uninit (VALUE klass, VALUE rtype, VALUE rshape)
1447
1609
  int8_t i;
1448
1610
  rb_ca_guess_type_and_bytes(rtype, Qnil, &data_type, &bytes);
1449
1611
  Check_Type(rshape, T_ARRAY);
1612
+ CA_CHECK_RANK_GIVEN(RARRAY_LEN(rshape)); /* before dim[] is filled */
1450
1613
  ndim = (int8_t) RARRAY_LEN(rshape);
1451
1614
  for (i = 0; i < ndim; i++) dim[i] = NUM2SIZE(rb_ary_entry(rshape, i));
1452
1615
  return rb_carray_new(data_type, ndim, dim, bytes, NULL);
@@ -1490,7 +1653,7 @@ Init_ca_obj_array (void)
1490
1653
  rb_define_method(rb_cCArray, "initialize", rb_ca_initialize, -1);
1491
1654
  rb_define_singleton_method(rb_cCArray, "__alloc_uninit__",
1492
1655
  rb_ca_s_alloc_uninit, 2);
1493
- rb_define_singleton_method(rb_cCArray, "__empty__", rb_ca_s_empty, -1);
1656
+ rb_define_private_method(rb_singleton_class(rb_cCArray), "empty_of_data_type", rb_ca_s_empty, -1);
1494
1657
 
1495
1658
  rb_define_singleton_method(rb_cCArray, "fixlen", rb_ca_s_fixlen, -1);
1496
1659
  rb_define_singleton_method(rb_cCArray, "boolean", rb_ca_s_boolean, -1);
@@ -1521,6 +1684,10 @@ Init_ca_obj_array (void)
1521
1684
  #endif
1522
1685
 
1523
1686
  rb_define_method(rb_cCArray, "initialize_copy", rb_ca_initialize_copy, 1);
1687
+ rb_define_method(rb_cCArray, "initialize_dup", rb_ca_initialize_dup, 1);
1688
+ rb_define_method(rb_cCArray, "initialize_clone", rb_ca_initialize_clone, -1);
1689
+ rb_define_method(rb_cCAWrap, "dup", rb_ca_wrap_dup, 0);
1690
+ rb_define_method(rb_cCAWrap, "clone", rb_ca_wrap_clone, -1);
1524
1691
  rb_define_singleton_method(rb_cCArray, "wrap", rb_ca_s_wrap, -1);
1525
1692
 
1526
1693
  /* ------------------------------------------------------------------- */