carray 3.0.3 → 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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_record.c CHANGED
@@ -100,6 +100,12 @@ ca_record_setup (CARecord *ca, CArray *parent, VALUE data_class)
100
100
  parent->data_type);
101
101
  }
102
102
 
103
+ /* ca == NULL asks for the checks above only, so that a constructor can
104
+ run them before it allocates. */
105
+ if ( ca == NULL ) {
106
+ return 0;
107
+ }
108
+
103
109
  ca->obj_type = CA_OBJ_RECORD;
104
110
  ca->data_type = CA_FIXLEN;
105
111
  ca->flags = CA_FLAG_IS_FACE;
@@ -119,9 +125,6 @@ ca_record_setup (CARecord *ca, CArray *parent, VALUE data_class)
119
125
 
120
126
  ca->data_class = data_class;
121
127
 
122
- if ( ca_has_mask(parent) ) {
123
- ca_create_mask((CArray *) ca);
124
- }
125
128
 
126
129
  if ( ca_is_scalar(parent) ) {
127
130
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -137,8 +140,11 @@ ca_record_setup (CARecord *ca, CArray *parent, VALUE data_class)
137
140
  CARecord *
138
141
  ca_record_new (CArray *parent, VALUE data_class)
139
142
  {
140
- CARecord *ca = (CARecord *) ca_array_alloc(CA_OBJ_RECORD, parent->ndim);
143
+ CARecord *ca;
144
+ ca_record_setup(NULL, parent, data_class);
145
+ ca = (CARecord *) ca_array_alloc(CA_OBJ_RECORD, parent->ndim);
141
146
  ca_record_setup(ca, parent, data_class);
147
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
142
148
  return ca;
143
149
  }
144
150
 
@@ -270,9 +276,7 @@ rb_ca_record_s_new (int argc, VALUE *argv, VALUE klass)
270
276
  shape_offset = 1;
271
277
  }
272
278
  ndim = argc - shape_offset;
273
- if ( ndim < 0 || ndim > CA_RANK_MAX ) {
274
- rb_raise(rb_eArgError, "invalid number of shape arguments (%d)", ndim);
275
- }
279
+ ca_check_rank_fits(ndim, NULL);
276
280
  for ( i = 0; i < ndim; i++ ) {
277
281
  dim[i] = NUM2SIZE(argv[shape_offset + i]);
278
282
  }
@@ -362,6 +366,7 @@ rb_ca_record_initialize_copy (VALUE self, VALUE other)
362
366
  ca_array_pool_alloc(ca, CA_OBJ_RECORD, cs->parent->ndim);
363
367
  }
364
368
  ca_record_setup(ca, cs->parent, cs->data_class);
369
+ ca_view_inherit_mask((VALUE) ca);
365
370
  /* Marshal loads into an empty instance through here without copying
366
371
  ivars, so the parent pin is set from `other`, not inherited. */
367
372
  rb_ca_set_parent(self, rb_ca_parent(other));
data/ext/ca_obj_reduce.c CHANGED
@@ -56,6 +56,12 @@ ca_reduce_setup (CAReduce *ca, CArray *parent, ca_size_t count, ca_size_t offset
56
56
  "[BUG] CAReduce can't inherit other than boolean array");
57
57
  }
58
58
 
59
+ /* ca == NULL asks for the checks above only, so that a constructor can
60
+ run them before it allocates. */
61
+ if ( ca == NULL ) {
62
+ return 0;
63
+ }
64
+
59
65
  elements = parent->elements / count;
60
66
 
61
67
  ca->obj_type = CA_OBJ_REDUCE;
@@ -75,9 +81,6 @@ ca_reduce_setup (CAReduce *ca, CArray *parent, ca_size_t count, ca_size_t offset
75
81
  ca->count = count;
76
82
  ca->offset = offset;
77
83
 
78
- if ( ca_has_mask(parent) ) {
79
- ca_create_mask(ca);
80
- }
81
84
 
82
85
  if ( ca_is_scalar(parent) ) {
83
86
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -89,8 +92,11 @@ ca_reduce_setup (CAReduce *ca, CArray *parent, ca_size_t count, ca_size_t offset
89
92
  CAReduce *
90
93
  ca_reduce_new (CArray *parent, ca_size_t count, ca_size_t offset)
91
94
  {
92
- CAReduce *ca = ALLOC(CAReduce);
95
+ CAReduce *ca;
96
+ ca_reduce_setup(NULL, parent, count, offset);
97
+ ca = ALLOC(CAReduce);
93
98
  ca_reduce_setup(ca, parent, count, offset);
99
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
94
100
  return ca;
95
101
  }
96
102
 
@@ -193,8 +199,7 @@ ca_reduce_func_allocate (void *ap)
193
199
  {
194
200
  CAReduce *ca = (CAReduce *) ap;
195
201
  ca_attach(ca->parent);
196
- /* ca->ptr = ALLOC_N(char, ca->elements); */
197
- ca->ptr = xmalloc(ca_length(ca));
202
+ ca->ptr = ca_alloc_cells((CArray *) ca);
198
203
  }
199
204
 
200
205
  static void
@@ -204,8 +209,7 @@ ca_reduce_func_attach (void *ap)
204
209
  char *p;
205
210
  ca_size_t i;
206
211
  ca_attach(ca->parent);
207
- /* ca->ptr = ALLOC_N(char, ca->elements); */
208
- ca->ptr = xmalloc(ca_length(ca));
212
+ ca->ptr = ca_alloc_cells((CArray *) ca);
209
213
  p = ca->ptr;
210
214
  for (i=0; i<ca->elements; i++) {
211
215
  ca_reduce_func_xfer_addrs(ca, 1, &i, p, CA_XFER_GET);
@@ -314,6 +318,7 @@ rb_ca_reduce_initialize_copy (VALUE self, VALUE other)
314
318
  TypedData_Get_Struct(other, CAReduce, &careduce_data_type, cs);
315
319
 
316
320
  ca_reduce_setup(ca, cs->parent, cs->count, cs->offset);
321
+ ca_view_inherit_mask((VALUE) ca);
317
322
 
318
323
  return self;
319
324
  }
data/ext/ca_obj_refer.c CHANGED
@@ -74,10 +74,10 @@ 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
82
  /* An object cell is a VALUE the GC marks: reading other bytes as one
83
83
  marks garbage, and reading one as bytes exposes an address. */
@@ -89,6 +89,14 @@ ca_refer_setup (CARefer *ca, CArray *parent,
89
89
  rb_raise(rb_eCADataTypeError,
90
90
  "non-object array can't be referred as object data type");
91
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
+ }
92
100
  if (parent->elements && bytes > parent_bytes * parent->elements) {
93
101
  rb_raise(rb_eArgError, "bytes exceeds the data size of referent");
94
102
  }
@@ -129,14 +137,13 @@ ca_refer_setup (CARefer *ca, CArray *parent,
129
137
  return 0;
130
138
  }
131
139
 
132
- /* CAREFUL: initialise mask0 before ca_stride_setup — the setup
133
- may dispatch to ca_refer_func_create_mask, which writes to
134
- mask0. Leaving it uninitialised risks freeing a garbage
135
- pointer during error unwind. */
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. */
136
143
  ca->mask0 = NULL;
137
144
 
138
- ca_stride_setup((CAStride *) ca, CA_OBJ_REFER, parent,
139
- 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);
140
147
 
141
148
  if (ca_is_scalar(parent)) {
142
149
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -153,6 +160,7 @@ ca_refer_new (CArray *parent,
153
160
  ca_refer_setup(NULL, parent, data_type, ndim, dim, bytes, offset);
154
161
  ca = (CARefer *) ca_array_alloc(CA_OBJ_REFER, ndim);
155
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);
156
164
  return ca;
157
165
  }
158
166
 
@@ -260,6 +268,7 @@ rb_ca_refer_initialize_copy (VALUE self, VALUE other)
260
268
  unusual mod-bytes alignments. */
261
269
  ca_refer_setup(ca, cs->parent, cs->data_type, cs->ndim, cs->dim,
262
270
  cs->bytes, cs->base_offset / cs->parent->bytes);
271
+ ca_view_inherit_mask((VALUE) ca);
263
272
  return self;
264
273
  }
265
274
 
@@ -488,7 +497,7 @@ rb_ca_refer_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
488
497
  }
489
498
  }
490
499
  Check_Type(rdim, T_ARRAY);
491
- CA_CHECK_RANK(RARRAY_LEN(rdim)); /* before dim[] is filled */
500
+ CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
492
501
  ndim = RARRAY_LEN(rdim);
493
502
  for (i = 0; i < ndim; i++) dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
494
503
  if (! NIL_P(roffset)) offset = NUM2SIZE(roffset);
@@ -610,9 +619,7 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
610
619
 
611
620
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
612
621
 
613
- if (argc < 0 || argc > CA_RANK_MAX) {
614
- rb_raise(rb_eArgError, "reshape: invalid number of dims (%d)", argc);
615
- }
622
+ ca_check_rank_fits(argc, "reshape");
616
623
 
617
624
  /* Locate the (at most one) auto-infer placeholder. `-1` is the
618
625
  conventional spelling; `:~` is the unified auto-fill sigil
@@ -775,7 +782,7 @@ rb_ca_flatten (VALUE self)
775
782
  before axis 0 twice -> [1, 1, 2, 3]
776
783
 
777
784
  Returns a CARefer view (zero-copy alias to +self+'s data, via reshape).
778
- Bound to the internal name __insert_axis_size1__; the user-facing
785
+ Bound to the private method insert_size_one_axes; the user-facing
779
786
  insert_axis (with the repeat: keyword) is the Ruby method in
780
787
  lib/carray/basics.rb, which builds on this primitive.
781
788
 
@@ -795,11 +802,7 @@ rb_ca_insert_axis (int argc, VALUE *argv, VALUE self)
795
802
 
796
803
  ndim = (int) ca->ndim;
797
804
  new_ndim = ndim + argc;
798
- if (new_ndim > CA_RANK_MAX) {
799
- rb_raise(rb_eArgError,
800
- "insert_axis: resulting ndim %d exceeds CA_RANK_MAX %d",
801
- new_ndim, CA_RANK_MAX);
802
- }
805
+ ca_check_rank_fits(new_ndim, "insert_axis");
803
806
 
804
807
  ngap = ndim + 1; /* gaps live in [0, ndim] (ndim = the end gap) */
805
808
 
@@ -809,12 +812,7 @@ rb_ca_insert_axis (int argc, VALUE *argv, VALUE self)
809
812
  gap_count[i] = 0;
810
813
  }
811
814
  for (i = 0; i < argc; i++) {
812
- int raw = (int) ca_axis_integer(argv[i], "insert_axis");
813
- int g = (raw < 0) ? raw + ngap : raw;
814
- if (g < 0 || g >= ngap) {
815
- rb_raise(rb_eArgError,
816
- "insert_axis: axis %d out of range for ndim %d", raw, ndim);
817
- }
815
+ int g = ca_normalize_axis_arg(argv[i], ngap, "insert_axis");
818
816
  gap_count[g]++;
819
817
  }
820
818
 
@@ -858,7 +856,7 @@ Init_ca_obj_refer (void)
858
856
  /* The bare size-1 primitive. The user-facing `insert_axis` (with its
859
857
  `repeat:` keyword) is the Ruby method in lib/carray/basics.rb, which
860
858
  owns the name and calls this primitive. */
861
- 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);
862
860
  rb_define_alloc_func(rb_cCARefer, rb_ca_refer_s_allocate);
863
861
  rb_define_method(rb_cCARefer, "initialize_copy",
864
862
  rb_ca_refer_initialize_copy, 1);
data/ext/ca_obj_remap.c CHANGED
@@ -129,6 +129,12 @@ ca_remap_setup (CARemap *ca, CArray *ref, CArray *idx)
129
129
  {
130
130
  ca_remap_check_constraints(ref, idx);
131
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
+
132
138
  ca->obj_type = CA_OBJ_REMAP;
133
139
  ca->data_type = ref->data_type;
134
140
  ca->flags = 0;
@@ -147,9 +153,6 @@ ca_remap_setup (CARemap *ca, CArray *ref, CArray *idx)
147
153
  ca->nosync = 0;
148
154
  ca->idx = idx;
149
155
 
150
- if ( ca_has_mask(ref) ) {
151
- ca_create_mask(ca);
152
- }
153
156
 
154
157
  if ( ca_is_scalar(ref) ) {
155
158
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -161,8 +164,11 @@ ca_remap_setup (CARemap *ca, CArray *ref, CArray *idx)
161
164
  CARemap *
162
165
  ca_remap_new (CArray *ref, CArray *idx)
163
166
  {
164
- 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);
165
170
  ca_remap_setup(ca, ref, idx);
171
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
166
172
  return ca;
167
173
  }
168
174
 
@@ -211,7 +217,7 @@ static void
211
217
  ca_remap_func_allocate (void *ap)
212
218
  {
213
219
  CARemap *ca = (CARemap *) ap;
214
- ca->ptr = xmalloc(ca_length(ca));
220
+ ca->ptr = ca_alloc_cells((CArray *) ca);
215
221
  }
216
222
 
217
223
  static void
@@ -435,8 +441,9 @@ rb_ca_remap_new (VALUE cary, VALUE rmapper)
435
441
  }
436
442
 
437
443
  /* Read-only accessor for the per-cell index CArray that defines this
438
- CARemap's mapping. Returns the same CArray VALUE the caller passed
439
- 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
440
447
  CABlock#start / CAStride#strides / CAWindow#count etc. — the view
441
448
  hierarchy is preserved so each named view class exposes its own
442
449
  defining semantic state. */
@@ -453,8 +460,22 @@ rb_ca_remap_mapper (VALUE self)
453
460
  static VALUE
454
461
  rb_ca_remap_dup (VALUE self)
455
462
  {
456
- return rb_ca_remap_new(rb_ca_parent(self),
457
- rb_ivar_get(self, rb_intern("remap_idx")));
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);
458
479
  }
459
480
 
460
481
  static VALUE
data/ext/ca_obj_repeat.c CHANGED
@@ -39,9 +39,7 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
39
39
  int8_t data_ndim = 0;
40
40
  int8_t i, j;
41
41
 
42
- if ( ndim < 0 || ndim > CA_RANK_MAX ) {
43
- rb_raise(rb_eArgError, "invalid ndim %d", (int) ndim);
44
- }
42
+ ca_check_rank_fits(ndim, NULL);
45
43
  for (i = 0; i < ndim; i++) {
46
44
  if (count[i] < 0) {
47
45
  rb_raise(rb_eArgError,
@@ -86,9 +84,9 @@ ca_repeat_setup (CAStride *ca, CArray *parent, int8_t ndim, ca_size_t *count)
86
84
  return 0;
87
85
  }
88
86
 
89
- ca_stride_setup(ca, CA_OBJ_REPEAT, parent,
90
- parent->data_type, parent->bytes,
91
- ndim, newdim, strides, 0);
87
+ ca_stride_setup_view(ca, CA_OBJ_REPEAT, parent,
88
+ parent->data_type, parent->bytes,
89
+ ndim, newdim, strides, 0);
92
90
 
93
91
  ca_set_flag(ca, CA_FLAG_READ_ONLY);
94
92
  if (ca->mask) {
@@ -104,6 +102,7 @@ ca_repeat_new (CArray *parent, int8_t ndim, ca_size_t *count)
104
102
  ca_repeat_setup(NULL, parent, ndim, count);
105
103
  ca = (CAStride *) ca_array_alloc(CA_OBJ_REPEAT, ndim);
106
104
  ca_repeat_setup(ca, parent, ndim, count);
105
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
107
106
  return ca;
108
107
  }
109
108
 
@@ -216,12 +215,12 @@ rb_ca_repeat (int argc, VALUE *argv, VALUE self)
216
215
  self = rb_ca_refer_new(self, ca->data_type, ndim, dim, ca->bytes, 0);
217
216
  }
218
217
  }
219
- return rb_ca_repeat((int)RARRAY_LEN(args), (VALUE *)RARRAY_CONST_PTR(args), self);
218
+ self = rb_ca_repeat((int)RARRAY_LEN(args), (VALUE *)RARRAY_CONST_PTR(args), self);
219
+ RB_GC_GUARD(args); /* the repeat reads its arguments out of args */
220
+ return self;
220
221
  }
221
222
 
222
- if ( argc > CA_RANK_MAX ) { /* count[] and dim[] hold CA_RANK_MAX */
223
- rb_raise(rb_eArgError, "invalid ndim %d", argc);
224
- }
223
+ ca_check_rank_fits(argc, NULL); /* count[] and dim[] hold CA_RANK_MAX */
225
224
 
226
225
  repeat = 1;
227
226
  for (i=0; i<argc; i++) {
data/ext/ca_obj_roll.c CHANGED
@@ -126,9 +126,6 @@ ca_roll_setup (CARoll *ca, CArray *parent, ca_size_t *shift)
126
126
  ca->reps[i] = s;
127
127
  }
128
128
 
129
- if ( ca_has_mask(parent) ) {
130
- ca_create_mask(ca);
131
- }
132
129
 
133
130
  return 0;
134
131
  }
@@ -140,6 +137,7 @@ ca_roll_new (CArray *parent, ca_size_t *shift)
140
137
  ca_roll_setup(NULL, parent, shift);
141
138
  ca = ALLOC(CARoll);
142
139
  ca_roll_setup(ca, parent, shift);
140
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
143
141
  return ca;
144
142
  }
145
143
 
@@ -261,6 +259,7 @@ ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
261
259
  ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
262
260
  for (k = 0; k < ndim; k++) base += starts[k] * rnative[k];
263
261
  for (k = 0; k < ndim; k++) idx[k] = 0;
262
+ /* empty: the slot returns on an empty region at its entry */
264
263
  while (1) {
265
264
  ca_size_t roff = base, ridx[CA_RANK_MAX];
266
265
  for (k = 0; k < ndim; k++) roff += idx[k] * strides[k];
@@ -364,6 +363,7 @@ ca_roll_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
364
363
  }
365
364
 
366
365
  for (k = 0; k < ndim; k++) o[k] = 0;
366
+ /* empty: the slot returns on an empty region at its entry */
367
367
  while (1) {
368
368
  ca_size_t pbase = 0, doff = 0, i;
369
369
  for (k = 0; k < inner; k++) {
@@ -506,7 +506,7 @@ ca_roll_func_allocate (void *ap)
506
506
  {
507
507
  CARoll *ca = (CARoll *) ap;
508
508
  ca_attach(ca->parent);
509
- ca->ptr = xmalloc(ca_length(ca));
509
+ ca->ptr = ca_alloc_cells((CArray *) ca);
510
510
  }
511
511
 
512
512
  static void
@@ -514,7 +514,7 @@ ca_roll_func_attach (void *ap)
514
514
  {
515
515
  CARoll *ca = (CARoll *) ap;
516
516
  ca_attach(ca->parent);
517
- ca->ptr = xmalloc(ca_length(ca));
517
+ ca->ptr = ca_alloc_cells((CArray *) ca);
518
518
  ca_roll_iterate_regions(ca, ca->ptr, 0);
519
519
  }
520
520
 
@@ -659,6 +659,7 @@ rb_ca_roll_initialize_copy (VALUE self, VALUE other)
659
659
  ca_check_uninitialized(ca);
660
660
  TypedData_Get_Struct(other, CARoll, &caroll_data_type, cs);
661
661
  ca_roll_setup(ca, cs->parent, cs->reps);
662
+ ca_view_inherit_mask((VALUE) ca);
662
663
  return self;
663
664
  }
664
665
 
data/ext/ca_obj_select.c CHANGED
@@ -162,15 +162,19 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
162
162
  if ( s[i] ) count++;
163
163
  }
164
164
  ca->elements = count;
165
- /* Placeholder 1-element allocation when count == 0 to avoid
166
- malloc(0) implementation variance; the engine treats
167
- elements==0 as a no-op so the contents are irrelevant. */
168
- ca->indices = (ca_size_t *) xmalloc(
169
- sizeof(ca_size_t) * (count > 0 ? count : 1));
165
+ /* One slot more than count: the loop below writes every position
166
+ and advances only on TRUE, so a run of FALSE after the last TRUE
167
+ writes slot `count`. Writing without a branch keeps a selector
168
+ with TRUE and FALSE mixed at random from mispredicting on most
169
+ cells. The extra slot also keeps count == 0 from malloc(0). */
170
+ ca->indices = (ca_size_t *) xmalloc(sizeof(ca_size_t) * (count + 1));
170
171
  {
171
- ca_size_t j = 0;
172
- for (i = 0; i < ca->select->elements; i++) {
173
- if ( s[i] ) ca->indices[j++] = i;
172
+ ca_size_t *ix = ca->indices;
173
+ ca_size_t n = ca->select->elements;
174
+ ca_size_t j = 0;
175
+ for (i = 0; i < n; i++) {
176
+ ix[j] = i;
177
+ j += ( s[i] != 0 );
174
178
  }
175
179
  }
176
180
  /* Constant-step detection: promotes to STRIDE descriptor kind
@@ -211,6 +215,7 @@ CArray *
211
215
  ca_select_new (CArray *parent, CArray *select)
212
216
  {
213
217
  CArray *snapshot = ca_select_snapshot(select);
218
+ /* check: the setup checks nothing */
214
219
  CASelect *ca = ALLOC(CASelect);
215
220
  ca_select_setup(ca, parent, snapshot);
216
221
  return (CArray*) ca;
@@ -431,7 +436,7 @@ ca_select_func_allocate (void *ap)
431
436
  if ( ! ca_parent_lends_no_memory(ca->parent) ) {
432
437
  ca_attach(ca->parent);
433
438
  }
434
- ca->ptr = xmalloc(ca_length(ca));
439
+ ca->ptr = ca_alloc_cells((CArray *) ca);
435
440
  }
436
441
 
437
442
  static void
@@ -311,6 +311,7 @@ ca_select_axis_new (CArray *parent, int8_t indirect_axis,
311
311
  CArray *selector,
312
312
  ca_size_t *ap_start, ca_size_t *ap_count, ca_size_t *ap_step)
313
313
  {
314
+ /* check: the callers (clone, create_mask) pass an existing view's checked selector */
314
315
  CASelectAxis *ca = (CASelectAxis *) ca_array_alloc(CA_OBJ_SELECT_AXIS, parent->ndim);
315
316
  ca_select_axis_setup(ca, parent, indirect_axis, selector,
316
317
  ap_start, ap_count, ap_step);
@@ -590,6 +591,7 @@ ca_select_axis_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
590
591
  ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
591
592
  for (k = 0; k < ndim; k++) base += starts[k] * cnative[k];
592
593
  for (k = 0; k < ndim; k++) idx[k] = 0;
594
+ /* empty: the slot returns on an empty region at its entry */
593
595
  while (1) {
594
596
  ca_size_t coff = base, cidx[CA_RANK_MAX];
595
597
  for (k = 0; k < ndim; k++) coff += idx[k] * strides[k];
@@ -673,6 +675,7 @@ ca_select_axis_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
673
675
  ca_xfer_stride/ca_xfer_addrs. */
674
676
  for (k = 0; k < ndim; k++) o[k] = 0;
675
677
 
678
+ /* empty: the slot returns on an empty region at its entry */
676
679
  while (1) {
677
680
  ca_size_t pbase = 0, doff = 0;
678
681
  for (k = 0; k < inner; k++) {
@@ -725,7 +728,7 @@ ca_select_axis_func_allocate (void *ap)
725
728
  if ( ! ca_parent_lends_no_memory(ca->parent) ) {
726
729
  ca_attach(ca->parent);
727
730
  }
728
- ca->ptr = xmalloc(ca_length(ca));
731
+ ca->ptr = ca_alloc_cells((CArray *) ca);
729
732
  }
730
733
 
731
734
  static void
@@ -895,6 +898,7 @@ rb_ca_select_axis_s_new_debug (VALUE klass, VALUE rparent, VALUE rindirect,
895
898
  VALUE rap_count, VALUE rap_step)
896
899
  {
897
900
  CArray *parent, *selector;
901
+ /* fits: an axis number from the view that made it */
898
902
  int8_t indirect_axis = (int8_t) NUM2INT(rindirect);
899
903
  int8_t ndim;
900
904
  int8_t k;
@@ -966,15 +970,15 @@ rb_ca_select_axis_eligible_p (int argc, VALUE *argv, VALUE self)
966
970
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
967
971
  if ( argc != ca->ndim ) return 0;
968
972
 
969
- /* axis 0 is the boolean (indirect). Walk rest; require nil/Integer/Range. */
973
+ /* axis 0 is the boolean (indirect). The rest are read as the indexer
974
+ reads them; a run of more than one step, or of no cells, goes to
975
+ CAGrid. */
970
976
  for ( i = 1; i < argc; i++ ) {
971
977
  VALUE arg = argv[i];
972
- if ( NIL_P(arg) ) continue;
973
- if ( FIXNUM_P(arg) ) continue;
974
- if ( TYPE(arg) == T_DATA ) return 0; /* CArray at axis > 0 → bail */
975
- if ( rb_obj_is_kind_of(arg, rb_cRange) ) continue;
976
- if ( rb_obj_is_kind_of(arg, rb_cInteger) ) continue;
977
- return 0;
978
+ ca_size_t start, count, step;
979
+ if ( rb_obj_is_carray(arg) ) return 0; /* CArray at axis > 0 → bail */
980
+ ca_index_axis_key(arg, ca->dim[i], i, &start, &count, &step);
981
+ if ( step != 1 || count < 1 ) return 0;
978
982
  }
979
983
 
980
984
  return 1;
@@ -1006,45 +1010,9 @@ rb_ca_select_axis (int argc, VALUE *argv, VALUE self)
1006
1010
  for ( i = 0; i < argc; i++ ) {
1007
1011
  VALUE arg = argv[i];
1008
1012
 
1009
- if ( NIL_P(arg) ) {
1010
- ap_start[i] = 0;
1011
- ap_count[i] = parent->dim[i];
1012
- ap_step[i] = 1;
1013
- }
1014
- else if ( FIXNUM_P(arg) || rb_obj_is_kind_of(arg, rb_cInteger) ) {
1015
- ca_size_t n = NUM2LL(arg);
1016
- if ( n < 0 ) n += parent->dim[i];
1017
- if ( n < 0 || n >= parent->dim[i] ) {
1018
- rb_raise(rb_eIndexError,
1019
- "CASelectAxis: index %lld out of range at axis %d",
1020
- (long long) n, i);
1021
- }
1022
- ap_start[i] = n;
1023
- ap_count[i] = 1;
1024
- ap_step[i] = 1;
1025
- }
1026
- else if ( rb_obj_is_kind_of(arg, rb_cRange) ) {
1027
- VALUE rfirst = rb_funcall(arg, rb_intern("first"), 0);
1028
- VALUE rlast = rb_funcall(arg, rb_intern("last"), 0);
1029
- int exclusive = RTEST(rb_funcall(arg, rb_intern("exclude_end?"), 0));
1030
- ca_size_t a = NUM2LL(rfirst);
1031
- ca_size_t b = NUM2LL(rlast);
1032
- if ( a < 0 ) a += parent->dim[i];
1033
- if ( b < 0 ) b += parent->dim[i];
1034
- ca_size_t cnt = exclusive ? (b - a) : (b - a + 1);
1035
- if ( cnt <= 0 ) {
1036
- rb_raise(rb_eIndexError,
1037
- "CASelectAxis: empty range at axis %d", i);
1038
- }
1039
- if ( a < 0 || a >= parent->dim[i] ||
1040
- (a + cnt - 1) < 0 || (a + cnt - 1) >= parent->dim[i] ) {
1041
- rb_raise(rb_eIndexError,
1042
- "CASelectAxis: range [%lld..%lld] out of bounds at axis %d",
1043
- (long long) a, (long long) (a + cnt - 1), i);
1044
- }
1045
- ap_start[i] = a;
1046
- ap_count[i] = cnt;
1047
- ap_step[i] = 1;
1013
+ if ( ! rb_obj_is_carray(arg) ) {
1014
+ ca_index_axis_key(arg, parent->dim[i], i,
1015
+ &ap_start[i], &ap_count[i], &ap_step[i]);
1048
1016
  }
1049
1017
  else if ( rb_obj_is_carray(arg) && rb_ca_is_boolean_type(arg) ) {
1050
1018
  TypedData_Get_Struct(arg, CArray, &carray_data_type, selector);
data/ext/ca_obj_shift.c CHANGED
@@ -16,6 +16,7 @@
16
16
  ---------------------------------------------------------------------------- */
17
17
 
18
18
  #include "carray.h"
19
+ #include "carray_internal.h" /* ca_window_create_bounds_mask */
19
20
  #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
20
21
 
21
22
  /* External: CAWindow's operation table + setup are the basis for CAShift. */
@@ -127,6 +128,7 @@ ca_shift_new (CArray *parent, ca_size_t *shift, char *fill, int8_t *roll,
127
128
  ca_shift_setup(NULL, parent, shift, fill, roll, fill_mask);
128
129
  ca = (CAShift *) ca_array_alloc(CA_OBJ_SHIFT, parent->ndim);
129
130
  ca_shift_setup(ca, parent, shift, fill, roll, fill_mask);
131
+ ca_fill_or_free((CArray *) ca, ca_window_create_bounds_mask, (VALUE) ca);
130
132
  return ca;
131
133
  }
132
134
 
@@ -152,7 +154,11 @@ ca_shift_func_clone (void *ap)
152
154
  }
153
155
  }
154
156
 
155
- return ca_shift_new(ca->parent, shift, ca->fill, roll, fill_mask);
157
+ {
158
+ CAShift *cp = ca_shift_new(ca->parent, shift, ca->fill, roll, fill_mask);
159
+ cp->mask_owner = ca->mask_owner;
160
+ return cp;
161
+ }
156
162
  }
157
163
 
158
164
 
@@ -306,6 +312,10 @@ rb_ca_shift_initialize_copy (VALUE self, VALUE other)
306
312
  ca_array_pool_alloc(ca, CA_OBJ_SHIFT, cs->ndim);
307
313
  }
308
314
  ca_shift_setup(ca, cs->parent, shift, cs->fill, roll, fill_mask);
315
+ ca_window_create_bounds_mask((VALUE) ca);
316
+ /* a copy of a mask over a stand-in gives way to the parent's mask as
317
+ the original does */
318
+ ca->mask_owner = cs->mask_owner;
309
319
 
310
320
  return self;
311
321
  }