carray 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_cast_func.rb
CHANGED
|
@@ -107,8 +107,8 @@ FLOAT = [
|
|
|
107
107
|
CA_FLOAT64 ,
|
|
108
108
|
]
|
|
109
109
|
|
|
110
|
-
# object -> int/float cast: a parse failure masks the output cell
|
|
111
|
-
#
|
|
110
|
+
# object -> int/float/complex cast: a parse failure masks the output cell
|
|
111
|
+
# (UNDEF) instead of raising. These parsers report
|
|
112
112
|
# failure through an out-param whose C type is `oktype`.
|
|
113
113
|
obj2cval_ok = {
|
|
114
114
|
CA_INT8 => "rb_obj2long_ok",
|
|
@@ -121,6 +121,8 @@ obj2cval_ok = {
|
|
|
121
121
|
CA_UINT64 => "rb_obj2ull_ok",
|
|
122
122
|
CA_FLOAT32 => "ca_obj2dbl_ok",
|
|
123
123
|
CA_FLOAT64 => "ca_obj2dbl_ok",
|
|
124
|
+
CA_CMPLX64 => "ca_obj2cmplx_ok",
|
|
125
|
+
CA_CMPLX128 => "ca_obj2cmplx_ok",
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
oktype = {
|
|
@@ -134,6 +136,8 @@ oktype = {
|
|
|
134
136
|
CA_UINT64 => "unsigned long long",
|
|
135
137
|
CA_FLOAT32 => "double",
|
|
136
138
|
CA_FLOAT64 => "double",
|
|
139
|
+
CA_CMPLX64 => "double complex",
|
|
140
|
+
CA_CMPLX128 => "double complex",
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
BOOLEAN = [
|
|
@@ -172,6 +176,7 @@ puts %{
|
|
|
172
176
|
---------------------------------------------------------------------------- */
|
|
173
177
|
|
|
174
178
|
#include "carray.h"
|
|
179
|
+
#include "carray_internal.h" /* ca_decimal_string_to / _store */
|
|
175
180
|
|
|
176
181
|
static void __attribute__((noreturn))
|
|
177
182
|
ca_cast_not_implemented(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
@@ -295,7 +300,7 @@ puts
|
|
|
295
300
|
*p2 = q;
|
|
296
301
|
}
|
|
297
302
|
else {
|
|
298
|
-
rb_raise(
|
|
303
|
+
rb_raise(rb_eRangeError, "out of range to cast to boolean (0 or 1)");
|
|
299
304
|
}
|
|
300
305
|
}
|
|
301
306
|
p1++; p2++; m++;
|
|
@@ -308,7 +313,7 @@ puts
|
|
|
308
313
|
*p2 = q;
|
|
309
314
|
}
|
|
310
315
|
else {
|
|
311
|
-
rb_raise(
|
|
316
|
+
rb_raise(rb_eRangeError, "out of range to cast to boolean (0 or 1)");
|
|
312
317
|
}
|
|
313
318
|
p1++; p2++;
|
|
314
319
|
}
|
|
@@ -456,17 +461,30 @@ OBJECT.each do |type1|
|
|
|
456
461
|
ctype1 = ctype[type1]
|
|
457
462
|
ctype2 = ctype[type2]
|
|
458
463
|
CA_CAST_TABLE[type1][type2] = "ca_cast_#{ctype1}_#{ctype2}"
|
|
459
|
-
if (INTEGER+FLOAT).include?(type2)
|
|
460
|
-
# object -> int/float: parse failure -> masked (UNDEF) output
|
|
461
|
-
# The mask-aware loop runs only when a mask buffer is supplied
|
|
462
|
-
# #to_type always supplies one for these targets
|
|
463
|
-
#
|
|
464
|
-
#
|
|
465
|
-
# value parser keeps its old behaviour (lenient 0.0 float / raising
|
|
466
|
-
# int), leaving those paths byte-identical.
|
|
464
|
+
if (INTEGER+FLOAT+[CA_CMPLX64, CA_CMPLX128]).include?(type2)
|
|
465
|
+
# object -> int/float/complex: parse failure -> masked (UNDEF) output
|
|
466
|
+
# cell. The mask-aware loop runs only when a mask buffer is supplied
|
|
467
|
+
# (m); #to_type always supplies one for these targets. With no mask
|
|
468
|
+
# buffer (a store, single-cell and view paths) the value parser
|
|
469
|
+
# raises for a cell it cannot read.
|
|
467
470
|
conv_ok = obj2cval_ok[type2]
|
|
468
471
|
conv = obj2cval[type2]
|
|
469
472
|
oktype2 = oktype[type2]
|
|
473
|
+
# A String cell of an integer or float target is read as a decimal
|
|
474
|
+
# number (ca_decimal_string_to / _store in carray_cast.c), not as a
|
|
475
|
+
# Ruby literal. Complex keeps its own reader.
|
|
476
|
+
if (INTEGER+FLOAT).include?(type2)
|
|
477
|
+
type_name = "CA_" + ctype2.sub(/_t\z/, "").upcase
|
|
478
|
+
read_ok = "( RB_TYPE_P(*p1, T_STRING) ? " \
|
|
479
|
+
"ca_decimal_string_to(*p1, #{type_name}, p2) : " \
|
|
480
|
+
"( #{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 ) )"
|
|
481
|
+
read = "if ( RB_TYPE_P(*p1, T_STRING) ) { " \
|
|
482
|
+
"ca_decimal_string_store(*p1, #{type_name}, p2); } " \
|
|
483
|
+
"else { *p2 = (#{ctype2}) #{conv}(*p1); }"
|
|
484
|
+
else
|
|
485
|
+
read_ok = "( #{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 )"
|
|
486
|
+
read = "*p2 = (#{ctype2}) #{conv}(*p1);"
|
|
487
|
+
end
|
|
470
488
|
puts <<-END_DEF .gsub(/^ {6}/, '')
|
|
471
489
|
static void
|
|
472
490
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
@@ -476,20 +494,15 @@ OBJECT.each do |type1|
|
|
|
476
494
|
#{oktype2} tmp;
|
|
477
495
|
if ( m ) {
|
|
478
496
|
while ( n-- ) {
|
|
479
|
-
if ( !*m ) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
*m = 1;
|
|
485
|
-
*p2 = 0;
|
|
486
|
-
}
|
|
497
|
+
if ( !*m && ! #{read_ok} ) {
|
|
498
|
+
*m = 1;
|
|
499
|
+
*p2 = 0;
|
|
487
500
|
}
|
|
488
501
|
p1++; p2++; m++;
|
|
489
502
|
}
|
|
490
503
|
}
|
|
491
504
|
else {
|
|
492
|
-
while ( n-- ) {
|
|
505
|
+
while ( n-- ) { #{read} p1++; p2++; }
|
|
493
506
|
}
|
|
494
507
|
return;
|
|
495
508
|
}
|
data/ext/carray_conversion.c
CHANGED
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
---------------------------------------------------------------------------- */
|
|
13
13
|
|
|
14
14
|
#include "carray.h"
|
|
15
|
+
#include "carray_internal.h" /* ca_attach_window */
|
|
15
16
|
|
|
16
17
|
#include "ruby/io.h"
|
|
18
|
+
#include "ruby/util.h" /* ruby_strtod */
|
|
19
|
+
#include <math.h>
|
|
17
20
|
|
|
18
21
|
/* to_a dispatch:
|
|
19
22
|
numeric / boolean data type + entity or attach-able view -> fast path
|
|
@@ -175,19 +178,34 @@ rb_ca_to_a_loop_universal (VALUE self, int32_t level, ca_size_t *idx, VALUE ary)
|
|
|
175
178
|
* fast path, so all view kinds land in the data type-direct leaf loop when
|
|
176
179
|
* the data type is numeric or boolean; CA_OBJECT / CA_FIXLEN fall through
|
|
177
180
|
* to the universal fetch_index walk. */
|
|
181
|
+
/* The universal walk reads each cell through the fetch path, which
|
|
182
|
+
decodes -- an object cell, a Face's element -- and can raise, so it runs
|
|
183
|
+
inside an attach window. The fast path only copies numbers out. */
|
|
184
|
+
typedef struct {
|
|
185
|
+
VALUE self;
|
|
186
|
+
VALUE ary;
|
|
187
|
+
} ca_to_a_ctx_t;
|
|
188
|
+
|
|
189
|
+
static VALUE
|
|
190
|
+
ca_to_a_universal (VALUE arg)
|
|
191
|
+
{
|
|
192
|
+
ca_to_a_ctx_t *c = (ca_to_a_ctx_t *) arg;
|
|
193
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
194
|
+
rb_ca_to_a_loop_universal(c->self, 0, idx, c->ary);
|
|
195
|
+
return Qnil;
|
|
196
|
+
}
|
|
197
|
+
|
|
178
198
|
VALUE
|
|
179
199
|
rb_ca_to_a (VALUE self)
|
|
180
200
|
{
|
|
181
201
|
volatile VALUE ary;
|
|
182
202
|
CArray *ca;
|
|
183
|
-
ca_size_t idx[CA_RANK_MAX];
|
|
184
203
|
int data_type, fast_eligible;
|
|
185
204
|
|
|
186
205
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
187
206
|
ary = rb_ca_is_empty(self) ? rb_ary_new() : rb_ary_new2(ca->dim[0]);
|
|
188
|
-
ca_attach(ca);
|
|
189
207
|
|
|
190
|
-
/*
|
|
208
|
+
/* Once attached, ca->ptr is a contig row-major buffer (alias for
|
|
191
209
|
contig views, materialised otherwise) and ca->mask matches, so the
|
|
192
210
|
fast path handles every view kind. CA_OBJECT / CA_FIXLEN stay on
|
|
193
211
|
the universal path because their ptr is VALUE / byte string and
|
|
@@ -210,16 +228,21 @@ rb_ca_to_a (VALUE self)
|
|
|
210
228
|
|| data_type == CA_BOOLEAN);
|
|
211
229
|
|
|
212
230
|
if ( fast_eligible ) {
|
|
213
|
-
int has_mask
|
|
214
|
-
const boolean8_t *mask_base
|
|
215
|
-
|
|
231
|
+
int has_mask;
|
|
232
|
+
const boolean8_t *mask_base;
|
|
233
|
+
ca_attach(ca); /* window: nothing raises inside */
|
|
234
|
+
has_mask = (ca->mask != NULL);
|
|
235
|
+
mask_base = has_mask ? (const boolean8_t *) ca->mask->ptr : NULL;
|
|
216
236
|
to_a_fast_recurse(ca, 0, ca->ptr, mask_base, ary,
|
|
217
237
|
data_type, ca->bytes, has_mask);
|
|
238
|
+
ca_detach(ca);
|
|
218
239
|
}
|
|
219
240
|
else if ( ca->elements > 0 ) {
|
|
220
|
-
|
|
241
|
+
ca_to_a_ctx_t c;
|
|
242
|
+
c.self = self;
|
|
243
|
+
c.ary = ary;
|
|
244
|
+
ca_attach_window(1, &ca, "r", ca_to_a_universal, (VALUE) &c);
|
|
221
245
|
}
|
|
222
|
-
ca_detach(ca);
|
|
223
246
|
return ary;
|
|
224
247
|
}
|
|
225
248
|
|
|
@@ -228,65 +251,44 @@ rb_ca_to_a (VALUE self)
|
|
|
228
251
|
#undef TO_A_DISPATCH_LEAF
|
|
229
252
|
#undef TO_A_DISPATCH_LEAF_MASKED
|
|
230
253
|
|
|
231
|
-
/*
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
254
|
+
/* convert yields inside the window over self and the output, so the loop
|
|
255
|
+
runs through ca_attach_window. An output mask made part way (the first
|
|
256
|
+
UNDEF from the block) is attached inside the loop, and closed by an
|
|
257
|
+
ensure of its own. */
|
|
258
|
+
|
|
259
|
+
typedef struct {
|
|
260
|
+
VALUE self;
|
|
261
|
+
VALUE obj;
|
|
262
|
+
CArray *ca;
|
|
263
|
+
CArray *co;
|
|
264
|
+
int has_mask;
|
|
265
|
+
int co_mask_attached;
|
|
266
|
+
} ca_convert_ctx_t;
|
|
267
|
+
|
|
239
268
|
static VALUE
|
|
240
|
-
|
|
269
|
+
ca_convert_loop (VALUE arg)
|
|
241
270
|
{
|
|
242
|
-
|
|
243
|
-
CArray *ca, *co;
|
|
244
|
-
ca_size_t i, n
|
|
245
|
-
|
|
246
|
-
const
|
|
271
|
+
ca_convert_ctx_t *c = (ca_convert_ctx_t *) arg;
|
|
272
|
+
CArray *ca = c->ca, *co = c->co;
|
|
273
|
+
ca_size_t i, n = ca->elements;
|
|
274
|
+
ca_size_t sbytes = ca->bytes, dbytes = co->bytes;
|
|
275
|
+
const char *src_ptr = ca->ptr;
|
|
276
|
+
char *dst_ptr = co->ptr;
|
|
247
277
|
boolean8_t *dst_mask = NULL;
|
|
248
|
-
const char *src_ptr;
|
|
249
|
-
char *dst_ptr;
|
|
250
278
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
obj = rb_apply(self, rb_intern("template"), rb_ary_new4(argc, argv));
|
|
254
|
-
|
|
255
|
-
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
256
|
-
TypedData_Get_Struct(obj, CArray, &carray_data_type, co);
|
|
257
|
-
|
|
258
|
-
n = ca->elements;
|
|
259
|
-
has_mask = ca_has_mask(ca);
|
|
260
|
-
sbytes = ca->bytes;
|
|
261
|
-
dbytes = co->bytes;
|
|
262
|
-
|
|
263
|
-
/* Attach every storage touched by ptr (self, obj, and either side's
|
|
264
|
-
mask) — parent → child order per the R4 attach protocol. */
|
|
265
|
-
ca_attach(ca);
|
|
266
|
-
ca_attach(co);
|
|
267
|
-
if ( has_mask ) {
|
|
268
|
-
ca_attach(ca->mask);
|
|
269
|
-
if ( ! co->mask ) {
|
|
270
|
-
ca_create_mask(co);
|
|
271
|
-
}
|
|
272
|
-
ca_attach(co->mask);
|
|
273
|
-
src_mask = (const boolean8_t *) ca->mask->ptr;
|
|
279
|
+
if ( c->has_mask ) {
|
|
280
|
+
const boolean8_t *src_mask = (const boolean8_t *) ca->mask->ptr;
|
|
274
281
|
dst_mask = (boolean8_t *) co->mask->ptr;
|
|
275
282
|
memset(dst_mask, 0, (size_t) n);
|
|
276
|
-
}
|
|
277
|
-
src_ptr = ca->ptr;
|
|
278
|
-
dst_ptr = co->ptr;
|
|
279
|
-
|
|
280
|
-
if ( has_mask ) {
|
|
281
283
|
for (i = 0; i < n; i++) {
|
|
282
284
|
if ( ! src_mask[i] ) {
|
|
283
|
-
VALUE val = rb_ca_ptr2obj(self, (void *) (src_ptr + i * sbytes));
|
|
285
|
+
VALUE val = rb_ca_ptr2obj(c->self, (void *) (src_ptr + i * sbytes));
|
|
284
286
|
VALUE ret = rb_yield(val);
|
|
285
287
|
if ( ret == CA_UNDEF ) {
|
|
286
288
|
dst_mask[i] = 1;
|
|
287
289
|
}
|
|
288
290
|
else {
|
|
289
|
-
rb_ca_obj2ptr(obj, ret, dst_ptr + i * dbytes);
|
|
291
|
+
rb_ca_obj2ptr(c->obj, ret, dst_ptr + i * dbytes);
|
|
290
292
|
}
|
|
291
293
|
}
|
|
292
294
|
else {
|
|
@@ -296,33 +298,78 @@ rb_ca_convert (int argc, VALUE *argv, VALUE self)
|
|
|
296
298
|
}
|
|
297
299
|
else {
|
|
298
300
|
for (i = 0; i < n; i++) {
|
|
299
|
-
VALUE val = rb_ca_ptr2obj(self, (void *) (src_ptr + i * sbytes));
|
|
301
|
+
VALUE val = rb_ca_ptr2obj(c->self, (void *) (src_ptr + i * sbytes));
|
|
300
302
|
VALUE ret = rb_yield(val);
|
|
301
303
|
if ( ret == CA_UNDEF ) {
|
|
302
304
|
if ( ! co->mask ) {
|
|
303
305
|
ca_create_mask(co);
|
|
304
|
-
ca_attach(co->mask);
|
|
306
|
+
ca_attach(co->mask); /* window: closed by the ensure in ca_convert_body */
|
|
307
|
+
c->co_mask_attached = 1;
|
|
305
308
|
dst_mask = (boolean8_t *) co->mask->ptr;
|
|
306
309
|
memset(dst_mask, 0, (size_t) n);
|
|
307
310
|
}
|
|
308
311
|
dst_mask[i] = 1;
|
|
309
312
|
}
|
|
310
313
|
else {
|
|
311
|
-
rb_ca_obj2ptr(obj, ret, dst_ptr + i * dbytes);
|
|
314
|
+
rb_ca_obj2ptr(c->obj, ret, dst_ptr + i * dbytes);
|
|
312
315
|
}
|
|
313
316
|
}
|
|
314
317
|
}
|
|
318
|
+
return Qnil;
|
|
319
|
+
}
|
|
315
320
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
321
|
+
static VALUE
|
|
322
|
+
ca_convert_close_mask (VALUE arg)
|
|
323
|
+
{
|
|
324
|
+
ca_convert_ctx_t *c = (ca_convert_ctx_t *) arg;
|
|
325
|
+
if ( c->co_mask_attached ) {
|
|
326
|
+
c->co_mask_attached = 0;
|
|
327
|
+
ca_sync_detach(c->co->mask);
|
|
319
328
|
}
|
|
320
|
-
|
|
321
|
-
|
|
329
|
+
return Qnil;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
static VALUE
|
|
333
|
+
ca_convert_body (VALUE arg)
|
|
334
|
+
{
|
|
335
|
+
return rb_ensure(ca_convert_loop, arg, ca_convert_close_mask, arg);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/* CArray#convert(data_type=nil, bytes: nil) { |elem| ... } — map every cell
|
|
339
|
+
* through the block, into a new array whose data type is chosen by argv via
|
|
340
|
+
* CArray#template (shape is inherited from self).
|
|
341
|
+
*
|
|
342
|
+
* Masked cells skip the block; if the block returns CA_UNDEF, the
|
|
343
|
+
* corresponding output cell is masked instead of stored. Both self
|
|
344
|
+
* and the template result are attached symmetrically (R3-compliant) so
|
|
345
|
+
* an overridden #template returning a view stays on the in-ptr path. */
|
|
346
|
+
static VALUE
|
|
347
|
+
rb_ca_convert (int argc, VALUE *argv, VALUE self)
|
|
348
|
+
{
|
|
349
|
+
volatile VALUE obj;
|
|
350
|
+
ca_convert_ctx_t c;
|
|
351
|
+
CArray *list[2];
|
|
352
|
+
|
|
353
|
+
rb_need_block();
|
|
354
|
+
|
|
355
|
+
obj = rb_apply(self, rb_intern("template"), rb_ary_new4(argc, argv));
|
|
356
|
+
|
|
357
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, c.ca);
|
|
358
|
+
TypedData_Get_Struct(obj, CArray, &carray_data_type, c.co);
|
|
359
|
+
c.self = self;
|
|
360
|
+
c.obj = obj;
|
|
361
|
+
c.has_mask = ca_has_mask(c.ca);
|
|
362
|
+
c.co_mask_attached = 0;
|
|
363
|
+
|
|
364
|
+
/* Attaching an array attaches its mask, so the output's mask is made
|
|
365
|
+
before the window opens when the source already has one. */
|
|
366
|
+
if ( c.has_mask && ! c.co->mask ) {
|
|
367
|
+
ca_create_mask(c.co);
|
|
322
368
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
369
|
+
|
|
370
|
+
list[0] = c.ca;
|
|
371
|
+
list[1] = c.co;
|
|
372
|
+
ca_attach_window(2, list, "rw", ca_convert_body, (VALUE) &c);
|
|
326
373
|
|
|
327
374
|
return obj;
|
|
328
375
|
}
|
|
@@ -395,7 +442,7 @@ rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
|
|
|
395
442
|
rb_funcall(io, rb_intern("write"), 1, buf);
|
|
396
443
|
}
|
|
397
444
|
else {
|
|
398
|
-
rb_raise(
|
|
445
|
+
rb_raise(rb_eTypeError, "IO like object should have 'write' method");
|
|
399
446
|
}
|
|
400
447
|
}
|
|
401
448
|
|
|
@@ -422,6 +469,7 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
422
469
|
{
|
|
423
470
|
CArray *ca;
|
|
424
471
|
|
|
472
|
+
rb_ca_modify(self);
|
|
425
473
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
426
474
|
|
|
427
475
|
if ( ca_is_object_type(ca) ) {
|
|
@@ -431,7 +479,7 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
431
479
|
switch ( TYPE(io) ) {
|
|
432
480
|
case T_STRING:
|
|
433
481
|
if ( ca_length(ca) != RSTRING_LEN(io) ) {
|
|
434
|
-
rb_raise(
|
|
482
|
+
rb_raise(rb_eArgError,
|
|
435
483
|
"data size mismatch (got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
436
484
|
(ca_size_t) RSTRING_LEN(io), (ca_size_t) ca_length(ca));
|
|
437
485
|
}
|
|
@@ -447,13 +495,13 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
447
495
|
const ca_size_t CHUNK = 65536;
|
|
448
496
|
volatile VALUE scratch = rb_str_buf_new(CHUNK < total ? CHUNK : total);
|
|
449
497
|
ca_size_t off = 0;
|
|
450
|
-
ca_allocate(ca);
|
|
498
|
+
ca_allocate(ca); /* window: an entity, whose allocate holds nothing */
|
|
451
499
|
while ( off < total ) {
|
|
452
500
|
ca_size_t want = (total - off < CHUNK) ? (total - off) : CHUNK;
|
|
453
501
|
VALUE r = rb_funcall(io, id_read, 2, SIZE2NUM(want), scratch);
|
|
454
502
|
if ( NIL_P(r) || RSTRING_LEN(r) != want ) {
|
|
455
503
|
ca_detach(ca);
|
|
456
|
-
rb_raise(
|
|
504
|
+
rb_raise(rb_eArgError,
|
|
457
505
|
"short read from IO at offset %" PRId64 " "
|
|
458
506
|
"(got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
459
507
|
(ca_size_t) off,
|
|
@@ -463,15 +511,14 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
463
511
|
memcpy(ca->ptr + off, RSTRING_PTR(r), want);
|
|
464
512
|
off += want;
|
|
465
513
|
}
|
|
466
|
-
|
|
467
|
-
ca_detach(ca);
|
|
514
|
+
ca_sync_detach(ca);
|
|
468
515
|
}
|
|
469
516
|
else {
|
|
470
517
|
/* ca_sync_data scatters in one pass, so buffer the full read
|
|
471
518
|
and recurse via T_STRING. */
|
|
472
519
|
volatile VALUE buf = rb_funcall(io, id_read, 1, SIZE2NUM(total));
|
|
473
520
|
if ( NIL_P(buf) || RSTRING_LEN(buf) != total ) {
|
|
474
|
-
rb_raise(
|
|
521
|
+
rb_raise(rb_eArgError,
|
|
475
522
|
"short read from IO (got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
476
523
|
(ca_size_t) (NIL_P(buf) ? 0 : RSTRING_LEN(buf)),
|
|
477
524
|
(ca_size_t) total);
|
|
@@ -481,13 +528,89 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
481
528
|
return self;
|
|
482
529
|
}
|
|
483
530
|
else {
|
|
484
|
-
rb_raise(
|
|
531
|
+
rb_raise(rb_eTypeError, "IO like object should have 'read' method");
|
|
485
532
|
}
|
|
486
533
|
}
|
|
487
534
|
|
|
488
535
|
return self;
|
|
489
536
|
}
|
|
490
537
|
|
|
538
|
+
/* The double nearest to the shortest decimal that reads back as x, the
|
|
539
|
+
float32 value, as from_csv reads text into float32: strtod, then the cast
|
|
540
|
+
to float. Its digits are those of the decimal (at most 9, which a double
|
|
541
|
+
holds), so Float#to_s writes them. */
|
|
542
|
+
static double
|
|
543
|
+
ca_float32_shortest (float x)
|
|
544
|
+
{
|
|
545
|
+
char buf[32];
|
|
546
|
+
int lo = 1, hi = 9;
|
|
547
|
+
double best;
|
|
548
|
+
if ( isnan(x) || isinf(x) ) {
|
|
549
|
+
return (double) x;
|
|
550
|
+
}
|
|
551
|
+
/* Nine significant digits always read back; search for the fewest. More
|
|
552
|
+
digits round closer to x, so the digit counts that read back are those
|
|
553
|
+
from some count up. */
|
|
554
|
+
best = 0.0;
|
|
555
|
+
while ( lo < hi ) {
|
|
556
|
+
int mid = (lo + hi) / 2;
|
|
557
|
+
double d;
|
|
558
|
+
snprintf(buf, sizeof(buf), "%.*e", mid - 1, (double) x);
|
|
559
|
+
d = ruby_strtod(buf, NULL);
|
|
560
|
+
if ( (float) d == x ) {
|
|
561
|
+
best = d;
|
|
562
|
+
hi = mid;
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
lo = mid + 1;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if ( lo == 9 ) {
|
|
569
|
+
snprintf(buf, sizeof(buf), "%.8e", (double) x);
|
|
570
|
+
best = ruby_strtod(buf, NULL);
|
|
571
|
+
}
|
|
572
|
+
return best;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* float32 -> float64 and cmplx64 -> cmplx128, each value replaced by the
|
|
576
|
+
double its shortest decimal reads as, for to_csv to write that decimal.
|
|
577
|
+
The mask is kept. */
|
|
578
|
+
static VALUE
|
|
579
|
+
rb_ca_shortest_float64 (VALUE self)
|
|
580
|
+
{
|
|
581
|
+
volatile VALUE out, holder = 0;
|
|
582
|
+
CArray *ca, *co;
|
|
583
|
+
ca_size_t i, n;
|
|
584
|
+
int8_t type;
|
|
585
|
+
|
|
586
|
+
GetCArray(self, ca);
|
|
587
|
+
if ( ca->data_type == CA_FLOAT32 ) {
|
|
588
|
+
type = CA_FLOAT64;
|
|
589
|
+
}
|
|
590
|
+
else if ( ca->data_type == CA_CMPLX64 ) {
|
|
591
|
+
type = CA_CMPLX128;
|
|
592
|
+
}
|
|
593
|
+
else {
|
|
594
|
+
rb_raise(rb_eCADataTypeError, "__shortest_float64__ takes float32 or cmplx64");
|
|
595
|
+
}
|
|
596
|
+
n = ca->elements * (ca->data_type == CA_CMPLX64 ? 2 : 1);
|
|
597
|
+
out = rb_carray_new_safe(type, ca->ndim, ca->dim, 0, NULL);
|
|
598
|
+
GetCArray(out, co);
|
|
599
|
+
{
|
|
600
|
+
float *src = ALLOCV_N(float, holder, n > 0 ? n : 1);
|
|
601
|
+
double *dst = (double *) co->ptr;
|
|
602
|
+
ca_copy_data(ca, (char *) src);
|
|
603
|
+
for (i = 0; i < n; i++) {
|
|
604
|
+
dst[i] = ca_float32_shortest(src[i]);
|
|
605
|
+
}
|
|
606
|
+
ALLOCV_END(holder);
|
|
607
|
+
}
|
|
608
|
+
if ( ca_has_mask(ca) ) {
|
|
609
|
+
ca_copy_mask_overlay(co, co->elements, 1, ca);
|
|
610
|
+
}
|
|
611
|
+
return out;
|
|
612
|
+
}
|
|
613
|
+
|
|
491
614
|
/* [MOVED] str_format (2.0-era per-element formatter) is replaced by the Ruby
|
|
492
615
|
CArray#format / CArray.format surface in lib/carray/methods/string_format.rb,
|
|
493
616
|
which yields a CAString. */
|
|
@@ -504,6 +627,7 @@ Init_carray_conversion (void)
|
|
|
504
627
|
rb_define_method(rb_cCArray, "dump_binary", rb_ca_dump_binary, -1);
|
|
505
628
|
rb_define_method(rb_cCArray, "to_s", rb_ca_to_s, 0);
|
|
506
629
|
rb_define_method(rb_cCArray, "load_binary", rb_ca_load_binary, 1);
|
|
630
|
+
rb_define_method(rb_cCArray, "__shortest_float64__", rb_ca_shortest_float64, 0);
|
|
507
631
|
|
|
508
632
|
/* CAREFUL: do not bind #to_ary — implicit array coercion in Ruby core
|
|
509
633
|
(splat / multiple assignment / Array()) then triggers on any CArray
|