carray 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- 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 +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- 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 +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -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 +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -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 +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- 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 +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- 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 +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- 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 +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- 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 +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- 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 +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- 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 +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- 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/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- 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 +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -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 +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- 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 +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -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_block.rb +2 -7
- 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 +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- 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 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -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 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_core.c
CHANGED
|
@@ -425,7 +425,6 @@ ca_attach_is_alias (void *ap)
|
|
|
425
425
|
CArray *ca = (CArray *) ap;
|
|
426
426
|
extern ca_operation_function_t ca_stride_func;
|
|
427
427
|
extern ca_operation_function_t ca_lazy_marker_func;
|
|
428
|
-
extern int ca_stride_is_contiguous (CAStride *ca);
|
|
429
428
|
extern int ca_stride_attach_aliases_root (CAStride *ca);
|
|
430
429
|
|
|
431
430
|
if ( ca == NULL ) return 0;
|
|
@@ -440,21 +439,13 @@ ca_attach_is_alias (void *ap)
|
|
|
440
439
|
return ca_attach_is_alias(((CAView *) ca)->parent);
|
|
441
440
|
}
|
|
442
441
|
|
|
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. */
|
|
442
|
+
/* CAStride family share ca_stride_func.attach, which aliases the root's
|
|
443
|
+
memory iff the strides composed to the root are row-major contiguous
|
|
444
|
+
and the root has memory to lend. Otherwise attach builds its own
|
|
445
|
+
buffer and writes through ca->ptr reach the root only via ca_sync, so
|
|
446
|
+
saying "alias" would let a caller write and skip the sync. */
|
|
455
447
|
if ( ca_func[ca->obj_type].attach == ca_stride_func.attach ) {
|
|
456
|
-
return
|
|
457
|
-
&& ca_stride_attach_aliases_root((CAStride *) ca);
|
|
448
|
+
return ca_stride_attach_aliases_root((CAStride *) ca);
|
|
458
449
|
}
|
|
459
450
|
return 0;
|
|
460
451
|
}
|
|
@@ -598,8 +589,8 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
|
|
|
598
589
|
to NUM2SIZE) of length `count`, normalises + range-checks + duplicate-
|
|
599
590
|
checks, fills out_axes[] in input order. Shared between the legacy
|
|
600
591
|
variadic entry (rb_ca_parse_reduce_axes) and the kwarg entry
|
|
601
|
-
(rb_ca_parse_reduce_axes_kw). ctx
|
|
602
|
-
|
|
592
|
+
(rb_ca_parse_reduce_axes_kw). ctx names the method in error messages;
|
|
593
|
+
the two public entries pass the method the user called. */
|
|
603
594
|
static int8_t
|
|
604
595
|
parse_axes_items (const VALUE *items, int count, CArray *ca,
|
|
605
596
|
int8_t *out_axes, const char *ctx)
|
|
@@ -623,12 +614,12 @@ parse_axes_items (const VALUE *items, int count, CArray *ca,
|
|
|
623
614
|
|
|
624
615
|
for ( i = 0; i < CA_RANK_MAX; i++ ) seen[i] = 0;
|
|
625
616
|
for ( i = 0; i < count; i++ ) {
|
|
626
|
-
ca_size_t
|
|
627
|
-
|
|
617
|
+
ca_size_t raw = ca_axis_integer(items[i], NULL);
|
|
618
|
+
ca_size_t a = ( raw < 0 ) ? raw + ca->ndim : raw;
|
|
628
619
|
if ( a < 0 || a >= ca->ndim ) {
|
|
629
|
-
rb_raise(
|
|
630
|
-
"%s: axis %ld out of range
|
|
631
|
-
ctx, (long)
|
|
620
|
+
rb_raise(rb_eArgError,
|
|
621
|
+
"%s: axis %ld out of range for ndim %d",
|
|
622
|
+
ctx, (long) raw, (int) ca->ndim);
|
|
632
623
|
}
|
|
633
624
|
if ( seen[a] ) {
|
|
634
625
|
rb_raise(rb_eArgError,
|
|
@@ -666,7 +657,7 @@ rb_ca_parse_reduce_axes (int argc, VALUE *argv, CArray *ca, int8_t *out_axes)
|
|
|
666
657
|
}
|
|
667
658
|
|
|
668
659
|
return parse_axes_items(items, count, ca, out_axes,
|
|
669
|
-
|
|
660
|
+
ca_calling_method_name());
|
|
670
661
|
}
|
|
671
662
|
|
|
672
663
|
/* Kwarg form of rb_ca_parse_reduce_axes — accepts the `axis:` value as
|
|
@@ -705,8 +696,8 @@ rb_ca_parse_reduce_axes_kw_ctx (VALUE axis_val, CArray *ca, int8_t *out_axes,
|
|
|
705
696
|
}
|
|
706
697
|
|
|
707
698
|
rb_raise(rb_eTypeError,
|
|
708
|
-
"%s: axis
|
|
709
|
-
"
|
|
699
|
+
"%s: axis must be nil, an Integer or an Array of Integer "
|
|
700
|
+
"(got %"PRIsVALUE")",
|
|
710
701
|
ctx, rb_obj_class(axis_val));
|
|
711
702
|
}
|
|
712
703
|
|
|
@@ -714,7 +705,7 @@ int8_t
|
|
|
714
705
|
rb_ca_parse_reduce_axes_kw (VALUE axis_val, CArray *ca, int8_t *out_axes)
|
|
715
706
|
{
|
|
716
707
|
return rb_ca_parse_reduce_axes_kw_ctx(axis_val, ca, out_axes,
|
|
717
|
-
|
|
708
|
+
ca_calling_method_name());
|
|
718
709
|
}
|
|
719
710
|
|
|
720
711
|
/* ------------------------------------------------------------------- */
|
|
@@ -832,7 +823,7 @@ ca_set_cyclic_check(void *ap)
|
|
|
832
823
|
/* ca.data_type == CA_OBJECT */
|
|
833
824
|
if ( ca_is_object_type(ca) ) {
|
|
834
825
|
if ( ca->flags & CA_FLAG_CYCLE_CHECK ) {
|
|
835
|
-
rb_raise(
|
|
826
|
+
rb_raise(rb_eArgError, "cyclic reference is not allowed in CArray");
|
|
836
827
|
}
|
|
837
828
|
ca_set_flag(ca, CA_FLAG_CYCLE_CHECK);
|
|
838
829
|
}
|
|
@@ -860,12 +851,36 @@ ca_test_cyclic_check(void *ap, void *ptr)
|
|
|
860
851
|
CArray *cv;
|
|
861
852
|
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
862
853
|
if ( ca_test_flag(cv, CA_FLAG_CYCLE_CHECK) ) {
|
|
863
|
-
rb_raise(
|
|
854
|
+
rb_raise(rb_eArgError, "cyclic reference is not allowed in CArray");
|
|
864
855
|
}
|
|
865
856
|
}
|
|
866
857
|
}
|
|
867
858
|
}
|
|
868
859
|
|
|
860
|
+
/* Runs body(arg) -- one transfer of an object cell or cells -- with ca's
|
|
861
|
+
cycle check set, and clears the check however body leaves. Either
|
|
862
|
+
direction can call into Ruby: a GET through a CAObject slot or the
|
|
863
|
+
check of what it delivered, a PUT that converts the caller's value. A
|
|
864
|
+
raise that skipped the clear would leave every later access to ca
|
|
865
|
+
reporting a cyclic reference. A PUT into an entity only copies VALUEs
|
|
866
|
+
and cannot raise, so it runs unprotected. */
|
|
867
|
+
static void
|
|
868
|
+
ca_with_cyclic_check (CArray *ca, int dir, VALUE (*body)(VALUE), VALUE arg)
|
|
869
|
+
{
|
|
870
|
+
int state = 0;
|
|
871
|
+
ca_set_cyclic_check(ca);
|
|
872
|
+
if ( dir == CA_XFER_PUT && ca_is_entity(ca) ) {
|
|
873
|
+
body(arg);
|
|
874
|
+
}
|
|
875
|
+
else {
|
|
876
|
+
rb_protect(body, arg, &state);
|
|
877
|
+
}
|
|
878
|
+
ca_clear_cyclic_check(ca);
|
|
879
|
+
if ( state ) {
|
|
880
|
+
rb_jump_tag(state);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
869
884
|
/* ------------------------------------------------------------------- */
|
|
870
885
|
/* CArray offers no per-cell ptr accessor (ca_ptr_at_addr /
|
|
871
886
|
ca_ptr_at_index): such a slot is structurally unsafe -- CABitarray /
|
|
@@ -911,14 +926,17 @@ struct ca_xfer_index_args {
|
|
|
911
926
|
CArray *ca;
|
|
912
927
|
ca_size_t *idx;
|
|
913
928
|
char *ptr;
|
|
929
|
+
int dir;
|
|
914
930
|
};
|
|
915
931
|
|
|
916
932
|
static VALUE
|
|
917
|
-
|
|
933
|
+
ca_xfer_index_body (VALUE arg)
|
|
918
934
|
{
|
|
919
935
|
struct ca_xfer_index_args *d = (struct ca_xfer_index_args *) arg;
|
|
920
|
-
ca_xfer_index_dispatch(d->ca, d->idx, d->ptr,
|
|
921
|
-
|
|
936
|
+
ca_xfer_index_dispatch(d->ca, d->idx, d->ptr, d->dir);
|
|
937
|
+
if ( d->dir == CA_XFER_GET ) {
|
|
938
|
+
ca_test_cyclic_check(d->ca, d->ptr);
|
|
939
|
+
}
|
|
922
940
|
return Qnil;
|
|
923
941
|
}
|
|
924
942
|
|
|
@@ -937,24 +955,14 @@ ca_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
937
955
|
return;
|
|
938
956
|
}
|
|
939
957
|
|
|
940
|
-
/* CA_OBJECT slow path: cyclic check
|
|
941
|
-
|
|
958
|
+
/* CA_OBJECT slow path: cyclic check. */
|
|
959
|
+
{
|
|
942
960
|
struct ca_xfer_index_args args;
|
|
943
|
-
int state = 0;
|
|
944
961
|
args.ca = ca;
|
|
945
962
|
args.idx = idx;
|
|
946
963
|
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);
|
|
964
|
+
args.dir = dir;
|
|
965
|
+
ca_with_cyclic_check(ca, dir, ca_xfer_index_body, (VALUE) &args);
|
|
958
966
|
}
|
|
959
967
|
}
|
|
960
968
|
|
|
@@ -1043,16 +1051,19 @@ struct ca_xfer_addrs_args {
|
|
|
1043
1051
|
ca_size_t n;
|
|
1044
1052
|
ca_size_t *addrs;
|
|
1045
1053
|
char *data;
|
|
1054
|
+
int dir;
|
|
1046
1055
|
};
|
|
1047
1056
|
|
|
1048
1057
|
static VALUE
|
|
1049
|
-
|
|
1058
|
+
ca_xfer_addrs_body (VALUE arg)
|
|
1050
1059
|
{
|
|
1051
1060
|
struct ca_xfer_addrs_args *d = (struct ca_xfer_addrs_args *) arg;
|
|
1052
1061
|
ca_size_t i;
|
|
1053
|
-
ca_xfer_addrs_dispatch(d->ca, d->n, d->addrs, d->data,
|
|
1054
|
-
|
|
1055
|
-
|
|
1062
|
+
ca_xfer_addrs_dispatch(d->ca, d->n, d->addrs, d->data, d->dir);
|
|
1063
|
+
if ( d->dir == CA_XFER_GET ) {
|
|
1064
|
+
for ( i = 0; i < d->n; i++ ) {
|
|
1065
|
+
ca_test_cyclic_check(d->ca, d->data + i * d->ca->bytes);
|
|
1066
|
+
}
|
|
1056
1067
|
}
|
|
1057
1068
|
return Qnil;
|
|
1058
1069
|
}
|
|
@@ -1072,25 +1083,15 @@ ca_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data, int dir)
|
|
|
1072
1083
|
return;
|
|
1073
1084
|
}
|
|
1074
1085
|
|
|
1075
|
-
/* CA_OBJECT slow path: cyclic check
|
|
1076
|
-
|
|
1086
|
+
/* CA_OBJECT slow path: cyclic check. */
|
|
1087
|
+
{
|
|
1077
1088
|
struct ca_xfer_addrs_args args;
|
|
1078
|
-
int state = 0;
|
|
1079
1089
|
args.ca = ca;
|
|
1080
1090
|
args.n = n;
|
|
1081
1091
|
args.addrs = addrs;
|
|
1082
1092
|
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);
|
|
1093
|
+
args.dir = dir;
|
|
1094
|
+
ca_with_cyclic_check(ca, dir, ca_xfer_addrs_body, (VALUE) &args);
|
|
1094
1095
|
}
|
|
1095
1096
|
}
|
|
1096
1097
|
|
|
@@ -1335,6 +1336,8 @@ ca_xfer_strided_walk (char *src_base,
|
|
|
1335
1336
|
ca_size_t doff = 0;
|
|
1336
1337
|
int8_t k;
|
|
1337
1338
|
|
|
1339
|
+
if ( ca_region_is_empty(ndim, counts) ) return;
|
|
1340
|
+
|
|
1338
1341
|
/* slab merge -- scan innermost contig run (src_strides[k] equals the
|
|
1339
1342
|
accumulated slab byte size). This collapses per-cell memcpy(_,_,
|
|
1340
1343
|
bytes) loops into per-slab memcpy when the source region is row-major
|
|
@@ -1481,16 +1484,20 @@ struct ca_xfer_stride_args {
|
|
|
1481
1484
|
ca_size_t *counts;
|
|
1482
1485
|
ca_size_t *strides;
|
|
1483
1486
|
char *data;
|
|
1487
|
+
int dir;
|
|
1484
1488
|
};
|
|
1485
1489
|
|
|
1486
1490
|
static VALUE
|
|
1487
|
-
|
|
1491
|
+
ca_xfer_stride_body (VALUE arg)
|
|
1488
1492
|
{
|
|
1489
1493
|
struct ca_xfer_stride_args *a = (struct ca_xfer_stride_args *) arg;
|
|
1490
1494
|
ca_size_t n = 1, i;
|
|
1491
1495
|
int8_t k;
|
|
1492
1496
|
ca_xfer_stride_dispatch(a->ca, a->starts, a->counts, a->strides, a->data,
|
|
1493
|
-
|
|
1497
|
+
a->dir);
|
|
1498
|
+
if ( a->dir != CA_XFER_GET ) {
|
|
1499
|
+
return Qnil;
|
|
1500
|
+
}
|
|
1494
1501
|
/* cyclic check over the delivered cells (CA_OBJECT only). dst is contiguous
|
|
1495
1502
|
row-major over counts (semantics b), so cell i is at data + i*bytes. */
|
|
1496
1503
|
for ( k = 0; k < a->ca->ndim; k++ ) n *= a->counts[k];
|
|
@@ -1510,25 +1517,18 @@ ca_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
1510
1517
|
rb_raise(rb_eRuntimeError, "can not store data to read-only array");
|
|
1511
1518
|
}
|
|
1512
1519
|
|
|
1520
|
+
if ( ca_region_is_empty(ca->ndim, counts) ) return;
|
|
1521
|
+
|
|
1513
1522
|
if ( ca->data_type != CA_OBJECT ) {
|
|
1514
1523
|
ca_xfer_stride_dispatch(ca, starts, counts, strides, data, dir);
|
|
1515
1524
|
return;
|
|
1516
1525
|
}
|
|
1517
1526
|
|
|
1518
|
-
|
|
1527
|
+
{
|
|
1519
1528
|
struct ca_xfer_stride_args args;
|
|
1520
|
-
int state = 0;
|
|
1521
1529
|
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);
|
|
1530
|
+
args.strides = strides; args.data = (char *) data; args.dir = dir;
|
|
1531
|
+
ca_with_cyclic_check(ca, dir, ca_xfer_stride_body, (VALUE) &args);
|
|
1532
1532
|
}
|
|
1533
1533
|
}
|
|
1534
1534
|
|
|
@@ -1580,6 +1580,10 @@ ca_xfer_all (void *ap, void *data, int dir)
|
|
|
1580
1580
|
"[BUG] xfer_all not defined for object type <%i>",
|
|
1581
1581
|
ca->obj_type);
|
|
1582
1582
|
}
|
|
1583
|
+
/* An empty view moves nothing; see ca_xfer_stride. */
|
|
1584
|
+
if ( ca->elements == 0 ) {
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1583
1587
|
/* Universal arena lifetime hook. ca_xfer_all is the single universal
|
|
1584
1588
|
entry for materialise (to_ca -> ca_copy -> ca_copy_data ->
|
|
1585
1589
|
ca_xfer_all), so wrapping here covers every outermost view type,
|
|
@@ -1615,8 +1619,74 @@ ca_xfer_all (void *ap, void *data, int dir)
|
|
|
1615
1619
|
|
|
1616
1620
|
/* ------------------------------------------------------------------- */
|
|
1617
1621
|
|
|
1622
|
+
/* What follows the slot in ca_allocate: the object cells cleared, then the
|
|
1623
|
+
mask. Clearing the mask can create it, which for a CAObject calls Ruby.
|
|
1624
|
+
mask0 is the mask the array had before; see ca_attach_view_first. */
|
|
1625
|
+
static void
|
|
1626
|
+
ca_allocate_rest (CArray *ca, CArray *mask0)
|
|
1627
|
+
{
|
|
1628
|
+
if ( ca->data_type == CA_OBJECT ) { /* protection against GC */
|
|
1629
|
+
volatile VALUE rzero = INT2NUM(0);
|
|
1630
|
+
VALUE *p = (VALUE*)ca->ptr;
|
|
1631
|
+
ca_size_t i;
|
|
1632
|
+
for (i=0; i<ca->elements; i++) {
|
|
1633
|
+
*p++ = rzero;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
ca_clear_mask(ca); /* ca_update_mask called in ca_clear_mask */
|
|
1638
|
+
if ( ca->mask == mask0 ) {
|
|
1639
|
+
ca_allocate(ca->mask);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
/* The view half of ca_allocate, after the attach level is taken. Run
|
|
1644
|
+
under rb_protect by ca_allocate. */
|
|
1645
|
+
static VALUE
|
|
1646
|
+
ca_allocate_view (VALUE arg)
|
|
1647
|
+
{
|
|
1648
|
+
CArray *ca = (CArray *) arg;
|
|
1649
|
+
CArray *mask0 = ca->mask;
|
|
1650
|
+
if ( ! ca->ptr ) {
|
|
1651
|
+
ca_func[ca->obj_type].allocate(ca);
|
|
1652
|
+
}
|
|
1653
|
+
ca_allocate_rest(ca, mask0);
|
|
1654
|
+
return Qnil;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1618
1657
|
/* make ca->ptr to point the allocated memory block */
|
|
1619
1658
|
|
|
1659
|
+
/* Steps a view's attach level by d. A development build also counts the
|
|
1660
|
+
views whose level is above zero, and the spec compares that count
|
|
1661
|
+
before and after every test: a window left open shows as a view that
|
|
1662
|
+
stays counted. */
|
|
1663
|
+
#ifdef CARRAY_DEV_BUILD
|
|
1664
|
+
static long ca_attached_views = 0;
|
|
1665
|
+
|
|
1666
|
+
#define CA_VIEW_ATTACH_STEP(ca, d) do { \
|
|
1667
|
+
uint32_t attach_before_ = CAVIEW(ca)->attach; \
|
|
1668
|
+
CAVIEW(ca)->attach += (d); \
|
|
1669
|
+
ca_attached_views += ( CAVIEW(ca)->attach > 0 ) - ( attach_before_ > 0 ); \
|
|
1670
|
+
} while (0)
|
|
1671
|
+
|
|
1672
|
+
static VALUE
|
|
1673
|
+
rb_ca_s_attached_views (VALUE klass)
|
|
1674
|
+
{
|
|
1675
|
+
return LONG2NUM(ca_attached_views);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
/* Set once at load from CARRAY_GENERAL_PATH; see carray_internal.h. */
|
|
1679
|
+
int ca_fast_paths_on = 1;
|
|
1680
|
+
|
|
1681
|
+
static VALUE
|
|
1682
|
+
rb_ca_s_fast_paths_enabled (VALUE klass)
|
|
1683
|
+
{
|
|
1684
|
+
return ca_fast_paths_on ? Qtrue : Qfalse;
|
|
1685
|
+
}
|
|
1686
|
+
#else
|
|
1687
|
+
#define CA_VIEW_ATTACH_STEP(ca, d) ( CAVIEW(ca)->attach += (d) )
|
|
1688
|
+
#endif
|
|
1689
|
+
|
|
1620
1690
|
void
|
|
1621
1691
|
ca_allocate (void *ap)
|
|
1622
1692
|
{
|
|
@@ -1628,31 +1698,59 @@ ca_allocate (void *ap)
|
|
|
1628
1698
|
|
|
1629
1699
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1630
1700
|
|
|
1631
|
-
CAVIEW(ca)->attach
|
|
1632
|
-
if ( CAVIEW(ca)->attach > CA_ATTACH_MAX ) {
|
|
1701
|
+
if ( CAVIEW(ca)->attach >= CA_ATTACH_MAX ) {
|
|
1633
1702
|
rb_raise(rb_eRuntimeError,
|
|
1634
1703
|
"too large attach count of view array");
|
|
1635
1704
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1705
|
+
CA_VIEW_ATTACH_STEP(ca, 1); /* increments attach level */
|
|
1706
|
+
|
|
1707
|
+
/* Undo the level if the slot or the mask raises, as ca_attach does.
|
|
1708
|
+
Left in place, the level is invisible while ptr is NULL, and the
|
|
1709
|
+
next attach / detach pair then leaves the view attached for good.
|
|
1710
|
+
A slot that got as far as publishing ca->ptr has taken what its
|
|
1711
|
+
detach slot releases; one that raised earlier has published
|
|
1712
|
+
nothing. */
|
|
1713
|
+
{
|
|
1714
|
+
char *ptr0 = ca->ptr;
|
|
1715
|
+
int tag = 0;
|
|
1716
|
+
rb_protect(ca_allocate_view, (VALUE) ca, &tag);
|
|
1717
|
+
if ( tag ) {
|
|
1718
|
+
if ( ! ptr0 && ca->ptr ) {
|
|
1719
|
+
ca_func[ca->obj_type].detach(ca);
|
|
1720
|
+
ca->ptr = NULL;
|
|
1721
|
+
}
|
|
1722
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1723
|
+
rb_jump_tag(tag);
|
|
1724
|
+
}
|
|
1639
1725
|
}
|
|
1640
1726
|
}
|
|
1641
1727
|
else { /* entity array */
|
|
1642
1728
|
ca_func[ca->obj_type].allocate(ap);
|
|
1729
|
+
ca_allocate_rest(ca, ca->mask); /* an entity's new mask is not yet allocated */
|
|
1643
1730
|
}
|
|
1731
|
+
}
|
|
1644
1732
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1733
|
+
/* The first attach of a view: materialise through the type's slot, then
|
|
1734
|
+
its mask. Run under rb_protect by ca_attach. */
|
|
1735
|
+
static VALUE
|
|
1736
|
+
ca_attach_view_first (VALUE arg)
|
|
1737
|
+
{
|
|
1738
|
+
CArray *ca = (CArray *) arg;
|
|
1739
|
+
CArray *mask0 = ca->mask;
|
|
1740
|
+
/* The mask moves in step with its view: attach, allocate and detach
|
|
1741
|
+
each take it one level with the view. A mask created here -- by the
|
|
1742
|
+
slot (a CAObject makes its mask while it attaches) or by
|
|
1743
|
+
ca_update_mask -- is already at the view's level, since
|
|
1744
|
+
ca_create_mask attaches a new mask to match an attached view. So
|
|
1745
|
+
only a mask that was there before the slot takes the step; stepping a
|
|
1746
|
+
new one too leaves it a level above the view, still attached after
|
|
1747
|
+
the view's last detach. */
|
|
1748
|
+
ca_func[ca->obj_type].attach(ca);
|
|
1749
|
+
ca_update_mask(ca);
|
|
1750
|
+
if ( ca->mask == mask0 ) {
|
|
1751
|
+
ca_attach(ca->mask);
|
|
1652
1752
|
}
|
|
1653
|
-
|
|
1654
|
-
ca_clear_mask(ca); /* ca_update_mask called in ca_clear_mask */
|
|
1655
|
-
ca_allocate(ca->mask);
|
|
1753
|
+
return Qnil;
|
|
1656
1754
|
}
|
|
1657
1755
|
|
|
1658
1756
|
/* attach parent's data to ca->ptr */
|
|
@@ -1668,22 +1766,242 @@ ca_attach (void *ap)
|
|
|
1668
1766
|
|
|
1669
1767
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1670
1768
|
|
|
1671
|
-
CAVIEW(ca)->attach
|
|
1672
|
-
if ( CAVIEW(ca)->attach > CA_ATTACH_MAX ) {
|
|
1769
|
+
if ( CAVIEW(ca)->attach >= CA_ATTACH_MAX ) {
|
|
1673
1770
|
rb_raise(rb_eRuntimeError,
|
|
1674
1771
|
"too large attach count of view array");
|
|
1675
1772
|
}
|
|
1773
|
+
CA_VIEW_ATTACH_STEP(ca, 1); /* increments attach level */
|
|
1676
1774
|
|
|
1677
1775
|
if ( ! ca->ptr ) {
|
|
1678
|
-
|
|
1776
|
+
/* A slot can raise part way (a conversion meeting a value it cannot
|
|
1777
|
+
hold). Undo the attach then, or the next attach finds ca->ptr
|
|
1778
|
+
set, skips the slot and reads a half-filled buffer. A slot that
|
|
1779
|
+
got as far as publishing ca->ptr has also attached what its
|
|
1780
|
+
detach slot releases; one that raised earlier has published
|
|
1781
|
+
nothing and released its own parent attach on the way out. */
|
|
1782
|
+
int tag = 0;
|
|
1783
|
+
rb_protect(ca_attach_view_first, (VALUE) ca, &tag);
|
|
1784
|
+
if ( tag ) {
|
|
1785
|
+
if ( ca->ptr ) {
|
|
1786
|
+
ca_func[ca->obj_type].detach(ca);
|
|
1787
|
+
ca->ptr = NULL;
|
|
1788
|
+
}
|
|
1789
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1790
|
+
rb_jump_tag(tag);
|
|
1791
|
+
}
|
|
1792
|
+
return;
|
|
1679
1793
|
}
|
|
1680
1794
|
}
|
|
1681
1795
|
else { /* entity array */
|
|
1682
1796
|
ca_func[ca->obj_type].attach(ap);
|
|
1683
1797
|
}
|
|
1684
1798
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1799
|
+
{
|
|
1800
|
+
CArray *mask0 = ca->mask;
|
|
1801
|
+
ca_update_mask(ca);
|
|
1802
|
+
if ( ca->mask == mask0 ) { /* see ca_attach_view_first */
|
|
1803
|
+
ca_attach(ca->mask);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
/* Attach every array in list[0..n-1], or, if one of those attaches
|
|
1809
|
+
raises, none of them: the ones already attached are detached before the
|
|
1810
|
+
raise propagates. For views over several parents. */
|
|
1811
|
+
|
|
1812
|
+
typedef struct {
|
|
1813
|
+
CArray **list;
|
|
1814
|
+
int32_t n;
|
|
1815
|
+
int32_t done;
|
|
1816
|
+
} ca_attach_all_ctx_t;
|
|
1817
|
+
|
|
1818
|
+
static VALUE
|
|
1819
|
+
ca_attach_all_body (VALUE arg)
|
|
1820
|
+
{
|
|
1821
|
+
ca_attach_all_ctx_t *c = (ca_attach_all_ctx_t *) arg;
|
|
1822
|
+
for ( ; c->done < c->n; c->done++ ) {
|
|
1823
|
+
ca_attach(c->list[c->done]);
|
|
1824
|
+
}
|
|
1825
|
+
return Qnil;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
void
|
|
1829
|
+
ca_attach_all (CArray **list, int32_t n)
|
|
1830
|
+
{
|
|
1831
|
+
ca_attach_all_ctx_t c;
|
|
1832
|
+
int tag = 0;
|
|
1833
|
+
c.list = list;
|
|
1834
|
+
c.n = n;
|
|
1835
|
+
c.done = 0;
|
|
1836
|
+
rb_protect(ca_attach_all_body, (VALUE) &c, &tag);
|
|
1837
|
+
if ( tag ) {
|
|
1838
|
+
while ( c.done > 0 ) {
|
|
1839
|
+
ca_detach(list[--c.done]);
|
|
1840
|
+
}
|
|
1841
|
+
rb_jump_tag(tag);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
static VALUE
|
|
1846
|
+
ca_sync_all_step (VALUE arg)
|
|
1847
|
+
{
|
|
1848
|
+
ca_sync((void *) arg);
|
|
1849
|
+
return Qnil;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
/* Syncs every one of list[0..n-1] in turn, carrying on past one that
|
|
1853
|
+
raises so that the others still receive what was written, then raises
|
|
1854
|
+
the first exception. A throw or break cannot wait, and goes at once. */
|
|
1855
|
+
void
|
|
1856
|
+
ca_sync_all (CArray **list, int32_t n)
|
|
1857
|
+
{
|
|
1858
|
+
volatile VALUE error = Qnil;
|
|
1859
|
+
int32_t k;
|
|
1860
|
+
for ( k = 0; k < n; k++ ) {
|
|
1861
|
+
int tag = 0;
|
|
1862
|
+
rb_protect(ca_sync_all_step, (VALUE) list[k], &tag);
|
|
1863
|
+
if ( tag ) {
|
|
1864
|
+
VALUE err = rb_errinfo();
|
|
1865
|
+
if ( ! RTEST(rb_obj_is_kind_of(err, rb_eException)) ) {
|
|
1866
|
+
rb_jump_tag(tag);
|
|
1867
|
+
}
|
|
1868
|
+
if ( NIL_P(error) ) {
|
|
1869
|
+
error = err;
|
|
1870
|
+
}
|
|
1871
|
+
rb_set_errinfo(Qnil);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
if ( ! NIL_P(error) ) {
|
|
1875
|
+
rb_exc_raise(error);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
/* An attach window over list[0..n-1] that closes however body leaves.
|
|
1880
|
+
|
|
1881
|
+
modes holds one letter per array:
|
|
1882
|
+
'r' attach; detach on close
|
|
1883
|
+
'w' attach; sync, then detach on close
|
|
1884
|
+
'a' allocate (write only); sync, then detach on close
|
|
1885
|
+
|
|
1886
|
+
Opening takes all of the arrays or none. Closing syncs the 'w' arrays
|
|
1887
|
+
even when body raised or broke out -- the cells body wrote reach the
|
|
1888
|
+
parent, as they would for an entity, which has no separate buffer. An
|
|
1889
|
+
'a' array is not synced after a raise: allocate did not gather, so its
|
|
1890
|
+
cells body never wrote hold nothing faithful to push back.
|
|
1891
|
+
|
|
1892
|
+
Every array is detached, in reverse order, whatever happens. body's
|
|
1893
|
+
own exception wins over one raised by a sync; when body returned and a
|
|
1894
|
+
sync raised, that exception propagates once everything is detached. */
|
|
1895
|
+
|
|
1896
|
+
typedef struct {
|
|
1897
|
+
int32_t n;
|
|
1898
|
+
CArray **list;
|
|
1899
|
+
const char *modes;
|
|
1900
|
+
int32_t opened;
|
|
1901
|
+
int body_done; /* body returned without raising */
|
|
1902
|
+
int sync_tag;
|
|
1903
|
+
volatile VALUE sync_err;
|
|
1904
|
+
VALUE (*body)(VALUE);
|
|
1905
|
+
VALUE arg;
|
|
1906
|
+
} ca_window_ctx_t;
|
|
1907
|
+
|
|
1908
|
+
static VALUE
|
|
1909
|
+
ca_attach_window_open (VALUE varg)
|
|
1910
|
+
{
|
|
1911
|
+
ca_window_ctx_t *w = (ca_window_ctx_t *) varg;
|
|
1912
|
+
for ( ; w->opened < w->n; w->opened++ ) {
|
|
1913
|
+
if ( w->modes[w->opened] == 'a' ) {
|
|
1914
|
+
ca_allocate(w->list[w->opened]);
|
|
1915
|
+
}
|
|
1916
|
+
else {
|
|
1917
|
+
ca_attach(w->list[w->opened]);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
return Qnil;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
static VALUE
|
|
1924
|
+
ca_attach_window_body (VALUE varg)
|
|
1925
|
+
{
|
|
1926
|
+
ca_window_ctx_t *w = (ca_window_ctx_t *) varg;
|
|
1927
|
+
VALUE result = w->body(w->arg);
|
|
1928
|
+
w->body_done = 1;
|
|
1929
|
+
return result;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
static VALUE
|
|
1933
|
+
ca_attach_window_sync (VALUE varg)
|
|
1934
|
+
{
|
|
1935
|
+
ca_sync((void *) varg);
|
|
1936
|
+
return Qnil;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
/* The ensure half. rb_ensure keeps the exception body raised (or the
|
|
1940
|
+
break it took) across this call, so a sync raising in here is caught
|
|
1941
|
+
and set aside rather than let replace it. */
|
|
1942
|
+
static VALUE
|
|
1943
|
+
ca_attach_window_close (VALUE varg)
|
|
1944
|
+
{
|
|
1945
|
+
ca_window_ctx_t *w = (ca_window_ctx_t *) varg;
|
|
1946
|
+
int32_t k;
|
|
1947
|
+
for ( k = w->opened - 1; k >= 0; k-- ) {
|
|
1948
|
+
CArray *ca = w->list[k];
|
|
1949
|
+
char mode = w->modes[k];
|
|
1950
|
+
if ( ! ca ) {
|
|
1951
|
+
continue;
|
|
1952
|
+
}
|
|
1953
|
+
if ( ca->ptr && ( mode == 'w' || ( mode == 'a' && w->body_done ) ) ) {
|
|
1954
|
+
int tag = 0;
|
|
1955
|
+
rb_protect(ca_attach_window_sync, (VALUE) ca, &tag);
|
|
1956
|
+
if ( tag && ! w->sync_tag ) {
|
|
1957
|
+
w->sync_tag = tag;
|
|
1958
|
+
w->sync_err = rb_errinfo();
|
|
1959
|
+
}
|
|
1960
|
+
rb_set_errinfo(Qnil);
|
|
1961
|
+
}
|
|
1962
|
+
if ( ca->ptr ) {
|
|
1963
|
+
ca_detach(ca);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return Qnil;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
VALUE
|
|
1970
|
+
ca_attach_window (int32_t n, CArray **list, const char *modes,
|
|
1971
|
+
VALUE (*body)(VALUE), VALUE arg)
|
|
1972
|
+
{
|
|
1973
|
+
ca_window_ctx_t w;
|
|
1974
|
+
VALUE result;
|
|
1975
|
+
int tag = 0;
|
|
1976
|
+
|
|
1977
|
+
w.n = n;
|
|
1978
|
+
w.list = list;
|
|
1979
|
+
w.modes = modes;
|
|
1980
|
+
w.opened = 0;
|
|
1981
|
+
w.body_done = 0;
|
|
1982
|
+
w.sync_tag = 0;
|
|
1983
|
+
w.sync_err = Qnil;
|
|
1984
|
+
w.body = body;
|
|
1985
|
+
w.arg = arg;
|
|
1986
|
+
|
|
1987
|
+
rb_protect(ca_attach_window_open, (VALUE) &w, &tag);
|
|
1988
|
+
if ( tag ) {
|
|
1989
|
+
while ( w.opened > 0 ) {
|
|
1990
|
+
w.opened--;
|
|
1991
|
+
if ( w.list[w.opened] ) {
|
|
1992
|
+
ca_detach(w.list[w.opened]);
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
rb_jump_tag(tag);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
result = rb_ensure(ca_attach_window_body, (VALUE) &w,
|
|
1999
|
+
ca_attach_window_close, (VALUE) &w);
|
|
2000
|
+
if ( w.sync_tag && RB_TYPE_P(w.sync_err, T_OBJECT) &&
|
|
2001
|
+
RTEST(rb_obj_is_kind_of(w.sync_err, rb_eException)) ) {
|
|
2002
|
+
rb_exc_raise(w.sync_err);
|
|
2003
|
+
}
|
|
2004
|
+
return result;
|
|
1687
2005
|
}
|
|
1688
2006
|
|
|
1689
2007
|
/* attach parent's data to ca->ptr */
|
|
@@ -1734,8 +2052,13 @@ ca_sync (void *ap)
|
|
|
1734
2052
|
"can not modify read-only array");
|
|
1735
2053
|
}
|
|
1736
2054
|
|
|
1737
|
-
|
|
1738
|
-
|
|
2055
|
+
/* Only a mask that exists can hold writes: one made inside the window
|
|
2056
|
+
is attached with the view (ca_create_mask). Making one here would
|
|
2057
|
+
read the parent's mask while the window closes, and a parent that
|
|
2058
|
+
cannot answer would leave the window open. */
|
|
2059
|
+
if ( ca->mask ) {
|
|
2060
|
+
ca_sync(ca->mask);
|
|
2061
|
+
}
|
|
1739
2062
|
|
|
1740
2063
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1741
2064
|
if ( ! CAVIEW(ca)->nosync ) { /* FIXME : */
|
|
@@ -1748,6 +2071,42 @@ ca_sync (void *ap)
|
|
|
1748
2071
|
|
|
1749
2072
|
}
|
|
1750
2073
|
|
|
2074
|
+
/* Sync ap and detach it -- the close of a window a frame opened with
|
|
2075
|
+
ca_attach or ca_allocate. The detach happens even when the sync raises
|
|
2076
|
+
(a read-only array, a backing whose write fails); the sync's exception
|
|
2077
|
+
then propagates. Written as two calls, a raising sync skips the detach
|
|
2078
|
+
and the window stays open.
|
|
2079
|
+
|
|
2080
|
+
Not a replacement for every ca_sync: a view's sync slot syncs its parent
|
|
2081
|
+
without detaching it, because that attach belongs to the view and its
|
|
2082
|
+
detach slot releases it. */
|
|
2083
|
+
|
|
2084
|
+
static VALUE
|
|
2085
|
+
ca_sync_body (VALUE arg)
|
|
2086
|
+
{
|
|
2087
|
+
ca_sync((void *) arg);
|
|
2088
|
+
return Qnil;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
void
|
|
2092
|
+
ca_sync_detach (void *ap)
|
|
2093
|
+
{
|
|
2094
|
+
CArray *ca = (CArray *) ap;
|
|
2095
|
+
int tag = 0;
|
|
2096
|
+
|
|
2097
|
+
if ( ! ca ) {
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
rb_protect(ca_sync_body, (VALUE) ca, &tag);
|
|
2102
|
+
if ( ca->ptr ) {
|
|
2103
|
+
ca_detach(ca);
|
|
2104
|
+
}
|
|
2105
|
+
if ( tag ) {
|
|
2106
|
+
rb_jump_tag(tag);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
|
|
1751
2110
|
/* make ca->ptr to be detached */
|
|
1752
2111
|
|
|
1753
2112
|
void
|
|
@@ -1768,38 +2127,86 @@ ca_detach (void *ap)
|
|
|
1768
2127
|
if ( CAVIEW(ca)->attach == 1 ) {
|
|
1769
2128
|
ca_func[ca->obj_type].detach(ap);
|
|
1770
2129
|
}
|
|
1771
|
-
|
|
2130
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1772
2131
|
}
|
|
1773
2132
|
else { /* entity array */
|
|
1774
2133
|
ca_func[ca->obj_type].detach(ap);
|
|
1775
2134
|
}
|
|
1776
2135
|
|
|
1777
|
-
|
|
1778
|
-
|
|
2136
|
+
/* The mask, if there is one, is at the view's level (see
|
|
2137
|
+
ca_attach_view_first). A mask that does not exist yet is not made
|
|
2138
|
+
here: it would be made unattached, and making it reads the parent's
|
|
2139
|
+
mask, which may raise with the view half detached. */
|
|
2140
|
+
if ( ca->mask ) {
|
|
2141
|
+
ca_detach(ca->mask);
|
|
2142
|
+
}
|
|
1779
2143
|
}
|
|
1780
2144
|
|
|
1781
2145
|
/* multiple versions of ca_allocate, ca_attach, ca_sync, ca_detach */
|
|
1782
2146
|
|
|
2147
|
+
/* ca_allocate_n and ca_attach_n take all of their arrays or none: when
|
|
2148
|
+
one raises, the ones already taken are detached before the raise
|
|
2149
|
+
propagates. */
|
|
2150
|
+
|
|
2151
|
+
typedef struct {
|
|
2152
|
+
CArray **list;
|
|
2153
|
+
int32_t n;
|
|
2154
|
+
int32_t done;
|
|
2155
|
+
} ca_allocate_all_ctx_t;
|
|
2156
|
+
|
|
2157
|
+
static VALUE
|
|
2158
|
+
ca_allocate_all_body (VALUE arg)
|
|
2159
|
+
{
|
|
2160
|
+
ca_allocate_all_ctx_t *c = (ca_allocate_all_ctx_t *) arg;
|
|
2161
|
+
for ( ; c->done < c->n; c->done++ ) {
|
|
2162
|
+
ca_allocate(c->list[c->done]);
|
|
2163
|
+
}
|
|
2164
|
+
return Qnil;
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
static void
|
|
2168
|
+
ca_allocate_all (CArray **list, int32_t n)
|
|
2169
|
+
{
|
|
2170
|
+
ca_allocate_all_ctx_t c;
|
|
2171
|
+
int tag = 0;
|
|
2172
|
+
c.list = list;
|
|
2173
|
+
c.n = n;
|
|
2174
|
+
c.done = 0;
|
|
2175
|
+
rb_protect(ca_allocate_all_body, (VALUE) &c, &tag);
|
|
2176
|
+
if ( tag ) {
|
|
2177
|
+
while ( c.done > 0 ) {
|
|
2178
|
+
ca_detach(list[--c.done]);
|
|
2179
|
+
}
|
|
2180
|
+
rb_jump_tag(tag);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
|
|
1783
2184
|
void
|
|
1784
2185
|
ca_allocate_n (int n, ...)
|
|
1785
2186
|
{
|
|
2187
|
+
CArray **list = ALLOCA_N(CArray *, n > 0 ? n : 1);
|
|
1786
2188
|
va_list args;
|
|
2189
|
+
int i;
|
|
1787
2190
|
va_start(args, n);
|
|
1788
|
-
|
|
1789
|
-
|
|
2191
|
+
for ( i = 0; i < n; i++ ) {
|
|
2192
|
+
list[i] = va_arg(args, CArray *);
|
|
1790
2193
|
}
|
|
1791
2194
|
va_end(args);
|
|
2195
|
+
ca_allocate_all(list, n);
|
|
1792
2196
|
}
|
|
1793
2197
|
|
|
1794
2198
|
void
|
|
1795
2199
|
ca_attach_n (int n, ...)
|
|
1796
2200
|
{
|
|
2201
|
+
CArray **list = ALLOCA_N(CArray *, n > 0 ? n : 1);
|
|
1797
2202
|
va_list args;
|
|
2203
|
+
int i;
|
|
1798
2204
|
va_start(args, n);
|
|
1799
|
-
|
|
1800
|
-
|
|
2205
|
+
for ( i = 0; i < n; i++ ) {
|
|
2206
|
+
list[i] = va_arg(args, CArray *);
|
|
1801
2207
|
}
|
|
1802
2208
|
va_end(args);
|
|
2209
|
+
ca_attach_all(list, n);
|
|
1803
2210
|
}
|
|
1804
2211
|
|
|
1805
2212
|
void
|
|
@@ -1924,15 +2331,12 @@ ca_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
|
1924
2331
|
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
1925
2332
|
{
|
|
1926
2333
|
CArray *ca = (CArray *) ap;
|
|
1927
|
-
int8_t k;
|
|
1928
2334
|
|
|
1929
2335
|
if ( ca_is_readonly(ca) ) {
|
|
1930
2336
|
rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
|
|
1931
2337
|
}
|
|
1932
2338
|
|
|
1933
|
-
|
|
1934
|
-
if ( counts[k] <= 0 ) return;
|
|
1935
|
-
}
|
|
2339
|
+
if ( ca_region_is_empty(ndim, counts) ) return;
|
|
1936
2340
|
|
|
1937
2341
|
if ( ca_func[ca->obj_type].fill_stride ) {
|
|
1938
2342
|
ca_func[ca->obj_type].fill_stride(ap, base, ndim, counts, steps, ptr);
|
|
@@ -2079,7 +2483,7 @@ ca_fill (void *ap, void *aptr)
|
|
|
2079
2483
|
char *ptr = (char *) aptr;
|
|
2080
2484
|
|
|
2081
2485
|
if ( ca_is_readonly(ca) ) {
|
|
2082
|
-
rb_raise(rb_eRuntimeError, "can
|
|
2486
|
+
rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
|
|
2083
2487
|
}
|
|
2084
2488
|
|
|
2085
2489
|
ca_fill_data(ap, ptr);
|
|
@@ -2087,6 +2491,17 @@ ca_fill (void *ap, void *aptr)
|
|
|
2087
2491
|
|
|
2088
2492
|
/* ------------------------------------------------------------------- */
|
|
2089
2493
|
|
|
2494
|
+
#ifdef CARRAY_DEV_BUILD
|
|
2495
|
+
|
|
2496
|
+
/* The Ruby attach surface is built into development builds only. Ruby has no
|
|
2497
|
+
raw pointer, so the only thing a block can do inside an attach window is call
|
|
2498
|
+
back into the array API -- and which door that takes is invisible in the
|
|
2499
|
+
syntax: v[0] reads the attached buffer while v[] and v[0..1] compose past it
|
|
2500
|
+
to the root (R5, see the contract beside ca_attach in carray.h). Per-cell and
|
|
2501
|
+
whole-array writes reach the buffer and survive the sync; a write through a
|
|
2502
|
+
derived view is discarded. The in-tree tests drive the healthy spellings, so
|
|
2503
|
+
the surface stays reachable here and out of released builds. */
|
|
2504
|
+
|
|
2090
2505
|
/* subroutines for CArray.attach, CArray.attach!
|
|
2091
2506
|
CArray#attach, CArray#attach! */
|
|
2092
2507
|
|
|
@@ -2307,6 +2722,8 @@ rb_ca__detach__ (VALUE self)
|
|
|
2307
2722
|
return self;
|
|
2308
2723
|
}
|
|
2309
2724
|
|
|
2725
|
+
#endif /* CARRAY_DEV_BUILD */
|
|
2726
|
+
|
|
2310
2727
|
/* ------------------------------------------------------------------- */
|
|
2311
2728
|
|
|
2312
2729
|
static ID id_decode, id_encode;
|
|
@@ -2347,7 +2764,7 @@ rb_ca_members (VALUE self)
|
|
|
2347
2764
|
{
|
|
2348
2765
|
volatile VALUE data_class = rb_ca_data_class(self);
|
|
2349
2766
|
if ( NIL_P(data_class) ) {
|
|
2350
|
-
rb_raise(
|
|
2767
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2351
2768
|
}
|
|
2352
2769
|
else {
|
|
2353
2770
|
return rb_obj_clone(rb_const_get(data_class, rb_intern("MEMBERS")));
|
|
@@ -2360,8 +2777,8 @@ rb_ca_members (VALUE self)
|
|
|
2360
2777
|
(= Face strip): the @member cache lives on self (the Face) while the
|
|
2361
2778
|
actual field view is the CAField on the parent. A plain FIXLEN entity
|
|
2362
2779
|
keeps self == receiver. */
|
|
2363
|
-
VALUE
|
|
2364
|
-
|
|
2780
|
+
static VALUE
|
|
2781
|
+
ca_face_field_lookup (VALUE self, VALUE sym)
|
|
2365
2782
|
{
|
|
2366
2783
|
volatile VALUE data_class = rb_ca_data_class(self);
|
|
2367
2784
|
volatile VALUE member;
|
|
@@ -2370,7 +2787,7 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2370
2787
|
CArray *ca;
|
|
2371
2788
|
|
|
2372
2789
|
if ( NIL_P(data_class) ) {
|
|
2373
|
-
rb_raise(
|
|
2790
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2374
2791
|
}
|
|
2375
2792
|
|
|
2376
2793
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -2386,7 +2803,9 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2386
2803
|
is local to the derived view; field views are still on its parent
|
|
2387
2804
|
(which itself is on the entity). */
|
|
2388
2805
|
member = rb_hash_new();
|
|
2389
|
-
|
|
2806
|
+
if ( ! OBJ_FROZEN(self) ) {
|
|
2807
|
+
rb_ivar_set(self, rb_intern("member"), member);
|
|
2808
|
+
}
|
|
2390
2809
|
}
|
|
2391
2810
|
|
|
2392
2811
|
if ( rb_obj_is_kind_of(sym, rb_cInteger) ) {
|
|
@@ -2412,7 +2831,7 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2412
2831
|
if ( TYPE(sym) != T_STRING ) {
|
|
2413
2832
|
sym = rb_funcall(sym, rb_intern("to_s"), 0);
|
|
2414
2833
|
}
|
|
2415
|
-
rb_raise(
|
|
2834
|
+
rb_raise(rb_eArgError,
|
|
2416
2835
|
"can't find data_member named <%s>", StringValuePtr(sym));
|
|
2417
2836
|
}
|
|
2418
2837
|
Check_Type(info, T_ARRAY);
|
|
@@ -2454,12 +2873,53 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2454
2873
|
return obj;
|
|
2455
2874
|
}
|
|
2456
2875
|
}
|
|
2876
|
+
/* `endian:` is not an option of #field; the member's byte order is a
|
|
2877
|
+
view over the field, as CAStruct#[] reads it. */
|
|
2878
|
+
{
|
|
2879
|
+
volatile VALUE opts = rb_ary_entry(info, 2);
|
|
2880
|
+
volatile VALUE endian = Qnil;
|
|
2881
|
+
if ( RB_TYPE_P(opts, T_HASH) ) {
|
|
2882
|
+
endian = rb_hash_aref(opts, ID2SYM(rb_intern("endian")));
|
|
2883
|
+
}
|
|
2884
|
+
if ( ! NIL_P(endian) ) {
|
|
2885
|
+
volatile VALUE field_opts = rb_hash_dup(opts);
|
|
2886
|
+
rb_hash_delete(field_opts, ID2SYM(rb_intern("endian")));
|
|
2887
|
+
if ( RHASH_SIZE(field_opts) > 0 ) {
|
|
2888
|
+
obj = rb_funcall(receiver, rb_intern("field"), 3,
|
|
2889
|
+
rb_ary_entry(info, 0), rb_ary_entry(info, 1),
|
|
2890
|
+
field_opts);
|
|
2891
|
+
}
|
|
2892
|
+
else {
|
|
2893
|
+
obj = rb_funcall(receiver, rb_intern("field"), 2,
|
|
2894
|
+
rb_ary_entry(info, 0), rb_ary_entry(info, 1));
|
|
2895
|
+
}
|
|
2896
|
+
obj = rb_funcall(obj, rb_intern("endian"), 1, endian);
|
|
2897
|
+
rb_hash_aset(member, sym, obj);
|
|
2898
|
+
return obj;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2457
2901
|
obj = rb_apply(receiver, rb_intern("field"), info);
|
|
2458
2902
|
rb_hash_aset(member, sym, obj);
|
|
2459
2903
|
return obj;
|
|
2460
2904
|
}
|
|
2461
2905
|
}
|
|
2462
2906
|
|
|
2907
|
+
/* A field is a view on the record array's storage, below the Face, so the
|
|
2908
|
+
read-only state of the record array (frozen, or a read-only view) is not
|
|
2909
|
+
on its parent chain; the field carries it itself. */
|
|
2910
|
+
VALUE
|
|
2911
|
+
rb_ca_face_field (VALUE self, VALUE sym)
|
|
2912
|
+
{
|
|
2913
|
+
volatile VALUE obj = ca_face_field_lookup(self, sym);
|
|
2914
|
+
CArray *ca, *co;
|
|
2915
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2916
|
+
if ( ca_is_readonly(ca) && rb_obj_is_carray(obj) ) {
|
|
2917
|
+
TypedData_Get_Struct(obj, CArray, &carray_data_type, co);
|
|
2918
|
+
ca_set_flag(co, CA_FLAG_READ_ONLY);
|
|
2919
|
+
}
|
|
2920
|
+
return obj;
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2463
2923
|
/* @overload fields
|
|
2464
2924
|
|
|
2465
2925
|
(Reference) Returns an array of data class members (fields)
|
|
@@ -2472,7 +2932,7 @@ rb_ca_fields (VALUE self)
|
|
|
2472
2932
|
volatile VALUE member_names, list;
|
|
2473
2933
|
int i;
|
|
2474
2934
|
if ( NIL_P(data_class) ) {
|
|
2475
|
-
rb_raise(
|
|
2935
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2476
2936
|
}
|
|
2477
2937
|
member_names = rb_const_get(data_class, rb_intern("MEMBERS"));
|
|
2478
2938
|
list = rb_ary_new2(RARRAY_LEN(member_names));
|
|
@@ -2495,7 +2955,7 @@ rb_ca_fields_at (int argc, VALUE *argv, VALUE self)
|
|
|
2495
2955
|
volatile VALUE member_names, list;
|
|
2496
2956
|
int i;
|
|
2497
2957
|
if ( NIL_P(data_class) ) {
|
|
2498
|
-
rb_raise(
|
|
2958
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2499
2959
|
}
|
|
2500
2960
|
member_names = rb_ary_new4(argc, argv);
|
|
2501
2961
|
list = rb_ary_new2(RARRAY_LEN(member_names));
|
|
@@ -2515,6 +2975,7 @@ Init_carray_core (void)
|
|
|
2515
2975
|
|
|
2516
2976
|
ca_init_obj_type();
|
|
2517
2977
|
|
|
2978
|
+
#ifdef CARRAY_DEV_BUILD
|
|
2518
2979
|
rb_define_singleton_method(rb_cCArray, "attach", rb_ca_s_attach, -1);
|
|
2519
2980
|
rb_define_singleton_method(rb_cCArray, "attach!", rb_ca_s_attach_bang, -1);
|
|
2520
2981
|
|
|
@@ -2525,6 +2986,17 @@ Init_carray_core (void)
|
|
|
2525
2986
|
rb_define_method(rb_cCArray, "__sync__", rb_ca__sync__, 0);
|
|
2526
2987
|
rb_define_method(rb_cCArray, "__detach__", rb_ca__detach__, 0);
|
|
2527
2988
|
|
|
2989
|
+
rb_define_singleton_method(rb_cCArray, "__attached_views__",
|
|
2990
|
+
rb_ca_s_attached_views, 0);
|
|
2991
|
+
|
|
2992
|
+
{
|
|
2993
|
+
const char *general = getenv("CARRAY_GENERAL_PATH");
|
|
2994
|
+
ca_fast_paths_on = !( general && general[0] && strcmp(general, "0") );
|
|
2995
|
+
}
|
|
2996
|
+
rb_define_singleton_method(rb_cCArray, "__fast_paths_enabled__",
|
|
2997
|
+
rb_ca_s_fast_paths_enabled, 0);
|
|
2998
|
+
#endif
|
|
2999
|
+
|
|
2528
3000
|
rb_define_method(rb_cCArray, "members", rb_ca_members, 0);
|
|
2529
3001
|
|
|
2530
3002
|
rb_define_method(rb_cCArray, "fields", rb_ca_fields, 0);
|