carray 2.0.1 → 3.0.1
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 +6 -25
- data/CHANGELOG.md +338 -0
- data/{NEWS.md → CHANGELOG.v1.md} +3 -0
- data/LICENSE +1 -1
- data/README.md +120 -36
- data/carray.gemspec +32 -30
- 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 +1244 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +124 -0
- data/ext/ca_binop_dispatch.h +152 -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 +239 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4367 -0
- data/ext/ca_kernel_iterator.h +2596 -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 +839 -0
- data/ext/ca_obj_binop.c +948 -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 +967 -0
- data/ext/ca_obj_face.c +750 -0
- data/ext/ca_obj_face.h +279 -0
- data/ext/ca_obj_fake.c +239 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +308 -0
- data/ext/ca_obj_grid.c +866 -440
- data/ext/ca_obj_meld.c +1039 -0
- data/ext/ca_obj_moncmp.c +588 -0
- data/ext/ca_obj_monop.c +1123 -0
- data/ext/ca_obj_object.c +866 -296
- data/ext/ca_obj_record.c +470 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +593 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +624 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1306 -0
- data/ext/ca_obj_shift.c +231 -793
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2584 -0
- data/ext/ca_obj_string.c +270 -0
- data/ext/ca_obj_tile.c +622 -0
- data/ext/ca_obj_time.c +548 -0
- data/ext/ca_obj_timedelta.c +437 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +785 -0
- data/ext/ca_obj_window.c +1202 -565
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +316 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +473 -0
- data/ext/ca_sweep_engine.h +166 -0
- data/ext/ca_transform_common.c +235 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +810 -420
- data/ext/carray_access.c +873 -731
- data/ext/carray_attribute.c +98 -329
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +376 -0
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2897 -874
- data/ext/carray_call_cfunc.h +313 -0
- data/ext/carray_cast.c +1264 -315
- 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 +168 -270
- data/ext/carray_core.c +1396 -206
- 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 +1021 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +136 -0
- data/ext/carray_kernels_bincmp.c +4446 -0
- data/ext/carray_kernels_binop.c +11001 -0
- data/ext/carray_kernels_init.c +1131 -0
- data/ext/carray_kernels_map.c +3467 -0
- data/ext/carray_kernels_moncmp.c +2097 -0
- data/ext/carray_kernels_monop.c +18313 -0
- data/ext/carray_kernels_reduce_aggregate.c +25837 -0
- data/ext/carray_kernels_reduce_boolean.c +330 -0
- data/ext/carray_kernels_reduce_cumulative.c +14593 -0
- data/ext/carray_kernels_reduce_extreme.c +16948 -0
- data/ext/carray_kernels_reduce_variance.c +3910 -0
- data/ext/carray_kernels_scan.c +3693 -0
- data/ext/carray_kernels_search.c +32138 -0
- data/ext/carray_kernels_sort.c +10626 -0
- data/ext/carray_kernels_triop.c +1392 -0
- data/ext/carray_lazy.c +737 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +853 -158
- 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 +1650 -0
- data/ext/carray_operator.c +1525 -320
- 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 +234 -55
- data/ext/mk_call_cfunc.rb +671 -0
- data/ext/mkkernel.rb +9096 -0
- data/ext/ruby_carray.c +211 -108
- 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 +239 -0
- data/lib/carray/autoload_method_extension.rb +45 -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 +614 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1084 -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 +160 -328
- data/lib/carray/core_extensions.rb +297 -0
- data/lib/carray/data_type_extension.rb +250 -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 +642 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +321 -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 +316 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -26
- data/lib/carray/iterator.rb +58 -349
- data/lib/carray/lazy.rb +941 -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 +52 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +90 -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 +161 -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 +89 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +305 -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 +2654 -38
- data/lib/carray/window_iterator.rb +927 -0
- data/lib/carray.rb +55 -57
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +73 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +49 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +114 -0
- data/yard-stubs/carray_count.rb +79 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +23 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +132 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +89 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +312 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +57 -0
- data/yard-stubs/carray_sort.rb +163 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +220 -138
- 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/ca_obj_unbound_repeat.c +0 -529
- 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/mailmap +0 -1
- 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/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
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
# ext/mk_call_cfunc.rb -- generator for ext/carray_call_cfunc.{c,h}
|
|
2
|
+
#
|
|
3
|
+
# Emits the ext-author-facing API `ca_call_cfunc_N` (= raw arity 1..7) and
|
|
4
|
+
# `ca_call_cfunc_M_N` (= typed dispatcher) used by external CArray gems
|
|
5
|
+
# (carray-gsl, etc.) to wrap C math functions over CArray operations.
|
|
6
|
+
#
|
|
7
|
+
# Generated 2026-06-10 as part of the PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA
|
|
8
|
+
# attach-elimination flow extension (= D phase): the raw `ca_call_cfunc_N`
|
|
9
|
+
# template applies C.7-style alias / non-alias bifurcation for INPUT-only
|
|
10
|
+
# operands (= fsync[k] == '0') and ca_xfer_all-based safe mask gather (= no
|
|
11
|
+
# `ca_attach` on operand masks). OUTPUT operands (= fsync[k] == '1') still
|
|
12
|
+
# use ca_attach + ca_sync (= legitimate per the refined input-only-operand
|
|
13
|
+
# invariant).
|
|
14
|
+
#
|
|
15
|
+
# ABI 100% preserved: signatures, data_type semantics, fsync format, return
|
|
16
|
+
# behavior all unchanged. External gems link against the same symbols
|
|
17
|
+
# without source change.
|
|
18
|
+
#
|
|
19
|
+
# Why a generator? Each of the 7 raw + 13 typed variants is mechanically
|
|
20
|
+
# the same body with arity differences. Hand-keeping 1088 lines invites
|
|
21
|
+
# divergence (= the attach-safe rewrite would have to be repeated 20 times
|
|
22
|
+
# perfectly). The generator centralises the template so a single edit
|
|
23
|
+
# updates every variant. Add a new arity / typed pair by appending one
|
|
24
|
+
# line to the spec.
|
|
25
|
+
#
|
|
26
|
+
# Header (`carray_call_cfunc.h`) is emitted alongside the source so the
|
|
27
|
+
# extern declarations cannot drift from the function definitions. Both
|
|
28
|
+
# files are written in a single invocation; output paths default to
|
|
29
|
+
# `carray_call_cfunc.c` / `carray_call_cfunc.h` in the current directory
|
|
30
|
+
# and can be overridden as `ruby mk_call_cfunc.rb <src.c> <hdr.h>`.
|
|
31
|
+
|
|
32
|
+
# --- spec -------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
RAW_ARITIES = (1..7).to_a # ca_call_cfunc_1 .. _7
|
|
35
|
+
SLAB_ARITIES = (1..7).to_a # ca_call_cslab_1 .. _7
|
|
36
|
+
TYPED_PAIRS = [ # ca_call_cfunc_<m>_<n> (m outputs, n inputs)
|
|
37
|
+
[1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6],
|
|
38
|
+
[2, 1], [2, 2], [2, 3], [2, 4],
|
|
39
|
+
[3, 1], [3, 2], [3, 3],
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
# --- helpers ----------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
def void_p_list(n)
|
|
45
|
+
(0...n).map { |k| "void *p#{k}" }.join(", ")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# For _r variants: callback signature gains a trailing `void *userdata`.
|
|
49
|
+
def void_p_list_r(n)
|
|
50
|
+
void_p_list(n) + ", void *userdata"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def value_param_list(n, prefix: "rcx")
|
|
54
|
+
(0...n).map { |k| "VALUE #{prefix}#{k}" }.join(", ")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def args_p(n)
|
|
58
|
+
(0...n).map { |k| "p[#{k}]" }.join(", ")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# For _r variants: inner call gains a trailing `userdata` arg.
|
|
62
|
+
def args_p_r(n)
|
|
63
|
+
args_p(n) + ", userdata"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# --- signature builders -----------------------------------------------------
|
|
67
|
+
#
|
|
68
|
+
# Each builder returns the multi-line function prototype (without trailing
|
|
69
|
+
# `;` or `{`). Source emitters append the body; header emitters append `;`.
|
|
70
|
+
# Centralising signatures here prevents drift between `.c` and `.h`.
|
|
71
|
+
|
|
72
|
+
def sig_raw(n)
|
|
73
|
+
"VALUE\nca_call_cfunc_#{n} (void (*func)(#{void_p_list(n)}), const char *fsync,\n #{value_param_list(n)})"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def sig_raw_r(n)
|
|
77
|
+
"VALUE\nca_call_cfunc_#{n}_r (void (*func)(#{void_p_list_r(n)}), const char *fsync,\n #{value_param_list(n)},\n void *userdata)"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def typed_params(m, n, r: false)
|
|
81
|
+
dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
|
|
82
|
+
out_data_type_params = (0...m).map { |k| "int8_t #{dty.(k)}" }
|
|
83
|
+
in_data_type_params = (0...n).map { |k| "int8_t dtx#{k + 1}" }
|
|
84
|
+
in_value_params = (0...n).map { |k| "volatile VALUE rx#{k + 1}" }
|
|
85
|
+
fp_args = ["void*"] * (m + n)
|
|
86
|
+
fp_args << "void *userdata" if r
|
|
87
|
+
func_sig = "void (*mathfunc)(#{fp_args.join(", ")})"
|
|
88
|
+
params = out_data_type_params + in_data_type_params + [func_sig] + in_value_params
|
|
89
|
+
params << "void *userdata" if r
|
|
90
|
+
params.join(", ")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def sig_typed(m, n)
|
|
94
|
+
"VALUE\nca_call_cfunc_#{m}_#{n} (#{typed_params(m, n)})"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def sig_typed_r(m, n)
|
|
98
|
+
"VALUE\nca_call_cfunc_#{m}_#{n}_r (#{typed_params(m, n, r: true)})"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The typed slab family declares its callback as ca_cslab_t rather than an
|
|
102
|
+
# arity-shaped function pointer: a slab callback takes its operands through
|
|
103
|
+
# `base`, so its signature does not grow with M + N.
|
|
104
|
+
def typed_slab_params(m, n, r: false)
|
|
105
|
+
dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
|
|
106
|
+
out_data_type_params = (0...m).map { |k| "int8_t #{dty.(k)}" }
|
|
107
|
+
in_data_type_params = (0...n).map { |k| "int8_t dtx#{k + 1}" }
|
|
108
|
+
in_value_params = (0...n).map { |k| "volatile VALUE rx#{k + 1}" }
|
|
109
|
+
func_sig = r ? "ca_cslab_r_t slabfunc" : "ca_cslab_t slabfunc"
|
|
110
|
+
params = out_data_type_params + in_data_type_params + [func_sig] + in_value_params
|
|
111
|
+
params << "void *userdata" if r
|
|
112
|
+
params.join(", ")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def sig_typed_slab(m, n)
|
|
116
|
+
"VALUE\nca_call_cslab_#{m}_#{n} (#{typed_slab_params(m, n)})"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def sig_typed_slab_r(m, n)
|
|
120
|
+
"VALUE\nca_call_cslab_#{m}_#{n}_r (#{typed_slab_params(m, n, r: true)})"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Re-indent each non-blank line of `s` with `prefix`. `<<~` strips the
|
|
124
|
+
# common leading whitespace from a heredoc, which would leave our body
|
|
125
|
+
# at column 0; we want a 2-space body indent inside the function brace.
|
|
126
|
+
def indent(s, prefix = " ")
|
|
127
|
+
s.each_line.map { |l| l.strip.empty? ? l : prefix + l }.join
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# --- raw ca_call_cfunc_N ----------------------------------------------------
|
|
131
|
+
|
|
132
|
+
def emit_raw(n)
|
|
133
|
+
$src.puts sig_raw(n)
|
|
134
|
+
$src.puts "{"
|
|
135
|
+
$src.puts indent(<<~END_C)
|
|
136
|
+
CArray *cx[#{n}];
|
|
137
|
+
char *base[#{n}];
|
|
138
|
+
ca_size_t stride[#{n}];
|
|
139
|
+
char *owned_buf[#{n}];
|
|
140
|
+
int attached[#{n}];
|
|
141
|
+
ca_sweep_state_t state;
|
|
142
|
+
int k_op;
|
|
143
|
+
|
|
144
|
+
END_C
|
|
145
|
+
# extract CArray* from VALUE
|
|
146
|
+
(0...n).each do |k|
|
|
147
|
+
$src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
|
|
148
|
+
end
|
|
149
|
+
$src.puts ""
|
|
150
|
+
$src.puts <<~END_C
|
|
151
|
+
/* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
|
|
152
|
+
broadcast shape check, mask OR across INPUTs, mask propagate to
|
|
153
|
+
OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
|
|
154
|
+
state.n_ops = #{n};
|
|
155
|
+
state.fsync = fsync;
|
|
156
|
+
state.cx = cx;
|
|
157
|
+
state.base = base;
|
|
158
|
+
state.stride = stride;
|
|
159
|
+
state.owned_buf = owned_buf;
|
|
160
|
+
state.attached = attached;
|
|
161
|
+
state.no_mask = 0;
|
|
162
|
+
state.src_label = "ca_call_cfunc_#{n}";
|
|
163
|
+
|
|
164
|
+
ca_sweep_acquire(&state);
|
|
165
|
+
|
|
166
|
+
/* inner loop: advance per-cell ptrs and invoke user kernel func */
|
|
167
|
+
{
|
|
168
|
+
char *p[#{n}];
|
|
169
|
+
ca_size_t k;
|
|
170
|
+
if ( state.m0 ) {
|
|
171
|
+
for ( k = 0; k < state.n_kernel; k++ ) {
|
|
172
|
+
if ( ! state.m0[k] ) {
|
|
173
|
+
for ( k_op = 0; k_op < #{n}; k_op++ ) {
|
|
174
|
+
p[k_op] = base[k_op] + k * stride[k_op];
|
|
175
|
+
}
|
|
176
|
+
func(#{args_p(n)});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
for ( k = 0; k < state.n_kernel; k++ ) {
|
|
181
|
+
for ( k_op = 0; k_op < #{n}; k_op++ ) {
|
|
182
|
+
p[k_op] = base[k_op] + k * stride[k_op];
|
|
183
|
+
}
|
|
184
|
+
func(#{args_p(n)});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
ca_sweep_release(&state);
|
|
190
|
+
|
|
191
|
+
return rcx0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
END_C
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# --- raw ca_call_cfunc_N_r (reentrant: + void *userdata at signature tail) --
|
|
198
|
+
#
|
|
199
|
+
# Variant of emit_raw with a trailing `void *userdata` parameter passed
|
|
200
|
+
# through to every per-cell `func(...)` invocation as its last argument.
|
|
201
|
+
# Naming follows POSIX convention (qsort_r / bsearch_r / strtok_r), where
|
|
202
|
+
# `_r` marks a reentrant form that takes a thunk so the callback no longer
|
|
203
|
+
# depends on file-static / global state. Use when the callback needs to
|
|
204
|
+
# share state with the caller (e.g. accumulators, configuration flags,
|
|
205
|
+
# library plan handles) without resorting to file-static plumbing.
|
|
206
|
+
def emit_raw_r(n)
|
|
207
|
+
$src.puts sig_raw_r(n)
|
|
208
|
+
$src.puts "{"
|
|
209
|
+
$src.puts indent(<<~END_C)
|
|
210
|
+
CArray *cx[#{n}];
|
|
211
|
+
char *base[#{n}];
|
|
212
|
+
ca_size_t stride[#{n}];
|
|
213
|
+
char *owned_buf[#{n}];
|
|
214
|
+
int attached[#{n}];
|
|
215
|
+
ca_sweep_state_t state;
|
|
216
|
+
int k_op;
|
|
217
|
+
|
|
218
|
+
END_C
|
|
219
|
+
(0...n).each do |k|
|
|
220
|
+
$src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
|
|
221
|
+
end
|
|
222
|
+
$src.puts ""
|
|
223
|
+
$src.puts <<~END_C
|
|
224
|
+
/* sweep engine: same lifecycle as ca_call_cfunc_#{n}; the difference is
|
|
225
|
+
the per-cell `func(...)` call has `userdata` as its last argument. */
|
|
226
|
+
state.n_ops = #{n};
|
|
227
|
+
state.fsync = fsync;
|
|
228
|
+
state.cx = cx;
|
|
229
|
+
state.base = base;
|
|
230
|
+
state.stride = stride;
|
|
231
|
+
state.owned_buf = owned_buf;
|
|
232
|
+
state.attached = attached;
|
|
233
|
+
state.no_mask = 0;
|
|
234
|
+
state.src_label = "ca_call_cfunc_#{n}_r";
|
|
235
|
+
|
|
236
|
+
ca_sweep_acquire(&state);
|
|
237
|
+
|
|
238
|
+
{
|
|
239
|
+
char *p[#{n}];
|
|
240
|
+
ca_size_t k;
|
|
241
|
+
if ( state.m0 ) {
|
|
242
|
+
for ( k = 0; k < state.n_kernel; k++ ) {
|
|
243
|
+
if ( ! state.m0[k] ) {
|
|
244
|
+
for ( k_op = 0; k_op < #{n}; k_op++ ) {
|
|
245
|
+
p[k_op] = base[k_op] + k * stride[k_op];
|
|
246
|
+
}
|
|
247
|
+
func(#{args_p_r(n)});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
for ( k = 0; k < state.n_kernel; k++ ) {
|
|
252
|
+
for ( k_op = 0; k_op < #{n}; k_op++ ) {
|
|
253
|
+
p[k_op] = base[k_op] + k * stride[k_op];
|
|
254
|
+
}
|
|
255
|
+
func(#{args_p_r(n)});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
ca_sweep_release(&state);
|
|
261
|
+
|
|
262
|
+
return rcx0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
END_C
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# --- typed dispatchers: M outputs, N inputs ---------------------------------
|
|
269
|
+
#
|
|
270
|
+
# The four typed emitters (cfunc / cfunc_r / cslab / cslab_r) differ in one
|
|
271
|
+
# line -- which lower-level family they delegate to -- and are identical in
|
|
272
|
+
# the wrapping, template allocation and return handling around it. That
|
|
273
|
+
# shared part lives in emit_typed_body so a change to the coercion rules is
|
|
274
|
+
# made once rather than four times, which is the same reason this file is a
|
|
275
|
+
# generator at all.
|
|
276
|
+
#
|
|
277
|
+
# Naming convention (matches legacy ext/carray_call_cfunc.c byte-for-byte):
|
|
278
|
+
# M==1 : output data_type = `dty`, output var = `ry`
|
|
279
|
+
# M >1 : output data_types = `dty1..dtyM`, output vars = `ry1..ryM`
|
|
280
|
+
def emit_typed_body(m, n)
|
|
281
|
+
dty = ->(k) { m == 1 ? "dty" : "dty#{k + 1}" }
|
|
282
|
+
ry = ->(k) { m == 1 ? "ry" : "ry#{k + 1}" }
|
|
283
|
+
|
|
284
|
+
# output VALUE declarations
|
|
285
|
+
out_decl = (0...m).map { |k| "#{ry.(k)} = Qnil" }.join(", ")
|
|
286
|
+
$src.puts " volatile VALUE #{out_decl};"
|
|
287
|
+
$src.puts ""
|
|
288
|
+
|
|
289
|
+
# wrap inputs readonly to declared input data_types
|
|
290
|
+
(0...n).each do |k|
|
|
291
|
+
$src.puts " rx#{k + 1} = rb_ca_wrap_readonly(rx#{k + 1}, INT2NUM(dtx#{k + 1}));"
|
|
292
|
+
end
|
|
293
|
+
$src.puts ""
|
|
294
|
+
|
|
295
|
+
# build one output template per output data_type, widening inputs as needed
|
|
296
|
+
(0...m).each do |out_k|
|
|
297
|
+
cur_dty = dty.(out_k)
|
|
298
|
+
conds = (0...n).map { |in_k| "#{cur_dty} != dtx#{in_k + 1}" }
|
|
299
|
+
wrapped = (0...n).map { |in_k|
|
|
300
|
+
"rb_ca_wrap_readonly(rx#{in_k + 1}, INT2NUM(#{cur_dty}))"
|
|
301
|
+
}
|
|
302
|
+
plain = (0...n).map { |in_k| "rx#{in_k + 1}" }
|
|
303
|
+
$src.puts " if ( #{conds.join(" || ")} ) {"
|
|
304
|
+
$src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{wrapped.join(", ")});"
|
|
305
|
+
$src.puts " } else {"
|
|
306
|
+
$src.puts " #{ry.(out_k)} = rb_ca_template_n(#{n}, #{plain.join(", ")});"
|
|
307
|
+
$src.puts " }"
|
|
308
|
+
end
|
|
309
|
+
$src.puts ""
|
|
310
|
+
|
|
311
|
+
# delegate to the lower-level family
|
|
312
|
+
args = (0...m).map { |k| ry.(k) } + (0...n).map { |k| "rx#{k + 1}" }
|
|
313
|
+
yield args.join(", ")
|
|
314
|
+
$src.puts ""
|
|
315
|
+
|
|
316
|
+
# return: scalar-fetch each output if rank-0, then assemble
|
|
317
|
+
(0...m).each do |k|
|
|
318
|
+
$src.puts " if ( rb_ca_is_scalar(#{ry.(k)}) ) {"
|
|
319
|
+
$src.puts " #{ry.(k)} = rb_ca_fetch_addr(#{ry.(k)}, 0);"
|
|
320
|
+
$src.puts " }"
|
|
321
|
+
end
|
|
322
|
+
if m == 1
|
|
323
|
+
$src.puts " return #{ry.(0)};"
|
|
324
|
+
else
|
|
325
|
+
list = (0...m).map { |k| ry.(k) }.join(", ")
|
|
326
|
+
$src.puts " return rb_ary_new3(#{m}, #{list});"
|
|
327
|
+
end
|
|
328
|
+
$src.puts "}"
|
|
329
|
+
$src.puts ""
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def fsync_literal(m, n)
|
|
333
|
+
"1" * m + "0" * n
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def emit_typed(m, n)
|
|
337
|
+
$src.puts sig_typed(m, n)
|
|
338
|
+
$src.puts "{"
|
|
339
|
+
emit_typed_body(m, n) do |args|
|
|
340
|
+
$src.puts " ca_call_cfunc_#{m + n}(mathfunc, \"#{fsync_literal(m, n)}\", #{args});"
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# --- typed ca_call_cfunc_M_N_r (reentrant variant) -------------------------
|
|
345
|
+
#
|
|
346
|
+
# Same as emit_typed but the callback signature and outer function gain a
|
|
347
|
+
# trailing `void *userdata`; the inner delegate calls ca_call_cfunc_(M+N)_r
|
|
348
|
+
# and forwards `userdata` through.
|
|
349
|
+
def emit_typed_r(m, n)
|
|
350
|
+
$src.puts sig_typed_r(m, n)
|
|
351
|
+
$src.puts "{"
|
|
352
|
+
emit_typed_body(m, n) do |args|
|
|
353
|
+
$src.puts " ca_call_cfunc_#{m + n}_r(mathfunc, \"#{fsync_literal(m, n)}\", #{args}, userdata);"
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# --- typed ca_call_cslab_M_N (chunked variant) -----------------------------
|
|
358
|
+
#
|
|
359
|
+
# The same convenience over the slab family: the caller declares the data
|
|
360
|
+
# types its callback works in and gets back a freshly allocated output,
|
|
361
|
+
# rather than allocating one and matching dtypes by hand.
|
|
362
|
+
#
|
|
363
|
+
# This is where chunking pays most, and not by coincidence. Coercion is
|
|
364
|
+
# what this layer is for, and rb_ca_wrap_readonly implements it as a lazy
|
|
365
|
+
# readonly cast view -- which is never attach-alias, so it is exactly the
|
|
366
|
+
# operand kind the whole-buffer path materialises with
|
|
367
|
+
# xmalloc(elements * bytes). Declaring CA_DOUBLE over an int32 array
|
|
368
|
+
# therefore costs a full converted copy through ca_call_cfunc_M_N and one
|
|
369
|
+
# chunk of arena scratch through ca_call_cslab_M_N. The typical use of the
|
|
370
|
+
# typed layer is the case chunking was built for.
|
|
371
|
+
def emit_typed_slab(m, n)
|
|
372
|
+
$src.puts sig_typed_slab(m, n)
|
|
373
|
+
$src.puts "{"
|
|
374
|
+
emit_typed_body(m, n) do |args|
|
|
375
|
+
$src.puts " ca_call_cslab_#{m + n}(slabfunc, \"#{fsync_literal(m, n)}\", #{args});"
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def emit_typed_slab_r(m, n)
|
|
380
|
+
$src.puts sig_typed_slab_r(m, n)
|
|
381
|
+
$src.puts "{"
|
|
382
|
+
emit_typed_body(m, n) do |args|
|
|
383
|
+
$src.puts " ca_call_cslab_#{m + n}_r(slabfunc, \"#{fsync_literal(m, n)}\", #{args}, userdata);"
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# --- slab ca_call_cslab_N ---------------------------------------------------
|
|
388
|
+
#
|
|
389
|
+
# The chunked counterpart of ca_call_cfunc_N. Two things differ, and they
|
|
390
|
+
# are the same thing seen from two sides:
|
|
391
|
+
#
|
|
392
|
+
# memory -- ca_sweep_acquire_chunked holds one arena scratch of ~32KB per
|
|
393
|
+
# non-alias INPUT for the whole walk and re-gathers it per chunk, where
|
|
394
|
+
# ca_sweep_acquire materialises each such operand whole. Peak input
|
|
395
|
+
# memory stops scaling with the operand.
|
|
396
|
+
#
|
|
397
|
+
# speed -- the callback is handed a whole chunk rather than one cell, so
|
|
398
|
+
# the indirect call is paid once per few thousand cells instead of once
|
|
399
|
+
# per cell. Measured on `y = a + b*2.0` over 10M doubles: 1.48 ns per
|
|
400
|
+
# element through a per-cell callback against 0.34 ns for the same
|
|
401
|
+
# arithmetic in a loop the compiler can see. A slab callback keeps the
|
|
402
|
+
# loop, so it keeps the 0.34, and it is the shape a vectoriser can work
|
|
403
|
+
# with -- a per-cell callback defeats one by construction.
|
|
404
|
+
#
|
|
405
|
+
# The callback signature does not depend on the arity, because the operands
|
|
406
|
+
# reach it through `base` / `stride` rather than as separate parameters.
|
|
407
|
+
# One typedef therefore serves every ca_call_cslab_N.
|
|
408
|
+
#
|
|
409
|
+
# Masked cells are NOT skipped for the author, as the per-cell form skips
|
|
410
|
+
# them: a slab has no way to leave a hole. The chunk's slice of the mask
|
|
411
|
+
# arrives as `m0` instead -- one byte per cell, indexed 0..n-1 alongside the
|
|
412
|
+
# data, or NULL when no INPUT carried a mask.
|
|
413
|
+
def sig_slab(n)
|
|
414
|
+
"VALUE\nca_call_cslab_#{n} (ca_cslab_t func, const char *fsync,\n #{value_param_list(n)})"
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def sig_slab_r(n)
|
|
418
|
+
"VALUE\nca_call_cslab_#{n}_r (ca_cslab_r_t func, const char *fsync,\n #{value_param_list(n)},\n void *userdata)"
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def emit_slab_body(n, name, call)
|
|
422
|
+
$src.puts indent(<<~END_C)
|
|
423
|
+
CArray *cx[#{n}];
|
|
424
|
+
char *base[#{n}];
|
|
425
|
+
char *base_orig[#{n}];
|
|
426
|
+
ca_size_t stride[#{n}];
|
|
427
|
+
char *owned_buf[#{n}];
|
|
428
|
+
int attached[#{n}];
|
|
429
|
+
ca_sweep_state_t state;
|
|
430
|
+
|
|
431
|
+
END_C
|
|
432
|
+
(0...n).each do |k|
|
|
433
|
+
$src.puts " TypedData_Get_Struct(rcx#{k}, CArray, &carray_data_type, cx[#{k}]);"
|
|
434
|
+
end
|
|
435
|
+
$src.puts ""
|
|
436
|
+
$src.puts <<~END_C
|
|
437
|
+
/* sweep engine, chunked path: per-operand acquire (attach for OUTPUT
|
|
438
|
+
and alias INPUT, arena chunk scratch for non-alias INPUT), broadcast
|
|
439
|
+
shape check, mask OR across INPUTs, mask propagate to OUTPUTs at
|
|
440
|
+
release. Lifecycle template lives in ext/ca_sweep_engine.{c,h}.
|
|
441
|
+
base_orig is the field the whole-buffer path leaves zero; the
|
|
442
|
+
chunked path walks it, so it has to be given here. */
|
|
443
|
+
state.n_ops = #{n};
|
|
444
|
+
state.fsync = fsync;
|
|
445
|
+
state.cx = cx;
|
|
446
|
+
state.base = base;
|
|
447
|
+
state.base_orig = base_orig;
|
|
448
|
+
state.stride = stride;
|
|
449
|
+
state.owned_buf = owned_buf;
|
|
450
|
+
state.attached = attached;
|
|
451
|
+
state.no_mask = 0;
|
|
452
|
+
state.src_label = "#{name}";
|
|
453
|
+
|
|
454
|
+
ca_sweep_acquire_chunked(&state);
|
|
455
|
+
|
|
456
|
+
/* outer loop: hand the author one chunk at a time. base[] is rewritten
|
|
457
|
+
per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
|
|
458
|
+
at the arena scratch the chunk was just gathered into, which is
|
|
459
|
+
packed, so stride[] is the element size and the author's inner loop
|
|
460
|
+
sees contiguous data. */
|
|
461
|
+
while ( ca_sweep_next_chunk(&state) ) {
|
|
462
|
+
#{call};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
ca_sweep_release_chunked(&state);
|
|
466
|
+
|
|
467
|
+
return rcx0;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
END_C
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def emit_slab(n)
|
|
474
|
+
$src.puts sig_slab(n)
|
|
475
|
+
$src.puts "{"
|
|
476
|
+
emit_slab_body(n, "ca_call_cslab_#{n}",
|
|
477
|
+
"func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state))")
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
# Variant of emit_slab with a trailing `void *userdata` parameter passed
|
|
481
|
+
# through to every chunk invocation as its last argument, following the same
|
|
482
|
+
# POSIX `_r` convention as ca_call_cfunc_N_r.
|
|
483
|
+
def emit_slab_r(n)
|
|
484
|
+
$src.puts sig_slab_r(n)
|
|
485
|
+
$src.puts "{"
|
|
486
|
+
emit_slab_body(n, "ca_call_cslab_#{n}_r",
|
|
487
|
+
"func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata)")
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# --- header declaration emitters --------------------------------------------
|
|
491
|
+
|
|
492
|
+
def decl_raw(n) ; $hdr.puts sig_raw(n) + ";"; $hdr.puts ""; end
|
|
493
|
+
def decl_raw_r(n) ; $hdr.puts sig_raw_r(n) + ";"; $hdr.puts ""; end
|
|
494
|
+
def decl_typed(m, n) ; $hdr.puts sig_typed(m, n) + ";"; $hdr.puts ""; end
|
|
495
|
+
def decl_typed_r(m, n) ; $hdr.puts sig_typed_r(m, n) + ";"; $hdr.puts ""; end
|
|
496
|
+
def decl_typed_slab(m, n) ; $hdr.puts sig_typed_slab(m, n) + ";"; $hdr.puts ""; end
|
|
497
|
+
def decl_typed_slab_r(m, n) ; $hdr.puts sig_typed_slab_r(m, n) + ";"; $hdr.puts ""; end
|
|
498
|
+
def decl_slab(n) ; $hdr.puts sig_slab(n) + ";"; $hdr.puts ""; end
|
|
499
|
+
def decl_slab_r(n) ; $hdr.puts sig_slab_r(n) + ";"; $hdr.puts ""; end
|
|
500
|
+
|
|
501
|
+
# --- main -------------------------------------------------------------------
|
|
502
|
+
|
|
503
|
+
src_path = ARGV[0] || "carray_call_cfunc.c"
|
|
504
|
+
hdr_path = ARGV[1] || "carray_call_cfunc.h"
|
|
505
|
+
|
|
506
|
+
$src = File.open(src_path, "w")
|
|
507
|
+
$hdr = File.open(hdr_path, "w")
|
|
508
|
+
|
|
509
|
+
$src.puts <<~END_C
|
|
510
|
+
/* ---------------------------------------------------------------------------
|
|
511
|
+
*
|
|
512
|
+
* carray_call_cfunc.c -- ext-author math-call wrapper API
|
|
513
|
+
*
|
|
514
|
+
* GENERATED by ext/mk_call_cfunc.rb -- DO NOT EDIT
|
|
515
|
+
* To modify the template or add a new arity, edit mk_call_cfunc.rb
|
|
516
|
+
* and regenerate (= make / extconf re-runs the generator).
|
|
517
|
+
*
|
|
518
|
+
* Provides `ca_call_cfunc_N` (raw arity 1..7) and `ca_call_cfunc_M_N`
|
|
519
|
+
* (typed dispatcher) used by external CArray gems (carray-gsl, etc.)
|
|
520
|
+
* to wrap C math functions over CArray operations.
|
|
521
|
+
*
|
|
522
|
+
* Reentrant variants `ca_call_cfunc_N_r` and `ca_call_cfunc_M_N_r`
|
|
523
|
+
* (= POSIX `_r` convention, cf. qsort_r / bsearch_r / strtok_r) take
|
|
524
|
+
* a trailing `void *userdata` argument that is passed through to every
|
|
525
|
+
* per-cell callback invocation as its last argument. Use when the
|
|
526
|
+
* callback needs to share state with the caller (accumulators,
|
|
527
|
+
* configuration flags, library plan handles, ...) without resorting to
|
|
528
|
+
* file-static / global plumbing.
|
|
529
|
+
*
|
|
530
|
+
* Attach-safe: INPUT-only operands (= fsync[k] == '0') never call
|
|
531
|
+
* ca_attach on the operand or its mask (= alias check + ALLOCV +
|
|
532
|
+
* ca_xfer_all for non-alias). OUTPUT operands (= fsync[k] == '1')
|
|
533
|
+
* use ca_attach + ca_sync (= legitimate per the refined input-only-
|
|
534
|
+
* operand invariant established in PROPOSAL_EAGER_ELEMENTWISE_NO_ATTACH
|
|
535
|
+
* and extended in PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA).
|
|
536
|
+
*
|
|
537
|
+
* Slab variants `ca_call_cslab_N` / `ca_call_cslab_N_r` take the chunked
|
|
538
|
+
* path instead (ca_sweep_acquire_chunked / ca_sweep_next_chunk /
|
|
539
|
+
* ca_sweep_release_chunked) and hand the callback a whole chunk -- base /
|
|
540
|
+
* stride per operand, a cell count, and the chunk's slice of the mask --
|
|
541
|
+
* rather than one cell. A non-alias INPUT is then re-gathered into a
|
|
542
|
+
* ~32KB arena scratch per chunk rather than materialised whole, so input
|
|
543
|
+
* memory peak stops scaling with the operand; and the indirect call is
|
|
544
|
+
* paid once per chunk, so the author's inner loop is one the compiler can
|
|
545
|
+
* vectorise. Use cfunc when the per-cell body is what you have (a math
|
|
546
|
+
* function to wrap); use cslab when the operand is large, virtual, or the
|
|
547
|
+
* body is worth vectorising.
|
|
548
|
+
*
|
|
549
|
+
* L0.1 (PROPOSAL_L0_AUTHOR_SURFACE, 2026-06-11): the per-operand acquire
|
|
550
|
+
* + broadcast check + mask OR + release lifecycle is now factored out
|
|
551
|
+
* into ext/ca_sweep_engine.{c,h} (ca_sweep_acquire / ca_sweep_release). This
|
|
552
|
+
* file keeps the arity-dependent inner loop only. ABI unchanged.
|
|
553
|
+
*
|
|
554
|
+
* --------------------------------------------------------------------------- */
|
|
555
|
+
|
|
556
|
+
#include "carray.h"
|
|
557
|
+
#include "ca_sweep_engine.h"
|
|
558
|
+
#include <string.h>
|
|
559
|
+
|
|
560
|
+
/* The chunk's iteration mask, or NULL when no INPUT operand carried one.
|
|
561
|
+
m0 is chunk-sized and re-gathered per chunk by ca_sweep_next_chunk, so
|
|
562
|
+
it is already the slice -- one byte per cell, indexed 0..chunk_n-1
|
|
563
|
+
alongside base[] and stride[]. */
|
|
564
|
+
static const boolean8_t *
|
|
565
|
+
ca_sweep_chunk_mask (ca_sweep_state_t *st)
|
|
566
|
+
{
|
|
567
|
+
return st->m0;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
END_C
|
|
571
|
+
|
|
572
|
+
$hdr.puts <<~END_H
|
|
573
|
+
/* ---------------------------------------------------------------------------
|
|
574
|
+
*
|
|
575
|
+
* carray_call_cfunc.h -- ext-author math-call wrapper API (declarations)
|
|
576
|
+
*
|
|
577
|
+
* GENERATED by ext/mk_call_cfunc.rb -- DO NOT EDIT
|
|
578
|
+
* Edit mk_call_cfunc.rb and rebuild to refresh both this header and
|
|
579
|
+
* the matching carray_call_cfunc.c.
|
|
580
|
+
*
|
|
581
|
+
* Included from carray.h so external gems pick up these prototypes
|
|
582
|
+
* transparently via `#include "carray.h"`. The generator co-emits
|
|
583
|
+
* source and header so the prototypes cannot drift from the function
|
|
584
|
+
* definitions. See carray_call_cfunc.c for the full design notes.
|
|
585
|
+
*
|
|
586
|
+
* --------------------------------------------------------------------------- */
|
|
587
|
+
|
|
588
|
+
#ifndef CARRAY_CALL_CFUNC_H
|
|
589
|
+
#define CARRAY_CALL_CFUNC_H
|
|
590
|
+
|
|
591
|
+
/* Chunk callback for the ca_call_cslab_N family. `base` and `stride` are
|
|
592
|
+
one entry per operand, in the order the operands were passed; `n` is the
|
|
593
|
+
number of cells in this chunk; `m0` is the chunk's slice of the mask,
|
|
594
|
+
one byte per cell, or NULL when no INPUT carried a mask. The arity does
|
|
595
|
+
not appear in the signature -- the operands arrive through `base` -- so
|
|
596
|
+
one typedef serves every arity. */
|
|
597
|
+
typedef void (*ca_cslab_t) (char **base, ca_size_t *stride, ca_size_t n,
|
|
598
|
+
const boolean8_t *m0);
|
|
599
|
+
|
|
600
|
+
typedef void (*ca_cslab_r_t) (char **base, ca_size_t *stride, ca_size_t n,
|
|
601
|
+
const boolean8_t *m0, void *userdata);
|
|
602
|
+
|
|
603
|
+
END_H
|
|
604
|
+
|
|
605
|
+
RAW_ARITIES.each do |n|
|
|
606
|
+
emit_raw(n)
|
|
607
|
+
decl_raw(n)
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
$src.puts "/* -------------------------------------------------------------------- */"
|
|
611
|
+
$src.puts "/* Typed dispatchers: M outputs, N inputs. Wrap each input readonly to */"
|
|
612
|
+
$src.puts "/* its declared data_type, allocate output template(s), delegate to raw. */"
|
|
613
|
+
$src.puts "/* -------------------------------------------------------------------- */"
|
|
614
|
+
$src.puts ""
|
|
615
|
+
|
|
616
|
+
TYPED_PAIRS.each do |m, n|
|
|
617
|
+
emit_typed(m, n)
|
|
618
|
+
decl_typed(m, n)
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
$src.puts "/* -------------------------------------------------------------------- */"
|
|
622
|
+
$src.puts "/* Reentrant variants (`_r` suffix, POSIX convention): same as the */"
|
|
623
|
+
$src.puts "/* corresponding non-`_r` variant but the callback takes a trailing */"
|
|
624
|
+
$src.puts "/* `void *userdata` argument and the outer function takes a trailing */"
|
|
625
|
+
$src.puts "/* `void *userdata` parameter forwarded to every per-cell invocation. */"
|
|
626
|
+
$src.puts "/* -------------------------------------------------------------------- */"
|
|
627
|
+
$src.puts ""
|
|
628
|
+
|
|
629
|
+
RAW_ARITIES.each do |n|
|
|
630
|
+
emit_raw_r(n)
|
|
631
|
+
decl_raw_r(n)
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
TYPED_PAIRS.each do |m, n|
|
|
635
|
+
emit_typed_r(m, n)
|
|
636
|
+
decl_typed_r(m, n)
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
$src.puts "/* -------------------------------------------------------------------- */"
|
|
640
|
+
$src.puts "/* Slab variants: the chunked counterpart of ca_call_cfunc_N. The */"
|
|
641
|
+
$src.puts "/* callback is handed a whole chunk (base / stride / count / mask */"
|
|
642
|
+
$src.puts "/* slice) rather than one cell, and non-alias INPUTs are gathered */"
|
|
643
|
+
$src.puts "/* into a ~32KB arena scratch per chunk instead of materialised */"
|
|
644
|
+
$src.puts "/* whole, so input memory peak stops scaling with the operand. */"
|
|
645
|
+
$src.puts "/* -------------------------------------------------------------------- */"
|
|
646
|
+
$src.puts ""
|
|
647
|
+
|
|
648
|
+
SLAB_ARITIES.each do |n|
|
|
649
|
+
emit_slab(n)
|
|
650
|
+
decl_slab(n)
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
SLAB_ARITIES.each do |n|
|
|
654
|
+
emit_slab_r(n)
|
|
655
|
+
decl_slab_r(n)
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
TYPED_PAIRS.each do |m, n|
|
|
659
|
+
emit_typed_slab(m, n)
|
|
660
|
+
decl_typed_slab(m, n)
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
TYPED_PAIRS.each do |m, n|
|
|
664
|
+
emit_typed_slab_r(m, n)
|
|
665
|
+
decl_typed_slab_r(m, n)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
$hdr.puts "#endif /* CARRAY_CALL_CFUNC_H */"
|
|
669
|
+
|
|
670
|
+
$src.close
|
|
671
|
+
$hdr.close
|