carray 3.0.0 → 3.0.2
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 +2 -1
- data/CHANGELOG.md +845 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +33 -33
- data/carray.gemspec +12 -8
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +256 -114
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +121 -67
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +386 -74
- data/ext/ca_kernel_iterator.h +145 -45
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +88 -27
- data/ext/ca_obj_face.c +104 -0
- data/ext/ca_obj_face.h +48 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +21 -6
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +125 -22
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +107 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +178 -24
- data/ext/ca_obj_string.c +11 -5
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +94 -19
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +1 -5
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +362 -155
- data/ext/ca_sweep_engine.h +39 -9
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +148 -132
- data/ext/carray_access.c +83 -49
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +102 -9
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2010 -335
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +184 -72
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +67 -32
- data/ext/carray_core.c +140 -13
- data/ext/carray_count.c +10 -11
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +72 -51
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +36 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +256 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +324 -54
- data/ext/carray_kernels_reduce_extreme.c +605 -58
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +5 -4
- data/ext/carray_kernels_search.c +187 -106
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +29 -13
- data/ext/carray_median_percentile.c +56 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +50 -53
- data/ext/carray_order.c +1 -1
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +391 -47
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +22 -24
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +323 -145
- data/ext/mkkernel.rb +651 -129
- data/ext/ruby_carray.c +28 -17
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +14 -1
- data/lib/carray/axis_group.rb +84 -7
- data/lib/carray/basics.rb +63 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +111 -25
- data/lib/carray/categorical.rb +154 -37
- data/lib/carray/categorical_iterator.rb +300 -151
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +61 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +21 -1
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +85 -21
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +224 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +32 -12
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +43 -16
- data/lib/carray/iterator.rb +147 -3
- data/lib/carray/lazy.rb +88 -73
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +25 -14
- data/lib/carray/methods/locate_addr.rb +81 -3
- data/lib/carray/methods/mask_duplicates.rb +36 -2
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +23 -2
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +44 -4
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +77 -19
- data/lib/carray/string_operation_extension.rb +10 -6
- data/lib/carray/time.rb +906 -491
- data/lib/carray/window_iterator.rb +421 -27
- data/lib/carray.rb +7 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +68 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +57 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +34 -0
- data/yard-stubs/carray_count.rb +84 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +228 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +1615 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +103 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +252 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +59 -0
- data/yard-stubs/carray_sort.rb +165 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +67 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/ca_obj_binop.c
CHANGED
|
@@ -70,11 +70,21 @@ typedef struct CABinOp {
|
|
|
70
70
|
collapse and attach lifecycle traversal) */
|
|
71
71
|
uint32_t attach;
|
|
72
72
|
uint8_t nosync;
|
|
73
|
+
/* ---- CAMultiParent conformance (CA_FLAG_MULTI_PARENTS): n_parents and
|
|
74
|
+
parents[] sit immediately after the CAView header, as the layout
|
|
75
|
+
convention in carray.h requires, so generic code that would walk a
|
|
76
|
+
single ->parent folds over both operands instead. What this buys
|
|
77
|
+
here is ca_has_mask: it answers for a two-parent view by asking both
|
|
78
|
+
and creating the mask on demand, which lets the mask stay unbuilt
|
|
79
|
+
until something reads it. ---- */
|
|
80
|
+
int32_t n_parents; /* always 2 */
|
|
81
|
+
CArray **parents; /* = &operands[0]; no separate allocation */
|
|
73
82
|
/* CABinOp-specific tail */
|
|
74
83
|
CArray *right;
|
|
75
84
|
uint16_t op_id;
|
|
76
85
|
uint8_t right_is_scalar; /* 1 ⇒ right has elements == 1, walk
|
|
77
86
|
with element-stride 0 (= broadcast) */
|
|
87
|
+
CArray *operands[2]; /* {left, right}; what parents points at */
|
|
78
88
|
} CABinOp;
|
|
79
89
|
|
|
80
90
|
static size_t
|
|
@@ -125,7 +135,7 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
|
125
135
|
|
|
126
136
|
ca->obj_type = CA_OBJ_BINOP;
|
|
127
137
|
ca->data_type = out_dt;
|
|
128
|
-
ca->flags = CA_FLAG_READ_ONLY;
|
|
138
|
+
ca->flags = CA_FLAG_READ_ONLY | CA_FLAG_MULTI_PARENTS;
|
|
129
139
|
ca->ndim = left->ndim;
|
|
130
140
|
ca->bytes = out_bytes;
|
|
131
141
|
ca->elements = left->elements;
|
|
@@ -139,6 +149,10 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
|
139
149
|
ca->nosync = 0;
|
|
140
150
|
ca->right = right;
|
|
141
151
|
ca->op_id = op_id;
|
|
152
|
+
ca->operands[0] = left;
|
|
153
|
+
ca->operands[1] = right;
|
|
154
|
+
ca->parents = ca->operands;
|
|
155
|
+
ca->n_parents = 2;
|
|
142
156
|
/* right_is_scalar fast path: when right holds a single element,
|
|
143
157
|
xfer_stride pulls only that cell into scratch and walks the
|
|
144
158
|
kernel with element-stride 0 (broadcast). The symmetric
|
|
@@ -148,9 +162,10 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
|
|
|
148
162
|
|
|
149
163
|
memcpy(ca->dim, left->dim, left->ndim * sizeof(ca_size_t));
|
|
150
164
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
/* The mask is NOT built here. ca_has_mask folds over parents[] for a
|
|
166
|
+
multi-parent view and creates it on demand, so an expression whose mask
|
|
167
|
+
nobody reads never allocates one -- and a chain of masked nodes builds
|
|
168
|
+
one array at the end rather than one per node. */
|
|
154
169
|
|
|
155
170
|
if ( ca_is_scalar(left) && ca_is_scalar(right) ) {
|
|
156
171
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
@@ -291,25 +306,25 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
291
306
|
one_counts[k] = 1;
|
|
292
307
|
one_strides[k] = right_bytes;
|
|
293
308
|
}
|
|
294
|
-
scratch =
|
|
309
|
+
scratch = ( bo->data_type == CA_OBJECT )
|
|
310
|
+
? ca_lazy_arena_acquire_object(1)
|
|
311
|
+
: ca_lazy_arena_acquire(right_bytes);
|
|
295
312
|
ca_binop_scratch_acquire_count++;
|
|
296
313
|
ca_xfer_stride(bo->right, one_starts, one_counts, one_strides,
|
|
297
314
|
scratch, CA_XFER_GET);
|
|
298
315
|
right_step = 0;
|
|
299
316
|
}
|
|
300
317
|
else {
|
|
301
|
-
/* Same-shape right.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
scratch = ca_lazy_arena_acquire(slab_n * right_bytes);
|
|
318
|
+
/* Same-shape right. `strides` is the step through the operand, the
|
|
319
|
+
same one the left was pulled with -- recomputing a packed one here
|
|
320
|
+
reads the right operand's cells 0, 1, 2 against the left's 0, 2, 4.
|
|
321
|
+
right.bytes matches output.bytes because right.data_type ==
|
|
322
|
+
out.data_type by cast-before, so the same steps serve both. */
|
|
323
|
+
scratch = ( bo->data_type == CA_OBJECT )
|
|
324
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
325
|
+
: ca_lazy_arena_acquire(slab_n * right_bytes);
|
|
311
326
|
ca_binop_scratch_acquire_count++;
|
|
312
|
-
ca_xfer_stride(bo->right, starts, counts,
|
|
327
|
+
ca_xfer_stride(bo->right, starts, counts, strides, scratch,
|
|
313
328
|
CA_XFER_GET);
|
|
314
329
|
right_step = 1;
|
|
315
330
|
}
|
|
@@ -438,6 +453,14 @@ ca_binop_func_allocate (void *ap)
|
|
|
438
453
|
{
|
|
439
454
|
CABinOp *ca = (CABinOp *) ap;
|
|
440
455
|
ca->ptr = xmalloc(ca_length(ca));
|
|
456
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
457
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
458
|
+
xmalloc garbage. */
|
|
459
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
460
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
461
|
+
ca_size_t i;
|
|
462
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
463
|
+
}
|
|
441
464
|
}
|
|
442
465
|
|
|
443
466
|
static void
|
|
@@ -459,6 +482,14 @@ ca_binop_func_attach (void *ap)
|
|
|
459
482
|
s = ca->bytes;
|
|
460
483
|
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
461
484
|
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
485
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
486
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
487
|
+
xmalloc garbage. */
|
|
488
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
489
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
490
|
+
ca_size_t i;
|
|
491
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
492
|
+
}
|
|
462
493
|
ca_binop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
|
|
463
494
|
}
|
|
464
495
|
|
|
@@ -517,6 +548,19 @@ ca_binop_func_create_mask (void *ap)
|
|
|
517
548
|
( bo->op_id == CA_BINOP_BIT_AND || bo->op_id == CA_BINOP_BIT_OR ) );
|
|
518
549
|
is_or = ( bo->op_id == CA_BINOP_BIT_OR );
|
|
519
550
|
|
|
551
|
+
/* One masked operand and no Kleene resolution: the answer is that
|
|
552
|
+
operand's mask, cell for cell. Share it the way CAMonOp shares its
|
|
553
|
+
parent's, rather than allocating a copy per node -- a chain of k
|
|
554
|
+
binops over one masked array then holds one boolean array, not k. */
|
|
555
|
+
if ( ! kleene && ( has_l != has_r ) ) {
|
|
556
|
+
CArray *src = has_l ? l : r;
|
|
557
|
+
if ( src->elements == bo->elements ) {
|
|
558
|
+
bo->mask = (CArray *) ca_refer_new(src->mask, CA_BOOLEAN,
|
|
559
|
+
bo->ndim, bo->dim, 0, 0);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
520
564
|
bo->mask = (CArray *) carray_new(CA_BOOLEAN, bo->ndim, bo->dim, 0, NULL);
|
|
521
565
|
dst = (boolean8_t *) bo->mask->ptr;
|
|
522
566
|
n = bo->elements;
|
|
@@ -524,8 +568,18 @@ ca_binop_func_create_mask (void *ap)
|
|
|
524
568
|
/* Kleene needs operand values even where an operand is unmasked. */
|
|
525
569
|
need_l = has_l || kleene;
|
|
526
570
|
need_r = has_r || kleene;
|
|
527
|
-
|
|
528
|
-
|
|
571
|
+
/* Only Kleene reads operand values. Every other op reads the operand
|
|
572
|
+
masks alone, and attaching the operand to reach its mask materialises
|
|
573
|
+
the whole subexpression under it -- so a chain of k masked binops
|
|
574
|
+
evaluates its own subtree k times over. Attach what is read. */
|
|
575
|
+
if ( kleene ) {
|
|
576
|
+
if ( need_l ) ca_attach(l);
|
|
577
|
+
if ( need_r ) ca_attach(r);
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
if ( has_l ) ca_attach(l->mask);
|
|
581
|
+
if ( has_r ) ca_attach(r->mask);
|
|
582
|
+
}
|
|
529
583
|
|
|
530
584
|
lm = has_l ? (boolean8_t *) l->mask->ptr : NULL;
|
|
531
585
|
rm = has_r ? (boolean8_t *) r->mask->ptr : NULL;
|
|
@@ -550,8 +604,14 @@ ca_binop_func_create_mask (void *ap)
|
|
|
550
604
|
dst[i] = m;
|
|
551
605
|
}
|
|
552
606
|
|
|
553
|
-
if (
|
|
554
|
-
|
|
607
|
+
if ( kleene ) {
|
|
608
|
+
if ( need_r ) ca_detach(r);
|
|
609
|
+
if ( need_l ) ca_detach(l);
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
if ( has_r ) ca_detach(r->mask);
|
|
613
|
+
if ( has_l ) ca_detach(l->mask);
|
|
614
|
+
}
|
|
555
615
|
}
|
|
556
616
|
|
|
557
617
|
ca_operation_function_t ca_binop_func = {
|
|
@@ -682,8 +742,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
682
742
|
|
|
683
743
|
/* === Step 2: broadcast via ca_broadcast_pair (same-ndim size-1
|
|
684
744
|
expansion). No-op when shapes already match or either operand
|
|
685
|
-
is scalar;
|
|
686
|
-
final elements-mismatch check below catches. */
|
|
745
|
+
is scalar; refuses a pair that cannot be brought to one shape. */
|
|
687
746
|
ca_broadcast_pair(&l_resolved, &r_resolved);
|
|
688
747
|
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
689
748
|
TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
|
|
@@ -735,14 +794,12 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
735
794
|
}
|
|
736
795
|
}
|
|
737
796
|
else {
|
|
738
|
-
/*
|
|
739
|
-
|
|
740
|
-
|
|
797
|
+
/* Unreachable from Ruby: ca_broadcast_pair above refuses a pair
|
|
798
|
+
it cannot bring to one shape, and states the rule there. Kept
|
|
799
|
+
so a caller reaching this builder by another route still finds
|
|
800
|
+
the kernel guarded. */
|
|
741
801
|
rb_raise(rb_eArgError,
|
|
742
|
-
"CABinOp:
|
|
743
|
-
"ndim size-1 broadcast is supported; cross-ndim "
|
|
744
|
-
"promotion is not adopted in CArray "
|
|
745
|
-
"(reshape explicitly)",
|
|
802
|
+
"CABinOp: element count mismatch (%lld vs %lld)",
|
|
746
803
|
(long long) l->elements, (long long) r->elements);
|
|
747
804
|
}
|
|
748
805
|
}
|
|
@@ -866,7 +923,6 @@ Init_ca_obj_binop (void)
|
|
|
866
923
|
rb_define_const(rb_cCABinOp, "OP_AND", INT2NUM(CA_BINOP_AND));
|
|
867
924
|
rb_define_const(rb_cCABinOp, "OP_OR", INT2NUM(CA_BINOP_OR));
|
|
868
925
|
rb_define_const(rb_cCABinOp, "OP_XOR", INT2NUM(CA_BINOP_XOR));
|
|
869
|
-
rb_define_const(rb_cCABinOp, "OP_REMINDER", INT2NUM(CA_BINOP_REMINDER));
|
|
870
926
|
|
|
871
927
|
rb_define_alloc_func(rb_cCABinOp, rb_ca_binop_s_allocate);
|
|
872
928
|
rb_define_method(rb_cCABinOp, "initialize_copy",
|
data/ext/ca_obj_block.c
CHANGED
|
@@ -269,8 +269,10 @@ rb_cb_initialize_copy (VALUE self, VALUE other)
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/* Per-axis accessor macro: defines a method that returns the named
|
|
272
|
-
CABlock tail array (size0 / start / step
|
|
273
|
-
`offset` is a single Integer and uses its own accessor below.
|
|
272
|
+
CABlock tail array (size0 / start / step) as a Ruby Array.
|
|
273
|
+
`offset` is a single Integer and uses its own accessor below.
|
|
274
|
+
`count` has no accessor: it is what `shape` already answers, and the
|
|
275
|
+
name belongs to CArray#count. */
|
|
274
276
|
#define rb_cb_get_attr_ary(name) \
|
|
275
277
|
rb_cb_ ## name (VALUE self) \
|
|
276
278
|
{ \
|
|
@@ -288,7 +290,6 @@ rb_cb_ ## name (VALUE self) \
|
|
|
288
290
|
static VALUE rb_cb_get_attr_ary(size0)
|
|
289
291
|
static VALUE rb_cb_get_attr_ary(start)
|
|
290
292
|
static VALUE rb_cb_get_attr_ary(step)
|
|
291
|
-
static VALUE rb_cb_get_attr_ary(count)
|
|
292
293
|
|
|
293
294
|
static VALUE
|
|
294
295
|
rb_cb_offset (VALUE self)
|
|
@@ -376,7 +377,6 @@ Init_ca_obj_block (void)
|
|
|
376
377
|
rb_define_method(rb_cCABlock, "size0", rb_cb_size0, 0);
|
|
377
378
|
rb_define_method(rb_cCABlock, "start", rb_cb_start, 0);
|
|
378
379
|
rb_define_method(rb_cCABlock, "step", rb_cb_step, 0);
|
|
379
|
-
rb_define_method(rb_cCABlock, "count", rb_cb_count, 0);
|
|
380
380
|
rb_define_method(rb_cCABlock, "offset", rb_cb_offset, 0);
|
|
381
381
|
|
|
382
382
|
rb_define_method(rb_cCABlock, "idx2addr0", rb_cb_idx2addr0, -1);
|
data/ext/ca_obj_const_string.c
CHANGED
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
typedef struct {
|
|
39
39
|
/* === CAView prefix === */
|
|
40
40
|
int16_t obj_type;
|
|
41
|
-
int8_t data_type; /* CA_FIXLEN surface (numeric gate); storage is
|
|
41
|
+
int8_t data_type; /* CA_FIXLEN surface (numeric gate); storage is fixlen-16 */
|
|
42
42
|
int8_t ndim;
|
|
43
43
|
int32_t flags; /* CA_FLAG_IS_FACE set */
|
|
44
|
-
ca_size_t bytes; /* sizeof(int64_t) =
|
|
44
|
+
ca_size_t bytes; /* 2 * sizeof(int64_t) = 16 (one (start,end) pair per element) */
|
|
45
45
|
ca_size_t elements;
|
|
46
46
|
ca_size_t *dim;
|
|
47
47
|
char *ptr;
|
|
@@ -227,7 +227,9 @@ ca_operation_function_t ca_const_string_func = {
|
|
|
227
227
|
ca_face_xfer_addrs,
|
|
228
228
|
NULL, /* fold_stride: identity Face is not foldable */
|
|
229
229
|
ca_face_xfer_stride,
|
|
230
|
-
ca_face_xfer_all
|
|
230
|
+
ca_face_xfer_all,
|
|
231
|
+
.fill_addrs = ca_face_fill_addrs,
|
|
232
|
+
.fill_stride = ca_face_fill_stride,
|
|
231
233
|
};
|
|
232
234
|
|
|
233
235
|
/* ------------------------------------------------------------------- */
|
|
@@ -297,6 +299,54 @@ rb_ca_const_string_wrap (VALUE parent_val, VALUE buffer, int encoding_id)
|
|
|
297
299
|
rb_raise(rb_eTypeError, "CAConstString.wrap: buffer: must be a String");
|
|
298
300
|
}
|
|
299
301
|
|
|
302
|
+
/* This is the one door through which already-built offsets enter, so it
|
|
303
|
+
validates rather than assumes. Everything downstream -- the per-cell
|
|
304
|
+
decode, the native byte scans, the sort comparator -- reads `buf + start`
|
|
305
|
+
for `end - start` bytes on the strength of these pairs; an out-of-range
|
|
306
|
+
one is an out-of-bounds read of the heap, not a wrong answer. Refuse it
|
|
307
|
+
here, while the input is still in the caller's hands, rather than letting
|
|
308
|
+
it surface as an IndexError from a decode or as a crash from a scan.
|
|
309
|
+
|
|
310
|
+
A masked cell is exempt: its bytes may be anything at all, that being the
|
|
311
|
+
CArray mask contract, and no reader dereferences them (the scan skips on
|
|
312
|
+
the mask before touching an offset; `.value`, the explicit strip, raises
|
|
313
|
+
from the decode). */
|
|
314
|
+
{
|
|
315
|
+
ca_size_t i, n;
|
|
316
|
+
int64_t *pair;
|
|
317
|
+
boolean8_t *m;
|
|
318
|
+
|
|
319
|
+
ca_attach(parent);
|
|
320
|
+
ca_update_mask(parent);
|
|
321
|
+
n = parent->elements;
|
|
322
|
+
pair = (int64_t *) parent->ptr;
|
|
323
|
+
m = parent->mask ? (boolean8_t *) parent->mask->ptr : NULL;
|
|
324
|
+
for ( i = 0; i < n; i++ ) {
|
|
325
|
+
int64_t start = pair[2 * i], end = pair[2 * i + 1];
|
|
326
|
+
if ( m && m[i] ) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if ( start < 0 || end < start || end > (int64_t) RSTRING_LEN(buffer) ) {
|
|
330
|
+
ca_detach(parent);
|
|
331
|
+
rb_raise(rb_eArgError,
|
|
332
|
+
"CAConstString.wrap: element %lld has range [%lld,%lld), "
|
|
333
|
+
"outside the %ld-byte buffer",
|
|
334
|
+
(long long) i, (long long) start, (long long) end,
|
|
335
|
+
(long) RSTRING_LEN(buffer));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
ca_detach(parent);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* Take ownership of the offsets, the way CACategorical.from_codes takes
|
|
342
|
+
ownership of its codes. Without this the Face is read-only but its
|
|
343
|
+
storage is not, so `cs.parent[i] = <anything>` walks straight past the
|
|
344
|
+
check above and back into an out-of-bounds read. The flag rather than
|
|
345
|
+
#freeze, for the reason from_codes gives: freeze would propagate through
|
|
346
|
+
views and Faces. A caller that wants to keep a mutable entity of its own
|
|
347
|
+
passes `.copy`. */
|
|
348
|
+
ca_set_flag(parent, CA_FLAG_READ_ONLY);
|
|
349
|
+
|
|
300
350
|
ca = ca_const_string_new(parent, rb_str_freeze(buffer), encoding_id);
|
|
301
351
|
obj = TypedData_Wrap_Struct(rb_cCAConstString, &catext_data_type, ca);
|
|
302
352
|
rb_ca_set_parent(obj, parent_val); /* pin parent VALUE for GC */
|
|
@@ -395,10 +445,13 @@ rb_ca_const_string_encoding (VALUE self)
|
|
|
395
445
|
return rb_enc_from_encoding(rb_enc_from_index(ca->encoding_id));
|
|
396
446
|
}
|
|
397
447
|
|
|
398
|
-
/* `CAConstString#buffer` — returns the frozen internal byte buffer
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
path.
|
|
448
|
+
/* `CAConstString#buffer` — returns the frozen internal byte buffer: a pure
|
|
449
|
+
concatenation of the element bytes, with no per-record length prefix (=
|
|
450
|
+
the Arrow values buffer). Exposes the defining tail state for
|
|
451
|
+
introspection and the Arrow-boundary component-buffer export path. The
|
|
452
|
+
ranges that index it live in the storage, one (start,end) int64 pair per
|
|
453
|
+
element; `wrap` is where a hand-built pair array is checked against a
|
|
454
|
+
buffer. */
|
|
402
455
|
static VALUE
|
|
403
456
|
rb_ca_const_string_buffer (VALUE self)
|
|
404
457
|
{
|
|
@@ -538,7 +591,7 @@ ca_const_string_scan_end (ca_const_string_scan_t *s)
|
|
|
538
591
|
so element i occupies s->off[2*i] (start) .. s->off[2*i+1] (end).
|
|
539
592
|
The buffer is a pure concatenation; length = end - start. */
|
|
540
593
|
static inline int
|
|
541
|
-
ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp,
|
|
594
|
+
ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp, int64_t *plen)
|
|
542
595
|
{
|
|
543
596
|
int64_t start, end;
|
|
544
597
|
if ( s->m && s->m[i] ) {
|
|
@@ -547,7 +600,7 @@ ca_const_string_record (ca_const_string_scan_t *s, ca_size_t i, const char **pp,
|
|
|
547
600
|
start = s->off[2 * i];
|
|
548
601
|
end = s->off[2 * i + 1];
|
|
549
602
|
*pp = s->buf + start;
|
|
550
|
-
*plen = (
|
|
603
|
+
*plen = (int64_t) (end - start);
|
|
551
604
|
return 1;
|
|
552
605
|
}
|
|
553
606
|
|
|
@@ -596,7 +649,7 @@ rb_ca_const_string_byte_length (VALUE self)
|
|
|
596
649
|
CArray *co;
|
|
597
650
|
int64_t *op;
|
|
598
651
|
const char *p;
|
|
599
|
-
|
|
652
|
+
int64_t len;
|
|
600
653
|
ca_size_t i;
|
|
601
654
|
|
|
602
655
|
ca_const_string_scan_begin(self, &s);
|
|
@@ -631,7 +684,7 @@ ca_const_string_predicate (VALUE self, VALUE query, int op)
|
|
|
631
684
|
boolean8_t *out;
|
|
632
685
|
const char *qp, *p;
|
|
633
686
|
long qlen;
|
|
634
|
-
|
|
687
|
+
int64_t len;
|
|
635
688
|
ca_size_t i;
|
|
636
689
|
|
|
637
690
|
if ( TYPE(query) != T_STRING ) {
|
|
@@ -684,7 +737,7 @@ rb_ca_const_string_eq (VALUE self, VALUE other)
|
|
|
684
737
|
they are read only when both records are valid, but GCC cannot prove
|
|
685
738
|
that -- initialize to keep -Wmaybe-uninitialized quiet and defensive. */
|
|
686
739
|
const char *pa = NULL, *pb = NULL;
|
|
687
|
-
|
|
740
|
+
int64_t la = 0, lb = 0;
|
|
688
741
|
ca_size_t i;
|
|
689
742
|
|
|
690
743
|
ca_const_string_scan_begin(self, &a);
|
|
@@ -715,7 +768,7 @@ rb_ca_const_string_count (VALUE self, VALUE query)
|
|
|
715
768
|
ca_const_string_scan_t s;
|
|
716
769
|
const char *qp, *p;
|
|
717
770
|
long qlen;
|
|
718
|
-
|
|
771
|
+
int64_t len;
|
|
719
772
|
ca_size_t i, c = 0;
|
|
720
773
|
|
|
721
774
|
if ( TYPE(query) != T_STRING ) {
|
|
@@ -745,7 +798,7 @@ rb_ca_const_string_search (VALUE self, VALUE query)
|
|
|
745
798
|
ca_const_string_scan_t s;
|
|
746
799
|
const char *qp, *p;
|
|
747
800
|
long qlen;
|
|
748
|
-
|
|
801
|
+
int64_t len;
|
|
749
802
|
ca_size_t i;
|
|
750
803
|
VALUE result = Qnil;
|
|
751
804
|
|
|
@@ -784,7 +837,7 @@ ca_const_string_byte_cmp (const void *a, const void *b)
|
|
|
784
837
|
/* sort raises on masked input, so record() always sets these here; the
|
|
785
838
|
initializers keep -Wmaybe-uninitialized quiet and stay defensive. */
|
|
786
839
|
const char *pa = NULL, *pb = NULL;
|
|
787
|
-
|
|
840
|
+
int64_t la = 0, lb = 0;
|
|
788
841
|
int c;
|
|
789
842
|
ca_const_string_record(ca_const_string_sort_ctx, ia, &pa, &la);
|
|
790
843
|
ca_const_string_record(ca_const_string_sort_ctx, ib, &pb, &lb);
|
|
@@ -834,9 +887,15 @@ rb_ca_const_string_sort_index (VALUE self)
|
|
|
834
887
|
return vout;
|
|
835
888
|
}
|
|
836
889
|
|
|
837
|
-
/*
|
|
838
|
-
|
|
839
|
-
|
|
890
|
+
/* The ordering surface is defined in Ruby (lib/carray/const_string.rb) on
|
|
891
|
+
top of these three: a storage cell is a byte range, so storage order is
|
|
892
|
+
insertion order rather than string order, and every member has to read
|
|
893
|
+
the bytes. What is native here is the flat form, which is the common one
|
|
894
|
+
for a string column and which a byte scan does an order of magnitude
|
|
895
|
+
faster than decoding a Ruby String per cell; the per-axis forms go
|
|
896
|
+
through #to_string. These are spelled as internals because the public
|
|
897
|
+
names carry CArray's meanings: what the permutation below answers is
|
|
898
|
+
sort_addr (view-flat addresses in sorted order), not sort_index. */
|
|
840
899
|
|
|
841
900
|
/* CAConstString#min / #max → the byte-min / byte-max element as a frozen String,
|
|
842
901
|
skipping masked elements; nil if empty or all masked. */
|
|
@@ -845,7 +904,7 @@ ca_const_string_extremum (VALUE self, int want_max)
|
|
|
845
904
|
{
|
|
846
905
|
ca_const_string_scan_t s;
|
|
847
906
|
const char *p, *bestp = NULL;
|
|
848
|
-
|
|
907
|
+
int64_t len, bestlen = 0;
|
|
849
908
|
ca_size_t i;
|
|
850
909
|
int found = 0;
|
|
851
910
|
|
|
@@ -892,9 +951,9 @@ rb_ca_const_string_initialize_copy (VALUE self, VALUE other)
|
|
|
892
951
|
CAConstString *ca, *cs;
|
|
893
952
|
TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
|
|
894
953
|
TypedData_Get_Struct(other, CAConstString, &catext_data_type, cs);
|
|
895
|
-
/*
|
|
896
|
-
|
|
897
|
-
buffer
|
|
954
|
+
/* Shallow re-setup: shares the buffer and the offset source, which is the
|
|
955
|
+
documented `dup` semantics for a view. `copy` is the compacting deep
|
|
956
|
+
copy (rebased offsets, compacted buffer, detached). */
|
|
898
957
|
if ( ca_func[CA_OBJ_CONST_STRING].pool_init ) {
|
|
899
958
|
ca_array_pool_alloc(ca, CA_OBJ_CONST_STRING, cs->parent->ndim);
|
|
900
959
|
}
|
|
@@ -947,11 +1006,13 @@ Init_ca_obj_const_string (void)
|
|
|
947
1006
|
rb_define_method(rb_cCAConstString, "search", rb_ca_const_string_search, 1);
|
|
948
1007
|
rb_define_method(rb_cCAConstString, "find_value_index", rb_ca_const_string_search, 1);
|
|
949
1008
|
|
|
950
|
-
/*
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
rb_define_method(rb_cCAConstString, "
|
|
954
|
-
|
|
1009
|
+
/* Native flat sort permutation / min / max (§3.7), byte-memcmp
|
|
1010
|
+
comparator. The public ordering surface is built on these in
|
|
1011
|
+
lib/carray/const_string.rb; see the comment above their definitions. */
|
|
1012
|
+
rb_define_method(rb_cCAConstString, "__sort_addr_bytes__",
|
|
1013
|
+
rb_ca_const_string_sort_index, 0);
|
|
1014
|
+
rb_define_method(rb_cCAConstString, "__min_bytes__", rb_ca_const_string_min, 0);
|
|
1015
|
+
rb_define_method(rb_cCAConstString, "__max_bytes__", rb_ca_const_string_max, 0);
|
|
955
1016
|
|
|
956
1017
|
/* Y-pilot: Face-local C-level fast path for per-cell scalar fetch. */
|
|
957
1018
|
ca_face_register_storage_to_scalar(CA_OBJ_CONST_STRING, rb_ca_const_string_storage_to_scalar);
|
data/ext/ca_obj_face.c
CHANGED
|
@@ -66,6 +66,21 @@ ca_face_fill_data (void *ap, void *ptr)
|
|
|
66
66
|
ca_fill(cav->parent, ptr);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
void
|
|
70
|
+
ca_face_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
71
|
+
{
|
|
72
|
+
CAView *cav = (CAView *) ap;
|
|
73
|
+
ca_fill_addrs(cav->parent, n, addrs, ptr);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
void
|
|
77
|
+
ca_face_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
78
|
+
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
79
|
+
{
|
|
80
|
+
CAView *cav = (CAView *) ap;
|
|
81
|
+
ca_fill_stride(cav->parent, base, ndim, counts, steps, ptr);
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
void
|
|
70
85
|
ca_face_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
71
86
|
{
|
|
@@ -270,6 +285,71 @@ ca_face_lift (VALUE view, VALUE face_parent)
|
|
|
270
285
|
return lifted;
|
|
271
286
|
}
|
|
272
287
|
|
|
288
|
+
/* ca_lazy_marker_lift(view, marker) — the CALazyMarker half of
|
|
289
|
+
* ca_wrapper_lift. Same invariant as the Face lift (wrapper on top, view
|
|
290
|
+
* built against what the wrapper wraps) reached by a shorter route: a
|
|
291
|
+
* marker carries no subclass state, so there is nothing for
|
|
292
|
+
* rb_ca_face_template's struct copy to preserve, and building a fresh
|
|
293
|
+
* marker over the view gets data_type, bytes, shape, mask and flags right
|
|
294
|
+
* by construction. That last part is load-bearing for `refer(type)`,
|
|
295
|
+
* where the view's data_type differs from the one the old marker copied
|
|
296
|
+
* off the entity.
|
|
297
|
+
*
|
|
298
|
+
* The one piece it shares with the Face lift is the one-level swap: the
|
|
299
|
+
* builder handed us a view whose parent is the marker, and leaving it
|
|
300
|
+
* there would stack a redundant marker in the middle. */
|
|
301
|
+
static VALUE
|
|
302
|
+
ca_lazy_marker_lift (VALUE view, VALUE marker)
|
|
303
|
+
{
|
|
304
|
+
CArray *view_ca, *mp;
|
|
305
|
+
extern VALUE rb_ca_lazy_marker_new (VALUE cary);
|
|
306
|
+
|
|
307
|
+
TypedData_Get_Struct(view, CArray, &carray_data_type, view_ca);
|
|
308
|
+
|
|
309
|
+
/* Idempotent: a builder that wrapped internally already returned a
|
|
310
|
+
marker (mirrors the same guard in ca_face_lift). */
|
|
311
|
+
if ( ca_is_lazy_marker(view_ca) ) {
|
|
312
|
+
return view;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
TypedData_Get_Struct(marker, CArray, &carray_data_type, mp);
|
|
316
|
+
|
|
317
|
+
/* One-level swap (CAFace.md section 8.3, same reasoning): move the view
|
|
318
|
+
off the marker and onto what the marker wraps. Guarded on pointer
|
|
319
|
+
equality so only a view built directly on this marker fires. */
|
|
320
|
+
if ( ca_is_view(view_ca)
|
|
321
|
+
&& ((CAView *) view_ca)->parent == mp
|
|
322
|
+
&& ! ca_test_flag(view_ca, CA_FLAG_MULTI_PARENTS) ) {
|
|
323
|
+
((CAView *) view_ca)->parent = ((CAView *) mp)->parent; /* C pointer */
|
|
324
|
+
rb_ca_set_parent(view, rb_ca_parent(marker)); /* @parent ivar */
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return rb_ca_lazy_marker_new(view);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ca_wrapper_lift(view, wrapper, wrapper_ca) — dispatch for
|
|
331
|
+
* CA_WRAPPER_LIFT. The macro has already established that wrapper_ca
|
|
332
|
+
* carries one of the two flags and that view is a CArray. */
|
|
333
|
+
VALUE
|
|
334
|
+
ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca)
|
|
335
|
+
{
|
|
336
|
+
CArray *ca = (CArray *) wrapper_ca;
|
|
337
|
+
|
|
338
|
+
if ( ca_is_face(ca) ) {
|
|
339
|
+
CArray *view_ca;
|
|
340
|
+
TypedData_Get_Struct(view, CArray, &carray_data_type, view_ca);
|
|
341
|
+
/* Some builders (select / repeat / ...) lift their own result; a
|
|
342
|
+
second lift here would double-wrap. Mirrors the guard the `[]`
|
|
343
|
+
call site used to carry inline. */
|
|
344
|
+
if ( ca_is_face(view_ca) ) {
|
|
345
|
+
return view;
|
|
346
|
+
}
|
|
347
|
+
return ca_face_lift(view, wrapper);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return ca_lazy_marker_lift(view, wrapper);
|
|
351
|
+
}
|
|
352
|
+
|
|
273
353
|
/* ca_strip_face(src) — walk down through Face parents to the storage
|
|
274
354
|
* CArray. Called at kernel_iterator entry and lazy chain endpoints
|
|
275
355
|
* where downstream code needs to observe the storage layout, not the
|
|
@@ -515,6 +595,30 @@ ca_face_class_has_portable_method (VALUE klass)
|
|
|
515
595
|
return ( owner != rb_singleton_class(rb_cCArray) ) ? 1 : 0;
|
|
516
596
|
}
|
|
517
597
|
|
|
598
|
+
VALUE
|
|
599
|
+
ca_face_operand_descend (VALUE operand, const char *name)
|
|
600
|
+
{
|
|
601
|
+
CArray *op;
|
|
602
|
+
if ( ! RTEST(rb_obj_is_carray(operand)) ) {
|
|
603
|
+
return operand;
|
|
604
|
+
}
|
|
605
|
+
TypedData_Get_Struct(operand, CArray, &carray_data_type, op);
|
|
606
|
+
if ( ! ca_is_face(op) ) {
|
|
607
|
+
return operand;
|
|
608
|
+
}
|
|
609
|
+
if ( ca_test_flag(op, CA_FLAG_FACE_COMPARABLE_STORAGE) ) {
|
|
610
|
+
return rb_ca_strip_face_value(operand);
|
|
611
|
+
}
|
|
612
|
+
rb_raise(rb_eArgError,
|
|
613
|
+
"%s: cannot take a %s operand: its storage is not its surface "
|
|
614
|
+
"(a cell encodes the value rather than being it), so comparing "
|
|
615
|
+
"the storage would compare the encoding. Convert the operand to "
|
|
616
|
+
"the receiver's space first -- #to_string for a string Face -- "
|
|
617
|
+
"or pass .parent on both sides to work in storage space",
|
|
618
|
+
name, rb_obj_classname(operand));
|
|
619
|
+
return Qnil; /* not reached */
|
|
620
|
+
}
|
|
621
|
+
|
|
518
622
|
int
|
|
519
623
|
ca_face_state_portable (int obj_type, VALUE klass)
|
|
520
624
|
{
|
data/ext/ca_obj_face.h
CHANGED
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
via parent)
|
|
35
35
|
- detach: release ptr alias, parent detach
|
|
36
36
|
- xfer_*: delegate to parent's xfer_* (= identical shape / index space)
|
|
37
|
-
- fill_data
|
|
37
|
+
- fill_data / fill_*: delegate to parent (= identical storage bytes,
|
|
38
|
+
and the identity layout makes the parent's addresses ours)
|
|
38
39
|
|
|
39
40
|
Subclasses may override as needed (= default policy, not an invariant;
|
|
40
41
|
does not preclude a future transform Face). */
|
|
@@ -43,6 +44,9 @@ void ca_face_attach (void *ap);
|
|
|
43
44
|
void ca_face_sync (void *ap);
|
|
44
45
|
void ca_face_detach (void *ap);
|
|
45
46
|
void ca_face_fill_data (void *ap, void *ptr);
|
|
47
|
+
void ca_face_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr);
|
|
48
|
+
void ca_face_fill_stride(void *ap, ca_size_t base, int8_t ndim,
|
|
49
|
+
ca_size_t *counts, ca_size_t *steps, void *ptr);
|
|
46
50
|
void ca_face_xfer_index (void *ap, ca_size_t *idx,
|
|
47
51
|
void *data, int dir);
|
|
48
52
|
void ca_face_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
@@ -112,6 +116,34 @@ VALUE rb_ca_record_get_data_class (CArray *ca);
|
|
|
112
116
|
} \
|
|
113
117
|
} while (0)
|
|
114
118
|
|
|
119
|
+
/* -- wrapper lift (Face or CALazyMarker) --
|
|
120
|
+
|
|
121
|
+
A Face and a CALazyMarker are both storage-identical wrappers: they add
|
|
122
|
+
an interpretation over their parent's bytes without changing them. Both
|
|
123
|
+
want the same invariant at a view-creating method -- the wrapper stays on
|
|
124
|
+
top, and the view is built against what the wrapper wraps. For a Face
|
|
125
|
+
that keeps `dt.shift(1)` a CATime; for a marker it keeps a fuse block's
|
|
126
|
+
expression lazy instead of dropping out of the chain.
|
|
127
|
+
|
|
128
|
+
The flag test comes first and covers both bits in one mask, so an
|
|
129
|
+
ordinary array leaves through a single AND. That matters: `[]` is the
|
|
130
|
+
hottest method this is deployed on (see devel/bench_index_percall.rb).
|
|
131
|
+
|
|
132
|
+
NOT interchangeable with CA_FACE_LIFT_IF_FACE. Face is lifted at ~24
|
|
133
|
+
sites, including ones a marker must not follow it through -- `copy` owns
|
|
134
|
+
its data, `sort` reorders values, `value` and `strip_mask` change what
|
|
135
|
+
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). */
|
|
138
|
+
#define CA_WRAPPER_LIFT(obj, self, ca) do { \
|
|
139
|
+
if ( ca_test_flag((ca), CA_FLAG_IS_FACE | CA_FLAG_IS_LAZY_MARKER) \
|
|
140
|
+
&& rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|
|
141
|
+
(obj) = ca_wrapper_lift((obj), (self), (ca)); \
|
|
142
|
+
} \
|
|
143
|
+
} while (0)
|
|
144
|
+
|
|
145
|
+
VALUE ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca);
|
|
146
|
+
|
|
115
147
|
/* -- Scalar fetch decode hook (storage -> surface) --
|
|
116
148
|
On the scalar-return path (= tail of rb_ca_fetch_index /
|
|
117
149
|
rb_ca_fetch_addr), if a Face-derived subclass defines a
|
|
@@ -227,6 +259,21 @@ void ca_face_register_state_portable (int obj_type, int portable);
|
|
|
227
259
|
(= falls through to default). */
|
|
228
260
|
int ca_face_state_portable (int obj_type, VALUE klass);
|
|
229
261
|
|
|
262
|
+
/* Bring a Face *operand* into the reference's storage space, or refuse.
|
|
263
|
+
|
|
264
|
+
The gate asks `fz_face_descend`'s question -- "is your storage your
|
|
265
|
+
surface?" -- of the receiver, and for a long time asked nothing at all of
|
|
266
|
+
the operand: a COMPARABLE receiver stripped any Face handed to it, and got
|
|
267
|
+
back that Face's encoding rather than its values. Where the two encodings
|
|
268
|
+
happened to be the same width the comparison then answered, wrongly and
|
|
269
|
+
silently. Call this instead of stripping an operand by hand.
|
|
270
|
+
|
|
271
|
+
A Face passes only if it declares COMPARABLE_STORAGE, i.e. its storage
|
|
272
|
+
cells *are* the values it shows. Anything else -- a byte range, a code, a
|
|
273
|
+
tick -- is refused rather than compared as bytes. Non-Face operands are
|
|
274
|
+
returned untouched. `name` opens the message. */
|
|
275
|
+
VALUE ca_face_operand_descend (VALUE operand, const char *name);
|
|
276
|
+
|
|
230
277
|
#define CA_FACE_STORAGE_TO_SCALAR_IF_FACE(obj, self, ca) do { \
|
|
231
278
|
if ( ca_is_face(ca) && (obj) != CA_UNDEF && (obj) != Qnil \
|
|
232
279
|
&& ! rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|