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_face.c
ADDED
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
Face mechanism — shared helpers, abstract CAFace base class, and
|
|
4
|
+
registration tables for state homogeneity / portability.
|
|
5
|
+
|
|
6
|
+
A Face is storage-identical to its parent (same data_type, same
|
|
7
|
+
layout) and performs no value transformation. Storage ops therefore
|
|
8
|
+
thin-forward:
|
|
9
|
+
attach parent attach + alias parent->ptr
|
|
10
|
+
sync parent sync (alias path auto-propagates)
|
|
11
|
+
detach release alias + parent detach
|
|
12
|
+
xfer_* / delegate to parent
|
|
13
|
+
fill_data
|
|
14
|
+
Concrete Faces (CATime / CATimedelta / CARecord / ...) may
|
|
15
|
+
override individually; the default is pure thin-forward.
|
|
16
|
+
|
|
17
|
+
Also housed here:
|
|
18
|
+
rb_ca_face_template struct duplication that carries subclass tail
|
|
19
|
+
ca_face_lift re-wrap a view as a Face when the source was
|
|
20
|
+
ca_strip_face walk down through Face parents to storage
|
|
21
|
+
CAFace abstract class organisational relay in the class hierarchy
|
|
22
|
+
storage_to_scalar / per-obj_type dispatch for element decode (read)
|
|
23
|
+
scalar_to_storage and encode (write) between surface and storage
|
|
24
|
+
state-compatible / homogeneity + portability registries used by
|
|
25
|
+
state-portable promote_list / CAStack / MV producer
|
|
26
|
+
|
|
27
|
+
---------------------------------------------------------------------------- */
|
|
28
|
+
|
|
29
|
+
#include "ruby.h"
|
|
30
|
+
#include "carray.h"
|
|
31
|
+
#include "ca_obj_face.h"
|
|
32
|
+
|
|
33
|
+
/* ---- shared op helpers (thin-forward) ---- */
|
|
34
|
+
|
|
35
|
+
void
|
|
36
|
+
ca_face_attach (void *ap)
|
|
37
|
+
{
|
|
38
|
+
CAView *cav = (CAView *) ap;
|
|
39
|
+
CArray *ca = (CArray *) ap;
|
|
40
|
+
ca_attach(cav->parent);
|
|
41
|
+
/* alias parent->ptr (Face has identical data layout, so copy is unneeded) */
|
|
42
|
+
ca->ptr = cav->parent->ptr;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void
|
|
46
|
+
ca_face_sync (void *ap)
|
|
47
|
+
{
|
|
48
|
+
CAView *cav = (CAView *) ap;
|
|
49
|
+
/* alias means no copy-back is needed; parent sync propagates */
|
|
50
|
+
ca_sync(cav->parent);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
void
|
|
54
|
+
ca_face_detach (void *ap)
|
|
55
|
+
{
|
|
56
|
+
CAView *cav = (CAView *) ap;
|
|
57
|
+
CArray *ca = (CArray *) ap;
|
|
58
|
+
ca->ptr = NULL; /* release alias (do not xfree — parent owns) */
|
|
59
|
+
ca_detach(cav->parent);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void
|
|
63
|
+
ca_face_fill_data (void *ap, void *ptr)
|
|
64
|
+
{
|
|
65
|
+
CAView *cav = (CAView *) ap;
|
|
66
|
+
ca_fill(cav->parent, ptr);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void
|
|
70
|
+
ca_face_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
71
|
+
{
|
|
72
|
+
CAView *cav = (CAView *) ap;
|
|
73
|
+
ca_xfer_index(cav->parent, idx, data, dir);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void
|
|
77
|
+
ca_face_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
78
|
+
void *data, int dir)
|
|
79
|
+
{
|
|
80
|
+
CAView *cav = (CAView *) ap;
|
|
81
|
+
ca_xfer_addrs(cav->parent, n, addrs, data, dir);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
void
|
|
85
|
+
ca_face_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
86
|
+
ca_size_t *strides, void *data, int dir)
|
|
87
|
+
{
|
|
88
|
+
CAView *cav = (CAView *) ap;
|
|
89
|
+
ca_xfer_stride(cav->parent, starts, counts, strides, data, dir);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void
|
|
93
|
+
ca_face_xfer_all (void *ap, void *data, int dir)
|
|
94
|
+
{
|
|
95
|
+
CAView *cav = (CAView *) ap;
|
|
96
|
+
ca_xfer_all(cav->parent, data, dir);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* rb_ca_face_template(original_face, new_parent, new_dim) — duplicate
|
|
100
|
+
* the CArray struct of original_face (including its subclass tail) and
|
|
101
|
+
* return a new Face VALUE bound to new_parent with its own shape.
|
|
102
|
+
*
|
|
103
|
+
* Called from ca_face_lift and from subclass lift / clone / dup paths. */
|
|
104
|
+
VALUE
|
|
105
|
+
rb_ca_face_template (VALUE original_face, CArray *new_parent,
|
|
106
|
+
ca_size_t *new_dim)
|
|
107
|
+
{
|
|
108
|
+
CArray *src;
|
|
109
|
+
CArray *dst;
|
|
110
|
+
CAView *vdst;
|
|
111
|
+
size_t size;
|
|
112
|
+
const rb_data_type_t *tdata;
|
|
113
|
+
|
|
114
|
+
TypedData_Get_Struct(original_face, CArray, &carray_data_type, src);
|
|
115
|
+
tdata = ca_typeddata[src->obj_type];
|
|
116
|
+
|
|
117
|
+
/* Actual subclass size (incl. tail) — via TypedData's dsize callback */
|
|
118
|
+
size = (tdata && tdata->function.dsize)
|
|
119
|
+
? tdata->function.dsize(src)
|
|
120
|
+
: sizeof(CAView);
|
|
121
|
+
|
|
122
|
+
dst = (CArray *) xmalloc(size);
|
|
123
|
+
/* CAREFUL: the whole-struct memcpy is how a C-tail Face
|
|
124
|
+
(CATime.unit, CARecord.data_class, ...) carries its subclass
|
|
125
|
+
state without per-subclass knowledge. It necessarily also copies
|
|
126
|
+
the CAView instance-state prefix — shape, attach state, and
|
|
127
|
+
framework-owned storage pointers — which must be reset below
|
|
128
|
+
before the new struct is exposed to GC. */
|
|
129
|
+
memcpy(dst, src, size);
|
|
130
|
+
|
|
131
|
+
/* CAREFUL: reset every field that was copied above but must not be
|
|
132
|
+
inherited from src. The framework-owned _pool / dim in
|
|
133
|
+
particular must be allocated fresh — reusing src's pool buffer
|
|
134
|
+
would alias it and double-free at GC. Pool-migrated obj_types
|
|
135
|
+
route through ca_array_pool_alloc; legacy ones fall back to
|
|
136
|
+
ALLOC_N. Any raw struct copy of a CArray-family object owes
|
|
137
|
+
this reset. */
|
|
138
|
+
vdst = (CAView *) dst;
|
|
139
|
+
vdst->parent = new_parent;
|
|
140
|
+
vdst->attach = 0;
|
|
141
|
+
vdst->nosync = 0;
|
|
142
|
+
dst->ptr = NULL;
|
|
143
|
+
dst->mask = NULL;
|
|
144
|
+
dst->elements = new_parent->elements;
|
|
145
|
+
dst->_pool = NULL;
|
|
146
|
+
if ( ca_func[src->obj_type].pool_init ) {
|
|
147
|
+
ca_array_pool_alloc(dst, src->obj_type, new_parent->ndim); /* ndim + _pool + dim */
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
dst->ndim = new_parent->ndim;
|
|
151
|
+
dst->dim = ALLOC_N(ca_size_t, new_parent->ndim);
|
|
152
|
+
}
|
|
153
|
+
memcpy(dst->dim,
|
|
154
|
+
new_dim ? new_dim : new_parent->dim,
|
|
155
|
+
sizeof(ca_size_t) * new_parent->ndim);
|
|
156
|
+
|
|
157
|
+
return TypedData_Wrap_Struct(CLASS_OF(original_face),
|
|
158
|
+
(rb_data_type_t *) tdata,
|
|
159
|
+
dst);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ca_face_lift(view, face_parent) — at the tail of user-facing entry
|
|
163
|
+
* points (`ca[...]` etc.), when the operand was a Face, re-wrap the
|
|
164
|
+
* resulting view as a Face of the same subclass. Thin wrapper over
|
|
165
|
+
* rb_ca_face_template.
|
|
166
|
+
*
|
|
167
|
+
* Caller (rb_ca_aref / rb_ca_store) must have already checked that
|
|
168
|
+
* face_parent carries the CA_FLAG_IS_FACE flag. */
|
|
169
|
+
VALUE
|
|
170
|
+
ca_face_lift (VALUE view, VALUE face_parent)
|
|
171
|
+
{
|
|
172
|
+
CArray *view_ca;
|
|
173
|
+
VALUE lifted;
|
|
174
|
+
static ID id_copy_state = 0;
|
|
175
|
+
if ( id_copy_state == 0 ) id_copy_state = rb_intern("copy_state");
|
|
176
|
+
|
|
177
|
+
TypedData_Get_Struct(view, CArray, &carray_data_type, view_ca);
|
|
178
|
+
|
|
179
|
+
/* Idempotent lift: if the view is already a Face of the same class as
|
|
180
|
+
face_parent, it has already been lifted — a builder that lifts internally
|
|
181
|
+
(e.g. rb_ca_refer_new → rb_ca_refer) whose caller lifts the result again.
|
|
182
|
+
Re-wrapping would stack an adjacent same-class double Face; return the
|
|
183
|
+
already-lifted view unchanged. Same *class* (not just obj_type) so two
|
|
184
|
+
distinct CAObject-based Faces, which share obj_type CA_OBJ_OBJECT, are not
|
|
185
|
+
conflated — that is a legitimate stack and must proceed to a real lift. */
|
|
186
|
+
if ( ca_is_face(view_ca)
|
|
187
|
+
&& rb_obj_class(view) == rb_obj_class(face_parent) ) {
|
|
188
|
+
return view;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* CAREFUL: rewrite view's data_type to the storage data_type before
|
|
192
|
+
lifting. view-creation inherits the Face's surface data_type
|
|
193
|
+
(often CA_FIXLEN), but the invariant is that Face.parent.data_type
|
|
194
|
+
is always the storage type — so view (the new Face's parent-to-be)
|
|
195
|
+
must carry the storage type, and only the new Face wrapper
|
|
196
|
+
presents the surface. */
|
|
197
|
+
{
|
|
198
|
+
CArray *fp, *p;
|
|
199
|
+
TypedData_Get_Struct(face_parent, CArray, &carray_data_type, fp);
|
|
200
|
+
p = fp;
|
|
201
|
+
while (p && ca_is_face(p)) {
|
|
202
|
+
p = ((CAView *) p)->parent;
|
|
203
|
+
}
|
|
204
|
+
if (p && p->data_type != view_ca->data_type) {
|
|
205
|
+
view_ca->data_type = p->data_type;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* §8.3 one-level local swap: put the view where the Face used to sit, so
|
|
209
|
+
the lifted chain carries exactly ONE Face (the new wrapper) rather than
|
|
210
|
+
a redundant intermediate Face. A fetch-path builder builds its view on
|
|
211
|
+
the un-stripped Face operand, leaving view->parent == the Face; move it
|
|
212
|
+
down ONE level to fp->parent. Never a full strip_face walk: an inner
|
|
213
|
+
distinct Face the user stacked underneath (docs/topics/CAFace.md §8.3) must be
|
|
214
|
+
preserved, and fp->parent points at it. Guard on pointer-equality so
|
|
215
|
+
only a view built directly on this Face fires (order.c builds on
|
|
216
|
+
stripped storage → no-op). CAStack (multi-parent) is excluded here and
|
|
217
|
+
handled by builder-side pre-strip. data_type above stays a full strip
|
|
218
|
+
(surface concern, §8 #7) — the parent pointer is the structural concern
|
|
219
|
+
(§8.3); the two axes are deliberately separate. */
|
|
220
|
+
if ( ((CAView *) view_ca)->parent == fp
|
|
221
|
+
&& ! ca_test_flag(view_ca, CA_FLAG_MULTI_PARENTS) ) {
|
|
222
|
+
((CAView *) view_ca)->parent = ((CAView *) fp)->parent; /* C pointer: one level */
|
|
223
|
+
rb_ca_set_parent(view, rb_ca_parent(face_parent)); /* @parent ivar: lockstep */
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* Pass view_ca->dim explicitly: passing new_dim=NULL would adopt
|
|
228
|
+
new_parent->dim, but new_parent here is the (typically) narrower
|
|
229
|
+
view. */
|
|
230
|
+
lifted = rb_ca_face_template(face_parent, view_ca, view_ca->dim);
|
|
231
|
+
/* Pin view as a GC root of lifted so the slice is not collected. */
|
|
232
|
+
rb_ca_set_parent(lifted, view);
|
|
233
|
+
|
|
234
|
+
/* Optional Ruby callback for ivar / state carry. Faces holding
|
|
235
|
+
semantic state in the struct tail (CATime / CATimedelta
|
|
236
|
+
etc.) auto-carry via the template memcpy; Faces holding state in
|
|
237
|
+
Ruby ivars (Ruby-implemented CAObject-derived Faces etc.) should
|
|
238
|
+
override copy_state to copy them. */
|
|
239
|
+
if ( rb_respond_to(face_parent, id_copy_state) ) {
|
|
240
|
+
rb_funcall(lifted, id_copy_state, 1, face_parent);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#ifdef CARRAY_DEV_BUILD
|
|
244
|
+
/* Soundness tripwire (docs/internal/FaceLiftSoundness.md §0/§7): after a lift the view
|
|
245
|
+
node under the new Face must not point back at the Face we lifted from —
|
|
246
|
+
the §8.3 one-level swap must have moved it exactly one level, so a
|
|
247
|
+
redundant middle Face is structurally caught here, wherever it enters.
|
|
248
|
+
Skip only when the lifted node is not a view (the ordering kernels lift a
|
|
249
|
+
fresh entity result — no swap applies). Multi-parent CAStack is covered:
|
|
250
|
+
its parents are pre-stripped in the builder (ca_stack_setup_with_axis), so
|
|
251
|
+
->parent (slot 0) is storage; this checks that slot. */
|
|
252
|
+
{
|
|
253
|
+
CArray *lifted_ca, *lp, *fps;
|
|
254
|
+
TypedData_Get_Struct(lifted, CArray, &carray_data_type, lifted_ca);
|
|
255
|
+
lp = CAVIEW(lifted_ca)->parent;
|
|
256
|
+
TypedData_Get_Struct(face_parent, CArray, &carray_data_type, fps);
|
|
257
|
+
if ( lp && ca_is_view(lp) ) {
|
|
258
|
+
if ( CAVIEW(lp)->parent == fps ) {
|
|
259
|
+
rb_bug("ca_face_lift: §8.3 one-level swap did not fire — redundant "
|
|
260
|
+
"middle Face (view->parent still points at the lifted Face)");
|
|
261
|
+
}
|
|
262
|
+
if ( ca_is_face(lp) && lp->obj_type == fps->obj_type ) {
|
|
263
|
+
rb_bug("ca_face_lift: adjacent same-class double Face under the lifted "
|
|
264
|
+
"wrapper (CAFace.md §8 #2/#3)");
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
#endif
|
|
269
|
+
|
|
270
|
+
return lifted;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* ca_strip_face(src) — walk down through Face parents to the storage
|
|
274
|
+
* CArray. Called at kernel_iterator entry and lazy chain endpoints
|
|
275
|
+
* where downstream code needs to observe the storage layout, not the
|
|
276
|
+
* Face surface. */
|
|
277
|
+
CArray *
|
|
278
|
+
ca_strip_face (CArray *src)
|
|
279
|
+
{
|
|
280
|
+
while (src && ca_is_face(src)) {
|
|
281
|
+
src = ((CAView *) src)->parent;
|
|
282
|
+
}
|
|
283
|
+
return src;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* rb_ca_strip_face_value(v) — VALUE-level counterpart to ca_strip_face.
|
|
287
|
+
* Walks down the Face `parent` ivar chain and returns the root storage
|
|
288
|
+
* VALUE (a non-Face CArray). Non-Face input is returned as-is.
|
|
289
|
+
*
|
|
290
|
+
* Used by ordering / search kernel dispatchers where the switch on
|
|
291
|
+
* data_type must see storage type instead of Face surface (CA_FIXLEN),
|
|
292
|
+
* and where subsequent `rb_ca_template*` calls must not re-lift the
|
|
293
|
+
* result into a Face wrapper (index / addr / linear outputs are not
|
|
294
|
+
* Face-semantic). Complements ca_strip_face on the C-struct axis. */
|
|
295
|
+
VALUE
|
|
296
|
+
rb_ca_strip_face_value (VALUE v)
|
|
297
|
+
{
|
|
298
|
+
CArray *ca;
|
|
299
|
+
if ( ! rb_obj_is_kind_of(v, rb_cCArray) ) return v;
|
|
300
|
+
TypedData_Get_Struct(v, CArray, &carray_data_type, ca);
|
|
301
|
+
while ( ca_is_face(ca) ) {
|
|
302
|
+
v = rb_ca_parent(v);
|
|
303
|
+
TypedData_Get_Struct(v, CArray, &carray_data_type, ca);
|
|
304
|
+
}
|
|
305
|
+
return v;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* CAFace — abstract marker class used as the code-organisation relay
|
|
309
|
+
for the Face mechanism. The semantic gate is CA_FLAG_IS_FACE only,
|
|
310
|
+
read via ca_is_face(); the class hierarchy is organisation, not the
|
|
311
|
+
basis for the predicate. CAObject-derived Faces satisfy
|
|
312
|
+
ca_is_face()=true without inheriting CAFace at the Ruby level.
|
|
313
|
+
|
|
314
|
+
caface_data_type is a TypedData chain entry with no callbacks;
|
|
315
|
+
subclasses provide their own dmark / dfree / dsize.
|
|
316
|
+
|
|
317
|
+
rb_cCAFace's allocator is sealed off so the class cannot be
|
|
318
|
+
instantiated directly; it exists only as the inheritance target
|
|
319
|
+
for concrete Faces (CATime / CATimedelta / CARecord / ...). */
|
|
320
|
+
|
|
321
|
+
VALUE rb_cCAFace;
|
|
322
|
+
|
|
323
|
+
const rb_data_type_t caface_data_type = {
|
|
324
|
+
.wrap_struct_name = "CAFace",
|
|
325
|
+
.parent = &caview_data_type,
|
|
326
|
+
.function = {
|
|
327
|
+
.dmark = NULL, /* subclass overrides */
|
|
328
|
+
.dfree = NULL, /* subclass overrides */
|
|
329
|
+
.dsize = NULL, /* subclass overrides */
|
|
330
|
+
},
|
|
331
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
static VALUE
|
|
335
|
+
rb_ca_face_s_allocate_forbidden (VALUE klass)
|
|
336
|
+
{
|
|
337
|
+
rb_raise(rb_eTypeError,
|
|
338
|
+
"CAFace is abstract; instantiate a concrete Face subclass "
|
|
339
|
+
"(CATime / CATimedelta / ...)");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/* Face-local C dispatch table for storage_to_scalar (the read/decode
|
|
343
|
+
direction). Sized to CA_OBJ_TYPE_MAX so any registered obj_type can be
|
|
344
|
+
indexed directly; file-scope zero-init leaves unregistered slots NULL. */
|
|
345
|
+
ca_face_storage_to_scalar_fn ca_face_storage_to_scalar_table[CA_OBJ_TYPE_MAX];
|
|
346
|
+
|
|
347
|
+
void
|
|
348
|
+
ca_face_register_storage_to_scalar (int obj_type, ca_face_storage_to_scalar_fn fn)
|
|
349
|
+
{
|
|
350
|
+
if ( obj_type < 0 || obj_type >= CA_OBJ_TYPE_MAX ) {
|
|
351
|
+
rb_raise(rb_eArgError,
|
|
352
|
+
"ca_face_register_storage_to_scalar: obj_type %d out of range",
|
|
353
|
+
obj_type);
|
|
354
|
+
}
|
|
355
|
+
ca_face_storage_to_scalar_table[obj_type] = fn;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* Face-local C dispatch table for scalar_to_storage (the write/encode
|
|
359
|
+
direction), the mirror of the decode table above. Unregistered slots
|
|
360
|
+
stay NULL; a Face without a C fast path relies on the Ruby fallback in
|
|
361
|
+
ca_face_scalar_to_storage (carray_cast.c). */
|
|
362
|
+
ca_face_scalar_to_storage_fn ca_face_scalar_to_storage_table[CA_OBJ_TYPE_MAX];
|
|
363
|
+
|
|
364
|
+
void
|
|
365
|
+
ca_face_register_scalar_to_storage (int obj_type, ca_face_scalar_to_storage_fn fn)
|
|
366
|
+
{
|
|
367
|
+
if ( obj_type < 0 || obj_type >= CA_OBJ_TYPE_MAX ) {
|
|
368
|
+
rb_raise(rb_eArgError,
|
|
369
|
+
"ca_face_register_scalar_to_storage: obj_type %d out of range",
|
|
370
|
+
obj_type);
|
|
371
|
+
}
|
|
372
|
+
ca_face_scalar_to_storage_table[obj_type] = fn;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/* -- Face state homogeneity check -- */
|
|
376
|
+
|
|
377
|
+
ca_face_state_compatible_fn ca_face_state_compatible_table[CA_OBJ_TYPE_MAX];
|
|
378
|
+
|
|
379
|
+
void
|
|
380
|
+
ca_face_register_state_compatible (int obj_type, ca_face_state_compatible_fn fn)
|
|
381
|
+
{
|
|
382
|
+
if ( obj_type < 0 || obj_type >= CA_OBJ_TYPE_MAX ) {
|
|
383
|
+
rb_raise(rb_eArgError,
|
|
384
|
+
"ca_face_register_state_compatible: obj_type %d out of range",
|
|
385
|
+
obj_type);
|
|
386
|
+
}
|
|
387
|
+
ca_face_state_compatible_table[obj_type] = fn;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* Detect whether `va`'s class overrides `face_state_compatible?` (= the
|
|
391
|
+
method is owned by a class other than rb_cCArray). Uses #method / #owner
|
|
392
|
+
reflection; called only on the cold path (no C hook registered). */
|
|
393
|
+
static int
|
|
394
|
+
ca_face_has_ruby_state_check (VALUE va)
|
|
395
|
+
{
|
|
396
|
+
static ID id_face_state_compatible_p = 0;
|
|
397
|
+
static ID id_method = 0;
|
|
398
|
+
static ID id_owner = 0;
|
|
399
|
+
VALUE m, owner;
|
|
400
|
+
if ( id_face_state_compatible_p == 0 ) {
|
|
401
|
+
id_face_state_compatible_p = rb_intern("face_state_compatible?");
|
|
402
|
+
id_method = rb_intern("method");
|
|
403
|
+
id_owner = rb_intern("owner");
|
|
404
|
+
}
|
|
405
|
+
m = rb_funcall(va, id_method, 1, ID2SYM(id_face_state_compatible_p));
|
|
406
|
+
owner = rb_funcall(m, id_owner, 0);
|
|
407
|
+
return ( owner != rb_cCArray ) ? 1 : 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
int
|
|
411
|
+
ca_face_state_compatible (VALUE va, CArray *a, VALUE vb, CArray *b)
|
|
412
|
+
{
|
|
413
|
+
ca_face_state_compatible_fn fn = ca_face_state_compatible_table[a->obj_type];
|
|
414
|
+
if ( fn != NULL ) {
|
|
415
|
+
return fn(a, b);
|
|
416
|
+
}
|
|
417
|
+
if ( ca_face_has_ruby_state_check(va) ) {
|
|
418
|
+
VALUE r = rb_funcall(va, rb_intern("face_state_compatible?"), 1, vb);
|
|
419
|
+
return RTEST(r) ? 1 : 0;
|
|
420
|
+
}
|
|
421
|
+
return 1;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/* Ruby-side: CArray#face_state_compatible?(other) */
|
|
425
|
+
static VALUE
|
|
426
|
+
rb_ca_face_state_compatible_p (VALUE self, VALUE other)
|
|
427
|
+
{
|
|
428
|
+
CArray *a, *b;
|
|
429
|
+
|
|
430
|
+
if ( ! rb_obj_is_kind_of(other, rb_cCArray) ) {
|
|
431
|
+
rb_raise(rb_eArgError,
|
|
432
|
+
"face_state_compatible?: argument must be a CArray");
|
|
433
|
+
}
|
|
434
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, a);
|
|
435
|
+
TypedData_Get_Struct(other, CArray, &carray_data_type, b);
|
|
436
|
+
if ( ! ca_is_face(a) || ! ca_is_face(b) ) {
|
|
437
|
+
rb_raise(rb_eArgError,
|
|
438
|
+
"face_state_compatible?: both receiver and argument must be Face");
|
|
439
|
+
}
|
|
440
|
+
if ( a->obj_type != b->obj_type ) {
|
|
441
|
+
rb_raise(rb_eArgError,
|
|
442
|
+
"face_state_compatible?: must be the same Face class");
|
|
443
|
+
}
|
|
444
|
+
return ca_face_state_compatible(self, a, other, b) ? Qtrue : Qfalse;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/* -- Face state portability -- */
|
|
448
|
+
|
|
449
|
+
/* int8_t per slot to distinguish "unregistered" (-1, dispatch falls
|
|
450
|
+
through to Ruby fallback) from "registered as not-portable"
|
|
451
|
+
(0, e.g. CAConstString) and "registered as portable" (1). */
|
|
452
|
+
int8_t ca_face_state_portable_table[CA_OBJ_TYPE_MAX];
|
|
453
|
+
|
|
454
|
+
/* Per-obj_type bound Ruby class method returning the registered value.
|
|
455
|
+
Defined once for each obj_type that registers a value, so user-facing
|
|
456
|
+
`<FaceClass>.face_state_portable?` reflects the C table without
|
|
457
|
+
needing a reverse-lookup at every call. */
|
|
458
|
+
static VALUE
|
|
459
|
+
rb_ca_s_face_state_portable_true (VALUE klass)
|
|
460
|
+
{
|
|
461
|
+
return Qtrue;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
static VALUE
|
|
465
|
+
rb_ca_s_face_state_portable_false (VALUE klass)
|
|
466
|
+
{
|
|
467
|
+
return Qfalse;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
void
|
|
471
|
+
ca_face_register_state_portable (int obj_type, int portable)
|
|
472
|
+
{
|
|
473
|
+
if ( obj_type < 0 || obj_type >= CA_OBJ_TYPE_MAX ) {
|
|
474
|
+
rb_raise(rb_eArgError,
|
|
475
|
+
"ca_face_register_state_portable: obj_type %d out of range",
|
|
476
|
+
obj_type);
|
|
477
|
+
}
|
|
478
|
+
ca_face_state_portable_table[obj_type] = portable ? 1 : 0;
|
|
479
|
+
/* Mirror to a singleton method on the class so Ruby-side
|
|
480
|
+
introspection (<FaceClass>.face_state_portable?) agrees with the
|
|
481
|
+
C table. CAREFUL: ca_class[obj_type] must be set by
|
|
482
|
+
ca_install_obj_type before this call — Faces register from
|
|
483
|
+
within their Init_*, which runs after ca_install_obj_type. */
|
|
484
|
+
if ( !NIL_P(ca_class[obj_type]) ) {
|
|
485
|
+
rb_define_singleton_method(ca_class[obj_type], "face_state_portable?",
|
|
486
|
+
portable ? rb_ca_s_face_state_portable_true
|
|
487
|
+
: rb_ca_s_face_state_portable_false,
|
|
488
|
+
0);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* Detect whether `klass`'s singleton class owns `face_state_portable?`
|
|
493
|
+
(= the predicate is defined on the Face class itself, not inherited
|
|
494
|
+
from rb_cCArray's metaclass). Cold path; only consulted when no C
|
|
495
|
+
entry is registered. */
|
|
496
|
+
static int
|
|
497
|
+
ca_face_class_has_portable_method (VALUE klass)
|
|
498
|
+
{
|
|
499
|
+
static ID id_face_state_portable_p = 0;
|
|
500
|
+
static ID id_method = 0;
|
|
501
|
+
static ID id_owner = 0;
|
|
502
|
+
VALUE m, owner;
|
|
503
|
+
if ( NIL_P(klass) ) return 0;
|
|
504
|
+
if ( id_face_state_portable_p == 0 ) {
|
|
505
|
+
id_face_state_portable_p = rb_intern("face_state_portable?");
|
|
506
|
+
id_method = rb_intern("method");
|
|
507
|
+
id_owner = rb_intern("owner");
|
|
508
|
+
}
|
|
509
|
+
if ( !rb_respond_to(klass, id_face_state_portable_p) ) return 0;
|
|
510
|
+
m = rb_funcall(klass, id_method, 1, ID2SYM(id_face_state_portable_p));
|
|
511
|
+
owner = rb_funcall(m, id_owner, 0);
|
|
512
|
+
/* owner is a (singleton) class — if it isn't rb_singleton_class(rb_cCArray)
|
|
513
|
+
or the singleton chain rooted at CArray, the Face class (or its
|
|
514
|
+
ancestor) has its own definition. */
|
|
515
|
+
return ( owner != rb_singleton_class(rb_cCArray) ) ? 1 : 0;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
int
|
|
519
|
+
ca_face_state_portable (int obj_type, VALUE klass)
|
|
520
|
+
{
|
|
521
|
+
int8_t entry;
|
|
522
|
+
if ( obj_type < 0 || obj_type >= CA_OBJ_TYPE_MAX ) return 1;
|
|
523
|
+
entry = ca_face_state_portable_table[obj_type];
|
|
524
|
+
if ( entry >= 0 ) {
|
|
525
|
+
return entry ? 1 : 0;
|
|
526
|
+
}
|
|
527
|
+
if ( !NIL_P(klass) && ca_face_class_has_portable_method(klass) ) {
|
|
528
|
+
VALUE r = rb_funcall(klass, rb_intern("face_state_portable?"), 0);
|
|
529
|
+
return RTEST(r) ? 1 : 0;
|
|
530
|
+
}
|
|
531
|
+
return 1; /* default portable */
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* CArray.face_state_portable? — class method on CArray. Subclasses
|
|
535
|
+
(Face classes) override by defining their own `def self.face_state_portable?`.
|
|
536
|
+
This default returns true (= 1) for non-Face CArray classes; the actual
|
|
537
|
+
per-Face decision goes through ca_face_state_portable from C callers. */
|
|
538
|
+
static VALUE
|
|
539
|
+
rb_ca_s_face_state_portable_p (VALUE klass)
|
|
540
|
+
{
|
|
541
|
+
return Qtrue;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/* CArray#face_lift(face_parent) — Ruby surface for ca_face_lift.
|
|
545
|
+
Used by CArray.stack to re-wrap a raw CAStack with the homogeneous
|
|
546
|
+
Face class carried by face_parent (typically list[0] after the
|
|
547
|
+
promote_list pass). Delegates the data_type rewrite and optional
|
|
548
|
+
copy_state callback to ca_face_lift. */
|
|
549
|
+
static VALUE
|
|
550
|
+
rb_ca_face_lift_method (VALUE self, VALUE face_parent)
|
|
551
|
+
{
|
|
552
|
+
CArray *fp;
|
|
553
|
+
if ( ! rb_obj_is_kind_of(face_parent, rb_cCArray) ) {
|
|
554
|
+
rb_raise(rb_eArgError, "face_lift: face_parent must be a CArray");
|
|
555
|
+
}
|
|
556
|
+
TypedData_Get_Struct(face_parent, CArray, &carray_data_type, fp);
|
|
557
|
+
if ( ! ca_is_face(fp) ) {
|
|
558
|
+
rb_raise(rb_eArgError, "face_lift: face_parent must be a Face instance");
|
|
559
|
+
}
|
|
560
|
+
return ca_face_lift(self, face_parent);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/* ca_face_reconcile_comparison(pself, pother) — Face gate for the element-
|
|
564
|
+
* wise comparison operators (< <= > >=, eq, ne; <=> composes from > and <).
|
|
565
|
+
* Mirrors the search query gate (PROPOSAL_FACE_ORDERING_GATE): when the LHS
|
|
566
|
+
* is a Face over NUMERIC storage, memcmp on the surface fixlen bytes would
|
|
567
|
+
* mis-order the storage, so descend to storage (ORDERABLE licenses that the
|
|
568
|
+
* numeric order equals the surface order) and reconcile the RHS:
|
|
569
|
+
*
|
|
570
|
+
* - RHS is a Face: COMPARABLE self strips it; else it must respond to
|
|
571
|
+
* to_comparable (reconcile to self's reference, e.g. unit alignment,
|
|
572
|
+
* which may raise on loss); else raise.
|
|
573
|
+
* - RHS is plain (bare number / non-Face array / Scalar): a direct storage
|
|
574
|
+
* compare, which only a COMPARABLE self licenses -- a non-COMPARABLE
|
|
575
|
+
* Face (e.g. a unit-bearing CATime) rejects it.
|
|
576
|
+
*
|
|
577
|
+
* A Face over FIXLEN storage (CARecord / string faces) is left untouched:
|
|
578
|
+
* memcmp on its bytes is already the correct order/equality, same as a plain
|
|
579
|
+
* fixlen array. Both operands are rebound to storage via *pself / *pother.
|
|
580
|
+
* No-op when self is not a Face. */
|
|
581
|
+
void
|
|
582
|
+
ca_face_reconcile_comparison (volatile VALUE *pself, volatile VALUE *pother)
|
|
583
|
+
{
|
|
584
|
+
VALUE self = *pself, other = *pother;
|
|
585
|
+
CArray *sc, *storage;
|
|
586
|
+
|
|
587
|
+
if ( ! rb_obj_is_kind_of(self, rb_cCArray) ) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, sc);
|
|
591
|
+
if ( ! ca_is_face(sc) ) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
storage = ca_strip_face(sc);
|
|
596
|
+
if ( storage->data_type == CA_FIXLEN ) {
|
|
597
|
+
/* genuine fixlen semantics: memcmp is the correct comparison, leave
|
|
598
|
+
the Face(s) in place (same result as a plain fixlen array). */
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if ( ! ca_test_flag(sc, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
|
|
603
|
+
rb_raise(rb_eArgError,
|
|
604
|
+
"comparison: Face operand (%s) is not orderable by storage; "
|
|
605
|
+
"use ca.parent to descend to storage",
|
|
606
|
+
rb_obj_classname(self));
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
{
|
|
610
|
+
VALUE self_ref = self; /* reference before stripping (for to_comparable) */
|
|
611
|
+
int comparable = ca_test_flag(sc, CA_FLAG_FACE_COMPARABLE_STORAGE);
|
|
612
|
+
int other_is_face = 0;
|
|
613
|
+
|
|
614
|
+
if ( rb_obj_is_kind_of(other, rb_cCArray) ) {
|
|
615
|
+
CArray *oc;
|
|
616
|
+
TypedData_Get_Struct(other, CArray, &carray_data_type, oc);
|
|
617
|
+
other_is_face = ca_is_face(oc);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if ( comparable ) {
|
|
621
|
+
/* directly comparable Face reference: strip a Face operand, take a
|
|
622
|
+
plain operand as-is (storage compare is licensed). */
|
|
623
|
+
if ( other_is_face ) {
|
|
624
|
+
other = rb_ca_strip_face_value(other);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
else if ( rb_respond_to(self_ref, rb_intern("to_comparable")) ) {
|
|
628
|
+
/* non-COMPARABLE Face reference: the reference brings the operand into
|
|
629
|
+
its own space (unit alignment / instant lift), whatever the operand
|
|
630
|
+
type -- Face CArray, our Scalar, a Ruby Time / DateTime, etc. The
|
|
631
|
+
reference's to_comparable raises if it cannot reconcile it. */
|
|
632
|
+
other = rb_funcall(self_ref, rb_intern("to_comparable"), 1, other);
|
|
633
|
+
other = rb_ca_strip_face_value(other);
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
rb_raise(rb_eArgError,
|
|
637
|
+
"comparison: non-comparable Face reference (%s) has no "
|
|
638
|
+
"to_comparable to reconcile the operand; use ca.parent to "
|
|
639
|
+
"compare the hidden storage explicitly",
|
|
640
|
+
rb_obj_classname(self_ref));
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
*pself = rb_ca_strip_face_value(self);
|
|
644
|
+
*pother = other;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
void
|
|
649
|
+
Init_ca_face (void)
|
|
650
|
+
{
|
|
651
|
+
int i;
|
|
652
|
+
|
|
653
|
+
/* CAREFUL: rb_cCAView must already exist (defined in ruby_carray.c
|
|
654
|
+
ahead of this Init) — CAFace inherits from it. */
|
|
655
|
+
rb_cCAFace = rb_define_class("CAFace", rb_cCAView);
|
|
656
|
+
rb_define_alloc_func(rb_cCAFace, rb_ca_face_s_allocate_forbidden);
|
|
657
|
+
|
|
658
|
+
/* Initialise the portable table to -1 for every slot so dispatch
|
|
659
|
+
can distinguish "explicitly registered 0" (CAConstString) from
|
|
660
|
+
"never registered" (falls through to the Ruby default). */
|
|
661
|
+
for ( i = 0; i < CA_OBJ_TYPE_MAX; i++ ) {
|
|
662
|
+
ca_face_state_portable_table[i] = -1;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
rb_define_method(rb_cCArray, "face_state_compatible?",
|
|
666
|
+
rb_ca_face_state_compatible_p, 1);
|
|
667
|
+
rb_define_singleton_method(rb_cCArray, "face_state_portable?",
|
|
668
|
+
rb_ca_s_face_state_portable_p, 0);
|
|
669
|
+
rb_define_method(rb_cCArray, "face_lift", rb_ca_face_lift_method, 1);
|
|
670
|
+
}
|