carray 3.0.1 → 3.0.3
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/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_face.h
CHANGED
|
@@ -4,16 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Face mechanism — shared op helper signatures + lift/strip entry points.
|
|
6
6
|
|
|
7
|
-
Phase 1 (= PROPOSAL_CAFACE_PHASE_1.md): skeleton.
|
|
8
|
-
Phase 2 (= PROPOSAL_CAFACE_PHASE_2.md F.2.1): replace shared op helpers
|
|
9
|
-
with thin-forward to parent.
|
|
10
|
-
|
|
11
7
|
This header provides signatures for (1) shared op helpers (= thin-forward
|
|
12
8
|
for storage ops, alias-based since Face is data-layout identical to
|
|
13
9
|
parent), (2) `rb_ca_face_template` (struct duplicate + parent swap),
|
|
14
10
|
(3) `ca_face_lift` (= wrap hook at the tail of user-facing access
|
|
15
|
-
methods), (4) `ca_strip_face` (= Face-stripping helper
|
|
16
|
-
|
|
11
|
+
methods), (4) `ca_strip_face` (= Face-stripping helper for code that
|
|
12
|
+
must see the storage).
|
|
17
13
|
|
|
18
14
|
A Face is a "mask of a semantic type" (= identity layered on a storage
|
|
19
15
|
type such as int64, with no value conversion), sibling to CAFake which
|
|
@@ -57,20 +53,27 @@ void ca_face_xfer_all (void *ap, void *data, int dir);
|
|
|
57
53
|
|
|
58
54
|
/* -- lift / strip helpers -- */
|
|
59
55
|
|
|
60
|
-
/* Struct duplicate + parent + shape swap
|
|
61
|
-
|
|
56
|
+
/* Struct duplicate + parent + shape swap. The primitive under
|
|
57
|
+
ca_face_lift; also called directly where a result is re-wrapped under
|
|
58
|
+
a Face without going through a view (partition, generated reduce). */
|
|
62
59
|
VALUE rb_ca_face_template (VALUE original_face, CArray *new_parent,
|
|
63
60
|
ca_size_t *new_dim);
|
|
64
61
|
|
|
65
|
-
/* At the tail of
|
|
66
|
-
the result as a Face`.
|
|
67
|
-
|
|
68
|
-
transpose / sort etc. in Phase 2. */
|
|
62
|
+
/* At the tail of view-creating methods, `if the receiver is a Face, wrap
|
|
63
|
+
the result as a Face`. Reached through CA_FACE_LIFT_IF_FACE, which
|
|
64
|
+
each view-creating method deploys at its return path. */
|
|
69
65
|
VALUE ca_face_lift (VALUE view, VALUE face_parent);
|
|
70
66
|
|
|
71
|
-
/*
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
/* Lift a fresh array `result` (one a reduction, a scan or a partition built
|
|
68
|
+
from the Face's storage) into the Face `face`: the same Face class over
|
|
69
|
+
`result`, carrying the subclass tail, `result`'s mask and the state
|
|
70
|
+
copy_state carries. `result` stays reachable through the new Face. */
|
|
71
|
+
VALUE ca_face_relift_entity (VALUE face, VALUE result);
|
|
72
|
+
|
|
73
|
+
/* Follow the Face flag down to the first non-Face parent, for code that
|
|
74
|
+
must talk to the storage (store, mask, MemoryView export). The kernel
|
|
75
|
+
iterator strips Faces at entry with its own loop, which also strips
|
|
76
|
+
lazy markers. */
|
|
74
77
|
CArray *ca_strip_face (CArray *src);
|
|
75
78
|
|
|
76
79
|
/* VALUE-level counterpart: walks the Face parent ivar chain to the root
|
|
@@ -101,15 +104,11 @@ void Init_ca_face (void);
|
|
|
101
104
|
extern int8_t CA_OBJ_RECORD;
|
|
102
105
|
VALUE rb_ca_record_get_data_class (CArray *ca);
|
|
103
106
|
|
|
104
|
-
/* -- Convenience macro for view-creating method deployment
|
|
107
|
+
/* -- Convenience macro for view-creating method deployment --
|
|
105
108
|
Insert at the tail of each view-creating Ruby method (= rb_ca_transpose
|
|
106
109
|
/ rb_ca_reshape / etc.) just before return. `ca` is self's CArray *,
|
|
107
110
|
`obj` is the view result, `self` is the calling VALUE. Achieves Face
|
|
108
|
-
transparency in a single C-level line, subclass-agnostic.
|
|
109
|
-
|
|
110
|
-
Macroises the pattern hand-written at the tail of `rb_ca_fetch_method`
|
|
111
|
-
in Phase 1; applied uniformly to view-creating methods from Phase 2
|
|
112
|
-
F.2.13 onward. */
|
|
111
|
+
transparency in a single C-level line, subclass-agnostic. */
|
|
113
112
|
#define CA_FACE_LIFT_IF_FACE(obj, self, ca) do { \
|
|
114
113
|
if ( ca_is_face(ca) && rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|
|
115
114
|
(obj) = ca_face_lift((obj), (self)); \
|
|
@@ -127,14 +126,13 @@ VALUE rb_ca_record_get_data_class (CArray *ca);
|
|
|
127
126
|
|
|
128
127
|
The flag test comes first and covers both bits in one mask, so an
|
|
129
128
|
ordinary array leaves through a single AND. That matters: `[]` is the
|
|
130
|
-
hottest method this is deployed on
|
|
129
|
+
hottest method this is deployed on.
|
|
131
130
|
|
|
132
131
|
NOT interchangeable with CA_FACE_LIFT_IF_FACE. Face is lifted at ~24
|
|
133
132
|
sites, including ones a marker must not follow it through -- `copy` owns
|
|
134
133
|
its data, `sort` reorders values, `value` and `strip_mask` change what
|
|
135
134
|
the mask means. Deploy this only where the result is a view whose shape
|
|
136
|
-
was fixed at construction and which only moves positions
|
|
137
|
-
(PROPOSAL_LAZY_MARKER_LIFT section 4). */
|
|
135
|
+
was fixed at construction and which only moves positions. */
|
|
138
136
|
#define CA_WRAPPER_LIFT(obj, self, ca) do { \
|
|
139
137
|
if ( ca_test_flag((ca), CA_FLAG_IS_FACE | CA_FLAG_IS_LAZY_MARKER) \
|
|
140
138
|
&& rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|
|
@@ -147,10 +145,10 @@ VALUE ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca);
|
|
|
147
145
|
/* -- Scalar fetch decode hook (storage -> surface) --
|
|
148
146
|
On the scalar-return path (= tail of rb_ca_fetch_index /
|
|
149
147
|
rb_ca_fetch_addr), if a Face-derived subclass defines a
|
|
150
|
-
`
|
|
148
|
+
`storage_to_element(raw_value)` Ruby callback, invoke it. This is a
|
|
151
149
|
decode (copy the storage value out and construct a new value object),
|
|
152
150
|
not a wrap (a zero-copy lens over live memory). Its write-direction
|
|
153
|
-
counterpart is `
|
|
151
|
+
counterpart is `element_to_storage` (below).
|
|
154
152
|
|
|
155
153
|
Use cases:
|
|
156
154
|
- `dt[i]` for CATime / CATimedelta → Scalar decode
|
|
@@ -163,39 +161,39 @@ VALUE ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca);
|
|
|
163
161
|
- !is_a?(CArray): CArray results go through the lift path
|
|
164
162
|
(= CA_FACE_LIFT_IF_FACE)
|
|
165
163
|
- !UNDEF: don't decode the masked-element sentinel
|
|
166
|
-
- respond_to?(:
|
|
164
|
+
- respond_to?(:storage_to_element): activates once the subclass adopts
|
|
167
165
|
the convention */
|
|
168
|
-
/* Face-local C-level dispatch table for
|
|
166
|
+
/* Face-local C-level dispatch table for storage_to_element, separate
|
|
169
167
|
from the global ca_operation_function_t (no API change to existing
|
|
170
168
|
subsystems). A Face subclass that wants the per-cell scalar fetch hot
|
|
171
169
|
path to skip rb_funcall registers its C function via
|
|
172
|
-
|
|
170
|
+
ca_face_register_storage_to_element(obj_type, fn) at Init time.
|
|
173
171
|
Unregistered obj_types (= external gem Faces that only define the Ruby
|
|
174
172
|
method) fall through to the rb_funcall branch. The Ruby
|
|
175
|
-
`
|
|
173
|
+
`storage_to_element` method is still defined as a regular method so
|
|
176
174
|
user-facing Ruby code may call it directly. */
|
|
177
|
-
typedef VALUE (*
|
|
175
|
+
typedef VALUE (*ca_face_storage_to_element_fn)(VALUE self, VALUE raw);
|
|
178
176
|
|
|
179
|
-
extern
|
|
177
|
+
extern ca_face_storage_to_element_fn ca_face_storage_to_element_table[];
|
|
180
178
|
|
|
181
|
-
void
|
|
182
|
-
|
|
179
|
+
void ca_face_register_storage_to_element (int obj_type,
|
|
180
|
+
ca_face_storage_to_element_fn fn);
|
|
183
181
|
|
|
184
182
|
/* -- Scalar store encode hook (surface -> storage), mirror of the decode --
|
|
185
|
-
The write-direction counterpart of
|
|
183
|
+
The write-direction counterpart of storage_to_element. Given a surface
|
|
186
184
|
value object (a Scalar / Time / DateTime), a Face-owned function returns
|
|
187
185
|
a storage-domain value (for datetime/timedelta: an Integer in self's
|
|
188
186
|
unit) that the storage cast in rb_ca_obj2ptr can consume directly. A
|
|
189
187
|
Face that needs no conversion (surface == storage) simply does not
|
|
190
188
|
register. Faces may either register a C fast-path function here or
|
|
191
|
-
define the Ruby method `
|
|
189
|
+
define the Ruby method `element_to_storage`; the C table is consulted
|
|
192
190
|
first, then the Ruby fallback. */
|
|
193
|
-
typedef VALUE (*
|
|
191
|
+
typedef VALUE (*ca_face_element_to_storage_fn)(VALUE self, VALUE surface);
|
|
194
192
|
|
|
195
|
-
extern
|
|
193
|
+
extern ca_face_element_to_storage_fn ca_face_element_to_storage_table[];
|
|
196
194
|
|
|
197
|
-
void
|
|
198
|
-
|
|
195
|
+
void ca_face_register_element_to_storage (int obj_type,
|
|
196
|
+
ca_face_element_to_storage_fn fn);
|
|
199
197
|
|
|
200
198
|
/* Single source of truth for the surface -> storage-domain conversion.
|
|
201
199
|
Returns `obj` unchanged when `ca` is not a Face or when no hook is
|
|
@@ -203,7 +201,7 @@ void ca_face_register_scalar_to_storage (int obj_type,
|
|
|
203
201
|
existing storage cast). Otherwise returns the storage-domain value the
|
|
204
202
|
Face produced. Called from rb_ca_obj2ptr (single-cell / fill / masked /
|
|
205
203
|
range stores) and from the Array-of-scalars bulk store branch. */
|
|
206
|
-
VALUE
|
|
204
|
+
VALUE ca_face_element_to_storage (VALUE self, CArray *ca, VALUE obj);
|
|
207
205
|
|
|
208
206
|
/* -- F.S0: Face state homogeneity check (= prerequisite for multi-Face APIs
|
|
209
207
|
such as CAStack lift) --
|
|
@@ -259,18 +257,80 @@ void ca_face_register_state_portable (int obj_type, int portable);
|
|
|
259
257
|
(= falls through to default). */
|
|
260
258
|
int ca_face_state_portable (int obj_type, VALUE klass);
|
|
261
259
|
|
|
262
|
-
|
|
260
|
+
/* Check a list of arrays about to be combined into one (CAStack, CAMeld,
|
|
261
|
+
promote_list). Returns the Face class every element shares, or Qnil
|
|
262
|
+
when none of them is a Face; the combined array is then lifted into
|
|
263
|
+
that class. Raises ArgumentError for a mix of Face and non-Face arrays
|
|
264
|
+
or of two Face classes, for two or more of a Face whose state is not
|
|
265
|
+
portable, and for elements whose state differs from the first one's.
|
|
266
|
+
`who` names the caller at the head of the message. */
|
|
267
|
+
VALUE ca_face_list_class (VALUE list, const char *who);
|
|
268
|
+
|
|
269
|
+
/* A Face array's storage-side parent, one level down; any other array
|
|
270
|
+
as it is. */
|
|
271
|
+
VALUE ca_face_strip_one (VALUE v);
|
|
272
|
+
|
|
273
|
+
/* Bring a Face *operand* into the reference's storage space, or refuse.
|
|
274
|
+
|
|
275
|
+
The gate asks `fz_face_descend`'s question -- "is your storage your
|
|
276
|
+
surface?" -- of the receiver, and for a long time asked nothing at all of
|
|
277
|
+
the operand: a COMPARABLE receiver stripped any Face handed to it, and got
|
|
278
|
+
back that Face's encoding rather than its values. Where the two encodings
|
|
279
|
+
happened to be the same width the comparison then answered, wrongly and
|
|
280
|
+
silently. Call this instead of stripping an operand by hand.
|
|
281
|
+
|
|
282
|
+
A Face passes only if it declares COMPARABLE_STORAGE, i.e. its storage
|
|
283
|
+
cells *are* the values it shows. Anything else -- a byte range, a code, a
|
|
284
|
+
tick -- is refused rather than compared as bytes. Non-Face operands are
|
|
285
|
+
returned untouched. `name` opens the message. */
|
|
286
|
+
/* Refuse to order (verb "order") or count by value (verb "count") a Face
|
|
287
|
+
whose storage does not hold its values in order, naming the conversion. */
|
|
288
|
+
NORETURN(void ca_face_refuse_order (const char *name, VALUE face,
|
|
289
|
+
const char *verb));
|
|
290
|
+
|
|
291
|
+
/* The conversion a refusal of a Face whose cells encode its values points
|
|
292
|
+
at (#to_string for a string Face, to_type(:object) for any other). */
|
|
293
|
+
const char *ca_face_conversion_hint (VALUE face);
|
|
294
|
+
|
|
295
|
+
/* Raise eclass naming a Face that does not define the numeric operation
|
|
296
|
+
`name`; returns when self is not a Face. See ca_obj_face.c. */
|
|
297
|
+
void ca_face_refuse_numeric (VALUE self, const char *name, VALUE eclass);
|
|
298
|
+
|
|
299
|
+
VALUE ca_face_operand_descend (VALUE operand, const char *name);
|
|
300
|
+
|
|
301
|
+
/* Bring an operand into the storage space of a Face reference (a record's
|
|
302
|
+
own data_class, a COMPARABLE Face's plain values, or the reference's
|
|
303
|
+
to_comparable), refusing what the reference cannot read. See
|
|
304
|
+
ca_obj_face.c. */
|
|
305
|
+
VALUE ca_face_reconcile_operand (VALUE reference, VALUE operand,
|
|
306
|
+
const char *name);
|
|
307
|
+
|
|
308
|
+
/* `==` (strict = 0) / `eql?` (strict = 1) when an operand is a Face other
|
|
309
|
+
than a record array. See ca_obj_face.c. */
|
|
310
|
+
int ca_face_equal (VALUE va, VALUE vb, int strict);
|
|
311
|
+
|
|
312
|
+
/* The storage value of a cell read through a Face. A gated (CA_FIXLEN)
|
|
313
|
+
surface over a numeric storage delivers the cell as its bytes; they are
|
|
314
|
+
read back as the storage data_type (a boolean as true / false). A
|
|
315
|
+
fixlen or object storage, and anything not a String, comes back as it
|
|
316
|
+
came. This is what a Ruby storage_to_element receives, and the element
|
|
317
|
+
of a Face that defines none. A C function registered for the obj_type
|
|
318
|
+
receives the cell as it was read, the bytes under a gated surface. */
|
|
319
|
+
VALUE ca_face_storage_value (CArray *ca, VALUE raw);
|
|
320
|
+
|
|
321
|
+
#define CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(obj, self, ca) do { \
|
|
263
322
|
if ( ca_is_face(ca) && (obj) != CA_UNDEF && (obj) != Qnil \
|
|
264
323
|
&& ! rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|
|
265
|
-
|
|
324
|
+
ca_face_storage_to_element_fn _decode_fn = ca_face_storage_to_element_table[(ca)->obj_type]; \
|
|
266
325
|
if ( _decode_fn != NULL ) { \
|
|
267
326
|
(obj) = _decode_fn((self), (obj)); \
|
|
268
327
|
} \
|
|
269
328
|
else { \
|
|
270
|
-
static ID
|
|
271
|
-
|
|
272
|
-
if (
|
|
273
|
-
|
|
329
|
+
static ID _id_storage_to_element = 0; \
|
|
330
|
+
(obj) = ca_face_storage_value((ca), (obj)); \
|
|
331
|
+
if ( _id_storage_to_element == 0 ) _id_storage_to_element = rb_intern("storage_to_element"); \
|
|
332
|
+
if ( rb_respond_to((self), _id_storage_to_element) ) { \
|
|
333
|
+
(obj) = rb_funcall((self), _id_storage_to_element, 1, (obj)); \
|
|
274
334
|
} \
|
|
275
335
|
} \
|
|
276
336
|
} \
|
data/ext/ca_obj_fake.c
CHANGED
|
@@ -154,8 +154,8 @@ static void
|
|
|
154
154
|
ca_fake_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
155
155
|
{
|
|
156
156
|
CAFake *ca = (CAFake *) ap;
|
|
157
|
-
|
|
158
|
-
char *v = (
|
|
157
|
+
volatile VALUE holder;
|
|
158
|
+
char *v = ALLOCV_N(char, holder, ca->parent->bytes);
|
|
159
159
|
if ( dir == CA_XFER_GET ) {
|
|
160
160
|
ca_fetch_index(ca->parent, idx, v);
|
|
161
161
|
ca_ptr2ptr(ca->parent, v, ca, data);
|
|
@@ -164,7 +164,7 @@ ca_fake_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
164
164
|
ca_ptr2ptr(ca, data, ca->parent, v);
|
|
165
165
|
ca_store_index(ca->parent, idx, v);
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
ALLOCV_END(holder);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/* Batched address gather/scatter. CAFake is a 1:1 reinterpret-cast
|
|
@@ -237,6 +237,7 @@ static void
|
|
|
237
237
|
ca_fake_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
238
238
|
ca_size_t *strides, void *data, int dir)
|
|
239
239
|
{
|
|
240
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
240
241
|
CAFake *ca = (CAFake *) ap;
|
|
241
242
|
int8_t ndim = ca->ndim;
|
|
242
243
|
ca_size_t pstrides[CA_RANK_MAX];
|
|
@@ -365,17 +366,11 @@ static void
|
|
|
365
366
|
ca_fake_func_fill_data (void *ap, void *ptr)
|
|
366
367
|
{
|
|
367
368
|
CAFake *ca = (CAFake *) ap;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
else {
|
|
374
|
-
char *v = xmalloc(ca->parent->bytes);
|
|
375
|
-
ca_ptr2ptr(ca, ptr, ca->parent, v);
|
|
376
|
-
ca_fill(ca->parent, v);
|
|
377
|
-
xfree(v);
|
|
378
|
-
}
|
|
369
|
+
volatile VALUE holder;
|
|
370
|
+
char *v = ALLOCV_N(char, holder, ca->parent->bytes);
|
|
371
|
+
ca_ptr2ptr(ca, ptr, ca->parent, v);
|
|
372
|
+
ca_fill(ca->parent, v);
|
|
373
|
+
ALLOCV_END(holder);
|
|
379
374
|
}
|
|
380
375
|
|
|
381
376
|
/* Same as fill_data, with a region: convert the one value once and pass the
|
|
@@ -389,47 +384,22 @@ ca_fake_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
|
389
384
|
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
390
385
|
{
|
|
391
386
|
CAFake *ca = (CAFake *) ap;
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
else {
|
|
398
|
-
char *v = xmalloc(ca->parent->bytes);
|
|
399
|
-
ca_ptr2ptr(ca, ptr, ca->parent, v);
|
|
400
|
-
ca_fill_stride(ca->parent, base, ndim, counts, steps, v);
|
|
401
|
-
xfree(v);
|
|
402
|
-
}
|
|
387
|
+
volatile VALUE holder;
|
|
388
|
+
char *v = ALLOCV_N(char, holder, ca->parent->bytes);
|
|
389
|
+
ca_ptr2ptr(ca, ptr, ca->parent, v);
|
|
390
|
+
ca_fill_stride(ca->parent, base, ndim, counts, steps, v);
|
|
391
|
+
ALLOCV_END(holder);
|
|
403
392
|
}
|
|
404
393
|
|
|
405
394
|
static void
|
|
406
395
|
ca_fake_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
407
396
|
{
|
|
408
397
|
CAFake *ca = (CAFake *) ap;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
else {
|
|
415
|
-
char *v = xmalloc(ca->parent->bytes);
|
|
416
|
-
ca_ptr2ptr(ca, ptr, ca->parent, v);
|
|
417
|
-
ca_fill_addrs(ca->parent, n, addrs, v);
|
|
418
|
-
xfree(v);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
static void
|
|
423
|
-
ca_fake_func_create_mask (void *ap)
|
|
424
|
-
{
|
|
425
|
-
CAFake *ca = (CAFake *) ap;
|
|
426
|
-
ca_update_mask(ca->parent);
|
|
427
|
-
if ( ! ca->parent->mask ) {
|
|
428
|
-
ca_create_mask(ca->parent);
|
|
429
|
-
}
|
|
430
|
-
ca->mask =
|
|
431
|
-
(CArray *) ca_refer_new(ca->parent->mask,
|
|
432
|
-
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
398
|
+
volatile VALUE holder;
|
|
399
|
+
char *v = ALLOCV_N(char, holder, ca->parent->bytes);
|
|
400
|
+
ca_ptr2ptr(ca, ptr, ca->parent, v);
|
|
401
|
+
ca_fill_addrs(ca->parent, n, addrs, v);
|
|
402
|
+
ALLOCV_END(holder);
|
|
433
403
|
}
|
|
434
404
|
|
|
435
405
|
ca_operation_function_t ca_fake_func = {
|
|
@@ -442,7 +412,7 @@ ca_operation_function_t ca_fake_func = {
|
|
|
442
412
|
ca_fake_func_sync,
|
|
443
413
|
ca_fake_func_detach,
|
|
444
414
|
ca_fake_func_fill_data,
|
|
445
|
-
|
|
415
|
+
ca_view_func_create_mask,
|
|
446
416
|
ca_fake_func_xfer_index,
|
|
447
417
|
ca_fake_func_xfer_addrs,
|
|
448
418
|
NULL, /* fold_stride: never-fold (transform boundary) */
|
|
@@ -522,6 +492,7 @@ rb_ca_fake_initialize_copy (VALUE self, VALUE other)
|
|
|
522
492
|
CAFake *ca, *cs;
|
|
523
493
|
|
|
524
494
|
TypedData_Get_Struct(self, CAFake, &cafake_data_type, ca);
|
|
495
|
+
ca_check_uninitialized(ca);
|
|
525
496
|
TypedData_Get_Struct(other, CAFake, &cafake_data_type, cs);
|
|
526
497
|
|
|
527
498
|
if ( ca_func[CA_OBJ_FAKE].pool_init ) {
|
data/ext/ca_obj_farray.c
CHANGED
|
@@ -92,6 +92,7 @@ rb_ca_farray_initialize_copy (VALUE self, VALUE other)
|
|
|
92
92
|
{
|
|
93
93
|
CAStride *ca, *cs;
|
|
94
94
|
TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
|
|
95
|
+
ca_check_uninitialized(ca);
|
|
95
96
|
TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
|
|
96
97
|
if ( ca_func[CA_OBJ_FARRAY].pool_init ) {
|
|
97
98
|
ca_array_pool_alloc(ca, CA_OBJ_FARRAY, cs->ndim);
|
data/ext/ca_obj_field.c
CHANGED
|
@@ -36,14 +36,18 @@ ca_field_setup (CAStride *ca, CArray *parent,
|
|
|
36
36
|
CA_CHECK_BYTES(data_type, bytes);
|
|
37
37
|
|
|
38
38
|
if ( offset < 0 ) {
|
|
39
|
-
rb_raise(
|
|
39
|
+
rb_raise(rb_eArgError, "negative offset");
|
|
40
40
|
}
|
|
41
41
|
if ( data_type == CA_OBJECT ) {
|
|
42
42
|
rb_raise(rb_eCADataTypeError,
|
|
43
43
|
"CA_OBJECT can not to be a data_type for CAField");
|
|
44
44
|
}
|
|
45
|
+
if ( ca_is_object_type(parent) ) {
|
|
46
|
+
rb_raise(rb_eCADataTypeError,
|
|
47
|
+
"a field can not be taken from an object array");
|
|
48
|
+
}
|
|
45
49
|
if ( parent->bytes < offset + bytes ) {
|
|
46
|
-
rb_raise(
|
|
50
|
+
rb_raise(rb_eArgError, "offset or bytes out of range");
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/* strides[k] = parent->bytes × Π_{i>k} parent->dim[i]. Same shape
|
|
@@ -57,6 +61,12 @@ ca_field_setup (CAStride *ca, CArray *parent,
|
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
/* ca == NULL asks for the checks above only, so that a constructor can
|
|
65
|
+
run them before it allocates. */
|
|
66
|
+
if ( ca == NULL ) {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
ca_stride_setup(ca, CA_OBJ_FIELD, parent,
|
|
61
71
|
data_type, bytes,
|
|
62
72
|
parent->ndim, parent->dim, strides, offset);
|
|
@@ -67,7 +77,9 @@ ca_field_setup (CAStride *ca, CArray *parent,
|
|
|
67
77
|
CAStride *
|
|
68
78
|
ca_field_new (CArray *parent, ca_size_t offset, int8_t data_type, ca_size_t bytes)
|
|
69
79
|
{
|
|
70
|
-
CAStride *ca
|
|
80
|
+
CAStride *ca;
|
|
81
|
+
ca_field_setup(NULL, parent, offset, data_type, bytes);
|
|
82
|
+
ca = (CAStride *) ca_array_alloc(CA_OBJ_FIELD, parent->ndim);
|
|
71
83
|
ca_field_setup(ca, parent, offset, data_type, bytes);
|
|
72
84
|
return ca;
|
|
73
85
|
}
|
|
@@ -160,6 +172,7 @@ rb_ca_field_initialize_copy (VALUE self, VALUE other)
|
|
|
160
172
|
CAStride *ca, *cs;
|
|
161
173
|
|
|
162
174
|
TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
|
|
175
|
+
ca_check_uninitialized(ca);
|
|
163
176
|
TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
|
|
164
177
|
|
|
165
178
|
if ( ca_func[CA_OBJ_FIELD].pool_init ) {
|
data/ext/ca_obj_fixlen_string.c
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
#include "carray.h"
|
|
24
24
|
#include "ca_obj_face.h"
|
|
25
|
+
#include "carray_internal.h"
|
|
25
26
|
|
|
26
27
|
typedef struct {
|
|
27
28
|
/* === CAView prefix === */
|
|
@@ -89,13 +90,32 @@ ca_fixlen_string_setup (CAFixlenString *ca, CArray *parent)
|
|
|
89
90
|
"CAFixlenString requires fixlen storage (parent.data_type != CA_FIXLEN)");
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
/* ca == NULL asks for the checks above only, so that a constructor can
|
|
94
|
+
run them before it allocates. */
|
|
95
|
+
if ( ca == NULL ) {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
92
99
|
ca->obj_type = CA_OBJ_FIXLEN_STRING;
|
|
93
100
|
ca->data_type = CA_FIXLEN;
|
|
94
|
-
/* ORDERABLE + COMPARABLE
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
/* ORDERABLE + COMPARABLE. The descent is NOT the identity map -- the
|
|
102
|
+
scalar decode below strips trailing NUL -- but both flags still hold,
|
|
103
|
+
for a reason worth stating exactly, since it is what a Face author
|
|
104
|
+
copying this would need:
|
|
105
|
+
|
|
106
|
+
ORDERABLE: every cell is padded to the same K with NUL, and NUL is
|
|
107
|
+
the smallest byte, so memcmp on the padded cells orders them the same
|
|
108
|
+
way String#<=> orders the stripped strings (a prefix sorts before any
|
|
109
|
+
continuation, which is what the padding reproduces). Stripping is
|
|
110
|
+
order-preserving; it is not order-irrelevant by being absent.
|
|
111
|
+
|
|
112
|
+
COMPARABLE: a String query is padded out to the cell width before it
|
|
113
|
+
is compared, so byte equality on the padded form is equality on the
|
|
114
|
+
stripped form -- for a query that fits. A query longer than K is
|
|
115
|
+
truncated to its own first K bytes by that same padding step, and
|
|
116
|
+
then matches a cell it is not equal to.
|
|
117
|
+
|
|
118
|
+
Which is what the equality families need (docs/topics/CAFace.md §6.3).
|
|
99
119
|
Without the flags the sort family still worked (it exempts CA_FIXLEN
|
|
100
120
|
storage from the gate and orders by memcmp), but the value-hash family
|
|
101
121
|
handed its results back as a plain fixlen array, and search refused a
|
|
@@ -135,8 +155,9 @@ ca_fixlen_string_setup (CAFixlenString *ca, CArray *parent)
|
|
|
135
155
|
CAFixlenString *
|
|
136
156
|
ca_fixlen_string_new (CArray *parent)
|
|
137
157
|
{
|
|
138
|
-
CAFixlenString *ca
|
|
139
|
-
|
|
158
|
+
CAFixlenString *ca;
|
|
159
|
+
ca_fixlen_string_setup(NULL, parent);
|
|
160
|
+
ca = (CAFixlenString *) ca_array_alloc(CA_OBJ_FIXLEN_STRING, parent->ndim);
|
|
140
161
|
ca_fixlen_string_setup(ca, parent);
|
|
141
162
|
return ca;
|
|
142
163
|
}
|
|
@@ -175,18 +196,6 @@ ca_fixlen_string_func_allocate (void *ap)
|
|
|
175
196
|
ca->ptr = ca->parent->ptr;
|
|
176
197
|
}
|
|
177
198
|
|
|
178
|
-
static void
|
|
179
|
-
ca_fixlen_string_func_create_mask (void *ap)
|
|
180
|
-
{
|
|
181
|
-
CAFixlenString *ca = (CAFixlenString *) ap;
|
|
182
|
-
ca_update_mask(ca->parent);
|
|
183
|
-
if ( ! ca->parent->mask ) {
|
|
184
|
-
ca_create_mask(ca->parent);
|
|
185
|
-
}
|
|
186
|
-
ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
|
|
187
|
-
CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
199
|
ca_operation_function_t ca_fixlen_string_func = {
|
|
191
200
|
-1, /* CA_OBJ_FIXLEN_STRING — filled by ca_install_obj_type */
|
|
192
201
|
CA_VIEW_ARRAY,
|
|
@@ -197,7 +206,7 @@ ca_operation_function_t ca_fixlen_string_func = {
|
|
|
197
206
|
ca_face_sync,
|
|
198
207
|
ca_face_detach,
|
|
199
208
|
ca_face_fill_data,
|
|
200
|
-
|
|
209
|
+
ca_view_func_create_mask,
|
|
201
210
|
ca_face_xfer_index,
|
|
202
211
|
ca_face_xfer_addrs,
|
|
203
212
|
NULL, /* fold_stride: identity Face is not foldable */
|
|
@@ -240,7 +249,7 @@ rb_ca_fixlen_string_wrap_method (VALUE klass, VALUE raw)
|
|
|
240
249
|
search / MemoryView still see the raw padded bytes. Genuine trailing NULs
|
|
241
250
|
cannot survive here; use a raw CA_FIXLEN array for binary blobs. */
|
|
242
251
|
static VALUE
|
|
243
|
-
|
|
252
|
+
rb_ca_fixlen_string_storage_to_element (VALUE self, VALUE raw)
|
|
244
253
|
{
|
|
245
254
|
(void) self;
|
|
246
255
|
if ( TYPE(raw) == T_STRING ) {
|
|
@@ -267,6 +276,7 @@ rb_ca_fixlen_string_initialize_copy (VALUE self, VALUE other)
|
|
|
267
276
|
{
|
|
268
277
|
CAFixlenString *ca, *cs;
|
|
269
278
|
TypedData_Get_Struct(self, CAFixlenString, &cafixlen_string_data_type, ca);
|
|
279
|
+
ca_check_uninitialized(ca);
|
|
270
280
|
TypedData_Get_Struct(other, CAFixlenString, &cafixlen_string_data_type, cs);
|
|
271
281
|
if ( ca_func[CA_OBJ_FIXLEN_STRING].pool_init ) {
|
|
272
282
|
ca_array_pool_alloc(ca, CA_OBJ_FIXLEN_STRING, cs->parent->ndim);
|
|
@@ -296,13 +306,16 @@ Init_ca_obj_fixlen_string (void)
|
|
|
296
306
|
rb_ca_fixlen_string_initialize_copy, 1);
|
|
297
307
|
rb_define_singleton_method(rb_cCAFixlenString, "wrap",
|
|
298
308
|
rb_ca_fixlen_string_wrap_method, 1);
|
|
299
|
-
rb_define_method(rb_cCAFixlenString, "
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
309
|
+
rb_define_method(rb_cCAFixlenString, "storage_to_element",
|
|
310
|
+
rb_ca_fixlen_string_storage_to_element, 1);
|
|
311
|
+
ca_face_register_storage_to_element(CA_OBJ_FIXLEN_STRING,
|
|
312
|
+
rb_ca_fixlen_string_storage_to_element);
|
|
303
313
|
|
|
304
314
|
/* CA_FIXLEN is portable storage (fixed-width bytes, no per-process VALUE
|
|
305
315
|
or per-parent buffer), so the Face can be carried across multi-parent
|
|
306
|
-
constructions like CAStack
|
|
316
|
+
constructions like CAStack. */
|
|
307
317
|
ca_face_register_state_portable(CA_OBJ_FIXLEN_STRING, 1);
|
|
318
|
+
|
|
319
|
+
/* The bytes are the strings: a MemoryView consumer reads them as "Ns". */
|
|
320
|
+
ca_face_register_memory_view(CA_OBJ_FIXLEN_STRING, 1);
|
|
308
321
|
}
|