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/carray_struct.c
ADDED
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
C-native member access for CAStruct subclasses. The hooked
|
|
4
|
+
methods (`[]`, `[]=`, `initialize`) are installed on a subclass by
|
|
5
|
+
`CArray.__install_castruct_methods__(klass)` — called from the
|
|
6
|
+
bottom of lib/carray/struct.rb once CAStruct is defined, so this
|
|
7
|
+
ext can load before that file.
|
|
8
|
+
|
|
9
|
+
Sibling of lib/carray/struct.rb (Ruby-side CAStruct::Builder that
|
|
10
|
+
populates the FAST_PRIMITIVES / DISPATCH_TABLE constants read
|
|
11
|
+
from here).
|
|
12
|
+
|
|
13
|
+
Dispatch order for both `[]` and `[]=`:
|
|
14
|
+
|
|
15
|
+
FAST_PRIMITIVES hit -> direct memcpy against @data.ptr + offset
|
|
16
|
+
(primitive / bitfield / endian-swap)
|
|
17
|
+
DISPATCH_TABLE hit -> Proc invoked via rb_funcall("call")
|
|
18
|
+
(nested struct / CArray template / fixlen)
|
|
19
|
+
miss -> send(name) / send(name=)
|
|
20
|
+
|
|
21
|
+
---------------------------------------------------------------------------- */
|
|
22
|
+
|
|
23
|
+
#include "carray.h"
|
|
24
|
+
#include <string.h>
|
|
25
|
+
|
|
26
|
+
/* ---------------------------------------------------------------------
|
|
27
|
+
FAST_PRIMITIVES entry kind tags.
|
|
28
|
+
*
|
|
29
|
+
* CAREFUL: these constants are kept in sync with the Ruby-side
|
|
30
|
+
* CAStruct::Builder::FAST_KIND_* — an off-by-one drift silently
|
|
31
|
+
* mis-dispatches every access.
|
|
32
|
+
--------------------------------------------------------------------- */
|
|
33
|
+
|
|
34
|
+
#define FAST_KIND_PRIMITIVE 0
|
|
35
|
+
#define FAST_KIND_BITFIELD 1
|
|
36
|
+
#define FAST_KIND_ENDIAN 2
|
|
37
|
+
|
|
38
|
+
/* 16/32/64-bit byte swap via compiler builtins. Clang and GCC both
|
|
39
|
+
expose __builtin_bswap*, and the project's CFLAGS already require
|
|
40
|
+
a recent toolchain. */
|
|
41
|
+
#define CA_BSWAP16(x) ((uint16_t) __builtin_bswap16((uint16_t)(x)))
|
|
42
|
+
#define CA_BSWAP32(x) ((uint32_t) __builtin_bswap32((uint32_t)(x)))
|
|
43
|
+
#define CA_BSWAP64(x) ((uint64_t) __builtin_bswap64((uint64_t)(x)))
|
|
44
|
+
|
|
45
|
+
/* ---------------------------------------------------------------------
|
|
46
|
+
Type-coded primitive read / write. Type codes are the same
|
|
47
|
+
CA_INT8 / CA_UINT8 / ... constants used everywhere else in carray.
|
|
48
|
+
--------------------------------------------------------------------- */
|
|
49
|
+
|
|
50
|
+
static VALUE
|
|
51
|
+
ca_struct_read_primitive_fast (const char *p, int type_code)
|
|
52
|
+
{
|
|
53
|
+
switch (type_code) {
|
|
54
|
+
case CA_BOOLEAN: {
|
|
55
|
+
int8_t v;
|
|
56
|
+
memcpy(&v, p, 1);
|
|
57
|
+
return v ? INT2FIX(1) : INT2FIX(0);
|
|
58
|
+
}
|
|
59
|
+
case CA_INT8: {
|
|
60
|
+
int8_t v;
|
|
61
|
+
memcpy(&v, p, 1);
|
|
62
|
+
return INT2FIX(v);
|
|
63
|
+
}
|
|
64
|
+
case CA_UINT8: {
|
|
65
|
+
uint8_t v;
|
|
66
|
+
memcpy(&v, p, 1);
|
|
67
|
+
return INT2FIX(v);
|
|
68
|
+
}
|
|
69
|
+
case CA_INT16: {
|
|
70
|
+
int16_t v;
|
|
71
|
+
memcpy(&v, p, 2);
|
|
72
|
+
return INT2FIX(v);
|
|
73
|
+
}
|
|
74
|
+
case CA_UINT16: {
|
|
75
|
+
uint16_t v;
|
|
76
|
+
memcpy(&v, p, 2);
|
|
77
|
+
return INT2FIX(v);
|
|
78
|
+
}
|
|
79
|
+
case CA_INT32: {
|
|
80
|
+
int32_t v;
|
|
81
|
+
memcpy(&v, p, 4);
|
|
82
|
+
return LONG2NUM(v);
|
|
83
|
+
}
|
|
84
|
+
case CA_UINT32: {
|
|
85
|
+
uint32_t v;
|
|
86
|
+
memcpy(&v, p, 4);
|
|
87
|
+
return ULONG2NUM(v);
|
|
88
|
+
}
|
|
89
|
+
case CA_INT64: {
|
|
90
|
+
int64_t v;
|
|
91
|
+
memcpy(&v, p, 8);
|
|
92
|
+
return LL2NUM(v);
|
|
93
|
+
}
|
|
94
|
+
case CA_UINT64: {
|
|
95
|
+
uint64_t v;
|
|
96
|
+
memcpy(&v, p, 8);
|
|
97
|
+
return ULL2NUM(v);
|
|
98
|
+
}
|
|
99
|
+
case CA_FLOAT32: {
|
|
100
|
+
float v;
|
|
101
|
+
memcpy(&v, p, 4);
|
|
102
|
+
return DBL2NUM((double) v);
|
|
103
|
+
}
|
|
104
|
+
case CA_FLOAT64: {
|
|
105
|
+
double v;
|
|
106
|
+
memcpy(&v, p, 8);
|
|
107
|
+
return DBL2NUM(v);
|
|
108
|
+
}
|
|
109
|
+
default:
|
|
110
|
+
return Qundef; /* should not happen; FAST_PRIMITIVES filters */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static void
|
|
115
|
+
ca_struct_write_primitive_fast (char *p, int type_code, VALUE val)
|
|
116
|
+
{
|
|
117
|
+
switch (type_code) {
|
|
118
|
+
case CA_BOOLEAN: {
|
|
119
|
+
int8_t v = RTEST(val) && val != INT2FIX(0) ? 1 : 0;
|
|
120
|
+
memcpy(p, &v, 1);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
case CA_INT8: {
|
|
124
|
+
int8_t v = (int8_t) NUM2INT(val);
|
|
125
|
+
memcpy(p, &v, 1);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
case CA_UINT8: {
|
|
129
|
+
uint8_t v = (uint8_t) NUM2UINT(val);
|
|
130
|
+
memcpy(p, &v, 1);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
case CA_INT16: {
|
|
134
|
+
int16_t v = (int16_t) NUM2INT(val);
|
|
135
|
+
memcpy(p, &v, 2);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
case CA_UINT16: {
|
|
139
|
+
uint16_t v = (uint16_t) NUM2UINT(val);
|
|
140
|
+
memcpy(p, &v, 2);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
case CA_INT32: {
|
|
144
|
+
int32_t v = (int32_t) NUM2LONG(val);
|
|
145
|
+
memcpy(p, &v, 4);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
case CA_UINT32: {
|
|
149
|
+
uint32_t v = (uint32_t) NUM2ULONG(val);
|
|
150
|
+
memcpy(p, &v, 4);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case CA_INT64: {
|
|
154
|
+
int64_t v = (int64_t) NUM2LL(val);
|
|
155
|
+
memcpy(p, &v, 8);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
case CA_UINT64: {
|
|
159
|
+
uint64_t v = (uint64_t) NUM2ULL(val);
|
|
160
|
+
memcpy(p, &v, 8);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
case CA_FLOAT32: {
|
|
164
|
+
float v = (float) NUM2DBL(val);
|
|
165
|
+
memcpy(p, &v, 4);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
case CA_FLOAT64: {
|
|
169
|
+
double v = NUM2DBL(val);
|
|
170
|
+
memcpy(p, &v, 8);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
rb_raise(rb_eRuntimeError,
|
|
175
|
+
"[BUG] ca_struct_write_primitive_fast: unsupported type %d",
|
|
176
|
+
type_code);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* ---------------------------------------------------------------------
|
|
181
|
+
Bit-field read / write. Mirrors CABitfield: load the spanning
|
|
182
|
+
power-of-2 word (1/2/4/8 bytes) at start_byte, shift right by
|
|
183
|
+
bit_in_word, mask off `bits` bits. Writes use load-modify-store
|
|
184
|
+
to keep neighbouring bits untouched.
|
|
185
|
+
--------------------------------------------------------------------- */
|
|
186
|
+
|
|
187
|
+
static VALUE
|
|
188
|
+
ca_struct_read_bitfield_fast (const char *p, int view_bytes,
|
|
189
|
+
int bit_in_word, int bits)
|
|
190
|
+
{
|
|
191
|
+
uint64_t word = 0;
|
|
192
|
+
switch (view_bytes) {
|
|
193
|
+
case 1: { uint8_t v; memcpy(&v, p, 1); word = v; break; }
|
|
194
|
+
case 2: { uint16_t v; memcpy(&v, p, 2); word = v; break; }
|
|
195
|
+
case 4: { uint32_t v; memcpy(&v, p, 4); word = v; break; }
|
|
196
|
+
case 8: { uint64_t v; memcpy(&v, p, 8); word = v; break; }
|
|
197
|
+
default:
|
|
198
|
+
rb_raise(rb_eRuntimeError,
|
|
199
|
+
"[BUG] bitfield view_bytes %d not in {1,2,4,8}", view_bytes);
|
|
200
|
+
}
|
|
201
|
+
uint64_t mask = (bits >= 64) ? ~(uint64_t)0
|
|
202
|
+
: ((uint64_t)1 << bits) - 1;
|
|
203
|
+
uint64_t val = (word >> bit_in_word) & mask;
|
|
204
|
+
/* Returned as an unsigned Integer; bit-fields don't carry a sign
|
|
205
|
+
bit in carray's CABitfield convention either. */
|
|
206
|
+
if (bits <= 31) return INT2FIX((long) val);
|
|
207
|
+
if (bits <= 32) return ULONG2NUM((unsigned long) val);
|
|
208
|
+
return ULL2NUM(val);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static void
|
|
212
|
+
ca_struct_write_bitfield_fast (char *p, int view_bytes,
|
|
213
|
+
int bit_in_word, int bits, VALUE val)
|
|
214
|
+
{
|
|
215
|
+
uint64_t v = NUM2ULL(val);
|
|
216
|
+
uint64_t mask = (bits >= 64) ? ~(uint64_t)0
|
|
217
|
+
: ((uint64_t)1 << bits) - 1;
|
|
218
|
+
v &= mask;
|
|
219
|
+
uint64_t shifted_mask = mask << bit_in_word;
|
|
220
|
+
uint64_t shifted_val = v << bit_in_word;
|
|
221
|
+
switch (view_bytes) {
|
|
222
|
+
case 1: {
|
|
223
|
+
uint8_t word;
|
|
224
|
+
memcpy(&word, p, 1);
|
|
225
|
+
word = (uint8_t)((word & ~(uint8_t)shifted_mask) | (uint8_t)shifted_val);
|
|
226
|
+
memcpy(p, &word, 1);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
case 2: {
|
|
230
|
+
uint16_t word;
|
|
231
|
+
memcpy(&word, p, 2);
|
|
232
|
+
word = (uint16_t)((word & ~(uint16_t)shifted_mask) | (uint16_t)shifted_val);
|
|
233
|
+
memcpy(p, &word, 2);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
case 4: {
|
|
237
|
+
uint32_t word;
|
|
238
|
+
memcpy(&word, p, 4);
|
|
239
|
+
word = (uint32_t)((word & ~(uint32_t)shifted_mask) | (uint32_t)shifted_val);
|
|
240
|
+
memcpy(p, &word, 4);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
case 8: {
|
|
244
|
+
uint64_t word;
|
|
245
|
+
memcpy(&word, p, 8);
|
|
246
|
+
word = (word & ~shifted_mask) | shifted_val;
|
|
247
|
+
memcpy(p, &word, 8);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
default:
|
|
251
|
+
rb_raise(rb_eRuntimeError,
|
|
252
|
+
"[BUG] bitfield view_bytes %d not in {1,2,4,8}", view_bytes);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* ---------------------------------------------------------------------
|
|
257
|
+
Endian-swapped primitive read / write. Only entries whose target
|
|
258
|
+
endian differs from the host land here -- the Ruby Builder folds
|
|
259
|
+
host-matching cases into the plain primitive fast path. No view
|
|
260
|
+
allocation; one __builtin_bswap per access.
|
|
261
|
+
--------------------------------------------------------------------- */
|
|
262
|
+
|
|
263
|
+
static VALUE
|
|
264
|
+
ca_struct_read_endian_swapped_fast (const char *p, int type_code)
|
|
265
|
+
{
|
|
266
|
+
switch (type_code) {
|
|
267
|
+
case CA_INT16: {
|
|
268
|
+
uint16_t v; memcpy(&v, p, 2); v = CA_BSWAP16(v);
|
|
269
|
+
return INT2FIX((int16_t) v);
|
|
270
|
+
}
|
|
271
|
+
case CA_UINT16: {
|
|
272
|
+
uint16_t v; memcpy(&v, p, 2); v = CA_BSWAP16(v);
|
|
273
|
+
return INT2FIX(v);
|
|
274
|
+
}
|
|
275
|
+
case CA_INT32: {
|
|
276
|
+
uint32_t v; memcpy(&v, p, 4); v = CA_BSWAP32(v);
|
|
277
|
+
return LONG2NUM((int32_t) v);
|
|
278
|
+
}
|
|
279
|
+
case CA_UINT32: {
|
|
280
|
+
uint32_t v; memcpy(&v, p, 4); v = CA_BSWAP32(v);
|
|
281
|
+
return ULONG2NUM(v);
|
|
282
|
+
}
|
|
283
|
+
case CA_INT64: {
|
|
284
|
+
uint64_t v; memcpy(&v, p, 8); v = CA_BSWAP64(v);
|
|
285
|
+
return LL2NUM((int64_t) v);
|
|
286
|
+
}
|
|
287
|
+
case CA_UINT64: {
|
|
288
|
+
uint64_t v; memcpy(&v, p, 8); v = CA_BSWAP64(v);
|
|
289
|
+
return ULL2NUM(v);
|
|
290
|
+
}
|
|
291
|
+
case CA_FLOAT32: {
|
|
292
|
+
uint32_t bits; memcpy(&bits, p, 4); bits = CA_BSWAP32(bits);
|
|
293
|
+
float v; memcpy(&v, &bits, 4);
|
|
294
|
+
return DBL2NUM((double) v);
|
|
295
|
+
}
|
|
296
|
+
case CA_FLOAT64: {
|
|
297
|
+
uint64_t bits; memcpy(&bits, p, 8); bits = CA_BSWAP64(bits);
|
|
298
|
+
double v; memcpy(&v, &bits, 8);
|
|
299
|
+
return DBL2NUM(v);
|
|
300
|
+
}
|
|
301
|
+
default:
|
|
302
|
+
rb_raise(rb_eRuntimeError,
|
|
303
|
+
"[BUG] endian-swapped type %d unsupported in fast path",
|
|
304
|
+
type_code);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
static void
|
|
309
|
+
ca_struct_write_endian_swapped_fast (char *p, int type_code, VALUE val)
|
|
310
|
+
{
|
|
311
|
+
switch (type_code) {
|
|
312
|
+
case CA_INT16: {
|
|
313
|
+
uint16_t v = (uint16_t) NUM2INT(val);
|
|
314
|
+
v = CA_BSWAP16(v); memcpy(p, &v, 2);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
case CA_UINT16: {
|
|
318
|
+
uint16_t v = (uint16_t) NUM2UINT(val);
|
|
319
|
+
v = CA_BSWAP16(v); memcpy(p, &v, 2);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
case CA_INT32: {
|
|
323
|
+
uint32_t v = (uint32_t) NUM2LONG(val);
|
|
324
|
+
v = CA_BSWAP32(v); memcpy(p, &v, 4);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
case CA_UINT32: {
|
|
328
|
+
uint32_t v = (uint32_t) NUM2ULONG(val);
|
|
329
|
+
v = CA_BSWAP32(v); memcpy(p, &v, 4);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
case CA_INT64: {
|
|
333
|
+
uint64_t v = (uint64_t) NUM2LL(val);
|
|
334
|
+
v = CA_BSWAP64(v); memcpy(p, &v, 8);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
case CA_UINT64: {
|
|
338
|
+
uint64_t v = NUM2ULL(val);
|
|
339
|
+
v = CA_BSWAP64(v); memcpy(p, &v, 8);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
case CA_FLOAT32: {
|
|
343
|
+
float vf = (float) NUM2DBL(val);
|
|
344
|
+
uint32_t bits; memcpy(&bits, &vf, 4);
|
|
345
|
+
bits = CA_BSWAP32(bits); memcpy(p, &bits, 4);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
case CA_FLOAT64: {
|
|
349
|
+
double vd = NUM2DBL(val);
|
|
350
|
+
uint64_t bits; memcpy(&bits, &vd, 8);
|
|
351
|
+
bits = CA_BSWAP64(bits); memcpy(p, &bits, 8);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
default:
|
|
355
|
+
rb_raise(rb_eRuntimeError,
|
|
356
|
+
"[BUG] endian-swapped type %d unsupported in fast path",
|
|
357
|
+
type_code);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ---------------------------------------------------------------------
|
|
362
|
+
Resolve a member name to a Ruby String key matching MEMBER_TABLE /
|
|
363
|
+
DISPATCH_TABLE / FAST_PRIMITIVES. Integer indices route through
|
|
364
|
+
MEMBERS, mirroring the Ruby implementation. Returns Qnil if the
|
|
365
|
+
integer is out of range (handled at the call site).
|
|
366
|
+
--------------------------------------------------------------------- */
|
|
367
|
+
|
|
368
|
+
static VALUE
|
|
369
|
+
ca_struct_resolve_name (VALUE klass, VALUE name)
|
|
370
|
+
{
|
|
371
|
+
if (RB_TYPE_P(name, T_FIXNUM)) {
|
|
372
|
+
VALUE members = rb_const_get(klass, rb_intern("MEMBERS"));
|
|
373
|
+
name = rb_ary_entry(members, FIX2LONG(name));
|
|
374
|
+
if (NIL_P(name)) return Qnil;
|
|
375
|
+
}
|
|
376
|
+
if (RB_TYPE_P(name, T_STRING)) {
|
|
377
|
+
return name;
|
|
378
|
+
}
|
|
379
|
+
if (RB_TYPE_P(name, T_SYMBOL)) {
|
|
380
|
+
/* rb_sym2str returns the symbol's underlying (frozen, interned)
|
|
381
|
+
String — no allocation, unlike `name.to_s` which copies. */
|
|
382
|
+
return rb_sym2str(name);
|
|
383
|
+
}
|
|
384
|
+
return rb_funcall(name, rb_intern("to_s"), 0);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* ---------------------------------------------------------------------
|
|
388
|
+
Shared write-dispatch helper reused by `[]=` and `initialize`.
|
|
389
|
+
Returns 1 if the member was written, 0 if neither table contained
|
|
390
|
+
the name (caller decides whether to send / raise).
|
|
391
|
+
--------------------------------------------------------------------- */
|
|
392
|
+
|
|
393
|
+
static int
|
|
394
|
+
ca_struct_dispatch_write (VALUE klass, VALUE name_s, VALUE val, VALUE data_val)
|
|
395
|
+
{
|
|
396
|
+
if (rb_const_defined(klass, rb_intern("FAST_PRIMITIVES"))) {
|
|
397
|
+
VALUE fast_table = rb_const_get(klass, rb_intern("FAST_PRIMITIVES"));
|
|
398
|
+
VALUE entry = rb_hash_aref(fast_table, name_s);
|
|
399
|
+
if (!NIL_P(entry)) {
|
|
400
|
+
int kind = NUM2INT(rb_ary_entry(entry, 0));
|
|
401
|
+
CArray *ca;
|
|
402
|
+
TypedData_Get_Struct(data_val, CArray, &carray_data_type, ca);
|
|
403
|
+
switch (kind) {
|
|
404
|
+
case FAST_KIND_PRIMITIVE: {
|
|
405
|
+
ca_size_t offset = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
406
|
+
int type_code = NUM2INT (rb_ary_entry(entry, 2));
|
|
407
|
+
ca_struct_write_primitive_fast(ca->ptr + offset, type_code, val);
|
|
408
|
+
return 1;
|
|
409
|
+
}
|
|
410
|
+
case FAST_KIND_BITFIELD: {
|
|
411
|
+
ca_size_t start_byte = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
412
|
+
int view_bytes = NUM2INT (rb_ary_entry(entry, 2));
|
|
413
|
+
int bit_in_word = NUM2INT (rb_ary_entry(entry, 3));
|
|
414
|
+
int bits = NUM2INT (rb_ary_entry(entry, 4));
|
|
415
|
+
ca_struct_write_bitfield_fast(ca->ptr + start_byte,
|
|
416
|
+
view_bytes, bit_in_word, bits, val);
|
|
417
|
+
return 1;
|
|
418
|
+
}
|
|
419
|
+
case FAST_KIND_ENDIAN: {
|
|
420
|
+
ca_size_t offset = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
421
|
+
int type_code = NUM2INT (rb_ary_entry(entry, 2));
|
|
422
|
+
ca_struct_write_endian_swapped_fast(ca->ptr + offset, type_code, val);
|
|
423
|
+
return 1;
|
|
424
|
+
}
|
|
425
|
+
default:
|
|
426
|
+
rb_raise(rb_eRuntimeError,
|
|
427
|
+
"[BUG] FAST_PRIMITIVES unknown kind %d", kind);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
VALUE dispatch_table = rb_const_get(klass, rb_intern("DISPATCH_TABLE"));
|
|
432
|
+
VALUE pair = rb_hash_aref(dispatch_table, name_s);
|
|
433
|
+
if (!NIL_P(pair)) {
|
|
434
|
+
VALUE writer = rb_ary_entry(pair, 1);
|
|
435
|
+
rb_funcall(writer, rb_intern("call"), 2, data_val, val);
|
|
436
|
+
return 1;
|
|
437
|
+
}
|
|
438
|
+
return 0;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* ---------------------------------------------------------------------
|
|
442
|
+
CAStruct#[] (C-native).
|
|
443
|
+
--------------------------------------------------------------------- */
|
|
444
|
+
|
|
445
|
+
static VALUE
|
|
446
|
+
rb_ca_struct_aref (VALUE self, VALUE name)
|
|
447
|
+
{
|
|
448
|
+
VALUE klass = rb_obj_class(self);
|
|
449
|
+
VALUE name_s = ca_struct_resolve_name(klass, name);
|
|
450
|
+
|
|
451
|
+
/* Fast path. FAST_PRIMITIVES may be absent on subclasses built
|
|
452
|
+
outside Builder — fall through to the dispatch table in that
|
|
453
|
+
case. Entry shape is `[kind, ...args]`; args depend on kind. */
|
|
454
|
+
if (rb_const_defined(klass, rb_intern("FAST_PRIMITIVES"))) {
|
|
455
|
+
VALUE fast_table = rb_const_get(klass, rb_intern("FAST_PRIMITIVES"));
|
|
456
|
+
VALUE entry = rb_hash_aref(fast_table, name_s);
|
|
457
|
+
if (!NIL_P(entry)) {
|
|
458
|
+
int kind = NUM2INT(rb_ary_entry(entry, 0));
|
|
459
|
+
VALUE data_val = rb_ivar_get(self, rb_intern("@data"));
|
|
460
|
+
CArray *ca;
|
|
461
|
+
TypedData_Get_Struct(data_val, CArray, &carray_data_type, ca);
|
|
462
|
+
/* @data is a CScalar entity, so ca->ptr is always valid. */
|
|
463
|
+
switch (kind) {
|
|
464
|
+
case FAST_KIND_PRIMITIVE: {
|
|
465
|
+
/* [kind, offset, type_code] */
|
|
466
|
+
ca_size_t offset = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
467
|
+
int type_code = NUM2INT (rb_ary_entry(entry, 2));
|
|
468
|
+
return ca_struct_read_primitive_fast(ca->ptr + offset, type_code);
|
|
469
|
+
}
|
|
470
|
+
case FAST_KIND_BITFIELD: {
|
|
471
|
+
/* [kind, start_byte, view_bytes, bit_in_word, bits] */
|
|
472
|
+
ca_size_t start_byte = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
473
|
+
int view_bytes = NUM2INT (rb_ary_entry(entry, 2));
|
|
474
|
+
int bit_in_word = NUM2INT (rb_ary_entry(entry, 3));
|
|
475
|
+
int bits = NUM2INT (rb_ary_entry(entry, 4));
|
|
476
|
+
return ca_struct_read_bitfield_fast(ca->ptr + start_byte,
|
|
477
|
+
view_bytes, bit_in_word, bits);
|
|
478
|
+
}
|
|
479
|
+
case FAST_KIND_ENDIAN: {
|
|
480
|
+
/* [kind, offset, type_code] — only the swap-needed branch;
|
|
481
|
+
same-endian members are folded into FAST_KIND_PRIMITIVE
|
|
482
|
+
at build time. */
|
|
483
|
+
ca_size_t offset = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
484
|
+
int type_code = NUM2INT (rb_ary_entry(entry, 2));
|
|
485
|
+
return ca_struct_read_endian_swapped_fast(ca->ptr + offset,
|
|
486
|
+
type_code);
|
|
487
|
+
}
|
|
488
|
+
default:
|
|
489
|
+
rb_raise(rb_eRuntimeError,
|
|
490
|
+
"[BUG] FAST_PRIMITIVES unknown kind %d", kind);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* Dispatch-table path (nested struct / CArray template / fixlen /
|
|
496
|
+
anything Builder didn't fold into FAST_PRIMITIVES) */
|
|
497
|
+
VALUE dispatch_table = rb_const_get(klass, rb_intern("DISPATCH_TABLE"));
|
|
498
|
+
VALUE pair = rb_hash_aref(dispatch_table, name_s);
|
|
499
|
+
if (!NIL_P(pair)) {
|
|
500
|
+
VALUE reader = rb_ary_entry(pair, 0);
|
|
501
|
+
VALUE data_val = rb_ivar_get(self, rb_intern("@data"));
|
|
502
|
+
return rb_funcall(reader, rb_intern("call"), 1, data_val);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* Unknown name: fall back to send(name) for computed members. */
|
|
506
|
+
return rb_funcall(self, rb_to_id(name), 0);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/* ---------------------------------------------------------------------
|
|
510
|
+
CAStruct#[]= (C-native).
|
|
511
|
+
--------------------------------------------------------------------- */
|
|
512
|
+
|
|
513
|
+
static VALUE
|
|
514
|
+
rb_ca_struct_aset (VALUE self, VALUE name, VALUE val)
|
|
515
|
+
{
|
|
516
|
+
VALUE klass = rb_obj_class(self);
|
|
517
|
+
VALUE name_s = ca_struct_resolve_name(klass, name);
|
|
518
|
+
|
|
519
|
+
/* Fast path (see rb_ca_struct_aref for the absent-FAST_PRIMITIVES
|
|
520
|
+
rationale and entry-shape contract). */
|
|
521
|
+
if (rb_const_defined(klass, rb_intern("FAST_PRIMITIVES"))) {
|
|
522
|
+
VALUE fast_table = rb_const_get(klass, rb_intern("FAST_PRIMITIVES"));
|
|
523
|
+
VALUE entry = rb_hash_aref(fast_table, name_s);
|
|
524
|
+
if (!NIL_P(entry)) {
|
|
525
|
+
int kind = NUM2INT(rb_ary_entry(entry, 0));
|
|
526
|
+
VALUE data_val = rb_ivar_get(self, rb_intern("@data"));
|
|
527
|
+
CArray *ca;
|
|
528
|
+
TypedData_Get_Struct(data_val, CArray, &carray_data_type, ca);
|
|
529
|
+
switch (kind) {
|
|
530
|
+
case FAST_KIND_PRIMITIVE: {
|
|
531
|
+
ca_size_t offset = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
532
|
+
int type_code = NUM2INT (rb_ary_entry(entry, 2));
|
|
533
|
+
ca_struct_write_primitive_fast(ca->ptr + offset, type_code, val);
|
|
534
|
+
return val;
|
|
535
|
+
}
|
|
536
|
+
case FAST_KIND_BITFIELD: {
|
|
537
|
+
ca_size_t start_byte = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
538
|
+
int view_bytes = NUM2INT (rb_ary_entry(entry, 2));
|
|
539
|
+
int bit_in_word = NUM2INT (rb_ary_entry(entry, 3));
|
|
540
|
+
int bits = NUM2INT (rb_ary_entry(entry, 4));
|
|
541
|
+
ca_struct_write_bitfield_fast(ca->ptr + start_byte,
|
|
542
|
+
view_bytes, bit_in_word, bits, val);
|
|
543
|
+
return val;
|
|
544
|
+
}
|
|
545
|
+
case FAST_KIND_ENDIAN: {
|
|
546
|
+
ca_size_t offset = NUM2SIZE(rb_ary_entry(entry, 1));
|
|
547
|
+
int type_code = NUM2INT (rb_ary_entry(entry, 2));
|
|
548
|
+
ca_struct_write_endian_swapped_fast(ca->ptr + offset, type_code, val);
|
|
549
|
+
return val;
|
|
550
|
+
}
|
|
551
|
+
default:
|
|
552
|
+
rb_raise(rb_eRuntimeError,
|
|
553
|
+
"[BUG] FAST_PRIMITIVES unknown kind %d", kind);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/* Dispatch-table path */
|
|
559
|
+
VALUE dispatch_table = rb_const_get(klass, rb_intern("DISPATCH_TABLE"));
|
|
560
|
+
VALUE pair = rb_hash_aref(dispatch_table, name_s);
|
|
561
|
+
if (!NIL_P(pair)) {
|
|
562
|
+
VALUE writer = rb_ary_entry(pair, 1);
|
|
563
|
+
VALUE data_val = rb_ivar_get(self, rb_intern("@data"));
|
|
564
|
+
rb_funcall(writer, rb_intern("call"), 2, data_val, val);
|
|
565
|
+
return val;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/* Unknown name: fall back to send("name=", val). */
|
|
569
|
+
VALUE setter_name = rb_str_plus(rb_obj_as_string(name), rb_str_new_cstr("="));
|
|
570
|
+
return rb_funcall(self, rb_intern_str(setter_name), 1, val);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* ---------------------------------------------------------------------
|
|
574
|
+
C-native CAStruct#initialize.
|
|
575
|
+
|
|
576
|
+
Always creates @data = CScalar.new(klass) as an entity. Hash init
|
|
577
|
+
walks the Hash once, dispatching each key through
|
|
578
|
+
ca_struct_dispatch_write and accumulating unknown keys into a
|
|
579
|
+
single ArgumentError. Positional init dispatches argv[i] under
|
|
580
|
+
MEMBERS[i].
|
|
581
|
+
--------------------------------------------------------------------- */
|
|
582
|
+
|
|
583
|
+
typedef struct {
|
|
584
|
+
VALUE klass;
|
|
585
|
+
VALUE data_val;
|
|
586
|
+
VALUE unknown_keys; /* lazily-allocated Array; Qnil until needed */
|
|
587
|
+
} ca_struct_hash_init_state_t;
|
|
588
|
+
|
|
589
|
+
/* rb_hash_foreach callback: dispatch one key/val pair via the
|
|
590
|
+
shared write helper, accumulating unknown keys for a single
|
|
591
|
+
ArgumentError after the iteration. */
|
|
592
|
+
static int
|
|
593
|
+
ca_struct_hash_init_iter (VALUE key, VALUE val, VALUE state_va)
|
|
594
|
+
{
|
|
595
|
+
ca_struct_hash_init_state_t *st =
|
|
596
|
+
(ca_struct_hash_init_state_t *) state_va;
|
|
597
|
+
VALUE name_s = ca_struct_resolve_name(st->klass, key);
|
|
598
|
+
if (!ca_struct_dispatch_write(st->klass, name_s, val, st->data_val)) {
|
|
599
|
+
if (NIL_P(st->unknown_keys)) st->unknown_keys = rb_ary_new();
|
|
600
|
+
rb_ary_push(st->unknown_keys, key);
|
|
601
|
+
}
|
|
602
|
+
return ST_CONTINUE;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
static VALUE
|
|
606
|
+
rb_ca_struct_initialize (int argc, VALUE *argv, VALUE self)
|
|
607
|
+
{
|
|
608
|
+
VALUE klass = rb_obj_class(self);
|
|
609
|
+
|
|
610
|
+
/* @data is a CScalar entity sized to klass::DATA_SIZE. The
|
|
611
|
+
FAST_PRIMITIVES / dispatcher paths access ca->ptr directly,
|
|
612
|
+
so it must be an entity (a view would not carry a stable ptr
|
|
613
|
+
across the fast path). */
|
|
614
|
+
VALUE data_val = rb_funcall(rb_cCScalar, rb_intern("new"), 1, klass);
|
|
615
|
+
rb_ivar_set(self, rb_intern("@data"), data_val);
|
|
616
|
+
|
|
617
|
+
if (argc == 0) return Qnil;
|
|
618
|
+
|
|
619
|
+
/* Hash init */
|
|
620
|
+
if (argc == 1 && TYPE(argv[0]) == T_HASH) {
|
|
621
|
+
VALUE hash = argv[0];
|
|
622
|
+
ca_struct_hash_init_state_t state = {
|
|
623
|
+
.klass = klass,
|
|
624
|
+
.data_val = data_val,
|
|
625
|
+
.unknown_keys = Qnil,
|
|
626
|
+
};
|
|
627
|
+
/* CAREFUL: pass ca_struct_hash_init_iter without a cast. Its
|
|
628
|
+
signature already matches rb_hash_foreach's callback shape,
|
|
629
|
+
and the old (int (*)(ANYARGS)) cast collapses to
|
|
630
|
+
(int (*)(void)) under C23 and is rejected by gcc-15 as an
|
|
631
|
+
incompatible pointer type. */
|
|
632
|
+
rb_hash_foreach(hash,
|
|
633
|
+
ca_struct_hash_init_iter,
|
|
634
|
+
(VALUE) &state);
|
|
635
|
+
if (!NIL_P(state.unknown_keys)) {
|
|
636
|
+
VALUE members = rb_const_get(klass, rb_intern("MEMBERS"));
|
|
637
|
+
VALUE unknown_inspect = rb_inspect(state.unknown_keys);
|
|
638
|
+
VALUE known_inspect = rb_inspect(members);
|
|
639
|
+
rb_raise(rb_eArgError,
|
|
640
|
+
"unknown member(s) for %s: %s (known: %s)",
|
|
641
|
+
rb_class2name(klass),
|
|
642
|
+
StringValueCStr(unknown_inspect),
|
|
643
|
+
StringValueCStr(known_inspect));
|
|
644
|
+
}
|
|
645
|
+
return Qnil;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/* Positional init */
|
|
649
|
+
VALUE members = rb_const_get(klass, rb_intern("MEMBERS"));
|
|
650
|
+
long mems_size = RARRAY_LEN(members);
|
|
651
|
+
if (argc > mems_size) {
|
|
652
|
+
rb_raise(rb_eArgError,
|
|
653
|
+
"too many arguments for %s.new (<%d> for <%ld>)",
|
|
654
|
+
rb_class2name(klass), argc, mems_size);
|
|
655
|
+
}
|
|
656
|
+
for (int i = 0; i < argc; i++) {
|
|
657
|
+
VALUE name_s = rb_ary_entry(members, i);
|
|
658
|
+
if (!ca_struct_dispatch_write(klass, name_s, argv[i], data_val)) {
|
|
659
|
+
/* Unreachable for Builder-constructed subclasses: MEMBERS
|
|
660
|
+
entries are seeded into both FAST_PRIMITIVES and
|
|
661
|
+
DISPATCH_TABLE. Fall back to send for hand-built
|
|
662
|
+
subclasses that only define writers. */
|
|
663
|
+
VALUE setter_name = rb_str_plus(rb_obj_as_string(name_s),
|
|
664
|
+
rb_str_new_cstr("="));
|
|
665
|
+
rb_funcall(self, rb_intern_str(setter_name), 1, argv[i]);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return Qnil;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/* ---------------------------------------------------------------------
|
|
672
|
+
Install the C `[]` / `[]=` / `initialize` on the given class.
|
|
673
|
+
Called from lib/carray/struct.rb once CAStruct is defined.
|
|
674
|
+
--------------------------------------------------------------------- */
|
|
675
|
+
|
|
676
|
+
static VALUE
|
|
677
|
+
rb_carray_install_castruct_methods (VALUE self, VALUE klass)
|
|
678
|
+
{
|
|
679
|
+
if (!RB_TYPE_P(klass, T_CLASS)) {
|
|
680
|
+
rb_raise(rb_eTypeError, "expected a Class");
|
|
681
|
+
}
|
|
682
|
+
rb_define_method(klass, "[]", rb_ca_struct_aref, 1);
|
|
683
|
+
rb_define_method(klass, "[]=", rb_ca_struct_aset, 2);
|
|
684
|
+
rb_define_method(klass, "initialize", rb_ca_struct_initialize, -1);
|
|
685
|
+
return klass;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
void
|
|
689
|
+
Init_carray_struct (void)
|
|
690
|
+
{
|
|
691
|
+
/* Singleton on rb_cCArray so lib/carray/struct.rb can call it as
|
|
692
|
+
`CArray.__install_castruct_methods__(klass)`. */
|
|
693
|
+
rb_define_singleton_method(rb_cCArray, "__install_castruct_methods__",
|
|
694
|
+
rb_carray_install_castruct_methods, 1);
|
|
695
|
+
}
|