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_meld.c
ADDED
|
@@ -0,0 +1,1034 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
CAMeld view = ragged concatenate along an existing axis of K parents.
|
|
4
|
+
|
|
5
|
+
shape[a] = parents[0]->dim[a] for a != meld_axis
|
|
6
|
+
shape[meld_axis] = sum_k parents[k]->dim[meld_axis]
|
|
7
|
+
|
|
8
|
+
Segment boundaries are held as an explicit prefix-sum table (seg_offset)
|
|
9
|
+
so segment resolution is per-segment (K-1 boundaries) rather than per-cell.
|
|
10
|
+
User sees a welded axis; engine keeps the segments.
|
|
11
|
+
|
|
12
|
+
Op coverage (all accept arbitrary meld_axis):
|
|
13
|
+
xfer_all:
|
|
14
|
+
meld_axis == 0 = K contig xfer_all into per-segment slots (best,
|
|
15
|
+
memcpy-bound)
|
|
16
|
+
meld_axis != 0 = per-parent slab buf gather + row-major
|
|
17
|
+
scatter/gather (adapted from CAStack k_axis!=0)
|
|
18
|
+
xfer_stride:
|
|
19
|
+
structural + ma==0 = K contig xfer_stride into per-segment slot
|
|
20
|
+
structural + ma!=0 = per-segment slab buf + row-major scatter/gather
|
|
21
|
+
non-structural = per-cell fallback via xfer_index (universal
|
|
22
|
+
safety net; correctness-first, not perf-optimised)
|
|
23
|
+
xfer_index: binary-search seg_offset + parent dispatch
|
|
24
|
+
xfer_addrs: naive per-addr binary search (O(n log K))
|
|
25
|
+
(sortedness-aware O(n+K) merge is a future
|
|
26
|
+
optimisation, memo §7.3)
|
|
27
|
+
fill_data: K-fold ca_fill
|
|
28
|
+
create_mask: horizontal propagation (mirrors CAStack)
|
|
29
|
+
fold_stride: decline (return 0)
|
|
30
|
+
|
|
31
|
+
Design ref: devel/MEMO_CAMELD_SEGMENT_MAJOR_ENGINE.md. Meld-axis reduce
|
|
32
|
+
fast path (per-parent decompose, eager parity) lives in Ruby land at
|
|
33
|
+
lib/carray/meld_reduce.rb. The internal-axis paths above give the
|
|
34
|
+
deliver-it-anyway correctness contract; they are not tile-cache
|
|
35
|
+
optimised, but
|
|
36
|
+
since all decomposable reductions bypass xfer_all/xfer_stride via the
|
|
37
|
+
Ruby fast path, this rarely matters in practice.
|
|
38
|
+
|
|
39
|
+
---------------------------------------------------------------------------- */
|
|
40
|
+
|
|
41
|
+
#include "carray.h"
|
|
42
|
+
|
|
43
|
+
/* ------------------------------------------------------------------- */
|
|
44
|
+
/* TypedData */
|
|
45
|
+
/* ------------------------------------------------------------------- */
|
|
46
|
+
|
|
47
|
+
static size_t
|
|
48
|
+
ca_meld_dsize (const void *ap)
|
|
49
|
+
{
|
|
50
|
+
const CAMeld *ca = (const CAMeld *) ap;
|
|
51
|
+
return sizeof(CAMeld)
|
|
52
|
+
+ ca->ndim * sizeof(ca_size_t) /* dim[] */
|
|
53
|
+
+ ca->n_parents * sizeof(CArray *) /* parents[] */
|
|
54
|
+
+ (ca->n_parents + 1) * sizeof(ca_size_t); /* seg_offset[] */
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const rb_data_type_t cameld_data_type = {
|
|
58
|
+
.parent = &caview_data_type,
|
|
59
|
+
.wrap_struct_name = "CAMeld",
|
|
60
|
+
.function = {
|
|
61
|
+
.dmark = ca_mark,
|
|
62
|
+
.dfree = ca_free,
|
|
63
|
+
.dsize = ca_meld_dsize,
|
|
64
|
+
.dcompact = NULL
|
|
65
|
+
},
|
|
66
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const rb_data_type_t cameld_mask_data_type = {
|
|
70
|
+
.parent = &cameld_data_type,
|
|
71
|
+
.wrap_struct_name = "CAMeldMask",
|
|
72
|
+
.function = {
|
|
73
|
+
.dmark = ca_mark,
|
|
74
|
+
.dfree = ca_free_nop,
|
|
75
|
+
.dsize = ca_meld_dsize,
|
|
76
|
+
.dcompact = NULL
|
|
77
|
+
},
|
|
78
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
int8_t CA_OBJ_MELD;
|
|
82
|
+
|
|
83
|
+
VALUE rb_cCAMeld;
|
|
84
|
+
VALUE rb_cCAMeldMask;
|
|
85
|
+
|
|
86
|
+
static ID id_parents;
|
|
87
|
+
|
|
88
|
+
/* ------------------------------------------------------------------- */
|
|
89
|
+
/* uniform check */
|
|
90
|
+
/* ------------------------------------------------------------------- */
|
|
91
|
+
|
|
92
|
+
/* Parents must share dtype, ndim, bytes, and all dims except meld_axis;
|
|
93
|
+
meld_axis lengths are the ragged dimension (may differ). */
|
|
94
|
+
static void
|
|
95
|
+
ca_meld_check_uniform (int32_t n_parents, CArray **parents, int8_t meld_axis)
|
|
96
|
+
{
|
|
97
|
+
CArray *ref;
|
|
98
|
+
int32_t i;
|
|
99
|
+
int8_t k;
|
|
100
|
+
if ( n_parents <= 0 ) {
|
|
101
|
+
rb_raise(rb_eArgError, "CAMeld requires at least one parent");
|
|
102
|
+
}
|
|
103
|
+
ref = parents[0];
|
|
104
|
+
if ( meld_axis < 0 || meld_axis >= ref->ndim ) {
|
|
105
|
+
rb_raise(rb_eArgError,
|
|
106
|
+
"CAMeld meld_axis %d out of range [0, %d)",
|
|
107
|
+
(int) meld_axis, (int) ref->ndim);
|
|
108
|
+
}
|
|
109
|
+
for ( i = 1; i < n_parents; i++ ) {
|
|
110
|
+
CArray *p = parents[i];
|
|
111
|
+
if ( p->data_type != ref->data_type ) {
|
|
112
|
+
rb_raise(rb_eArgError,
|
|
113
|
+
"CAMeld parents must have uniform data_type "
|
|
114
|
+
"(parent[0]=%d, parent[%d]=%d)",
|
|
115
|
+
ref->data_type, i, p->data_type);
|
|
116
|
+
}
|
|
117
|
+
if ( p->ndim != ref->ndim ) {
|
|
118
|
+
rb_raise(rb_eArgError,
|
|
119
|
+
"CAMeld parents must have uniform ndim "
|
|
120
|
+
"(parent[0]=%d, parent[%d]=%d)",
|
|
121
|
+
ref->ndim, i, p->ndim);
|
|
122
|
+
}
|
|
123
|
+
if ( p->bytes != ref->bytes ) {
|
|
124
|
+
rb_raise(rb_eArgError,
|
|
125
|
+
"CAMeld parents must have uniform bytes "
|
|
126
|
+
"(parent[0]=%lld, parent[%d]=%lld)",
|
|
127
|
+
(long long) ref->bytes, i, (long long) p->bytes);
|
|
128
|
+
}
|
|
129
|
+
for ( k = 0; k < ref->ndim; k++ ) {
|
|
130
|
+
if ( k == meld_axis ) continue;
|
|
131
|
+
if ( p->dim[k] != ref->dim[k] ) {
|
|
132
|
+
rb_raise(rb_eArgError,
|
|
133
|
+
"CAMeld parents must have uniform shape except at meld_axis %d "
|
|
134
|
+
"(mismatch at axis %d: parent[0]=%lld, parent[%d]=%lld)",
|
|
135
|
+
(int) meld_axis, (int) k,
|
|
136
|
+
(long long) ref->dim[k], i, (long long) p->dim[k]);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ------------------------------------------------------------------- */
|
|
143
|
+
/* setup / new / free / clone */
|
|
144
|
+
/* ------------------------------------------------------------------- */
|
|
145
|
+
|
|
146
|
+
int
|
|
147
|
+
ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis)
|
|
148
|
+
{
|
|
149
|
+
CArray *ref;
|
|
150
|
+
int32_t i;
|
|
151
|
+
int8_t a;
|
|
152
|
+
|
|
153
|
+
ca_meld_check_uniform(n_parents, parents, meld_axis);
|
|
154
|
+
ref = parents[0];
|
|
155
|
+
|
|
156
|
+
ca->obj_type = CA_OBJ_MELD;
|
|
157
|
+
ca->data_type = ref->data_type;
|
|
158
|
+
ca->flags = CA_FLAG_MULTI_PARENTS;
|
|
159
|
+
ca->ndim = ref->ndim;
|
|
160
|
+
ca->bytes = ref->bytes;
|
|
161
|
+
ca->ptr = NULL;
|
|
162
|
+
ca->mask = NULL;
|
|
163
|
+
ca->_pool = NULL;
|
|
164
|
+
|
|
165
|
+
ca->parent = ref; /* CAView base = parents[0] */
|
|
166
|
+
ca->attach = 0;
|
|
167
|
+
ca->nosync = 0;
|
|
168
|
+
|
|
169
|
+
ca->n_parents = n_parents;
|
|
170
|
+
ca->parents = ALLOC_N(CArray *, n_parents);
|
|
171
|
+
for ( i = 0; i < n_parents; i++ ) {
|
|
172
|
+
ca->parents[i] = parents[i];
|
|
173
|
+
}
|
|
174
|
+
ca->meld_axis = meld_axis;
|
|
175
|
+
|
|
176
|
+
/* Prefix-sum along meld_axis: seg_offset[k+1] = seg_offset[k] + parents[k]->dim[meld_axis]. */
|
|
177
|
+
ca->seg_offset = ALLOC_N(ca_size_t, n_parents + 1);
|
|
178
|
+
ca->seg_offset[0] = 0;
|
|
179
|
+
for ( i = 0; i < n_parents; i++ ) {
|
|
180
|
+
ca->seg_offset[i + 1] = ca->seg_offset[i] + parents[i]->dim[meld_axis];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
ca->dim = ALLOC_N(ca_size_t, ca->ndim);
|
|
184
|
+
for ( a = 0; a < ca->ndim; a++ ) {
|
|
185
|
+
ca->dim[a] = (a == meld_axis) ? ca->seg_offset[n_parents] : ref->dim[a];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
ca->elements = 0;
|
|
189
|
+
for ( i = 0; i < n_parents; i++ ) ca->elements += parents[i]->elements;
|
|
190
|
+
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
CAMeld *
|
|
195
|
+
ca_meld_new (int32_t n_parents, CArray **parents, int8_t meld_axis)
|
|
196
|
+
{
|
|
197
|
+
CAMeld *ca = ALLOC(CAMeld);
|
|
198
|
+
ca_meld_setup(ca, n_parents, parents, meld_axis);
|
|
199
|
+
return ca;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
static void
|
|
203
|
+
free_ca_meld (void *ap)
|
|
204
|
+
{
|
|
205
|
+
/* CAREFUL: `parents[]` is an alias array we allocated with ALLOC_N in
|
|
206
|
+
ca_meld_setup; individual parent CArrays are kept alive by the Ruby
|
|
207
|
+
wrapper's `@parents` ivar (set by rb_ca_meld_new / rb_ca_meld_initialize).
|
|
208
|
+
So we xfree the tail here but never touch parent contents. */
|
|
209
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
210
|
+
if ( ca != NULL ) {
|
|
211
|
+
ca_free(ca->mask);
|
|
212
|
+
xfree(ca->seg_offset);
|
|
213
|
+
xfree(ca->parents);
|
|
214
|
+
xfree(ca->dim);
|
|
215
|
+
xfree(ca);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static void *
|
|
220
|
+
ca_meld_func_clone (void *ap)
|
|
221
|
+
{
|
|
222
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
223
|
+
return ca_meld_new(ca->n_parents, ca->parents, ca->meld_axis);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* ------------------------------------------------------------------- */
|
|
227
|
+
/* helpers */
|
|
228
|
+
/* ------------------------------------------------------------------- */
|
|
229
|
+
|
|
230
|
+
/* Binary search: return k such that seg_offset[k] <= v < seg_offset[k+1].
|
|
231
|
+
Precondition: 0 <= v < seg_offset[n_parents]. */
|
|
232
|
+
static inline int32_t
|
|
233
|
+
ca_meld_segment_of (const CAMeld *ca, ca_size_t v)
|
|
234
|
+
{
|
|
235
|
+
int32_t lo = 0, hi = ca->n_parents;
|
|
236
|
+
while ( hi - lo > 1 ) {
|
|
237
|
+
int32_t mid = (lo + hi) >> 1;
|
|
238
|
+
if ( ca->seg_offset[mid] <= v ) lo = mid;
|
|
239
|
+
else hi = mid;
|
|
240
|
+
}
|
|
241
|
+
return lo;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Product of dims [meld_axis+1 .. ndim-1] (the tail after meld_axis). For
|
|
245
|
+
meld_axis == 0 this is the "row size in elements" for each meld_axis step. */
|
|
246
|
+
static inline ca_size_t
|
|
247
|
+
ca_meld_tail_elements (const CAMeld *ca)
|
|
248
|
+
{
|
|
249
|
+
int8_t a;
|
|
250
|
+
ca_size_t p = 1;
|
|
251
|
+
for ( a = ca->meld_axis + 1; a < ca->ndim; a++ ) p *= ca->dim[a];
|
|
252
|
+
return p;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ------------------------------------------------------------------- */
|
|
256
|
+
/* xfer_index */
|
|
257
|
+
/* ------------------------------------------------------------------- */
|
|
258
|
+
|
|
259
|
+
/* view[..., v at meld_axis, ...] = parents[k][..., v - seg_offset[k], ...]
|
|
260
|
+
where k = segment_of(v). */
|
|
261
|
+
static void
|
|
262
|
+
ca_meld_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
263
|
+
{
|
|
264
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
265
|
+
int8_t ma = ca->meld_axis;
|
|
266
|
+
ca_size_t v = idx[ma];
|
|
267
|
+
int32_t k;
|
|
268
|
+
ca_size_t pidx[CA_RANK_MAX];
|
|
269
|
+
int8_t a;
|
|
270
|
+
|
|
271
|
+
if ( v < 0 || v >= ca->dim[ma] ) {
|
|
272
|
+
rb_raise(rb_eIndexError,
|
|
273
|
+
"CAMeld meld_axis (axis %d) index %lld out of range [0, %lld)",
|
|
274
|
+
(int) ma, (long long) v, (long long) ca->dim[ma]);
|
|
275
|
+
}
|
|
276
|
+
k = ca_meld_segment_of(ca, v);
|
|
277
|
+
for ( a = 0; a < ca->ndim; a++ ) pidx[a] = idx[a];
|
|
278
|
+
pidx[ma] = v - ca->seg_offset[k];
|
|
279
|
+
ca_xfer_index(ca->parents[k], pidx, data, dir);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* ------------------------------------------------------------------- */
|
|
283
|
+
/* xfer_addrs — K-pass per-parent bucket */
|
|
284
|
+
/* ------------------------------------------------------------------- */
|
|
285
|
+
|
|
286
|
+
/* For each parent k, scan all n addrs and pick those whose meld-axis
|
|
287
|
+
coordinate lands in [seg_offset[k], seg_offset[k+1]). Total cost is
|
|
288
|
+
O(n·K) (K linear scans over n addrs); per-addr binary-search + K-way
|
|
289
|
+
bucket would drop this to O(n log K) with more temp storage, and a
|
|
290
|
+
sortedness-aware merge on sorted addrs (typical for boolean-mask
|
|
291
|
+
access) would give O(n+K) — both are demand-driven follow-ons. The
|
|
292
|
+
K-pass structure keeps peak scratch to a single (n * bytes) slab
|
|
293
|
+
shared across all parents. */
|
|
294
|
+
static void
|
|
295
|
+
ca_meld_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
296
|
+
void *data, int dir)
|
|
297
|
+
{
|
|
298
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
299
|
+
int8_t ma = ca->meld_axis;
|
|
300
|
+
ca_size_t bytes = ca->bytes;
|
|
301
|
+
ca_size_t view_div[CA_RANK_MAX]; /* row-major divisor per view axis */
|
|
302
|
+
ca_size_t parent_mul[CA_RANK_MAX]; /* per-parent (recomputed inside k loop) */
|
|
303
|
+
ca_size_t *paddrs;
|
|
304
|
+
char *pdata, *cdata = (char *) data;
|
|
305
|
+
volatile VALUE holder1, holder2;
|
|
306
|
+
ca_size_t s, i;
|
|
307
|
+
int32_t k;
|
|
308
|
+
int8_t a;
|
|
309
|
+
|
|
310
|
+
paddrs = ALLOCV_N(ca_size_t, holder1, n);
|
|
311
|
+
pdata = ALLOCV_N(char, holder2, n * bytes);
|
|
312
|
+
|
|
313
|
+
s = 1;
|
|
314
|
+
for ( a = ca->ndim - 1; a >= 0; a-- ) { view_div[a] = s; s *= ca->dim[a]; }
|
|
315
|
+
|
|
316
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
317
|
+
ca_size_t seg_lo = ca->seg_offset[k];
|
|
318
|
+
ca_size_t seg_hi = ca->seg_offset[k + 1];
|
|
319
|
+
ca_size_t parent_meld_len = seg_hi - seg_lo;
|
|
320
|
+
ca_size_t m = 0;
|
|
321
|
+
|
|
322
|
+
/* Per-parent row-major multiplier: uses parent[0]'s dims for non-meld
|
|
323
|
+
axes (uniform check) and this parent's segment length at meld_axis. */
|
|
324
|
+
s = 1;
|
|
325
|
+
for ( a = ca->ndim - 1; a >= 0; a-- ) {
|
|
326
|
+
parent_mul[a] = s;
|
|
327
|
+
if ( a == ma ) s *= parent_meld_len;
|
|
328
|
+
else s *= ca->parents[0]->dim[a];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
for ( i = 0; i < n; i++ ) {
|
|
332
|
+
ca_size_t addr = addrs[i];
|
|
333
|
+
ca_size_t vidx_ma = (addr / view_div[ma]) % ca->dim[ma];
|
|
334
|
+
ca_size_t paddr;
|
|
335
|
+
if ( vidx_ma < seg_lo || vidx_ma >= seg_hi ) continue;
|
|
336
|
+
paddr = 0;
|
|
337
|
+
for ( a = 0; a < ca->ndim; a++ ) {
|
|
338
|
+
ca_size_t vv = (addr / view_div[a]) % ca->dim[a];
|
|
339
|
+
if ( a == ma ) vv -= seg_lo;
|
|
340
|
+
paddr += vv * parent_mul[a];
|
|
341
|
+
}
|
|
342
|
+
paddrs[m] = paddr;
|
|
343
|
+
if ( dir == CA_XFER_PUT ) {
|
|
344
|
+
memcpy(pdata + m * bytes, cdata + i * bytes, bytes);
|
|
345
|
+
}
|
|
346
|
+
m++;
|
|
347
|
+
}
|
|
348
|
+
if ( m > 0 ) {
|
|
349
|
+
ca_xfer_addrs(ca->parents[k], m, paddrs, pdata, dir);
|
|
350
|
+
if ( dir == CA_XFER_GET ) {
|
|
351
|
+
ca_size_t mm = 0;
|
|
352
|
+
for ( i = 0; i < n; i++ ) {
|
|
353
|
+
ca_size_t addr = addrs[i];
|
|
354
|
+
ca_size_t vidx_ma = (addr / view_div[ma]) % ca->dim[ma];
|
|
355
|
+
if ( vidx_ma < seg_lo || vidx_ma >= seg_hi ) continue;
|
|
356
|
+
memcpy(cdata + i * bytes, pdata + mm * bytes, bytes);
|
|
357
|
+
mm++;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
ALLOCV_END(holder2);
|
|
364
|
+
ALLOCV_END(holder1);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* ------------------------------------------------------------------- */
|
|
368
|
+
/* xfer_stride */
|
|
369
|
+
/* ------------------------------------------------------------------- */
|
|
370
|
+
|
|
371
|
+
/* Structural best path (meld_axis == 0): K contig xfer_stride calls, each
|
|
372
|
+
parent's row-major output is a contig slot in dst -- zero copy. */
|
|
373
|
+
static void
|
|
374
|
+
ca_meld_xfer_stride_ma0 (CAMeld *ca, ca_size_t *starts, ca_size_t *counts,
|
|
375
|
+
ca_size_t *strides, void *data, int dir)
|
|
376
|
+
{
|
|
377
|
+
ca_size_t native[CA_RANK_MAX], dstride[CA_RANK_MAX];
|
|
378
|
+
ca_size_t pstarts[CA_RANK_MAX], pcounts[CA_RANK_MAX], pstrides[CA_RANK_MAX];
|
|
379
|
+
ca_size_t s, req_lo, req_hi;
|
|
380
|
+
int32_t k_lo, k_hi, k;
|
|
381
|
+
int8_t i;
|
|
382
|
+
char *d = (char *) data;
|
|
383
|
+
|
|
384
|
+
s = ca->bytes;
|
|
385
|
+
for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
386
|
+
for ( i = 0; i < ca->ndim; i++ ) pstrides[i] = native[i];
|
|
387
|
+
|
|
388
|
+
s = ca->bytes;
|
|
389
|
+
for ( i = ca->ndim - 1; i >= 0; i-- ) { dstride[i] = s; s *= counts[i]; }
|
|
390
|
+
|
|
391
|
+
req_lo = starts[0];
|
|
392
|
+
req_hi = starts[0] + counts[0];
|
|
393
|
+
if ( req_hi <= req_lo ) return;
|
|
394
|
+
k_lo = ca_meld_segment_of(ca, req_lo);
|
|
395
|
+
k_hi = ca_meld_segment_of(ca, req_hi - 1) + 1;
|
|
396
|
+
|
|
397
|
+
for ( i = 1; i < ca->ndim; i++ ) { pstarts[i] = starts[i]; pcounts[i] = counts[i]; }
|
|
398
|
+
|
|
399
|
+
for ( k = k_lo; k < k_hi; k++ ) {
|
|
400
|
+
ca_size_t seg_lo = ca->seg_offset[k];
|
|
401
|
+
ca_size_t seg_hi = ca->seg_offset[k + 1];
|
|
402
|
+
ca_size_t view_lo = (req_lo > seg_lo) ? req_lo : seg_lo;
|
|
403
|
+
ca_size_t view_hi = (req_hi < seg_hi) ? req_hi : seg_hi;
|
|
404
|
+
ca_size_t slot_off = (view_lo - req_lo) * dstride[0];
|
|
405
|
+
pstarts[0] = view_lo - seg_lo;
|
|
406
|
+
pcounts[0] = view_hi - view_lo;
|
|
407
|
+
ca_xfer_stride(ca->parents[k], pstarts, pcounts, pstrides, d + slot_off, dir);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* Internal-axis structural path (meld_axis != 0): per-segment slab buf
|
|
412
|
+
gather, then row-major scatter/gather to dst at view-strided positions.
|
|
413
|
+
The K stride sits mid-order so each parent's row-major slab does not fit
|
|
414
|
+
contig in dst. Follows CAStack's k_axis!=0 xfer_stride shape adapted
|
|
415
|
+
to segment-variable lengths. */
|
|
416
|
+
static void
|
|
417
|
+
ca_meld_xfer_stride_ma_internal (CAMeld *ca, ca_size_t *starts,
|
|
418
|
+
ca_size_t *counts, void *data, int dir)
|
|
419
|
+
{
|
|
420
|
+
int8_t ma = ca->meld_axis;
|
|
421
|
+
int8_t ndim = ca->ndim;
|
|
422
|
+
ca_size_t bytes = ca->bytes;
|
|
423
|
+
ca_size_t dstride[CA_RANK_MAX], pstrides[CA_RANK_MAX];
|
|
424
|
+
ca_size_t pstarts[CA_RANK_MAX], pcounts[CA_RANK_MAX];
|
|
425
|
+
ca_size_t req_lo, req_hi;
|
|
426
|
+
int32_t k_lo, k_hi, k;
|
|
427
|
+
int8_t i;
|
|
428
|
+
ca_size_t s;
|
|
429
|
+
char *d = (char *) data;
|
|
430
|
+
|
|
431
|
+
/* dst row-major over output counts[] */
|
|
432
|
+
s = bytes;
|
|
433
|
+
for ( i = ndim - 1; i >= 0; i-- ) { dstride[i] = s; s *= counts[i]; }
|
|
434
|
+
|
|
435
|
+
req_lo = starts[ma];
|
|
436
|
+
req_hi = starts[ma] + counts[ma];
|
|
437
|
+
if ( req_hi <= req_lo ) return;
|
|
438
|
+
k_lo = ca_meld_segment_of(ca, req_lo);
|
|
439
|
+
k_hi = ca_meld_segment_of(ca, req_hi - 1) + 1;
|
|
440
|
+
|
|
441
|
+
/* Non-meld pstarts/pcounts pass through */
|
|
442
|
+
for ( i = 0; i < ndim; i++ ) {
|
|
443
|
+
if ( i == ma ) continue;
|
|
444
|
+
pstarts[i] = starts[i];
|
|
445
|
+
pcounts[i] = counts[i];
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
for ( k = k_lo; k < k_hi; k++ ) {
|
|
449
|
+
CArray *p = ca->parents[k];
|
|
450
|
+
ca_size_t seg_lo = ca->seg_offset[k];
|
|
451
|
+
ca_size_t seg_hi = ca->seg_offset[k + 1];
|
|
452
|
+
ca_size_t view_lo = (req_lo > seg_lo) ? req_lo : seg_lo;
|
|
453
|
+
ca_size_t view_hi = (req_hi < seg_hi) ? req_hi : seg_hi;
|
|
454
|
+
ca_size_t ma_off_in_dst = view_lo - req_lo;
|
|
455
|
+
ca_size_t inner_dim[CA_RANK_MAX];
|
|
456
|
+
ca_size_t slab_bytes = bytes;
|
|
457
|
+
volatile VALUE holder;
|
|
458
|
+
char *buf;
|
|
459
|
+
ca_size_t paddr;
|
|
460
|
+
|
|
461
|
+
pstarts[ma] = view_lo - seg_lo;
|
|
462
|
+
pcounts[ma] = view_hi - view_lo;
|
|
463
|
+
for ( i = 0; i < ndim; i++ ) {
|
|
464
|
+
inner_dim[i] = pcounts[i];
|
|
465
|
+
slab_bytes *= pcounts[i];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/* pstrides is the SOURCE stride the parent uses to walk its own memory
|
|
469
|
+
(see ca_xfer_stride_dispatch + ca_xfer_strided_walk in carray_core.c:
|
|
470
|
+
for an entity source `strides` argument = byte offsets into
|
|
471
|
+
parent.ptr; dst walks contig via doff += slab_bytes). So pstrides
|
|
472
|
+
must be p's native row-major byte strides (based on p->dim), not
|
|
473
|
+
pcounts. partial-slab pcounts[i] < p->dim[i] just narrows the walk
|
|
474
|
+
range (counts) without changing the source layout. */
|
|
475
|
+
s = bytes;
|
|
476
|
+
for ( i = ndim - 1; i >= 0; i-- ) {
|
|
477
|
+
pstrides[i] = s;
|
|
478
|
+
s *= p->dim[i];
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
buf = ALLOCV_N(char, holder, slab_bytes);
|
|
482
|
+
|
|
483
|
+
if ( dir == CA_XFER_GET ) {
|
|
484
|
+
ca_xfer_stride(p, pstarts, pcounts, pstrides, buf, CA_XFER_GET);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/* Scatter/gather buf to dst using trailing-chunk memcpy.
|
|
488
|
+
Trailing block from meld_axis..ndim-1 is contig in BOTH parent slab
|
|
489
|
+
(row-major over pcounts[]) and dst (dst row-major stride dstride[]),
|
|
490
|
+
because within one parent + one outer combo, cells (ma..ndim-1) map
|
|
491
|
+
to a contig run in dst starting at ma_off_in_dst on meld_axis.
|
|
492
|
+
So we memcpy chunk_bytes = Π pcounts[ma..ndim-1] * bytes and only
|
|
493
|
+
odometer over outer axes 0..ma-1. */
|
|
494
|
+
paddr = 0;
|
|
495
|
+
{
|
|
496
|
+
ca_size_t voff = ma_off_in_dst * dstride[ma];
|
|
497
|
+
ca_size_t outer_step[CA_RANK_MAX], outer_back[CA_RANK_MAX];
|
|
498
|
+
ca_size_t outer_idx[CA_RANK_MAX];
|
|
499
|
+
ca_size_t chunk_bytes;
|
|
500
|
+
/* chunk_bytes = product of pcounts[ma..ndim-1] * bytes */
|
|
501
|
+
chunk_bytes = bytes;
|
|
502
|
+
for ( i = ma; i < ndim; i++ ) chunk_bytes *= inner_dim[i];
|
|
503
|
+
for ( i = 0; i < ma; i++ ) {
|
|
504
|
+
outer_step[i] = dstride[i];
|
|
505
|
+
outer_back[i] = (inner_dim[i] - 1) * dstride[i];
|
|
506
|
+
outer_idx[i] = 0;
|
|
507
|
+
}
|
|
508
|
+
if ( ma == 0 ) {
|
|
509
|
+
/* Guard (should not fire — caller dispatches ma==0 elsewhere) */
|
|
510
|
+
if ( dir == CA_XFER_GET ) memcpy(d + voff, buf, chunk_bytes);
|
|
511
|
+
else memcpy(buf, d + voff, chunk_bytes);
|
|
512
|
+
}
|
|
513
|
+
else if ( dir == CA_XFER_GET ) {
|
|
514
|
+
while ( 1 ) {
|
|
515
|
+
memcpy(d + voff, buf + paddr, chunk_bytes);
|
|
516
|
+
paddr += chunk_bytes;
|
|
517
|
+
i = ma - 1;
|
|
518
|
+
while ( i >= 0 ) {
|
|
519
|
+
if ( ++outer_idx[i] < inner_dim[i] ) { voff += outer_step[i]; break; }
|
|
520
|
+
outer_idx[i] = 0;
|
|
521
|
+
voff -= outer_back[i];
|
|
522
|
+
i--;
|
|
523
|
+
}
|
|
524
|
+
if ( i < 0 ) break;
|
|
525
|
+
}
|
|
526
|
+
} else {
|
|
527
|
+
while ( 1 ) {
|
|
528
|
+
memcpy(buf + paddr, d + voff, chunk_bytes);
|
|
529
|
+
paddr += chunk_bytes;
|
|
530
|
+
i = ma - 1;
|
|
531
|
+
while ( i >= 0 ) {
|
|
532
|
+
if ( ++outer_idx[i] < inner_dim[i] ) { voff += outer_step[i]; break; }
|
|
533
|
+
outer_idx[i] = 0;
|
|
534
|
+
voff -= outer_back[i];
|
|
535
|
+
i--;
|
|
536
|
+
}
|
|
537
|
+
if ( i < 0 ) break;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if ( dir == CA_XFER_PUT ) {
|
|
543
|
+
ca_xfer_stride(p, pstarts, pcounts, pstrides, buf, CA_XFER_PUT);
|
|
544
|
+
}
|
|
545
|
+
ALLOCV_END(holder);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/* Non-structural fallback: per-cell xfer_index. Universal correctness
|
|
550
|
+
safety net for arbitrary strides (works for any meld_axis, including
|
|
551
|
+
permutations like transpose). Follows CAStack's per-cell shape:
|
|
552
|
+
base = Σ starts[k] * native[k] (byte addr in flat root space)
|
|
553
|
+
toff = base + Σ idx[k] * strides[k] (composed byte offset)
|
|
554
|
+
addr2index(root, toff/bytes) → source N-D index
|
|
555
|
+
xfer_index at source idx, dst walks contig by bytes.
|
|
556
|
+
Slow but correct; hot paths stay on the structural branches above. */
|
|
557
|
+
static void
|
|
558
|
+
ca_meld_xfer_stride_per_cell (CAMeld *ca, ca_size_t *starts, ca_size_t *counts,
|
|
559
|
+
ca_size_t *strides, void *data, int dir)
|
|
560
|
+
{
|
|
561
|
+
int8_t ndim = ca->ndim;
|
|
562
|
+
ca_size_t native[CA_RANK_MAX];
|
|
563
|
+
ca_size_t idx[CA_RANK_MAX], vidx[CA_RANK_MAX];
|
|
564
|
+
ca_size_t base = 0, doff = 0, s;
|
|
565
|
+
char *d = (char *) data;
|
|
566
|
+
int8_t i;
|
|
567
|
+
|
|
568
|
+
CA_ASSUME(ndim >= 0 && ndim <= CA_RANK_MAX); /* bound loops over [CA_RANK_MAX] arrays */
|
|
569
|
+
s = ca->bytes;
|
|
570
|
+
for ( i = ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
571
|
+
for ( i = 0; i < ndim; i++ ) base += starts[i] * native[i];
|
|
572
|
+
for ( i = 0; i < ndim; i++ ) idx[i] = 0;
|
|
573
|
+
|
|
574
|
+
while ( 1 ) {
|
|
575
|
+
ca_size_t toff = base;
|
|
576
|
+
for ( i = 0; i < ndim; i++ ) toff += idx[i] * strides[i];
|
|
577
|
+
ca_addr2index((CArray *) ca, toff / ca->bytes, vidx);
|
|
578
|
+
ca_meld_func_xfer_index(ca, vidx, d + doff, dir);
|
|
579
|
+
doff += ca->bytes;
|
|
580
|
+
i = ndim - 1;
|
|
581
|
+
while ( i >= 0 ) {
|
|
582
|
+
if ( ++idx[i] < counts[i] ) break;
|
|
583
|
+
idx[i] = 0;
|
|
584
|
+
i--;
|
|
585
|
+
}
|
|
586
|
+
if ( i < 0 ) break;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
static void
|
|
591
|
+
ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
592
|
+
ca_size_t *strides, void *data, int dir)
|
|
593
|
+
{
|
|
594
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
595
|
+
int8_t ma = ca->meld_axis;
|
|
596
|
+
ca_size_t native[CA_RANK_MAX];
|
|
597
|
+
ca_size_t s;
|
|
598
|
+
int8_t i;
|
|
599
|
+
int structural = 1;
|
|
600
|
+
|
|
601
|
+
/* Bound check on meld_axis */
|
|
602
|
+
{
|
|
603
|
+
ca_size_t req_lo = starts[ma];
|
|
604
|
+
ca_size_t req_hi = starts[ma] + counts[ma];
|
|
605
|
+
if ( req_lo < 0 || req_hi > ca->dim[ma] ) {
|
|
606
|
+
rb_raise(rb_eIndexError,
|
|
607
|
+
"CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
|
|
608
|
+
(int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
s = ca->bytes;
|
|
613
|
+
for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
614
|
+
for ( i = 0; i < ca->ndim; i++ ) {
|
|
615
|
+
if ( strides[i] != native[i] ) { structural = 0; break; }
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if ( ! structural ) {
|
|
619
|
+
ca_meld_xfer_stride_per_cell(ca, starts, counts, strides, data, dir);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if ( ma == 0 ) {
|
|
623
|
+
ca_meld_xfer_stride_ma0(ca, starts, counts, strides, data, dir);
|
|
624
|
+
} else {
|
|
625
|
+
ca_meld_xfer_stride_ma_internal(ca, starts, counts, data, dir);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/* ------------------------------------------------------------------- */
|
|
630
|
+
/* xfer_all */
|
|
631
|
+
/* ------------------------------------------------------------------- */
|
|
632
|
+
|
|
633
|
+
/* meld_axis == 0 best path: K contig xfer_all at prefix-sum offsets. */
|
|
634
|
+
static void
|
|
635
|
+
ca_meld_xfer_all_ma0 (CAMeld *ca, void *data, int dir)
|
|
636
|
+
{
|
|
637
|
+
ca_size_t tail_bytes = ca_meld_tail_elements(ca) * ca->bytes;
|
|
638
|
+
char *d = (char *) data;
|
|
639
|
+
int32_t k;
|
|
640
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
641
|
+
ca_xfer_all(ca->parents[k], d + ca->seg_offset[k] * tail_bytes, dir);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/* Internal-axis xfer_all: per-parent slab buf + trailing-chunk memcpy.
|
|
646
|
+
Key observation — for meld_axis in [1, ndim-1], the trailing block from
|
|
647
|
+
meld_axis..ndim-1 is contig in BOTH parent and view (the meld cells at
|
|
648
|
+
[seg_lo..seg_hi) × non-meld inner cells all sit contig in view row-major
|
|
649
|
+
as long as outer axes 0..ma-1 are fixed). So per parent:
|
|
650
|
+
chunk_bytes = p->dim[ma..ndim-1] product * bytes (= trailing contig run)
|
|
651
|
+
outer_ndim = ma (axes to odometer)
|
|
652
|
+
Iterate outer axes 0..ma-1, memcpy one chunk_bytes block per iter.
|
|
653
|
+
Falls out of the K contig xfer_alls into the buf, then this loop scatters
|
|
654
|
+
the per-parent slab into its segmented slot in view.
|
|
655
|
+
The naive per-cell odometer that this replaces cost ~2x eager on M2;
|
|
656
|
+
chunked memcpy approaches memcpy bandwidth (eager parity target). */
|
|
657
|
+
static void
|
|
658
|
+
ca_meld_xfer_all_ma_internal (CAMeld *ca, void *data, int dir)
|
|
659
|
+
{
|
|
660
|
+
int8_t ma = ca->meld_axis;
|
|
661
|
+
int8_t ndim = ca->ndim;
|
|
662
|
+
ca_size_t bytes = ca->bytes;
|
|
663
|
+
ca_size_t view_stride[CA_RANK_MAX];
|
|
664
|
+
char *d = (char *) data;
|
|
665
|
+
int32_t k;
|
|
666
|
+
int8_t a;
|
|
667
|
+
ca_size_t s;
|
|
668
|
+
|
|
669
|
+
s = bytes;
|
|
670
|
+
for ( a = ndim - 1; a >= 0; a-- ) {
|
|
671
|
+
view_stride[a] = s;
|
|
672
|
+
s *= ca->dim[a];
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
676
|
+
CArray *p = ca->parents[k];
|
|
677
|
+
ca_size_t seg_lo = ca->seg_offset[k];
|
|
678
|
+
ca_size_t slab_bytes = (ca_size_t) p->elements * bytes;
|
|
679
|
+
ca_size_t chunk_bytes;
|
|
680
|
+
ca_size_t outer_step[CA_RANK_MAX], outer_back[CA_RANK_MAX];
|
|
681
|
+
ca_size_t outer_idx[CA_RANK_MAX];
|
|
682
|
+
volatile VALUE holder;
|
|
683
|
+
char *buf;
|
|
684
|
+
ca_size_t paddr;
|
|
685
|
+
ca_size_t voff;
|
|
686
|
+
int8_t i;
|
|
687
|
+
|
|
688
|
+
buf = ALLOCV_N(char, holder, slab_bytes);
|
|
689
|
+
|
|
690
|
+
if ( dir == CA_XFER_GET ) {
|
|
691
|
+
ca_xfer_all(p, buf, CA_XFER_GET);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* Trailing contig chunk = product(dim[ma..ndim-1]) elements. */
|
|
695
|
+
chunk_bytes = bytes;
|
|
696
|
+
for ( a = ma; a < ndim; a++ ) chunk_bytes *= p->dim[a];
|
|
697
|
+
|
|
698
|
+
/* Outer axes 0..ma-1: build step[]/back[] over view row-major. */
|
|
699
|
+
for ( a = 0; a < ma; a++ ) {
|
|
700
|
+
outer_step[a] = view_stride[a];
|
|
701
|
+
outer_back[a] = (p->dim[a] - 1) * view_stride[a];
|
|
702
|
+
outer_idx[a] = 0;
|
|
703
|
+
}
|
|
704
|
+
paddr = 0;
|
|
705
|
+
voff = seg_lo * view_stride[ma]; /* meld-axis start in view row-major */
|
|
706
|
+
|
|
707
|
+
if ( ma == 0 ) {
|
|
708
|
+
/* Should not reach here (caller dispatches ma==0 to the external
|
|
709
|
+
best path), but guard anyway: one chunk covers the whole parent. */
|
|
710
|
+
if ( dir == CA_XFER_GET ) memcpy(d + voff, buf, chunk_bytes);
|
|
711
|
+
else memcpy(buf, d + voff, chunk_bytes);
|
|
712
|
+
}
|
|
713
|
+
else if ( dir == CA_XFER_GET ) {
|
|
714
|
+
while ( 1 ) {
|
|
715
|
+
memcpy(d + voff, buf + paddr, chunk_bytes);
|
|
716
|
+
paddr += chunk_bytes;
|
|
717
|
+
i = ma - 1;
|
|
718
|
+
while ( i >= 0 ) {
|
|
719
|
+
if ( ++outer_idx[i] < p->dim[i] ) { voff += outer_step[i]; break; }
|
|
720
|
+
outer_idx[i] = 0;
|
|
721
|
+
voff -= outer_back[i];
|
|
722
|
+
i--;
|
|
723
|
+
}
|
|
724
|
+
if ( i < 0 ) break;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
while ( 1 ) {
|
|
729
|
+
memcpy(buf + paddr, d + voff, chunk_bytes);
|
|
730
|
+
paddr += chunk_bytes;
|
|
731
|
+
i = ma - 1;
|
|
732
|
+
while ( i >= 0 ) {
|
|
733
|
+
if ( ++outer_idx[i] < p->dim[i] ) { voff += outer_step[i]; break; }
|
|
734
|
+
outer_idx[i] = 0;
|
|
735
|
+
voff -= outer_back[i];
|
|
736
|
+
i--;
|
|
737
|
+
}
|
|
738
|
+
if ( i < 0 ) break;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if ( dir == CA_XFER_PUT ) {
|
|
743
|
+
ca_xfer_all(p, buf, CA_XFER_PUT);
|
|
744
|
+
}
|
|
745
|
+
ALLOCV_END(holder);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
static void
|
|
750
|
+
ca_meld_func_xfer_all (void *ap, void *data, int dir)
|
|
751
|
+
{
|
|
752
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
753
|
+
if ( ca->meld_axis == 0 ) {
|
|
754
|
+
ca_meld_xfer_all_ma0(ca, data, dir);
|
|
755
|
+
} else {
|
|
756
|
+
ca_meld_xfer_all_ma_internal(ca, data, dir);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* ------------------------------------------------------------------- */
|
|
761
|
+
/* attach / sync / detach */
|
|
762
|
+
/* ------------------------------------------------------------------- */
|
|
763
|
+
|
|
764
|
+
static void
|
|
765
|
+
ca_meld_func_allocate (void *ap)
|
|
766
|
+
{
|
|
767
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
768
|
+
int32_t k;
|
|
769
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
770
|
+
ca_attach(ca->parents[k]);
|
|
771
|
+
}
|
|
772
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
static void
|
|
776
|
+
ca_meld_func_attach (void *ap)
|
|
777
|
+
{
|
|
778
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
779
|
+
int32_t k;
|
|
780
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
781
|
+
ca_attach(ca->parents[k]);
|
|
782
|
+
}
|
|
783
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
784
|
+
ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
static void
|
|
788
|
+
ca_meld_func_sync (void *ap)
|
|
789
|
+
{
|
|
790
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
791
|
+
int32_t k;
|
|
792
|
+
ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_PUT);
|
|
793
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
794
|
+
ca_sync(ca->parents[k]);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
static void
|
|
799
|
+
ca_meld_func_detach (void *ap)
|
|
800
|
+
{
|
|
801
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
802
|
+
int32_t k;
|
|
803
|
+
xfree(ca->ptr);
|
|
804
|
+
ca->ptr = NULL;
|
|
805
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
806
|
+
ca_detach(ca->parents[k]);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/* ------------------------------------------------------------------- */
|
|
811
|
+
/* fill_data */
|
|
812
|
+
/* ------------------------------------------------------------------- */
|
|
813
|
+
|
|
814
|
+
static void
|
|
815
|
+
ca_meld_func_fill_data (void *ap, void *ptr)
|
|
816
|
+
{
|
|
817
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
818
|
+
int32_t k;
|
|
819
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
820
|
+
ca_fill(ca->parents[k], ptr);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/* ------------------------------------------------------------------- */
|
|
825
|
+
/* create_mask (horizontal propagation, mirrors CAStack) */
|
|
826
|
+
/* ------------------------------------------------------------------- */
|
|
827
|
+
|
|
828
|
+
static void
|
|
829
|
+
ca_meld_func_create_mask (void *ap)
|
|
830
|
+
{
|
|
831
|
+
CAMeld *ca = (CAMeld *) ap;
|
|
832
|
+
CArray **mask_parents;
|
|
833
|
+
volatile VALUE holder;
|
|
834
|
+
int32_t k;
|
|
835
|
+
|
|
836
|
+
mask_parents = ALLOCV_N(CArray *, holder, ca->n_parents);
|
|
837
|
+
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
838
|
+
ca_update_mask(ca->parents[k]);
|
|
839
|
+
if ( ! ca->parents[k]->mask ) {
|
|
840
|
+
ca_create_mask(ca->parents[k]);
|
|
841
|
+
}
|
|
842
|
+
mask_parents[k] = ca->parents[k]->mask;
|
|
843
|
+
}
|
|
844
|
+
ca->mask = (CArray *) ca_meld_new(ca->n_parents, mask_parents, ca->meld_axis);
|
|
845
|
+
ALLOCV_END(holder);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/* ------------------------------------------------------------------- */
|
|
849
|
+
/* fold_stride — always declines */
|
|
850
|
+
/* ------------------------------------------------------------------- */
|
|
851
|
+
|
|
852
|
+
static int
|
|
853
|
+
ca_meld_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
|
|
854
|
+
{
|
|
855
|
+
(void) ap; (void) f; (void) next_parent;
|
|
856
|
+
return 0; /* fall through to xfer_stride (which handles structural path) */
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/* ------------------------------------------------------------------- */
|
|
860
|
+
/* operation table */
|
|
861
|
+
/* ------------------------------------------------------------------- */
|
|
862
|
+
|
|
863
|
+
ca_operation_function_t ca_meld_func = {
|
|
864
|
+
-1, /* CA_OBJ_MELD */
|
|
865
|
+
CA_VIEW_ARRAY,
|
|
866
|
+
free_ca_meld,
|
|
867
|
+
ca_meld_func_clone,
|
|
868
|
+
ca_meld_func_allocate,
|
|
869
|
+
ca_meld_func_attach,
|
|
870
|
+
ca_meld_func_sync,
|
|
871
|
+
ca_meld_func_detach,
|
|
872
|
+
ca_meld_func_fill_data,
|
|
873
|
+
ca_meld_func_create_mask,
|
|
874
|
+
ca_meld_func_xfer_index,
|
|
875
|
+
ca_meld_func_xfer_addrs,
|
|
876
|
+
ca_meld_func_fold_stride,
|
|
877
|
+
ca_meld_func_xfer_stride,
|
|
878
|
+
ca_meld_func_xfer_all,
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
/* ------------------------------------------------------------------- */
|
|
882
|
+
/* Ruby surface */
|
|
883
|
+
/* ------------------------------------------------------------------- */
|
|
884
|
+
|
|
885
|
+
VALUE
|
|
886
|
+
rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
|
|
887
|
+
{
|
|
888
|
+
volatile VALUE obj;
|
|
889
|
+
CAMeld *ca;
|
|
890
|
+
CArray **parents;
|
|
891
|
+
volatile VALUE holder;
|
|
892
|
+
long n, i;
|
|
893
|
+
|
|
894
|
+
Check_Type(parents_ary, T_ARRAY);
|
|
895
|
+
n = RARRAY_LEN(parents_ary);
|
|
896
|
+
if ( n <= 0 ) {
|
|
897
|
+
rb_raise(rb_eArgError, "CAMeld requires at least one parent");
|
|
898
|
+
}
|
|
899
|
+
parents = ALLOCV_N(CArray *, holder, n);
|
|
900
|
+
for ( i = 0; i < n; i++ ) {
|
|
901
|
+
VALUE p = rb_ary_entry(parents_ary, i);
|
|
902
|
+
rb_check_carray_object(p);
|
|
903
|
+
TypedData_Get_Struct(p, CArray, &carray_data_type, parents[i]);
|
|
904
|
+
}
|
|
905
|
+
ca = ca_meld_new((int32_t) n, parents, meld_axis);
|
|
906
|
+
obj = ca_wrap_struct(ca);
|
|
907
|
+
rb_ivar_set(obj, id_parents, rb_ary_dup(parents_ary));
|
|
908
|
+
rb_ca_set_parent(obj, rb_ary_entry(parents_ary, 0));
|
|
909
|
+
ALLOCV_END(holder);
|
|
910
|
+
return obj;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
static VALUE
|
|
914
|
+
rb_ca_meld_s_allocate (VALUE klass)
|
|
915
|
+
{
|
|
916
|
+
CAMeld *ca;
|
|
917
|
+
return TypedData_Make_Struct(klass, CAMeld, &cameld_data_type, ca);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
static VALUE
|
|
921
|
+
rb_ca_meld_initialize_copy (VALUE self, VALUE other)
|
|
922
|
+
{
|
|
923
|
+
CAMeld *ca, *cs;
|
|
924
|
+
TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
|
|
925
|
+
TypedData_Get_Struct(other, CAMeld, &cameld_data_type, cs);
|
|
926
|
+
ca_meld_setup(ca, cs->n_parents, cs->parents, cs->meld_axis);
|
|
927
|
+
return self;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* CAMeld#initialize(list, axis: 0) */
|
|
931
|
+
static VALUE
|
|
932
|
+
rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
|
|
933
|
+
{
|
|
934
|
+
CAMeld *ca;
|
|
935
|
+
CArray **parents;
|
|
936
|
+
volatile VALUE holder;
|
|
937
|
+
VALUE list, kwargs, axis_val = Qnil;
|
|
938
|
+
int8_t meld_axis = 0;
|
|
939
|
+
long n, i;
|
|
940
|
+
|
|
941
|
+
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
942
|
+
Check_Type(list, T_ARRAY);
|
|
943
|
+
rb_scan_options(kwargs, "axis", &axis_val);
|
|
944
|
+
n = RARRAY_LEN(list);
|
|
945
|
+
if ( n <= 0 ) {
|
|
946
|
+
rb_raise(rb_eArgError, "CAMeld.new requires at least one parent");
|
|
947
|
+
}
|
|
948
|
+
if ( ! NIL_P(axis_val) ) {
|
|
949
|
+
CArray *ref;
|
|
950
|
+
VALUE first = rb_ary_entry(list, 0);
|
|
951
|
+
rb_check_carray_object(first);
|
|
952
|
+
TypedData_Get_Struct(first, CArray, &carray_data_type, ref);
|
|
953
|
+
meld_axis = (int8_t) rb_ca_normalize_axis_for_ndim(
|
|
954
|
+
NUM2LONG(axis_val), (int) ref->ndim, "CAMeld.new");
|
|
955
|
+
}
|
|
956
|
+
TypedData_Get_Struct(self, CAMeld, &cameld_data_type, ca);
|
|
957
|
+
parents = ALLOCV_N(CArray *, holder, n);
|
|
958
|
+
for ( i = 0; i < n; i++ ) {
|
|
959
|
+
VALUE p = rb_ary_entry(list, i);
|
|
960
|
+
rb_check_carray_object(p);
|
|
961
|
+
TypedData_Get_Struct(p, CArray, &carray_data_type, parents[i]);
|
|
962
|
+
}
|
|
963
|
+
ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
|
|
964
|
+
rb_ivar_set(self, id_parents, rb_ary_dup(list));
|
|
965
|
+
rb_ca_set_parent(self, rb_ary_entry(list, 0));
|
|
966
|
+
ALLOCV_END(holder);
|
|
967
|
+
return self;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
static VALUE
|
|
971
|
+
rb_ca_meld_n_parents (VALUE self)
|
|
972
|
+
{
|
|
973
|
+
CAMeld *ca = (CAMeld *) DATA_PTR(self);
|
|
974
|
+
return INT2NUM(ca->n_parents);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
static VALUE
|
|
978
|
+
rb_ca_meld_parents (VALUE self)
|
|
979
|
+
{
|
|
980
|
+
return rb_ivar_get(self, id_parents);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
static VALUE
|
|
984
|
+
rb_ca_meld_meld_axis (VALUE self)
|
|
985
|
+
{
|
|
986
|
+
CAMeld *ca = (CAMeld *) DATA_PTR(self);
|
|
987
|
+
return INT2NUM((int) ca->meld_axis);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/* Ruby-visible segment offsets (K+1 entries, prefix sum along meld_axis). */
|
|
991
|
+
static VALUE
|
|
992
|
+
rb_ca_meld_seg_offsets (VALUE self)
|
|
993
|
+
{
|
|
994
|
+
CAMeld *ca = (CAMeld *) DATA_PTR(self);
|
|
995
|
+
VALUE ary = rb_ary_new_capa(ca->n_parents + 1);
|
|
996
|
+
int32_t k;
|
|
997
|
+
for ( k = 0; k <= ca->n_parents; k++ ) {
|
|
998
|
+
rb_ary_push(ary, LL2NUM((long long) ca->seg_offset[k]));
|
|
999
|
+
}
|
|
1000
|
+
return ary;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
void
|
|
1004
|
+
Init_ca_obj_meld (void)
|
|
1005
|
+
{
|
|
1006
|
+
/* CAMultiParent layout convention check. */
|
|
1007
|
+
if ( offsetof(CAMeld, n_parents) != offsetof(CAMultiParent, n_parents) ||
|
|
1008
|
+
offsetof(CAMeld, parents) != offsetof(CAMultiParent, parents) ) {
|
|
1009
|
+
rb_raise(rb_eRuntimeError,
|
|
1010
|
+
"CAMeld/CAMultiParent layout mismatch (build error)");
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
rb_cCAMeld = rb_define_class("CAMeld", rb_cCAView);
|
|
1014
|
+
rb_cCAMeldMask = rb_define_class("CAMeldMask", rb_cCAMeld);
|
|
1015
|
+
|
|
1016
|
+
CA_OBJ_MELD = ca_install_obj_type(rb_cCAMeld,
|
|
1017
|
+
&cameld_data_type,
|
|
1018
|
+
rb_cCAMeldMask,
|
|
1019
|
+
&cameld_mask_data_type, &ca_meld_func, sizeof(ca_meld_func));
|
|
1020
|
+
rb_define_const(rb_cObject, "CA_OBJ_MELD", INT2NUM(CA_OBJ_MELD));
|
|
1021
|
+
|
|
1022
|
+
id_parents = rb_intern("parents");
|
|
1023
|
+
|
|
1024
|
+
rb_define_alloc_func(rb_cCAMeld, rb_ca_meld_s_allocate);
|
|
1025
|
+
rb_define_method(rb_cCAMeld, "initialize",
|
|
1026
|
+
rb_ca_meld_initialize, -1);
|
|
1027
|
+
rb_define_method(rb_cCAMeld, "initialize_copy",
|
|
1028
|
+
rb_ca_meld_initialize_copy, 1);
|
|
1029
|
+
|
|
1030
|
+
rb_define_method(rb_cCAMeld, "n_parents", rb_ca_meld_n_parents, 0);
|
|
1031
|
+
rb_define_method(rb_cCAMeld, "parents", rb_ca_meld_parents, 0);
|
|
1032
|
+
rb_define_method(rb_cCAMeld, "meld_axis", rb_ca_meld_meld_axis, 0);
|
|
1033
|
+
rb_define_method(rb_cCAMeld, "seg_offsets", rb_ca_meld_seg_offsets, 0);
|
|
1034
|
+
}
|