carray 3.0.1 → 3.0.3

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
@@ -117,11 +117,11 @@ ca_monop_kernel_lookup (uint16_t op_id, int8_t in_data_type)
117
117
  /* op category predicates */
118
118
  /* ------------------------------------------------------------------- */
119
119
 
120
- /* True if op widens integer / boolean parent to CA_FLOAT64. False for
120
+ /* True if op widens an integer parent to CA_FLOAT64. False for
121
121
  preserve ops and cast ops. Widening ops are enumerated explicitly
122
122
  because they were added in multiple groups outside the original
123
123
  contiguous WIDENING_BEGIN..WIDENING_END range. */
124
- static int
124
+ int
125
125
  ca_monop_is_widening (uint16_t op_id)
126
126
  {
127
127
  if ( op_id >= CA_MONOP_WIDENING_BEGIN && op_id < CA_MONOP_WIDENING_END ) {
@@ -170,8 +170,8 @@ ca_lazy_promote_monop (uint16_t op_id, int8_t in_data_type)
170
170
  return (int8_t)(op_id - CA_MONOP_CAST_BASE);
171
171
  }
172
172
  if ( ca_monop_is_widening(op_id) ) {
173
- /* integer → f64, else preserve. Boolean (CA_BOOLEAN = 1) is also
174
- widened to f64 (existing eager behaviour via wrap_readonly). */
173
+ /* integer → f64, else preserve. A boolean parent never reaches a
174
+ widening op: the builder refuses it, as the eager monop does. */
175
175
  if ( in_data_type < CA_FLOAT32 ) return CA_FLOAT64;
176
176
  return in_data_type;
177
177
  }
@@ -194,6 +194,10 @@ ca_monop_func_t ca_monop_kernel_lookup (uint16_t op_id, int8_t in_data_type);
194
194
  /* Returns true iff op_id encodes a cast operation. */
195
195
  int ca_monop_is_cast (uint16_t op_id);
196
196
 
197
+ /* Returns true iff op_id widens an integer parent to CA_FLOAT64 (the
198
+ math functions: sqrt, sin, exp, ...). */
199
+ int ca_monop_is_widening (uint16_t op_id);
200
+
197
201
  /* Phase 6 P.6.3: returns true iff op_id is a "writable view" op
198
202
  (= cast or byte_swap). These ops:
199
203
  - support writable view lifecycle (CA_FLAG_READ_ONLY not set)
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
 
@@ -137,7 +138,6 @@ carray_setup_i (CArray *ca,
137
138
  CArray *mask, int allocate, int use_calloc, char *adopt_ptr)
138
139
  {
139
140
  ca_size_t elements;
140
- double length;
141
141
  int8_t i;
142
142
  ca_size_t k;
143
143
 
@@ -147,21 +147,7 @@ carray_setup_i (CArray *ca,
147
147
  CA_CHECK_DIM(ndim, dim);
148
148
  CA_CHECK_BYTES(data_type, bytes);
149
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
- }
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
- }
150
+ elements = ca_shape_elements(ndim, dim, bytes);
165
151
 
166
152
  /* An adopted buffer produces an owning entity (CA_OBJ_ARRAY), not a
167
153
  wrap: free_carray xfree()s ca->ptr, so the caller's buffer must be
@@ -173,6 +159,12 @@ carray_setup_i (CArray *ca,
173
159
  "cannot adopt a raw buffer as a CA_OBJECT array");
174
160
  }
175
161
 
162
+ /* ca == NULL asks for the checks above only, so that a constructor can
163
+ run them before it allocates. */
164
+ if ( ca == NULL ) {
165
+ return 0;
166
+ }
167
+
176
168
  /* set values to the struct members */
177
169
  if ( allocate || adopt_ptr ) {
178
170
  ca->obj_type = CA_OBJ_ARRAY;
@@ -274,7 +266,9 @@ CArray *
274
266
  carray_new (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
275
267
  CArray *mask)
276
268
  {
277
- CArray *ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
269
+ CArray *ca;
270
+ carray_setup(NULL, data_type, ndim, dim, bytes, mask);
271
+ ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
278
272
  carray_setup(ca, data_type, ndim, dim, bytes, mask);
279
273
  return ca;
280
274
  }
@@ -283,7 +277,9 @@ CArray *
283
277
  carray_new_safe (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
284
278
  CArray *mask)
285
279
  {
286
- CArray *ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
280
+ CArray *ca;
281
+ carray_safe_setup(NULL, data_type, ndim, dim, bytes, mask);
282
+ ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
287
283
  carray_safe_setup(ca, data_type, ndim, dim, bytes, mask);
288
284
  return ca;
289
285
  }
@@ -583,6 +579,8 @@ ca_fill_stride_buffer (char *dst, ca_size_t bytes, ca_size_t base, int8_t ndim,
583
579
  ca_size_t inner_count, inner_step;
584
580
  int8_t outer_ndim, k;
585
581
 
582
+ if ( ca_region_is_empty(ndim, counts) ) return;
583
+
586
584
  if ( ndim <= 0 ) {
587
585
  memcpy(dst + base * bytes, ptr, bytes);
588
586
  return;
@@ -825,26 +823,17 @@ rb_ca_s_allocate (VALUE klass)
825
823
  return TypedData_Make_Struct(klass, CArray, &carray_data_type, ca);
826
824
  }
827
825
 
828
- /* @overload initialize(data_type, dim, bytes=0) { ... }
826
+ /* Reads the (data_type, dim, bytes: nil) argument list that CArray.new
827
+ and CArray.__empty__ share. The two differ only in whether the buffer
828
+ is filled, so the rule for reading their arguments -- the optional
829
+ bytes for a fixlen, the refusal of a Class, the guess of the data type,
830
+ the demand that dim be an Array -- is written once here. */
829
831
 
830
- Constructs a new CArray object of <i>data_type</i>, which has the
831
- ndim and the dimensions specified by an <code>Array</code> of
832
- <code>Integer</code> or an argument list of <code>Integer</code>.
833
- The byte size of each element for the fixed length data type
834
- (<code>data_type == CA_FIXLEN</code>) is specified optional argument
835
- <i>bytes</i>. Otherwise, this optional argument has no
836
- effect. If the block is given, the new CArray
837
- object will be initialized by the value returned from the block.
838
- */
839
-
840
- static VALUE
841
- rb_ca_initialize (int argc, VALUE *argv, VALUE self)
832
+ static void
833
+ ca_scan_construct_args (int argc, VALUE *argv, int8_t *data_type,
834
+ ca_size_t *bytes, int8_t *ndim, ca_size_t *dim)
842
835
  {
843
836
  volatile VALUE rtype, rdim, ropt, rbytes = Qnil;
844
- CArray *ca;
845
- int8_t data_type, ndim;
846
- ca_size_t dim[CA_RANK_MAX];
847
- ca_size_t bytes;
848
837
  int8_t i;
849
838
 
850
839
  rb_scan_args(argc, argv, "21", (VALUE *)&rtype, (VALUE *) &rdim, (VALUE *) &ropt);
@@ -863,15 +852,43 @@ rb_ca_initialize (int argc, VALUE *argv, VALUE self)
863
852
  rtype, rtype, rtype);
864
853
  }
865
854
 
866
- rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
855
+ rb_ca_guess_type_and_bytes(rtype, rbytes, data_type, bytes);
867
856
 
868
857
  Check_Type(rdim, T_ARRAY);
869
- ndim = RARRAY_LEN(rdim);
870
- for (i=0; i<ndim; i++) {
858
+ CA_CHECK_RANK(RARRAY_LEN(rdim)); /* before dim[] is filled */
859
+ *ndim = RARRAY_LEN(rdim);
860
+ for (i=0; i<*ndim; i++) {
871
861
  dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
872
862
  }
863
+ }
864
+
865
+ /* @overload initialize(data_type, dim, bytes=0) { ... }
866
+
867
+ Constructs a new CArray object of <i>data_type</i>, which has the
868
+ ndim and the dimensions specified by an <code>Array</code> of
869
+ <code>Integer</code> or an argument list of <code>Integer</code>.
870
+ The byte size of each element for the fixed length data type
871
+ (<code>data_type == CA_FIXLEN</code>) is specified optional argument
872
+ <i>bytes</i>. Otherwise, this optional argument has no
873
+ effect. If the block is given, the new CArray
874
+ object will be initialized by the value returned from the block.
875
+ */
876
+
877
+ static VALUE
878
+ rb_ca_initialize (int argc, VALUE *argv, VALUE self)
879
+ {
880
+ CArray *ca;
881
+ int8_t data_type, ndim;
882
+ ca_size_t dim[CA_RANK_MAX];
883
+ ca_size_t bytes;
884
+
885
+ ca_scan_construct_args(argc, argv, &data_type, &bytes, &ndim, dim);
873
886
 
874
887
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
888
+ ca_check_uninitialized(ca);
889
+ /* Checks first: a rejected argument leaves the struct as allocated, so
890
+ it takes no pool and can be initialized again. */
891
+ carray_safe_setup(NULL, data_type, ndim, dim, bytes, NULL);
875
892
  if ( ca_func[CA_OBJ_ARRAY].pool_init ) {
876
893
  ca_array_pool_alloc(ca, CA_OBJ_ARRAY, ndim);
877
894
  }
@@ -898,10 +915,7 @@ rb_ca_initialize (int argc, VALUE *argv, VALUE self)
898
915
  else if ( ca->ndim > 0 ) {
899
916
  ca_size_t idx[CA_RANK_MAX];
900
917
  volatile VALUE ridx = rb_ary_new2(ca->ndim);
901
- ca_attach(ca);
902
918
  rb_ca_index_walk(self, ca, 0, idx, ridx, CA_LOOP_STORE);
903
- ca_sync(ca);
904
- ca_detach(ca);
905
919
  }
906
920
  else {
907
921
  /* 0-D safety net (rare from CArray.new path): yield no args. */
@@ -1095,6 +1109,7 @@ rb_ca_initialize_copy (VALUE self, VALUE other)
1095
1109
  rb_call_super(1, &other);
1096
1110
 
1097
1111
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1112
+ ca_check_uninitialized(ca);
1098
1113
  TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
1099
1114
 
1100
1115
  ca_update_mask(cs);
@@ -1103,11 +1118,112 @@ rb_ca_initialize_copy (VALUE self, VALUE other)
1103
1118
  }
1104
1119
  carray_setup(ca, cs->data_type, cs->ndim, cs->dim, cs->bytes, cs->mask);
1105
1120
 
1106
- memcpy(ca->ptr, cs->ptr, ca_length(cs));
1121
+ if ( cs->ptr ) {
1122
+ memcpy(ca->ptr, cs->ptr, ca_length(cs));
1123
+ }
1124
+ else {
1125
+ /* An entity cold at rest (a CAObject's mask, a source) is read
1126
+ through its slots. */
1127
+ ca_copy_data(cs, ca->ptr);
1128
+ }
1129
+
1130
+ return self;
1131
+ }
1107
1132
 
1133
+ /* dup and clone go through here before each class's initialize_copy. A
1134
+ view's copy is another view onto the same parent (Ruby's shallow copy),
1135
+ rebuilt by that class from the parent, so what the original was told
1136
+ about itself -- that it is a value array, read-only, a mask -- has to be
1137
+ carried across here, once for every class. An entity's copy owns new
1138
+ memory, so it is not a value array and its writability is its own, but
1139
+ a copy of a mask is still a mask (its class, CArrayMask, says so) and
1140
+ can no more hold a mask of its own than the original. */
1141
+ static void
1142
+ ca_dup_keep_state (VALUE self, VALUE other)
1143
+ {
1144
+ CArray *ca, *cs;
1145
+ if ( ! rb_obj_is_kind_of(other, rb_cCArray) ) {
1146
+ return;
1147
+ }
1148
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1149
+ TypedData_Get_Struct(other, CArray, &carray_data_type, cs);
1150
+ if ( ca_is_view(cs) ) {
1151
+ ca_keep_chain_flags(ca, cs);
1152
+ }
1153
+ else if ( ca_is_mask_array(cs) ) {
1154
+ ca_set_flag(ca, CA_FLAG_MASK_ARRAY);
1155
+ }
1156
+ }
1157
+
1158
+ static VALUE
1159
+ rb_ca_initialize_dup (VALUE self, VALUE other)
1160
+ {
1161
+ rb_call_super(1, &other);
1162
+ ca_dup_keep_state(self, other);
1163
+ return self;
1164
+ }
1165
+
1166
+ /* clone freezes its result without calling #freeze, so the read-only flag
1167
+ that CArray#freeze sets would be missing: the copy refuses writes as
1168
+ frozen but answers read_only? false. Set it here when the result is
1169
+ going to be frozen (freeze: true, or freeze: omitted and the original
1170
+ frozen). */
1171
+ static VALUE
1172
+ rb_ca_initialize_clone (int argc, VALUE *argv, VALUE self)
1173
+ {
1174
+ VALUE orig, opts, vfreeze = Qnil;
1175
+ int will_freeze;
1176
+
1177
+ rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);
1178
+ rb_scan_args(argc, argv, "1:", &orig, &opts);
1179
+ ca_dup_keep_state(self, orig);
1180
+
1181
+ if ( ! NIL_P(opts) ) {
1182
+ vfreeze = rb_hash_lookup2(opts, ID2SYM(rb_intern("freeze")), Qnil);
1183
+ }
1184
+ will_freeze = NIL_P(vfreeze) ? OBJ_FROZEN(orig) : RTEST(vfreeze);
1185
+ if ( will_freeze ) {
1186
+ CArray *ca;
1187
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1188
+ ca_set_flag(ca, CA_FLAG_READ_ONLY);
1189
+ }
1108
1190
  return self;
1109
1191
  }
1110
1192
 
1193
+ /* A wrap borrows memory it does not own. Object#dup would give the copy
1194
+ the wrap's class over memory the copy owns, so a subclass that names what
1195
+ it borrows (a libvips image's pixels) would name an array that borrows
1196
+ nothing. The copy is a plain CArray, as #copy is: the name goes with
1197
+ what is borrowed. */
1198
+ static VALUE
1199
+ rb_ca_wrap_dup (VALUE self)
1200
+ {
1201
+ return rb_ca_copy(self);
1202
+ }
1203
+
1204
+ static VALUE
1205
+ rb_ca_wrap_clone (int argc, VALUE *argv, VALUE self)
1206
+ {
1207
+ VALUE opt = Qnil, rfreeze = Qnil;
1208
+ volatile VALUE obj;
1209
+ rb_scan_args(argc, argv, "0:", &opt);
1210
+ if ( ! NIL_P(opt) ) {
1211
+ /* rb_get_kwargs refuses any key but freeze:, as Kernel#clone does. */
1212
+ ID kw[1];
1213
+ VALUE val[1];
1214
+ kw[0] = rb_intern("freeze");
1215
+ rb_get_kwargs(opt, kw, 0, 1, val);
1216
+ if ( val[0] != Qundef ) {
1217
+ rfreeze = val[0];
1218
+ }
1219
+ }
1220
+ obj = rb_ca_copy(self);
1221
+ if ( RTEST(rfreeze) || ( NIL_P(rfreeze) && OBJ_FROZEN(self) ) ) {
1222
+ rb_obj_freeze(obj);
1223
+ }
1224
+ return obj;
1225
+ }
1226
+
1111
1227
  /* @overload wrap (data_type, dim, bytes=0) { target }
1112
1228
 
1113
1229
  [TBD] (Construction)
@@ -1130,6 +1246,7 @@ rb_ca_s_wrap (int argc, VALUE *argv, VALUE self)
1130
1246
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
1131
1247
 
1132
1248
  Check_Type(rdim, T_ARRAY);
1249
+ CA_CHECK_RANK(RARRAY_LEN(rdim)); /* before dim[] is filled */
1133
1250
  ndim = RARRAY_LEN(rdim);
1134
1251
  for (i=0; i<ndim; i++) {
1135
1252
  dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
@@ -1198,6 +1315,7 @@ rb_cs_initialize (int argc, VALUE *argv, VALUE self)
1198
1315
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
1199
1316
 
1200
1317
  TypedData_Get_Struct(self, CScalar, &cscalar_data_type, ca);
1318
+ ca_check_uninitialized(ca);
1201
1319
  cscalar_setup(ca, data_type, bytes, NULL);
1202
1320
 
1203
1321
  if ( rb_block_given_p() ) {
@@ -1391,6 +1509,7 @@ rb_cs_initialize_copy (VALUE self, VALUE other)
1391
1509
  CScalar *ca, *cs;
1392
1510
 
1393
1511
  TypedData_Get_Struct(self, CScalar, &cscalar_data_type, ca);
1512
+ ca_check_uninitialized(ca);
1394
1513
  TypedData_Get_Struct(other, CScalar, &cscalar_data_type, cs);
1395
1514
 
1396
1515
  cscalar_setup(ca, cs->data_type, cs->bytes, NULL);
@@ -1433,11 +1552,39 @@ rb_ca_s_alloc_uninit (VALUE klass, VALUE rtype, VALUE rshape)
1433
1552
  int8_t i;
1434
1553
  rb_ca_guess_type_and_bytes(rtype, Qnil, &data_type, &bytes);
1435
1554
  Check_Type(rshape, T_ARRAY);
1555
+ CA_CHECK_RANK(RARRAY_LEN(rshape)); /* before dim[] is filled */
1436
1556
  ndim = (int8_t) RARRAY_LEN(rshape);
1437
1557
  for (i = 0; i < ndim; i++) dim[i] = NUM2SIZE(rb_ary_entry(rshape, i));
1438
1558
  return rb_carray_new(data_type, ndim, dim, bytes, NULL);
1439
1559
  }
1440
1560
 
1561
+ /* Internal primitive behind CArray.empty(data_type, dim, bytes: nil) in
1562
+ lib/carray/construct.rb, which also routes the compatibility spelling
1563
+ CArray.empty(*shape). It is CArray.new with the fill left out: the
1564
+ arguments are read by the same function, and the buffer comes from
1565
+ rb_carray_new (= no MEMZERO) rather than rb_carray_new_safe. A block
1566
+ is refused -- filling is what CArray.new is for. CA_OBJECT still
1567
+ falls through to the zero-VALUE init inside carray_setup_i (= required
1568
+ for GC), so any data_type is safe to ask for. */
1569
+
1570
+ static VALUE
1571
+ rb_ca_s_empty (int argc, VALUE *argv, VALUE klass)
1572
+ {
1573
+ int8_t data_type, ndim;
1574
+ ca_size_t dim[CA_RANK_MAX];
1575
+ ca_size_t bytes;
1576
+
1577
+ if ( rb_block_given_p() ) {
1578
+ rb_raise(rb_eArgError,
1579
+ "CArray.empty does not take a block "
1580
+ "(its contents are left undefined); use CArray.new to fill.");
1581
+ }
1582
+
1583
+ ca_scan_construct_args(argc, argv, &data_type, &bytes, &ndim, dim);
1584
+
1585
+ return rb_carray_new(data_type, ndim, dim, bytes, NULL);
1586
+ }
1587
+
1441
1588
  void
1442
1589
  Init_ca_obj_array (void)
1443
1590
  {
@@ -1449,6 +1596,7 @@ Init_ca_obj_array (void)
1449
1596
  rb_define_method(rb_cCArray, "initialize", rb_ca_initialize, -1);
1450
1597
  rb_define_singleton_method(rb_cCArray, "__alloc_uninit__",
1451
1598
  rb_ca_s_alloc_uninit, 2);
1599
+ rb_define_singleton_method(rb_cCArray, "__empty__", rb_ca_s_empty, -1);
1452
1600
 
1453
1601
  rb_define_singleton_method(rb_cCArray, "fixlen", rb_ca_s_fixlen, -1);
1454
1602
  rb_define_singleton_method(rb_cCArray, "boolean", rb_ca_s_boolean, -1);
@@ -1479,6 +1627,10 @@ Init_ca_obj_array (void)
1479
1627
  #endif
1480
1628
 
1481
1629
  rb_define_method(rb_cCArray, "initialize_copy", rb_ca_initialize_copy, 1);
1630
+ rb_define_method(rb_cCArray, "initialize_dup", rb_ca_initialize_dup, 1);
1631
+ rb_define_method(rb_cCArray, "initialize_clone", rb_ca_initialize_clone, -1);
1632
+ rb_define_method(rb_cCAWrap, "dup", rb_ca_wrap_dup, 0);
1633
+ rb_define_method(rb_cCAWrap, "clone", rb_ca_wrap_clone, -1);
1482
1634
  rb_define_singleton_method(rb_cCArray, "wrap", rb_ca_s_wrap, -1);
1483
1635
 
1484
1636
  /* ------------------------------------------------------------------- */