carray 3.0.2 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- 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 +104 -81
- 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 +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- 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/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -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 +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_core.c
CHANGED
|
@@ -323,12 +323,13 @@ ca_install_obj_type (VALUE klass,
|
|
|
323
323
|
const ca_operation_function_t *func,
|
|
324
324
|
size_t func_size)
|
|
325
325
|
{
|
|
326
|
-
int obj_type
|
|
326
|
+
int obj_type;
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
/* The obj_type parameters of ca_array_alloc / ca_stride_setup are
|
|
329
|
+
int8_t, so a number of 128 or above cannot be passed to them. */
|
|
330
|
+
if ( ca_obj_num > INT8_MAX || ca_obj_num + 1 >= CA_OBJ_TYPE_MAX ) {
|
|
329
331
|
rb_raise(rb_eRuntimeError,
|
|
330
|
-
"internal: too many CArray object types installed
|
|
331
|
-
CA_OBJ_TYPE_MAX);
|
|
332
|
+
"internal: too many CArray object types installed (an obj_type is numbered below 128)");
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
if ( func_size > sizeof(ca_operation_function_t) ) {
|
|
@@ -338,16 +339,20 @@ ca_install_obj_type (VALUE klass,
|
|
|
338
339
|
func_size, sizeof(ca_operation_function_t));
|
|
339
340
|
}
|
|
340
341
|
|
|
341
|
-
/*
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
342
|
+
/* xfer_index, xfer_addrs and xfer_all have no default, so the table
|
|
343
|
+
reaches through xfer_all; the slots after it fall back when NULL. */
|
|
344
|
+
if ( func_size < offsetof(ca_operation_function_t, xfer_all) +
|
|
345
|
+
sizeof(((ca_operation_function_t *) 0)->xfer_all) ) {
|
|
345
346
|
rb_raise(rb_eRuntimeError,
|
|
346
347
|
"operation table is too small to dispatch (%zu < %zu)",
|
|
347
348
|
func_size,
|
|
348
|
-
(size_t) offsetof(ca_operation_function_t,
|
|
349
|
+
(size_t) (offsetof(ca_operation_function_t, xfer_all) +
|
|
350
|
+
sizeof(((ca_operation_function_t *) 0)->xfer_all)));
|
|
349
351
|
}
|
|
350
352
|
|
|
353
|
+
/* A refused table takes no number. */
|
|
354
|
+
obj_type = ca_obj_num++;
|
|
355
|
+
|
|
351
356
|
/* Copy by the caller's length and zero the rest: slots this build knows
|
|
352
357
|
about but the caller does not are NULL, which every dispatcher already
|
|
353
358
|
reads as "not provided". */
|
|
@@ -425,7 +430,6 @@ ca_attach_is_alias (void *ap)
|
|
|
425
430
|
CArray *ca = (CArray *) ap;
|
|
426
431
|
extern ca_operation_function_t ca_stride_func;
|
|
427
432
|
extern ca_operation_function_t ca_lazy_marker_func;
|
|
428
|
-
extern int ca_stride_is_contiguous (CAStride *ca);
|
|
429
433
|
extern int ca_stride_attach_aliases_root (CAStride *ca);
|
|
430
434
|
|
|
431
435
|
if ( ca == NULL ) return 0;
|
|
@@ -440,21 +444,13 @@ ca_attach_is_alias (void *ap)
|
|
|
440
444
|
return ca_attach_is_alias(((CAView *) ca)->parent);
|
|
441
445
|
}
|
|
442
446
|
|
|
443
|
-
/* CAStride family share ca_stride_func.attach
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
chain is too (transitively, since each CAStride's strides are
|
|
449
|
-
composed against parent's), the alias path fires.
|
|
450
|
-
|
|
451
|
-
...and iff there is parent memory to alias at the end of that fold.
|
|
452
|
-
A non-entity root has none to lend, so attach builds its own buffer
|
|
453
|
-
and writes through ca->ptr reach the root only via ca_sync. Saying
|
|
454
|
-
"alias" there would let a caller write and skip the sync. */
|
|
447
|
+
/* CAStride family share ca_stride_func.attach, which aliases the root's
|
|
448
|
+
memory iff the strides composed to the root are row-major contiguous
|
|
449
|
+
and the root has memory to lend. Otherwise attach builds its own
|
|
450
|
+
buffer and writes through ca->ptr reach the root only via ca_sync, so
|
|
451
|
+
saying "alias" would let a caller write and skip the sync. */
|
|
455
452
|
if ( ca_func[ca->obj_type].attach == ca_stride_func.attach ) {
|
|
456
|
-
return
|
|
457
|
-
&& ca_stride_attach_aliases_root((CAStride *) ca);
|
|
453
|
+
return ca_stride_attach_aliases_root((CAStride *) ca);
|
|
458
454
|
}
|
|
459
455
|
return 0;
|
|
460
456
|
}
|
|
@@ -566,7 +562,7 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
|
|
|
566
562
|
ca_size_t bytes = ca_sizeof[data_type];
|
|
567
563
|
if ( bytes <= 0 ) {
|
|
568
564
|
rb_raise(rb_eArgError,
|
|
569
|
-
"rb_ca_new_reduced: data_type=%d
|
|
565
|
+
"rb_ca_new_reduced: data_type=%d has no fixed width (use rb_ca_new_reduced_bytes)",
|
|
570
566
|
(int) data_type);
|
|
571
567
|
}
|
|
572
568
|
return rb_ca_new_reduced_bytes(self, slab_axes, naxes, data_type, bytes, keep_axis);
|
|
@@ -574,9 +570,8 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
|
|
|
574
570
|
|
|
575
571
|
/* ------------------------------------------------------------------- */
|
|
576
572
|
|
|
577
|
-
/* Parse the variadic axis argument of a reduction kernel into
|
|
578
|
-
|
|
579
|
-
int8_t array, with full validation.
|
|
573
|
+
/* Parse the variadic axis argument of a reduction kernel into an int8_t
|
|
574
|
+
array, with full validation.
|
|
580
575
|
|
|
581
576
|
Accepts:
|
|
582
577
|
- Integer args: kernel(0, 2, 3) → axes = {0, 2, 3}
|
|
@@ -584,8 +579,9 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
|
|
|
584
579
|
- Negative axes (Python-style): -1 = innermost, normalised to
|
|
585
580
|
positive in-range indices before validation
|
|
586
581
|
|
|
582
|
+
argc == 0 means every axis (a full reduction).
|
|
583
|
+
|
|
587
584
|
Validation (raises ArgumentError on failure):
|
|
588
|
-
- argc == 0 → no axes given
|
|
589
585
|
- naxes > ca->ndim → too many axes
|
|
590
586
|
- any axis out of [0, ca->ndim) → range
|
|
591
587
|
- duplicate axes → duplicate
|
|
@@ -598,8 +594,12 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
|
|
|
598
594
|
to NUM2SIZE) of length `count`, normalises + range-checks + duplicate-
|
|
599
595
|
checks, fills out_axes[] in input order. Shared between the legacy
|
|
600
596
|
variadic entry (rb_ca_parse_reduce_axes) and the kwarg entry
|
|
601
|
-
(rb_ca_parse_reduce_axes_kw). ctx
|
|
602
|
-
|
|
597
|
+
(rb_ca_parse_reduce_axes_kw). ctx names the method in error messages;
|
|
598
|
+
the two public entries pass the method the user called. */
|
|
599
|
+
/* ctx NULL names the method the user called, looked up only when a
|
|
600
|
+
message is built: the lookup walks the frames. */
|
|
601
|
+
#define CA_CTX_NAME(ctx) ( (ctx) ? (ctx) : ca_calling_method_name() )
|
|
602
|
+
|
|
603
603
|
static int8_t
|
|
604
604
|
parse_axes_items (const VALUE *items, int count, CArray *ca,
|
|
605
605
|
int8_t *out_axes, const char *ctx)
|
|
@@ -608,31 +608,25 @@ parse_axes_items (const VALUE *items, int count, CArray *ca,
|
|
|
608
608
|
int8_t seen[CA_RANK_MAX];
|
|
609
609
|
|
|
610
610
|
if ( count <= 0 ) {
|
|
611
|
-
rb_raise(rb_eArgError, "%s: empty axes array", ctx);
|
|
611
|
+
rb_raise(rb_eArgError, "%s: empty axes array", CA_CTX_NAME(ctx));
|
|
612
612
|
}
|
|
613
|
-
if ( count > CA_RANK_MAX ) {
|
|
613
|
+
if ( count > CA_RANK_MAX ) { /* rank-check: a list of axes, no longer than the rank */
|
|
614
614
|
rb_raise(rb_eArgError,
|
|
615
615
|
"%s: too many axes (%d > CA_RANK_MAX=%d)",
|
|
616
|
-
ctx, count, CA_RANK_MAX);
|
|
616
|
+
CA_CTX_NAME(ctx), count, CA_RANK_MAX);
|
|
617
617
|
}
|
|
618
618
|
if ( count > ca->ndim ) {
|
|
619
619
|
rb_raise(rb_eArgError,
|
|
620
620
|
"%s: too many axes (%d > ndim=%d)",
|
|
621
|
-
ctx, count, (int) ca->ndim);
|
|
621
|
+
CA_CTX_NAME(ctx), count, (int) ca->ndim);
|
|
622
622
|
}
|
|
623
623
|
|
|
624
624
|
for ( i = 0; i < CA_RANK_MAX; i++ ) seen[i] = 0;
|
|
625
625
|
for ( i = 0; i < count; i++ ) {
|
|
626
|
-
ca_size_t a =
|
|
627
|
-
if ( a < 0 ) a += ca->ndim;
|
|
628
|
-
if ( a < 0 || a >= ca->ndim ) {
|
|
629
|
-
rb_raise(rb_eIndexError,
|
|
630
|
-
"%s: axis %ld out of range [0, %d)",
|
|
631
|
-
ctx, (long) a, (int) ca->ndim);
|
|
632
|
-
}
|
|
626
|
+
ca_size_t a = ca_normalize_axis_arg(items[i], (int) ca->ndim, ctx);
|
|
633
627
|
if ( seen[a] ) {
|
|
634
628
|
rb_raise(rb_eArgError,
|
|
635
|
-
"%s: duplicate axis %ld", ctx, (long) a);
|
|
629
|
+
"%s: duplicate axis %ld", CA_CTX_NAME(ctx), (long) a);
|
|
636
630
|
}
|
|
637
631
|
seen[a] = 1;
|
|
638
632
|
out_axes[i] = (int8_t) a;
|
|
@@ -665,8 +659,7 @@ rb_ca_parse_reduce_axes (int argc, VALUE *argv, CArray *ca, int8_t *out_axes)
|
|
|
665
659
|
items = (const VALUE *) RARRAY_CONST_PTR(arr);
|
|
666
660
|
}
|
|
667
661
|
|
|
668
|
-
return parse_axes_items(items, count, ca, out_axes,
|
|
669
|
-
"rb_ca_parse_reduce_axes");
|
|
662
|
+
return parse_axes_items(items, count, ca, out_axes, NULL);
|
|
670
663
|
}
|
|
671
664
|
|
|
672
665
|
/* Kwarg form of rb_ca_parse_reduce_axes — accepts the `axis:` value as
|
|
@@ -705,16 +698,15 @@ rb_ca_parse_reduce_axes_kw_ctx (VALUE axis_val, CArray *ca, int8_t *out_axes,
|
|
|
705
698
|
}
|
|
706
699
|
|
|
707
700
|
rb_raise(rb_eTypeError,
|
|
708
|
-
"%s: axis
|
|
709
|
-
"
|
|
710
|
-
ctx, rb_obj_class(axis_val));
|
|
701
|
+
"%s: axis must be nil, an Integer or an Array of Integer "
|
|
702
|
+
"(got %"PRIsVALUE")",
|
|
703
|
+
CA_CTX_NAME(ctx), rb_obj_class(axis_val));
|
|
711
704
|
}
|
|
712
705
|
|
|
713
706
|
int8_t
|
|
714
707
|
rb_ca_parse_reduce_axes_kw (VALUE axis_val, CArray *ca, int8_t *out_axes)
|
|
715
708
|
{
|
|
716
|
-
return rb_ca_parse_reduce_axes_kw_ctx(axis_val, ca, out_axes,
|
|
717
|
-
"rb_ca_parse_reduce_axes_kw");
|
|
709
|
+
return rb_ca_parse_reduce_axes_kw_ctx(axis_val, ca, out_axes, NULL);
|
|
718
710
|
}
|
|
719
711
|
|
|
720
712
|
/* ------------------------------------------------------------------- */
|
|
@@ -832,7 +824,7 @@ ca_set_cyclic_check(void *ap)
|
|
|
832
824
|
/* ca.data_type == CA_OBJECT */
|
|
833
825
|
if ( ca_is_object_type(ca) ) {
|
|
834
826
|
if ( ca->flags & CA_FLAG_CYCLE_CHECK ) {
|
|
835
|
-
rb_raise(
|
|
827
|
+
rb_raise(rb_eArgError, "cyclic reference is not allowed in CArray");
|
|
836
828
|
}
|
|
837
829
|
ca_set_flag(ca, CA_FLAG_CYCLE_CHECK);
|
|
838
830
|
}
|
|
@@ -860,12 +852,36 @@ ca_test_cyclic_check(void *ap, void *ptr)
|
|
|
860
852
|
CArray *cv;
|
|
861
853
|
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
862
854
|
if ( ca_test_flag(cv, CA_FLAG_CYCLE_CHECK) ) {
|
|
863
|
-
rb_raise(
|
|
855
|
+
rb_raise(rb_eArgError, "cyclic reference is not allowed in CArray");
|
|
864
856
|
}
|
|
865
857
|
}
|
|
866
858
|
}
|
|
867
859
|
}
|
|
868
860
|
|
|
861
|
+
/* Runs body(arg) -- one transfer of an object cell or cells -- with ca's
|
|
862
|
+
cycle check set, and clears the check however body leaves. Either
|
|
863
|
+
direction can call into Ruby: a GET through a CAObject slot or the
|
|
864
|
+
check of what it delivered, a PUT that converts the caller's value. A
|
|
865
|
+
raise that skipped the clear would leave every later access to ca
|
|
866
|
+
reporting a cyclic reference. A PUT into an entity only copies VALUEs
|
|
867
|
+
and cannot raise, so it runs unprotected. */
|
|
868
|
+
static void
|
|
869
|
+
ca_with_cyclic_check (CArray *ca, int dir, VALUE (*body)(VALUE), VALUE arg)
|
|
870
|
+
{
|
|
871
|
+
int state = 0;
|
|
872
|
+
ca_set_cyclic_check(ca);
|
|
873
|
+
if ( dir == CA_XFER_PUT && ca_is_entity(ca) ) {
|
|
874
|
+
body(arg);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
rb_protect(body, arg, &state);
|
|
878
|
+
}
|
|
879
|
+
ca_clear_cyclic_check(ca);
|
|
880
|
+
if ( state ) {
|
|
881
|
+
rb_jump_tag(state);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
869
885
|
/* ------------------------------------------------------------------- */
|
|
870
886
|
/* CArray offers no per-cell ptr accessor (ca_ptr_at_addr /
|
|
871
887
|
ca_ptr_at_index): such a slot is structurally unsafe -- CABitarray /
|
|
@@ -911,14 +927,17 @@ struct ca_xfer_index_args {
|
|
|
911
927
|
CArray *ca;
|
|
912
928
|
ca_size_t *idx;
|
|
913
929
|
char *ptr;
|
|
930
|
+
int dir;
|
|
914
931
|
};
|
|
915
932
|
|
|
916
933
|
static VALUE
|
|
917
|
-
|
|
934
|
+
ca_xfer_index_body (VALUE arg)
|
|
918
935
|
{
|
|
919
936
|
struct ca_xfer_index_args *d = (struct ca_xfer_index_args *) arg;
|
|
920
|
-
ca_xfer_index_dispatch(d->ca, d->idx, d->ptr,
|
|
921
|
-
|
|
937
|
+
ca_xfer_index_dispatch(d->ca, d->idx, d->ptr, d->dir);
|
|
938
|
+
if ( d->dir == CA_XFER_GET ) {
|
|
939
|
+
ca_test_cyclic_check(d->ca, d->ptr);
|
|
940
|
+
}
|
|
922
941
|
return Qnil;
|
|
923
942
|
}
|
|
924
943
|
|
|
@@ -928,7 +947,7 @@ ca_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
928
947
|
CArray *ca = (CArray *) ap;
|
|
929
948
|
|
|
930
949
|
if ( dir == CA_XFER_PUT && ca_is_readonly(ca) ) {
|
|
931
|
-
|
|
950
|
+
ca_refuse_read_only();
|
|
932
951
|
}
|
|
933
952
|
|
|
934
953
|
/* Fast path: non-CA_OBJECT element type needs no GC protection. */
|
|
@@ -937,24 +956,14 @@ ca_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
937
956
|
return;
|
|
938
957
|
}
|
|
939
958
|
|
|
940
|
-
/* CA_OBJECT slow path: cyclic check
|
|
941
|
-
|
|
959
|
+
/* CA_OBJECT slow path: cyclic check. */
|
|
960
|
+
{
|
|
942
961
|
struct ca_xfer_index_args args;
|
|
943
|
-
int state = 0;
|
|
944
962
|
args.ca = ca;
|
|
945
963
|
args.idx = idx;
|
|
946
964
|
args.ptr = (char *) data;
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
ca_clear_cyclic_check(ca);
|
|
950
|
-
if ( state ) {
|
|
951
|
-
rb_jump_tag(state);
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
else {
|
|
955
|
-
ca_set_cyclic_check(ca);
|
|
956
|
-
ca_xfer_index_dispatch(ca, idx, data, CA_XFER_PUT);
|
|
957
|
-
ca_clear_cyclic_check(ca);
|
|
965
|
+
args.dir = dir;
|
|
966
|
+
ca_with_cyclic_check(ca, dir, ca_xfer_index_body, (VALUE) &args);
|
|
958
967
|
}
|
|
959
968
|
}
|
|
960
969
|
|
|
@@ -1043,16 +1052,19 @@ struct ca_xfer_addrs_args {
|
|
|
1043
1052
|
ca_size_t n;
|
|
1044
1053
|
ca_size_t *addrs;
|
|
1045
1054
|
char *data;
|
|
1055
|
+
int dir;
|
|
1046
1056
|
};
|
|
1047
1057
|
|
|
1048
1058
|
static VALUE
|
|
1049
|
-
|
|
1059
|
+
ca_xfer_addrs_body (VALUE arg)
|
|
1050
1060
|
{
|
|
1051
1061
|
struct ca_xfer_addrs_args *d = (struct ca_xfer_addrs_args *) arg;
|
|
1052
1062
|
ca_size_t i;
|
|
1053
|
-
ca_xfer_addrs_dispatch(d->ca, d->n, d->addrs, d->data,
|
|
1054
|
-
|
|
1055
|
-
|
|
1063
|
+
ca_xfer_addrs_dispatch(d->ca, d->n, d->addrs, d->data, d->dir);
|
|
1064
|
+
if ( d->dir == CA_XFER_GET ) {
|
|
1065
|
+
for ( i = 0; i < d->n; i++ ) {
|
|
1066
|
+
ca_test_cyclic_check(d->ca, d->data + i * d->ca->bytes);
|
|
1067
|
+
}
|
|
1056
1068
|
}
|
|
1057
1069
|
return Qnil;
|
|
1058
1070
|
}
|
|
@@ -1063,7 +1075,7 @@ ca_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data, int dir)
|
|
|
1063
1075
|
CArray *ca = (CArray *) ap;
|
|
1064
1076
|
|
|
1065
1077
|
if ( dir == CA_XFER_PUT && ca_is_readonly(ca) ) {
|
|
1066
|
-
|
|
1078
|
+
ca_refuse_read_only();
|
|
1067
1079
|
}
|
|
1068
1080
|
|
|
1069
1081
|
/* Fast path: non-CA_OBJECT element type needs no GC protection. */
|
|
@@ -1072,25 +1084,15 @@ ca_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data, int dir)
|
|
|
1072
1084
|
return;
|
|
1073
1085
|
}
|
|
1074
1086
|
|
|
1075
|
-
/* CA_OBJECT slow path: cyclic check
|
|
1076
|
-
|
|
1087
|
+
/* CA_OBJECT slow path: cyclic check. */
|
|
1088
|
+
{
|
|
1077
1089
|
struct ca_xfer_addrs_args args;
|
|
1078
|
-
int state = 0;
|
|
1079
1090
|
args.ca = ca;
|
|
1080
1091
|
args.n = n;
|
|
1081
1092
|
args.addrs = addrs;
|
|
1082
1093
|
args.data = (char *) data;
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
ca_clear_cyclic_check(ca);
|
|
1086
|
-
if ( state ) {
|
|
1087
|
-
rb_jump_tag(state);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
else {
|
|
1091
|
-
ca_set_cyclic_check(ca);
|
|
1092
|
-
ca_xfer_addrs_dispatch(ca, n, addrs, data, CA_XFER_PUT);
|
|
1093
|
-
ca_clear_cyclic_check(ca);
|
|
1094
|
+
args.dir = dir;
|
|
1095
|
+
ca_with_cyclic_check(ca, dir, ca_xfer_addrs_body, (VALUE) &args);
|
|
1094
1096
|
}
|
|
1095
1097
|
}
|
|
1096
1098
|
|
|
@@ -1335,6 +1337,8 @@ ca_xfer_strided_walk (char *src_base,
|
|
|
1335
1337
|
ca_size_t doff = 0;
|
|
1336
1338
|
int8_t k;
|
|
1337
1339
|
|
|
1340
|
+
if ( ca_region_is_empty(ndim, counts) ) return;
|
|
1341
|
+
|
|
1338
1342
|
/* slab merge -- scan innermost contig run (src_strides[k] equals the
|
|
1339
1343
|
accumulated slab byte size). This collapses per-cell memcpy(_,_,
|
|
1340
1344
|
bytes) loops into per-slab memcpy when the source region is row-major
|
|
@@ -1373,6 +1377,7 @@ ca_xfer_strided_walk (char *src_base,
|
|
|
1373
1377
|
ca_size_t inner_dst_bytes = counts[ndim-2] * counts[ndim-1] * bytes;
|
|
1374
1378
|
|
|
1375
1379
|
for ( k = 0; k < outer_n; k++ ) idx[k] = 0;
|
|
1380
|
+
/* empty: the walk returns on an empty region at its entry */
|
|
1376
1381
|
while ( 1 ) {
|
|
1377
1382
|
ca_size_t soff = 0;
|
|
1378
1383
|
for ( k = 0; k < outer_n; k++ ) soff += idx[k] * src_strides[k];
|
|
@@ -1390,6 +1395,7 @@ ca_xfer_strided_walk (char *src_base,
|
|
|
1390
1395
|
|
|
1391
1396
|
/* prefix axes [0..slab_start-1] on odometer, slab-sized memcpy per iter. */
|
|
1392
1397
|
for ( k = 0; k < slab_start; k++ ) idx[k] = 0;
|
|
1398
|
+
/* empty: the walk returns on an empty region at its entry */
|
|
1393
1399
|
while ( 1 ) {
|
|
1394
1400
|
ca_size_t soff = 0;
|
|
1395
1401
|
for ( k = 0; k < slab_start; k++ ) soff += idx[k] * src_strides[k];
|
|
@@ -1463,6 +1469,7 @@ ca_xfer_stride_dispatch (CArray *ca, ca_size_t *starts, ca_size_t *counts,
|
|
|
1463
1469
|
|
|
1464
1470
|
/* fallback: per-cell via byte offset -> flat addr -> index -> xfer_index. */
|
|
1465
1471
|
for ( k = 0; k < ndim; k++ ) idx[k] = 0;
|
|
1472
|
+
/* empty: its one caller, ca_xfer_stride, returns on an empty region */
|
|
1466
1473
|
while ( 1 ) {
|
|
1467
1474
|
ca_size_t soff = base, vidx[CA_RANK_MAX];
|
|
1468
1475
|
for ( k = 0; k < ndim; k++ ) soff += idx[k] * strides[k];
|
|
@@ -1481,16 +1488,20 @@ struct ca_xfer_stride_args {
|
|
|
1481
1488
|
ca_size_t *counts;
|
|
1482
1489
|
ca_size_t *strides;
|
|
1483
1490
|
char *data;
|
|
1491
|
+
int dir;
|
|
1484
1492
|
};
|
|
1485
1493
|
|
|
1486
1494
|
static VALUE
|
|
1487
|
-
|
|
1495
|
+
ca_xfer_stride_body (VALUE arg)
|
|
1488
1496
|
{
|
|
1489
1497
|
struct ca_xfer_stride_args *a = (struct ca_xfer_stride_args *) arg;
|
|
1490
1498
|
ca_size_t n = 1, i;
|
|
1491
1499
|
int8_t k;
|
|
1492
1500
|
ca_xfer_stride_dispatch(a->ca, a->starts, a->counts, a->strides, a->data,
|
|
1493
|
-
|
|
1501
|
+
a->dir);
|
|
1502
|
+
if ( a->dir != CA_XFER_GET ) {
|
|
1503
|
+
return Qnil;
|
|
1504
|
+
}
|
|
1494
1505
|
/* cyclic check over the delivered cells (CA_OBJECT only). dst is contiguous
|
|
1495
1506
|
row-major over counts (semantics b), so cell i is at data + i*bytes. */
|
|
1496
1507
|
for ( k = 0; k < a->ca->ndim; k++ ) n *= a->counts[k];
|
|
@@ -1507,28 +1518,21 @@ ca_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
1507
1518
|
CArray *ca = (CArray *) ap;
|
|
1508
1519
|
|
|
1509
1520
|
if ( dir == CA_XFER_PUT && ca_is_readonly(ca) ) {
|
|
1510
|
-
|
|
1521
|
+
ca_refuse_read_only();
|
|
1511
1522
|
}
|
|
1512
1523
|
|
|
1524
|
+
if ( ca_region_is_empty(ca->ndim, counts) ) return;
|
|
1525
|
+
|
|
1513
1526
|
if ( ca->data_type != CA_OBJECT ) {
|
|
1514
1527
|
ca_xfer_stride_dispatch(ca, starts, counts, strides, data, dir);
|
|
1515
1528
|
return;
|
|
1516
1529
|
}
|
|
1517
1530
|
|
|
1518
|
-
|
|
1531
|
+
{
|
|
1519
1532
|
struct ca_xfer_stride_args args;
|
|
1520
|
-
int state = 0;
|
|
1521
1533
|
args.ca = ca; args.starts = starts; args.counts = counts;
|
|
1522
|
-
args.strides = strides; args.data = (char *) data;
|
|
1523
|
-
|
|
1524
|
-
rb_protect(ca_xfer_stride_get_body, (VALUE) &args, &state);
|
|
1525
|
-
ca_clear_cyclic_check(ca);
|
|
1526
|
-
if ( state ) rb_jump_tag(state);
|
|
1527
|
-
}
|
|
1528
|
-
else {
|
|
1529
|
-
ca_set_cyclic_check(ca);
|
|
1530
|
-
ca_xfer_stride_dispatch(ca, starts, counts, strides, data, CA_XFER_PUT);
|
|
1531
|
-
ca_clear_cyclic_check(ca);
|
|
1534
|
+
args.strides = strides; args.data = (char *) data; args.dir = dir;
|
|
1535
|
+
ca_with_cyclic_check(ca, dir, ca_xfer_stride_body, (VALUE) &args);
|
|
1532
1536
|
}
|
|
1533
1537
|
}
|
|
1534
1538
|
|
|
@@ -1580,6 +1584,10 @@ ca_xfer_all (void *ap, void *data, int dir)
|
|
|
1580
1584
|
"[BUG] xfer_all not defined for object type <%i>",
|
|
1581
1585
|
ca->obj_type);
|
|
1582
1586
|
}
|
|
1587
|
+
/* An empty view moves nothing; see ca_xfer_stride. */
|
|
1588
|
+
if ( ca->elements == 0 ) {
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1583
1591
|
/* Universal arena lifetime hook. ca_xfer_all is the single universal
|
|
1584
1592
|
entry for materialise (to_ca -> ca_copy -> ca_copy_data ->
|
|
1585
1593
|
ca_xfer_all), so wrapping here covers every outermost view type,
|
|
@@ -1603,9 +1611,7 @@ ca_xfer_all (void *ap, void *data, int dir)
|
|
|
1603
1611
|
written by nested transfers land inside it. */
|
|
1604
1612
|
if ( ca->data_type == CA_OBJECT && dir == CA_XFER_GET ) {
|
|
1605
1613
|
if ( data != (void *) ca->ptr ) {
|
|
1606
|
-
|
|
1607
|
-
ca_size_t i;
|
|
1608
|
-
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
1614
|
+
ca_object_cells_clear(data, ca->elements);
|
|
1609
1615
|
}
|
|
1610
1616
|
guard = ca_gc_hold_push(data, ca->elements);
|
|
1611
1617
|
}
|
|
@@ -1615,8 +1621,83 @@ ca_xfer_all (void *ap, void *data, int dir)
|
|
|
1615
1621
|
|
|
1616
1622
|
/* ------------------------------------------------------------------- */
|
|
1617
1623
|
|
|
1624
|
+
/* What follows the slot in ca_allocate: the object cells cleared, then the
|
|
1625
|
+
mask. Clearing the mask can create it, which for a CAObject calls Ruby.
|
|
1626
|
+
mask0 is the mask the array had before; see ca_attach_view_first. */
|
|
1627
|
+
static void
|
|
1628
|
+
ca_allocate_rest (CArray *ca, CArray *mask0)
|
|
1629
|
+
{
|
|
1630
|
+
if ( ca->data_type == CA_OBJECT ) { /* protection against GC */
|
|
1631
|
+
volatile VALUE rzero = INT2NUM(0);
|
|
1632
|
+
VALUE *p = (VALUE*)ca->ptr;
|
|
1633
|
+
ca_size_t i;
|
|
1634
|
+
for (i=0; i<ca->elements; i++) {
|
|
1635
|
+
*p++ = rzero;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
ca_clear_mask(ca); /* ca_update_mask called in ca_clear_mask */
|
|
1640
|
+
if ( ca->mask == mask0 ) {
|
|
1641
|
+
ca_allocate(ca->mask);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/* The view half of ca_allocate, after the attach level is taken. Run
|
|
1646
|
+
under rb_protect by ca_allocate. */
|
|
1647
|
+
static VALUE
|
|
1648
|
+
ca_allocate_view (VALUE arg)
|
|
1649
|
+
{
|
|
1650
|
+
CArray *ca = (CArray *) arg;
|
|
1651
|
+
CArray *mask0 = ca->mask;
|
|
1652
|
+
if ( ! ca->ptr ) {
|
|
1653
|
+
ca_func[ca->obj_type].allocate(ca);
|
|
1654
|
+
}
|
|
1655
|
+
ca_allocate_rest(ca, mask0);
|
|
1656
|
+
return Qnil;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1618
1659
|
/* make ca->ptr to point the allocated memory block */
|
|
1619
1660
|
|
|
1661
|
+
/* Steps a view's attach level by d. A development build also counts the
|
|
1662
|
+
views whose level is above zero, and the spec compares that count
|
|
1663
|
+
before and after every test: a window left open shows as a view that
|
|
1664
|
+
stays counted. */
|
|
1665
|
+
#ifdef CARRAY_DEV_BUILD
|
|
1666
|
+
static long ca_attached_views = 0;
|
|
1667
|
+
|
|
1668
|
+
#define CA_VIEW_ATTACH_STEP(ca, d) do { \
|
|
1669
|
+
uint32_t attach_before_ = CAVIEW(ca)->attach; \
|
|
1670
|
+
CAVIEW(ca)->attach += (d); \
|
|
1671
|
+
__atomic_add_fetch(&ca_attached_views, \
|
|
1672
|
+
( CAVIEW(ca)->attach > 0 ) - ( attach_before_ > 0 ), \
|
|
1673
|
+
__ATOMIC_RELAXED); \
|
|
1674
|
+
} while (0)
|
|
1675
|
+
|
|
1676
|
+
static VALUE
|
|
1677
|
+
rb_ca_s_attached_views (VALUE klass)
|
|
1678
|
+
{
|
|
1679
|
+
return LONG2NUM(__atomic_load_n(&ca_attached_views, __ATOMIC_RELAXED));
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/* Set once at load from CARRAY_GENERAL_PATH; see carray_internal.h. */
|
|
1683
|
+
int ca_fast_paths_on = 1;
|
|
1684
|
+
int ca_iter_transfer_only_on = 0;
|
|
1685
|
+
|
|
1686
|
+
static VALUE
|
|
1687
|
+
rb_ca_s_fast_paths_enabled (VALUE klass)
|
|
1688
|
+
{
|
|
1689
|
+
return ca_fast_paths_on ? Qtrue : Qfalse;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
static VALUE
|
|
1693
|
+
rb_ca_s_iter_by_transfer_only (VALUE klass)
|
|
1694
|
+
{
|
|
1695
|
+
return ca_iter_transfer_only_on ? Qtrue : Qfalse;
|
|
1696
|
+
}
|
|
1697
|
+
#else
|
|
1698
|
+
#define CA_VIEW_ATTACH_STEP(ca, d) ( CAVIEW(ca)->attach += (d) )
|
|
1699
|
+
#endif
|
|
1700
|
+
|
|
1620
1701
|
void
|
|
1621
1702
|
ca_allocate (void *ap)
|
|
1622
1703
|
{
|
|
@@ -1628,31 +1709,36 @@ ca_allocate (void *ap)
|
|
|
1628
1709
|
|
|
1629
1710
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1630
1711
|
|
|
1631
|
-
CAVIEW(ca)->attach
|
|
1632
|
-
if ( CAVIEW(ca)->attach > CA_ATTACH_MAX ) {
|
|
1712
|
+
if ( CAVIEW(ca)->attach >= CA_ATTACH_MAX ) {
|
|
1633
1713
|
rb_raise(rb_eRuntimeError,
|
|
1634
1714
|
"too large attach count of view array");
|
|
1635
1715
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1716
|
+
CA_VIEW_ATTACH_STEP(ca, 1); /* increments attach level */
|
|
1717
|
+
|
|
1718
|
+
/* Undo the level if the slot or the mask raises, as ca_attach does.
|
|
1719
|
+
Left in place, the level is invisible while ptr is NULL, and the
|
|
1720
|
+
next attach / detach pair then leaves the view attached for good.
|
|
1721
|
+
A slot that got as far as publishing ca->ptr has taken what its
|
|
1722
|
+
detach slot releases; one that raised earlier has published
|
|
1723
|
+
nothing. */
|
|
1724
|
+
{
|
|
1725
|
+
char *ptr0 = ca->ptr;
|
|
1726
|
+
int tag = 0;
|
|
1727
|
+
rb_protect(ca_allocate_view, (VALUE) ca, &tag);
|
|
1728
|
+
if ( tag ) {
|
|
1729
|
+
if ( ! ptr0 && ca->ptr ) {
|
|
1730
|
+
ca_func[ca->obj_type].detach(ca);
|
|
1731
|
+
ca->ptr = NULL;
|
|
1732
|
+
}
|
|
1733
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1734
|
+
rb_jump_tag(tag);
|
|
1735
|
+
}
|
|
1639
1736
|
}
|
|
1640
1737
|
}
|
|
1641
1738
|
else { /* entity array */
|
|
1642
1739
|
ca_func[ca->obj_type].allocate(ap);
|
|
1740
|
+
ca_allocate_rest(ca, ca->mask); /* an entity's new mask is not yet allocated */
|
|
1643
1741
|
}
|
|
1644
|
-
|
|
1645
|
-
if ( ca->data_type == CA_OBJECT ) { /* protection against GC */
|
|
1646
|
-
volatile VALUE rzero = INT2NUM(0);
|
|
1647
|
-
VALUE *p = (VALUE*)ca->ptr;
|
|
1648
|
-
ca_size_t i;
|
|
1649
|
-
for (i=0; i<ca->elements; i++) {
|
|
1650
|
-
*p++ = rzero;
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
ca_clear_mask(ca); /* ca_update_mask called in ca_clear_mask */
|
|
1655
|
-
ca_allocate(ca->mask);
|
|
1656
1742
|
}
|
|
1657
1743
|
|
|
1658
1744
|
/* The first attach of a view: materialise through the type's slot, then
|
|
@@ -1660,10 +1746,33 @@ ca_allocate (void *ap)
|
|
|
1660
1746
|
static VALUE
|
|
1661
1747
|
ca_attach_view_first (VALUE arg)
|
|
1662
1748
|
{
|
|
1663
|
-
CArray *ca
|
|
1749
|
+
CArray *ca = (CArray *) arg;
|
|
1750
|
+
CArray *mask0 = ca->mask;
|
|
1751
|
+
/* The mask moves in step with its view: attach, allocate and detach
|
|
1752
|
+
each take it one level with the view. A mask created here -- by the
|
|
1753
|
+
slot (a CAObject makes its mask while it attaches) or by
|
|
1754
|
+
ca_update_mask -- is already at the view's level, since
|
|
1755
|
+
ca_create_mask attaches a new mask to match an attached view. So
|
|
1756
|
+
only a mask that was there before the slot takes the step; stepping a
|
|
1757
|
+
new one too leaves it a level above the view, still attached after
|
|
1758
|
+
the view's last detach. */
|
|
1664
1759
|
ca_func[ca->obj_type].attach(ca);
|
|
1665
1760
|
ca_update_mask(ca);
|
|
1666
|
-
|
|
1761
|
+
if ( ca->mask == mask0 ) {
|
|
1762
|
+
ca_attach(ca->mask);
|
|
1763
|
+
}
|
|
1764
|
+
return Qnil;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
static VALUE
|
|
1768
|
+
ca_attach_mask_step (VALUE arg)
|
|
1769
|
+
{
|
|
1770
|
+
CArray *ca = (CArray *) arg;
|
|
1771
|
+
CArray *mask0 = ca->mask;
|
|
1772
|
+
ca_update_mask(ca);
|
|
1773
|
+
if ( ca->mask == mask0 ) { /* see ca_attach_view_first */
|
|
1774
|
+
ca_attach(ca->mask);
|
|
1775
|
+
}
|
|
1667
1776
|
return Qnil;
|
|
1668
1777
|
}
|
|
1669
1778
|
|
|
@@ -1684,7 +1793,7 @@ ca_attach (void *ap)
|
|
|
1684
1793
|
rb_raise(rb_eRuntimeError,
|
|
1685
1794
|
"too large attach count of view array");
|
|
1686
1795
|
}
|
|
1687
|
-
|
|
1796
|
+
CA_VIEW_ATTACH_STEP(ca, 1); /* increments attach level */
|
|
1688
1797
|
|
|
1689
1798
|
if ( ! ca->ptr ) {
|
|
1690
1799
|
/* A slot can raise part way (a conversion meeting a value it cannot
|
|
@@ -1700,7 +1809,7 @@ ca_attach (void *ap)
|
|
|
1700
1809
|
ca_func[ca->obj_type].detach(ca);
|
|
1701
1810
|
ca->ptr = NULL;
|
|
1702
1811
|
}
|
|
1703
|
-
|
|
1812
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1704
1813
|
rb_jump_tag(tag);
|
|
1705
1814
|
}
|
|
1706
1815
|
return;
|
|
@@ -1710,8 +1819,21 @@ ca_attach (void *ap)
|
|
|
1710
1819
|
ca_func[ca->obj_type].attach(ap);
|
|
1711
1820
|
}
|
|
1712
1821
|
|
|
1713
|
-
|
|
1714
|
-
|
|
1822
|
+
{
|
|
1823
|
+
/* Making the mask can raise (a CAObject's mask hooks); the attach
|
|
1824
|
+
taken above is given back then. */
|
|
1825
|
+
int tag = 0;
|
|
1826
|
+
rb_protect(ca_attach_mask_step, (VALUE) ca, &tag);
|
|
1827
|
+
if ( tag ) {
|
|
1828
|
+
if ( ca_is_view(ca) ) {
|
|
1829
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1830
|
+
}
|
|
1831
|
+
else {
|
|
1832
|
+
ca_func[ca->obj_type].detach(ap);
|
|
1833
|
+
}
|
|
1834
|
+
rb_jump_tag(tag);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1715
1837
|
}
|
|
1716
1838
|
|
|
1717
1839
|
/* Attach every array in list[0..n-1], or, if one of those attaches
|
|
@@ -1751,7 +1873,226 @@ ca_attach_all (CArray **list, int32_t n)
|
|
|
1751
1873
|
}
|
|
1752
1874
|
}
|
|
1753
1875
|
|
|
1754
|
-
|
|
1876
|
+
static VALUE
|
|
1877
|
+
ca_sync_all_step (VALUE arg)
|
|
1878
|
+
{
|
|
1879
|
+
ca_sync((void *) arg);
|
|
1880
|
+
return Qnil;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
/* Syncs every one of list[0..n-1] in turn, carrying on past one that
|
|
1884
|
+
raises so that the others still receive what was written, then raises
|
|
1885
|
+
the first exception. A throw or break cannot wait, and goes at once. */
|
|
1886
|
+
void
|
|
1887
|
+
ca_sync_all (CArray **list, int32_t n)
|
|
1888
|
+
{
|
|
1889
|
+
volatile VALUE error = Qnil;
|
|
1890
|
+
int32_t k;
|
|
1891
|
+
for ( k = 0; k < n; k++ ) {
|
|
1892
|
+
int tag = 0;
|
|
1893
|
+
rb_protect(ca_sync_all_step, (VALUE) list[k], &tag);
|
|
1894
|
+
if ( tag ) {
|
|
1895
|
+
VALUE err = rb_errinfo();
|
|
1896
|
+
if ( ! RTEST(rb_obj_is_kind_of(err, rb_eException)) ) {
|
|
1897
|
+
rb_jump_tag(tag);
|
|
1898
|
+
}
|
|
1899
|
+
if ( NIL_P(error) ) {
|
|
1900
|
+
error = err;
|
|
1901
|
+
}
|
|
1902
|
+
rb_set_errinfo(Qnil);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
if ( ! NIL_P(error) ) {
|
|
1906
|
+
rb_exc_raise(error);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
/* An attach window over list[0..n-1] that closes however body leaves.
|
|
1911
|
+
|
|
1912
|
+
modes holds one letter per array:
|
|
1913
|
+
'r' attach; detach on close
|
|
1914
|
+
'w' attach; sync, then detach on close
|
|
1915
|
+
'a' allocate (write only); sync, then detach on close
|
|
1916
|
+
|
|
1917
|
+
Opening takes all of the arrays or none. Closing syncs the 'w' arrays
|
|
1918
|
+
even when body raised or broke out -- the cells body wrote reach the
|
|
1919
|
+
parent, as they would for an entity, which has no separate buffer. An
|
|
1920
|
+
'a' array is not synced after a raise: allocate did not gather, so its
|
|
1921
|
+
cells body never wrote hold nothing faithful to push back. Allocate
|
|
1922
|
+
clears the mask as it opens, and an entity (or the parent under a view)
|
|
1923
|
+
has no separate mask to fall back on, so the mask of an 'a' array is
|
|
1924
|
+
copied before it opens and written back when body raises.
|
|
1925
|
+
|
|
1926
|
+
Every array is detached, in reverse order, whatever happens. body's
|
|
1927
|
+
own exception wins over one raised by a sync; when body returned and a
|
|
1928
|
+
sync raised, that exception propagates once everything is detached. */
|
|
1929
|
+
|
|
1930
|
+
typedef struct {
|
|
1931
|
+
int32_t n;
|
|
1932
|
+
CArray **list;
|
|
1933
|
+
const char *modes;
|
|
1934
|
+
int32_t opened;
|
|
1935
|
+
int body_done; /* body returned without raising */
|
|
1936
|
+
int sync_tag;
|
|
1937
|
+
volatile VALUE sync_err;
|
|
1938
|
+
VALUE (*body)(VALUE);
|
|
1939
|
+
VALUE arg;
|
|
1940
|
+
volatile VALUE masks; /* per array: the mask bytes of an 'a' array, or nil */
|
|
1941
|
+
} ca_window_ctx_t;
|
|
1942
|
+
|
|
1943
|
+
/* Copy the masks of the 'a' arrays before they open. */
|
|
1944
|
+
static void
|
|
1945
|
+
ca_attach_window_save_masks (ca_window_ctx_t *w)
|
|
1946
|
+
{
|
|
1947
|
+
int32_t k;
|
|
1948
|
+
w->masks = Qnil;
|
|
1949
|
+
for ( k = 0; k < w->n; k++ ) {
|
|
1950
|
+
CArray *ca = w->list[k];
|
|
1951
|
+
if ( w->modes[k] != 'a' || ! ca || ! ca_has_mask(ca) ) {
|
|
1952
|
+
continue;
|
|
1953
|
+
}
|
|
1954
|
+
if ( NIL_P(w->masks) ) {
|
|
1955
|
+
w->masks = rb_ary_new_capa(w->n);
|
|
1956
|
+
}
|
|
1957
|
+
ca_update_mask(ca);
|
|
1958
|
+
{
|
|
1959
|
+
VALUE buf = rb_str_new(NULL, (long) ca->elements);
|
|
1960
|
+
ca_copy_data(ca->mask, RSTRING_PTR(buf));
|
|
1961
|
+
rb_ary_store(w->masks, k, buf);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/* Write the copied masks back, once every array is detached. */
|
|
1967
|
+
static void
|
|
1968
|
+
ca_attach_window_restore_masks (ca_window_ctx_t *w)
|
|
1969
|
+
{
|
|
1970
|
+
int32_t k;
|
|
1971
|
+
if ( NIL_P(w->masks) ) {
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
for ( k = 0; k < w->n; k++ ) {
|
|
1975
|
+
VALUE buf = rb_ary_entry(w->masks, k);
|
|
1976
|
+
CArray *ca = w->list[k];
|
|
1977
|
+
if ( NIL_P(buf) ) {
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
ca_update_mask(ca);
|
|
1981
|
+
if ( ! ca->mask ) {
|
|
1982
|
+
ca_create_mask(ca);
|
|
1983
|
+
}
|
|
1984
|
+
ca_xfer_all(ca->mask, RSTRING_PTR(buf), CA_XFER_PUT);
|
|
1985
|
+
/* held only by w->masks, where compaction can move it; the write may
|
|
1986
|
+
call into Ruby (a CAObject's mask hooks) */
|
|
1987
|
+
RB_GC_GUARD(buf);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
static VALUE
|
|
1992
|
+
ca_attach_window_open (VALUE varg)
|
|
1993
|
+
{
|
|
1994
|
+
ca_window_ctx_t *w = (ca_window_ctx_t *) varg;
|
|
1995
|
+
for ( ; w->opened < w->n; w->opened++ ) {
|
|
1996
|
+
if ( w->modes[w->opened] == 'a' ) {
|
|
1997
|
+
ca_allocate(w->list[w->opened]);
|
|
1998
|
+
}
|
|
1999
|
+
else {
|
|
2000
|
+
ca_attach(w->list[w->opened]);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
return Qnil;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
static VALUE
|
|
2007
|
+
ca_attach_window_body (VALUE varg)
|
|
2008
|
+
{
|
|
2009
|
+
ca_window_ctx_t *w = (ca_window_ctx_t *) varg;
|
|
2010
|
+
VALUE result = w->body(w->arg);
|
|
2011
|
+
w->body_done = 1;
|
|
2012
|
+
return result;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
static VALUE
|
|
2016
|
+
ca_attach_window_sync (VALUE varg)
|
|
2017
|
+
{
|
|
2018
|
+
ca_sync((void *) varg);
|
|
2019
|
+
return Qnil;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
/* The ensure half. rb_ensure keeps the exception body raised (or the
|
|
2023
|
+
break it took) across this call, so a sync raising in here is caught
|
|
2024
|
+
and set aside rather than let replace it. */
|
|
2025
|
+
static VALUE
|
|
2026
|
+
ca_attach_window_close (VALUE varg)
|
|
2027
|
+
{
|
|
2028
|
+
ca_window_ctx_t *w = (ca_window_ctx_t *) varg;
|
|
2029
|
+
int32_t k;
|
|
2030
|
+
for ( k = w->opened - 1; k >= 0; k-- ) {
|
|
2031
|
+
CArray *ca = w->list[k];
|
|
2032
|
+
char mode = w->modes[k];
|
|
2033
|
+
if ( ! ca ) {
|
|
2034
|
+
continue;
|
|
2035
|
+
}
|
|
2036
|
+
if ( ca->ptr && ( mode == 'w' || ( mode == 'a' && w->body_done ) ) ) {
|
|
2037
|
+
int tag = 0;
|
|
2038
|
+
rb_protect(ca_attach_window_sync, (VALUE) ca, &tag);
|
|
2039
|
+
if ( tag && ! w->sync_tag ) {
|
|
2040
|
+
w->sync_tag = tag;
|
|
2041
|
+
w->sync_err = rb_errinfo();
|
|
2042
|
+
}
|
|
2043
|
+
rb_set_errinfo(Qnil);
|
|
2044
|
+
}
|
|
2045
|
+
if ( ca->ptr ) {
|
|
2046
|
+
ca_detach(ca);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
if ( ! w->body_done ) {
|
|
2050
|
+
ca_attach_window_restore_masks(w);
|
|
2051
|
+
}
|
|
2052
|
+
return Qnil;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
VALUE
|
|
2056
|
+
ca_attach_window (int32_t n, CArray **list, const char *modes,
|
|
2057
|
+
VALUE (*body)(VALUE), VALUE arg)
|
|
2058
|
+
{
|
|
2059
|
+
ca_window_ctx_t w;
|
|
2060
|
+
VALUE result;
|
|
2061
|
+
int tag = 0;
|
|
2062
|
+
|
|
2063
|
+
w.n = n;
|
|
2064
|
+
w.list = list;
|
|
2065
|
+
w.modes = modes;
|
|
2066
|
+
w.opened = 0;
|
|
2067
|
+
w.body_done = 0;
|
|
2068
|
+
w.sync_tag = 0;
|
|
2069
|
+
w.sync_err = Qnil;
|
|
2070
|
+
w.body = body;
|
|
2071
|
+
w.arg = arg;
|
|
2072
|
+
ca_attach_window_save_masks(&w);
|
|
2073
|
+
|
|
2074
|
+
rb_protect(ca_attach_window_open, (VALUE) &w, &tag);
|
|
2075
|
+
if ( tag ) {
|
|
2076
|
+
while ( w.opened > 0 ) {
|
|
2077
|
+
w.opened--;
|
|
2078
|
+
if ( w.list[w.opened] ) {
|
|
2079
|
+
ca_detach(w.list[w.opened]);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
ca_attach_window_restore_masks(&w);
|
|
2083
|
+
rb_jump_tag(tag);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
result = rb_ensure(ca_attach_window_body, (VALUE) &w,
|
|
2087
|
+
ca_attach_window_close, (VALUE) &w);
|
|
2088
|
+
if ( w.sync_tag && RB_TYPE_P(w.sync_err, T_OBJECT) &&
|
|
2089
|
+
RTEST(rb_obj_is_kind_of(w.sync_err, rb_eException)) ) {
|
|
2090
|
+
rb_exc_raise(w.sync_err);
|
|
2091
|
+
}
|
|
2092
|
+
return result;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
/* re-gather an attached view's buffer from its parent */
|
|
1755
2096
|
|
|
1756
2097
|
void
|
|
1757
2098
|
ca_update (void *ap)
|
|
@@ -1769,7 +2110,7 @@ ca_update (void *ap)
|
|
|
1769
2110
|
}
|
|
1770
2111
|
else {
|
|
1771
2112
|
rb_raise(rb_eRuntimeError,
|
|
1772
|
-
"[BUG] ca_update() called for not-attached
|
|
2113
|
+
"[BUG] ca_update() called for not-attached virtual array");
|
|
1773
2114
|
}
|
|
1774
2115
|
|
|
1775
2116
|
}
|
|
@@ -1795,12 +2136,16 @@ ca_sync (void *ap)
|
|
|
1795
2136
|
}
|
|
1796
2137
|
|
|
1797
2138
|
if ( ca_is_readonly(ca) ) {
|
|
1798
|
-
|
|
1799
|
-
"can not modify read-only array");
|
|
2139
|
+
ca_refuse_read_only();
|
|
1800
2140
|
}
|
|
1801
2141
|
|
|
1802
|
-
|
|
1803
|
-
|
|
2142
|
+
/* Only a mask that exists can hold writes: one made inside the window
|
|
2143
|
+
is attached with the view (ca_create_mask). Making one here would
|
|
2144
|
+
read the parent's mask while the window closes, and a parent that
|
|
2145
|
+
cannot answer would leave the window open. */
|
|
2146
|
+
if ( ca->mask ) {
|
|
2147
|
+
ca_sync(ca->mask);
|
|
2148
|
+
}
|
|
1804
2149
|
|
|
1805
2150
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1806
2151
|
if ( ! CAVIEW(ca)->nosync ) { /* FIXME : */
|
|
@@ -1813,6 +2158,42 @@ ca_sync (void *ap)
|
|
|
1813
2158
|
|
|
1814
2159
|
}
|
|
1815
2160
|
|
|
2161
|
+
/* Sync ap and detach it -- the close of a window a frame opened with
|
|
2162
|
+
ca_attach or ca_allocate. The detach happens even when the sync raises
|
|
2163
|
+
(a read-only array, a backing whose write fails); the sync's exception
|
|
2164
|
+
then propagates. Written as two calls, a raising sync skips the detach
|
|
2165
|
+
and the window stays open.
|
|
2166
|
+
|
|
2167
|
+
Not a replacement for every ca_sync: a view's sync slot syncs its parent
|
|
2168
|
+
without detaching it, because that attach belongs to the view and its
|
|
2169
|
+
detach slot releases it. */
|
|
2170
|
+
|
|
2171
|
+
static VALUE
|
|
2172
|
+
ca_sync_body (VALUE arg)
|
|
2173
|
+
{
|
|
2174
|
+
ca_sync((void *) arg);
|
|
2175
|
+
return Qnil;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
void
|
|
2179
|
+
ca_sync_detach (void *ap)
|
|
2180
|
+
{
|
|
2181
|
+
CArray *ca = (CArray *) ap;
|
|
2182
|
+
int tag = 0;
|
|
2183
|
+
|
|
2184
|
+
if ( ! ca ) {
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
rb_protect(ca_sync_body, (VALUE) ca, &tag);
|
|
2189
|
+
if ( ca->ptr ) {
|
|
2190
|
+
ca_detach(ca);
|
|
2191
|
+
}
|
|
2192
|
+
if ( tag ) {
|
|
2193
|
+
rb_jump_tag(tag);
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
|
|
1816
2197
|
/* make ca->ptr to be detached */
|
|
1817
2198
|
|
|
1818
2199
|
void
|
|
@@ -1833,38 +2214,86 @@ ca_detach (void *ap)
|
|
|
1833
2214
|
if ( CAVIEW(ca)->attach == 1 ) {
|
|
1834
2215
|
ca_func[ca->obj_type].detach(ap);
|
|
1835
2216
|
}
|
|
1836
|
-
|
|
2217
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1837
2218
|
}
|
|
1838
2219
|
else { /* entity array */
|
|
1839
2220
|
ca_func[ca->obj_type].detach(ap);
|
|
1840
2221
|
}
|
|
1841
2222
|
|
|
1842
|
-
|
|
1843
|
-
|
|
2223
|
+
/* The mask, if there is one, is at the view's level (see
|
|
2224
|
+
ca_attach_view_first). A mask that does not exist yet is not made
|
|
2225
|
+
here: it would be made unattached, and making it reads the parent's
|
|
2226
|
+
mask, which may raise with the view half detached. */
|
|
2227
|
+
if ( ca->mask ) {
|
|
2228
|
+
ca_detach(ca->mask);
|
|
2229
|
+
}
|
|
1844
2230
|
}
|
|
1845
2231
|
|
|
1846
2232
|
/* multiple versions of ca_allocate, ca_attach, ca_sync, ca_detach */
|
|
1847
2233
|
|
|
2234
|
+
/* ca_allocate_n and ca_attach_n take all of their arrays or none: when
|
|
2235
|
+
one raises, the ones already taken are detached before the raise
|
|
2236
|
+
propagates. */
|
|
2237
|
+
|
|
2238
|
+
typedef struct {
|
|
2239
|
+
CArray **list;
|
|
2240
|
+
int32_t n;
|
|
2241
|
+
int32_t done;
|
|
2242
|
+
} ca_allocate_all_ctx_t;
|
|
2243
|
+
|
|
2244
|
+
static VALUE
|
|
2245
|
+
ca_allocate_all_body (VALUE arg)
|
|
2246
|
+
{
|
|
2247
|
+
ca_allocate_all_ctx_t *c = (ca_allocate_all_ctx_t *) arg;
|
|
2248
|
+
for ( ; c->done < c->n; c->done++ ) {
|
|
2249
|
+
ca_allocate(c->list[c->done]);
|
|
2250
|
+
}
|
|
2251
|
+
return Qnil;
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
static void
|
|
2255
|
+
ca_allocate_all (CArray **list, int32_t n)
|
|
2256
|
+
{
|
|
2257
|
+
ca_allocate_all_ctx_t c;
|
|
2258
|
+
int tag = 0;
|
|
2259
|
+
c.list = list;
|
|
2260
|
+
c.n = n;
|
|
2261
|
+
c.done = 0;
|
|
2262
|
+
rb_protect(ca_allocate_all_body, (VALUE) &c, &tag);
|
|
2263
|
+
if ( tag ) {
|
|
2264
|
+
while ( c.done > 0 ) {
|
|
2265
|
+
ca_detach(list[--c.done]);
|
|
2266
|
+
}
|
|
2267
|
+
rb_jump_tag(tag);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
1848
2271
|
void
|
|
1849
2272
|
ca_allocate_n (int n, ...)
|
|
1850
2273
|
{
|
|
2274
|
+
CArray **list = ALLOCA_N(CArray *, n > 0 ? n : 1);
|
|
1851
2275
|
va_list args;
|
|
2276
|
+
int i;
|
|
1852
2277
|
va_start(args, n);
|
|
1853
|
-
|
|
1854
|
-
|
|
2278
|
+
for ( i = 0; i < n; i++ ) {
|
|
2279
|
+
list[i] = va_arg(args, CArray *);
|
|
1855
2280
|
}
|
|
1856
2281
|
va_end(args);
|
|
2282
|
+
ca_allocate_all(list, n);
|
|
1857
2283
|
}
|
|
1858
2284
|
|
|
1859
2285
|
void
|
|
1860
2286
|
ca_attach_n (int n, ...)
|
|
1861
2287
|
{
|
|
2288
|
+
CArray **list = ALLOCA_N(CArray *, n > 0 ? n : 1);
|
|
1862
2289
|
va_list args;
|
|
2290
|
+
int i;
|
|
1863
2291
|
va_start(args, n);
|
|
1864
|
-
|
|
1865
|
-
|
|
2292
|
+
for ( i = 0; i < n; i++ ) {
|
|
2293
|
+
list[i] = va_arg(args, CArray *);
|
|
1866
2294
|
}
|
|
1867
2295
|
va_end(args);
|
|
2296
|
+
ca_attach_all(list, n);
|
|
1868
2297
|
}
|
|
1869
2298
|
|
|
1870
2299
|
void
|
|
@@ -1917,8 +2346,7 @@ ca_sync_data (void *ap, char *ptr)
|
|
|
1917
2346
|
CArray *ca = (CArray *) ap;
|
|
1918
2347
|
|
|
1919
2348
|
if ( ca_is_readonly(ca) ) {
|
|
1920
|
-
|
|
1921
|
-
"can not sync data to read-only array");
|
|
2349
|
+
ca_refuse_read_only();
|
|
1922
2350
|
}
|
|
1923
2351
|
|
|
1924
2352
|
if ( ca_is_view(ca) && CAVIEW(ca)->nosync ) {
|
|
@@ -1939,8 +2367,7 @@ ca_fill_data (void *ap, void *aptr)
|
|
|
1939
2367
|
char *ptr = (char *) aptr;
|
|
1940
2368
|
|
|
1941
2369
|
if ( ca_is_readonly(ca) ) {
|
|
1942
|
-
|
|
1943
|
-
"can not fill data to read-only array");
|
|
2370
|
+
ca_refuse_read_only();
|
|
1944
2371
|
}
|
|
1945
2372
|
|
|
1946
2373
|
if ( ca_is_view(ca) ) { /* view array */
|
|
@@ -1972,7 +2399,10 @@ ca_fill_stride_default (void *ap, ca_size_t base, int8_t ndim,
|
|
|
1972
2399
|
ca_size_t idx[CA_RANK_MAX];
|
|
1973
2400
|
int8_t k;
|
|
1974
2401
|
|
|
2402
|
+
if ( ca_region_is_empty(ndim, counts) ) return;
|
|
2403
|
+
|
|
1975
2404
|
for ( k = 0; k < ndim; k++ ) idx[k] = 0;
|
|
2405
|
+
/* empty: the function returns on an empty region at its entry */
|
|
1976
2406
|
while ( 1 ) {
|
|
1977
2407
|
ca_size_t addr = base, vidx[CA_RANK_MAX];
|
|
1978
2408
|
for ( k = 0; k < ndim; k++ ) addr += idx[k] * steps[k];
|
|
@@ -1989,15 +2419,12 @@ ca_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
|
1989
2419
|
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
1990
2420
|
{
|
|
1991
2421
|
CArray *ca = (CArray *) ap;
|
|
1992
|
-
int8_t k;
|
|
1993
2422
|
|
|
1994
2423
|
if ( ca_is_readonly(ca) ) {
|
|
1995
|
-
|
|
2424
|
+
ca_refuse_read_only();
|
|
1996
2425
|
}
|
|
1997
2426
|
|
|
1998
|
-
|
|
1999
|
-
if ( counts[k] <= 0 ) return;
|
|
2000
|
-
}
|
|
2427
|
+
if ( ca_region_is_empty(ndim, counts) ) return;
|
|
2001
2428
|
|
|
2002
2429
|
if ( ca_func[ca->obj_type].fill_stride ) {
|
|
2003
2430
|
ca_func[ca->obj_type].fill_stride(ap, base, ndim, counts, steps, ptr);
|
|
@@ -2090,6 +2517,7 @@ ca_fill_stride_via_addrs (void *ap, ca_size_t base, int8_t ndim,
|
|
|
2090
2517
|
idx[k] = 0;
|
|
2091
2518
|
}
|
|
2092
2519
|
|
|
2520
|
+
/* empty: an axis of count 0 returns above */
|
|
2093
2521
|
while ( 1 ) {
|
|
2094
2522
|
ca_size_t addr = base;
|
|
2095
2523
|
for ( k = 0; k < ndim; k++ ) addr += idx[k] * steps[k];
|
|
@@ -2113,7 +2541,7 @@ ca_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
|
2113
2541
|
CArray *ca = (CArray *) ap;
|
|
2114
2542
|
|
|
2115
2543
|
if ( ca_is_readonly(ca) ) {
|
|
2116
|
-
|
|
2544
|
+
ca_refuse_read_only();
|
|
2117
2545
|
}
|
|
2118
2546
|
|
|
2119
2547
|
if ( ca_func[ca->obj_type].fill_addrs ) {
|
|
@@ -2144,7 +2572,7 @@ ca_fill (void *ap, void *aptr)
|
|
|
2144
2572
|
char *ptr = (char *) aptr;
|
|
2145
2573
|
|
|
2146
2574
|
if ( ca_is_readonly(ca) ) {
|
|
2147
|
-
|
|
2575
|
+
ca_refuse_read_only();
|
|
2148
2576
|
}
|
|
2149
2577
|
|
|
2150
2578
|
ca_fill_data(ap, ptr);
|
|
@@ -2425,7 +2853,7 @@ rb_ca_members (VALUE self)
|
|
|
2425
2853
|
{
|
|
2426
2854
|
volatile VALUE data_class = rb_ca_data_class(self);
|
|
2427
2855
|
if ( NIL_P(data_class) ) {
|
|
2428
|
-
rb_raise(
|
|
2856
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2429
2857
|
}
|
|
2430
2858
|
else {
|
|
2431
2859
|
return rb_obj_clone(rb_const_get(data_class, rb_intern("MEMBERS")));
|
|
@@ -2438,8 +2866,8 @@ rb_ca_members (VALUE self)
|
|
|
2438
2866
|
(= Face strip): the @member cache lives on self (the Face) while the
|
|
2439
2867
|
actual field view is the CAField on the parent. A plain FIXLEN entity
|
|
2440
2868
|
keeps self == receiver. */
|
|
2441
|
-
VALUE
|
|
2442
|
-
|
|
2869
|
+
static VALUE
|
|
2870
|
+
ca_face_field_lookup (VALUE self, VALUE sym)
|
|
2443
2871
|
{
|
|
2444
2872
|
volatile VALUE data_class = rb_ca_data_class(self);
|
|
2445
2873
|
volatile VALUE member;
|
|
@@ -2448,7 +2876,7 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2448
2876
|
CArray *ca;
|
|
2449
2877
|
|
|
2450
2878
|
if ( NIL_P(data_class) ) {
|
|
2451
|
-
rb_raise(
|
|
2879
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2452
2880
|
}
|
|
2453
2881
|
|
|
2454
2882
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -2464,7 +2892,9 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2464
2892
|
is local to the derived view; field views are still on its parent
|
|
2465
2893
|
(which itself is on the entity). */
|
|
2466
2894
|
member = rb_hash_new();
|
|
2467
|
-
|
|
2895
|
+
if ( ! OBJ_FROZEN(self) ) {
|
|
2896
|
+
rb_ivar_set(self, rb_intern("member"), member);
|
|
2897
|
+
}
|
|
2468
2898
|
}
|
|
2469
2899
|
|
|
2470
2900
|
if ( rb_obj_is_kind_of(sym, rb_cInteger) ) {
|
|
@@ -2490,7 +2920,7 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2490
2920
|
if ( TYPE(sym) != T_STRING ) {
|
|
2491
2921
|
sym = rb_funcall(sym, rb_intern("to_s"), 0);
|
|
2492
2922
|
}
|
|
2493
|
-
rb_raise(
|
|
2923
|
+
rb_raise(rb_eArgError,
|
|
2494
2924
|
"can't find data_member named <%s>", StringValuePtr(sym));
|
|
2495
2925
|
}
|
|
2496
2926
|
Check_Type(info, T_ARRAY);
|
|
@@ -2532,12 +2962,53 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2532
2962
|
return obj;
|
|
2533
2963
|
}
|
|
2534
2964
|
}
|
|
2965
|
+
/* `endian:` is not an option of #field; the member's byte order is a
|
|
2966
|
+
view over the field, as CAStruct#[] reads it. */
|
|
2967
|
+
{
|
|
2968
|
+
volatile VALUE opts = rb_ary_entry(info, 2);
|
|
2969
|
+
volatile VALUE endian = Qnil;
|
|
2970
|
+
if ( RB_TYPE_P(opts, T_HASH) ) {
|
|
2971
|
+
endian = rb_hash_aref(opts, ID2SYM(rb_intern("endian")));
|
|
2972
|
+
}
|
|
2973
|
+
if ( ! NIL_P(endian) ) {
|
|
2974
|
+
volatile VALUE field_opts = rb_hash_dup(opts);
|
|
2975
|
+
rb_hash_delete(field_opts, ID2SYM(rb_intern("endian")));
|
|
2976
|
+
if ( RHASH_SIZE(field_opts) > 0 ) {
|
|
2977
|
+
obj = rb_funcall(receiver, rb_intern("field"), 3,
|
|
2978
|
+
rb_ary_entry(info, 0), rb_ary_entry(info, 1),
|
|
2979
|
+
field_opts);
|
|
2980
|
+
}
|
|
2981
|
+
else {
|
|
2982
|
+
obj = rb_funcall(receiver, rb_intern("field"), 2,
|
|
2983
|
+
rb_ary_entry(info, 0), rb_ary_entry(info, 1));
|
|
2984
|
+
}
|
|
2985
|
+
obj = rb_funcall(obj, rb_intern("endian"), 1, endian);
|
|
2986
|
+
rb_hash_aset(member, sym, obj);
|
|
2987
|
+
return obj;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2535
2990
|
obj = rb_apply(receiver, rb_intern("field"), info);
|
|
2536
2991
|
rb_hash_aset(member, sym, obj);
|
|
2537
2992
|
return obj;
|
|
2538
2993
|
}
|
|
2539
2994
|
}
|
|
2540
2995
|
|
|
2996
|
+
/* A field is a view on the record array's storage, below the Face, so the
|
|
2997
|
+
read-only state of the record array (frozen, or a read-only view) is not
|
|
2998
|
+
on its parent chain; the field carries it itself. */
|
|
2999
|
+
VALUE
|
|
3000
|
+
rb_ca_face_field (VALUE self, VALUE sym)
|
|
3001
|
+
{
|
|
3002
|
+
volatile VALUE obj = ca_face_field_lookup(self, sym);
|
|
3003
|
+
CArray *ca, *co;
|
|
3004
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
3005
|
+
if ( ca_is_readonly(ca) && rb_obj_is_carray(obj) ) {
|
|
3006
|
+
TypedData_Get_Struct(obj, CArray, &carray_data_type, co);
|
|
3007
|
+
ca_set_flag(co, CA_FLAG_READ_ONLY);
|
|
3008
|
+
}
|
|
3009
|
+
return obj;
|
|
3010
|
+
}
|
|
3011
|
+
|
|
2541
3012
|
/* @overload fields
|
|
2542
3013
|
|
|
2543
3014
|
(Reference) Returns an array of data class members (fields)
|
|
@@ -2550,7 +3021,7 @@ rb_ca_fields (VALUE self)
|
|
|
2550
3021
|
volatile VALUE member_names, list;
|
|
2551
3022
|
int i;
|
|
2552
3023
|
if ( NIL_P(data_class) ) {
|
|
2553
|
-
rb_raise(
|
|
3024
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2554
3025
|
}
|
|
2555
3026
|
member_names = rb_const_get(data_class, rb_intern("MEMBERS"));
|
|
2556
3027
|
list = rb_ary_new2(RARRAY_LEN(member_names));
|
|
@@ -2573,7 +3044,7 @@ rb_ca_fields_at (int argc, VALUE *argv, VALUE self)
|
|
|
2573
3044
|
volatile VALUE member_names, list;
|
|
2574
3045
|
int i;
|
|
2575
3046
|
if ( NIL_P(data_class) ) {
|
|
2576
|
-
rb_raise(
|
|
3047
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2577
3048
|
}
|
|
2578
3049
|
member_names = rb_ary_new4(argc, argv);
|
|
2579
3050
|
list = rb_ary_new2(RARRAY_LEN(member_names));
|
|
@@ -2603,6 +3074,19 @@ Init_carray_core (void)
|
|
|
2603
3074
|
rb_define_method(rb_cCArray, "__attach__", rb_ca__attach__, 0);
|
|
2604
3075
|
rb_define_method(rb_cCArray, "__sync__", rb_ca__sync__, 0);
|
|
2605
3076
|
rb_define_method(rb_cCArray, "__detach__", rb_ca__detach__, 0);
|
|
3077
|
+
|
|
3078
|
+
rb_define_singleton_method(rb_cCArray, "__attached_views__",
|
|
3079
|
+
rb_ca_s_attached_views, 0);
|
|
3080
|
+
|
|
3081
|
+
{
|
|
3082
|
+
const char *general = getenv("CARRAY_GENERAL_PATH");
|
|
3083
|
+
ca_fast_paths_on = !( general && general[0] && strcmp(general, "0") );
|
|
3084
|
+
ca_iter_transfer_only_on = ( general && ! strcmp(general, "2") );
|
|
3085
|
+
}
|
|
3086
|
+
rb_define_singleton_method(rb_cCArray, "__fast_paths_enabled__",
|
|
3087
|
+
rb_ca_s_fast_paths_enabled, 0);
|
|
3088
|
+
rb_define_singleton_method(rb_cCArray, "__iter_by_transfer_only__",
|
|
3089
|
+
rb_ca_s_iter_by_transfer_only, 0);
|
|
2606
3090
|
#endif
|
|
2607
3091
|
|
|
2608
3092
|
rb_define_method(rb_cCArray, "members", rb_ca_members, 0);
|