carray 3.0.3 → 3.0.4
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 +264 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +1 -6
- data/ext/ca_axis_group.c +27 -27
- data/ext/ca_binop_dispatch.c +1 -29
- data/ext/ca_binop_dispatch.h +0 -1
- data/ext/ca_categorical_iterator.c +205 -134
- data/ext/ca_compare.c +7 -18
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1234 -1994
- data/ext/ca_kernel_iterator.h +391 -437
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +96 -39
- data/ext/ca_obj_bincmp.c +24 -21
- data/ext/ca_obj_binop.c +15 -26
- data/ext/ca_obj_bitarray.c +3 -2
- data/ext/ca_obj_bitfield.c +5 -6
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +5 -6
- data/ext/ca_obj_const_string.c +173 -19
- data/ext/ca_obj_face.c +238 -57
- data/ext/ca_obj_face.h +19 -0
- data/ext/ca_obj_fake.c +15 -29
- data/ext/ca_obj_farray.c +6 -3
- data/ext/ca_obj_field.c +17 -5
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +406 -132
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +67 -57
- data/ext/ca_obj_object.c +157 -51
- data/ext/ca_obj_record.c +12 -7
- data/ext/ca_obj_reduce.c +13 -8
- data/ext/ca_obj_refer.c +25 -27
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +6 -5
- data/ext/ca_obj_select.c +14 -9
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +11 -1
- data/ext/ca_obj_stack.c +179 -34
- data/ext/ca_obj_stride.c +162 -115
- data/ext/ca_obj_string.c +71 -4
- data/ext/ca_obj_tile.c +6 -5
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +5 -3
- data/ext/ca_obj_triop.c +23 -32
- data/ext/ca_obj_window.c +190 -26
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +181 -75
- data/ext/carray_access.c +184 -96
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +89 -6
- data/ext/carray_bincount.c +10 -8
- data/ext/carray_broadcast.c +13 -8
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +108 -0
- data/ext/carray_cast.c +142 -24
- data/ext/carray_cast_func.rb +46 -6
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +16 -7
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +147 -55
- data/ext/carray_count.c +50 -20
- data/ext/carray_element.c +76 -33
- data/ext/carray_factorize.c +118 -64
- data/ext/carray_generate.c +191 -50
- data/ext/carray_histogram.c +62 -17
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +336 -29
- data/ext/carray_kernels_bincmp.c +4453 -0
- data/ext/carray_kernels_binop.c +11368 -0
- data/ext/carray_kernels_init.c +1734 -0
- data/ext/carray_kernels_moncmp.c +2104 -0
- data/ext/carray_kernels_monop.c +18369 -0
- data/ext/carray_kernels_reduce_aggregate.c +23818 -0
- data/ext/carray_kernels_reduce_boolean.c +406 -0
- data/ext/carray_kernels_reduce_cumulative.c +10086 -0
- data/ext/carray_kernels_reduce_extreme.c +17634 -0
- data/ext/carray_kernels_reduce_variance.c +3849 -0
- data/ext/carray_kernels_scan.c +4302 -0
- data/ext/carray_kernels_search.c +33829 -0
- data/ext/carray_kernels_sort.c +10906 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +292 -72
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +124 -47
- data/ext/carray_order.c +384 -76
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +67 -13
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +63 -38
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +91 -28
- data/ext/carray_sort.c +35 -35
- data/ext/carray_struct.c +19 -18
- data/ext/carray_test.c +26 -5
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +246 -45
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +198 -240
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +126 -22
- data/lib/carray/autoload_carray.rb +8 -31
- data/lib/carray/autoload_method_extension.rb +14 -5
- data/lib/carray/axis_group.rb +255 -106
- data/lib/carray/basics.rb +78 -10
- data/lib/carray/bincount_nd.rb +12 -2
- data/lib/carray/block_iterator.rb +126 -23
- data/lib/carray/boolean_reduce.rb +17 -17
- data/lib/carray/categorical.rb +165 -43
- data/lib/carray/categorical_iterator.rb +130 -27
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +14 -5
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/convert.rb +69 -0
- data/lib/carray/frame/csv_parser.rb +111 -17
- data/lib/carray/frame/describe.rb +3 -2
- data/lib/carray/frame/frame.rb +246 -21
- data/lib/carray/frame/group.rb +510 -95
- data/lib/carray/frame/io.rb +115 -28
- data/lib/carray/frame/join.rb +312 -51
- data/lib/carray/frame/records.rb +83 -7
- data/lib/carray/frame/reshape.rb +42 -35
- data/lib/carray/frame/sort.rb +7 -19
- data/lib/carray/frame/verbs.rb +188 -48
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +11 -4
- data/lib/carray/fusion.rb +40 -16
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +31 -8
- data/lib/carray/iterator.rb +85 -7
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +182 -183
- data/lib/carray/mask_gap_fill.rb +63 -57
- data/lib/carray/meld_reduce.rb +12 -14
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +16 -0
- data/lib/carray/methods/bit_string.rb +1 -1
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +3 -1
- data/lib/carray/methods/gather_nd.rb +14 -5
- data/lib/carray/methods/insert_block.rb +2 -2
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +53 -36
- data/lib/carray/methods/join.rb +1 -6
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +47 -51
- data/lib/carray/methods/mode.rb +1 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/resize.rb +3 -3
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +3 -3
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +53 -8
- data/lib/carray/segment_iterator.rb +313 -82
- data/lib/carray/serialize.rb +24 -10
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +8 -1
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +19 -8
- data/lib/carray/time.rb +726 -104
- data/lib/carray/window_iterator.rb +122 -16
- data/lib/carray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +4 -0
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +2 -1
- data/yard-stubs/ca_obj_roll.rb +2 -2
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_cast.rb +10 -0
- data/yard-stubs/carray_conversion.rb +2 -1
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +26 -2
- data/yard-stubs/carray_math.rb +27 -1
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +29 -18
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +14 -9
- data/yard-stubs/carray_slab.rb +9 -2
- data/yard-stubs/carray_sort.rb +6 -5
- data/yard-stubs/carray_test.rb +5 -3
- metadata +25 -3
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_element.c
CHANGED
|
@@ -20,18 +20,35 @@
|
|
|
20
20
|
#include "ca_obj_face.h"
|
|
21
21
|
#include "carray_internal.h" /* ca_obj_extremum_replaces */
|
|
22
22
|
|
|
23
|
+
/* An element index is an Integer, as it is for `[]`; a Float would be cut
|
|
24
|
+
to an integer by NUM2SIZE. */
|
|
25
|
+
static inline ca_size_t
|
|
26
|
+
elem_index_value (VALUE v)
|
|
27
|
+
{
|
|
28
|
+
if ( FIXNUM_P(v) ) return (ca_size_t) FIX2LONG(v);
|
|
29
|
+
if ( ! RB_INTEGER_TYPE_P(v) ) {
|
|
30
|
+
rb_raise(rb_eIndexError, "object '%"PRIsVALUE"' is invalid for an index",
|
|
31
|
+
rb_inspect(v));
|
|
32
|
+
}
|
|
33
|
+
return NUM2SIZE(v);
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
/* T_ARRAY index parser. ridx is assumed already known to be T_ARRAY.
|
|
24
37
|
Direct VALUE * access + FIXNUM_P fast path eliminates rb_ary_entry
|
|
25
38
|
bounds check and NUM2SIZE Bignum branching for the common case. */
|
|
26
39
|
static inline void
|
|
27
40
|
elem_parse_idx_array (CArray *ca, VALUE rary, ca_size_t *idx)
|
|
28
41
|
{
|
|
29
|
-
const VALUE *iarr
|
|
42
|
+
const VALUE *iarr;
|
|
30
43
|
int8_t ndim = ca->ndim;
|
|
31
44
|
int8_t i;
|
|
45
|
+
if ( RARRAY_LEN(rary) != ndim ) {
|
|
46
|
+
rb_raise(rb_eIndexError, "%ld indices given for a carray of ndim %i",
|
|
47
|
+
(long) RARRAY_LEN(rary), (int) ndim);
|
|
48
|
+
}
|
|
49
|
+
iarr = RARRAY_CONST_PTR(rary);
|
|
32
50
|
for (i=0; i<ndim; i++) {
|
|
33
|
-
|
|
34
|
-
ca_size_t k = FIXNUM_P(v) ? (ca_size_t)FIX2LONG(v) : NUM2SIZE(v);
|
|
51
|
+
ca_size_t k = elem_index_value(iarr[i]);
|
|
35
52
|
CA_CHECK_INDEX(k, ca->dim[i]);
|
|
36
53
|
idx[i] = k;
|
|
37
54
|
}
|
|
@@ -41,7 +58,7 @@ elem_parse_idx_array (CArray *ca, VALUE rary, ca_size_t *idx)
|
|
|
41
58
|
static inline ca_size_t
|
|
42
59
|
elem_parse_idx_scalar (CArray *ca, VALUE ridx)
|
|
43
60
|
{
|
|
44
|
-
ca_size_t k =
|
|
61
|
+
ca_size_t k = elem_index_value(ridx);
|
|
45
62
|
CA_CHECK_INDEX(k, ca->elements);
|
|
46
63
|
return k;
|
|
47
64
|
}
|
|
@@ -278,33 +295,56 @@ rb_ca_elem_store (VALUE self, VALUE ridx, VALUE obj)
|
|
|
278
295
|
if ( FIXNUM_P(obj) ) { *(int64_t *)p = (int64_t)FIX2LONG(obj); return obj; }
|
|
279
296
|
break;
|
|
280
297
|
case CA_INT32:
|
|
281
|
-
if ( FIXNUM_P(obj)
|
|
298
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= INT32_MIN && FIX2LONG(obj) <= INT32_MAX ) {
|
|
299
|
+
/* fits: checked against the type's range above */
|
|
300
|
+
*(int32_t *)p = (int32_t)FIX2LONG(obj); return obj;
|
|
301
|
+
}
|
|
282
302
|
break;
|
|
283
303
|
case CA_INT16:
|
|
284
|
-
if ( FIXNUM_P(obj)
|
|
304
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= INT16_MIN && FIX2LONG(obj) <= INT16_MAX ) {
|
|
305
|
+
/* fits: checked against the type's range above */
|
|
306
|
+
*(int16_t *)p = (int16_t)FIX2LONG(obj); return obj;
|
|
307
|
+
}
|
|
285
308
|
break;
|
|
286
309
|
case CA_INT8:
|
|
287
|
-
if ( FIXNUM_P(obj)
|
|
310
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= INT8_MIN && FIX2LONG(obj) <= INT8_MAX ) {
|
|
311
|
+
/* fits: checked against the type's range above */
|
|
312
|
+
*(int8_t *)p = (int8_t)FIX2LONG(obj); return obj;
|
|
313
|
+
}
|
|
288
314
|
break;
|
|
289
315
|
case CA_UINT64:
|
|
290
|
-
if ( FIXNUM_P(obj)
|
|
316
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 ) {
|
|
317
|
+
*(uint64_t *)p = (uint64_t)FIX2LONG(obj); return obj;
|
|
318
|
+
}
|
|
291
319
|
break;
|
|
292
320
|
case CA_UINT32:
|
|
293
|
-
if ( FIXNUM_P(obj)
|
|
321
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 && FIX2LONG(obj) <= (long) UINT32_MAX ) {
|
|
322
|
+
/* fits: checked against the type's range above */
|
|
323
|
+
*(uint32_t *)p = (uint32_t)FIX2LONG(obj); return obj;
|
|
324
|
+
}
|
|
294
325
|
break;
|
|
295
326
|
case CA_UINT16:
|
|
296
|
-
if ( FIXNUM_P(obj)
|
|
327
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 && FIX2LONG(obj) <= (long) UINT16_MAX ) {
|
|
328
|
+
/* fits: checked against the type's range above */
|
|
329
|
+
*(uint16_t *)p = (uint16_t)FIX2LONG(obj); return obj;
|
|
330
|
+
}
|
|
297
331
|
break;
|
|
298
332
|
case CA_UINT8:
|
|
299
|
-
if ( FIXNUM_P(obj)
|
|
333
|
+
if ( FIXNUM_P(obj) && FIX2LONG(obj) >= 0 && FIX2LONG(obj) <= (long) UINT8_MAX ) {
|
|
334
|
+
/* fits: checked against the type's range above */
|
|
335
|
+
*(uint8_t *)p = (uint8_t)FIX2LONG(obj); return obj;
|
|
336
|
+
}
|
|
300
337
|
break;
|
|
301
338
|
case CA_BOOLEAN:
|
|
302
339
|
if ( obj == Qtrue ) { *(uint8_t *)p = 1; return obj; }
|
|
303
340
|
if ( obj == Qfalse ) { *(uint8_t *)p = 0; return obj; }
|
|
304
|
-
if (
|
|
341
|
+
if ( obj == INT2FIX(0) || obj == INT2FIX(1) ) {
|
|
342
|
+
*(uint8_t *)p = (obj == INT2FIX(1)); return obj;
|
|
343
|
+
}
|
|
305
344
|
break;
|
|
306
345
|
}
|
|
307
|
-
/* Fall through:
|
|
346
|
+
/* Fall through: the value needs the general coercion, or does not fit
|
|
347
|
+
the cell, which the general path refuses. */
|
|
308
348
|
}
|
|
309
349
|
}
|
|
310
350
|
|
|
@@ -331,14 +371,12 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
|
|
|
331
371
|
|
|
332
372
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
333
373
|
|
|
334
|
-
if ( ca_is_empty(ca) ) return Qnil;
|
|
335
|
-
|
|
336
374
|
if ( TYPE(ridx) == T_ARRAY ) {
|
|
337
375
|
volatile VALUE out;
|
|
338
376
|
elem_parse_idx_array(ca, ridx, idx);
|
|
339
377
|
|
|
340
378
|
/* Super-hot path: entity + common numeric data type + no mask.
|
|
341
|
-
Bypass ca_fetch_index dispatch AND
|
|
379
|
+
Bypass ca_fetch_index dispatch AND rb_ca_ptr2obj_storage cast-table dispatch.
|
|
342
380
|
Covers the bench's float64 / int64 / int32 cases. */
|
|
343
381
|
if ( ca_is_entity(ca) && ! ca->mask ) {
|
|
344
382
|
ca_size_t addr = elem_entity_addr(ca, idx);
|
|
@@ -370,13 +408,13 @@ rb_ca_elem_fetch (VALUE self, VALUE ridx)
|
|
|
370
408
|
else {
|
|
371
409
|
ca_fetch_index(ca, idx, v);
|
|
372
410
|
}
|
|
373
|
-
out =
|
|
411
|
+
out = rb_ca_ptr2obj_storage(self, v);
|
|
374
412
|
}
|
|
375
413
|
else {
|
|
376
414
|
volatile VALUE holder;
|
|
377
415
|
char *v = ALLOCV_N(char, holder, ca->bytes);
|
|
378
416
|
ca_fetch_index(ca, idx, v);
|
|
379
|
-
out =
|
|
417
|
+
out = rb_ca_ptr2obj_storage(self, v);
|
|
380
418
|
ALLOCV_END(holder);
|
|
381
419
|
}
|
|
382
420
|
|
|
@@ -749,6 +787,11 @@ rb_ca_elem_unmask (VALUE self, VALUE ridx)
|
|
|
749
787
|
* rule (NaN is treated as missing: `min(NaN, v)` returns `v`,
|
|
750
788
|
* `min(x, NaN)` returns `x`). Raises for non-numeric data_type. */
|
|
751
789
|
|
|
790
|
+
/* The entity fast path takes a Float into a float cell and an Integer
|
|
791
|
+
that fits the cell. Anything else -- a Float into an integer cell, an
|
|
792
|
+
Integer out of the type's range, a Bignum or Rational -- goes to the
|
|
793
|
+
general path, which compares in Ruby and stores as `self[idx] = v`
|
|
794
|
+
does, so a value that wins but does not fit raises. */
|
|
752
795
|
#define ELEM_MINMAX_BODY(OP) do { \
|
|
753
796
|
if ( ca_is_entity(ca) ) { \
|
|
754
797
|
ca_size_t addr; \
|
|
@@ -766,14 +809,6 @@ rb_ca_elem_unmask (VALUE self, VALUE ridx)
|
|
|
766
809
|
switch ( ca->data_type ) { \
|
|
767
810
|
case CA_FLOAT64: { double *q=(double *)p; if (v OP *q || *q != *q) *q = v; return self; } \
|
|
768
811
|
case CA_FLOAT32: { float *q=(float *)p; float vf=(float)v; if (vf OP *q || *q != *q) *q = vf; return self; } \
|
|
769
|
-
case CA_INT64: { int64_t *q=(int64_t *)p; if ((int64_t)v OP *q) *q = (int64_t)v; return self; } \
|
|
770
|
-
case CA_INT32: { int32_t *q=(int32_t *)p; if ((int32_t)v OP *q) *q = (int32_t)v; return self; } \
|
|
771
|
-
case CA_INT16: { int16_t *q=(int16_t *)p; if ((int16_t)v OP *q) *q = (int16_t)v; return self; } \
|
|
772
|
-
case CA_INT8: { int8_t *q=(int8_t *)p; if ((int8_t )v OP *q) *q = (int8_t )v; return self; } \
|
|
773
|
-
case CA_UINT64: { uint64_t *q=(uint64_t*)p; if ((uint64_t)v OP *q) *q = (uint64_t)v; return self; } \
|
|
774
|
-
case CA_UINT32: { uint32_t *q=(uint32_t*)p; if ((uint32_t)v OP *q) *q = (uint32_t)v; return self; } \
|
|
775
|
-
case CA_UINT16: { uint16_t *q=(uint16_t*)p; if ((uint16_t)v OP *q) *q = (uint16_t)v; return self; } \
|
|
776
|
-
case CA_UINT8: { uint8_t *q=(uint8_t *)p; if ((uint8_t )v OP *q) *q = (uint8_t )v; return self; } \
|
|
777
812
|
} \
|
|
778
813
|
} \
|
|
779
814
|
else if ( FIXNUM_P(rval) ) { \
|
|
@@ -782,13 +817,13 @@ rb_ca_elem_unmask (VALUE self, VALUE ridx)
|
|
|
782
817
|
case CA_FLOAT64: { double *q=(double *)p; double vd=(double)v; if (vd OP *q || *q != *q) *q = vd; return self; } \
|
|
783
818
|
case CA_FLOAT32: { float *q=(float *)p; float vf=(float )v; if (vf OP *q || *q != *q) *q = vf; return self; } \
|
|
784
819
|
case CA_INT64: { int64_t *q=(int64_t *)p; if ((int64_t)v OP *q) *q = (int64_t)v; return self; } \
|
|
785
|
-
case CA_INT32: { int32_t *q=(int32_t *)p; if ((int32_t)v OP *q) *q = (int32_t)v; return self; } \
|
|
786
|
-
case CA_INT16: { int16_t *q=(int16_t *)p; if ((int16_t)v OP *q) *q = (int16_t)v; return self; } \
|
|
787
|
-
case CA_INT8: { int8_t *q=(int8_t *)p; if ((int8_t )v OP *q) *q = (int8_t )v; return self; } \
|
|
788
|
-
case CA_UINT64: { uint64_t *q=(uint64_t*)p; if ((uint64_t)v OP *q) *q = (uint64_t)v; return self; } \
|
|
789
|
-
case CA_UINT32: { uint32_t *q=(uint32_t*)p; if ((uint32_t)v OP *q) *q = (uint32_t)v; return self; } \
|
|
790
|
-
case CA_UINT16: { uint16_t *q=(uint16_t*)p; if ((uint16_t)v OP *q) *q = (uint16_t)v; return self; } \
|
|
791
|
-
case CA_UINT8: { uint8_t *q=(uint8_t *)p; if ((uint8_t )v OP *q) *q = (uint8_t )v; return self; } \
|
|
820
|
+
case CA_INT32: { if ( ! (v >= INT32_MIN && v <= INT32_MAX) ) break; int32_t *q=(int32_t *)p; if ((int32_t)v OP *q) *q = (int32_t)v; return self; } \
|
|
821
|
+
case CA_INT16: { if ( ! (v >= INT16_MIN && v <= INT16_MAX) ) break; int16_t *q=(int16_t *)p; if ((int16_t)v OP *q) *q = (int16_t)v; return self; } \
|
|
822
|
+
case CA_INT8: { if ( ! (v >= INT8_MIN && v <= INT8_MAX) ) break; int8_t *q=(int8_t *)p; if ((int8_t )v OP *q) *q = (int8_t )v; return self; } \
|
|
823
|
+
case CA_UINT64: { if ( ! (v >= 0) ) break; uint64_t *q=(uint64_t*)p; if ((uint64_t)v OP *q) *q = (uint64_t)v; return self; } \
|
|
824
|
+
case CA_UINT32: { if ( ! (v >= 0 && v <= (long) UINT32_MAX) ) break; uint32_t *q=(uint32_t*)p; if ((uint32_t)v OP *q) *q = (uint32_t)v; return self; } \
|
|
825
|
+
case CA_UINT16: { if ( ! (v >= 0 && v <= (long) UINT16_MAX) ) break; uint16_t *q=(uint16_t*)p; if ((uint16_t)v OP *q) *q = (uint16_t)v; return self; } \
|
|
826
|
+
case CA_UINT8: { if ( ! (v >= 0 && v <= (long) UINT8_MAX) ) break; uint8_t *q=(uint8_t *)p; if ((uint8_t )v OP *q) *q = (uint8_t )v; return self; } \
|
|
792
827
|
} \
|
|
793
828
|
} \
|
|
794
829
|
} \
|
|
@@ -808,6 +843,10 @@ rb_ca_elem_min (VALUE self, VALUE ridx, VALUE rval)
|
|
|
808
843
|
rb_raise(rb_eCADataTypeError,
|
|
809
844
|
"elem_min requires a numeric array");
|
|
810
845
|
}
|
|
846
|
+
if ( ca_is_complex_type(ca) ) {
|
|
847
|
+
rb_raise(rb_eCADataTypeError,
|
|
848
|
+
"elem_min requires a real array (complex values have no order)");
|
|
849
|
+
}
|
|
811
850
|
|
|
812
851
|
/* Super-hot path: entity + numeric data type + Fixnum/Float rval. */
|
|
813
852
|
ELEM_MINMAX_BODY(<);
|
|
@@ -864,6 +903,10 @@ rb_ca_elem_max (VALUE self, VALUE ridx, VALUE rval)
|
|
|
864
903
|
rb_raise(rb_eCADataTypeError,
|
|
865
904
|
"elem_max requires a numeric array");
|
|
866
905
|
}
|
|
906
|
+
if ( ca_is_complex_type(ca) ) {
|
|
907
|
+
rb_raise(rb_eCADataTypeError,
|
|
908
|
+
"elem_max requires a real array (complex values have no order)");
|
|
909
|
+
}
|
|
867
910
|
|
|
868
911
|
ELEM_MINMAX_BODY(>);
|
|
869
912
|
|
data/ext/carray_factorize.c
CHANGED
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
(Float#eql? treats them equal). The object lane adds one deviation from Ruby
|
|
51
51
|
Hash, aligning it with the numeric lane: every Float NaN collapses to one
|
|
52
52
|
distinct value (a NaN takes a fixed canonical key and matches any stored Float
|
|
53
|
-
NaN), where Ruby Hash would keep distinct NaN objects apart
|
|
53
|
+
NaN), where Ruby Hash would keep distinct NaN objects apart, and a Complex
|
|
54
|
+
with a NaN part is one value with any Complex whose parts match it that way.
|
|
54
55
|
__factorize_appearance__ and the discovery members (unique, value_counts,
|
|
55
56
|
mask_duplicates) all cover the numeric / object / fixlen lanes.
|
|
56
57
|
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
|
|
78
79
|
#include "carray.h"
|
|
79
80
|
#include "ca_obj_face.h"
|
|
81
|
+
#include "carray_internal.h" /* ca_object_cells_clear */
|
|
80
82
|
#include <string.h>
|
|
81
83
|
#include <math.h>
|
|
82
84
|
|
|
@@ -175,6 +177,7 @@ fz_complex_key (VALUE self)
|
|
|
175
177
|
if ( ca_has_mask(ca) ) {
|
|
176
178
|
ca_copy_mask(co, ca);
|
|
177
179
|
}
|
|
180
|
+
RB_GC_GUARD(self); /* read through ca after rb_carray_new allocates */
|
|
178
181
|
return out;
|
|
179
182
|
}
|
|
180
183
|
|
|
@@ -206,24 +209,19 @@ fz_face_descend (VALUE self, volatile VALUE *pface, const char *name)
|
|
|
206
209
|
}
|
|
207
210
|
if ( ca_is_face(ca) ) {
|
|
208
211
|
/* A record is its bytes: two records are the same value exactly when
|
|
209
|
-
their bytes are, so the fixlen lane answers for it.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
their bytes are, so the fixlen lane answers for it. Any other Face
|
|
213
|
+
is descended only when ORDERABLE. One that cannot be descended must
|
|
214
|
+
not flow on undescended: whatever reads it next reads its storage
|
|
215
|
+
anyway, which is the encoding rather than the values. A Face in this
|
|
216
|
+
position normally never arrives -- CAConstString and CACategorical
|
|
217
|
+
define their own members in Ruby -- but the overrides only fire when
|
|
218
|
+
the Face is the receiver, and this same helper descends the
|
|
219
|
+
*reference* for locate_addr, where it is the argument. */
|
|
220
|
+
if ( ca->obj_type != CA_OBJ_RECORD ) {
|
|
221
|
+
ca_face_require_orderable(self, name, "compare");
|
|
214
222
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
than the values. A Face in this position normally never arrives --
|
|
218
|
-
CAConstString and CACategorical define their own members in Ruby -- but
|
|
219
|
-
the overrides only fire when the Face is the receiver, and this same
|
|
220
|
-
helper descends the *reference* for locate_addr, where it is the
|
|
221
|
-
argument. */
|
|
222
|
-
rb_raise(rb_eArgError,
|
|
223
|
-
"%s: %s is not orderable by storage (a cell encodes the value "
|
|
224
|
-
"rather than being it); convert it first -- %s -- or pass "
|
|
225
|
-
".parent to work in storage space",
|
|
226
|
-
name, rb_obj_classname(self), ca_face_conversion_hint(self));
|
|
223
|
+
*pface = self;
|
|
224
|
+
return rb_ca_strip_face_value(self);
|
|
227
225
|
}
|
|
228
226
|
*pface = Qnil;
|
|
229
227
|
return self;
|
|
@@ -250,6 +248,7 @@ fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
|
250
248
|
}
|
|
251
249
|
GetCArray(operand, op);
|
|
252
250
|
if ( op->data_type != ca->data_type ) {
|
|
251
|
+
/* coerce: the callers have met both sides at result_type already */
|
|
253
252
|
operand = rb_ca_to_type(operand, INT2NUM(ca->data_type), Qnil);
|
|
254
253
|
}
|
|
255
254
|
return fz_complex_key(operand);
|
|
@@ -402,8 +401,7 @@ fz_hash_alloc (fz_hash *h, ca_size_t cap)
|
|
|
402
401
|
h->cap = cap;
|
|
403
402
|
MEMZERO(h->used, uint8_t, cap);
|
|
404
403
|
if ( has_val ) {
|
|
405
|
-
|
|
406
|
-
for ( i = 0; i < cap; i++ ) h->val[i] = Qnil;
|
|
404
|
+
ca_object_cells_clear(h->val, cap);
|
|
407
405
|
fz_tmp_values(h->hbuf, h->val, cap);
|
|
408
406
|
}
|
|
409
407
|
}
|
|
@@ -512,25 +510,84 @@ fz_is_float_nan (VALUE v)
|
|
|
512
510
|
return RB_FLOAT_TYPE_P(v) && isnan(RFLOAT_VALUE(v));
|
|
513
511
|
}
|
|
514
512
|
|
|
513
|
+
/* True when v holds a NaN that eql? would keep apart from an equal value:
|
|
514
|
+
a Float NaN, or a Complex with a Float NaN part. */
|
|
515
|
+
static int
|
|
516
|
+
fz_obj_has_nan (VALUE v)
|
|
517
|
+
{
|
|
518
|
+
if ( fz_is_float_nan(v) ) {
|
|
519
|
+
return 1;
|
|
520
|
+
}
|
|
521
|
+
return RB_TYPE_P(v, T_COMPLEX)
|
|
522
|
+
&& ( fz_is_float_nan(rb_complex_real(v))
|
|
523
|
+
|| fz_is_float_nan(rb_complex_imag(v)) );
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* A part of a NaN-bearing value: every NaN is one value, the rest go by
|
|
527
|
+
eql?, as in Ruby Hash. */
|
|
528
|
+
static uint64_t
|
|
529
|
+
fz_obj_part_key (VALUE v)
|
|
530
|
+
{
|
|
531
|
+
return fz_is_float_nan(v) ? FZ_NAN_KEY_DOUBLE : (uint64_t) NUM2LL(rb_hash(v));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static int
|
|
535
|
+
fz_obj_part_eql (VALUE a, VALUE b)
|
|
536
|
+
{
|
|
537
|
+
if ( fz_is_float_nan(a) || fz_is_float_nan(b) ) {
|
|
538
|
+
return fz_is_float_nan(a) && fz_is_float_nan(b);
|
|
539
|
+
}
|
|
540
|
+
return rb_eql(a, b);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/* The hash key of an object cell. A NaN-bearing value is keyed part by
|
|
544
|
+
part with every NaN as one value, so it matches the numeric lane: all
|
|
545
|
+
NaN are one value, and a complex value is one value when its parts are. */
|
|
546
|
+
static uint64_t
|
|
547
|
+
fz_obj_key (VALUE v, int has_nan)
|
|
548
|
+
{
|
|
549
|
+
if ( ! has_nan ) {
|
|
550
|
+
return (uint64_t) NUM2LL(rb_hash(v));
|
|
551
|
+
}
|
|
552
|
+
if ( RB_TYPE_P(v, T_COMPLEX) ) {
|
|
553
|
+
return fz_obj_part_key(rb_complex_real(v)) * 31u
|
|
554
|
+
^ fz_obj_part_key(rb_complex_imag(v)) ^ 0x9e3779b97f4a7c15ULL;
|
|
555
|
+
}
|
|
556
|
+
return FZ_NAN_KEY_DOUBLE;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* Whether a stored cell is the same value as v (has_nan from fz_obj_has_nan). */
|
|
560
|
+
static int
|
|
561
|
+
fz_obj_same (VALUE stored, VALUE v, int has_nan)
|
|
562
|
+
{
|
|
563
|
+
if ( ! has_nan ) {
|
|
564
|
+
return rb_eql(stored, v);
|
|
565
|
+
}
|
|
566
|
+
if ( RB_TYPE_P(v, T_COMPLEX) ) {
|
|
567
|
+
return RB_TYPE_P(stored, T_COMPLEX)
|
|
568
|
+
&& fz_obj_part_eql(rb_complex_real(stored), rb_complex_real(v))
|
|
569
|
+
&& fz_obj_part_eql(rb_complex_imag(stored), rb_complex_imag(v));
|
|
570
|
+
}
|
|
571
|
+
return fz_is_float_nan(stored);
|
|
572
|
+
}
|
|
573
|
+
|
|
515
574
|
/* Object-lane intern: key = rb_hash(v) (lossy), collision re-check via rb_eql.
|
|
516
575
|
Matches Ruby Hash distinctness (`hash` + `eql?`) element for element, with one
|
|
517
576
|
value-based exception aligning with the numeric lane: every Float NaN collapses
|
|
518
577
|
to a single distinct value (Ruby Hash keeps distinct NaN objects apart via
|
|
519
|
-
eql?, but the discovery family unifies them)
|
|
520
|
-
|
|
521
|
-
into the first. */
|
|
578
|
+
eql?, but the discovery family unifies them), and so does a Complex whose
|
|
579
|
+
parts are the same with every NaN as one (fz_obj_key / fz_obj_same). */
|
|
522
580
|
static int32_t
|
|
523
581
|
fz_hash_intern_obj (fz_hash *h, VALUE v, int *is_new)
|
|
524
582
|
{
|
|
525
583
|
if ( (h->n + 1) * 10 >= h->cap * 7 ) { fz_hash_grow(h); } /* load factor 0.7 */
|
|
526
|
-
int v_nan =
|
|
527
|
-
uint64_t key = v_nan
|
|
528
|
-
: (uint64_t) NUM2LL(rb_hash(v));
|
|
584
|
+
int v_nan = fz_obj_has_nan(v);
|
|
585
|
+
uint64_t key = fz_obj_key(v, v_nan);
|
|
529
586
|
ca_size_t mask = h->cap - 1;
|
|
530
587
|
ca_size_t slot = FZ_HOME(h, key);
|
|
531
588
|
while ( h->used[slot] ) {
|
|
532
589
|
if ( h->key[slot] == key &&
|
|
533
|
-
(
|
|
590
|
+
fz_obj_same(h->val[slot], v, v_nan) ) {
|
|
534
591
|
*is_new = 0; return h->code[slot];
|
|
535
592
|
}
|
|
536
593
|
slot = (slot + 1) & mask;
|
|
@@ -621,14 +678,13 @@ fz_hash_lookup (fz_hash *h, uint64_t key, int32_t *code_out)
|
|
|
621
678
|
static int
|
|
622
679
|
fz_hash_lookup_obj (fz_hash *h, VALUE v, int32_t *code_out)
|
|
623
680
|
{
|
|
624
|
-
int v_nan =
|
|
625
|
-
uint64_t key = v_nan
|
|
626
|
-
: (uint64_t) NUM2LL(rb_hash(v));
|
|
681
|
+
int v_nan = fz_obj_has_nan(v);
|
|
682
|
+
uint64_t key = fz_obj_key(v, v_nan);
|
|
627
683
|
ca_size_t mask = h->cap - 1;
|
|
628
684
|
ca_size_t slot = FZ_HOME(h, key);
|
|
629
685
|
while ( h->used[slot] ) {
|
|
630
686
|
if ( h->key[slot] == key &&
|
|
631
|
-
(
|
|
687
|
+
fz_obj_same(h->val[slot], v, v_nan) ) {
|
|
632
688
|
if ( code_out ) { *code_out = h->code[slot]; }
|
|
633
689
|
return 1;
|
|
634
690
|
}
|
|
@@ -669,9 +725,7 @@ typedef struct {
|
|
|
669
725
|
static void
|
|
670
726
|
fz_levels_values (fz_levels *l, ca_size_t from)
|
|
671
727
|
{
|
|
672
|
-
|
|
673
|
-
ca_size_t i;
|
|
674
|
-
for ( i = from; i < l->cap; i++ ) v[i] = Qnil;
|
|
728
|
+
ca_object_cells_clear((VALUE *) l->p + from, l->cap - from);
|
|
675
729
|
fz_tmp_values(l->hp, l->p, l->cap);
|
|
676
730
|
}
|
|
677
731
|
|
|
@@ -717,7 +771,13 @@ fz_levels_free (fz_levels *l)
|
|
|
717
771
|
in the middle of a walk. The walks' states live in this frame, outside the
|
|
718
772
|
method's body, and ca_iter_ensure finishes them however the body leaves;
|
|
719
773
|
the tables have owners the unwind collects (fz_tmp_alloc). Slots 0
|
|
720
|
-
and 1 hold a method's own walks, slot 2 the walk of fz_intern_all.
|
|
774
|
+
and 1 hold a method's own walks, slot 2 the walk of fz_intern_all.
|
|
775
|
+
|
|
776
|
+
A body that replaces self or an operand with an array it made (complex
|
|
777
|
+
keys, a Face's storage, an operand brought into self's space) writes the
|
|
778
|
+
new VALUE back into the frame. The walks read it only through its
|
|
779
|
+
CArray *, so a C local alone would leave it to the collector halfway
|
|
780
|
+
through. */
|
|
721
781
|
|
|
722
782
|
typedef struct {
|
|
723
783
|
ca_iter_state st[3];
|
|
@@ -761,7 +821,7 @@ fz_factorize_appearance_body (VALUE arg)
|
|
|
761
821
|
VALUE self = fr->self;
|
|
762
822
|
CArray *ca;
|
|
763
823
|
volatile VALUE face;
|
|
764
|
-
self = fz_face_descend(self, &face, "categorize");
|
|
824
|
+
fr->self = self = fz_face_descend(self, &face, "categorize");
|
|
765
825
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
766
826
|
|
|
767
827
|
int8_t dt = ca->data_type;
|
|
@@ -1132,7 +1192,7 @@ fz_unique_flat_body (VALUE arg)
|
|
|
1132
1192
|
VALUE self = fr->self;
|
|
1133
1193
|
CArray *ca;
|
|
1134
1194
|
volatile VALUE face;
|
|
1135
|
-
self = fz_face_descend(self, &face, "unique");
|
|
1195
|
+
fr->self = self = fz_face_descend(self, &face, "unique");
|
|
1136
1196
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1137
1197
|
|
|
1138
1198
|
int8_t dt = ca->data_type;
|
|
@@ -1158,8 +1218,6 @@ fz_unique_flat_body (VALUE arg)
|
|
|
1158
1218
|
else { fz_hash_init(&h); }
|
|
1159
1219
|
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1160
1220
|
|
|
1161
|
-
int8_t axis = (int8_t) (ca->ndim - 1); /* innermost fiber; hash not reset =
|
|
1162
|
-
one seen-set over the whole array */
|
|
1163
1221
|
ca_iter_state *st_in = &fr->st[0];
|
|
1164
1222
|
char *p_in;
|
|
1165
1223
|
boolean8_t *m;
|
|
@@ -1220,7 +1278,7 @@ fz_unique_flat_body (VALUE arg)
|
|
|
1220
1278
|
} \
|
|
1221
1279
|
} while (0)
|
|
1222
1280
|
|
|
1223
|
-
|
|
1281
|
+
CA_FOR_EACH_WHOLE_MASKED(*st_in, ca, CA_KERNEL_READ, p_in, n, m) {
|
|
1224
1282
|
switch ( dt ) {
|
|
1225
1283
|
case CA_INT8: UQ_LOOP(int8_t, (int64_t)); break;
|
|
1226
1284
|
case CA_INT16: UQ_LOOP(int16_t, (int64_t)); break;
|
|
@@ -1265,7 +1323,7 @@ rb_ca_unique_flat (VALUE self)
|
|
|
1265
1323
|
}
|
|
1266
1324
|
|
|
1267
1325
|
/* Intern every non-masked cell of cv into h, one seen-set over the whole array
|
|
1268
|
-
|
|
1326
|
+
walked in row-major order. When lv is non-NULL, the first-seen
|
|
1269
1327
|
raw element of each distinct value is pushed to it (appearance order), so the
|
|
1270
1328
|
same pass builds both a probe set and the distinct-value list. Dispatches the
|
|
1271
1329
|
three key lanes exactly as the discovery family: numeric widen with all NaN
|
|
@@ -1276,7 +1334,6 @@ static void
|
|
|
1276
1334
|
fz_intern_all (ca_iter_state *st_v, fz_hash *h, CArray *cv, fz_levels *lv)
|
|
1277
1335
|
{
|
|
1278
1336
|
int8_t dt = cv->data_type;
|
|
1279
|
-
int8_t vaxis = (int8_t) (cv->ndim - 1);
|
|
1280
1337
|
char *p_v;
|
|
1281
1338
|
boolean8_t *mv;
|
|
1282
1339
|
ca_size_t nv;
|
|
@@ -1329,7 +1386,7 @@ fz_intern_all (ca_iter_state *st_v, fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1329
1386
|
} \
|
|
1330
1387
|
} while (0)
|
|
1331
1388
|
|
|
1332
|
-
|
|
1389
|
+
CA_FOR_EACH_WHOLE_MASKED(*st_v, cv, CA_KERNEL_READ, p_v, nv, mv) {
|
|
1333
1390
|
switch ( dt ) {
|
|
1334
1391
|
case CA_INT8: FZ_IA(int8_t, (int64_t)); break;
|
|
1335
1392
|
case CA_INT16: FZ_IA(int16_t, (int64_t)); break;
|
|
@@ -1376,8 +1433,8 @@ fz_is_in_body (VALUE arg)
|
|
|
1376
1433
|
VALUE rvalues = fr->a;
|
|
1377
1434
|
CArray *ca, *cv;
|
|
1378
1435
|
volatile VALUE face;
|
|
1379
|
-
self
|
|
1380
|
-
rvalues
|
|
1436
|
+
fr->self = self = fz_face_descend(self, &face, "is_in");
|
|
1437
|
+
fr->a = rvalues = fz_face_reconcile(face, rvalues, "is_in");
|
|
1381
1438
|
GetCArray(self, ca);
|
|
1382
1439
|
|
|
1383
1440
|
int8_t dt = ca->data_type;
|
|
@@ -1543,8 +1600,8 @@ fz_locate_addr_body (VALUE arg)
|
|
|
1543
1600
|
output is an address, so nothing is lifted back. */
|
|
1544
1601
|
{
|
|
1545
1602
|
volatile VALUE ref_face;
|
|
1546
|
-
rref = fz_face_descend(rref, &ref_face, "locate_addr");
|
|
1547
|
-
self = fz_face_reconcile(ref_face, self, "locate_addr");
|
|
1603
|
+
fr->a = rref = fz_face_descend(rref, &ref_face, "locate_addr");
|
|
1604
|
+
fr->self = self = fz_face_reconcile(ref_face, self, "locate_addr");
|
|
1548
1605
|
}
|
|
1549
1606
|
GetCArray(self, ca);
|
|
1550
1607
|
|
|
@@ -1807,8 +1864,8 @@ fz_set_relation_body (VALUE arg)
|
|
|
1807
1864
|
int keep_when_hit = fr->i;
|
|
1808
1865
|
CArray *ca, *co;
|
|
1809
1866
|
volatile VALUE face;
|
|
1810
|
-
self = fz_face_descend(self, &face, "set relation");
|
|
1811
|
-
rother = fz_face_reconcile(face, rother, "set relation");
|
|
1867
|
+
fr->self = self = fz_face_descend(self, &face, "set relation");
|
|
1868
|
+
fr->a = rother = fz_face_reconcile(face, rother, "set relation");
|
|
1812
1869
|
GetCArray(self, ca);
|
|
1813
1870
|
|
|
1814
1871
|
int8_t dt = ca->data_type;
|
|
@@ -2002,8 +2059,8 @@ fz_set_union_body (VALUE arg)
|
|
|
2002
2059
|
VALUE rother = fr->a;
|
|
2003
2060
|
CArray *ca, *co;
|
|
2004
2061
|
volatile VALUE face;
|
|
2005
|
-
self = fz_face_descend(self, &face, "union");
|
|
2006
|
-
rother = fz_face_reconcile(face, rother, "union");
|
|
2062
|
+
fr->self = self = fz_face_descend(self, &face, "union");
|
|
2063
|
+
fr->a = rother = fz_face_reconcile(face, rother, "union");
|
|
2007
2064
|
GetCArray(self, ca);
|
|
2008
2065
|
|
|
2009
2066
|
int8_t dt = ca->data_type;
|
|
@@ -2095,7 +2152,7 @@ fz_value_counts_flat_body (VALUE arg)
|
|
|
2095
2152
|
VALUE self = fr->self;
|
|
2096
2153
|
CArray *ca;
|
|
2097
2154
|
volatile VALUE face;
|
|
2098
|
-
self = fz_face_descend(self, &face, "value_counts");
|
|
2155
|
+
fr->self = self = fz_face_descend(self, &face, "value_counts");
|
|
2099
2156
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2100
2157
|
|
|
2101
2158
|
int8_t dt = ca->data_type;
|
|
@@ -2255,10 +2312,10 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
2255
2312
|
|
|
2256
2313
|
/* @overload __nunique__(axis, keep_axis)
|
|
2257
2314
|
|
|
2258
|
-
INTERNAL (CArray#nunique). Count the distinct values along axis
|
|
2259
|
-
pass per fiber with an independent
|
|
2260
|
-
CA_INT64 CArray of self.shape with
|
|
2261
|
-
keep_axis). Masked cells do not participate; an all-masked fiber counts 0
|
|
2315
|
+
INTERNAL (CArray#nunique). Count the distinct values along axis (an Integer
|
|
2316
|
+
or an Array of them), one linear pass per fiber with an independent
|
|
2317
|
+
seen-set. Returns a reduced CA_INT64 CArray of self.shape with the axes
|
|
2318
|
+
removed (or kept as length-1 when keep_axis). Masked cells do not participate; an all-masked fiber counts 0
|
|
2262
2319
|
(an empty set has zero distinct values, not UNDEF -- nunique has identity 0).
|
|
2263
2320
|
Numeric distinctness collapses all NaN to one value and treats -0.0 == +0.0;
|
|
2264
2321
|
object keys on rb_hash + rb_eql and fixlen on a byte-hash + memcmp, reproducing
|
|
@@ -2290,14 +2347,11 @@ fz_nunique_body (VALUE arg)
|
|
|
2290
2347
|
rb_raise(rb_eRuntimeError, "__nunique__: need ndim >= 1");
|
|
2291
2348
|
}
|
|
2292
2349
|
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
rb_raise(rb_eArgError, "__nunique__: axis %d out of range", axis);
|
|
2296
|
-
}
|
|
2350
|
+
int8_t axes[CA_RANK_MAX];
|
|
2351
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw_ctx(vaxis, ca, axes, "nunique");
|
|
2297
2352
|
int keep_axis = RTEST(vkeep);
|
|
2298
2353
|
|
|
2299
|
-
|
|
2300
|
-
VALUE vout = rb_ca_new_reduced(self, &ax, 1, CA_INT64, keep_axis);
|
|
2354
|
+
VALUE vout = rb_ca_new_reduced(self, axes, naxes, CA_INT64, keep_axis);
|
|
2301
2355
|
CArray *cout;
|
|
2302
2356
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, cout);
|
|
2303
2357
|
int64_t *op = (int64_t *) cout->ptr;
|
|
@@ -2308,7 +2362,7 @@ fz_nunique_body (VALUE arg)
|
|
|
2308
2362
|
else { fz_hash_init(&h); }
|
|
2309
2363
|
|
|
2310
2364
|
ca_iter_state *st = &fr->st[0];
|
|
2311
|
-
int rc = ca_iter_state_init_l2(st, ca, CA_SLAB_AXES,
|
|
2365
|
+
int rc = ca_iter_state_init_l2(st, ca, CA_SLAB_AXES, axes, naxes, 0);
|
|
2312
2366
|
if ( rc != CA_ITER_OK ) {
|
|
2313
2367
|
fz_hash_free(&h);
|
|
2314
2368
|
rb_raise(rb_eRuntimeError, "__nunique__: kernel_iterator init failed rc=%d", rc);
|
|
@@ -2641,7 +2695,7 @@ fz_mode_axis_body (VALUE arg)
|
|
|
2641
2695
|
VALUE vaxis = fr->a;
|
|
2642
2696
|
CArray *ca;
|
|
2643
2697
|
volatile VALUE face;
|
|
2644
|
-
self = fz_face_descend(self, &face, "mode");
|
|
2698
|
+
fr->self = self = fz_face_descend(self, &face, "mode");
|
|
2645
2699
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2646
2700
|
|
|
2647
2701
|
int8_t dt = ca->data_type;
|