carray 2.0.0 → 3.0.0
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/.yardopts +5 -25
- data/CHANGELOG.md +16 -0
- data/LICENSE +1 -1
- data/NEWS.md +3 -0
- data/README.md +128 -44
- data/carray.gemspec +22 -24
- data/ext/ca_array_pool.c +91 -0
- data/ext/ca_axis_descriptor.h +186 -0
- data/ext/ca_axis_dispatch.c +924 -0
- data/ext/ca_axis_group.c +1208 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +125 -0
- data/ext/ca_binop_dispatch.h +159 -0
- data/ext/ca_categorical_iterator.c +1375 -0
- data/ext/ca_compare.c +94 -0
- data/ext/ca_compare.h +26 -0
- data/ext/ca_composite_dispatch.c +414 -0
- data/ext/ca_composite_dispatch.h +116 -0
- data/ext/ca_for_buffer.h +96 -0
- data/ext/ca_for_each_element.h +241 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4321 -0
- data/ext/ca_kernel_iterator.h +2603 -0
- data/ext/ca_moncmp_dispatch.c +37 -0
- data/ext/ca_moncmp_dispatch.h +62 -0
- data/ext/ca_monop_dispatch.c +200 -0
- data/ext/ca_monop_dispatch.h +235 -0
- data/ext/ca_obj_array.c +355 -359
- data/ext/ca_obj_bincmp.c +809 -0
- data/ext/ca_obj_binop.c +892 -0
- data/ext/ca_obj_bitarray.c +369 -164
- data/ext/ca_obj_bitfield.c +294 -234
- data/ext/ca_obj_block.c +189 -711
- data/ext/ca_obj_byte_swap.c +766 -0
- data/ext/ca_obj_const_string.c +965 -0
- data/ext/ca_obj_face.c +670 -0
- data/ext/ca_obj_face.h +247 -0
- data/ext/ca_obj_fake.c +228 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +306 -0
- data/ext/ca_obj_grid.c +858 -440
- data/ext/ca_obj_meld.c +1034 -0
- data/ext/ca_obj_moncmp.c +569 -0
- data/ext/ca_obj_monop.c +1111 -0
- data/ext/ca_obj_object.c +774 -298
- data/ext/ca_obj_record.c +468 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +569 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +616 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1296 -0
- data/ext/ca_obj_shift.c +230 -792
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2501 -0
- data/ext/ca_obj_string.c +268 -0
- data/ext/ca_obj_tile.c +614 -0
- data/ext/ca_obj_time.c +546 -0
- data/ext/ca_obj_timedelta.c +435 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +746 -0
- data/ext/ca_obj_unbound_repeat.c +208 -241
- data/ext/ca_obj_window.c +1131 -563
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_ipower.c +319 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +430 -0
- data/ext/ca_sweep_engine.h +157 -0
- data/ext/ca_transform_common.c +228 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +795 -402
- data/ext/carray_access.c +831 -711
- data/ext/carray_attribute.c +98 -330
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +283 -0
- data/ext/carray_call_cfunc.c +1360 -828
- data/ext/carray_call_cfunc.h +160 -0
- data/ext/carray_cast.c +1212 -301
- data/ext/carray_cast_func.rb +81 -40
- data/ext/carray_class.c +53 -63
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +350 -346
- data/ext/carray_copy.c +156 -268
- data/ext/carray_core.c +1342 -199
- data/ext/carray_count.c +312 -0
- data/ext/carray_data_type.c +43 -19
- data/ext/carray_element.c +585 -213
- data/ext/carray_factorize.c +2542 -0
- data/ext/carray_generate.c +230 -559
- data/ext/carray_histogram.c +490 -0
- data/ext/carray_hold.c +228 -0
- data/ext/carray_index_classifier.c +1035 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +120 -0
- data/ext/carray_kernels_bincmp.c +4445 -0
- data/ext/carray_kernels_binop.c +10979 -0
- data/ext/carray_kernels_init.c +36 -0
- data/ext/carray_kernels_map.c +3466 -0
- data/ext/carray_kernels_moncmp.c +2096 -0
- data/ext/carray_kernels_monop.c +18312 -0
- data/ext/carray_kernels_reduce_aggregate.c +25836 -0
- data/ext/carray_kernels_reduce_boolean.c +329 -0
- data/ext/carray_kernels_reduce_cumulative.c +14592 -0
- data/ext/carray_kernels_reduce_extreme.c +16947 -0
- data/ext/carray_kernels_reduce_variance.c +3909 -0
- data/ext/carray_kernels_scan.c +3692 -0
- data/ext/carray_kernels_search.c +32137 -0
- data/ext/carray_kernels_sort.c +10625 -0
- data/ext/carray_kernels_triop.c +1391 -0
- data/ext/carray_lazy.c +567 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +848 -154
- data/ext/carray_math_kernel.h +120 -0
- data/ext/carray_mathfunc.c +10 -241
- data/ext/carray_median_percentile.c +1257 -0
- data/ext/carray_memory_view.c +1625 -0
- data/ext/carray_operator.c +1526 -318
- data/ext/carray_order.c +664 -1394
- data/ext/carray_partition.c +416 -0
- data/ext/carray_random.c +518 -0
- data/ext/carray_scatter.c +357 -0
- data/ext/carray_slab.c +1219 -0
- data/ext/carray_slab.h +84 -0
- data/ext/carray_sort.c +829 -0
- data/ext/carray_sort_kernel.c +620 -0
- data/ext/carray_struct.c +695 -0
- data/ext/carray_test.c +343 -229
- data/ext/carray_undef.c +34 -17
- data/ext/carray_utils.c +175 -74
- data/ext/extconf.rb +216 -55
- data/ext/mk_call_cfunc.rb +480 -0
- data/ext/mkkernel.rb +8842 -0
- data/ext/ruby_carray.c +202 -101
- data/ext/version.h +4 -14
- data/ext/version.rb +5 -13
- data/lib/carray/arrow_tensor.rb +401 -0
- data/lib/carray/attribute.rb +166 -0
- data/lib/carray/autoload_carray.rb +220 -0
- data/lib/carray/autoload_method_extension.rb +44 -0
- data/lib/carray/axis_group.rb +711 -0
- data/lib/carray/basics.rb +481 -0
- data/lib/carray/bincount_nd.rb +358 -0
- data/lib/carray/block_iterator.rb +604 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1062 -0
- data/lib/carray/complex.rb +150 -0
- data/lib/carray/conditional.rb +216 -0
- data/lib/carray/const_string.rb +228 -0
- data/lib/carray/construct.rb +139 -328
- data/lib/carray/core_extensions.rb +240 -0
- data/lib/carray/data_type_extension.rb +233 -0
- data/lib/carray/fixlen_string.rb +95 -0
- data/lib/carray/frame/concat.rb +132 -0
- data/lib/carray/frame/convert.rb +95 -0
- data/lib/carray/frame/csv_parser.rb +211 -0
- data/lib/carray/frame/frame.rb +649 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +164 -0
- data/lib/carray/frame/join.rb +248 -0
- data/lib/carray/frame/records.rb +99 -0
- data/lib/carray/frame/sort.rb +113 -0
- data/lib/carray/frame/verbs.rb +299 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -20
- data/lib/carray/iterator.rb +57 -349
- data/lib/carray/lazy.rb +889 -0
- data/lib/carray/mask_gap_fill.rb +200 -0
- data/lib/carray/math.rb +78 -342
- data/lib/carray/meld_reduce.rb +289 -0
- data/lib/carray/methods/align_addr.rb +116 -0
- data/lib/carray/methods/bin.rb +128 -0
- data/lib/carray/methods/bincount.rb +87 -0
- data/lib/carray/methods/bit_string.rb +92 -0
- data/lib/carray/methods/broadcast.rb +63 -0
- data/lib/carray/methods/choose.rb +39 -0
- data/lib/carray/methods/composition.rb +280 -0
- data/lib/carray/methods/gather_nd.rb +206 -0
- data/lib/carray/methods/index.rb +39 -0
- data/lib/carray/methods/insert_block.rb +99 -0
- data/lib/carray/methods/is_in.rb +141 -0
- data/lib/carray/methods/join.rb +90 -0
- data/lib/carray/methods/locate_addr.rb +47 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +91 -0
- data/lib/carray/methods/mode.rb +126 -0
- data/lib/carray/methods/nunique.rb +46 -0
- data/lib/carray/methods/resize.rb +56 -0
- data/lib/carray/methods/snap.rb +156 -0
- data/lib/carray/methods/string_format.rb +57 -0
- data/lib/carray/methods/unique.rb +47 -0
- data/lib/carray/methods/value_counts.rb +71 -0
- data/lib/carray/mkmf.rb +124 -101
- data/lib/carray/runtime.rb +108 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +292 -0
- data/lib/carray/stack.rb +291 -0
- data/lib/carray/string.rb +56 -180
- data/lib/carray/string_operation_extension.rb +289 -0
- data/lib/carray/struct.rb +335 -323
- data/lib/carray/struct_builder.rb +697 -0
- data/lib/carray/table.rb +41 -2
- data/lib/carray/time.rb +2255 -38
- data/lib/carray/window_iterator.rb +655 -0
- data/lib/carray.rb +55 -57
- metadata +163 -130
- data/Rakefile +0 -51
- data/TODO.md +0 -18
- data/ext/ca_iter_block.c +0 -257
- data/ext/ca_iter_dimension.c +0 -299
- data/ext/ca_iter_window.c +0 -214
- data/ext/ca_obj_mapping.c +0 -644
- data/ext/carray_iterator.c +0 -641
- data/ext/carray_math.rb +0 -850
- data/ext/carray_numeric.c +0 -259
- data/ext/carray_sort_addr.c +0 -254
- data/ext/carray_stat.c +0 -2100
- data/ext/carray_stat_proc.rb +0 -1999
- data/ext/mkmath.rb +0 -741
- data/ext/ruby_ccomplex.c +0 -509
- data/ext/ruby_float_func.c +0 -86
- data/lib/carray/array.rb +0 -8
- data/lib/carray/autoload/autoload_base.rb +0 -19
- data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
- data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
- data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
- data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
- data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
- data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
- data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
- data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
- data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
- data/lib/carray/autoload/autoload_gem_random.rb +0 -8
- data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
- data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
- data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
- data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
- data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
- data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
- data/lib/carray/autoload/autoload_object_link.rb +0 -1
- data/lib/carray/autoload/autoload_object_pack.rb +0 -2
- data/lib/carray/autoload.rb +0 -141
- data/lib/carray/basic.rb +0 -191
- data/lib/carray/broadcast.rb +0 -101
- data/lib/carray/compose.rb +0 -315
- data/lib/carray/convert.rb +0 -115
- data/lib/carray/info.rb +0 -110
- data/lib/carray/io/imagemagick.rb +0 -235
- data/lib/carray/mask.rb +0 -102
- data/lib/carray/math/histogram.rb +0 -177
- data/lib/carray/math/recurrence.rb +0 -93
- data/lib/carray/object/ca_obj_iterator.rb +0 -50
- data/lib/carray/object/ca_obj_link.rb +0 -50
- data/lib/carray/object/ca_obj_pack.rb +0 -99
- data/lib/carray/obsolete.rb +0 -256
- data/lib/carray/ordering.rb +0 -181
- data/lib/carray/testing.rb +0 -51
- data/lib/carray/transform.rb +0 -109
- data/misc/Methods.ja.md +0 -182
- data/misc/NOTE +0 -51
- data/spec/Classes/CABitfield_spec.rb +0 -58
- data/spec/Classes/CABlockIterator_spec.rb +0 -114
- data/spec/Classes/CABlock_spec.rb +0 -205
- data/spec/Classes/CAField_spec.rb +0 -39
- data/spec/Classes/CAGrid_spec.rb +0 -75
- data/spec/Classes/CAMap_spec.rb +0 -0
- data/spec/Classes/CAMapping_spec.rb +0 -105
- data/spec/Classes/CAObject_attribute_spec.rb +0 -33
- data/spec/Classes/CAObject_spec.rb +0 -33
- data/spec/Classes/CARefer_spec.rb +0 -93
- data/spec/Classes/CARepeat_spec.rb +0 -65
- data/spec/Classes/CASelect_spec.rb +0 -22
- data/spec/Classes/CAShift_spec.rb +0 -16
- data/spec/Classes/CAStruct_spec.rb +0 -71
- data/spec/Classes/CATranspose_spec.rb +0 -60
- data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
- data/spec/Classes/CAWindow_spec.rb +0 -54
- data/spec/Classes/CAWrap_spec.rb +0 -8
- data/spec/Classes/CArray_spec.rb +0 -184
- data/spec/Classes/CScalar_spec.rb +0 -55
- data/spec/Classes/ex1.rb +0 -46
- data/spec/Features/feature_130_spec.rb +0 -19
- data/spec/Features/feature_attributes_spec.rb +0 -280
- data/spec/Features/feature_boolean_spec.rb +0 -98
- data/spec/Features/feature_broadcast.rb +0 -116
- data/spec/Features/feature_cast_function.rb +0 -19
- data/spec/Features/feature_cast_spec.rb +0 -33
- data/spec/Features/feature_class_spec.rb +0 -84
- data/spec/Features/feature_complex_spec.rb +0 -42
- data/spec/Features/feature_composite_spec.rb +0 -124
- data/spec/Features/feature_convert_spec.rb +0 -46
- data/spec/Features/feature_copy_spec.rb +0 -123
- data/spec/Features/feature_creation_spec.rb +0 -84
- data/spec/Features/feature_element_spec.rb +0 -144
- data/spec/Features/feature_extream_spec.rb +0 -54
- data/spec/Features/feature_generate_spec.rb +0 -74
- data/spec/Features/feature_index_spec.rb +0 -69
- data/spec/Features/feature_mask_spec.rb +0 -580
- data/spec/Features/feature_math_spec.rb +0 -97
- data/spec/Features/feature_order_spec.rb +0 -146
- data/spec/Features/feature_ref_store_spec.rb +0 -209
- data/spec/Features/feature_serialization_spec.rb +0 -125
- data/spec/Features/feature_stat_spec.rb +0 -397
- data/spec/Features/feature_virtual_spec.rb +0 -48
- data/spec/Features/method_eq_spec.rb +0 -81
- data/spec/Features/method_is_nan_spec.rb +0 -12
- data/spec/Features/method_map_spec.rb +0 -54
- data/spec/Features/method_max_with.rb +0 -20
- data/spec/Features/method_min_with.rb +0 -19
- data/spec/Features/method_ne_spec.rb +0 -18
- data/spec/Features/method_project_spec.rb +0 -188
- data/spec/Features/method_ref_spec.rb +0 -27
- data/spec/Features/method_round_spec.rb +0 -11
- data/spec/Features/method_s_linspace_spec.rb +0 -48
- data/spec/Features/method_s_span_spec.rb +0 -14
- data/spec/Features/method_seq_spec.rb +0 -47
- data/spec/Features/method_sort_with.rb +0 -43
- data/spec/Features/method_sorted_with.rb +0 -29
- data/spec/Features/method_span_spec.rb +0 -42
- data/spec/Features/method_wrap_readonly_spec.rb +0 -43
- data/spec/UnitTest/test_CAVirtual.rb +0 -214
- data/spec/spec_all.rb +0 -10
- data/utils/ca_ase.rb +0 -21
- data/utils/ca_methods.rb +0 -15
- data/utils/cast_checker.rb +0 -30
- data/utils/convert_test.rb +0 -73
- data/utils/extract_yard.rb +0 -22
- data/utils/guess_shape.rb +0 -76
- data/utils/monkey_patch_methods.rb +0 -62
- data/utils/remove_resource_fork.sh +0 -5
data/ext/ca_obj_window.c
CHANGED
|
@@ -1,36 +1,111 @@
|
|
|
1
1
|
/* ---------------------------------------------------------------------------
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CAWindow: a sliding rectangular view of the parent whose cells may fall
|
|
4
|
+
outside it. Each axis carries a start / count and a bounds policy that says
|
|
5
|
+
what an out-of-range (OOB) cell means: FILL / MASK give it `ca->fill` (or
|
|
6
|
+
mask it), NEAREST / RUBY / STRICT normalise or reject the index.
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
CAShift is a typedef of this struct (ca_obj_shift.c) and shares the whole
|
|
9
|
+
operation table, so every path here serves both.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
Two internal models coexist, chosen per view by ca_window_recompute_embed:
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
embed model (FILL / MASK on every axis, embed_eligible)
|
|
14
|
+
The view decomposes into one alias rectangle (the part of the parent it
|
|
15
|
+
actually addresses, embed_*) plus its fill complement (the OOB part).
|
|
16
|
+
Attach / xfer are then "1 typed fill + 1 strided memcpy", with no
|
|
17
|
+
per-cell bound check. A window whose inner axes are full and which sits
|
|
18
|
+
entirely inside the parent (embed_alias_eligible) skips even that and
|
|
19
|
+
aliases the parent's buffer.
|
|
20
|
+
|
|
21
|
+
descriptor engine (any other bounds policy)
|
|
22
|
+
ca_window_describe_axes emits a per-axis descriptor and the shared engine
|
|
23
|
+
(ca_axis_dispatch.c) applies the policy per cell.
|
|
24
|
+
|
|
25
|
+
Region-copy helpers shared with CATile / CAStack live in
|
|
26
|
+
ca_composite_dispatch.c (included above).
|
|
27
|
+
|
|
28
|
+
--------------------------------------------------------------------------- */
|
|
10
29
|
|
|
11
30
|
#include "carray.h"
|
|
31
|
+
#include "ca_composite_dispatch.h"
|
|
32
|
+
#include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE, used by rb_ca_window */
|
|
12
33
|
|
|
13
34
|
/* should not be static variable as used by CAIteratorWindow */
|
|
14
35
|
|
|
36
|
+
static size_t
|
|
37
|
+
ca_window_dsize (const void *ap)
|
|
38
|
+
{
|
|
39
|
+
const CAWindow *ca = (const CAWindow *) ap;
|
|
40
|
+
/* dim points to count; start, count, size0 are each ALLOC_N(ndim);
|
|
41
|
+
bounds is ALLOC_N(uint8_t, ndim) (per-axis);
|
|
42
|
+
fill is ALLOC_N(bytes);
|
|
43
|
+
embed_{parent_start,count,output_offset} are each ALLOC_N(ndim). */
|
|
44
|
+
return sizeof(CAWindow) + 6 * ca->ndim * sizeof(ca_size_t)
|
|
45
|
+
+ ca->ndim * sizeof(uint8_t) + ca->bytes;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Pool framework hooks for CAWindow. CAWindow owns eight variable-size tail
|
|
49
|
+
fields; seven of them are ndim-sized and move into a single _pool buffer:
|
|
50
|
+
|
|
51
|
+
6 * ndim ca_size_t : start, count, size0,
|
|
52
|
+
embed_parent_start, embed_count, embed_output_offset
|
|
53
|
+
1 * ndim uint8_t : bounds
|
|
54
|
+
|
|
55
|
+
`dim` aliases `count` (no allocation). The eighth field, `fill`, is
|
|
56
|
+
`bytes`-sized (element width, not ndim) and the ndim-only pool_bytes/
|
|
57
|
+
pool_init signature cannot size it; it stays on its own ALLOC_N inside
|
|
58
|
+
ca_window_setup. CAShift shares this struct and reuses these hooks via
|
|
59
|
+
the ca_window_func copy in Init_ca_obj_shift. */
|
|
60
|
+
static size_t
|
|
61
|
+
ca_window_pool_bytes (int8_t ndim)
|
|
62
|
+
{
|
|
63
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
64
|
+
return 6 * (size_t) n * sizeof(ca_size_t) + (size_t) n * sizeof(uint8_t);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static void
|
|
68
|
+
ca_window_pool_init (void *ap, int8_t ndim)
|
|
69
|
+
{
|
|
70
|
+
CAWindow *ca = (CAWindow *) ap;
|
|
71
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
72
|
+
ca_size_t *base = (ca_size_t *) ca->_pool;
|
|
73
|
+
/* six ca_size_t arrays first (8-byte aligned), then the uint8_t bounds
|
|
74
|
+
array after them. */
|
|
75
|
+
ca->start = base + 0 * n;
|
|
76
|
+
ca->count = base + 1 * n;
|
|
77
|
+
ca->size0 = base + 2 * n;
|
|
78
|
+
ca->embed_parent_start = base + 3 * n;
|
|
79
|
+
ca->embed_count = base + 4 * n;
|
|
80
|
+
ca->embed_output_offset = base + 5 * n;
|
|
81
|
+
ca->bounds = (uint8_t *) (base + 6 * n);
|
|
82
|
+
ca->dim = ca->count; /* alias; ca_window_setup re-sets */
|
|
83
|
+
}
|
|
84
|
+
|
|
15
85
|
const rb_data_type_t cawindow_data_type = {
|
|
16
|
-
.parent = &
|
|
86
|
+
.parent = &caview_data_type,
|
|
17
87
|
.wrap_struct_name = "CAWindow",
|
|
18
88
|
.function = {
|
|
19
89
|
.dmark = ca_mark,
|
|
20
90
|
.dfree = ca_free,
|
|
21
|
-
.dsize =
|
|
91
|
+
.dsize = ca_window_dsize,
|
|
22
92
|
.dcompact = NULL
|
|
23
93
|
},
|
|
24
94
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
25
95
|
};
|
|
26
96
|
|
|
97
|
+
/* CAREFUL: the mask TypedData must keep dfree = ca_free_nop. The mask CArray
|
|
98
|
+
is owned by the parent CAWindow's `ca->mask` field and freed by
|
|
99
|
+
free_ca_window's ca_free(ca->mask); if the wrapped Ruby VALUE (from the
|
|
100
|
+
`ca.mask` accessor / rb_ca_mask_array) freed it as well, GC stress would
|
|
101
|
+
double-free it. */
|
|
27
102
|
const rb_data_type_t cawindow_mask_data_type = {
|
|
28
103
|
.parent = &cawindow_data_type,
|
|
29
104
|
.wrap_struct_name = "CAWindowMask",
|
|
30
105
|
.function = {
|
|
31
106
|
.dmark = ca_mark,
|
|
32
|
-
.dfree =
|
|
33
|
-
.dsize =
|
|
107
|
+
.dfree = ca_free_nop,
|
|
108
|
+
.dsize = ca_window_dsize,
|
|
34
109
|
.dcompact = NULL
|
|
35
110
|
},
|
|
36
111
|
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
@@ -38,26 +113,525 @@ const rb_data_type_t cawindow_mask_data_type = {
|
|
|
38
113
|
|
|
39
114
|
int8_t CA_OBJ_WINDOW;
|
|
40
115
|
|
|
41
|
-
VALUE rb_cCAWindow;
|
|
42
|
-
VALUE rb_cCAWindowMask;
|
|
116
|
+
VALUE rb_cCAWindow;
|
|
117
|
+
VALUE rb_cCAWindowMask;
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
/* ------------------------------------------------------------------- */
|
|
121
|
+
|
|
122
|
+
/* Computes the embed descriptor for a CAWindow / CAShift view. The
|
|
123
|
+
descriptor decomposes the view into "1 alias region (the part of parent
|
|
124
|
+
that is actually addressable) + 1 fill complement (the OOB part)".
|
|
125
|
+
|
|
126
|
+
Inputs: parent_dim[ndim], start[ndim], count[ndim]. step is
|
|
127
|
+
implicitly 1 for CAWindow (enforced in rb_ca_window).
|
|
128
|
+
bounds[] is not read here — the embed shape is policy-independent
|
|
129
|
+
(policy decides what to put in the fill complement, not which cells
|
|
130
|
+
are in the alias).
|
|
131
|
+
|
|
132
|
+
Outputs (written into ca->embed_*):
|
|
133
|
+
embed_parent_start[k] = max(0, start[k])
|
|
134
|
+
embed_count[k] = min(start[k]+count[k], parent_dim[k])
|
|
135
|
+
- embed_parent_start[k] (clamped to >= 0)
|
|
136
|
+
embed_output_offset[k]= embed_parent_start[k] - start[k]
|
|
137
|
+
embed_is_empty = 1 if any axis has embed_count[k] <= 0
|
|
138
|
+
embed_covers_all = 1 if every axis has start[k] >= 0
|
|
139
|
+
AND start[k]+count[k] <= parent_dim[k]
|
|
140
|
+
|
|
141
|
+
Called only through ca_window_recompute_embed, which also derives the
|
|
142
|
+
eligibility flags from the result. */
|
|
143
|
+
static void
|
|
144
|
+
ca_compute_embed_descriptor (int8_t ndim,
|
|
145
|
+
ca_size_t *parent_dim,
|
|
146
|
+
ca_size_t *start,
|
|
147
|
+
ca_size_t *count,
|
|
148
|
+
ca_size_t *embed_parent_start,
|
|
149
|
+
ca_size_t *embed_count,
|
|
150
|
+
ca_size_t *embed_output_offset,
|
|
151
|
+
uint8_t *embed_is_empty,
|
|
152
|
+
uint8_t *embed_covers_all)
|
|
153
|
+
{
|
|
154
|
+
int8_t k;
|
|
155
|
+
uint8_t any_empty = 0;
|
|
156
|
+
uint8_t all_interior = 1;
|
|
157
|
+
|
|
158
|
+
for ( k = 0; k < ndim; k++ ) {
|
|
159
|
+
ca_size_t s = start[k];
|
|
160
|
+
ca_size_t c = count[k];
|
|
161
|
+
ca_size_t pd = parent_dim[k];
|
|
162
|
+
ca_size_t ps, pe, oo, ec;
|
|
163
|
+
|
|
164
|
+
ps = (s > 0) ? s : 0; /* clamp low */
|
|
165
|
+
pe = (s + c < pd) ? (s + c) : pd;/* clamp high */
|
|
166
|
+
ec = pe - ps; /* alias count this axis */
|
|
167
|
+
if ( ec < 0 ) ec = 0; /* fully outside */
|
|
168
|
+
oo = ps - s; /* output-side offset */
|
|
169
|
+
|
|
170
|
+
embed_parent_start[k] = ps;
|
|
171
|
+
embed_count[k] = ec;
|
|
172
|
+
embed_output_offset[k] = oo;
|
|
173
|
+
|
|
174
|
+
if ( ec <= 0 ) any_empty = 1;
|
|
175
|
+
if ( s < 0 || s + c > pd ) all_interior = 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
*embed_is_empty = any_empty;
|
|
179
|
+
*embed_covers_all = all_interior;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* ------------------------------------------------------------------- */
|
|
183
|
+
|
|
184
|
+
/* [MOVED] ca_fill_typed / ca_composite_region_gather / _scatter /
|
|
185
|
+
ca_composite_fill_complement -> ca_composite_dispatch.c (shared with
|
|
186
|
+
CATile / CAStack); reached via the include at the top of this file. */
|
|
187
|
+
|
|
188
|
+
/* Exposes CAWindow as a synthetic CAStride for compose-fold purposes. Used
|
|
189
|
+
by ca_stride_compose_to_root to walk *through* an interior-only CAWindow
|
|
190
|
+
without materialising it, enabling a full zero-copy chain when CAStride
|
|
191
|
+
family children wrap an interior-only CAWindow.
|
|
192
|
+
|
|
193
|
+
On success (interior-only + embed_eligible):
|
|
194
|
+
- synth_strides[k] = row-major byte stride of window->parent
|
|
195
|
+
(= bytes * Π window->parent->dim[k+1..ndim-1])
|
|
196
|
+
- synth_base = Σ embed_parent_start[k] * synth_strides[k]
|
|
197
|
+
(byte offset of embedded region start in
|
|
198
|
+
window->parent's byte space)
|
|
199
|
+
- synth_dim = pointer to window->dim (window's logical shape)
|
|
200
|
+
- synth_bytes = window->bytes
|
|
201
|
+
- synth_ndim = window->ndim
|
|
202
|
+
- next_parent = window->parent
|
|
203
|
+
Returns 1.
|
|
204
|
+
|
|
205
|
+
Caller assembles a CAStride struct from these fields and feeds it to
|
|
206
|
+
ca_stride_compose_through; the loop continues with next_parent.
|
|
207
|
+
|
|
208
|
+
Returns 0 if not foldable (= not a CAWindow / not embed_eligible /
|
|
209
|
+
not embed_covers_all). Callers must then break out of the
|
|
210
|
+
compose-fold loop and accept window as the root (= materialise via
|
|
211
|
+
ca_attach).
|
|
212
|
+
|
|
213
|
+
ndim invariant: synth_ndim equals window->ndim equals the leaf's
|
|
214
|
+
ndim by construction (CAStride children inherit ndim from parent).
|
|
215
|
+
No reshaping. */
|
|
216
|
+
int
|
|
217
|
+
ca_window_compose_fold (void *win_ap,
|
|
218
|
+
ca_size_t *synth_strides,
|
|
219
|
+
ca_size_t *synth_base,
|
|
220
|
+
ca_size_t **synth_dim,
|
|
221
|
+
ca_size_t *synth_bytes,
|
|
222
|
+
int8_t *synth_ndim,
|
|
223
|
+
CArray **next_parent)
|
|
224
|
+
{
|
|
225
|
+
CAWindow *w = (CAWindow *) win_ap;
|
|
226
|
+
ca_size_t s;
|
|
227
|
+
int8_t k;
|
|
228
|
+
|
|
229
|
+
if ( ! w->embed_eligible ) return 0;
|
|
230
|
+
if ( ! w->embed_covers_all ) return 0;
|
|
231
|
+
|
|
232
|
+
/* synth_strides = row-major byte stride over window->parent->dim */
|
|
233
|
+
s = w->bytes;
|
|
234
|
+
for ( k = w->ndim - 1; k >= 0; k-- ) {
|
|
235
|
+
synth_strides[k] = s;
|
|
236
|
+
s *= w->parent->dim[k];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* synth_base = embedded region origin in window->parent's byte space */
|
|
240
|
+
*synth_base = 0;
|
|
241
|
+
for ( k = 0; k < w->ndim; k++ ) {
|
|
242
|
+
*synth_base += w->embed_parent_start[k] * synth_strides[k];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
*synth_dim = w->dim;
|
|
246
|
+
*synth_bytes = w->bytes;
|
|
247
|
+
*synth_ndim = w->ndim;
|
|
248
|
+
*next_parent = w->parent;
|
|
249
|
+
return 1;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* fold_stride slot: compose the fold state f (leaf coords in this window's
|
|
253
|
+
byte space) through the interior
|
|
254
|
+
window into window->parent's byte space. Synthesises a CAStride layer
|
|
255
|
+
for the window-over-parent mapping (ca_window_compose_fold) and composes
|
|
256
|
+
f through it (ca_stride_compose_through). Declines (returns 0) when the
|
|
257
|
+
window is not interior-only, making the window the fold boundary. */
|
|
258
|
+
static int
|
|
259
|
+
ca_window_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
260
|
+
{
|
|
261
|
+
CAWindow *w = (CAWindow *) ap;
|
|
262
|
+
ca_size_t synth_strides[CA_RANK_MAX];
|
|
263
|
+
ca_size_t synth_base;
|
|
264
|
+
ca_size_t *synth_dim;
|
|
265
|
+
ca_size_t synth_bytes;
|
|
266
|
+
int8_t synth_ndim;
|
|
267
|
+
CArray *win_parent;
|
|
268
|
+
CAStride tmp, synth;
|
|
269
|
+
ca_size_t next_strides[CA_RANK_MAX];
|
|
270
|
+
ca_size_t next_base;
|
|
271
|
+
int8_t k;
|
|
272
|
+
|
|
273
|
+
if (!ca_window_compose_fold(w, synth_strides, &synth_base, &synth_dim,
|
|
274
|
+
&synth_bytes, &synth_ndim, &win_parent)) {
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
tmp.ndim = f->ndim;
|
|
279
|
+
tmp.bytes = synth_bytes;
|
|
280
|
+
tmp.dim = f->counts; /* leaf extent in this window's space */
|
|
281
|
+
tmp.strides = f->strides;
|
|
282
|
+
tmp.base_offset = f->base;
|
|
283
|
+
|
|
284
|
+
synth.ndim = synth_ndim;
|
|
285
|
+
synth.bytes = synth_bytes;
|
|
286
|
+
synth.dim = synth_dim;
|
|
287
|
+
synth.strides = synth_strides;
|
|
288
|
+
synth.base_offset = synth_base;
|
|
289
|
+
|
|
290
|
+
if (!ca_stride_compose_through(&tmp, &synth, next_strides, &next_base)) {
|
|
291
|
+
return 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
for (k = 0; k < f->ndim; k++) f->strides[k] = next_strides[k];
|
|
295
|
+
f->base = next_base;
|
|
296
|
+
*next_parent = win_parent;
|
|
297
|
+
return 1;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static void ca_window_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir);
|
|
301
|
+
|
|
302
|
+
/* xfer_stride: structural region delivery when a boundary-crossing CAWindow is
|
|
303
|
+
the (declining) fold boundary. The window fills the OOB cells itself and
|
|
304
|
+
hands the in-bound region to the parent via parent.xfer_stride, so no whole
|
|
305
|
+
view is materialised.
|
|
306
|
+
|
|
307
|
+
Structural path requires: FILL/MASK bounds (so OOB is a contiguous edge),
|
|
308
|
+
axis-aligned access, and unit src step (the natural window region / a
|
|
309
|
+
contiguous window slice). Other cases (PERIODIC/REFLECT/NEAREST bounds,
|
|
310
|
+
transposed / sub-sampled leaf) fall back to per-cell delivery (correct,
|
|
311
|
+
no whole-view attach). data is contiguous (semantics b). The wiring
|
|
312
|
+
guards ndim == window ndim. window.bytes == parent.bytes (no reinterpret). */
|
|
313
|
+
static void
|
|
314
|
+
ca_window_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
315
|
+
ca_size_t *strides, void *data, int dir)
|
|
316
|
+
{
|
|
317
|
+
CAWindow *w = (CAWindow *) ap;
|
|
318
|
+
CArray *parent = w->parent;
|
|
319
|
+
int8_t ndim = w->ndim;
|
|
320
|
+
int8_t inner = ndim - 1;
|
|
321
|
+
ca_size_t pnative[CA_RANK_MAX], wnative[CA_RANK_MAX], dstride[CA_RANK_MAX];
|
|
322
|
+
ca_size_t base_pos[CA_RANK_MAX]; /* window.start[k] + starts[k] (parent pos at o=0) */
|
|
323
|
+
ca_size_t lo[CA_RANK_MAX], hi[CA_RANK_MAX], o[CA_RANK_MAX];
|
|
324
|
+
ca_size_t s, n = 1, i;
|
|
325
|
+
int8_t k;
|
|
326
|
+
int structural = 1;
|
|
327
|
+
char *d = (char *) data;
|
|
328
|
+
|
|
329
|
+
s = parent->bytes;
|
|
330
|
+
for (k = ndim - 1; k >= 0; k--) { pnative[k] = s; s *= parent->dim[k]; }
|
|
331
|
+
s = w->bytes;
|
|
332
|
+
for (k = ndim - 1; k >= 0; k--) { wnative[k] = s; s *= w->dim[k]; }
|
|
333
|
+
s = w->bytes;
|
|
334
|
+
for (k = ndim - 1; k >= 0; k--) { dstride[k] = s; s *= counts[k]; }
|
|
335
|
+
for (k = 0; k < ndim; k++) n *= counts[k];
|
|
336
|
+
|
|
337
|
+
for (k = 0; k < ndim; k++) {
|
|
338
|
+
if ( (w->bounds[k] != CA_BOUNDS_FILL && w->bounds[k] != CA_BOUNDS_MASK)
|
|
339
|
+
|| strides[k] % wnative[k] != 0
|
|
340
|
+
|| strides[k] / wnative[k] != 1 ) {
|
|
341
|
+
structural = 0;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (!structural) {
|
|
347
|
+
ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
|
|
348
|
+
for (k = 0; k < ndim; k++) base += starts[k] * wnative[k];
|
|
349
|
+
for (k = 0; k < ndim; k++) idx[k] = 0;
|
|
350
|
+
while (1) {
|
|
351
|
+
ca_size_t woff = base, widx[CA_RANK_MAX];
|
|
352
|
+
for (k = 0; k < ndim; k++) woff += idx[k] * strides[k];
|
|
353
|
+
ca_addr2index((CArray *) w, woff / w->bytes, widx);
|
|
354
|
+
ca_window_func_xfer_index(w, widx, d + doff, dir);
|
|
355
|
+
doff += w->bytes;
|
|
356
|
+
k = ndim - 1;
|
|
357
|
+
while (k >= 0) { if (++idx[k] < counts[k]) break; idx[k] = 0; k--; }
|
|
358
|
+
if (k < 0) break;
|
|
359
|
+
}
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Intersect sub-region [starts, starts+counts) with the in-bound region.
|
|
364
|
+
lo[k]/hi[k] are offsets within the sub-region (= output-coordinate)
|
|
365
|
+
where the parent is in-bound. Same algebra as the per-row loop below,
|
|
366
|
+
hoisted up so the embed-based path can share it. */
|
|
367
|
+
for (k = 0; k < ndim; k++) {
|
|
368
|
+
ca_size_t l, h;
|
|
369
|
+
base_pos[k] = w->start[k] + starts[k];
|
|
370
|
+
l = -base_pos[k]; if (l < 0) l = 0;
|
|
371
|
+
h = w->size0[k] - base_pos[k]; if (h > counts[k]) h = counts[k];
|
|
372
|
+
if (h < 0) h = 0;
|
|
373
|
+
if (l > h) l = h;
|
|
374
|
+
lo[k] = l; hi[k] = h;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* Fast path: when the parent is attached (ptr != NULL), drive
|
|
378
|
+
ca_composite_region_* + fill_complement directly with the sub-region
|
|
379
|
+
intersection geometry. This collapses the outer per-row dispatch loop
|
|
380
|
+
(one ca_xfer_stride per inner row) into a single batched routine. An
|
|
381
|
+
unattached parent falls through to the per-row loop below, which is
|
|
382
|
+
equivalent but slower. */
|
|
383
|
+
if ( parent->ptr ) {
|
|
384
|
+
ca_size_t any_empty = 0;
|
|
385
|
+
ca_size_t alias_parent_start[CA_RANK_MAX];
|
|
386
|
+
ca_size_t alias_count[CA_RANK_MAX];
|
|
387
|
+
ca_size_t alias_output_offset[CA_RANK_MAX];
|
|
388
|
+
ca_size_t parent_strides[CA_RANK_MAX];
|
|
389
|
+
|
|
390
|
+
for (k = 0; k < ndim; k++) {
|
|
391
|
+
if (lo[k] >= hi[k]) { any_empty = 1; break; }
|
|
392
|
+
alias_output_offset[k] = lo[k];
|
|
393
|
+
alias_count[k] = hi[k] - lo[k];
|
|
394
|
+
alias_parent_start[k] = base_pos[k] + lo[k];
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (dir == CA_XFER_GET) {
|
|
398
|
+
if (any_empty) {
|
|
399
|
+
ca_fill_typed(d, w->fill, w->bytes, n);
|
|
400
|
+
} else {
|
|
401
|
+
ca_composite_fill_complement(d, dstride, counts,
|
|
402
|
+
alias_output_offset, alias_count,
|
|
403
|
+
w->fill, w->bytes, ndim);
|
|
404
|
+
/* parent_strides = row-major byte stride over parent->dim */
|
|
405
|
+
s = parent->bytes;
|
|
406
|
+
for (k = ndim - 1; k >= 0; k--) { parent_strides[k] = s; s *= parent->dim[k]; }
|
|
407
|
+
ca_composite_region_gather(parent->ptr, parent_strides,
|
|
408
|
+
alias_parent_start,
|
|
409
|
+
d, dstride, alias_output_offset,
|
|
410
|
+
alias_count, ndim, w->bytes);
|
|
411
|
+
}
|
|
412
|
+
} else { /* CA_XFER_PUT */
|
|
413
|
+
/* complement silent skip (no parent storage for fill region) */
|
|
414
|
+
if (!any_empty) {
|
|
415
|
+
s = parent->bytes;
|
|
416
|
+
for (k = ndim - 1; k >= 0; k--) { parent_strides[k] = s; s *= parent->dim[k]; }
|
|
417
|
+
ca_composite_region_scatter(parent->ptr, parent_strides,
|
|
418
|
+
alias_parent_start,
|
|
419
|
+
d, dstride, alias_output_offset,
|
|
420
|
+
alias_count, ndim, w->bytes);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/* Parent unattached: per-row outer loop + ca_xfer_stride(parent)
|
|
427
|
+
recursion. */
|
|
428
|
+
if (dir == CA_XFER_GET) {
|
|
429
|
+
for (i = 0; i < n; i++) memcpy(d + i * w->bytes, w->fill, w->bytes);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
for (k = 0; k < ndim; k++) {
|
|
433
|
+
if (lo[k] >= hi[k]) return; /* no in-bound cells (GET: filled; PUT: skip) */
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
for (k = 0; k < ndim; k++) o[k] = lo[k];
|
|
437
|
+
while (1) {
|
|
438
|
+
ca_size_t pbase = 0, doff = 0;
|
|
439
|
+
ca_size_t pstarts[CA_RANK_MAX], pcounts[CA_RANK_MAX], pstrides[CA_RANK_MAX];
|
|
440
|
+
ca_size_t inner_pbase;
|
|
441
|
+
for (k = 0; k < inner; k++) {
|
|
442
|
+
pbase += (base_pos[k] + o[k]) * pnative[k];
|
|
443
|
+
doff += o[k] * dstride[k];
|
|
444
|
+
}
|
|
445
|
+
inner_pbase = (base_pos[inner] + lo[inner]) * pnative[inner];
|
|
446
|
+
ca_addr2index((CArray *) parent, (pbase + inner_pbase) / parent->bytes, pstarts);
|
|
447
|
+
for (k = 0; k < ndim; k++) { pcounts[k] = 1; pstrides[k] = 0; }
|
|
448
|
+
pcounts[inner] = hi[inner] - lo[inner];
|
|
449
|
+
pstrides[inner] = pnative[inner];
|
|
450
|
+
ca_xfer_stride(parent, pstarts, pcounts, pstrides,
|
|
451
|
+
d + doff + lo[inner] * dstride[inner], dir);
|
|
452
|
+
|
|
453
|
+
k = inner - 1;
|
|
454
|
+
while (k >= 0) { o[k]++; if (o[k] < hi[k]) break; o[k] = lo[k]; k--; }
|
|
455
|
+
if (k < 0) break;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Executes the "1 typed fill + 1 strided memcpy" embed path on a
|
|
460
|
+
pre-allocated output buffer. Requires the parent to be attached (the
|
|
461
|
+
caller's responsibility).
|
|
462
|
+
|
|
463
|
+
Pre-conditions (must hold; not validated here):
|
|
464
|
+
- ca->embed_eligible == 1 (all axes FILL or MASK)
|
|
465
|
+
- ca->parent->ptr != NULL (parent attached)
|
|
466
|
+
- out_ptr points to ca->elements * ca->bytes writable bytes
|
|
467
|
+
|
|
468
|
+
Behaviour:
|
|
469
|
+
- if embed_covers_all: skip fill (alias overwrites every cell)
|
|
470
|
+
- else: fill the entire output with ca->fill (typed loop)
|
|
471
|
+
- if embed_is_empty: skip alias copy
|
|
472
|
+
- else: strided memcpy from parent[embed_parent_*] rectangle to
|
|
473
|
+
out_ptr[embed_output_*] rectangle. Inner contig run =
|
|
474
|
+
embed_count[ndim-1] * bytes. Outer axes iterate row-major
|
|
475
|
+
via a multi-dim cursor; per-axis offsets are precomputed in
|
|
476
|
+
bytes for both parent and output.
|
|
477
|
+
|
|
478
|
+
The strided copy itself is ca_composite_region_gather
|
|
479
|
+
(ca_composite_dispatch.c), shared with CATile / CAStack. */
|
|
480
|
+
static void
|
|
481
|
+
ca_window_attach_embed (CAWindow *ca, char *out_ptr)
|
|
482
|
+
{
|
|
483
|
+
int8_t ndim = ca->ndim;
|
|
484
|
+
ca_size_t bytes = ca->bytes;
|
|
485
|
+
ca_size_t parent_strides[CA_RANK_MAX];
|
|
486
|
+
ca_size_t output_strides[CA_RANK_MAX];
|
|
487
|
+
ca_size_t s;
|
|
488
|
+
int8_t k;
|
|
489
|
+
|
|
490
|
+
/* Row-major byte strides for output (used by fill-complement and
|
|
491
|
+
region-gather both). */
|
|
492
|
+
s = bytes;
|
|
493
|
+
for ( k = ndim - 1; k >= 0; k-- ) {
|
|
494
|
+
output_strides[k] = s;
|
|
495
|
+
s *= ca->count[k];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* Step 1: fill the complement of the alias rectangle only — filling the
|
|
499
|
+
whole output first would write the alias area twice. For
|
|
500
|
+
embed_is_empty (= alias is empty, whole output is fill) short-circuit
|
|
501
|
+
to a full-output typed fill since the complement is the whole output;
|
|
502
|
+
for embed_covers_all (= alias is the whole output, no fill) skip. */
|
|
503
|
+
if ( ! ca->embed_covers_all ) {
|
|
504
|
+
if ( ca->embed_is_empty ) {
|
|
505
|
+
ca_fill_typed(out_ptr, ca->fill, bytes, ca->elements);
|
|
506
|
+
} else {
|
|
507
|
+
ca_composite_fill_complement(out_ptr, output_strides, ca->count,
|
|
508
|
+
ca->embed_output_offset,
|
|
509
|
+
ca->embed_count,
|
|
510
|
+
ca->fill, bytes, ndim);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* Step 2: strided memcpy from parent alias rectangle to output rectangle. */
|
|
515
|
+
if ( ca->embed_is_empty ) return;
|
|
516
|
+
|
|
517
|
+
s = bytes;
|
|
518
|
+
for ( k = ndim - 1; k >= 0; k-- ) {
|
|
519
|
+
parent_strides[k] = s;
|
|
520
|
+
s *= ca->parent->dim[k];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
ca_composite_region_gather(ca->parent->ptr, parent_strides,
|
|
524
|
+
ca->embed_parent_start,
|
|
525
|
+
out_ptr, output_strides,
|
|
526
|
+
ca->embed_output_offset,
|
|
527
|
+
ca->embed_count, ndim, bytes);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/* Executes the reverse of ca_window_attach_embed on a caller-provided source
|
|
531
|
+
buffer. Strided memcpy from the alias sub-rectangle of in_ptr (= the
|
|
532
|
+
view's data layout) back into the parent's alias rectangle. The fill
|
|
533
|
+
region is ignored: writes in the OOB area have no parent cell to land in
|
|
534
|
+
and are dropped, matching ca_axis_dispatch_scatter's SHIFT-kind OOB.
|
|
43
535
|
|
|
536
|
+
Pre-conditions:
|
|
537
|
+
- ca->embed_eligible == 1
|
|
538
|
+
- ca->parent->ptr != NULL (parent attached)
|
|
539
|
+
- in_ptr points to ca->elements * ca->bytes valid bytes
|
|
44
540
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
541
|
+
The reverse strided copy is ca_composite_region_scatter
|
|
542
|
+
(ca_composite_dispatch.c), shared with the CATile / CAStack sync paths. */
|
|
543
|
+
static void
|
|
544
|
+
ca_window_sync_embed (CAWindow *ca, char *in_ptr)
|
|
545
|
+
{
|
|
546
|
+
int8_t ndim = ca->ndim;
|
|
547
|
+
ca_size_t bytes = ca->bytes;
|
|
548
|
+
ca_size_t parent_strides[CA_RANK_MAX];
|
|
549
|
+
ca_size_t input_strides[CA_RANK_MAX];
|
|
550
|
+
ca_size_t s;
|
|
551
|
+
int8_t k;
|
|
552
|
+
|
|
553
|
+
if ( ca->embed_is_empty ) return; /* nothing of in_ptr maps back */
|
|
554
|
+
|
|
555
|
+
/* Row-major byte strides for parent and the view-shaped source. */
|
|
556
|
+
s = bytes;
|
|
557
|
+
for ( k = ndim - 1; k >= 0; k-- ) {
|
|
558
|
+
parent_strides[k] = s;
|
|
559
|
+
s *= ca->parent->dim[k];
|
|
560
|
+
}
|
|
561
|
+
s = bytes;
|
|
562
|
+
for ( k = ndim - 1; k >= 0; k-- ) {
|
|
563
|
+
input_strides[k] = s;
|
|
564
|
+
s *= ca->count[k];
|
|
565
|
+
}
|
|
49
566
|
|
|
567
|
+
ca_composite_region_scatter(ca->parent->ptr, parent_strides,
|
|
568
|
+
ca->embed_parent_start,
|
|
569
|
+
in_ptr, input_strides,
|
|
570
|
+
ca->embed_output_offset,
|
|
571
|
+
ca->embed_count, ndim, bytes);
|
|
572
|
+
}
|
|
50
573
|
|
|
51
574
|
/* ------------------------------------------------------------------- */
|
|
52
575
|
|
|
576
|
+
/* Recomputes the embed descriptor + eligibility flags from the current
|
|
577
|
+
(start, count, bounds). The recompute is unconditional — no eligibility
|
|
578
|
+
pre-check — so callers never have to reason about which flags are stale.
|
|
579
|
+
Called by ca_window_setup.
|
|
580
|
+
*
|
|
581
|
+
* CAREFUL: any code path that mutates ca->start[] in place (e.g.
|
|
582
|
+
* ca_window_move, which is why this is not static) must call this
|
|
583
|
+
* afterwards. Otherwise embed_* keeps describing the OLD start and the
|
|
584
|
+
* embed-model attach / copy_data reads the wrong parent rectangle — wrong
|
|
585
|
+
* data, no error. */
|
|
586
|
+
void
|
|
587
|
+
ca_window_recompute_embed (CAWindow *ca)
|
|
588
|
+
{
|
|
589
|
+
int8_t ndim = ca->ndim;
|
|
590
|
+
int8_t i;
|
|
591
|
+
|
|
592
|
+
ca_compute_embed_descriptor(ndim, ca->parent->dim, ca->start, ca->count,
|
|
593
|
+
ca->embed_parent_start,
|
|
594
|
+
ca->embed_count,
|
|
595
|
+
ca->embed_output_offset,
|
|
596
|
+
&ca->embed_is_empty,
|
|
597
|
+
&ca->embed_covers_all);
|
|
598
|
+
|
|
599
|
+
/* embed path eligibility = all axes use FILL or MASK bounds. */
|
|
600
|
+
ca->embed_eligible = 1;
|
|
601
|
+
for (i = 0; i < ndim; i++) {
|
|
602
|
+
if ( ca->bounds[i] != CA_BOUNDS_FILL
|
|
603
|
+
&& ca->bounds[i] != CA_BOUNDS_MASK ) {
|
|
604
|
+
ca->embed_eligible = 0;
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/* direct-attach alias eligibility (see ca_window_func_attach). */
|
|
610
|
+
ca->embed_alias_eligible = 0;
|
|
611
|
+
if ( ca->embed_eligible && ca->embed_covers_all ) {
|
|
612
|
+
int alias_ok = 1;
|
|
613
|
+
for (i = 1; i < ndim; i++) {
|
|
614
|
+
if ( ca->start[i] != 0 || ca->count[i] != ca->parent->dim[i] ) {
|
|
615
|
+
alias_ok = 0;
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if ( alias_ok ) ca->embed_alias_eligible = 1;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/* `bounds` is a per-axis uint8_t array. CAWindow's Ruby surface
|
|
624
|
+
(rb_ca_window) receives a single scalar policy and fans it out to all axes;
|
|
625
|
+
the per-axis form is what lets CAShift be a CAWindow specialisation. */
|
|
53
626
|
int
|
|
54
627
|
ca_window_setup (CAWindow *ca, CArray *parent,
|
|
55
|
-
ca_size_t *start, ca_size_t *count,
|
|
628
|
+
ca_size_t *start, ca_size_t *count, uint8_t *bounds, char *fill)
|
|
56
629
|
{
|
|
57
630
|
int8_t data_type, ndim;
|
|
58
631
|
ca_size_t *dim;
|
|
59
632
|
ca_size_t bytes, elements;
|
|
60
633
|
int i;
|
|
634
|
+
int any_mask;
|
|
61
635
|
|
|
62
636
|
data_type = parent->data_type;
|
|
63
637
|
ndim = parent->ndim;
|
|
@@ -86,18 +660,34 @@ ca_window_setup (CAWindow *ca, CArray *parent,
|
|
|
86
660
|
ca->parent = parent;
|
|
87
661
|
ca->attach = 0;
|
|
88
662
|
ca->nosync = 0;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
663
|
+
/* Pool path: bounds/start/count/size0/embed_* are already wired into
|
|
664
|
+
ca->_pool by ca_window_pool_init. Legacy path: ALLOC_N each. `fill`
|
|
665
|
+
is bytes-sized (not ndim) so it stays on its own ALLOC_N in both
|
|
666
|
+
branches. */
|
|
667
|
+
if ( ! ca->_pool ) {
|
|
668
|
+
ca->bounds = ALLOC_N(uint8_t, ndim);
|
|
669
|
+
ca->start = ALLOC_N(ca_size_t, ndim);
|
|
670
|
+
ca->count = ALLOC_N(ca_size_t, ndim);
|
|
671
|
+
ca->size0 = ALLOC_N(ca_size_t, ndim);
|
|
672
|
+
ca->embed_parent_start = ALLOC_N(ca_size_t, ndim);
|
|
673
|
+
ca->embed_count = ALLOC_N(ca_size_t, ndim);
|
|
674
|
+
ca->embed_output_offset = ALLOC_N(ca_size_t, ndim);
|
|
675
|
+
}
|
|
93
676
|
ca->fill = ALLOC_N(char, ca->bytes);
|
|
677
|
+
ca->embed_is_empty = 0;
|
|
678
|
+
ca->embed_covers_all = 0;
|
|
94
679
|
|
|
95
680
|
ca->dim = ca->count;
|
|
96
681
|
|
|
682
|
+
memcpy(ca->bounds, bounds, ndim * sizeof(uint8_t));
|
|
97
683
|
memcpy(ca->start, start, ndim * sizeof(ca_size_t));
|
|
98
684
|
memcpy(ca->count, count, ndim * sizeof(ca_size_t));
|
|
99
685
|
memcpy(ca->size0, dim, ndim * sizeof(ca_size_t));
|
|
100
686
|
|
|
687
|
+
/* Compute the embed descriptor + eligibility flags from the current
|
|
688
|
+
(start, count, bounds). See ca_window_recompute_embed below. */
|
|
689
|
+
ca_window_recompute_embed(ca);
|
|
690
|
+
|
|
101
691
|
if ( fill ) {
|
|
102
692
|
memcpy(ca->fill, fill, ca->bytes);
|
|
103
693
|
}
|
|
@@ -110,7 +700,15 @@ ca_window_setup (CAWindow *ca, CArray *parent,
|
|
|
110
700
|
}
|
|
111
701
|
}
|
|
112
702
|
|
|
113
|
-
if
|
|
703
|
+
/* Mask is needed if ANY axis uses MASK policy (per-axis). */
|
|
704
|
+
any_mask = 0;
|
|
705
|
+
for (i=0; i<ndim; i++) {
|
|
706
|
+
if ( ca->bounds[i] == CA_BOUNDS_MASK ) {
|
|
707
|
+
any_mask = 1;
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if ( any_mask ) {
|
|
114
712
|
ca_create_mask(ca);
|
|
115
713
|
}
|
|
116
714
|
|
|
@@ -119,9 +717,9 @@ ca_window_setup (CAWindow *ca, CArray *parent,
|
|
|
119
717
|
|
|
120
718
|
CAWindow *
|
|
121
719
|
ca_window_new (CArray *parent,
|
|
122
|
-
ca_size_t *start, ca_size_t *count,
|
|
720
|
+
ca_size_t *start, ca_size_t *count, uint8_t *bounds, char *fill)
|
|
123
721
|
{
|
|
124
|
-
CAWindow *ca =
|
|
722
|
+
CAWindow *ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
|
|
125
723
|
ca_window_setup(ca, parent, start, count, bounds, fill);
|
|
126
724
|
return ca;
|
|
127
725
|
}
|
|
@@ -132,18 +730,38 @@ free_ca_window (void *ap)
|
|
|
132
730
|
CAWindow *ca = (CAWindow *) ap;
|
|
133
731
|
if ( ca != NULL ) {
|
|
134
732
|
ca_free(ca->mask);
|
|
135
|
-
xfree(ca->fill);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
733
|
+
xfree(ca->fill); /* always separate (bytes-sized) */
|
|
734
|
+
if ( ca->_pool ) {
|
|
735
|
+
/* bounds/start/count/size0/embed_* all live in ca->_pool. */
|
|
736
|
+
ca_array_free(ca); /* one xfree pool + one xfree struct */
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
xfree(ca->bounds);
|
|
740
|
+
xfree(ca->start);
|
|
741
|
+
xfree(ca->count);
|
|
742
|
+
xfree(ca->size0);
|
|
743
|
+
xfree(ca->embed_parent_start);
|
|
744
|
+
xfree(ca->embed_count);
|
|
745
|
+
xfree(ca->embed_output_offset);
|
|
746
|
+
/* xfree(ca->dim); */
|
|
747
|
+
xfree(ca);
|
|
748
|
+
}
|
|
141
749
|
}
|
|
142
750
|
}
|
|
143
751
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
752
|
+
/* Path selection for attach / sync / copy_data / sync_data below.
|
|
753
|
+
|
|
754
|
+
embed_eligible (= all axes use FILL or MASK bounds) takes the embed path:
|
|
755
|
+
"1 typed fill + 1 strided memcpy" with no per-cell bound check (see
|
|
756
|
+
ca_window_attach_embed / ca_window_sync_embed above).
|
|
757
|
+
|
|
758
|
+
Everything else (PERIODIC — still reached through CAShift's roll form —
|
|
759
|
+
REFLECT / NEAREST / RUBY / STRICT) goes through the descriptor engine,
|
|
760
|
+
ca_axis_dispatch_* fed by ca_window_describe_axes (defined below), which
|
|
761
|
+
still promotes interior axes to STRIDE kind.
|
|
762
|
+
|
|
763
|
+
fill_data is the exception: it has its own split (see
|
|
764
|
+
ca_window_func_fill_data). */
|
|
147
765
|
|
|
148
766
|
/* ------------------------------------------------------------------- */
|
|
149
767
|
|
|
@@ -154,57 +772,11 @@ ca_window_func_clone (void *ap)
|
|
|
154
772
|
return ca_window_new(ca->parent, ca->start, ca->count, ca->bounds, ca->fill);
|
|
155
773
|
}
|
|
156
774
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
static char *
|
|
161
|
-
ca_window_func_ptr_at_addr (void *ap, ca_size_t addr)
|
|
162
|
-
{
|
|
163
|
-
CAWindow *ca = (CAWindow *) ap;
|
|
164
|
-
if ( ca->ptr ) {
|
|
165
|
-
return ca->ptr + ca->bytes * addr;
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
ca_size_t idx[CA_RANK_MAX];
|
|
169
|
-
ca_addr2index((CArray *)ca, addr, idx);
|
|
170
|
-
return ca_window_func_ptr_at_index(ca, idx);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
static char *
|
|
175
|
-
ca_window_func_ptr_at_index (void *ap, ca_size_t *idx)
|
|
176
|
-
{
|
|
177
|
-
ca_size_t k;
|
|
178
|
-
CAWindow *ca = (CAWindow *) ap;
|
|
179
|
-
if ( ! ca->ptr ) {
|
|
180
|
-
ca_size_t *start = ca->start;
|
|
181
|
-
ca_size_t *size0 = ca->size0;
|
|
182
|
-
int8_t i;
|
|
183
|
-
ca_size_t n;
|
|
184
|
-
n = 0;
|
|
185
|
-
for (i=0; i<ca->ndim; i++) {
|
|
186
|
-
k = start[i] + idx[i];
|
|
187
|
-
k = ca_bounds_normalize_index(ca->bounds, size0[i], k);
|
|
188
|
-
if ( k < 0 || k >= size0[i] ) {
|
|
189
|
-
return ca->fill;
|
|
190
|
-
}
|
|
191
|
-
n = size0[i] * n + k;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if ( ! ca->parent->ptr ) {
|
|
195
|
-
return ca_ptr_at_addr(ca->parent, n);
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
return ca->parent->ptr + ca->bytes * n;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
return ca_func[CA_OBJ_ARRAY].ptr_at_index(ca, idx);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
775
|
+
/* Per-cell access. GET and PUT share the bound-normalised index walk; an OOB
|
|
776
|
+
cell is filled on GET and skipped on PUT. CAShift inherits this via the
|
|
777
|
+
ca_shift_func copy of the operation table. */
|
|
206
778
|
static void
|
|
207
|
-
|
|
779
|
+
ca_window_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
208
780
|
{
|
|
209
781
|
CAWindow *ca = (CAWindow *) ap;
|
|
210
782
|
ca_size_t *start = ca->start;
|
|
@@ -214,34 +786,143 @@ ca_window_func_fetch_index (void *ap, ca_size_t *idx, void *ptr)
|
|
|
214
786
|
ca_size_t k;
|
|
215
787
|
for (i=0; i<ca->ndim; i++) {
|
|
216
788
|
k = start[i] + idx[i];
|
|
217
|
-
k = ca_bounds_normalize_index(ca->bounds, size0[i], k);
|
|
789
|
+
k = ca_bounds_normalize_index(ca->bounds[i], size0[i], k);
|
|
218
790
|
if ( k < 0 || k >= size0[i] ) {
|
|
219
|
-
memcpy(
|
|
220
|
-
return;
|
|
791
|
+
if ( dir == CA_XFER_GET ) memcpy(data, ca->fill, ca->bytes);
|
|
792
|
+
return; /* PUT to out-of-bounds cell: skip */
|
|
221
793
|
}
|
|
222
794
|
idx0[i] = k;
|
|
223
795
|
}
|
|
224
|
-
|
|
796
|
+
ca_xfer_index(ca->parent, idx0, data, dir);
|
|
225
797
|
}
|
|
226
798
|
|
|
799
|
+
/* Batched address gather/scatter. Bound-normalises each view addr; OOB cells are handled inline (GET fills,
|
|
800
|
+
PUT skips) and the in-bounds cells are delivered to the parent in ONE
|
|
801
|
+
ca_xfer_addrs call. When some cells are OOB the in-bounds set is packed
|
|
802
|
+
into a contiguous temp (the parent's contig-buf contract), gathered/
|
|
803
|
+
scattered, then unpacked. No whole-view attach.
|
|
804
|
+
CAShift inherits via ca_shift_func copy. */
|
|
227
805
|
static void
|
|
228
|
-
|
|
806
|
+
ca_window_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
807
|
+
void *data, int dir)
|
|
229
808
|
{
|
|
230
809
|
CAWindow *ca = (CAWindow *) ap;
|
|
231
810
|
ca_size_t *start = ca->start;
|
|
232
811
|
ca_size_t *size0 = ca->size0;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
ca_size_t
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
812
|
+
char *d = (char *) data;
|
|
813
|
+
ca_size_t *paddrs;
|
|
814
|
+
ca_size_t *pos;
|
|
815
|
+
ca_size_t m = 0, i, base;
|
|
816
|
+
int8_t k;
|
|
817
|
+
volatile VALUE h1, h2;
|
|
818
|
+
|
|
819
|
+
/* Fast path: an embed-eligible window (interior alias rectangle + OOB
|
|
820
|
+
strips for FILL mode) over a parent that resolves to a ptr-bearing root.
|
|
821
|
+
Whole-view sequential addrs let us drive ca_composite_region_gather /
|
|
822
|
+
ca_composite_fill_complement directly (= the same helpers
|
|
823
|
+
ca_window_attach_embed / _sync_embed use), skipping the per-cell
|
|
824
|
+
bounds-normalise + OOB-pack two-pass. Covers both interior-only windows
|
|
825
|
+
and boundary-crossing ones (CAShift included): the OOB strip fill is
|
|
826
|
+
batched through ca_composite_fill_complement. */
|
|
827
|
+
if ( ca->embed_eligible
|
|
828
|
+
&& n == ca->elements
|
|
829
|
+
&& ca_xfer_addrs_is_sequential_run(n, addrs, &base) && base == 0 ) {
|
|
830
|
+
CArray *eff_parent = ca_resolve_attached_root_via_identity(ca->parent);
|
|
831
|
+
if ( eff_parent->ptr ) {
|
|
832
|
+
ca_size_t output_strides[CA_RANK_MAX];
|
|
833
|
+
ca_size_t parent_strides[CA_RANK_MAX];
|
|
834
|
+
ca_size_t s;
|
|
835
|
+
s = ca->bytes;
|
|
836
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) {
|
|
837
|
+
output_strides[k] = s;
|
|
838
|
+
s *= ca->count[k];
|
|
839
|
+
}
|
|
840
|
+
s = eff_parent->bytes;
|
|
841
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) {
|
|
842
|
+
parent_strides[k] = s;
|
|
843
|
+
s *= ca->parent->dim[k]; /* logical shape from immediate parent */
|
|
844
|
+
}
|
|
845
|
+
if ( dir == CA_XFER_GET ) {
|
|
846
|
+
/* Step 1: fill OOB complement (no-op when covers_all). */
|
|
847
|
+
if ( ! ca->embed_covers_all ) {
|
|
848
|
+
if ( ca->embed_is_empty ) {
|
|
849
|
+
ca_fill_typed((char *) data, ca->fill, ca->bytes, ca->elements);
|
|
850
|
+
} else {
|
|
851
|
+
ca_composite_fill_complement((char *) data, output_strides, ca->count,
|
|
852
|
+
ca->embed_output_offset,
|
|
853
|
+
ca->embed_count,
|
|
854
|
+
ca->fill, ca->bytes, ca->ndim);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/* Step 2: gather interior alias rectangle from parent. */
|
|
858
|
+
if ( ! ca->embed_is_empty ) {
|
|
859
|
+
ca_composite_region_gather(eff_parent->ptr, parent_strides,
|
|
860
|
+
ca->embed_parent_start,
|
|
861
|
+
(char *) data, output_strides,
|
|
862
|
+
ca->embed_output_offset,
|
|
863
|
+
ca->embed_count, ca->ndim, ca->bytes);
|
|
864
|
+
}
|
|
865
|
+
} else { /* CA_XFER_PUT */
|
|
866
|
+
/* Scatter the input rectangle back to the parent's alias
|
|
867
|
+
rectangle. Writes to OOB cells are dropped — same as
|
|
868
|
+
ca_window_sync_embed and the engine's SHIFT-kind scatter. */
|
|
869
|
+
if ( ! ca->embed_is_empty ) {
|
|
870
|
+
ca_composite_region_scatter(eff_parent->ptr, parent_strides,
|
|
871
|
+
ca->embed_parent_start,
|
|
872
|
+
(char *) data, output_strides,
|
|
873
|
+
ca->embed_output_offset,
|
|
874
|
+
ca->embed_count, ca->ndim, ca->bytes);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
240
877
|
return;
|
|
241
878
|
}
|
|
242
|
-
idx0[i] = k;
|
|
243
879
|
}
|
|
244
|
-
|
|
880
|
+
|
|
881
|
+
paddrs = ALLOCV_N(ca_size_t, h1, n);
|
|
882
|
+
pos = ALLOCV_N(ca_size_t, h2, n);
|
|
883
|
+
|
|
884
|
+
for (i = 0; i < n; i++) {
|
|
885
|
+
ca_size_t vidx[CA_RANK_MAX], pidx[CA_RANK_MAX];
|
|
886
|
+
int oob = 0;
|
|
887
|
+
ca_addr2index((CArray *) ca, addrs[i], vidx);
|
|
888
|
+
for (k = 0; k < ca->ndim; k++) {
|
|
889
|
+
ca_size_t kk = start[k] + vidx[k];
|
|
890
|
+
kk = ca_bounds_normalize_index(ca->bounds[k], size0[k], kk);
|
|
891
|
+
if (kk < 0 || kk >= size0[k]) { oob = 1; break; }
|
|
892
|
+
pidx[k] = kk;
|
|
893
|
+
}
|
|
894
|
+
if (oob) {
|
|
895
|
+
if (dir == CA_XFER_GET) memcpy(d + i * ca->bytes, ca->fill, ca->bytes);
|
|
896
|
+
/* PUT to OOB cell: skip */
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
paddrs[m] = ca_index2addr(ca->parent, pidx);
|
|
900
|
+
pos[m] = i;
|
|
901
|
+
m++;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
if (m == n) { /* no OOB: deliver in place, contiguous */
|
|
906
|
+
ca_xfer_addrs(ca->parent, n, paddrs, data, dir);
|
|
907
|
+
}
|
|
908
|
+
else if (m > 0) { /* some OOB: pack the in-bounds set */
|
|
909
|
+
volatile VALUE h3;
|
|
910
|
+
char *packed = ALLOCV_N(char, h3, m * ca->bytes);
|
|
911
|
+
if (dir == CA_XFER_GET) {
|
|
912
|
+
ca_xfer_addrs(ca->parent, m, paddrs, packed, CA_XFER_GET);
|
|
913
|
+
for (i = 0; i < m; i++)
|
|
914
|
+
memcpy(d + pos[i] * ca->bytes, packed + i * ca->bytes, ca->bytes);
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
for (i = 0; i < m; i++)
|
|
918
|
+
memcpy(packed + i * ca->bytes, d + pos[i] * ca->bytes, ca->bytes);
|
|
919
|
+
ca_xfer_addrs(ca->parent, m, paddrs, packed, CA_XFER_PUT);
|
|
920
|
+
}
|
|
921
|
+
ALLOCV_END(h3);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
ALLOCV_END(h2);
|
|
925
|
+
ALLOCV_END(h1);
|
|
245
926
|
}
|
|
246
927
|
|
|
247
928
|
static void
|
|
@@ -250,26 +931,66 @@ ca_window_func_allocate (void *ap)
|
|
|
250
931
|
CAWindow *ca = (CAWindow *) ap;
|
|
251
932
|
ca_attach(ca->parent);
|
|
252
933
|
/* ca->ptr = ALLOC_N(char, ca_length(ca)); */
|
|
253
|
-
ca->ptr =
|
|
934
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
254
935
|
}
|
|
255
936
|
|
|
937
|
+
/* The engine paths below emit a per-axis descriptor (ca_window_describe_axes)
|
|
938
|
+
and let the shared engine's SHIFT-kind handling apply the boundary policy
|
|
939
|
+
and the OOB cell fill. CAShift inherits all of it through
|
|
940
|
+
ca_shift_func = a copy of ca_window_func. */
|
|
941
|
+
|
|
942
|
+
void ca_window_describe_axes (void *ap, ca_axis_desc_t *out,
|
|
943
|
+
ca_size_t *out_parent_dims);
|
|
944
|
+
|
|
256
945
|
static void
|
|
257
946
|
ca_window_func_attach (void *ap)
|
|
258
947
|
{
|
|
259
|
-
void ca_window_attach (CAWindow *cb);
|
|
260
|
-
|
|
261
948
|
CAWindow *ca = (CAWindow *) ap;
|
|
262
949
|
ca_attach(ca->parent);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
950
|
+
if ( ca->embed_alias_eligible ) {
|
|
951
|
+
/* Alias path: inner axes full + interior, so the embedded region is a
|
|
952
|
+
contiguous run of parent storage. Skip malloc/memcpy and point
|
|
953
|
+
ca->ptr into the parent's buffer.
|
|
954
|
+
CAREFUL: sync and detach must agree with this — sync has nothing to
|
|
955
|
+
scatter back (the writes already landed in the parent) and detach must
|
|
956
|
+
not xfree a pointer it does not own. */
|
|
957
|
+
ca_size_t parent_row_stride = ca->bytes;
|
|
958
|
+
int8_t k;
|
|
959
|
+
for (k = ca->ndim - 1; k >= 1; k--) parent_row_stride *= ca->parent->dim[k];
|
|
960
|
+
ca->ptr = ca->parent->ptr + ca->start[0] * parent_row_stride;
|
|
961
|
+
} else if ( ca->embed_eligible ) {
|
|
962
|
+
/* Embed path: allocate, then 1 fill + 1 strided memcpy. */
|
|
963
|
+
ca_size_t out_len = ca->elements * ca->bytes;
|
|
964
|
+
ca->ptr = xmalloc(out_len > 0 ? out_len : 1);
|
|
965
|
+
ca_window_attach_embed(ca, ca->ptr);
|
|
966
|
+
} else {
|
|
967
|
+
/* Fallback: PERIODIC / REFLECT / NEAREST / RUBY / STRICT go through
|
|
968
|
+
the descriptor engine. */
|
|
969
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
970
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
971
|
+
ca_window_describe_axes(ca, desc, pdims);
|
|
972
|
+
ca->ptr = ca_axis_dispatch_attach(ca->parent, pdims, desc, ca->ndim,
|
|
973
|
+
ca->bytes, ca->elements, ca->fill);
|
|
974
|
+
}
|
|
266
975
|
}
|
|
267
976
|
|
|
268
977
|
static void
|
|
269
978
|
ca_window_func_sync (void *ap)
|
|
270
979
|
{
|
|
271
980
|
CAWindow *ca = (CAWindow *) ap;
|
|
272
|
-
|
|
981
|
+
if ( ca->embed_alias_eligible ) {
|
|
982
|
+
/* Alias path: ca->ptr aliases the parent, so the writes already landed
|
|
983
|
+
in parent storage. Nothing to scatter back. */
|
|
984
|
+
} else if ( ca->embed_eligible ) {
|
|
985
|
+
/* Embed path: write back the alias region only. */
|
|
986
|
+
ca_window_sync_embed(ca, ca->ptr);
|
|
987
|
+
} else {
|
|
988
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
989
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
990
|
+
ca_window_describe_axes(ca, desc, pdims);
|
|
991
|
+
ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
992
|
+
ca->elements, ca->ptr);
|
|
993
|
+
}
|
|
273
994
|
ca_sync(ca->parent);
|
|
274
995
|
}
|
|
275
996
|
|
|
@@ -277,42 +998,177 @@ static void
|
|
|
277
998
|
ca_window_func_detach (void *ap)
|
|
278
999
|
{
|
|
279
1000
|
CAWindow *ca = (CAWindow *) ap;
|
|
280
|
-
|
|
1001
|
+
/* Alias path: ca->ptr aliases parent storage; it is not ours to xfree. */
|
|
1002
|
+
if ( ! ca->embed_alias_eligible ) {
|
|
1003
|
+
xfree(ca->ptr);
|
|
1004
|
+
}
|
|
281
1005
|
ca->ptr = NULL;
|
|
282
1006
|
ca_detach(ca->parent);
|
|
283
1007
|
}
|
|
284
1008
|
|
|
1009
|
+
/* Fast path body for xfer_all, shared by the warm and the cold-parent case.
|
|
1010
|
+
Both the embed path and the engine dispatch read ca->parent->ptr directly,
|
|
1011
|
+
so the caller must have made it available.
|
|
1012
|
+
|
|
1013
|
+
CAREFUL: neither this nor ca_window_func_xfer_all may call
|
|
1014
|
+
ca_attach(parent). A transfer slot that silently attaches its parent
|
|
1015
|
+
materialises the whole parent behind the caller's back — the cold case
|
|
1016
|
+
below instead materialises a parent-shaped scratch through ca_xfer_all,
|
|
1017
|
+
which recurses under the same rule. */
|
|
285
1018
|
static void
|
|
286
|
-
|
|
1019
|
+
ca_window_func_run_fast_path (CAWindow *ca, char *data, int dir)
|
|
287
1020
|
{
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
1021
|
+
if ( dir == CA_XFER_GET ) {
|
|
1022
|
+
if ( ca->embed_eligible ) {
|
|
1023
|
+
ca_window_attach_embed(ca, data);
|
|
1024
|
+
} else {
|
|
1025
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1026
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1027
|
+
ca_window_describe_axes(ca, desc, pdims);
|
|
1028
|
+
ca_axis_dispatch_gather(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
1029
|
+
ca->elements, ca->fill, data);
|
|
1030
|
+
}
|
|
1031
|
+
} else {
|
|
1032
|
+
if ( ca->embed_eligible ) {
|
|
1033
|
+
ca_window_sync_embed(ca, data);
|
|
1034
|
+
} else {
|
|
1035
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1036
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1037
|
+
ca_window_describe_axes(ca, desc, pdims);
|
|
1038
|
+
ca_axis_dispatch_scatter(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
1039
|
+
ca->elements, data);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
295
1042
|
}
|
|
296
1043
|
|
|
297
1044
|
static void
|
|
298
|
-
|
|
1045
|
+
ca_window_func_xfer_all (void *ap, void *data, int dir)
|
|
299
1046
|
{
|
|
300
1047
|
CAWindow *ca = (CAWindow *) ap;
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
1048
|
+
if ( ca->parent->ptr ) {
|
|
1049
|
+
ca_window_func_run_fast_path(ca, (char *) data, dir);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
/* Cold parent: materialise it into a scratch buffer via ca_xfer_all, then
|
|
1053
|
+
run the normal fast path with the scratch standing in for parent->ptr. */
|
|
1054
|
+
{
|
|
1055
|
+
volatile VALUE holder;
|
|
1056
|
+
CArray *parent = ca->parent;
|
|
1057
|
+
ca_size_t plen = parent->elements * parent->bytes;
|
|
1058
|
+
char *parent_scratch = ALLOCV_N(char, holder, plen);
|
|
1059
|
+
char *parent_ptr_saved = parent->ptr;
|
|
1060
|
+
|
|
1061
|
+
/* GET path needs parent data; PUT path will overwrite parent so we
|
|
1062
|
+
still need to read existing parent state if the view's fast path
|
|
1063
|
+
does partial writes (e.g., embed_sync overwrites only the embed
|
|
1064
|
+
rectangle, OOB cells untouched in parent). Safe default: always
|
|
1065
|
+
GET first. */
|
|
1066
|
+
ca_xfer_all(parent, parent_scratch, CA_XFER_GET);
|
|
1067
|
+
parent->ptr = parent_scratch;
|
|
1068
|
+
|
|
1069
|
+
ca_window_func_run_fast_path(ca, (char *) data, dir);
|
|
1070
|
+
|
|
1071
|
+
if ( dir == CA_XFER_PUT ) {
|
|
1072
|
+
/* Push back scratch (modified by scatter) to parent. */
|
|
1073
|
+
ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
parent->ptr = parent_ptr_saved;
|
|
1077
|
+
ALLOCV_END(holder);
|
|
1078
|
+
}
|
|
308
1079
|
}
|
|
309
1080
|
|
|
1081
|
+
/* fill_data (= view.fill(scalar) / view[] = scalar).
|
|
1082
|
+
|
|
1083
|
+
Wrapping the window in a CAStride and filling that is markedly faster than
|
|
1084
|
+
the engine path, because compose-fold reaches the entity and the inner loop
|
|
1085
|
+
collapses to a per-row memset. So for an embed-eligible window we do the
|
|
1086
|
+
same thing directly: build a transient CAStride header matching
|
|
1087
|
+
ca_window_compose_fold's synthetic strides and dispatch to CAStride's
|
|
1088
|
+
fill_data, which continues compose-fold (covering
|
|
1089
|
+
CAStride-of-CAWindow-of-CAStride chains) and runs the merge + tight-fill
|
|
1090
|
+
inner loop. PERIODIC / REFLECT windows fall through to the engine path. */
|
|
310
1091
|
static void
|
|
311
1092
|
ca_window_func_fill_data (void *ap, void *ptr)
|
|
312
1093
|
{
|
|
313
1094
|
CAWindow *ca = (CAWindow *) ap;
|
|
1095
|
+
|
|
1096
|
+
/* embed_eligible (= no PERIODIC/REFLECT) covers both interior-only
|
|
1097
|
+
windows (embed_covers_all == 1) and OOB-bearing ones such as a CAShift
|
|
1098
|
+
with a fill_value (embed_covers_all == 0, embed_is_empty == 0). In the
|
|
1099
|
+
OOB case the synth is restricted to the interior region (embed_count
|
|
1100
|
+
cells starting at embed_parent_start in the parent): the view's OOB
|
|
1101
|
+
cells have no parent cell and must be skipped, which the restricted
|
|
1102
|
+
synth does by construction. A wholly-OOB window (embed_is_empty == 1)
|
|
1103
|
+
is a no-op. */
|
|
1104
|
+
if ( ca->embed_eligible && ! ca->embed_is_empty ) {
|
|
1105
|
+
ca_size_t synth_strides[CA_RANK_MAX];
|
|
1106
|
+
ca_size_t synth_base;
|
|
1107
|
+
ca_size_t s;
|
|
1108
|
+
int8_t k;
|
|
1109
|
+
ca_size_t synth_elements;
|
|
1110
|
+
|
|
1111
|
+
/* Row-major byte strides over parent. */
|
|
1112
|
+
s = ca->bytes;
|
|
1113
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) {
|
|
1114
|
+
synth_strides[k] = s;
|
|
1115
|
+
s *= ca->parent->dim[k];
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/* Origin: embedded region start in parent's byte space. */
|
|
1119
|
+
synth_base = 0;
|
|
1120
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
1121
|
+
synth_base += ca->embed_parent_start[k] * synth_strides[k];
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/* synth dims = interior count per axis (= the cells we actually
|
|
1125
|
+
write to; OOB view cells are skipped by construction). */
|
|
1126
|
+
synth_elements = 1;
|
|
1127
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
1128
|
+
synth_elements *= ca->embed_count[k];
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/* Stack-allocated transient CAStride header. Dispatched via the
|
|
1132
|
+
op table since ca_stride_func_fill_data is static in
|
|
1133
|
+
ca_obj_stride.c. It reads only struct fields (parent, ndim,
|
|
1134
|
+
dim, strides, base_offset, bytes, elements) and never
|
|
1135
|
+
registers / persists this pointer. */
|
|
1136
|
+
CAStride synth;
|
|
1137
|
+
memset(&synth, 0, sizeof(synth));
|
|
1138
|
+
synth.obj_type = CA_OBJ_STRIDE;
|
|
1139
|
+
synth.data_type = ca->data_type;
|
|
1140
|
+
synth.ndim = ca->ndim;
|
|
1141
|
+
synth.bytes = ca->bytes;
|
|
1142
|
+
synth.elements = synth_elements;
|
|
1143
|
+
synth.dim = ca->embed_count;
|
|
1144
|
+
synth.parent = ca->parent;
|
|
1145
|
+
synth.strides = synth_strides;
|
|
1146
|
+
synth.base_offset = synth_base;
|
|
1147
|
+
ca_func[CA_OBJ_STRIDE].fill_data(&synth, ptr);
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/* Engine path: PERIODIC / REFLECT, or pure-OOB window (no-op via
|
|
1152
|
+
engine's OOB-skip). Bound_fill writes to view's OOB cells are
|
|
1153
|
+
not propagated to parent (no cells to write to). */
|
|
1154
|
+
ca_axis_desc_t desc[CA_RANK_MAX];
|
|
1155
|
+
ca_size_t pdims[CA_RANK_MAX];
|
|
1156
|
+
|
|
1157
|
+
ca_window_describe_axes(ca, desc, pdims);
|
|
1158
|
+
|
|
1159
|
+
/* A wrapping window writes the cells it lands on, but a whole-parent attach
|
|
1160
|
+
and sync carries the rest of the parent with it — and over a lossy layer
|
|
1161
|
+
those cells do not come back the same. Hand each slab to the parent as a
|
|
1162
|
+
region instead, as the other views on the descriptor engine do. */
|
|
1163
|
+
if ( !ca_is_attached(ca->parent) && !ca_attach_is_alias(ca->parent) ) {
|
|
1164
|
+
ca_axis_dispatch_fill_value_via_parent(ca->parent, pdims, desc, ca->ndim,
|
|
1165
|
+
ca->bytes, ca->elements, ptr);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
314
1169
|
ca_attach(ca->parent);
|
|
315
|
-
|
|
1170
|
+
ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
|
|
1171
|
+
ca->elements, ptr);
|
|
316
1172
|
ca_sync(ca->parent);
|
|
317
1173
|
ca_detach(ca->parent);
|
|
318
1174
|
}
|
|
@@ -322,392 +1178,97 @@ ca_window_func_create_mask (void *ap)
|
|
|
322
1178
|
{
|
|
323
1179
|
CAWindow *ca = (CAWindow *) ap;
|
|
324
1180
|
boolean8_t fill;
|
|
325
|
-
|
|
1181
|
+
uint8_t mbounds[CA_RANK_MAX];
|
|
1182
|
+
int8_t i;
|
|
1183
|
+
int any_mask;
|
|
326
1184
|
|
|
327
1185
|
ca_update_mask(ca->parent);
|
|
328
1186
|
if ( ! ca->parent->mask ) {
|
|
329
1187
|
ca_create_mask(ca->parent);
|
|
330
1188
|
}
|
|
331
1189
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
1190
|
+
/* Any MASK axis of the view becomes FILL in the mask sub-view, with the
|
|
1191
|
+
mask cell forced to 1 (= "masked"). Other axes keep their policy. When
|
|
1192
|
+
every axis shares MASK this is exactly "OOB cells are masked". */
|
|
1193
|
+
any_mask = 0;
|
|
1194
|
+
for (i = 0; i < ca->ndim; i++) {
|
|
1195
|
+
if ( ca->bounds[i] == CA_BOUNDS_MASK ) {
|
|
1196
|
+
mbounds[i] = CA_BOUNDS_FILL;
|
|
1197
|
+
any_mask = 1;
|
|
1198
|
+
} else {
|
|
1199
|
+
mbounds[i] = ca->bounds[i];
|
|
1200
|
+
}
|
|
338
1201
|
}
|
|
1202
|
+
fill = any_mask ? 1 : 0;
|
|
339
1203
|
|
|
340
1204
|
ca->mask = (CArray *) ca_window_new(ca->parent->mask,
|
|
341
|
-
ca->start, ca->count,
|
|
1205
|
+
ca->start, ca->count, mbounds, (char*)&fill);
|
|
342
1206
|
}
|
|
343
1207
|
|
|
344
1208
|
ca_operation_function_t ca_window_func = {
|
|
345
1209
|
-1, /* CA_OBJ_WINDOW */
|
|
346
|
-
|
|
1210
|
+
CA_VIEW_ARRAY,
|
|
347
1211
|
free_ca_window,
|
|
348
1212
|
ca_window_func_clone,
|
|
349
|
-
ca_window_func_ptr_at_addr,
|
|
350
|
-
ca_window_func_ptr_at_index,
|
|
351
|
-
NULL,
|
|
352
|
-
ca_window_func_fetch_index,
|
|
353
|
-
NULL,
|
|
354
|
-
ca_window_func_store_index,
|
|
355
1213
|
ca_window_func_allocate,
|
|
356
1214
|
ca_window_func_attach,
|
|
357
1215
|
ca_window_func_sync,
|
|
358
1216
|
ca_window_func_detach,
|
|
359
|
-
ca_window_func_copy_data,
|
|
360
|
-
ca_window_func_sync_data,
|
|
361
1217
|
ca_window_func_fill_data,
|
|
362
1218
|
ca_window_func_create_mask,
|
|
1219
|
+
ca_window_func_xfer_index,
|
|
1220
|
+
ca_window_func_xfer_addrs,
|
|
1221
|
+
ca_window_func_fold_stride,
|
|
1222
|
+
ca_window_func_xfer_stride,
|
|
1223
|
+
ca_window_func_xfer_all,
|
|
363
1224
|
};
|
|
364
1225
|
|
|
365
1226
|
/* ------------------------------------------------------------------- */
|
|
1227
|
+
/* Producer interface: emits one descriptor per axis. The engine
|
|
1228
|
+
(ca_axis_dispatch.c) consumes these and applies the per-axis bounds policy
|
|
1229
|
+
via ca_bounds_normalize_index, writing ca->fill for cells that resolve
|
|
1230
|
+
out of range.
|
|
366
1231
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
idx[level] = 0; \
|
|
371
|
-
p = ca_ptr_at_index((CArray*)cb, idx); \
|
|
372
|
-
v = (type*)cb->fill; \
|
|
373
|
-
for (i=0; i<count; i++, p++) { \
|
|
374
|
-
*p = *v; \
|
|
375
|
-
} \
|
|
376
|
-
} \
|
|
377
|
-
else { \
|
|
378
|
-
CArray *parent = cb->parent; \
|
|
379
|
-
ca_size_t start = cb->start[level]; \
|
|
380
|
-
ca_size_t size0 = cb->size0[level]; \
|
|
381
|
-
type *p, *q, *v; \
|
|
382
|
-
idx[level] = 0; \
|
|
383
|
-
p = (type*)ca_ptr_at_index((CArray*)cb, idx); \
|
|
384
|
-
v = (type*)cb->fill; \
|
|
385
|
-
i = 0; \
|
|
386
|
-
while ( start+i<0 && i<count ) { \
|
|
387
|
-
k = start + i; \
|
|
388
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k); \
|
|
389
|
-
if ( k < 0 || k >= size0 ) { \
|
|
390
|
-
*p = *v; \
|
|
391
|
-
} \
|
|
392
|
-
else { \
|
|
393
|
-
idx0[level] = k; \
|
|
394
|
-
*p = *(type*) ca_ptr_at_index(parent, idx0); \
|
|
395
|
-
} \
|
|
396
|
-
i++; p++; \
|
|
397
|
-
} \
|
|
398
|
-
idx0[level] = start+i; \
|
|
399
|
-
q = (type*)ca_ptr_at_index(parent, idx0);\
|
|
400
|
-
while ( start+i<size0 && i < count ) { \
|
|
401
|
-
*p = *q; \
|
|
402
|
-
i++, p++, q++; \
|
|
403
|
-
} \
|
|
404
|
-
while ( i < count ) { \
|
|
405
|
-
k = start + i; \
|
|
406
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k); \
|
|
407
|
-
if ( k < 0 || k >= size0 ) { \
|
|
408
|
-
*p = *v; \
|
|
409
|
-
} \
|
|
410
|
-
else { \
|
|
411
|
-
idx0[level] = k; \
|
|
412
|
-
*p = *(type*) ca_ptr_at_index(parent, idx0); \
|
|
413
|
-
} \
|
|
414
|
-
i++, p++; \
|
|
415
|
-
} \
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
static void
|
|
419
|
-
ca_window_attach_loop (CAWindow *cb, int8_t level,
|
|
420
|
-
ca_size_t *idx, ca_size_t *idx0, int fill)
|
|
421
|
-
{
|
|
422
|
-
ca_size_t count = cb->count[level];
|
|
423
|
-
ca_size_t i, k;
|
|
424
|
-
|
|
425
|
-
if ( level == cb->ndim - 1 ) {
|
|
426
|
-
switch ( cb->data_type ) {
|
|
427
|
-
case CA_BOOLEAN:
|
|
428
|
-
case CA_INT8: proc_window_attach_get(int8_t); break;
|
|
429
|
-
case CA_UINT8: proc_window_attach_get(uint8_t); break;
|
|
430
|
-
case CA_INT16: proc_window_attach_get(int16_t); break;
|
|
431
|
-
case CA_UINT16: proc_window_attach_get(uint16_t); break;
|
|
432
|
-
case CA_INT32: proc_window_attach_get(int32_t); break;
|
|
433
|
-
case CA_UINT32: proc_window_attach_get(uint32_t); break;
|
|
434
|
-
case CA_INT64: proc_window_attach_get(int64_t); break;
|
|
435
|
-
case CA_UINT64: proc_window_attach_get(uint64_t); break;
|
|
436
|
-
case CA_FLOAT32: proc_window_attach_get(float32_t); break;
|
|
437
|
-
case CA_FLOAT64: proc_window_attach_get(float64_t); break;
|
|
438
|
-
case CA_FLOAT128: proc_window_attach_get(float128_t); break;
|
|
439
|
-
#ifdef HAVE_COMPLEX_H
|
|
440
|
-
case CA_CMPLX64: proc_window_attach_get(cmplx64_t); break;
|
|
441
|
-
case CA_CMPLX128: proc_window_attach_get(cmplx128_t); break;
|
|
442
|
-
case CA_CMPLX256: proc_window_attach_get(cmplx256_t); break;
|
|
443
|
-
#endif
|
|
444
|
-
default:
|
|
445
|
-
if ( fill ) {
|
|
446
|
-
for (i=0; i<count; i++) {
|
|
447
|
-
idx[level] = i;
|
|
448
|
-
memcpy(ca_ptr_at_index((CArray*)cb, idx), cb->fill, cb->bytes);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
ca_size_t start = cb->start[level];
|
|
453
|
-
ca_size_t size0 = cb->size0[level];
|
|
454
|
-
for (i=0; i<count; i++) {
|
|
455
|
-
idx[level] = i;
|
|
456
|
-
k = start + i;
|
|
457
|
-
if ( k < 0 || k >= size0 ) {
|
|
458
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k);
|
|
459
|
-
if ( k < 0 || k >= size0 ) {
|
|
460
|
-
memcpy(ca_ptr_at_index((CArray*)cb, idx), cb->fill, cb->bytes);
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
idx0[level] = k;
|
|
465
|
-
memcpy(ca_ptr_at_index((CArray*)cb, idx), ca_ptr_at_index(cb->parent, idx0), cb->bytes);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
if ( fill ) {
|
|
472
|
-
for (i=0; i<count; i++) {
|
|
473
|
-
idx[level] = i;
|
|
474
|
-
ca_window_attach_loop(cb, level+1, idx, idx0, 1);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
else {
|
|
478
|
-
ca_size_t start = cb->start[level];
|
|
479
|
-
ca_size_t size0 = cb->size0[level];
|
|
480
|
-
for (i=0; i<count; i++) {
|
|
481
|
-
idx[level] = i;
|
|
482
|
-
k = start + i;
|
|
483
|
-
if ( k < 0 || k >= size0 ) {
|
|
484
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k);
|
|
485
|
-
if ( k < 0 || k >= size0 ) {
|
|
486
|
-
ca_window_attach_loop(cb, level+1, idx, idx0, 1); /* fill */
|
|
487
|
-
continue;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
idx0[level] = k;
|
|
491
|
-
ca_window_attach_loop(cb, level+1, idx, idx0, 0); /* not-fill */
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
1232
|
+
CAWindow's step is implicitly 1 (count cells starting at start, sliding by
|
|
1233
|
+
1); the engine's SHIFT-axis offset computation is parent_index = start + i,
|
|
1234
|
+
with bounds normalisation per policy.
|
|
496
1235
|
|
|
1236
|
+
Reached only from the non-embed paths: an embed_eligible view attaches and
|
|
1237
|
+
syncs through ca_window_attach_embed / _sync_embed and never gets here. */
|
|
497
1238
|
void
|
|
498
|
-
|
|
1239
|
+
ca_window_describe_axes (void *ap, ca_axis_desc_t *out,
|
|
1240
|
+
ca_size_t *out_parent_dims)
|
|
499
1241
|
{
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
k
|
|
514
|
-
k
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
i++; p++; q++; \
|
|
529
|
-
} \
|
|
530
|
-
while ( i<count ) { \
|
|
531
|
-
k = start + i; \
|
|
532
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k); \
|
|
533
|
-
if ( k < 0 || k >= size0 ) { \
|
|
534
|
-
; \
|
|
535
|
-
} \
|
|
536
|
-
else { \
|
|
537
|
-
idx0[level] = k; \
|
|
538
|
-
*(type*)ca_ptr_at_index(parent, idx0) = *p; \
|
|
539
|
-
} \
|
|
540
|
-
i++; p++; \
|
|
541
|
-
} \
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
static void
|
|
545
|
-
ca_window_sync_loop (CAWindow *cb, int8_t level,
|
|
546
|
-
ca_size_t *idx, ca_size_t *idx0)
|
|
547
|
-
{
|
|
548
|
-
ca_size_t count = cb->count[level];
|
|
549
|
-
ca_size_t start = cb->start[level];
|
|
550
|
-
ca_size_t size0 = cb->size0[level];
|
|
551
|
-
ca_size_t i, k;
|
|
552
|
-
|
|
553
|
-
if ( level == cb->ndim - 1 ) {
|
|
554
|
-
switch ( cb->data_type ) {
|
|
555
|
-
case CA_BOOLEAN:
|
|
556
|
-
case CA_INT8: proc_window_sync_set(int8_t); break;
|
|
557
|
-
case CA_UINT8: proc_window_sync_set(uint8_t); break;
|
|
558
|
-
case CA_INT16: proc_window_sync_set(int16_t); break;
|
|
559
|
-
case CA_UINT16: proc_window_sync_set(uint16_t); break;
|
|
560
|
-
case CA_INT32: proc_window_sync_set(int32_t); break;
|
|
561
|
-
case CA_UINT32: proc_window_sync_set(uint32_t); break;
|
|
562
|
-
case CA_INT64: proc_window_sync_set(int64_t); break;
|
|
563
|
-
case CA_UINT64: proc_window_sync_set(uint64_t); break;
|
|
564
|
-
case CA_FLOAT32: proc_window_sync_set(float32_t); break;
|
|
565
|
-
case CA_FLOAT64: proc_window_sync_set(float64_t); break;
|
|
566
|
-
case CA_FLOAT128: proc_window_sync_set(float128_t); break;
|
|
567
|
-
#ifdef HAVE_COMPLEX_H
|
|
568
|
-
case CA_CMPLX64: proc_window_sync_set(cmplx64_t); break;
|
|
569
|
-
case CA_CMPLX128: proc_window_sync_set(cmplx128_t); break;
|
|
570
|
-
case CA_CMPLX256: proc_window_sync_set(cmplx256_t); break;
|
|
571
|
-
#endif
|
|
572
|
-
default:
|
|
573
|
-
for (i=0; i<count; i++) {
|
|
574
|
-
idx[level] = i;
|
|
575
|
-
k = start + i;
|
|
576
|
-
if ( k < 0 || k >= size0 ) {
|
|
577
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k);
|
|
578
|
-
if ( k < 0 || k >= size0 ) {
|
|
579
|
-
continue;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
idx0[level] = k;
|
|
583
|
-
memcpy(ca_ptr_at_index(cb->parent, idx0), ca_ptr_at_index((CArray*)cb, idx), cb->bytes);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
else {
|
|
588
|
-
for (i=0; i<count; i++) {
|
|
589
|
-
idx[level] = i;
|
|
590
|
-
k = start + i;
|
|
591
|
-
if ( k < 0 || k >= size0 ) {
|
|
592
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k);
|
|
593
|
-
if ( k < 0 || k >= size0 ) {
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
idx0[level] = k;
|
|
598
|
-
ca_window_sync_loop(cb, level+1, idx, idx0);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
void
|
|
604
|
-
ca_window_sync (CAWindow *cb)
|
|
605
|
-
{
|
|
606
|
-
ca_size_t idx[CA_RANK_MAX];
|
|
607
|
-
ca_size_t idx0[CA_RANK_MAX];
|
|
608
|
-
ca_window_sync_loop(cb, (int8_t) 0, idx, idx0);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
#define proc_window_fill_set(type) \
|
|
612
|
-
{ \
|
|
613
|
-
CArray *parent = cb->parent; \
|
|
614
|
-
type *q; \
|
|
615
|
-
i = 0; \
|
|
616
|
-
while ( start+i<0 && i<count ) { \
|
|
617
|
-
k = start + i; \
|
|
618
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k); \
|
|
619
|
-
if ( k < 0 || k >= size0 ) { \
|
|
620
|
-
; \
|
|
621
|
-
} \
|
|
622
|
-
else { \
|
|
623
|
-
idx0[level] = k; \
|
|
624
|
-
*(type *)ca_ptr_at_index(parent, idx0) = *ptr; \
|
|
625
|
-
} \
|
|
626
|
-
i++; \
|
|
627
|
-
}\
|
|
628
|
-
idx0[level] = start + i; \
|
|
629
|
-
q = (type*)ca_ptr_at_index(parent, idx0);\
|
|
630
|
-
while ( start+i < size0 && i<count ) { \
|
|
631
|
-
*q = *ptr; \
|
|
632
|
-
i++; q++; \
|
|
633
|
-
} \
|
|
634
|
-
while ( i<count ) { \
|
|
635
|
-
k = start + i; \
|
|
636
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k); \
|
|
637
|
-
if ( k < 0 || k >= size0 ) { \
|
|
638
|
-
; \
|
|
639
|
-
} \
|
|
640
|
-
else { \
|
|
641
|
-
idx0[level] = k; \
|
|
642
|
-
*(type*)ca_ptr_at_index(parent, idx0) = *ptr; \
|
|
643
|
-
} \
|
|
644
|
-
i++; \
|
|
645
|
-
} \
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
static void
|
|
649
|
-
ca_window_fill_loop (CAWindow *cb, char *ptr,
|
|
650
|
-
int8_t level, ca_size_t *idx0)
|
|
651
|
-
{
|
|
652
|
-
ca_size_t count = cb->count[level];
|
|
653
|
-
ca_size_t start = cb->start[level];
|
|
654
|
-
ca_size_t size0 = cb->size0[level];
|
|
655
|
-
ca_size_t i, k;
|
|
656
|
-
|
|
657
|
-
if ( level == cb->ndim - 1 ) {
|
|
658
|
-
switch ( cb->data_type ) {
|
|
659
|
-
case CA_BOOLEAN:
|
|
660
|
-
case CA_INT8: proc_window_fill_set(int8_t); break;
|
|
661
|
-
case CA_UINT8: proc_window_fill_set(uint8_t); break;
|
|
662
|
-
case CA_INT16: proc_window_fill_set(int16_t); break;
|
|
663
|
-
case CA_UINT16: proc_window_fill_set(uint16_t); break;
|
|
664
|
-
case CA_INT32: proc_window_fill_set(int32_t); break;
|
|
665
|
-
case CA_UINT32: proc_window_fill_set(uint32_t); break;
|
|
666
|
-
case CA_INT64: proc_window_fill_set(int64_t); break;
|
|
667
|
-
case CA_UINT64: proc_window_fill_set(uint64_t); break;
|
|
668
|
-
case CA_FLOAT32: proc_window_fill_set(float32_t); break;
|
|
669
|
-
case CA_FLOAT64: proc_window_fill_set(float64_t); break;
|
|
670
|
-
case CA_FLOAT128: proc_window_fill_set(float128_t); break;
|
|
671
|
-
#ifdef HAVE_COMPLEX_H
|
|
672
|
-
case CA_CMPLX64: proc_window_fill_set(cmplx64_t); break;
|
|
673
|
-
case CA_CMPLX128: proc_window_fill_set(cmplx128_t); break;
|
|
674
|
-
case CA_CMPLX256: proc_window_fill_set(cmplx256_t); break;
|
|
675
|
-
#endif
|
|
676
|
-
default:
|
|
677
|
-
for (i=0; i<count; i++) {
|
|
678
|
-
k = start + i;
|
|
679
|
-
if ( k < 0 || k >= size0 ) {
|
|
680
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k);
|
|
681
|
-
if ( k < 0 || k >= size0 ) {
|
|
682
|
-
continue;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
idx0[level] = k;
|
|
686
|
-
memcpy(ca_ptr_at_index(cb->parent, idx0), ptr, cb->bytes);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
else {
|
|
691
|
-
for (i=0; i<count; i++) {
|
|
692
|
-
k = start + i;
|
|
693
|
-
if ( k < 0 || k >= size0 ) {
|
|
694
|
-
k = ca_bounds_normalize_index(cb->bounds, size0, k);
|
|
695
|
-
if ( k < 0 || k >= size0 ) {
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
idx0[level] = k;
|
|
700
|
-
ca_window_fill_loop(cb, ptr, level+1, idx0);
|
|
1242
|
+
CAWindow *ca = (CAWindow *) ap;
|
|
1243
|
+
int8_t k;
|
|
1244
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
1245
|
+
out_parent_dims[k] = ca->parent->dim[k];
|
|
1246
|
+
/* Interior-only axes are promoted to STRIDE kind. An axis touches no
|
|
1247
|
+
boundary cell iff start[k] >= 0 and start[k] + count[k] <=
|
|
1248
|
+
parent->dim[k] (step is implicitly 1); it is then a pure strided slice
|
|
1249
|
+
of the parent, so emitting STRIDE lets the engine take its strided fast
|
|
1250
|
+
paths (slab fusion, axis-merge, alias) and skip the per-cell
|
|
1251
|
+
ca_bounds_normalize_index + OOB check that SHIFT costs. */
|
|
1252
|
+
if ( ca->start[k] >= 0
|
|
1253
|
+
&& ca->start[k] + ca->count[k] <= ca->parent->dim[k] ) {
|
|
1254
|
+
out[k].kind = CA_AXIS_KIND_STRIDE;
|
|
1255
|
+
out[k].count = ca->count[k];
|
|
1256
|
+
out[k].start = ca->start[k];
|
|
1257
|
+
out[k].step = 1;
|
|
1258
|
+
out[k].indices = NULL;
|
|
1259
|
+
/* size0 / policy unused for STRIDE — set defaults for hygiene. */
|
|
1260
|
+
out[k].size0 = ca->size0[k];
|
|
1261
|
+
out[k].policy = ca->bounds[k];
|
|
1262
|
+
} else {
|
|
1263
|
+
out[k].kind = CA_AXIS_KIND_SHIFT;
|
|
1264
|
+
out[k].count = ca->count[k];
|
|
1265
|
+
out[k].start = ca->start[k];
|
|
1266
|
+
out[k].step = 1;
|
|
1267
|
+
out[k].indices = NULL;
|
|
1268
|
+
out[k].size0 = ca->size0[k];
|
|
1269
|
+
out[k].policy = ca->bounds[k];
|
|
701
1270
|
}
|
|
702
1271
|
}
|
|
703
|
-
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
void
|
|
707
|
-
ca_window_fill (CAWindow *cb, char *ptr)
|
|
708
|
-
{
|
|
709
|
-
ca_size_t idx0[CA_RANK_MAX];
|
|
710
|
-
ca_window_fill_loop(cb, ptr, (int8_t) 0, idx0);
|
|
711
1272
|
}
|
|
712
1273
|
|
|
713
1274
|
/* ------------------------------------------------------------------- */
|
|
@@ -716,25 +1277,22 @@ VALUE
|
|
|
716
1277
|
rb_ca_window_new (VALUE cary,
|
|
717
1278
|
ca_size_t *start, ca_size_t *count, int8_t bounds, char *fill)
|
|
718
1279
|
{
|
|
1280
|
+
/* Scalar-bounds wrapper for the Ruby surface: fan the single policy out
|
|
1281
|
+
to a per-axis array before calling ca_window_new. */
|
|
719
1282
|
volatile VALUE obj;
|
|
720
1283
|
CArray *parent;
|
|
721
1284
|
CAWindow *ca;
|
|
1285
|
+
uint8_t bounds_arr[CA_RANK_MAX];
|
|
1286
|
+
int8_t i;
|
|
722
1287
|
rb_check_carray_object(cary);
|
|
723
1288
|
TypedData_Get_Struct(cary, CArray, &carray_data_type, parent);
|
|
724
|
-
|
|
1289
|
+
for (i = 0; i < parent->ndim; i++) bounds_arr[i] = (uint8_t) bounds;
|
|
1290
|
+
ca = ca_window_new(parent, start, count, bounds_arr, fill);
|
|
725
1291
|
obj = ca_wrap_struct(ca);
|
|
726
1292
|
rb_ca_set_parent(obj, cary);
|
|
727
|
-
rb_ca_data_type_inherit(obj, cary);
|
|
728
1293
|
return obj;
|
|
729
1294
|
}
|
|
730
1295
|
|
|
731
|
-
/* yard:
|
|
732
|
-
class CArray
|
|
733
|
-
def window (*argv)
|
|
734
|
-
end
|
|
735
|
-
end
|
|
736
|
-
*/
|
|
737
|
-
|
|
738
1296
|
VALUE
|
|
739
1297
|
rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
740
1298
|
{
|
|
@@ -770,13 +1328,10 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
770
1328
|
count[i] = len;
|
|
771
1329
|
}
|
|
772
1330
|
|
|
773
|
-
if (
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
779
|
-
/* rb_warn(":fill_value option for CArray#window will be obsoleted."); */
|
|
1331
|
+
if ( rb_block_given_p() ) {
|
|
1332
|
+
rb_raise(rb_eArgError,
|
|
1333
|
+
"window: block form for fill value removed in 3.0; "
|
|
1334
|
+
"use fill_value: kwarg (e.g. window(-1..1, fill_value: UNDEF))");
|
|
780
1335
|
}
|
|
781
1336
|
|
|
782
1337
|
if ( rfval == CA_NIL ) {
|
|
@@ -809,14 +1364,19 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
809
1364
|
bounds = CA_BOUNDS_NEAREST;
|
|
810
1365
|
}
|
|
811
1366
|
else if ( ! strncmp(cbounds, "periodic", 8) ) {
|
|
812
|
-
|
|
1367
|
+
rb_raise(rb_eArgError,
|
|
1368
|
+
"bounds=>'periodic' removed in 3.0; "
|
|
1369
|
+
"use CArray#roll(...) for cyclic shift "
|
|
1370
|
+
"(returns a CARoll view)");
|
|
813
1371
|
}
|
|
814
1372
|
else if ( ! strncmp(cbounds, "reflect", 7) ) {
|
|
815
|
-
|
|
1373
|
+
rb_raise(rb_eArgError,
|
|
1374
|
+
"bounds=>'reflect' removed in 3.0; "
|
|
1375
|
+
"there is no view-based alternative");
|
|
816
1376
|
}
|
|
817
1377
|
else if ( ! strncmp(cbounds, "mask", 4) ) {
|
|
818
1378
|
rb_warn("CAWindow option :bounds=>\"mask\" will be obsolete");
|
|
819
|
-
rb_warn("use ca.window(
|
|
1379
|
+
rb_warn("use ca.window(..., fill_value: UNDEF)");
|
|
820
1380
|
bounds = CA_BOUNDS_MASK;
|
|
821
1381
|
}
|
|
822
1382
|
else if ( ! strncmp(cbounds, "fill", 4) ) {
|
|
@@ -837,6 +1397,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
837
1397
|
|
|
838
1398
|
obj = rb_ca_window_new(self, start, count, bounds, fill);
|
|
839
1399
|
|
|
1400
|
+
CA_FACE_LIFT_IF_FACE(obj, self, ca);
|
|
840
1401
|
return obj;
|
|
841
1402
|
}
|
|
842
1403
|
|
|
@@ -857,18 +1418,17 @@ rb_ca_window_initialize_copy (VALUE self, VALUE other)
|
|
|
857
1418
|
TypedData_Get_Struct(self, CAWindow, &cawindow_data_type, ca);
|
|
858
1419
|
TypedData_Get_Struct(other, CAWindow, &cawindow_data_type, cs);
|
|
859
1420
|
|
|
1421
|
+
/* `self` came from rb_ca_window_s_allocate (TypedData_Make_Struct,
|
|
1422
|
+
_pool == NULL). Attach the pool before setup so the ndim-sized
|
|
1423
|
+
tail fields skip ALLOC_N. */
|
|
1424
|
+
if ( ca_func[CA_OBJ_WINDOW].pool_init ) {
|
|
1425
|
+
ca_array_pool_alloc(ca, CA_OBJ_WINDOW, cs->ndim);
|
|
1426
|
+
}
|
|
860
1427
|
ca_window_setup(ca, cs->parent, cs->start, cs->count, cs->bounds, cs->fill);
|
|
861
1428
|
|
|
862
1429
|
return self;
|
|
863
1430
|
}
|
|
864
1431
|
|
|
865
|
-
/* yard:
|
|
866
|
-
class CAWindow
|
|
867
|
-
def index2addr0 (idx)
|
|
868
|
-
end
|
|
869
|
-
end
|
|
870
|
-
*/
|
|
871
|
-
|
|
872
1432
|
static VALUE
|
|
873
1433
|
rb_ca_window_idx2addr0 (int argc, VALUE *argv, VALUE self)
|
|
874
1434
|
{
|
|
@@ -899,13 +1459,6 @@ rb_ca_window_idx2addr0 (int argc, VALUE *argv, VALUE self)
|
|
|
899
1459
|
}
|
|
900
1460
|
}
|
|
901
1461
|
|
|
902
|
-
/* yard:
|
|
903
|
-
class CAWindow
|
|
904
|
-
def addr2addr0 (addr)
|
|
905
|
-
end
|
|
906
|
-
end
|
|
907
|
-
*/
|
|
908
|
-
|
|
909
1462
|
static VALUE
|
|
910
1463
|
rb_ca_window_addr2addr0 (VALUE self, VALUE raddr)
|
|
911
1464
|
{
|
|
@@ -924,43 +1477,13 @@ rb_ca_window_addr2addr0 (VALUE self, VALUE raddr)
|
|
|
924
1477
|
addr += cw->start[i] + idx[i];
|
|
925
1478
|
}
|
|
926
1479
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
static VALUE
|
|
932
|
-
rb_ca_window_move (int argc, VALUE *argv, VALUE self)
|
|
933
|
-
{
|
|
934
|
-
CAWindow *cw;
|
|
935
|
-
ca_size_t start;
|
|
936
|
-
int8_t i;
|
|
937
|
-
|
|
938
|
-
TypedData_Get_Struct(self, CAWindow, &cawindow_data_type, cw);
|
|
939
|
-
|
|
940
|
-
if ( argc != cw->ndim ) {
|
|
941
|
-
rb_raise(rb_eArgError, "invalid # of arguments");
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
ca_update_mask(cw);
|
|
945
|
-
for (i=0; i<cw->ndim; i++) {
|
|
946
|
-
start = NUM2SIZE(argv[i]);
|
|
947
|
-
cw->start[i] = start;
|
|
948
|
-
if ( cw->mask ) {
|
|
949
|
-
((CAWindow*)(cw->mask))->start[i] = start;
|
|
950
|
-
}
|
|
1480
|
+
if ( addr < 0 || addr >= cw->parent->elements ) {
|
|
1481
|
+
return Qnil;
|
|
951
1482
|
}
|
|
952
1483
|
|
|
953
|
-
return
|
|
1484
|
+
return SIZE2NUM(addr);
|
|
954
1485
|
}
|
|
955
1486
|
|
|
956
|
-
/* yard:
|
|
957
|
-
class CAWindow
|
|
958
|
-
def fill_value
|
|
959
|
-
end
|
|
960
|
-
def fill_value= (val)
|
|
961
|
-
end
|
|
962
|
-
end
|
|
963
|
-
*/
|
|
964
1487
|
|
|
965
1488
|
static VALUE
|
|
966
1489
|
rb_ca_window_set_fill_value (VALUE self, VALUE rfval)
|
|
@@ -982,9 +1505,12 @@ rb_ca_window_get_fill_value (VALUE self)
|
|
|
982
1505
|
static VALUE
|
|
983
1506
|
rb_ca_window_get_bounds (VALUE self)
|
|
984
1507
|
{
|
|
1508
|
+
/* bounds is per-axis, but the Ruby surface always constructs with a single
|
|
1509
|
+
scalar policy fanned out across all axes, so axis 0 reproduces the value
|
|
1510
|
+
that was passed in. */
|
|
985
1511
|
CAWindow *cw;
|
|
986
1512
|
TypedData_Get_Struct(self, CAWindow, &cawindow_data_type, cw);
|
|
987
|
-
return SIZE2NUM(cw->bounds);
|
|
1513
|
+
return SIZE2NUM(cw->bounds[0]);
|
|
988
1514
|
}
|
|
989
1515
|
|
|
990
1516
|
#define rb_cw_get_attr_ary(name) \
|
|
@@ -1001,36 +1527,73 @@ rb_ca_window_get_bounds (VALUE self)
|
|
|
1001
1527
|
return ary; \
|
|
1002
1528
|
}
|
|
1003
1529
|
|
|
1004
|
-
/* yard:
|
|
1005
|
-
class CAWindow
|
|
1006
|
-
def size0
|
|
1007
|
-
end
|
|
1008
|
-
def start
|
|
1009
|
-
end
|
|
1010
|
-
def step
|
|
1011
|
-
end
|
|
1012
|
-
def count
|
|
1013
|
-
end
|
|
1014
|
-
def offset
|
|
1015
|
-
end
|
|
1016
|
-
end
|
|
1017
|
-
*/
|
|
1018
|
-
|
|
1019
1530
|
static VALUE rb_cw_get_attr_ary(start);
|
|
1020
1531
|
static VALUE rb_cw_get_attr_ary(count);
|
|
1021
1532
|
static VALUE rb_cw_get_attr_ary(size0);
|
|
1022
1533
|
|
|
1534
|
+
#ifdef CARRAY_DEV_BUILD
|
|
1535
|
+
/* Debug accessor (dev-only, stripped in release), returning the embed
|
|
1536
|
+
descriptor as a Hash. The descriptor is an internal implementation detail
|
|
1537
|
+
with no user-facing meaning; this exists so spec_ai can pin its geometry,
|
|
1538
|
+
which nothing else can observe (a stale descriptor produces wrong data, not
|
|
1539
|
+
an error). Gated by CARRAY_DEV_BUILD, enabled via
|
|
1540
|
+
`extconf.rb --enable-dev-build` or `CARRAY_DEV=1 rake build_ext`.
|
|
1541
|
+
|
|
1542
|
+
Polymorphic over CAWindow / CAShift: both share the same C struct layout
|
|
1543
|
+
(CAShift is a typedef of CAWindow) but use distinct TypedData types.
|
|
1544
|
+
DATA_PTR is safe here because Ruby method dispatch has already restricted
|
|
1545
|
+
self to one of those two classes. */
|
|
1546
|
+
VALUE
|
|
1547
|
+
rb_ca_window_embed_descriptor (VALUE self)
|
|
1548
|
+
{
|
|
1549
|
+
CAWindow *ca = (CAWindow *) DATA_PTR(self);
|
|
1550
|
+
VALUE hash, ps_ary, ec_ary, oo_ary;
|
|
1551
|
+
int8_t k;
|
|
1552
|
+
|
|
1553
|
+
ps_ary = rb_ary_new_capa(ca->ndim);
|
|
1554
|
+
ec_ary = rb_ary_new_capa(ca->ndim);
|
|
1555
|
+
oo_ary = rb_ary_new_capa(ca->ndim);
|
|
1556
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
1557
|
+
rb_ary_push(ps_ary, SIZE2NUM(ca->embed_parent_start[k]));
|
|
1558
|
+
rb_ary_push(ec_ary, SIZE2NUM(ca->embed_count[k]));
|
|
1559
|
+
rb_ary_push(oo_ary, SIZE2NUM(ca->embed_output_offset[k]));
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
hash = rb_hash_new();
|
|
1563
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("parent_start")), ps_ary);
|
|
1564
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("count")), ec_ary);
|
|
1565
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("output_offset")), oo_ary);
|
|
1566
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("is_empty")),
|
|
1567
|
+
ca->embed_is_empty ? Qtrue : Qfalse);
|
|
1568
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("covers_all")),
|
|
1569
|
+
ca->embed_covers_all ? Qtrue : Qfalse);
|
|
1570
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("eligible")),
|
|
1571
|
+
ca->embed_eligible ? Qtrue : Qfalse);
|
|
1572
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("alias_eligible")),
|
|
1573
|
+
ca->embed_alias_eligible ? Qtrue : Qfalse);
|
|
1574
|
+
return hash;
|
|
1575
|
+
}
|
|
1576
|
+
#endif /* CARRAY_DEV_BUILD */
|
|
1577
|
+
|
|
1023
1578
|
void
|
|
1024
|
-
Init_ca_obj_window ()
|
|
1579
|
+
Init_ca_obj_window (void)
|
|
1025
1580
|
{
|
|
1026
1581
|
|
|
1027
|
-
rb_cCAWindow = rb_define_class("CAWindow",
|
|
1582
|
+
rb_cCAWindow = rb_define_class("CAWindow", rb_cCAView);
|
|
1028
1583
|
rb_cCAWindowMask = rb_define_class("CAWindowMask", rb_cCAWindow);
|
|
1029
1584
|
|
|
1030
|
-
|
|
1585
|
+
/* Pool framework: seven ndim-sized tail fields live in one _pool buffer
|
|
1586
|
+
(fill stays separate, bytes-sized). Set on the global ca_window_func
|
|
1587
|
+
before ca_install_obj_type copies it into ca_func[], and before
|
|
1588
|
+
Init_ca_obj_shift copies ca_window_func into ca_shift_func. */
|
|
1589
|
+
ca_window_func.struct_size = sizeof(CAWindow);
|
|
1590
|
+
ca_window_func.pool_bytes = ca_window_pool_bytes;
|
|
1591
|
+
ca_window_func.pool_init = ca_window_pool_init;
|
|
1592
|
+
|
|
1593
|
+
CA_OBJ_WINDOW = ca_install_obj_type(rb_cCAWindow,
|
|
1031
1594
|
&cawindow_data_type,
|
|
1032
1595
|
rb_cCAWindowMask,
|
|
1033
|
-
&cawindow_mask_data_type, ca_window_func);
|
|
1596
|
+
&cawindow_mask_data_type, &ca_window_func, sizeof(ca_window_func));
|
|
1034
1597
|
rb_define_const(rb_cObject, "CA_OBJ_WINDOW", INT2NUM(CA_OBJ_WINDOW));
|
|
1035
1598
|
|
|
1036
1599
|
rb_define_method(rb_cCArray, "window", rb_ca_window, -1);
|
|
@@ -1039,7 +1602,6 @@ Init_ca_obj_window ()
|
|
|
1039
1602
|
rb_define_method(rb_cCAWindow, "initialize_copy",
|
|
1040
1603
|
rb_ca_window_initialize_copy, 1);
|
|
1041
1604
|
|
|
1042
|
-
rb_define_method(rb_cCAWindow, "move", rb_ca_window_move, -1);
|
|
1043
1605
|
|
|
1044
1606
|
rb_define_method(rb_cCAWindow, "index2addr0", rb_ca_window_idx2addr0, -1);
|
|
1045
1607
|
rb_define_method(rb_cCAWindow, "addr2addr0", rb_ca_window_addr2addr0, 1);
|
|
@@ -1053,5 +1615,11 @@ Init_ca_obj_window ()
|
|
|
1053
1615
|
rb_define_method(rb_cCAWindow, "count", rb_cw_count, 0);
|
|
1054
1616
|
rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
|
|
1055
1617
|
|
|
1618
|
+
#ifdef CARRAY_DEV_BUILD
|
|
1619
|
+
/* debug accessor (dev-only, stripped in release) */
|
|
1620
|
+
rb_define_method(rb_cCAWindow, "_embed_descriptor",
|
|
1621
|
+
rb_ca_window_embed_descriptor, 0);
|
|
1622
|
+
#endif
|
|
1623
|
+
|
|
1056
1624
|
}
|
|
1057
1625
|
|