carray 3.0.2 → 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 +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- 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/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -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_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_cast_func.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
data_type = []
|
|
2
|
+
type_const = {}
|
|
2
3
|
%w[
|
|
3
4
|
CA_FIXLEN
|
|
4
5
|
CA_BOOLEAN
|
|
@@ -20,6 +21,7 @@ data_type = []
|
|
|
20
21
|
].each_with_index do |name, i|
|
|
21
22
|
eval("#{name} = #{i}")
|
|
22
23
|
data_type.push(i)
|
|
24
|
+
type_const[i] = name
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
ctype = {
|
|
@@ -107,8 +109,8 @@ FLOAT = [
|
|
|
107
109
|
CA_FLOAT64 ,
|
|
108
110
|
]
|
|
109
111
|
|
|
110
|
-
# object -> int/float cast: a parse failure masks the output cell
|
|
111
|
-
#
|
|
112
|
+
# object -> int/float/complex cast: a parse failure masks the output cell
|
|
113
|
+
# (UNDEF) instead of raising. These parsers report
|
|
112
114
|
# failure through an out-param whose C type is `oktype`.
|
|
113
115
|
obj2cval_ok = {
|
|
114
116
|
CA_INT8 => "rb_obj2long_ok",
|
|
@@ -121,6 +123,8 @@ obj2cval_ok = {
|
|
|
121
123
|
CA_UINT64 => "rb_obj2ull_ok",
|
|
122
124
|
CA_FLOAT32 => "ca_obj2dbl_ok",
|
|
123
125
|
CA_FLOAT64 => "ca_obj2dbl_ok",
|
|
126
|
+
CA_CMPLX64 => "ca_obj2cmplx_ok",
|
|
127
|
+
CA_CMPLX128 => "ca_obj2cmplx_ok",
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
oktype = {
|
|
@@ -134,6 +138,8 @@ oktype = {
|
|
|
134
138
|
CA_UINT64 => "unsigned long long",
|
|
135
139
|
CA_FLOAT32 => "double",
|
|
136
140
|
CA_FLOAT64 => "double",
|
|
141
|
+
CA_CMPLX64 => "double complex",
|
|
142
|
+
CA_CMPLX128 => "double complex",
|
|
137
143
|
}
|
|
138
144
|
|
|
139
145
|
BOOLEAN = [
|
|
@@ -172,6 +178,7 @@ puts %{
|
|
|
172
178
|
---------------------------------------------------------------------------- */
|
|
173
179
|
|
|
174
180
|
#include "carray.h"
|
|
181
|
+
#include "carray_internal.h" /* ca_decimal_string_to / _store */
|
|
175
182
|
|
|
176
183
|
static void __attribute__((noreturn))
|
|
177
184
|
ca_cast_not_implemented(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
@@ -295,7 +302,8 @@ puts
|
|
|
295
302
|
*p2 = q;
|
|
296
303
|
}
|
|
297
304
|
else {
|
|
298
|
-
rb_raise(
|
|
305
|
+
rb_raise(rb_eRangeError, "%s: out of range to cast to boolean (0 or 1)",
|
|
306
|
+
ca_calling_method_name());
|
|
299
307
|
}
|
|
300
308
|
}
|
|
301
309
|
p1++; p2++; m++;
|
|
@@ -308,7 +316,8 @@ puts
|
|
|
308
316
|
*p2 = q;
|
|
309
317
|
}
|
|
310
318
|
else {
|
|
311
|
-
rb_raise(
|
|
319
|
+
rb_raise(rb_eRangeError, "%s: out of range to cast to boolean (0 or 1)",
|
|
320
|
+
ca_calling_method_name());
|
|
312
321
|
}
|
|
313
322
|
p1++; p2++;
|
|
314
323
|
}
|
|
@@ -327,7 +336,34 @@ puts
|
|
|
327
336
|
ctype1 = ctype[type1]
|
|
328
337
|
ctype2 = ctype[type2]
|
|
329
338
|
CA_CAST_TABLE[type1][type2] = "ca_cast_#{ctype1}_#{ctype2}"
|
|
330
|
-
|
|
339
|
+
# float / complex -> integer: a NaN has no integer and C leaves its
|
|
340
|
+
# conversion undefined. A cell that is not masked refuses it before
|
|
341
|
+
# anything is written. #to_type masks NaN cells first (UNDEF), so
|
|
342
|
+
# only a store, a view and a single cell reach the raise.
|
|
343
|
+
nan_check = ""
|
|
344
|
+
if (FLOAT+[CA_CMPLX64, CA_CMPLX128]).include?(type1) && INTEGER.include?(type2)
|
|
345
|
+
isnan = if [CA_CMPLX64, CA_CMPLX128].include?(type1)
|
|
346
|
+
"( isnan(creal(q1[k])) || isnan(cimag(q1[k])) )"
|
|
347
|
+
else
|
|
348
|
+
"isnan(q1[k])"
|
|
349
|
+
end
|
|
350
|
+
nan_check = <<-END_CHECK.gsub(/^ {6}/, '')
|
|
351
|
+
for (k=0; k<n; k++) {
|
|
352
|
+
if ( ( ! m || ! m[k] ) && #{isnan} ) {
|
|
353
|
+
rb_raise(rb_eFloatDomainError, "%s: NaN cannot be converted to %s",
|
|
354
|
+
ca_calling_method_name(), ca_type_name[#{type_const[type2]}]);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
END_CHECK
|
|
358
|
+
end
|
|
359
|
+
# int64 / uint64 -> float32 / cmplx64 goes through double, as a Ruby
|
|
360
|
+
# Integer stored into a float32 cell does (Integer#to_f). Converting in
|
|
361
|
+
# one step rounds once where the compiler keeps the loop scalar and twice
|
|
362
|
+
# where it vectorises it through double, so the answer for a value past
|
|
363
|
+
# 2**53 would depend on its place in the array.
|
|
364
|
+
via = ( [CA_INT64, CA_UINT64].include?(type1) &&
|
|
365
|
+
[CA_FLOAT32, CA_CMPLX64].include?(type2) ) ? "(double) " : ""
|
|
366
|
+
puts <<-END_DEF.gsub(/^ {6}/, '').sub("@@NAN_CHECK@@\n", nan_check).gsub("@@VIA@@", via)
|
|
331
367
|
static void
|
|
332
368
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
333
369
|
{
|
|
@@ -336,6 +372,7 @@ puts
|
|
|
336
372
|
#{ctype2} *q2 = ptr2;
|
|
337
373
|
#{ctype2} *p2 = q2;
|
|
338
374
|
ca_size_t k;
|
|
375
|
+
@@NAN_CHECK@@
|
|
339
376
|
if ( m ) {
|
|
340
377
|
boolean8_t *pm = m;
|
|
341
378
|
for (k=0; k<n; k++) {
|
|
@@ -343,7 +380,7 @@ puts
|
|
|
343
380
|
if ( ! *pm ) {
|
|
344
381
|
p1 = q1 + k;
|
|
345
382
|
p2 = q2 + k;
|
|
346
|
-
*p2 = (#{ctype2})
|
|
383
|
+
*p2 = (#{ctype2}) @@VIA@@*p1;
|
|
347
384
|
}
|
|
348
385
|
}
|
|
349
386
|
}
|
|
@@ -351,7 +388,7 @@ puts
|
|
|
351
388
|
for (k=0; k<n; k++) {
|
|
352
389
|
p1 = q1 + k;
|
|
353
390
|
p2 = q2 + k;
|
|
354
|
-
*p2 = (#{ctype2})
|
|
391
|
+
*p2 = (#{ctype2}) @@VIA@@*p1;
|
|
355
392
|
}
|
|
356
393
|
}
|
|
357
394
|
return;
|
|
@@ -456,17 +493,38 @@ OBJECT.each do |type1|
|
|
|
456
493
|
ctype1 = ctype[type1]
|
|
457
494
|
ctype2 = ctype[type2]
|
|
458
495
|
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.
|
|
496
|
+
if (INTEGER+FLOAT+[CA_CMPLX64, CA_CMPLX128]).include?(type2)
|
|
497
|
+
# object -> int/float/complex: parse failure -> masked (UNDEF) output
|
|
498
|
+
# cell. The mask-aware loop runs only when a mask buffer is supplied
|
|
499
|
+
# (m); #to_type always supplies one for these targets. With no mask
|
|
500
|
+
# buffer (a store, single-cell and view paths) the value parser
|
|
501
|
+
# raises for a cell it cannot read.
|
|
467
502
|
conv_ok = obj2cval_ok[type2]
|
|
468
503
|
conv = obj2cval[type2]
|
|
469
504
|
oktype2 = oktype[type2]
|
|
505
|
+
# A String cell of an integer or float target is read as a decimal
|
|
506
|
+
# number (ca_decimal_string_to / _store in carray_cast.c), not as a
|
|
507
|
+
# Ruby literal. Complex keeps its own reader.
|
|
508
|
+
if (INTEGER+FLOAT).include?(type2)
|
|
509
|
+
type_name = "CA_" + ctype2.sub(/_t\z/, "").upcase
|
|
510
|
+
read_ok = "( RB_TYPE_P(*p1, T_STRING) ? " \
|
|
511
|
+
"ca_decimal_string_to(*p1, #{type_name}, p2) : " \
|
|
512
|
+
"( #{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 ) )"
|
|
513
|
+
# A store refuses an integer the cell cannot hold
|
|
514
|
+
# (ca_obj2integer_fitting); to_type, above, keeps the C conversion.
|
|
515
|
+
store_conv = if INTEGER.include?(type2)
|
|
516
|
+
num = [CA_UINT8, CA_UINT16, CA_UINT32, CA_UINT64].include?(type2) ? "rb_num2ull" : "NUM2LL"
|
|
517
|
+
"#{num}(ca_obj2integer_fitting(*p1, #{type_name}))"
|
|
518
|
+
else
|
|
519
|
+
"#{conv}(*p1)"
|
|
520
|
+
end
|
|
521
|
+
read = "if ( RB_TYPE_P(*p1, T_STRING) ) { " \
|
|
522
|
+
"ca_decimal_string_store(*p1, #{type_name}, p2); } " \
|
|
523
|
+
"else { *p2 = (#{ctype2}) #{store_conv}; }"
|
|
524
|
+
else
|
|
525
|
+
read_ok = "( #{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 )"
|
|
526
|
+
read = "*p2 = (#{ctype2}) #{conv}(*p1);"
|
|
527
|
+
end
|
|
470
528
|
puts <<-END_DEF .gsub(/^ {6}/, '')
|
|
471
529
|
static void
|
|
472
530
|
ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
|
|
@@ -476,20 +534,15 @@ OBJECT.each do |type1|
|
|
|
476
534
|
#{oktype2} tmp;
|
|
477
535
|
if ( m ) {
|
|
478
536
|
while ( n-- ) {
|
|
479
|
-
if ( !*m ) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
*m = 1;
|
|
485
|
-
*p2 = 0;
|
|
486
|
-
}
|
|
537
|
+
if ( !*m && ! #{read_ok} ) {
|
|
538
|
+
*m = 1;
|
|
539
|
+
*p2 = 0;
|
|
487
540
|
}
|
|
488
541
|
p1++; p2++; m++;
|
|
489
542
|
}
|
|
490
543
|
}
|
|
491
544
|
else {
|
|
492
|
-
while ( n-- ) {
|
|
545
|
+
while ( n-- ) { #{read} p1++; p2++; }
|
|
493
546
|
}
|
|
494
547
|
return;
|
|
495
548
|
}
|
data/ext/carray_class.c
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
---------------------------------------------------------------------------- */
|
|
7
7
|
|
|
8
8
|
#include "carray.h"
|
|
9
|
+
#include "carray_internal.h" /* CA_CHECK_*_GIVEN */
|
|
9
10
|
|
|
10
11
|
/* ------------------------------------------------------------------- */
|
|
11
12
|
/* Symbol cache for data_type code → Symbol lookup.
|
|
@@ -25,7 +26,7 @@ ID ca_data_type_sym[CA_NTYPE];
|
|
|
25
26
|
VALUE
|
|
26
27
|
rb_ca_data_type_to_sym (int8_t data_type)
|
|
27
28
|
{
|
|
28
|
-
|
|
29
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
29
30
|
return ID2SYM(ca_data_type_sym[data_type]);
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -69,7 +70,7 @@ static VALUE
|
|
|
69
70
|
rb_ca_s_data_type_name (VALUE klass, VALUE type)
|
|
70
71
|
{
|
|
71
72
|
int8_t data_type = rb_ca_guess_type(type);
|
|
72
|
-
|
|
73
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
73
74
|
return rb_str_new2(ca_type_name[data_type]);
|
|
74
75
|
}
|
|
75
76
|
|
|
@@ -84,7 +85,7 @@ static VALUE
|
|
|
84
85
|
rb_ca_s_data_type_code (VALUE klass, VALUE type)
|
|
85
86
|
{
|
|
86
87
|
int8_t data_type = rb_ca_guess_type(type);
|
|
87
|
-
|
|
88
|
+
CA_CHECK_DATA_TYPE_GIVEN(data_type);
|
|
88
89
|
return INT2NUM(data_type);
|
|
89
90
|
}
|
|
90
91
|
|
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,11 +479,17 @@ 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(
|
|
435
|
-
"data size mismatch (got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
436
|
-
(ca_size_t) RSTRING_LEN(io), (ca_size_t) ca_length(ca));
|
|
482
|
+
rb_raise(rb_eArgError,
|
|
483
|
+
"%s: data size mismatch (got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
484
|
+
ca_calling_method_name(), (ca_size_t) RSTRING_LEN(io), (ca_size_t) ca_length(ca));
|
|
485
|
+
}
|
|
486
|
+
if ( ca->data_type == CA_BOOLEAN ) {
|
|
487
|
+
io = rb_str_dup(io);
|
|
488
|
+
rb_str_modify(io);
|
|
489
|
+
ca_boolean_normalize_bytes(RSTRING_PTR(io), ca->elements);
|
|
437
490
|
}
|
|
438
491
|
ca_sync_data(ca, RSTRING_PTR(io));
|
|
492
|
+
RB_GC_GUARD(io);
|
|
439
493
|
return self;
|
|
440
494
|
break;
|
|
441
495
|
default:
|
|
@@ -447,13 +501,13 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
447
501
|
const ca_size_t CHUNK = 65536;
|
|
448
502
|
volatile VALUE scratch = rb_str_buf_new(CHUNK < total ? CHUNK : total);
|
|
449
503
|
ca_size_t off = 0;
|
|
450
|
-
ca_allocate(ca);
|
|
504
|
+
ca_allocate(ca); /* window: an entity, whose allocate holds nothing */
|
|
451
505
|
while ( off < total ) {
|
|
452
506
|
ca_size_t want = (total - off < CHUNK) ? (total - off) : CHUNK;
|
|
453
507
|
VALUE r = rb_funcall(io, id_read, 2, SIZE2NUM(want), scratch);
|
|
454
508
|
if ( NIL_P(r) || RSTRING_LEN(r) != want ) {
|
|
455
509
|
ca_detach(ca);
|
|
456
|
-
rb_raise(
|
|
510
|
+
rb_raise(rb_eArgError,
|
|
457
511
|
"short read from IO at offset %" PRId64 " "
|
|
458
512
|
"(got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
459
513
|
(ca_size_t) off,
|
|
@@ -463,15 +517,17 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
463
517
|
memcpy(ca->ptr + off, RSTRING_PTR(r), want);
|
|
464
518
|
off += want;
|
|
465
519
|
}
|
|
466
|
-
|
|
467
|
-
|
|
520
|
+
if ( ca->data_type == CA_BOOLEAN ) {
|
|
521
|
+
ca_boolean_normalize_bytes(ca->ptr, ca->elements);
|
|
522
|
+
}
|
|
523
|
+
ca_sync_detach(ca);
|
|
468
524
|
}
|
|
469
525
|
else {
|
|
470
526
|
/* ca_sync_data scatters in one pass, so buffer the full read
|
|
471
527
|
and recurse via T_STRING. */
|
|
472
528
|
volatile VALUE buf = rb_funcall(io, id_read, 1, SIZE2NUM(total));
|
|
473
529
|
if ( NIL_P(buf) || RSTRING_LEN(buf) != total ) {
|
|
474
|
-
rb_raise(
|
|
530
|
+
rb_raise(rb_eArgError,
|
|
475
531
|
"short read from IO (got %" PRId64 " bytes, expected %" PRId64 ")",
|
|
476
532
|
(ca_size_t) (NIL_P(buf) ? 0 : RSTRING_LEN(buf)),
|
|
477
533
|
(ca_size_t) total);
|
|
@@ -481,13 +537,89 @@ rb_ca_load_binary (VALUE self, VALUE io)
|
|
|
481
537
|
return self;
|
|
482
538
|
}
|
|
483
539
|
else {
|
|
484
|
-
rb_raise(
|
|
540
|
+
rb_raise(rb_eTypeError, "IO like object should have 'read' method");
|
|
485
541
|
}
|
|
486
542
|
}
|
|
487
543
|
|
|
488
544
|
return self;
|
|
489
545
|
}
|
|
490
546
|
|
|
547
|
+
/* The double nearest to the shortest decimal that reads back as x, the
|
|
548
|
+
float32 value, as from_csv reads text into float32: strtod, then the cast
|
|
549
|
+
to float. Its digits are those of the decimal (at most 9, which a double
|
|
550
|
+
holds), so Float#to_s writes them. */
|
|
551
|
+
static double
|
|
552
|
+
ca_double_of_shortest_decimal_of_float32 (float x)
|
|
553
|
+
{
|
|
554
|
+
char buf[32];
|
|
555
|
+
int lo = 1, hi = 9;
|
|
556
|
+
double best;
|
|
557
|
+
if ( isnan(x) || isinf(x) ) {
|
|
558
|
+
return (double) x;
|
|
559
|
+
}
|
|
560
|
+
/* Nine significant digits always read back; search for the fewest. More
|
|
561
|
+
digits round closer to x, so the digit counts that read back are those
|
|
562
|
+
from some count up. */
|
|
563
|
+
best = 0.0;
|
|
564
|
+
while ( lo < hi ) {
|
|
565
|
+
int mid = (lo + hi) / 2;
|
|
566
|
+
double d;
|
|
567
|
+
snprintf(buf, sizeof(buf), "%.*e", mid - 1, (double) x);
|
|
568
|
+
d = ruby_strtod(buf, NULL);
|
|
569
|
+
if ( (float) d == x ) {
|
|
570
|
+
best = d;
|
|
571
|
+
hi = mid;
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
lo = mid + 1;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if ( lo == 9 ) {
|
|
578
|
+
snprintf(buf, sizeof(buf), "%.8e", (double) x);
|
|
579
|
+
best = ruby_strtod(buf, NULL);
|
|
580
|
+
}
|
|
581
|
+
return best;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/* float32 -> float64 and cmplx64 -> cmplx128, each value replaced by the
|
|
585
|
+
double its shortest decimal reads as, for to_csv to write that decimal.
|
|
586
|
+
The mask is kept. */
|
|
587
|
+
static VALUE
|
|
588
|
+
rb_ca_widen_keeping_shortest_decimal (VALUE self)
|
|
589
|
+
{
|
|
590
|
+
volatile VALUE out, holder = 0;
|
|
591
|
+
CArray *ca, *co;
|
|
592
|
+
ca_size_t i, n;
|
|
593
|
+
int8_t type;
|
|
594
|
+
|
|
595
|
+
GetCArray(self, ca);
|
|
596
|
+
if ( ca->data_type == CA_FLOAT32 ) {
|
|
597
|
+
type = CA_FLOAT64;
|
|
598
|
+
}
|
|
599
|
+
else if ( ca->data_type == CA_CMPLX64 ) {
|
|
600
|
+
type = CA_CMPLX128;
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
rb_raise(rb_eCADataTypeError, "__widen_keeping_shortest_decimal__ takes float32 or cmplx64");
|
|
604
|
+
}
|
|
605
|
+
n = ca->elements * (ca->data_type == CA_CMPLX64 ? 2 : 1);
|
|
606
|
+
out = rb_carray_new_safe(type, ca->ndim, ca->dim, 0, NULL);
|
|
607
|
+
GetCArray(out, co);
|
|
608
|
+
{
|
|
609
|
+
float *src = ALLOCV_N(float, holder, n > 0 ? n : 1);
|
|
610
|
+
double *dst = (double *) co->ptr;
|
|
611
|
+
ca_copy_data(ca, (char *) src);
|
|
612
|
+
for (i = 0; i < n; i++) {
|
|
613
|
+
dst[i] = ca_double_of_shortest_decimal_of_float32(src[i]);
|
|
614
|
+
}
|
|
615
|
+
ALLOCV_END(holder);
|
|
616
|
+
}
|
|
617
|
+
if ( ca_has_mask(ca) ) {
|
|
618
|
+
ca_copy_mask_overlay(co, co->elements, 1, ca);
|
|
619
|
+
}
|
|
620
|
+
return out;
|
|
621
|
+
}
|
|
622
|
+
|
|
491
623
|
/* [MOVED] str_format (2.0-era per-element formatter) is replaced by the Ruby
|
|
492
624
|
CArray#format / CArray.format surface in lib/carray/methods/string_format.rb,
|
|
493
625
|
which yields a CAString. */
|
|
@@ -504,6 +636,7 @@ Init_carray_conversion (void)
|
|
|
504
636
|
rb_define_method(rb_cCArray, "dump_binary", rb_ca_dump_binary, -1);
|
|
505
637
|
rb_define_method(rb_cCArray, "to_s", rb_ca_to_s, 0);
|
|
506
638
|
rb_define_method(rb_cCArray, "load_binary", rb_ca_load_binary, 1);
|
|
639
|
+
rb_define_method(rb_cCArray, "__widen_keeping_shortest_decimal__", rb_ca_widen_keeping_shortest_decimal, 0);
|
|
507
640
|
|
|
508
641
|
/* CAREFUL: do not bind #to_ary — implicit array coercion in Ruby core
|
|
509
642
|
(splat / multiple assignment / Array()) then triggers on any CArray
|