carray 3.0.4 → 3.0.5
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 +205 -0
- data/carray.gemspec +1 -1
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_dispatch.c +13 -20
- data/ext/ca_categorical_iterator.c +27 -20
- data/ext/ca_compare.c +4 -4
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_kernel_iterator.c +6 -6
- data/ext/ca_kernel_iterator.h +112 -83
- data/ext/ca_obj_array.c +69 -19
- data/ext/ca_obj_bincmp.c +1 -0
- data/ext/ca_obj_binop.c +1 -0
- data/ext/ca_obj_bitarray.c +5 -1
- data/ext/ca_obj_bitfield.c +58 -43
- data/ext/ca_obj_byte_swap.c +2 -1
- data/ext/ca_obj_const_string.c +15 -3
- data/ext/ca_obj_face.c +42 -1
- data/ext/ca_obj_field.c +13 -3
- data/ext/ca_obj_grid.c +52 -5
- data/ext/ca_obj_monop.c +46 -10
- data/ext/ca_obj_object.c +64 -12
- data/ext/ca_obj_record.c +3 -0
- data/ext/ca_obj_reduce.c +4 -0
- data/ext/ca_obj_refer.c +18 -9
- data/ext/ca_obj_roll.c +26 -6
- data/ext/ca_obj_select.c +34 -5
- data/ext/ca_obj_shift.c +31 -7
- data/ext/ca_obj_stack.c +1 -0
- data/ext/ca_obj_stride.c +28 -19
- data/ext/ca_obj_string.c +11 -2
- data/ext/ca_obj_tile.c +27 -7
- data/ext/ca_obj_transpose.c +8 -4
- data/ext/ca_obj_triop.c +3 -0
- data/ext/ca_obj_window.c +79 -50
- data/ext/ca_op_ipower.c +4 -4
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/carray.h +33 -0
- data/ext/carray_access.c +16 -3
- data/ext/carray_attribute.c +24 -0
- data/ext/carray_cast.c +243 -82
- data/ext/carray_cast_func.rb +56 -26
- data/ext/carray_conversion.c +2 -2
- data/ext/carray_core.c +3 -0
- data/ext/carray_count.c +6 -0
- data/ext/carray_element.c +9 -4
- data/ext/carray_factorize.c +20 -20
- data/ext/carray_generate.c +8 -2
- data/ext/carray_histogram.c +1 -1
- data/ext/carray_index_classifier.c +4 -4
- data/ext/carray_internal.h +12 -0
- data/ext/carray_kernels_bincmp.c +168 -168
- data/ext/carray_kernels_binop.c +900 -900
- data/ext/carray_kernels_init.c +4 -4
- data/ext/carray_kernels_moncmp.c +96 -96
- data/ext/carray_kernels_monop.c +1984 -1984
- data/ext/carray_kernels_reduce_aggregate.c +1733 -1733
- data/ext/carray_kernels_reduce_cumulative.c +642 -642
- data/ext/carray_kernels_reduce_extreme.c +1150 -1150
- data/ext/carray_kernels_reduce_variance.c +258 -258
- data/ext/carray_kernels_scan.c +128 -128
- data/ext/carray_kernels_search.c +340 -340
- data/ext/carray_kernels_sort.c +295 -304
- data/ext/carray_kernels_triop.c +114 -114
- data/ext/carray_key_windows.c +4 -0
- data/ext/carray_mask.c +45 -22
- data/ext/carray_memory_view.c +2 -2
- data/ext/carray_operator.c +5 -5
- data/ext/carray_order.c +227 -8
- data/ext/carray_random.c +18 -18
- data/ext/carray_scatter.c +24 -7
- data/ext/carray_slab.c +32 -9
- data/ext/carray_sort.c +224 -16
- data/ext/carray_sort_kernel.c +5 -7
- data/ext/carray_struct.c +35 -43
- data/ext/carray_time_text.c +4 -2
- data/ext/carray_utils.c +63 -21
- data/ext/mkkernel.rb +210 -115
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +17 -4
- data/lib/carray/basics.rb +27 -7
- data/lib/carray/categorical.rb +30 -16
- data/lib/carray/categorical_iterator.rb +6 -6
- data/lib/carray/const_string.rb +10 -0
- data/lib/carray/data_type_extension.rb +8 -1
- data/lib/carray/fixlen_string.rb +41 -2
- data/lib/carray/frame/column_verbs.rb +4 -3
- data/lib/carray/frame/concat.rb +17 -3
- data/lib/carray/frame/frame.rb +6 -7
- data/lib/carray/frame/group.rb +100 -13
- data/lib/carray/frame/io.rb +3 -1
- data/lib/carray/fuse_source.rb +31 -2
- data/lib/carray/lazy.rb +35 -0
- data/lib/carray/methods/is_in.rb +8 -1
- data/lib/carray/segment_iterator.rb +12 -8
- data/lib/carray/serialize.rb +19 -2
- data/lib/carray/stack.rb +15 -12
- data/lib/carray/string.rb +8 -0
- data/lib/carray/string_operation_extension.rb +13 -5
- data/lib/carray/struct_builder.rb +5 -3
- data/lib/carray/time.rb +107 -68
- data/yard-stubs/ca_obj_transpose.rb +5 -4
- data/yard-stubs/carray_attribute.rb +3 -1
- data/yard-stubs/carray_cast.rb +2 -0
- data/yard-stubs/carray_conversion.rb +5 -1
- data/yard-stubs/carray_element.rb +7 -6
- data/yard-stubs/carray_mask.rb +8 -3
- data/yard-stubs/carray_math.rb +14 -4
- data/yard-stubs/carray_order.rb +100 -4
- data/yard-stubs/carray_scatter.rb +7 -5
- metadata +1 -1
data/ext/carray_cast.c
CHANGED
|
@@ -1215,26 +1215,48 @@ typedef struct {
|
|
|
1215
1215
|
boolean8_t *scratch;
|
|
1216
1216
|
} ca_to_type_ctx_t;
|
|
1217
1217
|
|
|
1218
|
-
/*
|
|
1219
|
-
|
|
1220
|
-
|
|
1218
|
+
/* Whether a double truncates into integer type `dt`: not NaN, not an
|
|
1219
|
+
infinity, and inside the open interval of values whose integer part `dt`
|
|
1220
|
+
holds (closed below for int64: -2**63-1 rounds to -2**63 in double).
|
|
1221
|
+
The same bounds as the generated casts in carray_cast_func.rb. */
|
|
1222
|
+
static int
|
|
1223
|
+
ca_double_fits_integer (double v, int8_t dt)
|
|
1224
|
+
{
|
|
1225
|
+
switch ( dt ) {
|
|
1226
|
+
case CA_INT8: return v > -129.0 && v < 128.0;
|
|
1227
|
+
case CA_UINT8: return v > -1.0 && v < 256.0;
|
|
1228
|
+
case CA_INT16: return v > -32769.0 && v < 32768.0;
|
|
1229
|
+
case CA_UINT16: return v > -1.0 && v < 65536.0;
|
|
1230
|
+
case CA_INT32: return v > -2147483649.0 && v < 2147483648.0;
|
|
1231
|
+
case CA_UINT32: return v > -1.0 && v < 4294967296.0;
|
|
1232
|
+
case CA_INT64: return v >= -9223372036854775808.0 && v < 9223372036854775808.0;
|
|
1233
|
+
case CA_UINT64: return v > -1.0 && v < 18446744073709551616.0;
|
|
1234
|
+
default: return 1;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/* Marks in `m` the cells of a float or complex array that have no integer
|
|
1239
|
+
of type `dt`: NaN (in either part), an infinity, or a value out of
|
|
1240
|
+
range. C leaves their conversion undefined, and machines differ. */
|
|
1221
1241
|
static void
|
|
1222
|
-
|
|
1242
|
+
ca_mark_unconvertible (CArray *ca, boolean8_t *m, int8_t dt)
|
|
1223
1243
|
{
|
|
1224
1244
|
ca_size_t i, n = ca->elements;
|
|
1225
1245
|
switch ( ca->data_type ) {
|
|
1226
|
-
case CA_FLOAT32: {
|
|
1227
|
-
for (i=0; i<n; i++) if (
|
|
1246
|
+
case CA_FLOAT32: { ca_u_float32_t *p = (ca_u_float32_t *) ca->ptr;
|
|
1247
|
+
for (i=0; i<n; i++) if ( ! ca_double_fits_integer(p[i], dt) ) m[i] = 1;
|
|
1228
1248
|
break; }
|
|
1229
|
-
case CA_FLOAT64: {
|
|
1230
|
-
for (i=0; i<n; i++) if (
|
|
1249
|
+
case CA_FLOAT64: { ca_u_float64_t *p = (ca_u_float64_t *) ca->ptr;
|
|
1250
|
+
for (i=0; i<n; i++) if ( ! ca_double_fits_integer(p[i], dt) ) m[i] = 1;
|
|
1231
1251
|
break; }
|
|
1232
1252
|
#ifdef HAVE_COMPLEX_H
|
|
1233
|
-
case CA_CMPLX64: {
|
|
1234
|
-
for (i=0; i<n; i++)
|
|
1253
|
+
case CA_CMPLX64: { ca_u_cmplx64_t *p = (ca_u_cmplx64_t *) ca->ptr;
|
|
1254
|
+
for (i=0; i<n; i++)
|
|
1255
|
+
if ( ! ca_double_fits_integer(crealf(p[i]), dt) || isnan(cimagf(p[i])) ) m[i] = 1;
|
|
1235
1256
|
break; }
|
|
1236
|
-
case CA_CMPLX128: {
|
|
1237
|
-
for (i=0; i<n; i++)
|
|
1257
|
+
case CA_CMPLX128: { ca_u_cmplx128_t *p = (ca_u_cmplx128_t *) ca->ptr;
|
|
1258
|
+
for (i=0; i<n; i++)
|
|
1259
|
+
if ( ! ca_double_fits_integer(creal(p[i]), dt) || isnan(cimag(p[i])) ) m[i] = 1;
|
|
1238
1260
|
break; }
|
|
1239
1261
|
#endif
|
|
1240
1262
|
default:
|
|
@@ -1274,11 +1296,11 @@ ca_to_type_cast (VALUE arg)
|
|
|
1274
1296
|
else {
|
|
1275
1297
|
memset(scratch, 0, ne);
|
|
1276
1298
|
}
|
|
1277
|
-
/* float -> integer: a
|
|
1278
|
-
|
|
1279
|
-
|
|
1299
|
+
/* float -> integer: a cell with no integer of the type (NaN, an
|
|
1300
|
+
infinity, a value out of range) becomes UNDEF, as an unparseable
|
|
1301
|
+
object cell does. */
|
|
1280
1302
|
if ( from_float ) {
|
|
1281
|
-
|
|
1303
|
+
ca_mark_unconvertible(ca, scratch, cb->data_type);
|
|
1282
1304
|
memset(cb->ptr, 0, ne * cb->bytes);
|
|
1283
1305
|
}
|
|
1284
1306
|
ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
|
|
@@ -2017,7 +2039,9 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
|
|
|
2017
2039
|
else {
|
|
2018
2040
|
CArray *ca_tmp;
|
|
2019
2041
|
volatile VALUE ref = obj;
|
|
2020
|
-
ca_size_t
|
|
2042
|
+
ca_size_t bytes = ca_sizeof[data_type];
|
|
2043
|
+
CA_CHECK_BYTES_GIVEN(data_type, bytes);
|
|
2044
|
+
ca_size_t dim = RSTRING_LEN(ref)/bytes;
|
|
2021
2045
|
obj = rb_carray_new(data_type, 1, &dim, 0, NULL);
|
|
2022
2046
|
TypedData_Get_Struct(obj, CArray, &carray_data_type, ca_tmp);
|
|
2023
2047
|
memcpy(ca_tmp->ptr, RSTRING_PTR(ref), dim * ca_sizeof[data_type]);
|
|
@@ -2150,7 +2174,15 @@ ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
|
2150
2174
|
if ( cr->data_type != CA_FIXLEN ) {
|
|
2151
2175
|
return 0;
|
|
2152
2176
|
}
|
|
2153
|
-
|
|
2177
|
+
/* A String longer than the cell keeps its length: cut to the cell, it
|
|
2178
|
+
would equal a cell it does not (a two-byte "ab" equal to "abX"). The
|
|
2179
|
+
wider scalar is then compared as two fixlen widths are. */
|
|
2180
|
+
{
|
|
2181
|
+
ca_size_t len = (ca_size_t) RSTRING_LEN(*scalar);
|
|
2182
|
+
*scalar = rb_cscalar_new_with_value(CA_FIXLEN,
|
|
2183
|
+
len > cr->bytes ? len : cr->bytes,
|
|
2184
|
+
*scalar);
|
|
2185
|
+
}
|
|
2154
2186
|
return 1;
|
|
2155
2187
|
}
|
|
2156
2188
|
|
|
@@ -2240,6 +2272,69 @@ ca_integer_scalar_operand (volatile VALUE *scalar, VALUE reference)
|
|
|
2240
2272
|
return 1;
|
|
2241
2273
|
}
|
|
2242
2274
|
|
|
2275
|
+
/* A Ruby Array operand against a numeric or boolean array is read as its
|
|
2276
|
+
cells, as the array CArray.wrap_readonly makes of it (nested Arrays give
|
|
2277
|
+
its axes). Its data type is the
|
|
2278
|
+
one the cells would take one at a time as scalar operands of the same
|
|
2279
|
+
operation (an Integer
|
|
2280
|
+
against an integer array takes the array's type and has to fit it),
|
|
2281
|
+
promoted together. Against an object array, a Face or a fixlen array an
|
|
2282
|
+
Array stays one value. */
|
|
2283
|
+
static int
|
|
2284
|
+
ca_array_operand (volatile VALUE *ary, VALUE reference, int both)
|
|
2285
|
+
{
|
|
2286
|
+
CArray *cr;
|
|
2287
|
+
volatile VALUE flat, probe_self, probe;
|
|
2288
|
+
long i, n;
|
|
2289
|
+
int8_t type = -1, seen_fix = -1, seen_big = -1, seen_flo = -1, seen_cpx = -1,
|
|
2290
|
+
seen_bool = -1;
|
|
2291
|
+
|
|
2292
|
+
if ( ! RB_TYPE_P(*ary, T_ARRAY) || ! rb_obj_is_carray(reference) ) {
|
|
2293
|
+
return 0;
|
|
2294
|
+
}
|
|
2295
|
+
TypedData_Get_Struct(reference, CArray, &carray_data_type, cr);
|
|
2296
|
+
if ( ca_is_face(cr) || ca_is_object_type(cr) || ca_is_fixlen_type(cr) ) {
|
|
2297
|
+
return 0;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
flat = rb_funcall(*ary, rb_intern("flatten"), 0);
|
|
2301
|
+
n = RARRAY_LEN(flat);
|
|
2302
|
+
for (i = 0; i < n; i++) {
|
|
2303
|
+
VALUE e = RARRAY_AREF(flat, i);
|
|
2304
|
+
int8_t *seen, t;
|
|
2305
|
+
CArray *cp;
|
|
2306
|
+
if ( FIXNUM_P(e) ) seen = &seen_fix;
|
|
2307
|
+
else if ( RB_TYPE_P(e, T_BIGNUM) ) seen = &seen_big;
|
|
2308
|
+
else if ( RB_FLOAT_TYPE_P(e) ) seen = &seen_flo;
|
|
2309
|
+
else if ( RB_TYPE_P(e, T_COMPLEX) ) seen = &seen_cpx;
|
|
2310
|
+
else if ( e == Qtrue || e == Qfalse ) seen = &seen_bool;
|
|
2311
|
+
else seen = NULL;
|
|
2312
|
+
if ( RB_INTEGER_TYPE_P(e) && ca_is_integer_type(cr) ) {
|
|
2313
|
+
ca_check_integer_fits(e, cr->data_type);
|
|
2314
|
+
}
|
|
2315
|
+
if ( seen && *seen >= 0 ) {
|
|
2316
|
+
continue;
|
|
2317
|
+
}
|
|
2318
|
+
probe_self = reference;
|
|
2319
|
+
probe = e;
|
|
2320
|
+
if ( both ) {
|
|
2321
|
+
rb_ca_cast_self_or_other(&probe_self, &probe);
|
|
2322
|
+
}
|
|
2323
|
+
else {
|
|
2324
|
+
rb_ca_cast_other((VALUE *) &probe_self, (volatile VALUE *) &probe);
|
|
2325
|
+
}
|
|
2326
|
+
TypedData_Get_Struct(probe, CArray, &carray_data_type, cp);
|
|
2327
|
+
t = cp->data_type;
|
|
2328
|
+
if ( seen ) *seen = t;
|
|
2329
|
+
type = ( type < 0 ) ? t : ca_promote_type(type, t);
|
|
2330
|
+
}
|
|
2331
|
+
if ( type < 0 ) {
|
|
2332
|
+
type = cr->data_type;
|
|
2333
|
+
}
|
|
2334
|
+
*ary = rb_ca_wrap_readonly(*ary, INT2NUM(type));
|
|
2335
|
+
return 1;
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2243
2338
|
/* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
|
|
2244
2339
|
returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
|
|
2245
2340
|
User doc lives in yard-stubs/carray_cast.rb. */
|
|
@@ -2304,6 +2399,10 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
2304
2399
|
*other = ca_operand_from_memory_view(*other);
|
|
2305
2400
|
}
|
|
2306
2401
|
|
|
2402
|
+
if ( ! ca_array_operand(other, *self, 1) ) {
|
|
2403
|
+
ca_array_operand(self, *other, 1);
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2307
2406
|
if ( ! rb_obj_is_carray(*self) ) {
|
|
2308
2407
|
self_is_object = 1;
|
|
2309
2408
|
if ( rb_ca_is_object_type(*other) ) {
|
|
@@ -2427,12 +2526,32 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
|
|
|
2427
2526
|
return;
|
|
2428
2527
|
}
|
|
2429
2528
|
|
|
2430
|
-
|
|
2529
|
+
/* A data type the operation does not take, as `sqrt!` on an integer
|
|
2530
|
+
array is refused (CArray::DataTypeError is a TypeError). */
|
|
2531
|
+
rb_raise(rb_eCADataTypeError,
|
|
2431
2532
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
2432
2533
|
ca_coerce_operand_name(*self, ca),
|
|
2433
2534
|
ca_coerce_operand_name(*other, cb));
|
|
2434
2535
|
}
|
|
2435
2536
|
|
|
2537
|
+
/* Refuses a pair of arrays with no common data_type in the words of
|
|
2538
|
+
rb_ca_cast_self_or_other (the eager operators'), and returns otherwise
|
|
2539
|
+
without casting either. A lazy builder calls it before it works out
|
|
2540
|
+
the kernel's data_types, so that a pair the eager operator refuses is
|
|
2541
|
+
refused the same way. */
|
|
2542
|
+
void
|
|
2543
|
+
ca_refuse_without_common_type (VALUE self, VALUE other)
|
|
2544
|
+
{
|
|
2545
|
+
CArray *ca, *cb;
|
|
2546
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2547
|
+
TypedData_Get_Struct(other, CArray, &carray_data_type, cb);
|
|
2548
|
+
if ( ca->data_type != cb->data_type
|
|
2549
|
+
&& ca_cast_table[cb->data_type][ca->data_type] < 0
|
|
2550
|
+
&& ca_cast_table[ca->data_type][cb->data_type] < 0 ) {
|
|
2551
|
+
rb_ca_cast_self_or_other(&self, &other); /* raises */
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2436
2555
|
/* CArray.cast_self_or_other(self, other) — promote self and other
|
|
2437
2556
|
* to a common data_type and return [self', other']. Wraps the
|
|
2438
2557
|
* void rb_ca_cast_self_or_other above into a class method.
|
|
@@ -2471,6 +2590,15 @@ ca_arg_to_data_type (VALUE obj)
|
|
|
2471
2590
|
/* MemoryView producer -> its format's data_type (T_STRING excluded above,
|
|
2472
2591
|
so a String never reaches here). data_type already assigned. */
|
|
2473
2592
|
}
|
|
2593
|
+
else if ( rb_memory_view_available_p(obj) ) {
|
|
2594
|
+
/* A MemoryView producer whose format says nothing usable (typeless, the
|
|
2595
|
+
other byte order) is read as the operators read it, and refused in
|
|
2596
|
+
the same words. */
|
|
2597
|
+
VALUE ca_obj = ca_operand_from_memory_view(obj);
|
|
2598
|
+
CArray *ca;
|
|
2599
|
+
TypedData_Get_Struct(ca_obj, CArray, &carray_data_type, ca);
|
|
2600
|
+
data_type = ca->data_type;
|
|
2601
|
+
}
|
|
2474
2602
|
else {
|
|
2475
2603
|
data_type = ca_value_to_data_type(obj);
|
|
2476
2604
|
}
|
|
@@ -2606,6 +2734,24 @@ ca_query_match_type (int8_t ref, VALUE query)
|
|
|
2606
2734
|
return ref;
|
|
2607
2735
|
}
|
|
2608
2736
|
|
|
2737
|
+
/* A fixlen array searched or counted for a String longer than its cells
|
|
2738
|
+
is read as cells of the String's width (NUL-padded), so the query is not
|
|
2739
|
+
cut to the cell: "abX" matches no two-byte cell, as a wider scalar does
|
|
2740
|
+
not in `eq`. Anything else is returned as given. */
|
|
2741
|
+
VALUE
|
|
2742
|
+
ca_fixlen_widen_for_query (VALUE self, VALUE query)
|
|
2743
|
+
{
|
|
2744
|
+
CArray *ca;
|
|
2745
|
+
if ( ! RB_TYPE_P(query, T_STRING) || ! rb_obj_is_carray(self) ) {
|
|
2746
|
+
return self;
|
|
2747
|
+
}
|
|
2748
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2749
|
+
if ( ca->data_type != CA_FIXLEN || RSTRING_LEN(query) <= ca->bytes ) {
|
|
2750
|
+
return self;
|
|
2751
|
+
}
|
|
2752
|
+
return rb_ca_to_type(self, INT2NUM(CA_FIXLEN), SIZE2NUM(RSTRING_LEN(query)));
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2609
2755
|
/* ca.query_match_type(query) -- ca_query_match_type with self as the
|
|
2610
2756
|
reference, for the set family and locate_addr. */
|
|
2611
2757
|
static VALUE
|
|
@@ -2641,7 +2787,7 @@ ca_arg_is_scalar (VALUE obj)
|
|
|
2641
2787
|
if ( TYPE(obj) == T_SYMBOL || TYPE(obj) == T_STRING || TYPE(obj) == T_CLASS ) {
|
|
2642
2788
|
return 0;
|
|
2643
2789
|
}
|
|
2644
|
-
return
|
|
2790
|
+
return ! rb_memory_view_available_p(obj);
|
|
2645
2791
|
}
|
|
2646
2792
|
|
|
2647
2793
|
/* The type a scalar `obj` (of type `st`) and an array of type `at` share,
|
|
@@ -2852,6 +2998,8 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
2852
2998
|
*other = ca_operand_from_memory_view(*other);
|
|
2853
2999
|
}
|
|
2854
3000
|
|
|
3001
|
+
ca_array_operand(other, *self, 0);
|
|
3002
|
+
|
|
2855
3003
|
if ( ! rb_obj_is_carray(*other) ) {
|
|
2856
3004
|
if ( rb_ca_is_object_type(*self) ) {
|
|
2857
3005
|
*other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
|
|
@@ -2894,7 +3042,9 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
|
|
|
2894
3042
|
return;
|
|
2895
3043
|
}
|
|
2896
3044
|
|
|
2897
|
-
|
|
3045
|
+
/* A data type the operation does not take, as `sqrt!` on an integer
|
|
3046
|
+
array is refused (CArray::DataTypeError is a TypeError). */
|
|
3047
|
+
rb_raise(rb_eCADataTypeError,
|
|
2898
3048
|
"can't coerce carray with data_types of '%s' and '%s'",
|
|
2899
3049
|
ca_coerce_operand_name(*self, ca),
|
|
2900
3050
|
ca_coerce_operand_name(*other, cb));
|
|
@@ -2920,78 +3070,89 @@ rb_ca_cast_with (VALUE self, VALUE other)
|
|
|
2920
3070
|
/* -----------------------------------------------------------------------
|
|
2921
3071
|
clip_<type> family — clip into the target data type's representable
|
|
2922
3072
|
range, then cast. Sugar for `clip(lo, hi).as_<type>`.
|
|
3073
|
+
|
|
3074
|
+
A float source takes a saturating path instead. The type's maximum is
|
|
3075
|
+
not always exact in the source float (INT64_MAX and UINT64_MAX round up
|
|
3076
|
+
in float64, INT32_MAX and UINT32_MAX in float32), so clip-then-cast
|
|
3077
|
+
would hand the cast a value just past the range. Instead each cell is
|
|
3078
|
+
compared in double against the range the cast truncates into
|
|
3079
|
+
(ca_double_fits_integer) and saturates to the type's minimum or maximum
|
|
3080
|
+
outside it. A NaN that is not masked is refused.
|
|
2923
3081
|
----------------------------------------------------------------------- */
|
|
2924
3082
|
|
|
2925
|
-
|
|
3083
|
+
static VALUE
|
|
3084
|
+
ca_clip_float_to_integer (VALUE self, int8_t to_dt)
|
|
3085
|
+
{
|
|
3086
|
+
CArray *ca;
|
|
3087
|
+
GetCArray(self, ca);
|
|
3088
|
+
volatile VALUE vsrc = ( ca->data_type == CA_FLOAT64 ) ? self : rb_ca_as_float64(self);
|
|
3089
|
+
CArray *src;
|
|
3090
|
+
GetCArray(vsrc, src);
|
|
3091
|
+
volatile VALUE vout = rb_carray_new(to_dt, ca->ndim, ca->dim, 0, NULL);
|
|
3092
|
+
CArray *out;
|
|
3093
|
+
GetCArray(vout, out);
|
|
3094
|
+
ca_attach(src); /* window: nothing raises inside */
|
|
3095
|
+
double *sp = (double *) src->ptr;
|
|
3096
|
+
char *op = out->ptr;
|
|
3097
|
+
ca_size_t n = ca->elements;
|
|
3098
|
+
boolean8_t *m = ca_has_mask(src) ? (boolean8_t *) src->mask->ptr : NULL; /* attached with src */
|
|
3099
|
+
int found_nan = 0;
|
|
3100
|
+
for ( ca_size_t i = 0; i < n; i++ ) {
|
|
3101
|
+
double v = sp[i];
|
|
3102
|
+
int fits = ca_double_fits_integer(v, to_dt);
|
|
3103
|
+
if ( v != v ) { /* NaN has no integer: refused below */
|
|
3104
|
+
v = 0.0;
|
|
3105
|
+
fits = 1;
|
|
3106
|
+
if ( ! m || ! m[i] ) found_nan = 1;
|
|
3107
|
+
}
|
|
3108
|
+
#define CLIP_STORE(type, lo, hi) \
|
|
3109
|
+
((type *) op)[i] = fits ? (type) v : ( v > 0 ? (hi) : (lo) )
|
|
3110
|
+
switch ( to_dt ) {
|
|
3111
|
+
case CA_INT8: CLIP_STORE(int8_t, INT8_MIN, INT8_MAX); break;
|
|
3112
|
+
case CA_UINT8: CLIP_STORE(uint8_t, 0, UINT8_MAX); break;
|
|
3113
|
+
case CA_INT16: CLIP_STORE(int16_t, INT16_MIN, INT16_MAX); break;
|
|
3114
|
+
case CA_UINT16: CLIP_STORE(uint16_t, 0, UINT16_MAX); break;
|
|
3115
|
+
case CA_INT32: CLIP_STORE(int32_t, INT32_MIN, INT32_MAX); break;
|
|
3116
|
+
case CA_UINT32: CLIP_STORE(uint32_t, 0, UINT32_MAX); break;
|
|
3117
|
+
case CA_INT64: CLIP_STORE(int64_t, INT64_MIN, INT64_MAX); break;
|
|
3118
|
+
case CA_UINT64: CLIP_STORE(uint64_t, 0, UINT64_MAX); break;
|
|
3119
|
+
}
|
|
3120
|
+
#undef CLIP_STORE
|
|
3121
|
+
}
|
|
3122
|
+
ca_detach(src);
|
|
3123
|
+
if ( found_nan ) {
|
|
3124
|
+
rb_raise(rb_eFloatDomainError, "%s: NaN cannot be converted to %s",
|
|
3125
|
+
ca_calling_method_name(), ca_type_name[to_dt]);
|
|
3126
|
+
}
|
|
3127
|
+
if ( ca_has_mask(ca) ) {
|
|
3128
|
+
ca_copy_mask(out, ca);
|
|
3129
|
+
}
|
|
3130
|
+
return vout;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
#define CLIP_CAST_FUNC(name, to_dt, lo_expr, hi_expr, cast_func) \
|
|
2926
3134
|
static VALUE \
|
|
2927
3135
|
rb_ca_##name (VALUE self) \
|
|
2928
3136
|
{ \
|
|
3137
|
+
CArray *ca; \
|
|
3138
|
+
GetCArray(self, ca); \
|
|
3139
|
+
if ( ca->data_type == CA_FLOAT32 || ca->data_type == CA_FLOAT64 ) { \
|
|
3140
|
+
return ca_clip_float_to_integer(self, to_dt); \
|
|
3141
|
+
} \
|
|
2929
3142
|
return cast_func(rb_ca_clip(self, lo_expr, hi_expr)); \
|
|
2930
3143
|
}
|
|
2931
3144
|
|
|
2932
|
-
CLIP_CAST_FUNC(clip_int8, INT2NUM(-128),
|
|
2933
|
-
CLIP_CAST_FUNC(clip_int16, INT2NUM(-32768),
|
|
2934
|
-
CLIP_CAST_FUNC(clip_int32, INT2NUM(-2147483648),
|
|
2935
|
-
CLIP_CAST_FUNC(clip_int64, LL2NUM(-9223372036854775807-1),
|
|
2936
|
-
CLIP_CAST_FUNC(clip_uint8, INT2NUM(0),
|
|
2937
|
-
CLIP_CAST_FUNC(clip_uint16, INT2NUM(0),
|
|
2938
|
-
CLIP_CAST_FUNC(clip_uint32, INT2NUM(0),
|
|
3145
|
+
CLIP_CAST_FUNC(clip_int8, CA_INT8, INT2NUM(-128), INT2NUM(127), rb_ca_as_int8)
|
|
3146
|
+
CLIP_CAST_FUNC(clip_int16, CA_INT16, INT2NUM(-32768), INT2NUM(32767), rb_ca_as_int16)
|
|
3147
|
+
CLIP_CAST_FUNC(clip_int32, CA_INT32, INT2NUM(-2147483648), INT2NUM(2147483647), rb_ca_as_int32)
|
|
3148
|
+
CLIP_CAST_FUNC(clip_int64, CA_INT64, LL2NUM(-9223372036854775807-1), LL2NUM(9223372036854775807), rb_ca_as_int64)
|
|
3149
|
+
CLIP_CAST_FUNC(clip_uint8, CA_UINT8, INT2NUM(0), INT2NUM(255), rb_ca_as_uint8)
|
|
3150
|
+
CLIP_CAST_FUNC(clip_uint16, CA_UINT16, INT2NUM(0), INT2NUM(65535), rb_ca_as_uint16)
|
|
3151
|
+
CLIP_CAST_FUNC(clip_uint32, CA_UINT32, INT2NUM(0), UINT2NUM(4294967295U), rb_ca_as_uint32)
|
|
3152
|
+
CLIP_CAST_FUNC(clip_uint64, CA_UINT64, INT2NUM(0), ULL2NUM(18446744073709551615ULL), rb_ca_as_uint64)
|
|
2939
3153
|
|
|
2940
3154
|
#undef CLIP_CAST_FUNC
|
|
2941
3155
|
|
|
2942
|
-
/* CArray#clip_uint64 -- dedicated implementation.
|
|
2943
|
-
|
|
2944
|
-
UINT64_MAX (= 2^64-1) is not exactly representable in float64; the nearest
|
|
2945
|
-
double rounds up to 2^64. A generic clip-then-cast path therefore clamps
|
|
2946
|
-
an overflowing float source (e.g. 1e20) to 2^64 and the subsequent cast to
|
|
2947
|
-
uint64 wraps around to 0. For floating-point sources we take a saturating
|
|
2948
|
-
path: compare in float space against 2^64 (which IS representable) and
|
|
2949
|
-
saturate to UINT64_MAX above it and 0 below zero. Other source data types use
|
|
2950
|
-
the plain clip-then-cast path. */
|
|
2951
|
-
static VALUE
|
|
2952
|
-
rb_ca_clip_uint64 (VALUE self)
|
|
2953
|
-
{
|
|
2954
|
-
CArray *ca;
|
|
2955
|
-
GetCArray(self, ca);
|
|
2956
|
-
int dt = ca->data_type;
|
|
2957
|
-
if ( dt == CA_FLOAT32 || dt == CA_FLOAT64 ) {
|
|
2958
|
-
volatile VALUE vsrc = ( dt == CA_FLOAT64 ) ? self : rb_ca_as_float64(self);
|
|
2959
|
-
CArray *src;
|
|
2960
|
-
GetCArray(vsrc, src);
|
|
2961
|
-
volatile VALUE vout = rb_carray_new(CA_UINT64, ca->ndim, ca->dim, 0, NULL);
|
|
2962
|
-
CArray *out;
|
|
2963
|
-
GetCArray(vout, out);
|
|
2964
|
-
ca_attach(src); /* window: nothing raises inside */
|
|
2965
|
-
double *sp = (double *) src->ptr;
|
|
2966
|
-
uint64_t *op = (uint64_t *) out->ptr;
|
|
2967
|
-
ca_size_t n = ca->elements;
|
|
2968
|
-
const double LIMIT = 18446744073709551616.0; /* 2^64, exact in f64 */
|
|
2969
|
-
boolean8_t *m = ca_has_mask(src) ? (boolean8_t *) src->mask->ptr : NULL; /* attached with src */
|
|
2970
|
-
int found_nan = 0;
|
|
2971
|
-
for ( ca_size_t i = 0; i < n; i++ ) {
|
|
2972
|
-
double v = sp[i];
|
|
2973
|
-
if ( v != v ) { /* NaN has no integer: refused below */
|
|
2974
|
-
op[i] = 0;
|
|
2975
|
-
if ( ! m || ! m[i] ) found_nan = 1;
|
|
2976
|
-
}
|
|
2977
|
-
else if ( v >= LIMIT ) op[i] = UINT64_MAX;
|
|
2978
|
-
else if ( v <= 0.0 ) op[i] = 0;
|
|
2979
|
-
else op[i] = (uint64_t) v;
|
|
2980
|
-
}
|
|
2981
|
-
ca_detach(src);
|
|
2982
|
-
if ( found_nan ) {
|
|
2983
|
-
rb_raise(rb_eFloatDomainError, "%s: NaN cannot be converted to uint64",
|
|
2984
|
-
ca_calling_method_name());
|
|
2985
|
-
}
|
|
2986
|
-
if ( ca_has_mask(ca) ) {
|
|
2987
|
-
ca_copy_mask(out, ca);
|
|
2988
|
-
}
|
|
2989
|
-
return vout;
|
|
2990
|
-
}
|
|
2991
|
-
return rb_ca_as_uint64(rb_ca_clip(self, INT2NUM(0),
|
|
2992
|
-
ULL2NUM(18446744073709551615ULL)));
|
|
2993
|
-
}
|
|
2994
|
-
|
|
2995
3156
|
/* ------------------------------------------------------------------------
|
|
2996
3157
|
Global cast functions CA_INT32(data) ... CA_OBJECT(data) etc.
|
|
2997
3158
|
|
data/ext/carray_cast_func.rb
CHANGED
|
@@ -24,6 +24,19 @@ type_const = {}
|
|
|
24
24
|
type_const[i] = name
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# The open interval (lo, hi) of doubles whose integer part a type holds:
|
|
28
|
+
# a cast truncates toward zero, so -128.5 still fits int8.
|
|
29
|
+
INTEGER_TRUNC_RANGE = {
|
|
30
|
+
CA_INT8 => ["-129.0", "128.0"],
|
|
31
|
+
CA_UINT8 => ["-1.0", "256.0"],
|
|
32
|
+
CA_INT16 => ["-32769.0", "32768.0"],
|
|
33
|
+
CA_UINT16 => ["-1.0", "65536.0"],
|
|
34
|
+
CA_INT32 => ["-2147483649.0", "2147483648.0"],
|
|
35
|
+
CA_UINT32 => ["-1.0", "4294967296.0"],
|
|
36
|
+
CA_INT64 => ["-9223372036854775808.0", "9223372036854775808.0"],
|
|
37
|
+
CA_UINT64 => ["-1.0", "18446744073709551616.0"],
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
ctype = {
|
|
28
41
|
CA_FIXLEN => "fixlen",
|
|
29
42
|
CA_BOOLEAN => "boolean8_t",
|
|
@@ -42,6 +55,12 @@ ctype = {
|
|
|
42
55
|
CA_OBJECT => "VALUE"
|
|
43
56
|
}
|
|
44
57
|
|
|
58
|
+
# The type a cast reads and writes a cell through. A view's cells need not
|
|
59
|
+
# be aligned to their size (a struct member at offset 1, a refer with a
|
|
60
|
+
# byte offset), so a pointer to a multi-byte cell is the unaligned typedef
|
|
61
|
+
# from carray.h; ctype stays the plain name the functions are called by.
|
|
62
|
+
utype = Hash.new { |h, c| h[c] = %w[fixlen boolean8_t int8_t uint8_t].include?(c) ? c : "ca_u_#{c}" }
|
|
63
|
+
|
|
45
64
|
obj2cval = {
|
|
46
65
|
CA_FIXLEN => nil,
|
|
47
66
|
CA_BOOLEAN => "OBJ2BOOL",
|
|
@@ -256,7 +275,7 @@ FIXLEN.each do |type1|
|
|
|
256
275
|
{
|
|
257
276
|
char *p1 = ptr1;
|
|
258
277
|
ca_size_t bytes;
|
|
259
|
-
|
|
278
|
+
ca_u_VALUE *p2 = ptr2;
|
|
260
279
|
if ( a1 == NULL ) {
|
|
261
280
|
rb_raise(rb_eRuntimeError, "[BUG] failed to cast fixlen -> object");
|
|
262
281
|
}
|
|
@@ -291,8 +310,8 @@ puts
|
|
|
291
310
|
static void
|
|
292
311
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
293
312
|
{
|
|
294
|
-
#{ctype1} *p1 = ptr1;
|
|
295
|
-
#{ctype2} *p2 = ptr2;
|
|
313
|
+
#{utype[ctype1]} *p1 = ptr1;
|
|
314
|
+
#{utype[ctype2]} *p2 = ptr2;
|
|
296
315
|
#{ctype1} q;
|
|
297
316
|
if ( m ) {
|
|
298
317
|
while ( n-- ) {
|
|
@@ -336,22 +355,33 @@ puts
|
|
|
336
355
|
ctype1 = ctype[type1]
|
|
337
356
|
ctype2 = ctype[type2]
|
|
338
357
|
CA_CAST_TABLE[type1][type2] = "ca_cast_#{ctype1}_#{ctype2}"
|
|
339
|
-
# float / complex -> integer: a NaN
|
|
340
|
-
#
|
|
341
|
-
#
|
|
342
|
-
#
|
|
358
|
+
# float / complex -> integer: a NaN, an infinity, or a value whose
|
|
359
|
+
# integer part the type cannot hold has no integer, and C leaves its
|
|
360
|
+
# conversion undefined (x86 gives the type's minimum, ARM saturates). A
|
|
361
|
+
# cell that is not masked refuses it before anything is written.
|
|
362
|
+
# #to_type masks such cells first (UNDEF), so only a store, a view and a
|
|
363
|
+
# single cell reach the raise. The range is the open interval of values
|
|
364
|
+
# that truncate into the type, in double; for int64 the lower end is
|
|
365
|
+
# taken as closed, since -2**63-1 rounds to -2**63 in double.
|
|
343
366
|
nan_check = ""
|
|
344
367
|
if (FLOAT+[CA_CMPLX64, CA_CMPLX128]).include?(type1) && INTEGER.include?(type2)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
368
|
+
complex = [CA_CMPLX64, CA_CMPLX128].include?(type1)
|
|
369
|
+
real = complex ? "creal(q1[k])" : "q1[k]"
|
|
370
|
+
lo, hi = INTEGER_TRUNC_RANGE[type2]
|
|
371
|
+
lo_cmp = ( type2 == CA_INT64 ) ? ">=" : ">"
|
|
372
|
+
fits = "( v #{lo_cmp} #{lo} && v < #{hi} )"
|
|
373
|
+
fits = "( #{fits} && ! isnan(cimag(q1[k])) )" if complex
|
|
350
374
|
nan_check = <<-END_CHECK.gsub(/^ {6}/, '')
|
|
351
375
|
for (k=0; k<n; k++) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
376
|
+
double v = (double) #{real};
|
|
377
|
+
if ( ( ! m || ! m[k] ) && ! #{fits} ) {
|
|
378
|
+
if ( isfinite(v)#{complex ? " && ! isnan(cimag(q1[k]))" : ""} ) {
|
|
379
|
+
rb_raise(rb_eRangeError, "%s: %.17g is out of range for %s",
|
|
380
|
+
ca_calling_method_name(), v, ca_type_name[#{type_const[type2]}]);
|
|
381
|
+
}
|
|
382
|
+
rb_raise(rb_eFloatDomainError, "%s: %s cannot be converted to %s",
|
|
383
|
+
ca_calling_method_name(), isinf(v) ? "an infinity" : "NaN",
|
|
384
|
+
ca_type_name[#{type_const[type2]}]);
|
|
355
385
|
}
|
|
356
386
|
}
|
|
357
387
|
END_CHECK
|
|
@@ -367,10 +397,10 @@ puts
|
|
|
367
397
|
static void
|
|
368
398
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
369
399
|
{
|
|
370
|
-
#{ctype1} *q1 = ptr1;
|
|
371
|
-
#{ctype1} *p1 = q1;
|
|
372
|
-
#{ctype2} *q2 = ptr2;
|
|
373
|
-
#{ctype2} *p2 = q2;
|
|
400
|
+
#{utype[ctype1]} *q1 = ptr1;
|
|
401
|
+
#{utype[ctype1]} *p1 = q1;
|
|
402
|
+
#{utype[ctype2]} *q2 = ptr2;
|
|
403
|
+
#{utype[ctype2]} *p2 = q2;
|
|
374
404
|
ca_size_t k;
|
|
375
405
|
@@NAN_CHECK@@
|
|
376
406
|
if ( m ) {
|
|
@@ -412,8 +442,8 @@ puts
|
|
|
412
442
|
static void
|
|
413
443
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
414
444
|
{
|
|
415
|
-
#{ctype1} *p1 = ptr1;
|
|
416
|
-
|
|
445
|
+
#{utype[ctype1]} *p1 = ptr1;
|
|
446
|
+
ca_u_VALUE *p2 = ptr2;
|
|
417
447
|
if ( m ) {
|
|
418
448
|
while ( n-- ) {
|
|
419
449
|
if ( !*m ) { *p2 = (VALUE) #{conv}(*p1); }
|
|
@@ -441,7 +471,7 @@ OBJECT.each do |type1|
|
|
|
441
471
|
static void
|
|
442
472
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
443
473
|
{
|
|
444
|
-
|
|
474
|
+
ca_u_VALUE *p1 = ptr1;
|
|
445
475
|
char *p2 = ptr2;
|
|
446
476
|
ca_size_t bytes;
|
|
447
477
|
if ( a2 == NULL ) {
|
|
@@ -529,8 +559,8 @@ OBJECT.each do |type1|
|
|
|
529
559
|
static void
|
|
530
560
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
531
561
|
{
|
|
532
|
-
|
|
533
|
-
#{ctype2} *p2 = ptr2;
|
|
562
|
+
ca_u_VALUE *p1 = ptr1;
|
|
563
|
+
#{utype[ctype2]} *p2 = ptr2;
|
|
534
564
|
#{oktype2} tmp;
|
|
535
565
|
if ( m ) {
|
|
536
566
|
while ( n-- ) {
|
|
@@ -557,8 +587,8 @@ OBJECT.each do |type1|
|
|
|
557
587
|
static void
|
|
558
588
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
559
589
|
{
|
|
560
|
-
|
|
561
|
-
#{ctype2} *p2 = ptr2;
|
|
590
|
+
ca_u_VALUE *p1 = ptr1;
|
|
591
|
+
#{utype[ctype2]} *p2 = ptr2;
|
|
562
592
|
if ( m ) {
|
|
563
593
|
while ( n-- ) {
|
|
564
594
|
if ( !*m ) { *p2 = (#{ctype2}) #{conv}(*p1); }
|
data/ext/carray_conversion.c
CHANGED
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
/* Leaf macro: data type-specialized inner loop. Produces `n` VALUE objects
|
|
31
31
|
from a contig ptr base + element width, storing into `dst` (Ruby Array). */
|
|
32
32
|
#define TO_A_LEAF_LOOP(T, TO_VALUE) do { \
|
|
33
|
-
const T *src = (const T *) base; \
|
|
33
|
+
const CA_U(T) *src = (const CA_U(T) *) base; \
|
|
34
34
|
for (li = 0; li < n; li++) { \
|
|
35
35
|
rb_ary_store(dst, li, TO_VALUE(src[li])); \
|
|
36
36
|
} \
|
|
37
37
|
} while (0)
|
|
38
38
|
|
|
39
39
|
#define TO_A_LEAF_LOOP_MASKED(T, TO_VALUE) do { \
|
|
40
|
-
const T *src = (const T *) base; \
|
|
40
|
+
const CA_U(T) *src = (const CA_U(T) *) base; \
|
|
41
41
|
for (li = 0; li < n; li++) { \
|
|
42
42
|
rb_ary_store(dst, li, mask[li] ? CA_UNDEF : TO_VALUE(src[li])); \
|
|
43
43
|
} \
|
data/ext/carray_core.c
CHANGED
|
@@ -2955,6 +2955,9 @@ ca_face_field_lookup (VALUE self, VALUE sym)
|
|
|
2955
2955
|
vtype_sym = ID2SYM(rb_intern(vtype_name));
|
|
2956
2956
|
word_view = rb_funcall(receiver, rb_intern("field"), 2,
|
|
2957
2957
|
SIZE2NUM(start_byte), vtype_sym);
|
|
2958
|
+
/* little-endian on every host, as the layout numbers the bits */
|
|
2959
|
+
word_view = rb_funcall(word_view, rb_intern("endian"), 1,
|
|
2960
|
+
ID2SYM(rb_intern("little")));
|
|
2958
2961
|
range = rb_range_new(LONG2NUM(bit_in_word),
|
|
2959
2962
|
SIZE2NUM(bit_in_word + bits - 1), 0);
|
|
2960
2963
|
obj = rb_funcall(word_view, rb_intern("bitfield"), 1, range);
|
data/ext/carray_count.c
CHANGED
|
@@ -252,8 +252,10 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
|
|
|
252
252
|
int8_t slab_axes[CA_RANK_MAX];
|
|
253
253
|
int8_t naxes;
|
|
254
254
|
VALUE axis_val = Qnil;
|
|
255
|
+
int keep_axis = 0;
|
|
255
256
|
if ( ! NIL_P(opt_hash) ) {
|
|
256
257
|
axis_val = rb_hash_lookup2(opt_hash, ID2SYM(rb_intern("axis")), Qnil);
|
|
258
|
+
keep_axis = RTEST(rb_hash_lookup2(opt_hash, ID2SYM(rb_intern("keep_axis")), Qfalse));
|
|
257
259
|
}
|
|
258
260
|
naxes = rb_ca_parse_reduce_axes_kw(axis_val, src, slab_axes);
|
|
259
261
|
(void) inner_axes; /* axes no longer parsed from inner_axes */
|
|
@@ -270,6 +272,9 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
|
|
|
270
272
|
out_dim[out_ndim++] = src->dim[k];
|
|
271
273
|
base_elements *= src->dim[k];
|
|
272
274
|
}
|
|
275
|
+
else if ( keep_axis ) {
|
|
276
|
+
out_dim[out_ndim++] = 1; /* the reduced axis kept at length 1 */
|
|
277
|
+
}
|
|
273
278
|
}
|
|
274
279
|
/* Full reduction (naxes == ndim): base_elements = 1, no base axes. */
|
|
275
280
|
/* Append v.shape. */
|
|
@@ -377,6 +382,7 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
|
|
|
377
382
|
self = rb_ca_wrap_readonly(self, INT2NUM(qt));
|
|
378
383
|
}
|
|
379
384
|
}
|
|
385
|
+
self = ca_fixlen_widen_for_query(self, rval);
|
|
380
386
|
/* Pass full argv; count_equal_ki pops argv[0] as value_arg. */
|
|
381
387
|
return rb_ca_count_equal_ki(argc, argv, self);
|
|
382
388
|
}
|