carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_object.c CHANGED
@@ -60,6 +60,15 @@ ca_object_pool_init (void *ap, int8_t ndim)
60
60
  ca->dim = (ca_size_t *) ca->_pool;
61
61
  }
62
62
 
63
+ /* ca->self is the CAObject's own VALUE, which compaction can move; the
64
+ hooks call back through it, so follow the object to its new slot. */
65
+ static void
66
+ ca_object_compact (void *ap)
67
+ {
68
+ CAObject *ca = (CAObject *) ap;
69
+ ca->self = rb_gc_location(ca->self);
70
+ }
71
+
63
72
  const rb_data_type_t caobject_data_type = {
64
73
  .parent = &caview_data_type,
65
74
  .wrap_struct_name = "CAObject",
@@ -67,7 +76,7 @@ const rb_data_type_t caobject_data_type = {
67
76
  .dmark = ca_mark,
68
77
  .dfree = ca_free,
69
78
  .dsize = ca_object_dsize,
70
- .dcompact = NULL
79
+ .dcompact = ca_object_compact
71
80
  },
72
81
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
73
82
  };
@@ -84,15 +93,23 @@ ca_objectmask_dsize (const void *ap)
84
93
  }
85
94
 
86
95
  /* The mask reads and writes through its CAObject, and its cache is the
87
- CAObject's; it keeps the CAObject alive. */
96
+ CAObject's; it keeps the CAObject alive, and follows it when compaction
97
+ moves it. */
88
98
  static void
89
99
  ca_objmask_mark (void *ap)
90
100
  {
91
101
  CAObjectMask *ca = (CAObjectMask *) ap;
92
- rb_gc_mark(ca->array);
102
+ rb_gc_mark_movable(ca->array);
93
103
  ca_mark(ap);
94
104
  }
95
105
 
106
+ static void
107
+ ca_objmask_compact (void *ap)
108
+ {
109
+ CAObjectMask *ca = (CAObjectMask *) ap;
110
+ ca->array = rb_gc_location(ca->array);
111
+ }
112
+
96
113
  const rb_data_type_t caobjectmask_data_type = {
97
114
  .parent = &carray_data_type,
98
115
  .wrap_struct_name = "CAObjectMask",
@@ -100,7 +117,7 @@ const rb_data_type_t caobjectmask_data_type = {
100
117
  .dmark = ca_objmask_mark,
101
118
  .dfree = ca_free,
102
119
  .dsize = ca_objectmask_dsize,
103
- .dcompact = NULL
120
+ .dcompact = ca_objmask_compact
104
121
  },
105
122
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
106
123
  };
@@ -111,6 +128,7 @@ VALUE rb_cCAObjectMask;
111
128
  static CAObjectMask *
112
129
  ca_objmask_new (VALUE array, int8_t ndim, ca_size_t *dim)
113
130
  {
131
+ /* check: the mask takes the CAObject's own shape, already checked */
114
132
  CAObjectMask *ca = ALLOC(CAObjectMask);
115
133
  /* CA_OBJ_OBJECT_MASK registers no pool_init, so it lives on the legacy
116
134
  ALLOC_N path (dim allocated separately, freed via free_ca_wrap's else
@@ -135,50 +153,126 @@ ca_objmask_mask_data (void *ap)
135
153
  rb_intern("mask"), 0);
136
154
  }
137
155
 
138
- /* Calls recv.mid(arg(ap)) with *slot pointing at a caller's buffer for
139
- the duration, and puts *slot back however the call leaves. The bulk
140
- bridge lends the buffer this way so that copy_data / sync_data write
141
- straight into it; a raise that skipped the restore would leave the
142
- array pointing at a buffer its caller is about to free. */
156
+ /* A wrap handed to a hook points at a buffer the caller frees once the
157
+ hook returns. Taking it back leaves an array of no cells: a hook that
158
+ kept it holds something that raises when read, not a pointer into freed
159
+ memory. */
160
+ static char ca_object_no_cells[16];
161
+
162
+ static void
163
+ ca_object_empty_wrap (CArray *w)
164
+ {
165
+ int8_t k;
166
+ /* Not NULL: an entity whose pointer is NULL reads as detached. */
167
+ w->ptr = ca_object_no_cells;
168
+ w->elements = 0;
169
+ for ( k = 0; k < w->ndim; k++ ) {
170
+ w->dim[k] = 0;
171
+ }
172
+ }
173
+
174
+ /* Moves the cells of a wrap (or of its lent mask, `w`) into an array of
175
+ their own, held by `holder` under `name`, and points `w` at them. The
176
+ cells are those the hook left in the caller's buffer. */
177
+ static void
178
+ ca_object_keep_cells (VALUE holder, const char *name, CArray *w)
179
+ {
180
+ volatile VALUE cells;
181
+ CArray *c;
182
+ cells = rb_carray_new(w->data_type, w->ndim, w->dim, w->bytes, NULL);
183
+ c = (CArray *) DATA_PTR(cells);
184
+ memcpy(c->ptr, w->ptr, (size_t) w->elements * w->bytes);
185
+ rb_ivar_set(holder, rb_intern(name), cells);
186
+ w->ptr = c->ptr;
187
+ }
188
+
189
+ /* Takes the caller's buffer back from a wrap the hook was lent, together
190
+ with `lent_mask`, the wrap of the data's mask bits it was lent with (or
191
+ NULL). When the hook took a view of either, the view outlives the call,
192
+ so both keep their cells; otherwise both are left with none. A mask the
193
+ hook made on the wrap is the wrap's own, with cells of its own. */
194
+ static void
195
+ ca_object_take_back (VALUE wrap, CArray *lent_mask)
196
+ {
197
+ CArray *w = (CArray *) DATA_PTR(wrap);
198
+ CArray *m = ( lent_mask != NULL && w->mask == lent_mask ) ? lent_mask : NULL;
199
+ int viewed = ca_test_flag(w, CA_FLAG_LENT_VIEWED) ||
200
+ ( m != NULL && ca_test_flag(m, CA_FLAG_LENT_VIEWED) );
201
+ ca_unset_flag(w, CA_FLAG_LENT | CA_FLAG_LENT_VIEWED);
202
+ if ( lent_mask != NULL ) {
203
+ ca_unset_flag(lent_mask, CA_FLAG_LENT | CA_FLAG_LENT_VIEWED);
204
+ }
205
+ if ( viewed ) {
206
+ ca_object_keep_cells(wrap, "kept_cells", w);
207
+ if ( m != NULL ) {
208
+ ca_object_keep_cells(wrap, "kept_mask_cells", m);
209
+ }
210
+ }
211
+ else {
212
+ if ( m != NULL ) {
213
+ ca_object_empty_wrap(m);
214
+ }
215
+ ca_object_empty_wrap(w);
216
+ }
217
+ }
218
+
219
+ /* Calls copy_data / sync_data with a wrap of a caller's buffer, shaped as
220
+ the object, and takes the buffer back however the call leaves. When the
221
+ data has a mask, the wrap's mask is a wrap of its bits: a hook that writes
222
+ masked values masks the object's cells, and the data keeps its mask
223
+ whatever the hook does with the wrap's. A mask the hook makes on a wrap
224
+ that had none is the wrap's own and goes with it. The data points at the
225
+ buffer for the duration too, for a hook that reads the object back while
226
+ it runs. */
143
227
 
144
228
  typedef struct {
145
- char **slot;
146
- char *saved;
147
- VALUE recv;
148
- ID mid;
149
- VALUE (*arg)(void *);
150
- void *ap;
229
+ CAObject *ca;
230
+ char *saved;
231
+ ID mid;
232
+ VALUE wrap;
233
+ CArray *mask; /* the wrap of the data's mask bits, or NULL */
151
234
  } ca_object_lend_t;
152
235
 
153
236
  static VALUE
154
237
  ca_object_lend_body (VALUE varg)
155
238
  {
156
239
  ca_object_lend_t *l = (ca_object_lend_t *) varg;
157
- return rb_funcall(l->recv, l->mid, 1, l->arg(l->ap));
240
+ return rb_funcall(l->ca->self, l->mid, 1, l->wrap);
158
241
  }
159
242
 
160
243
  static VALUE
161
244
  ca_object_lend_restore (VALUE varg)
162
245
  {
163
246
  ca_object_lend_t *l = (ca_object_lend_t *) varg;
164
- *l->slot = l->saved;
247
+ l->ca->data->ptr = l->saved;
248
+ ca_object_take_back(l->wrap, l->mask);
165
249
  return Qnil;
166
250
  }
167
251
 
168
252
  static void
169
- ca_object_call_lending (char **slot, void *ptr, VALUE recv, const char *mid,
170
- VALUE (*arg)(void *), void *ap)
253
+ ca_object_call_lending (CAObject *ca, void *ptr, const char *mid)
171
254
  {
172
255
  ca_object_lend_t l;
173
- l.slot = slot;
174
- l.saved = *slot;
175
- l.recv = recv;
256
+ CArray *data = ca->data;
257
+ CAWrap *w;
258
+ w = ca_wrap_new(data->data_type, data->ndim, data->dim, data->bytes,
259
+ NULL, (char *) ptr);
260
+ l.wrap = ca_wrap_struct(w);
261
+ l.mask = NULL;
262
+ if ( data->mask != NULL ) {
263
+ l.mask = (CArray *) ca_wrap_new(CA_BOOLEAN, data->ndim, data->dim, 0,
264
+ NULL, data->mask->ptr);
265
+ ca_set_flag(l.mask, CA_FLAG_LENT);
266
+ w->mask = l.mask;
267
+ }
268
+ ca_set_flag(w, CA_FLAG_LENT);
269
+ l.ca = ca;
270
+ l.saved = data->ptr;
176
271
  l.mid = rb_intern(mid);
177
- l.arg = arg;
178
- l.ap = ap;
179
- *slot = (char *) ptr;
272
+ data->ptr = (char *) ptr;
180
273
  rb_ensure(ca_object_lend_body, (VALUE) &l,
181
274
  ca_object_lend_restore, (VALUE) &l);
275
+ RB_GC_GUARD(l.wrap);
182
276
  }
183
277
 
184
278
  /* Calls recv.mid(*argv), where some of argv are transient wraps of a
@@ -187,8 +281,7 @@ ca_object_call_lending (char **slot, void *ptr, VALUE recv, const char *mid,
187
281
  when it returns, and a wrap outlives the call: the collector scans the
188
282
  machine stack conservatively and still finds it there, and an object
189
283
  wrap is marked cell by cell -- through a buffer that is gone. A wrap
190
- taken back points at nothing; a hook that kept it holds an empty
191
- handle, not a stale one. */
284
+ taken back has no cells (ca_object_empty_wrap). */
192
285
 
193
286
  typedef struct {
194
287
  VALUE recv;
@@ -212,7 +305,7 @@ ca_object_hook_release (VALUE varg)
212
305
  ca_object_hook_t *h = (ca_object_hook_t *) varg;
213
306
  int i;
214
307
  for ( i = 0; i < h->ntrans; i++ ) {
215
- ((CArray *) DATA_PTR(h->trans[i]))->ptr = NULL;
308
+ ca_object_take_back(h->trans[i], NULL);
216
309
  }
217
310
  return Qnil;
218
311
  }
@@ -233,11 +326,6 @@ ca_object_call_transient (VALUE recv, const char *mid,
233
326
  ca_object_hook_release, (VALUE) &h);
234
327
  }
235
328
 
236
- static VALUE
237
- ca_object_data_of (void *ap)
238
- {
239
- return rb_ivar_get(((CAObject *) ap)->self, rb_intern("__data__"));
240
- }
241
329
 
242
330
 
243
331
  /* Forward declaration: ca_object_wrap_transient (defined further down,
@@ -706,14 +794,19 @@ ca_object_setup (CAObject *ca,
706
794
  int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes)
707
795
  {
708
796
  ca_size_t elements;
709
- int8_t i;
710
797
 
711
798
  /* check arguments */
712
799
 
713
- CA_CHECK_DATA_TYPE(data_type);
714
- CA_CHECK_RANK(ndim);
715
- CA_CHECK_DIM(ndim, dim);
716
- CA_CHECK_BYTES(data_type, bytes);
800
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
801
+ CA_CHECK_RANK_GIVEN(ndim);
802
+ CA_CHECK_DIM_GIVEN(ndim, dim);
803
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
804
+
805
+ /* ca == NULL asks for the checks above only, so that a constructor can
806
+ run them before it allocates. */
807
+ if ( ca == NULL ) {
808
+ return 0;
809
+ }
717
810
 
718
811
  /* calculate total number of elements */
719
812
 
@@ -745,7 +838,9 @@ ca_object_setup (CAObject *ca,
745
838
  static CAObject *
746
839
  ca_object_new (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes)
747
840
  {
748
- CAObject *ca = (CAObject *) ca_array_alloc(CA_OBJ_OBJECT, ndim);
841
+ CAObject *ca;
842
+ ca_object_setup(NULL, data_type, ndim, dim, bytes);
843
+ ca = (CAObject *) ca_array_alloc(CA_OBJ_OBJECT, ndim);
749
844
  ca_object_setup(ca, data_type, ndim, dim, bytes);
750
845
  return ca;
751
846
  }
@@ -755,7 +850,12 @@ free_ca_object (void *ap)
755
850
  {
756
851
  CAObject *ca = (CAObject *) ap;
757
852
  if ( ca != NULL ) {
758
- /* ca->mask will be GC-ed by Ruby interpreter */
853
+ /* A Face's mask is a view over its parent's mask (made by
854
+ ca_view_func_create_mask) and belongs to this struct. Otherwise
855
+ the mask is a Ruby object held in @mask, and the GC frees it. */
856
+ if ( ca_is_face(ca) ) {
857
+ ca_free(ca->mask);
858
+ }
759
859
  if ( ca->_pool ) {
760
860
  ca_array_free(ca); /* dim lives in _pool */
761
861
  }
@@ -789,6 +889,19 @@ ca_object_mask_bytes (CAObject *ca)
789
889
  return (boolean8_t *) ca->mask->ptr;
790
890
  }
791
891
 
892
+ /* Whether the mask of this object comes from its mask_* hooks. Then a
893
+ fetched value says nothing about the mask: a cell the hooks mask stays
894
+ masked when its value is read, and only a fetcher answering UNDEF marks
895
+ one. Without hooks the mask is what the fetches have answered, so a
896
+ value fetched clears the cell. */
897
+ static int
898
+ ca_object_mask_from_hooks (CAObject *ca)
899
+ {
900
+ return rb_obj_respond_to(ca->self, rb_intern("mask_fetch_addr"), Qtrue)
901
+ || rb_obj_respond_to(ca->self, rb_intern("mask_fetch_index"), Qtrue)
902
+ || rb_obj_respond_to(ca->self, rb_intern("mask_copy_data"), Qtrue);
903
+ }
904
+
792
905
  /* per-cell cores: the addr- and index-primary Ruby-callback bridge logic,
793
906
  direction-unified. The fetch_* / store_* slots below are thin
794
907
  forwarders onto these. */
@@ -809,7 +922,7 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
809
922
  }
810
923
  }
811
924
  else {
812
- if ( ca_has_mask(ca) ) {
925
+ if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
813
926
  ca_object_mask_bytes(ca)[addr] = 0;
814
927
  }
815
928
  rb_ca_obj2ptr(ca->self, rval, ptr);
@@ -831,7 +944,7 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
831
944
  }
832
945
  }
833
946
  else {
834
- if ( ca_has_mask(ca) ) {
947
+ if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
835
948
  ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
836
949
  }
837
950
  rb_ca_obj2ptr(ca->self, rval, ptr);
@@ -877,7 +990,7 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
877
990
  }
878
991
  }
879
992
  else {
880
- if ( ca_has_mask(ca) ) {
993
+ if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
881
994
  ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
882
995
  }
883
996
  rb_ca_obj2ptr(ca->self, rval, ptr);
@@ -895,7 +1008,7 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
895
1008
  }
896
1009
  }
897
1010
  else {
898
- if ( ca_has_mask(ca) ) {
1011
+ if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
899
1012
  ca_object_mask_bytes(ca)[addr] = 0;
900
1013
  }
901
1014
  rb_ca_obj2ptr(ca->self, rval, ptr);
@@ -924,8 +1037,8 @@ static void
924
1037
  ca_object_func_allocate (void *ap)
925
1038
  {
926
1039
  CAObject *ca = (CAObject *) ap;
927
- /* ca->data->ptr = ALLOC_N(char, ca_length(ca)); */
928
- ca->data->ptr = xmalloc(ca_length(ca));
1040
+ /* cells: seeded with 0, which a copy_data that skips cells leaves visible */
1041
+ ca->data->ptr = xmalloc(ca_length(ca));
929
1042
  if ( ca_is_object_type(ca->data) ) { /* GC safe */
930
1043
  VALUE *p = (VALUE *) ca->data->ptr;
931
1044
  VALUE zero = INT2NUM(0);
@@ -951,12 +1064,51 @@ ca_object_func_allocate (void *ap)
951
1064
  arithmetic all work via the slow per-element fallback. The fast bulk
952
1065
  path is opt-in by defining copy_data / sync_data / fill_data. */
953
1066
 
1067
+ /* copy_data of an object whose mask comes from its hooks: the array it is
1068
+ handed must not carry the mask's cache, or a store of its values into it
1069
+ (d[] = src) would clear the cells the hooks mask. It is handed without a
1070
+ mask, and a mask the call makes on it is dropped. */
1071
+ typedef struct {
1072
+ CAObject *ca;
1073
+ void *ptr;
1074
+ CArray *mask;
1075
+ } ca_object_copy_bare_t;
1076
+
1077
+ static VALUE
1078
+ ca_object_copy_bare_body (VALUE arg)
1079
+ {
1080
+ ca_object_copy_bare_t *c = (ca_object_copy_bare_t *) arg;
1081
+ ca_object_call_lending(c->ca, c->ptr, "copy_data");
1082
+ return Qnil;
1083
+ }
1084
+
1085
+ static VALUE
1086
+ ca_object_copy_bare_restore (VALUE arg)
1087
+ {
1088
+ ca_object_copy_bare_t *c = (ca_object_copy_bare_t *) arg;
1089
+ CArray *made = c->ca->data->mask;
1090
+ if ( made != NULL && made != c->mask ) {
1091
+ ca_free(made);
1092
+ }
1093
+ c->ca->data->mask = c->mask;
1094
+ return Qnil;
1095
+ }
1096
+
954
1097
  static void
955
1098
  ca_object_dispatch_copy (CAObject *ca, void *ptr)
956
1099
  {
957
1100
  if ( rb_obj_respond_to(ca->self, rb_intern("copy_data"), Qtrue) ) {
958
- ca_object_call_lending(&ca->data->ptr, ptr, ca->self, "copy_data",
959
- ca_object_data_of, ca);
1101
+ if ( ca->data->mask != NULL && ca_object_mask_from_hooks(ca) ) {
1102
+ ca_object_copy_bare_t c;
1103
+ c.ca = ca;
1104
+ c.ptr = ptr;
1105
+ c.mask = ca->data->mask;
1106
+ ca->data->mask = NULL;
1107
+ rb_ensure(ca_object_copy_bare_body, (VALUE) &c,
1108
+ ca_object_copy_bare_restore, (VALUE) &c);
1109
+ return;
1110
+ }
1111
+ ca_object_call_lending(ca, ptr, "copy_data");
960
1112
  }
961
1113
  else {
962
1114
  ca_size_t addr;
@@ -971,8 +1123,7 @@ static void
971
1123
  ca_object_dispatch_sync (CAObject *ca, void *ptr)
972
1124
  {
973
1125
  if ( rb_obj_respond_to(ca->self, rb_intern("sync_data"), Qtrue) ) {
974
- ca_object_call_lending(&ca->data->ptr, ptr, ca->self, "sync_data",
975
- ca_object_data_of, ca);
1126
+ ca_object_call_lending(ca, ptr, "sync_data");
976
1127
  }
977
1128
  else {
978
1129
  ca_size_t addr;
@@ -1017,7 +1168,7 @@ ca_object_func_attach (void *ap)
1017
1168
  ca_face_attach(ap);
1018
1169
  return;
1019
1170
  }
1020
- /* ca->data->ptr = ALLOC_N(char, ca_length(ca)); */
1171
+ /* cells: seeded with 0, which a copy_data that skips cells leaves visible */
1021
1172
  ca->data->ptr = xmalloc(ca_length(ca));
1022
1173
  if ( ca_is_object_type(ca->data) ) { /* GC safe */
1023
1174
  VALUE *p = (VALUE *) ca->data->ptr;
@@ -1094,6 +1245,7 @@ ca_object_wrap_transient (int8_t data_type, ca_size_t bytes,
1094
1245
  }
1095
1246
 
1096
1247
  wrap = ca_wrap_new(data_type, ndim, dim, bytes, NULL, (char *) data);
1248
+ ca_set_flag(wrap, CA_FLAG_LENT);
1097
1249
  return ca_wrap_struct(wrap);
1098
1250
  }
1099
1251
 
@@ -1468,6 +1620,12 @@ rb_ca_object_initialize_copy (VALUE self, VALUE other)
1468
1620
  data = ca_wrap_struct(ca->data);
1469
1621
  rb_ivar_set(self, rb_intern("__data__"), data);
1470
1622
 
1623
+ /* A Face's mask is a C struct owned by the Face, so the copy makes its
1624
+ own from the parent when it is asked for one. */
1625
+ if ( ca_is_face(ca) ) {
1626
+ return self;
1627
+ }
1628
+
1471
1629
  ca_update_mask(cs);
1472
1630
  if ( cs->mask ) {
1473
1631
  ca->mask = cs->mask;
@@ -1567,7 +1725,7 @@ rb_ca_object_initialize (int argc, VALUE *argv, VALUE self)
1567
1725
  }
1568
1726
 
1569
1727
  Check_Type(rdim, T_ARRAY);
1570
- CA_CHECK_RANK(RARRAY_LEN(rdim)); /* before dim[] is filled */
1728
+ CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
1571
1729
 
1572
1730
  ndim = RARRAY_LEN(rdim);
1573
1731
  for (i=0; i<ndim; i++) {
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
  }
@@ -305,6 +309,9 @@ rb_ca_record_s_wrap (int argc, VALUE *argv, VALUE klass)
305
309
  rb_scan_args(argc, argv, "2", &entity_val, &data_class);
306
310
  }
307
311
  rb_check_carray_object(entity_val);
312
+ /* A record array (or another Face) is wrapped from its storage, so the
313
+ new record is not a Face over a Face. */
314
+ entity_val = rb_ca_strip_face_value(entity_val);
308
315
  return ca_record_build(klass, data_class, entity_val);
309
316
  }
310
317
 
@@ -362,6 +369,7 @@ rb_ca_record_initialize_copy (VALUE self, VALUE other)
362
369
  ca_array_pool_alloc(ca, CA_OBJ_RECORD, cs->parent->ndim);
363
370
  }
364
371
  ca_record_setup(ca, cs->parent, cs->data_class);
372
+ ca_view_inherit_mask((VALUE) ca);
365
373
  /* Marshal loads into an empty instance through here without copying
366
374
  ivars, so the parent pin is set from `other`, not inherited. */
367
375
  rb_ca_set_parent(self, rb_ca_parent(other));
data/ext/ca_obj_reduce.c CHANGED
@@ -56,6 +56,16 @@ 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
+ if ( count <= 0 ) {
60
+ rb_raise(rb_eArgError, "CAReduce: count should be positive");
61
+ }
62
+
63
+ /* ca == NULL asks for the checks above only, so that a constructor can
64
+ run them before it allocates. */
65
+ if ( ca == NULL ) {
66
+ return 0;
67
+ }
68
+
59
69
  elements = parent->elements / count;
60
70
 
61
71
  ca->obj_type = CA_OBJ_REDUCE;
@@ -75,9 +85,6 @@ ca_reduce_setup (CAReduce *ca, CArray *parent, ca_size_t count, ca_size_t offset
75
85
  ca->count = count;
76
86
  ca->offset = offset;
77
87
 
78
- if ( ca_has_mask(parent) ) {
79
- ca_create_mask(ca);
80
- }
81
88
 
82
89
  if ( ca_is_scalar(parent) ) {
83
90
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -89,8 +96,11 @@ ca_reduce_setup (CAReduce *ca, CArray *parent, ca_size_t count, ca_size_t offset
89
96
  CAReduce *
90
97
  ca_reduce_new (CArray *parent, ca_size_t count, ca_size_t offset)
91
98
  {
92
- CAReduce *ca = ALLOC(CAReduce);
99
+ CAReduce *ca;
100
+ ca_reduce_setup(NULL, parent, count, offset);
101
+ ca = ALLOC(CAReduce);
93
102
  ca_reduce_setup(ca, parent, count, offset);
103
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
94
104
  return ca;
95
105
  }
96
106
 
@@ -193,8 +203,7 @@ ca_reduce_func_allocate (void *ap)
193
203
  {
194
204
  CAReduce *ca = (CAReduce *) ap;
195
205
  ca_attach(ca->parent);
196
- /* ca->ptr = ALLOC_N(char, ca->elements); */
197
- ca->ptr = xmalloc(ca_length(ca));
206
+ ca->ptr = ca_alloc_cells((CArray *) ca);
198
207
  }
199
208
 
200
209
  static void
@@ -204,8 +213,7 @@ ca_reduce_func_attach (void *ap)
204
213
  char *p;
205
214
  ca_size_t i;
206
215
  ca_attach(ca->parent);
207
- /* ca->ptr = ALLOC_N(char, ca->elements); */
208
- ca->ptr = xmalloc(ca_length(ca));
216
+ ca->ptr = ca_alloc_cells((CArray *) ca);
209
217
  p = ca->ptr;
210
218
  for (i=0; i<ca->elements; i++) {
211
219
  ca_reduce_func_xfer_addrs(ca, 1, &i, p, CA_XFER_GET);
@@ -314,6 +322,7 @@ rb_ca_reduce_initialize_copy (VALUE self, VALUE other)
314
322
  TypedData_Get_Struct(other, CAReduce, &careduce_data_type, cs);
315
323
 
316
324
  ca_reduce_setup(ca, cs->parent, cs->count, cs->offset);
325
+ ca_view_inherit_mask((VALUE) ca);
317
326
 
318
327
  return self;
319
328
  }