carray 3.0.2 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +149 -27
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +102 -79
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_stack.c
CHANGED
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
partial cost)
|
|
13
13
|
- conditional fold_stride: counts[0] == 1 → fold to that parent;
|
|
14
14
|
multi-parent → fold boundary (decline)
|
|
15
|
-
- create_mask:
|
|
16
|
-
|
|
15
|
+
- create_mask: a mask CAStack over the parents' masks, with an all-false
|
|
16
|
+
stand-in for a parent that has none (ca_multi_parent_mask)
|
|
17
17
|
|
|
18
18
|
---------------------------------------------------------------------------- */
|
|
19
19
|
|
|
20
20
|
#include "carray.h"
|
|
21
|
-
#include "carray_internal.h" /* ca_attach_all */
|
|
21
|
+
#include "carray_internal.h" /* ca_attach_all / ca_sync_all */
|
|
22
22
|
#include "ca_composite_dispatch.h"
|
|
23
23
|
#include "ca_obj_face.h"
|
|
24
24
|
|
|
@@ -87,9 +87,9 @@ ca_stack_check_uniform (int32_t n_parents, CArray **parents)
|
|
|
87
87
|
CArray *p = parents[i];
|
|
88
88
|
if ( p->data_type != ref->data_type ) {
|
|
89
89
|
rb_raise(rb_eArgError,
|
|
90
|
-
"
|
|
91
|
-
"(
|
|
92
|
-
ref->data_type, i, p->data_type);
|
|
90
|
+
"stack: the arrays must have the same data type "
|
|
91
|
+
"(array 0 is %s, array %d is %s)",
|
|
92
|
+
ca_type_name[ref->data_type], i, ca_type_name[p->data_type]);
|
|
93
93
|
}
|
|
94
94
|
if ( p->ndim != ref->ndim ) {
|
|
95
95
|
rb_raise(rb_eArgError,
|
|
@@ -117,17 +117,6 @@ ca_stack_check_uniform (int32_t n_parents, CArray **parents)
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
/* One-level strip of a Face VALUE to its storage-side parent (non-Face as-is).
|
|
121
|
-
Used to keep the @parent GC/`.parent` ivar in step with the pre-stripped C
|
|
122
|
-
parents so the Ruby-visible chain of a stacked Face is single-Face too. */
|
|
123
|
-
static VALUE
|
|
124
|
-
ca_stack_face_parent1 (VALUE v)
|
|
125
|
-
{
|
|
126
|
-
CArray *c;
|
|
127
|
-
TypedData_Get_Struct(v, CArray, &carray_data_type, c);
|
|
128
|
-
return ca_is_face(c) ? rb_ca_parent(v) : v;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
120
|
int
|
|
132
121
|
ca_stack_setup_with_axis (CAStack *ca, int32_t n_parents, CArray **parents,
|
|
133
122
|
int8_t k_axis)
|
|
@@ -171,6 +160,8 @@ ca_stack_setup_with_axis (CAStack *ca, int32_t n_parents, CArray **parents,
|
|
|
171
160
|
ca->attach = 0;
|
|
172
161
|
ca->nosync = 0;
|
|
173
162
|
|
|
163
|
+
ca->mask_standins = NULL;
|
|
164
|
+
ca->mask_owner = NULL;
|
|
174
165
|
ca->n_parents = n_parents;
|
|
175
166
|
ca->parents = ALLOC_N(CArray *, n_parents);
|
|
176
167
|
for ( i = 0; i < n_parents; i++ ) {
|
|
@@ -186,7 +177,7 @@ ca_stack_setup_with_axis (CAStack *ca, int32_t n_parents, CArray **parents,
|
|
|
186
177
|
ca->dim[k_axis] = n_parents;
|
|
187
178
|
for ( a = k_axis + 1; a < ca->ndim; a++ ) ca->dim[a] = ref->dim[a - 1];
|
|
188
179
|
|
|
189
|
-
/* mask: lazy
|
|
180
|
+
/* mask: lazy, built on first mask access. */
|
|
190
181
|
return 0;
|
|
191
182
|
}
|
|
192
183
|
|
|
@@ -216,6 +207,13 @@ free_ca_stack (void *ap)
|
|
|
216
207
|
CAStack *ca = (CAStack *) ap;
|
|
217
208
|
if ( ca != NULL ) {
|
|
218
209
|
ca_free(ca->mask);
|
|
210
|
+
if ( ca->mask_standins ) {
|
|
211
|
+
int32_t k;
|
|
212
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
213
|
+
if ( ca->mask_standins[k] ) ca_free(ca->mask_standins[k]);
|
|
214
|
+
}
|
|
215
|
+
xfree(ca->mask_standins);
|
|
216
|
+
}
|
|
219
217
|
xfree(ca->parents);
|
|
220
218
|
xfree(ca->dim);
|
|
221
219
|
xfree(ca);
|
|
@@ -235,17 +233,40 @@ ca_stack_func_clone (void *ap)
|
|
|
235
233
|
|
|
236
234
|
/* view[..., k at k_axis, ...] = parents[k][parent_idx]
|
|
237
235
|
where parent_idx = idx[] with the k_axis slot removed. */
|
|
236
|
+
/* On the mask of a CAStack: let its stand-ins give way to the parents' own
|
|
237
|
+
masks (see ca_multi_parent_mask_refresh). */
|
|
238
|
+
static void
|
|
239
|
+
ca_stack_mask_refresh (CAStack *ca, int for_write)
|
|
240
|
+
{
|
|
241
|
+
CAStack *o = (CAStack *) ca->mask_owner;
|
|
242
|
+
if ( o != NULL ) {
|
|
243
|
+
ca_multi_parent_mask_refresh((CArray *) ca, o->parents, o->mask_standins,
|
|
244
|
+
o->n_parents, for_write);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
static void
|
|
249
|
+
ca_stack_mask_settle (CAStack *ca)
|
|
250
|
+
{
|
|
251
|
+
CAStack *o = (CAStack *) ca->mask_owner;
|
|
252
|
+
if ( o != NULL ) {
|
|
253
|
+
ca_multi_parent_mask_settle((CArray *) ca, o->parents, o->mask_standins,
|
|
254
|
+
o->n_parents);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
238
258
|
static void
|
|
239
259
|
ca_stack_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
240
260
|
{
|
|
241
261
|
CAStack *ca = (CAStack *) ap;
|
|
262
|
+
ca_stack_mask_refresh(ca, dir == CA_XFER_PUT);
|
|
242
263
|
int8_t k_axis = ca->k_axis;
|
|
243
264
|
ca_size_t k = idx[k_axis];
|
|
244
265
|
if ( k < 0 || k >= ca->n_parents ) {
|
|
245
266
|
rb_raise(rb_eIndexError, "CAStack k-axis (axis %d) index %lld out of range [0, %d)",
|
|
246
267
|
(int) k_axis, (long long) k, (int) ca->n_parents);
|
|
247
268
|
}
|
|
248
|
-
if ( k_axis == 0 ) {
|
|
269
|
+
if ( k_axis == 0 && ca_fast_paths_enabled() ) {
|
|
249
270
|
/* Fast path: parent_idx = idx[1..ndim-1]; pass idx+1 directly. */
|
|
250
271
|
ca_xfer_index(ca->parents[k], idx + 1, data, dir);
|
|
251
272
|
return;
|
|
@@ -274,6 +295,7 @@ ca_stack_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
274
295
|
void *data, int dir)
|
|
275
296
|
{
|
|
276
297
|
CAStack *ca = (CAStack *) ap;
|
|
298
|
+
ca_stack_mask_refresh(ca, dir == CA_XFER_PUT);
|
|
277
299
|
int8_t k_axis = ca->k_axis;
|
|
278
300
|
ca_size_t parent_elements = ca->parents[0]->elements;
|
|
279
301
|
ca_size_t bytes = ca->bytes;
|
|
@@ -286,7 +308,7 @@ ca_stack_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
286
308
|
paddrs = ALLOCV_N(ca_size_t, holder1, n);
|
|
287
309
|
pdata = ALLOCV_N(char, holder2, n * bytes);
|
|
288
310
|
|
|
289
|
-
if ( k_axis == 0 ) {
|
|
311
|
+
if ( k_axis == 0 && ca_fast_paths_enabled() ) {
|
|
290
312
|
/* Fast path: addr = k * parent_elements + parent_addr (row-major over
|
|
291
313
|
view shape with K at axis 0). */
|
|
292
314
|
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
@@ -398,7 +420,9 @@ static void
|
|
|
398
420
|
ca_stack_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
399
421
|
ca_size_t *strides, void *data, int dir)
|
|
400
422
|
{
|
|
423
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
401
424
|
CAStack *ca = (CAStack *) ap;
|
|
425
|
+
ca_stack_mask_refresh(ca, dir == CA_XFER_PUT);
|
|
402
426
|
int8_t k_axis = ca->k_axis;
|
|
403
427
|
int8_t pndim = ca->ndim - 1;
|
|
404
428
|
ca_size_t native[CA_RANK_MAX], dstride[CA_RANK_MAX];
|
|
@@ -419,19 +443,24 @@ ca_stack_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
419
443
|
s *= ca->parents[0]->dim[i];
|
|
420
444
|
}
|
|
421
445
|
|
|
422
|
-
/* Structural iff strides[k] == native[k] for all k
|
|
446
|
+
/* Structural iff strides[k] == native[k] for all k and the request is a
|
|
447
|
+
box over the view's own axes. Equal strides alone are not enough: a
|
|
448
|
+
size-1 axis gives two axes the same native stride, and a flat window
|
|
449
|
+
reshaped back to ndim has native strides yet wraps across an axis. The
|
|
450
|
+
request is over the view's addresses; see
|
|
451
|
+
ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
423
452
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
424
453
|
if ( strides[i] != native[i] ) { structural = 0; break; }
|
|
425
454
|
}
|
|
455
|
+
if ( structural &&
|
|
456
|
+
! ca_xfer_stride_request_is_axis_box(ca, starts, counts, strides) ) {
|
|
457
|
+
structural = 0;
|
|
458
|
+
}
|
|
459
|
+
if ( ! ca_fast_paths_enabled() ) structural = 0;
|
|
426
460
|
|
|
427
461
|
if ( structural ) {
|
|
428
462
|
ca_size_t k_lo = starts[k_axis];
|
|
429
463
|
ca_size_t k_hi = starts[k_axis] + counts[k_axis];
|
|
430
|
-
if ( k_lo < 0 || k_hi > ca->n_parents ) {
|
|
431
|
-
rb_raise(rb_eIndexError,
|
|
432
|
-
"CAStack xfer_stride k-axis (axis %d) [%lld, %lld) out of range [0, %d)",
|
|
433
|
-
(int) k_axis, (long long) k_lo, (long long) k_hi, (int) ca->n_parents);
|
|
434
|
-
}
|
|
435
464
|
|
|
436
465
|
/* dst row-major byte strides over output counts[]. */
|
|
437
466
|
s = ca->bytes;
|
|
@@ -518,7 +547,7 @@ ca_stack_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
518
547
|
with native[k_axis] removed, in order. */
|
|
519
548
|
{
|
|
520
549
|
int8_t p = -1;
|
|
521
|
-
int reloc =
|
|
550
|
+
int reloc = ca_fast_paths_enabled();
|
|
522
551
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
523
552
|
if ( strides[i] == native[k_axis] ) { p = i; break; }
|
|
524
553
|
}
|
|
@@ -538,16 +567,27 @@ ca_stack_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
538
567
|
if ( strides[i] != native[v] ) { reloc = 0; break; }
|
|
539
568
|
}
|
|
540
569
|
}
|
|
570
|
+
/* Each output axis must stay inside the view axis it was matched to;
|
|
571
|
+
otherwise the request wraps (or the match was one of two axes sharing
|
|
572
|
+
a native stride because the other has size 1), and only the per-cell
|
|
573
|
+
walk reads it correctly. */
|
|
574
|
+
if ( reloc ) {
|
|
575
|
+
for ( i = 0; i < ca->ndim; i++ ) {
|
|
576
|
+
int8_t j, v;
|
|
577
|
+
if ( counts[i] <= 1 ) continue;
|
|
578
|
+
if ( i == p ) {
|
|
579
|
+
v = k_axis;
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
j = (i < p) ? i : (i - 1);
|
|
583
|
+
v = (j < k_axis) ? j : (j + 1);
|
|
584
|
+
}
|
|
585
|
+
if ( starts[v] + counts[i] > ca->dim[v] ) { reloc = 0; break; }
|
|
586
|
+
}
|
|
587
|
+
}
|
|
541
588
|
if ( reloc ) {
|
|
542
|
-
ca_size_t kk_lo = starts[k_axis];
|
|
543
|
-
ca_size_t kk_hi = starts[k_axis] + counts[p];
|
|
544
589
|
ca_size_t odo[CA_RANK_MAX];
|
|
545
590
|
int8_t a;
|
|
546
|
-
if ( kk_lo < 0 || kk_hi > ca->n_parents ) {
|
|
547
|
-
rb_raise(rb_eIndexError,
|
|
548
|
-
"CAStack xfer_stride k-axis [%lld, %lld) out of range [0, %d)",
|
|
549
|
-
(long long) kk_lo, (long long) kk_hi, (int) ca->n_parents);
|
|
550
|
-
}
|
|
551
591
|
if ( p == ca->ndim - 1 ) {
|
|
552
592
|
/* K innermost: per-cell via the parent's xfer_index directly, escaping
|
|
553
593
|
the CAStack-level addr2index dispatch hop in the per-cell fallback. */
|
|
@@ -624,20 +664,34 @@ ca_stack_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
624
664
|
- k_axis != 0: per-parent contiguous read into a temp buffer, then
|
|
625
665
|
scattered-write to dst at view row-major positions. This is the
|
|
626
666
|
correctness path (per-parent contig-read / scattered-write), not a
|
|
627
|
-
perf-optimised one.
|
|
667
|
+
perf-optimised one.
|
|
668
|
+
|
|
669
|
+
into_buffers (PUT only) writes each parent's cells into the buffer its
|
|
670
|
+
attach handed out, rather than through the parent to what is behind it:
|
|
671
|
+
the sync of an attached stack, which then syncs each parent. Writing
|
|
672
|
+
past the buffer would leave it stale, and the parent's own sync would
|
|
673
|
+
push the stale buffer back over the cells just written. */
|
|
628
674
|
static void
|
|
629
|
-
|
|
675
|
+
ca_stack_xfer_parents (CAStack *ca, char *d, int dir, int into_buffers)
|
|
630
676
|
{
|
|
631
|
-
CAStack *ca = (CAStack *) ap;
|
|
632
677
|
int8_t k_axis = ca->k_axis;
|
|
633
678
|
ca_size_t bytes = ca->bytes;
|
|
634
|
-
char *d = (char *) data;
|
|
635
679
|
int32_t k;
|
|
636
680
|
|
|
637
|
-
|
|
681
|
+
/* The walk below visits a parent's first cell before it tests the
|
|
682
|
+
counts. */
|
|
683
|
+
if ( ca->elements == 0 ) return;
|
|
684
|
+
|
|
685
|
+
if ( k_axis == 0 && ca_fast_paths_enabled() ) {
|
|
638
686
|
ca_size_t parent_bytes_total = ca->parents[0]->elements * bytes;
|
|
639
687
|
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
640
|
-
|
|
688
|
+
if ( into_buffers ) {
|
|
689
|
+
memcpy(ca->parents[k]->ptr, d + k * parent_bytes_total,
|
|
690
|
+
(size_t) parent_bytes_total);
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
ca_xfer_all(ca->parents[k], d + k * parent_bytes_total, dir);
|
|
694
|
+
}
|
|
641
695
|
}
|
|
642
696
|
return;
|
|
643
697
|
}
|
|
@@ -725,7 +779,12 @@ ca_stack_func_xfer_all (void *ap, void *data, int dir)
|
|
|
725
779
|
}
|
|
726
780
|
|
|
727
781
|
if ( dir == CA_XFER_PUT ) {
|
|
728
|
-
|
|
782
|
+
if ( into_buffers ) {
|
|
783
|
+
memcpy(ca->parents[k]->ptr, buf, (size_t) (parent_elements * bytes));
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
ca_xfer_all(ca->parents[k], buf, CA_XFER_PUT);
|
|
787
|
+
}
|
|
729
788
|
}
|
|
730
789
|
}
|
|
731
790
|
}
|
|
@@ -733,6 +792,13 @@ ca_stack_func_xfer_all (void *ap, void *data, int dir)
|
|
|
733
792
|
}
|
|
734
793
|
}
|
|
735
794
|
|
|
795
|
+
static void
|
|
796
|
+
ca_stack_func_xfer_all (void *ap, void *data, int dir)
|
|
797
|
+
{
|
|
798
|
+
ca_stack_mask_refresh((CAStack *) ap, dir == CA_XFER_PUT);
|
|
799
|
+
ca_stack_xfer_parents((CAStack *) ap, (char *) data, dir, 0);
|
|
800
|
+
}
|
|
801
|
+
|
|
736
802
|
/* ------------------------------------------------------------------- */
|
|
737
803
|
/* attach / sync / detach (materialise via xfer_all) */
|
|
738
804
|
/* ------------------------------------------------------------------- */
|
|
@@ -741,28 +807,42 @@ static void
|
|
|
741
807
|
ca_stack_func_allocate (void *ap)
|
|
742
808
|
{
|
|
743
809
|
CAStack *ca = (CAStack *) ap;
|
|
810
|
+
ca_stack_mask_refresh(ca, 0);
|
|
744
811
|
ca_attach_all(ca->parents, ca->n_parents);
|
|
745
812
|
ca->ptr = xmalloc(ca_length(ca));
|
|
746
813
|
}
|
|
747
814
|
|
|
815
|
+
static VALUE
|
|
816
|
+
ca_stack_attach_owned (VALUE arg)
|
|
817
|
+
{
|
|
818
|
+
ca_axis_view_attach_owned((void *) arg);
|
|
819
|
+
return Qnil;
|
|
820
|
+
}
|
|
821
|
+
|
|
748
822
|
static void
|
|
749
823
|
ca_stack_func_attach (void *ap)
|
|
750
824
|
{
|
|
751
825
|
CAStack *ca = (CAStack *) ap;
|
|
826
|
+
ca_stack_mask_refresh(ca, 0);
|
|
827
|
+
int32_t k;
|
|
828
|
+
int tag = 0;
|
|
752
829
|
ca_attach_all(ca->parents, ca->n_parents);
|
|
753
|
-
|
|
754
|
-
|
|
830
|
+
rb_protect(ca_stack_attach_owned, (VALUE) ca, &tag);
|
|
831
|
+
if ( tag ) {
|
|
832
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
833
|
+
ca_detach(ca->parents[k]);
|
|
834
|
+
}
|
|
835
|
+
rb_jump_tag(tag);
|
|
836
|
+
}
|
|
755
837
|
}
|
|
756
838
|
|
|
757
839
|
static void
|
|
758
840
|
ca_stack_func_sync (void *ap)
|
|
759
841
|
{
|
|
760
842
|
CAStack *ca = (CAStack *) ap;
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
ca_sync(ca->parents[k]);
|
|
765
|
-
}
|
|
843
|
+
ca_stack_xfer_parents(ca, ca->ptr, CA_XFER_PUT, 1);
|
|
844
|
+
ca_sync_all(ca->parents, ca->n_parents);
|
|
845
|
+
ca_stack_mask_settle(ca);
|
|
766
846
|
}
|
|
767
847
|
|
|
768
848
|
static void
|
|
@@ -785,6 +865,7 @@ static void
|
|
|
785
865
|
ca_stack_func_fill_data (void *ap, void *ptr)
|
|
786
866
|
{
|
|
787
867
|
CAStack *ca = (CAStack *) ap;
|
|
868
|
+
ca_stack_mask_refresh(ca, 1);
|
|
788
869
|
int32_t k;
|
|
789
870
|
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
790
871
|
ca_fill(ca->parents[k], ptr);
|
|
@@ -792,12 +873,13 @@ ca_stack_func_fill_data (void *ap, void *ptr)
|
|
|
792
873
|
}
|
|
793
874
|
|
|
794
875
|
/* ------------------------------------------------------------------- */
|
|
795
|
-
/* create_mask
|
|
876
|
+
/* create_mask */
|
|
796
877
|
/* ------------------------------------------------------------------- */
|
|
797
878
|
|
|
798
|
-
/*
|
|
799
|
-
|
|
800
|
-
re-used as its own mask
|
|
879
|
+
/* The mask is a CAStack over the K parents' masks, a stand-in standing
|
|
880
|
+
for a parent that has none (ca_multi_parent_mask), so building it gives
|
|
881
|
+
no parent a mask. Self-similar (= CAStack re-used as its own mask
|
|
882
|
+
class). */
|
|
801
883
|
static void
|
|
802
884
|
ca_stack_func_create_mask (void *ap)
|
|
803
885
|
{
|
|
@@ -807,12 +889,13 @@ ca_stack_func_create_mask (void *ap)
|
|
|
807
889
|
int32_t k;
|
|
808
890
|
|
|
809
891
|
mask_parents = ALLOCV_N(CArray *, holder, ca->n_parents);
|
|
892
|
+
if ( ! ca->mask_standins ) {
|
|
893
|
+
ca->mask_standins = ALLOC_N(CArray *, ca->n_parents);
|
|
894
|
+
MEMZERO(ca->mask_standins, CArray *, ca->n_parents);
|
|
895
|
+
}
|
|
810
896
|
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
ca_create_mask(ca->parents[k]);
|
|
814
|
-
}
|
|
815
|
-
mask_parents[k] = ca->parents[k]->mask;
|
|
897
|
+
mask_parents[k] = ca_multi_parent_mask(ca->parents[k],
|
|
898
|
+
&ca->mask_standins[k]);
|
|
816
899
|
}
|
|
817
900
|
/* Build the mask stack with the parent's k_axis from the start so its
|
|
818
901
|
dim[] is laid out for that axis. (Patching ->k_axis after a default
|
|
@@ -821,6 +904,7 @@ ca_stack_func_create_mask (void *ap)
|
|
|
821
904
|
xfer_stride k-range check when k_axis != 0.) */
|
|
822
905
|
ca->mask = (CArray *) ca_stack_new_with_axis(ca->n_parents, mask_parents,
|
|
823
906
|
ca->k_axis);
|
|
907
|
+
((CAStack *) ca->mask)->mask_owner = (CArray *) ca;
|
|
824
908
|
ALLOCV_END(holder);
|
|
825
909
|
}
|
|
826
910
|
|
|
@@ -846,6 +930,13 @@ ca_stack_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
|
846
930
|
ca_size_t k;
|
|
847
931
|
int8_t i;
|
|
848
932
|
|
|
933
|
+
/* The mask of a stack while it still reads stand-ins: a write must
|
|
934
|
+
reach the stack's transfer, which replaces them first. */
|
|
935
|
+
if ( ca->mask_owner != NULL
|
|
936
|
+
&& ((CAStack *) ca->mask_owner)->mask_standins != NULL ) {
|
|
937
|
+
return 0;
|
|
938
|
+
}
|
|
939
|
+
|
|
849
940
|
/* k_axis != 0: parent byte blocks are interleaved (not contig in view
|
|
850
941
|
buffer), so the byte-box containment check and the size-1 K-axis
|
|
851
942
|
degeneration below would require detecting the K-axis contribution
|
|
@@ -854,6 +945,7 @@ ca_stack_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
|
854
945
|
through to CAStack.xfer_stride (k_axis-aware), which still delivers
|
|
855
946
|
correct (if non-folded) per-parent dispatch. */
|
|
856
947
|
if ( ca->k_axis != 0 ) return 0;
|
|
948
|
+
if ( ! ca_fast_paths_enabled() ) return 0;
|
|
857
949
|
|
|
858
950
|
for ( i = 0; i < f->ndim; i++ ) {
|
|
859
951
|
ca_size_t span = (f->counts[i] - 1) * f->strides[i];
|
|
@@ -876,6 +968,56 @@ ca_stack_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
|
876
968
|
/* operation table */
|
|
877
969
|
/* ------------------------------------------------------------------- */
|
|
878
970
|
|
|
971
|
+
/* The table's write slots: after a write, refuse a true that reached the
|
|
972
|
+
stand-in of a value array or a mask array (ca_multi_parent_mask_check).
|
|
973
|
+
Only the mask of a CAStack has stand-ins to check. */
|
|
974
|
+
static void
|
|
975
|
+
ca_stack_mask_check (CAStack *ca)
|
|
976
|
+
{
|
|
977
|
+
CAStack *o = (CAStack *) ca->mask_owner;
|
|
978
|
+
if ( o != NULL ) {
|
|
979
|
+
ca_multi_parent_mask_check((CArray *) ca, o->parents, o->mask_standins,
|
|
980
|
+
o->n_parents);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
static void
|
|
985
|
+
ca_stack_put_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
986
|
+
{
|
|
987
|
+
ca_stack_func_xfer_index(ap, idx, data, dir);
|
|
988
|
+
if ( dir == CA_XFER_PUT ) ca_stack_mask_check((CAStack *) ap);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
static void
|
|
992
|
+
ca_stack_put_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data,
|
|
993
|
+
int dir)
|
|
994
|
+
{
|
|
995
|
+
ca_stack_func_xfer_addrs(ap, n, addrs, data, dir);
|
|
996
|
+
if ( dir == CA_XFER_PUT ) ca_stack_mask_check((CAStack *) ap);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
static void
|
|
1000
|
+
ca_stack_put_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
1001
|
+
ca_size_t *strides, void *data, int dir)
|
|
1002
|
+
{
|
|
1003
|
+
ca_stack_func_xfer_stride(ap, starts, counts, strides, data, dir);
|
|
1004
|
+
if ( dir == CA_XFER_PUT ) ca_stack_mask_check((CAStack *) ap);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
static void
|
|
1008
|
+
ca_stack_put_xfer_all (void *ap, void *data, int dir)
|
|
1009
|
+
{
|
|
1010
|
+
ca_stack_func_xfer_all(ap, data, dir);
|
|
1011
|
+
if ( dir == CA_XFER_PUT ) ca_stack_mask_check((CAStack *) ap);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
static void
|
|
1015
|
+
ca_stack_put_fill_data (void *ap, void *ptr)
|
|
1016
|
+
{
|
|
1017
|
+
ca_stack_func_fill_data(ap, ptr);
|
|
1018
|
+
ca_stack_mask_check((CAStack *) ap);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
879
1021
|
ca_operation_function_t ca_stack_func = {
|
|
880
1022
|
-1, /* CA_OBJ_STACK */
|
|
881
1023
|
CA_VIEW_ARRAY,
|
|
@@ -885,13 +1027,13 @@ ca_operation_function_t ca_stack_func = {
|
|
|
885
1027
|
ca_stack_func_attach,
|
|
886
1028
|
ca_stack_func_sync,
|
|
887
1029
|
ca_stack_func_detach,
|
|
888
|
-
|
|
1030
|
+
ca_stack_put_fill_data,
|
|
889
1031
|
ca_stack_func_create_mask,
|
|
890
|
-
|
|
891
|
-
|
|
1032
|
+
ca_stack_put_xfer_index,
|
|
1033
|
+
ca_stack_put_xfer_addrs,
|
|
892
1034
|
ca_stack_func_fold_stride,
|
|
893
|
-
|
|
894
|
-
|
|
1035
|
+
ca_stack_put_xfer_stride,
|
|
1036
|
+
ca_stack_put_xfer_all,
|
|
895
1037
|
};
|
|
896
1038
|
|
|
897
1039
|
/* ------------------------------------------------------------------- */
|
|
@@ -935,7 +1077,7 @@ rb_ca_stack_new_with_axis (VALUE parents_ary, int8_t k_axis)
|
|
|
935
1077
|
ca = ca_stack_new_with_axis((int32_t) n, parents, k_axis);
|
|
936
1078
|
obj = ca_wrap_struct(ca);
|
|
937
1079
|
rb_ivar_set(obj, id_parents, rb_ary_dup(parents_ary)); /* GC anchor */
|
|
938
|
-
rb_ca_set_parent(obj,
|
|
1080
|
+
rb_ca_set_parent(obj, ca_face_strip_one(rb_ary_entry(parents_ary, 0))); /* CAView base (Face-stripped, matches C ->parent) */
|
|
939
1081
|
ALLOCV_END(holder);
|
|
940
1082
|
return obj;
|
|
941
1083
|
}
|
|
@@ -963,8 +1105,14 @@ rb_ca_stack_initialize_copy (VALUE self, VALUE other)
|
|
|
963
1105
|
{
|
|
964
1106
|
CAStack *ca, *cs;
|
|
965
1107
|
TypedData_Get_Struct(self, CAStack, &castack_data_type, ca);
|
|
1108
|
+
ca_check_uninitialized(ca);
|
|
966
1109
|
TypedData_Get_Struct(other, CAStack, &castack_data_type, cs);
|
|
967
1110
|
ca_stack_setup_with_axis(ca, cs->n_parents, cs->parents, cs->k_axis);
|
|
1111
|
+
/* A copy of a stack's mask reads and writes the same stand-ins, so it
|
|
1112
|
+
answers to the same owner: its writes reach the parents' masks. The
|
|
1113
|
+
copy holds the owner alive through the masked_array ivar that dup
|
|
1114
|
+
carries over (see rb_ca_mask_array). */
|
|
1115
|
+
ca->mask_owner = cs->mask_owner;
|
|
968
1116
|
return self;
|
|
969
1117
|
}
|
|
970
1118
|
|
|
@@ -1005,6 +1153,7 @@ rb_ca_stack_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1005
1153
|
NUM2LONG(axis_val), (int) ref->ndim + 1, "CAStack.new");
|
|
1006
1154
|
}
|
|
1007
1155
|
TypedData_Get_Struct(self, CAStack, &castack_data_type, ca);
|
|
1156
|
+
ca_check_uninitialized(ca);
|
|
1008
1157
|
parents = ALLOCV_N(CArray *, holder, n);
|
|
1009
1158
|
for ( i = 0; i < n; i++ ) {
|
|
1010
1159
|
VALUE p = rb_ary_entry(list, i);
|
|
@@ -1013,7 +1162,7 @@ rb_ca_stack_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1013
1162
|
}
|
|
1014
1163
|
ca_stack_setup_with_axis(ca, (int32_t) n, parents, k_axis);
|
|
1015
1164
|
rb_ivar_set(self, id_parents, rb_ary_dup(list)); /* GC anchor */
|
|
1016
|
-
rb_ca_set_parent(self,
|
|
1165
|
+
rb_ca_set_parent(self, ca_face_strip_one(rb_ary_entry(list, 0))); /* CAView base (Face-stripped, matches C ->parent) */
|
|
1017
1166
|
ALLOCV_END(holder);
|
|
1018
1167
|
return self;
|
|
1019
1168
|
}
|
|
@@ -1029,8 +1178,9 @@ rb_ca_stack_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1029
1178
|
this method)
|
|
1030
1179
|
- then ca_face_lift re-wraps the result as the same Face class,
|
|
1031
1180
|
carrying state from list[0]
|
|
1032
|
-
|
|
1033
|
-
|
|
1181
|
+
A single Face parent is lifted too. A list mixing Face and non-Face
|
|
1182
|
+
parents, or two Face classes, is refused; a non-Face list returns the
|
|
1183
|
+
raw CAStack (= same result as the inherited Class#new chain).
|
|
1034
1184
|
|
|
1035
1185
|
Replaces the Ruby-level CAStack.new override in lib/carray/compose.rb
|
|
1036
1186
|
(= used alias_method :__new_raw__, :new + class << self def new).
|
|
@@ -1039,68 +1189,23 @@ rb_ca_stack_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
1039
1189
|
static VALUE
|
|
1040
1190
|
rb_ca_stack_s_new (int argc, VALUE *argv, VALUE klass)
|
|
1041
1191
|
{
|
|
1042
|
-
VALUE list, kwargs;
|
|
1043
|
-
long n, i;
|
|
1044
|
-
int all_face = 1;
|
|
1045
|
-
VALUE face_class = Qnil;
|
|
1046
|
-
CArray *ref_face = NULL;
|
|
1192
|
+
VALUE list, kwargs, face_class;
|
|
1047
1193
|
VALUE obj;
|
|
1048
1194
|
|
|
1049
1195
|
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
1050
1196
|
Check_Type(list, T_ARRAY);
|
|
1051
|
-
|
|
1052
|
-
if ( n <= 0 ) {
|
|
1197
|
+
if ( RARRAY_LEN(list) <= 0 ) {
|
|
1053
1198
|
rb_raise(rb_eArgError, "CAStack.new requires at least one parent");
|
|
1054
1199
|
}
|
|
1200
|
+
face_class = ca_face_list_class(list, "CAStack.new");
|
|
1055
1201
|
|
|
1056
|
-
/*
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
VALUE p = rb_ary_entry(list, i);
|
|
1060
|
-
CArray *ca;
|
|
1061
|
-
rb_check_carray_object(p);
|
|
1062
|
-
TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
|
|
1063
|
-
if ( !ca_is_face(ca) ) { all_face = 0; break; }
|
|
1064
|
-
if ( i == 0 ) {
|
|
1065
|
-
face_class = rb_obj_class(p);
|
|
1066
|
-
ref_face = ca;
|
|
1067
|
-
} else if ( rb_obj_class(p) != face_class ) {
|
|
1068
|
-
all_face = 0; break;
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
/* Allocate + initialize raw CAStack. rb_obj_alloc calls the
|
|
1073
|
-
TypedData allocator directly (= bypasses the overridden Class#new,
|
|
1074
|
-
avoiding infinite recursion); rb_obj_call_init_kw dispatches to
|
|
1075
|
-
#initialize forwarding the kwargs hash (= Ruby 3.x strict kwarg
|
|
1076
|
-
separation requires the _kw variant when passing through). */
|
|
1202
|
+
/* rb_obj_alloc calls the TypedData allocator directly (= bypasses the
|
|
1203
|
+
overridden Class#new, avoiding infinite recursion); rb_obj_call_init_kw
|
|
1204
|
+
forwards the kwargs hash. */
|
|
1077
1205
|
obj = rb_obj_alloc(klass);
|
|
1078
1206
|
rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
|
1079
1207
|
|
|
1080
|
-
|
|
1081
|
-
if ( !all_face || n < 2 ) return obj;
|
|
1082
|
-
|
|
1083
|
-
/* Homogeneous Face: portable + pairwise state-compatible checks,
|
|
1084
|
-
then ca_face_lift to re-wrap as the same Face class. */
|
|
1085
|
-
if ( !ca_face_state_portable(ref_face->obj_type, face_class) ) {
|
|
1086
|
-
rb_raise(rb_eArgError,
|
|
1087
|
-
"CAStack.new: %s state is not portable across multiple "
|
|
1088
|
-
"parents (= per-parent storage like CAConstString's buffer); "
|
|
1089
|
-
"strip Face with .parent if a storage-level CAStack is intended",
|
|
1090
|
-
rb_class2name(face_class));
|
|
1091
|
-
}
|
|
1092
|
-
for ( i = 1; i < n; i++ ) {
|
|
1093
|
-
VALUE p = rb_ary_entry(list, i);
|
|
1094
|
-
CArray *ca;
|
|
1095
|
-
TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
|
|
1096
|
-
if ( !ca_face_state_compatible(rb_ary_entry(list, 0), ref_face,
|
|
1097
|
-
p, ca) ) {
|
|
1098
|
-
rb_raise(rb_eArgError,
|
|
1099
|
-
"CAStack.new: Face state mismatch across parents "
|
|
1100
|
-
"(= %s instance at index %ld differs in state from index 0)",
|
|
1101
|
-
rb_class2name(face_class), i);
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1208
|
+
if ( NIL_P(face_class) ) return obj;
|
|
1104
1209
|
return ca_face_lift(obj, rb_ary_entry(list, 0));
|
|
1105
1210
|
}
|
|
1106
1211
|
|