carray 3.0.3 → 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.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
data/ext/carray_cast.c CHANGED
@@ -496,6 +496,7 @@ ca_decimal_object_integer (VALUE v, int *negative, uint64_t *magnitude)
496
496
  /* truncate raises for a NaN or infinite BigDecimal, which reads as
497
497
  nothing an integer can hold. */
498
498
  int state = 0;
499
+ /* protect: a BigDecimal that is not finite reads as no integer; nothing is held */
499
500
  VALUE whole = rb_protect(ca_decimal_truncate, v, &state);
500
501
  if ( state ) {
501
502
  rb_set_errinfo(Qnil);
@@ -589,11 +590,11 @@ ca_decimal_string_store (VALUE str, int8_t data_type, void *out)
589
590
  case CA_DECIMAL_OK:
590
591
  return;
591
592
  case CA_DECIMAL_OUT_OF_RANGE:
592
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is out of range for %s",
593
- str, ca_type_name[data_type]);
593
+ rb_raise(rb_eRangeError, "%s: %+"PRIsVALUE" is out of range for %s",
594
+ ca_calling_method_name(), str, ca_type_name[data_type]);
594
595
  default:
595
- rb_raise(rb_eArgError, "%+"PRIsVALUE" cannot be read as %s",
596
- str, ca_type_name[data_type]);
596
+ rb_raise(rb_eArgError, "%s: %+"PRIsVALUE" cannot be read as %s",
597
+ ca_calling_method_name(), str, ca_type_name[data_type]);
597
598
  }
598
599
  }
599
600
 
@@ -767,6 +768,7 @@ ca_obj2dbl_ok (VALUE val, double *out)
767
768
  }
768
769
  {
769
770
  int state = 0;
771
+ /* protect: converts the caller's value and reports failure; nothing is held */
770
772
  volatile VALUE r = rb_protect(ca_kernel_float, val, &state);
771
773
  if ( state ) {
772
774
  rb_set_errinfo(Qnil);
@@ -795,6 +797,7 @@ ca_obj2cmplx_ok (VALUE val, double complex *out)
795
797
  if ( NIL_P(val) ) {
796
798
  return 0;
797
799
  }
800
+ /* protect: converts the caller's value and reports failure; nothing is held */
798
801
  r = rb_protect(ca_cmplx_cell_body, val, &state);
799
802
  if ( state ) {
800
803
  rb_set_errinfo(Qnil);
@@ -819,6 +822,7 @@ ca_obj2integer_ok (VALUE val, int8_t wide_type, void *wide, VALUE *integer)
819
822
  if ( RB_TYPE_P(val, T_STRING) ) {
820
823
  return ca_decimal_string_to(val, wide_type, wide);
821
824
  }
825
+ /* protect: converts the caller's value and reports failure; nothing is held */
822
826
  *integer = rb_protect(ca_kernel_integer, val, &state);
823
827
  if ( state ) {
824
828
  rb_set_errinfo(Qnil);
@@ -1052,7 +1056,7 @@ ca_ptr2val (void *ap1, void *ptr1, int8_t data_type, void *ptr2)
1052
1056
  {
1053
1057
  CArray *ca1 = (CArray *)ap1;
1054
1058
  static CArray dummy;
1055
- CA_CHECK_DATA_TYPE(data_type);
1059
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
1056
1060
  dummy.data_type = data_type;
1057
1061
  ca_cast_func_table[ca1->data_type][data_type](1, ca1, ptr1, &dummy, ptr2, NULL);
1058
1062
  return;
@@ -1063,7 +1067,7 @@ ca_val2ptr (int8_t data_type, void *ptr1, void *ap2, void *ptr2)
1063
1067
  {
1064
1068
  CArray *ca2 = (CArray *)ap2;
1065
1069
  static CArray dummy;
1066
- CA_CHECK_DATA_TYPE(data_type);
1070
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
1067
1071
  dummy.data_type = data_type;
1068
1072
  ca_cast_func_table[data_type][ca2->data_type](1, &dummy, ptr1, ca2, ptr2, NULL);
1069
1073
  return;
@@ -1073,8 +1077,8 @@ void
1073
1077
  ca_val2val (int8_t data_type1, void *ptr1, int8_t data_type2, void *ptr2)
1074
1078
  {
1075
1079
  static CArray dummy1, dummy2;
1076
- CA_CHECK_DATA_TYPE(data_type1);
1077
- CA_CHECK_DATA_TYPE(data_type2);
1080
+ CA_CHECK_DATA_TYPE_GIVEN(data_type1);
1081
+ CA_CHECK_DATA_TYPE_GIVEN(data_type2);
1078
1082
  dummy1.data_type = data_type1;
1079
1083
  dummy2.data_type = data_type2;
1080
1084
  ca_cast_func_table[data_type1][data_type2](1, &dummy1, ptr1, &dummy2, ptr2, NULL);
@@ -1211,26 +1215,48 @@ typedef struct {
1211
1215
  boolean8_t *scratch;
1212
1216
  } ca_to_type_ctx_t;
1213
1217
 
1214
- /* Marks in `m` the cells of a float or complex array that hold NaN (in
1215
- either part). A NaN has no integer, and C leaves its conversion
1216
- undefined. */
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. */
1217
1241
  static void
1218
- ca_mark_nan (CArray *ca, boolean8_t *m)
1242
+ ca_mark_unconvertible (CArray *ca, boolean8_t *m, int8_t dt)
1219
1243
  {
1220
1244
  ca_size_t i, n = ca->elements;
1221
1245
  switch ( ca->data_type ) {
1222
- case CA_FLOAT32: { float32_t *p = (float32_t *) ca->ptr;
1223
- for (i=0; i<n; i++) if ( isnan(p[i]) ) m[i] = 1;
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;
1224
1248
  break; }
1225
- case CA_FLOAT64: { float64_t *p = (float64_t *) ca->ptr;
1226
- for (i=0; i<n; i++) if ( isnan(p[i]) ) m[i] = 1;
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;
1227
1251
  break; }
1228
1252
  #ifdef HAVE_COMPLEX_H
1229
- case CA_CMPLX64: { cmplx64_t *p = (cmplx64_t *) ca->ptr;
1230
- for (i=0; i<n; i++) if ( isnan(crealf(p[i])) || isnan(cimagf(p[i])) ) m[i] = 1;
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;
1231
1256
  break; }
1232
- case CA_CMPLX128: { cmplx128_t *p = (cmplx128_t *) ca->ptr;
1233
- for (i=0; i<n; i++) if ( isnan(creal(p[i])) || isnan(cimag(p[i])) ) m[i] = 1;
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;
1234
1260
  break; }
1235
1261
  #endif
1236
1262
  default:
@@ -1270,11 +1296,11 @@ ca_to_type_cast (VALUE arg)
1270
1296
  else {
1271
1297
  memset(scratch, 0, ne);
1272
1298
  }
1273
- /* float -> integer: a NaN cell becomes UNDEF, as an unparseable object
1274
- cell does. A finite value outside the integer type is converted the
1275
- way the machine's C converts it, which differs between machines. */
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. */
1276
1302
  if ( from_float ) {
1277
- ca_mark_nan(ca, scratch);
1303
+ ca_mark_unconvertible(ca, scratch, cb->data_type);
1278
1304
  memset(cb->ptr, 0, ne * cb->bytes);
1279
1305
  }
1280
1306
  ca_cast_block_with_mask(ne, ca, ca->ptr, cb, cb->ptr, scratch);
@@ -1767,8 +1793,11 @@ rb_ca_ptr2ptr (VALUE ra1, void *ptr1, VALUE ra2, void *ptr2)
1767
1793
  }
1768
1794
 
1769
1795
 
1796
+ /* A cell's bytes as the value of self's data type before the last two
1797
+ steps of ca[i]: a boolean is 0 or 1 and a Face cell is its storage
1798
+ value. The element readers call this, check the mask, then decode. */
1770
1799
  VALUE
1771
- rb_ca_ptr2obj (VALUE self, void *ptr)
1800
+ rb_ca_ptr2obj_storage (VALUE self, void *ptr)
1772
1801
  {
1773
1802
  volatile VALUE obj;
1774
1803
  static CArray dummy;
@@ -1784,6 +1813,20 @@ rb_ca_ptr2obj (VALUE self, void *ptr)
1784
1813
  }
1785
1814
  }
1786
1815
 
1816
+ VALUE
1817
+ rb_ca_ptr2obj (VALUE self, void *ptr)
1818
+ {
1819
+ CArray *ca;
1820
+ VALUE obj = rb_ca_ptr2obj_storage(self, ptr);
1821
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1822
+ CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(obj, self, ca);
1823
+ if ( ca->data_type == CA_BOOLEAN &&
1824
+ ( obj == INT2FIX(0) || obj == INT2FIX(1) ) ) {
1825
+ obj = ( obj == INT2FIX(1) ) ? Qtrue : Qfalse;
1826
+ }
1827
+ return obj;
1828
+ }
1829
+
1787
1830
  /* Surface -> storage-domain conversion for a Face store (mirror of the
1788
1831
  storage_to_element read hook). Non-Face `ca` returns `obj` unchanged, so
1789
1832
  the non-Face store path is untouched. For a Face, the per-obj_type C
@@ -1853,7 +1896,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1853
1896
  if ( rb_obj_is_carray(obj) ) { /* obj == carray */
1854
1897
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1855
1898
  if ( ca_is_readonly(ca) ) {
1856
- rb_raise(rb_eRuntimeError, "can not modify read-only array");
1899
+ ca_refuse_read_only();
1857
1900
  }
1858
1901
  if ( NIL_P(rtype) ) {
1859
1902
  data_type = ca->data_type;
@@ -1891,7 +1934,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1891
1934
  }
1892
1935
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1893
1936
  if ( ca_is_readonly(ca) ) {
1894
- rb_raise(rb_eRuntimeError, "can not modify read-only array");
1937
+ ca_refuse_read_only();
1895
1938
  }
1896
1939
  if ( NIL_P(rtype) ) {
1897
1940
  data_type = ca->data_type;
@@ -1905,12 +1948,9 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1905
1948
  }
1906
1949
  }
1907
1950
  else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
1908
- obj = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
1951
+ obj = ca_mv_wrap(obj, Qnil, rb_cCAWrap, -1,
1952
+ NIL_P(rtype) ? -1 : rb_ca_guess_type(rtype), 1);
1909
1953
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1910
- if ( ca_is_readonly(ca) ) {
1911
- rb_raise(rb_eRuntimeError,
1912
- "MemoryView source is read-only; can't wrap as writable");
1913
- }
1914
1954
  if ( NIL_P(rtype) ) {
1915
1955
  data_type = ca->data_type;
1916
1956
  }
@@ -1999,7 +2039,9 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
1999
2039
  else {
2000
2040
  CArray *ca_tmp;
2001
2041
  volatile VALUE ref = obj;
2002
- ca_size_t dim = RSTRING_LEN(ref)/ca_sizeof[data_type];
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;
2003
2045
  obj = rb_carray_new(data_type, 1, &dim, 0, NULL);
2004
2046
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca_tmp);
2005
2047
  memcpy(ca_tmp->ptr, RSTRING_PTR(ref), dim * ca_sizeof[data_type]);
@@ -2029,7 +2071,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
2029
2071
  }
2030
2072
  }
2031
2073
  else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
2032
- obj = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
2074
+ obj = ca_mv_wrap(obj, Qnil, rb_cCAWrap, -1,
2075
+ NIL_P(rtype) ? -1 : rb_ca_guess_type(rtype), 0);
2033
2076
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
2034
2077
  if ( NIL_P(rtype) ) {
2035
2078
  data_type = ca->data_type;
@@ -2131,7 +2174,15 @@ ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
2131
2174
  if ( cr->data_type != CA_FIXLEN ) {
2132
2175
  return 0;
2133
2176
  }
2134
- *scalar = rb_cscalar_new_with_value(CA_FIXLEN, cr->bytes, *scalar);
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
+ }
2135
2186
  return 1;
2136
2187
  }
2137
2188
 
@@ -2171,6 +2222,36 @@ ca_check_integer_fits (VALUE v, int8_t dt)
2171
2222
  }
2172
2223
  }
2173
2224
 
2225
+ /* The store reader for an integer cell: the value as an Integer, refused
2226
+ when it does not fit the cell's type, as an operator refuses it. A
2227
+ store raises where an array cast (to_type) keeps the C conversion. A
2228
+ non-Integer goes through Integer() (1.5 is 1; nil and NaN raise). */
2229
+ VALUE
2230
+ ca_obj2integer_fitting (VALUE v, int8_t data_type)
2231
+ {
2232
+ VALUE integer = RB_INTEGER_TYPE_P(v) ? v : rb_Integer(v);
2233
+ if ( FIXNUM_P(integer) ) {
2234
+ long x = FIX2LONG(integer);
2235
+ int fits;
2236
+ switch ( data_type ) {
2237
+ case CA_INT8: fits = ( x >= INT8_MIN && x <= INT8_MAX ); break;
2238
+ case CA_UINT8: fits = ( x >= 0 && x <= UINT8_MAX ); break;
2239
+ case CA_INT16: fits = ( x >= INT16_MIN && x <= INT16_MAX ); break;
2240
+ case CA_UINT16: fits = ( x >= 0 && x <= UINT16_MAX ); break;
2241
+ case CA_INT32: fits = ( x >= INT32_MIN && x <= INT32_MAX ); break;
2242
+ case CA_UINT32: fits = ( x >= 0 && (unsigned long) x <= UINT32_MAX ); break;
2243
+ case CA_INT64: fits = 1; break;
2244
+ case CA_UINT64: fits = ( x >= 0 ); break;
2245
+ default: fits = 1; break;
2246
+ }
2247
+ if ( fits ) {
2248
+ return integer;
2249
+ }
2250
+ }
2251
+ ca_check_integer_fits(integer, data_type);
2252
+ return integer;
2253
+ }
2254
+
2174
2255
  /* A Ruby Integer operand against an integer array is taken in the array's
2175
2256
  own data type, refused when it does not fit (ca_check_integer_fits).
2176
2257
  Widening instead would make the result's type depend on a scalar's
@@ -2191,6 +2272,69 @@ ca_integer_scalar_operand (volatile VALUE *scalar, VALUE reference)
2191
2272
  return 1;
2192
2273
  }
2193
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
+
2194
2338
  /* CArray.cast(value) -- singleton entry delegating to rb_ca_cast, which
2195
2339
  returns a CArray unchanged and coerces a Ruby value to a CScalar / CArray.
2196
2340
  User doc lives in yard-stubs/carray_cast.rb. */
@@ -2255,6 +2399,10 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2255
2399
  *other = ca_operand_from_memory_view(*other);
2256
2400
  }
2257
2401
 
2402
+ if ( ! ca_array_operand(other, *self, 1) ) {
2403
+ ca_array_operand(self, *other, 1);
2404
+ }
2405
+
2258
2406
  if ( ! rb_obj_is_carray(*self) ) {
2259
2407
  self_is_object = 1;
2260
2408
  if ( rb_ca_is_object_type(*other) ) {
@@ -2378,12 +2526,32 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2378
2526
  return;
2379
2527
  }
2380
2528
 
2381
- rb_raise(rb_eTypeError,
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,
2382
2532
  "can't coerce carray with data_types of '%s' and '%s'",
2383
2533
  ca_coerce_operand_name(*self, ca),
2384
2534
  ca_coerce_operand_name(*other, cb));
2385
2535
  }
2386
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
+
2387
2555
  /* CArray.cast_self_or_other(self, other) — promote self and other
2388
2556
  * to a common data_type and return [self', other']. Wraps the
2389
2557
  * void rb_ca_cast_self_or_other above into a class method.
@@ -2422,10 +2590,19 @@ ca_arg_to_data_type (VALUE obj)
2422
2590
  /* MemoryView producer -> its format's data_type (T_STRING excluded above,
2423
2591
  so a String never reaches here). data_type already assigned. */
2424
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
+ }
2425
2602
  else {
2426
2603
  data_type = ca_value_to_data_type(obj);
2427
2604
  }
2428
- CA_CHECK_DATA_TYPE(data_type);
2605
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
2429
2606
  if ( ! ca_valid[data_type] ) {
2430
2607
  rb_raise(rb_eArgError,
2431
2608
  "data type '%s' is not valid in this build",
@@ -2465,6 +2642,9 @@ int8_t
2465
2642
  ca_promote_type (int8_t a, int8_t b)
2466
2643
  {
2467
2644
  int test;
2645
+ if ( a <= CA_NONE || a >= CA_NTYPE || b <= CA_NONE || b >= CA_NTYPE ) {
2646
+ rb_raise(rb_eArgError, "invalid data_type id (%i, %i)", (int) a, (int) b);
2647
+ }
2468
2648
  if ( a == b ) {
2469
2649
  return a;
2470
2650
  }
@@ -2521,6 +2701,67 @@ ca_value_match_type (int8_t t, int8_t a, int8_t b)
2521
2701
  }
2522
2702
  }
2523
2703
 
2704
+ /* The type a value query and a reference of type `ref` are compared in,
2705
+ by equality or order, as `eq` compares them: the reference is read
2706
+ through a view of that type, so the query is never cut to the
2707
+ reference's type (3.9 does not match 3, -1 does not read as 255).
2708
+ A Float query takes the type the operators give it beside the
2709
+ reference; an Integer query keeps the reference's type when it fits and
2710
+ otherwise the type its value needs, where it matches nothing; a CArray
2711
+ query takes the type the two arrays match in (the common type, widened
2712
+ by ca_value_match_type). Beside a reference that is not a number, a
2713
+ scalar query keeps the reference's type. */
2714
+ int8_t
2715
+ ca_query_match_type (int8_t ref, VALUE query)
2716
+ {
2717
+ int ref_int = ( ref >= CA_INT8 && ref <= CA_UINT64 );
2718
+ int ref_float = ( ref == CA_FLOAT32 || ref == CA_FLOAT64 );
2719
+ if ( rb_obj_is_carray(query) ) {
2720
+ CArray *q;
2721
+ TypedData_Get_Struct(query, CArray, &carray_data_type, q);
2722
+ return ca_value_match_type(ca_promote_type(ref, q->data_type), ref,
2723
+ q->data_type);
2724
+ }
2725
+ if ( ! ref_int && ! ref_float && ref != CA_BOOLEAN ) {
2726
+ return ref;
2727
+ }
2728
+ if ( RB_FLOAT_TYPE_P(query) ) {
2729
+ return ca_promote_scalar_type(ref, query, CA_FLOAT64);
2730
+ }
2731
+ if ( RB_INTEGER_TYPE_P(query) ) {
2732
+ return ref_int ? ca_promote_scalar_type(ref, query, CA_INT64) : ref;
2733
+ }
2734
+ return ref;
2735
+ }
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
+
2755
+ /* ca.query_match_type(query) -- ca_query_match_type with self as the
2756
+ reference, for the set family and locate_addr. */
2757
+ static VALUE
2758
+ rb_ca_query_match_type (VALUE self, VALUE query)
2759
+ {
2760
+ CArray *ca;
2761
+ GetCArray(self, ca);
2762
+ return rb_ca_data_type_to_sym(ca_query_match_type(ca->data_type, query));
2763
+ }
2764
+
2524
2765
  /* ca.value_match_type(t, other_type) -- ca_value_match_type with self's
2525
2766
  data type as the first operand, for the set family and locate_addr. */
2526
2767
  static VALUE
@@ -2546,20 +2787,30 @@ ca_arg_is_scalar (VALUE obj)
2546
2787
  if ( TYPE(obj) == T_SYMBOL || TYPE(obj) == T_STRING || TYPE(obj) == T_CLASS ) {
2547
2788
  return 0;
2548
2789
  }
2549
- return ca_mv_probe_data_type(obj) < 0;
2790
+ return ! rb_memory_view_available_p(obj);
2550
2791
  }
2551
2792
 
2552
2793
  /* The type a scalar `obj` (of type `st`) and an array of type `at` share,
2553
2794
  by the rule the operators apply: a scalar of the same kind takes the
2554
2795
  array's type (0.1 beside float32 is float32, 1 beside int8 is int8); one
2555
2796
  of another kind promotes (1.5 beside int32 is float64). An Integer that
2556
- does not fit the array's integer type takes the type of its value, where
2557
- an operator would raise RangeError. */
2797
+ does not fit the array's integer type takes a type that holds it and the
2798
+ array's values (int64, or object where no integer type does), where an
2799
+ operator would raise RangeError. */
2558
2800
  int8_t
2559
2801
  ca_promote_scalar_type (int8_t at, VALUE obj, int8_t st)
2560
2802
  {
2561
2803
  if ( RB_INTEGER_TYPE_P(obj) && at >= CA_INT8 && at <= CA_UINT64 ) {
2562
- return ( ca_integer_range_side(obj, at) == 0 ) ? at : ca_promote_type(at, st);
2804
+ int8_t vt;
2805
+ if ( ca_integer_range_side(obj, at) == 0 ) {
2806
+ return at;
2807
+ }
2808
+ /* The type the value needs, widened so that the array's values are
2809
+ kept beside it (a uint64 array and -1 meet in object). */
2810
+ vt = ( ca_integer_range_side(obj, CA_INT64) == 0 ) ? CA_INT64
2811
+ : ( ca_integer_range_side(obj, CA_UINT64) == 0 ) ? CA_UINT64
2812
+ : CA_OBJECT;
2813
+ return ca_value_match_type(ca_promote_type(at, vt), at, vt);
2563
2814
  }
2564
2815
  if ( ca_cast_table2[st][at] >= 0 ) {
2565
2816
  return at;
@@ -2606,6 +2857,8 @@ rb_ca_s_result_type (int argc, VALUE *argv, VALUE klass)
2606
2857
  cur = ( cur < 0 ) ? t : ca_promote_scalar_type(cur, argv[i], t);
2607
2858
  }
2608
2859
  }
2860
+ /* argv points into rest, and classifying an argument can allocate */
2861
+ RB_GC_GUARD(rest);
2609
2862
  /* Return Symbol for family consistency with
2610
2863
  CArray.value_to_data_type and ca.data_type. */
2611
2864
  return rb_ca_data_type_to_sym(cur);
@@ -2745,6 +2998,8 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
2745
2998
  *other = ca_operand_from_memory_view(*other);
2746
2999
  }
2747
3000
 
3001
+ ca_array_operand(other, *self, 0);
3002
+
2748
3003
  if ( ! rb_obj_is_carray(*other) ) {
2749
3004
  if ( rb_ca_is_object_type(*self) ) {
2750
3005
  *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
@@ -2787,7 +3042,9 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
2787
3042
  return;
2788
3043
  }
2789
3044
 
2790
- rb_raise(rb_eTypeError,
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,
2791
3048
  "can't coerce carray with data_types of '%s' and '%s'",
2792
3049
  ca_coerce_operand_name(*self, ca),
2793
3050
  ca_coerce_operand_name(*other, cb));
@@ -2813,69 +3070,89 @@ rb_ca_cast_with (VALUE self, VALUE other)
2813
3070
  /* -----------------------------------------------------------------------
2814
3071
  clip_<type> family — clip into the target data type's representable
2815
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.
2816
3081
  ----------------------------------------------------------------------- */
2817
3082
 
2818
- #define CLIP_CAST_FUNC(name, lo_expr, hi_expr, cast_func) \
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) \
2819
3134
  static VALUE \
2820
3135
  rb_ca_##name (VALUE self) \
2821
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
+ } \
2822
3142
  return cast_func(rb_ca_clip(self, lo_expr, hi_expr)); \
2823
3143
  }
2824
3144
 
2825
- CLIP_CAST_FUNC(clip_int8, INT2NUM(-128), INT2NUM(127), rb_ca_as_int8)
2826
- CLIP_CAST_FUNC(clip_int16, INT2NUM(-32768), INT2NUM(32767), rb_ca_as_int16)
2827
- CLIP_CAST_FUNC(clip_int32, INT2NUM(-2147483648), INT2NUM(2147483647), rb_ca_as_int32)
2828
- CLIP_CAST_FUNC(clip_int64, LL2NUM(-9223372036854775807-1), LL2NUM(9223372036854775807), rb_ca_as_int64)
2829
- CLIP_CAST_FUNC(clip_uint8, INT2NUM(0), INT2NUM(255), rb_ca_as_uint8)
2830
- CLIP_CAST_FUNC(clip_uint16, INT2NUM(0), INT2NUM(65535), rb_ca_as_uint16)
2831
- CLIP_CAST_FUNC(clip_uint32, INT2NUM(0), UINT2NUM(4294967295U), rb_ca_as_uint32)
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)
2832
3153
 
2833
3154
  #undef CLIP_CAST_FUNC
2834
3155
 
2835
- /* CArray#clip_uint64 -- dedicated implementation.
2836
-
2837
- UINT64_MAX (= 2^64-1) is not exactly representable in float64; the nearest
2838
- double rounds up to 2^64. A generic clip-then-cast path therefore clamps
2839
- an overflowing float source (e.g. 1e20) to 2^64 and the subsequent cast to
2840
- uint64 wraps around to 0. For floating-point sources we take a saturating
2841
- path: compare in float space against 2^64 (which IS representable) and
2842
- saturate to UINT64_MAX above it and 0 below zero. Other source data types use
2843
- the plain clip-then-cast path. */
2844
- static VALUE
2845
- rb_ca_clip_uint64 (VALUE self)
2846
- {
2847
- CArray *ca;
2848
- GetCArray(self, ca);
2849
- int dt = ca->data_type;
2850
- if ( dt == CA_FLOAT32 || dt == CA_FLOAT64 ) {
2851
- volatile VALUE vsrc = ( dt == CA_FLOAT64 ) ? self : rb_ca_as_float64(self);
2852
- CArray *src;
2853
- GetCArray(vsrc, src);
2854
- volatile VALUE vout = rb_carray_new(CA_UINT64, ca->ndim, ca->dim, 0, NULL);
2855
- CArray *out;
2856
- GetCArray(vout, out);
2857
- ca_attach(src); /* window: nothing raises inside */
2858
- double *sp = (double *) src->ptr;
2859
- uint64_t *op = (uint64_t *) out->ptr;
2860
- ca_size_t n = ca->elements;
2861
- const double LIMIT = 18446744073709551616.0; /* 2^64, exact in f64 */
2862
- for ( ca_size_t i = 0; i < n; i++ ) {
2863
- double v = sp[i];
2864
- if ( v != v ) op[i] = 0; /* NaN -> 0 */
2865
- else if ( v >= LIMIT ) op[i] = UINT64_MAX;
2866
- else if ( v <= 0.0 ) op[i] = 0;
2867
- else op[i] = (uint64_t) v;
2868
- }
2869
- ca_detach(src);
2870
- if ( ca_has_mask(ca) ) {
2871
- ca_copy_mask(out, ca);
2872
- }
2873
- return vout;
2874
- }
2875
- return rb_ca_as_uint64(rb_ca_clip(self, INT2NUM(0),
2876
- ULL2NUM(18446744073709551615ULL)));
2877
- }
2878
-
2879
3156
  /* ------------------------------------------------------------------------
2880
3157
  Global cast functions CA_INT32(data) ... CA_OBJECT(data) etc.
2881
3158
 
@@ -2889,7 +3166,7 @@ rb_ca_clip_uint64 (VALUE self)
2889
3166
  Numeric -> CScalar, or #to_ca when the object answers it
2890
3167
  String -> the whitespace / `,` / `;` / `_`->UNDEF parser, which reads
2891
3168
  far more naturally in Ruby and so is the one branch that
2892
- calls back out to it (CArray.__cast_string__ in
3169
+ calls back out to it (CArray.cast_string in
2893
3170
  carray/basics.rb, eager-loaded). It receives the data_type
2894
3171
  as a Symbol.
2895
3172
 
@@ -3541,6 +3818,8 @@ Init_carray_cast (void)
3541
3818
  "result_type", rb_ca_s_result_type, -1);
3542
3819
  rb_define_private_method(rb_cCArray,
3543
3820
  "value_match_type", rb_ca_value_match_type, 2);
3821
+ rb_define_private_method(rb_cCArray,
3822
+ "query_match_type", rb_ca_query_match_type, 1);
3544
3823
 
3545
3824
  rb_define_singleton_method(rb_cCArray,
3546
3825
  "promote_list", rb_ca_s_promote_list, -1);
@@ -3554,7 +3833,7 @@ Init_carray_cast (void)
3554
3833
  classes registered in ext/carray_data_type.c. */
3555
3834
  id_new_cast = rb_intern("new");
3556
3835
  id_guess_array_shape_cast = rb_intern("guess_array_shape");
3557
- id_cast_string = rb_intern("__cast_string__");
3836
+ id_cast_string = rb_intern("cast_string");
3558
3837
  id_to_ca_cast = rb_intern("to_ca");
3559
3838
  id_length_cast = rb_intern("length");
3560
3839
  id_begin_cast = rb_intern("begin");