carray 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +149 -27
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +102 -79
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/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,36 @@ 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
|
}
|
|
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
1731
|
}
|
|
1657
1732
|
|
|
1658
1733
|
/* The first attach of a view: materialise through the type's slot, then
|
|
@@ -1660,10 +1735,21 @@ ca_allocate (void *ap)
|
|
|
1660
1735
|
static VALUE
|
|
1661
1736
|
ca_attach_view_first (VALUE arg)
|
|
1662
1737
|
{
|
|
1663
|
-
CArray *ca
|
|
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. */
|
|
1664
1748
|
ca_func[ca->obj_type].attach(ca);
|
|
1665
1749
|
ca_update_mask(ca);
|
|
1666
|
-
|
|
1750
|
+
if ( ca->mask == mask0 ) {
|
|
1751
|
+
ca_attach(ca->mask);
|
|
1752
|
+
}
|
|
1667
1753
|
return Qnil;
|
|
1668
1754
|
}
|
|
1669
1755
|
|
|
@@ -1684,7 +1770,7 @@ ca_attach (void *ap)
|
|
|
1684
1770
|
rb_raise(rb_eRuntimeError,
|
|
1685
1771
|
"too large attach count of view array");
|
|
1686
1772
|
}
|
|
1687
|
-
|
|
1773
|
+
CA_VIEW_ATTACH_STEP(ca, 1); /* increments attach level */
|
|
1688
1774
|
|
|
1689
1775
|
if ( ! ca->ptr ) {
|
|
1690
1776
|
/* A slot can raise part way (a conversion meeting a value it cannot
|
|
@@ -1700,7 +1786,7 @@ ca_attach (void *ap)
|
|
|
1700
1786
|
ca_func[ca->obj_type].detach(ca);
|
|
1701
1787
|
ca->ptr = NULL;
|
|
1702
1788
|
}
|
|
1703
|
-
|
|
1789
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1704
1790
|
rb_jump_tag(tag);
|
|
1705
1791
|
}
|
|
1706
1792
|
return;
|
|
@@ -1710,8 +1796,13 @@ ca_attach (void *ap)
|
|
|
1710
1796
|
ca_func[ca->obj_type].attach(ap);
|
|
1711
1797
|
}
|
|
1712
1798
|
|
|
1713
|
-
|
|
1714
|
-
|
|
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
|
+
}
|
|
1715
1806
|
}
|
|
1716
1807
|
|
|
1717
1808
|
/* Attach every array in list[0..n-1], or, if one of those attaches
|
|
@@ -1751,6 +1842,168 @@ ca_attach_all (CArray **list, int32_t n)
|
|
|
1751
1842
|
}
|
|
1752
1843
|
}
|
|
1753
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;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1754
2007
|
/* attach parent's data to ca->ptr */
|
|
1755
2008
|
|
|
1756
2009
|
void
|
|
@@ -1799,8 +2052,13 @@ ca_sync (void *ap)
|
|
|
1799
2052
|
"can not modify read-only array");
|
|
1800
2053
|
}
|
|
1801
2054
|
|
|
1802
|
-
|
|
1803
|
-
|
|
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
|
+
}
|
|
1804
2062
|
|
|
1805
2063
|
if ( ca_is_view(ca) ) { /* view array */
|
|
1806
2064
|
if ( ! CAVIEW(ca)->nosync ) { /* FIXME : */
|
|
@@ -1813,6 +2071,42 @@ ca_sync (void *ap)
|
|
|
1813
2071
|
|
|
1814
2072
|
}
|
|
1815
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
|
+
|
|
1816
2110
|
/* make ca->ptr to be detached */
|
|
1817
2111
|
|
|
1818
2112
|
void
|
|
@@ -1833,38 +2127,86 @@ ca_detach (void *ap)
|
|
|
1833
2127
|
if ( CAVIEW(ca)->attach == 1 ) {
|
|
1834
2128
|
ca_func[ca->obj_type].detach(ap);
|
|
1835
2129
|
}
|
|
1836
|
-
|
|
2130
|
+
CA_VIEW_ATTACH_STEP(ca, -1);
|
|
1837
2131
|
}
|
|
1838
2132
|
else { /* entity array */
|
|
1839
2133
|
ca_func[ca->obj_type].detach(ap);
|
|
1840
2134
|
}
|
|
1841
2135
|
|
|
1842
|
-
|
|
1843
|
-
|
|
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
|
+
}
|
|
1844
2143
|
}
|
|
1845
2144
|
|
|
1846
2145
|
/* multiple versions of ca_allocate, ca_attach, ca_sync, ca_detach */
|
|
1847
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
|
+
|
|
1848
2184
|
void
|
|
1849
2185
|
ca_allocate_n (int n, ...)
|
|
1850
2186
|
{
|
|
2187
|
+
CArray **list = ALLOCA_N(CArray *, n > 0 ? n : 1);
|
|
1851
2188
|
va_list args;
|
|
2189
|
+
int i;
|
|
1852
2190
|
va_start(args, n);
|
|
1853
|
-
|
|
1854
|
-
|
|
2191
|
+
for ( i = 0; i < n; i++ ) {
|
|
2192
|
+
list[i] = va_arg(args, CArray *);
|
|
1855
2193
|
}
|
|
1856
2194
|
va_end(args);
|
|
2195
|
+
ca_allocate_all(list, n);
|
|
1857
2196
|
}
|
|
1858
2197
|
|
|
1859
2198
|
void
|
|
1860
2199
|
ca_attach_n (int n, ...)
|
|
1861
2200
|
{
|
|
2201
|
+
CArray **list = ALLOCA_N(CArray *, n > 0 ? n : 1);
|
|
1862
2202
|
va_list args;
|
|
2203
|
+
int i;
|
|
1863
2204
|
va_start(args, n);
|
|
1864
|
-
|
|
1865
|
-
|
|
2205
|
+
for ( i = 0; i < n; i++ ) {
|
|
2206
|
+
list[i] = va_arg(args, CArray *);
|
|
1866
2207
|
}
|
|
1867
2208
|
va_end(args);
|
|
2209
|
+
ca_attach_all(list, n);
|
|
1868
2210
|
}
|
|
1869
2211
|
|
|
1870
2212
|
void
|
|
@@ -1989,15 +2331,12 @@ ca_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
|
1989
2331
|
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
1990
2332
|
{
|
|
1991
2333
|
CArray *ca = (CArray *) ap;
|
|
1992
|
-
int8_t k;
|
|
1993
2334
|
|
|
1994
2335
|
if ( ca_is_readonly(ca) ) {
|
|
1995
2336
|
rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
|
|
1996
2337
|
}
|
|
1997
2338
|
|
|
1998
|
-
|
|
1999
|
-
if ( counts[k] <= 0 ) return;
|
|
2000
|
-
}
|
|
2339
|
+
if ( ca_region_is_empty(ndim, counts) ) return;
|
|
2001
2340
|
|
|
2002
2341
|
if ( ca_func[ca->obj_type].fill_stride ) {
|
|
2003
2342
|
ca_func[ca->obj_type].fill_stride(ap, base, ndim, counts, steps, ptr);
|
|
@@ -2144,7 +2483,7 @@ ca_fill (void *ap, void *aptr)
|
|
|
2144
2483
|
char *ptr = (char *) aptr;
|
|
2145
2484
|
|
|
2146
2485
|
if ( ca_is_readonly(ca) ) {
|
|
2147
|
-
rb_raise(rb_eRuntimeError, "can
|
|
2486
|
+
rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
|
|
2148
2487
|
}
|
|
2149
2488
|
|
|
2150
2489
|
ca_fill_data(ap, ptr);
|
|
@@ -2425,7 +2764,7 @@ rb_ca_members (VALUE self)
|
|
|
2425
2764
|
{
|
|
2426
2765
|
volatile VALUE data_class = rb_ca_data_class(self);
|
|
2427
2766
|
if ( NIL_P(data_class) ) {
|
|
2428
|
-
rb_raise(
|
|
2767
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2429
2768
|
}
|
|
2430
2769
|
else {
|
|
2431
2770
|
return rb_obj_clone(rb_const_get(data_class, rb_intern("MEMBERS")));
|
|
@@ -2438,8 +2777,8 @@ rb_ca_members (VALUE self)
|
|
|
2438
2777
|
(= Face strip): the @member cache lives on self (the Face) while the
|
|
2439
2778
|
actual field view is the CAField on the parent. A plain FIXLEN entity
|
|
2440
2779
|
keeps self == receiver. */
|
|
2441
|
-
VALUE
|
|
2442
|
-
|
|
2780
|
+
static VALUE
|
|
2781
|
+
ca_face_field_lookup (VALUE self, VALUE sym)
|
|
2443
2782
|
{
|
|
2444
2783
|
volatile VALUE data_class = rb_ca_data_class(self);
|
|
2445
2784
|
volatile VALUE member;
|
|
@@ -2448,7 +2787,7 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2448
2787
|
CArray *ca;
|
|
2449
2788
|
|
|
2450
2789
|
if ( NIL_P(data_class) ) {
|
|
2451
|
-
rb_raise(
|
|
2790
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2452
2791
|
}
|
|
2453
2792
|
|
|
2454
2793
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -2464,7 +2803,9 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2464
2803
|
is local to the derived view; field views are still on its parent
|
|
2465
2804
|
(which itself is on the entity). */
|
|
2466
2805
|
member = rb_hash_new();
|
|
2467
|
-
|
|
2806
|
+
if ( ! OBJ_FROZEN(self) ) {
|
|
2807
|
+
rb_ivar_set(self, rb_intern("member"), member);
|
|
2808
|
+
}
|
|
2468
2809
|
}
|
|
2469
2810
|
|
|
2470
2811
|
if ( rb_obj_is_kind_of(sym, rb_cInteger) ) {
|
|
@@ -2490,7 +2831,7 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2490
2831
|
if ( TYPE(sym) != T_STRING ) {
|
|
2491
2832
|
sym = rb_funcall(sym, rb_intern("to_s"), 0);
|
|
2492
2833
|
}
|
|
2493
|
-
rb_raise(
|
|
2834
|
+
rb_raise(rb_eArgError,
|
|
2494
2835
|
"can't find data_member named <%s>", StringValuePtr(sym));
|
|
2495
2836
|
}
|
|
2496
2837
|
Check_Type(info, T_ARRAY);
|
|
@@ -2532,12 +2873,53 @@ rb_ca_face_field (VALUE self, VALUE sym)
|
|
|
2532
2873
|
return obj;
|
|
2533
2874
|
}
|
|
2534
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
|
+
}
|
|
2535
2901
|
obj = rb_apply(receiver, rb_intern("field"), info);
|
|
2536
2902
|
rb_hash_aset(member, sym, obj);
|
|
2537
2903
|
return obj;
|
|
2538
2904
|
}
|
|
2539
2905
|
}
|
|
2540
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
|
+
|
|
2541
2923
|
/* @overload fields
|
|
2542
2924
|
|
|
2543
2925
|
(Reference) Returns an array of data class members (fields)
|
|
@@ -2550,7 +2932,7 @@ rb_ca_fields (VALUE self)
|
|
|
2550
2932
|
volatile VALUE member_names, list;
|
|
2551
2933
|
int i;
|
|
2552
2934
|
if ( NIL_P(data_class) ) {
|
|
2553
|
-
rb_raise(
|
|
2935
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2554
2936
|
}
|
|
2555
2937
|
member_names = rb_const_get(data_class, rb_intern("MEMBERS"));
|
|
2556
2938
|
list = rb_ary_new2(RARRAY_LEN(member_names));
|
|
@@ -2573,7 +2955,7 @@ rb_ca_fields_at (int argc, VALUE *argv, VALUE self)
|
|
|
2573
2955
|
volatile VALUE member_names, list;
|
|
2574
2956
|
int i;
|
|
2575
2957
|
if ( NIL_P(data_class) ) {
|
|
2576
|
-
rb_raise(
|
|
2958
|
+
rb_raise(rb_eTypeError, "carray doesn't have data class");
|
|
2577
2959
|
}
|
|
2578
2960
|
member_names = rb_ary_new4(argc, argv);
|
|
2579
2961
|
list = rb_ary_new2(RARRAY_LEN(member_names));
|
|
@@ -2603,6 +2985,16 @@ Init_carray_core (void)
|
|
|
2603
2985
|
rb_define_method(rb_cCArray, "__attach__", rb_ca__attach__, 0);
|
|
2604
2986
|
rb_define_method(rb_cCArray, "__sync__", rb_ca__sync__, 0);
|
|
2605
2987
|
rb_define_method(rb_cCArray, "__detach__", rb_ca__detach__, 0);
|
|
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);
|
|
2606
2998
|
#endif
|
|
2607
2999
|
|
|
2608
3000
|
rb_define_method(rb_cCArray, "members", rb_ca_members, 0);
|