carray 3.0.6 → 3.0.7

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +110 -0
  3. data/README.md +24 -3
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_group.c +6 -6
  6. data/ext/ca_binop_dispatch.c +8 -0
  7. data/ext/ca_binop_dispatch.h +1 -0
  8. data/ext/ca_categorical_iterator.c +7 -7
  9. data/ext/ca_kernel_iterator.h +6 -4
  10. data/ext/ca_obj_array.c +4 -4
  11. data/ext/ca_obj_bincmp.c +19 -3
  12. data/ext/ca_obj_binop.c +36 -11
  13. data/ext/ca_obj_bitarray.c +2 -4
  14. data/ext/ca_obj_bitfield.c +86 -4
  15. data/ext/ca_obj_byte_swap.c +2 -4
  16. data/ext/ca_obj_const_string.c +422 -257
  17. data/ext/ca_obj_face.c +71 -33
  18. data/ext/ca_obj_fake.c +112 -13
  19. data/ext/ca_obj_farray.c +7 -1
  20. data/ext/ca_obj_fixlen_string.c +51 -17
  21. data/ext/ca_obj_grid.c +12 -7
  22. data/ext/ca_obj_meld.c +5 -5
  23. data/ext/ca_obj_monop.c +65 -39
  24. data/ext/ca_obj_object.c +9 -9
  25. data/ext/ca_obj_reduce.c +2 -4
  26. data/ext/ca_obj_refer.c +104 -10
  27. data/ext/ca_obj_repeat.c +1 -1
  28. data/ext/ca_obj_roll.c +2 -4
  29. data/ext/ca_obj_select.c +8 -6
  30. data/ext/ca_obj_select_axis.c +8 -6
  31. data/ext/ca_obj_stack.c +5 -5
  32. data/ext/ca_obj_stride.c +46 -8
  33. data/ext/ca_obj_string.c +2 -2
  34. data/ext/ca_obj_tile.c +2 -4
  35. data/ext/ca_obj_triop.c +15 -12
  36. data/ext/ca_obj_window.c +22 -15
  37. data/ext/ca_op_ipower.c +63 -15
  38. data/ext/ca_op_powi.h +6 -29
  39. data/ext/ca_sort_kernels.h +3 -0
  40. data/ext/ca_sweep_engine.c +90 -23
  41. data/ext/ca_sweep_engine.h +5 -6
  42. data/ext/caframe_csv_reader.c +1 -1
  43. data/ext/carray.h +3 -1
  44. data/ext/carray_access.c +98 -39
  45. data/ext/carray_address_basis.c +98 -24
  46. data/ext/carray_broadcast.c +2 -2
  47. data/ext/carray_call_cfunc.c +5 -8
  48. data/ext/carray_cast.c +311 -37
  49. data/ext/carray_cast_func.rb +37 -5
  50. data/ext/carray_conversion.c +56 -2
  51. data/ext/carray_copy.c +24 -0
  52. data/ext/carray_core.c +69 -6
  53. data/ext/carray_count.c +28 -9
  54. data/ext/carray_element.c +9 -3
  55. data/ext/carray_factorize.c +11 -11
  56. data/ext/carray_histogram.c +2 -2
  57. data/ext/carray_index_classifier.c +7 -5
  58. data/ext/carray_internal.h +94 -0
  59. data/ext/carray_kernels_binop.c +55 -55
  60. data/ext/carray_kernels_init.c +14 -14
  61. data/ext/carray_kernels_monop.c +90 -140
  62. data/ext/carray_lazy.c +16 -1
  63. data/ext/carray_loop.c +9 -2
  64. data/ext/carray_mask.c +118 -11
  65. data/ext/carray_median_percentile.c +13 -8
  66. data/ext/carray_memory_view.c +41 -22
  67. data/ext/carray_operator.c +72 -11
  68. data/ext/carray_order.c +52 -9
  69. data/ext/carray_partition.c +1 -1
  70. data/ext/carray_random.c +1 -1
  71. data/ext/carray_round.c +24 -1
  72. data/ext/carray_scatter.c +4 -0
  73. data/ext/carray_segment.c +1 -1
  74. data/ext/carray_slab.c +13 -4
  75. data/ext/carray_sort.c +6 -3
  76. data/ext/carray_sort_kernel.c +24 -0
  77. data/ext/carray_struct.c +21 -6
  78. data/ext/carray_test.c +85 -39
  79. data/ext/carray_time_text.c +6 -0
  80. data/ext/carray_utils.c +124 -54
  81. data/ext/mk_call_cfunc.rb +6 -11
  82. data/ext/mkkernel.rb +37 -27
  83. data/ext/version.h +4 -4
  84. data/lib/carray/axis_group.rb +9 -6
  85. data/lib/carray/basics.rb +26 -8
  86. data/lib/carray/bincount_nd.rb +8 -2
  87. data/lib/carray/block_iterator.rb +48 -21
  88. data/lib/carray/categorical.rb +21 -8
  89. data/lib/carray/categorical_iterator.rb +2 -1
  90. data/lib/carray/conditional.rb +52 -4
  91. data/lib/carray/const_string.rb +74 -0
  92. data/lib/carray/construct.rb +2 -2
  93. data/lib/carray/core_extensions.rb +19 -68
  94. data/lib/carray/data_type_extension.rb +1 -0
  95. data/lib/carray/fixlen_string.rb +83 -1
  96. data/lib/carray/frame/column_verbs.rb +61 -6
  97. data/lib/carray/frame/concat.rb +50 -6
  98. data/lib/carray/frame/csv_parser.rb +13 -4
  99. data/lib/carray/frame/frame.rb +38 -6
  100. data/lib/carray/frame/group.rb +67 -40
  101. data/lib/carray/frame/io.rb +10 -5
  102. data/lib/carray/frame/join.rb +20 -6
  103. data/lib/carray/frame/records.rb +6 -4
  104. data/lib/carray/frame/reshape.rb +25 -5
  105. data/lib/carray/frame/verbs.rb +78 -25
  106. data/lib/carray/frame/windows.rb +30 -6
  107. data/lib/carray/fuse_source.rb +4 -2
  108. data/lib/carray/iterator.rb +8 -0
  109. data/lib/carray/key_windows.rb +10 -4
  110. data/lib/carray/lazy.rb +12 -17
  111. data/lib/carray/methods/bin.rb +3 -0
  112. data/lib/carray/methods/composition.rb +1 -1
  113. data/lib/carray/methods/factorize.rb +2 -0
  114. data/lib/carray/methods/gather_nd.rb +4 -1
  115. data/lib/carray/methods/is_in.rb +23 -3
  116. data/lib/carray/methods/locate_addr.rb +63 -12
  117. data/lib/carray/methods/repeat.rb +11 -1
  118. data/lib/carray/record_order.rb +35 -6
  119. data/lib/carray/runtime.rb +10 -0
  120. data/lib/carray/segment_iterator.rb +19 -16
  121. data/lib/carray/serialize.rb +22 -0
  122. data/lib/carray/slab_iterator.rb +1 -1
  123. data/lib/carray/stack.rb +3 -3
  124. data/lib/carray/string.rb +6 -6
  125. data/lib/carray/string_operation_extension.rb +25 -4
  126. data/lib/carray/struct_builder.rb +4 -1
  127. data/lib/carray/time.rb +190 -46
  128. data/lib/carray/window_iterator.rb +48 -12
  129. data/yard-stubs/ca_obj_bitfield.rb +4 -1
  130. data/yard-stubs/ca_obj_refer.rb +3 -0
  131. data/yard-stubs/ca_obj_window.rb +2 -1
  132. data/yard-stubs/carray_access.rb +4 -2
  133. data/yard-stubs/carray_cast.rb +6 -0
  134. data/yard-stubs/carray_count.rb +6 -3
  135. data/yard-stubs/carray_math.rb +5 -0
  136. data/yard-stubs/carray_order.rb +6 -0
  137. data/yard-stubs/carray_scatter.rb +2 -1
  138. data/yard-stubs/carray_test.rb +18 -5
  139. metadata +2 -2
data/ext/carray_cast.c CHANGED
@@ -607,10 +607,11 @@ OBJ2BOOL (VALUE v)
607
607
  else if ( v == Qtrue ) {
608
608
  return 1;
609
609
  }
610
- else if ( rb_obj_is_kind_of(v, rb_cInteger) ) {
611
- int flag = NUM2INT(v);
610
+ else if ( FIXNUM_P(v) ) {
611
+ /* an Integer past a Fixnum is no 0 or 1, and is refused below */
612
+ long flag = FIX2LONG(v);
612
613
  if ( flag == 0 || flag == 1 ) {
613
- return flag;
614
+ return (boolean8_t) flag;
614
615
  }
615
616
  }
616
617
  {
@@ -638,7 +639,7 @@ ca_str_nonfinite (const char *str, double *out)
638
639
  if ( ! strcasecmp(str, "nan")
639
640
  || ! strcasecmp(str, "+nan")
640
641
  || ! strcasecmp(str, "-nan") ) {
641
- *out = 0.0/0.0;
642
+ *out = NAN; /* 0.0/0.0 sets the sign bit on x86 */
642
643
  return 1;
643
644
  }
644
645
  else if ( ! strcasecmp(str, "inf")
@@ -831,6 +832,40 @@ ca_obj2integer_ok (VALUE val, int8_t wide_type, void *wide, VALUE *integer)
831
832
  return 1;
832
833
  }
833
834
 
835
+ /* The to_type reader of an object cell for an integer type: a number that
836
+ is not an Integer (Float, Rational, BigDecimal, Complex) and does not fit
837
+ the type is a missing value, as a float array's cell is. An Integer
838
+ keeps its low bytes (the readers below). Returns 1 when the cell may be
839
+ read on. */
840
+ int
841
+ ca_obj_number_fits_integer (VALUE val, int8_t data_type)
842
+ {
843
+ int state = 0;
844
+ volatile VALUE integer;
845
+ if ( RB_INTEGER_TYPE_P(val) || NIL_P(val) || RB_TYPE_P(val, T_STRING) ) {
846
+ return 1;
847
+ }
848
+ /* protect: converts the caller's value and reports failure; nothing is held */
849
+ integer = rb_protect(ca_kernel_integer, val, &state);
850
+ if ( state ) {
851
+ rb_set_errinfo(Qnil);
852
+ return 1; /* the reader fails it on its own */
853
+ }
854
+ return ca_integer_range_side(integer, data_type) == 0;
855
+ }
856
+
857
+ /* The low bytes of an Integer in two's complement, for the _ok readers
858
+ below: an Integer wider than the C type is cut to it, as an Integer that
859
+ fits a long is when the caller narrows it to the cell's type. These
860
+ readers report failure through their return value and do not raise, so
861
+ a Bignum cannot go through NUM2LONG and friends. */
862
+ static void
863
+ ca_integer_low_bytes (VALUE integer, void *out, size_t size)
864
+ {
865
+ rb_integer_pack(integer, out, 1, size, 0,
866
+ INTEGER_PACK_2COMP | INTEGER_PACK_NATIVE_BYTE_ORDER);
867
+ }
868
+
834
869
  int
835
870
  rb_obj2long_ok (VALUE val, long *out)
836
871
  {
@@ -843,7 +878,12 @@ rb_obj2long_ok (VALUE val, long *out)
843
878
  if ( ! ca_obj2integer_ok(val, CA_INT64, &wide, &integer) ) {
844
879
  return 0;
845
880
  }
846
- *out = NIL_P(integer) ? (long) wide : NUM2LONG(integer);
881
+ if ( NIL_P(integer) ) {
882
+ *out = (long) wide;
883
+ }
884
+ else {
885
+ ca_integer_low_bytes(integer, out, sizeof(*out));
886
+ }
847
887
  return 1;
848
888
  }
849
889
 
@@ -859,7 +899,12 @@ rb_obj2ulong_ok (VALUE val, unsigned long *out)
859
899
  if ( ! ca_obj2integer_ok(val, CA_UINT64, &wide, &integer) ) {
860
900
  return 0;
861
901
  }
862
- *out = NIL_P(integer) ? (unsigned long) wide : NUM2ULONG(integer);
902
+ if ( NIL_P(integer) ) {
903
+ *out = (unsigned long) wide;
904
+ }
905
+ else {
906
+ ca_integer_low_bytes(integer, out, sizeof(*out));
907
+ }
863
908
  return 1;
864
909
  }
865
910
 
@@ -875,7 +920,12 @@ rb_obj2ll_ok (VALUE val, long long *out)
875
920
  if ( ! ca_obj2integer_ok(val, CA_INT64, &wide, &integer) ) {
876
921
  return 0;
877
922
  }
878
- *out = NIL_P(integer) ? (long long) wide : NUM2LL(integer);
923
+ if ( NIL_P(integer) ) {
924
+ *out = (long long) wide;
925
+ }
926
+ else {
927
+ ca_integer_low_bytes(integer, out, sizeof(*out));
928
+ }
879
929
  return 1;
880
930
  }
881
931
 
@@ -891,7 +941,12 @@ rb_obj2ull_ok (VALUE val, unsigned long long *out)
891
941
  if ( ! ca_obj2integer_ok(val, CA_UINT64, &wide, &integer) ) {
892
942
  return 0;
893
943
  }
894
- *out = NIL_P(integer) ? (unsigned long long) wide : rb_num2ull(integer);
944
+ if ( NIL_P(integer) ) {
945
+ *out = (unsigned long long) wide;
946
+ }
947
+ else {
948
+ ca_integer_low_bytes(integer, out, sizeof(*out));
949
+ }
895
950
  return 1;
896
951
  }
897
952
 
@@ -1021,6 +1076,42 @@ ca_cast_block_with_mask (ca_size_t n, void *ap1, void *ptr1,
1021
1076
  ca_cast_func_table[ca1->data_type][ca2->data_type](n, ca1, ptr1, ca2, ptr2, m);
1022
1077
  }
1023
1078
 
1079
+ /* A store and a cast view: the masked cells are left alone and every other
1080
+ cell is converted as it is with no mask at all, so that the answer for a
1081
+ cell does not depend on another cell being masked. An object cell needs
1082
+ this: the table's loop with a mask is #to_type's, which wraps an integer
1083
+ the cell cannot hold and masks a value it cannot read. */
1084
+ void
1085
+ ca_cast_block_skip_masked (ca_size_t n, void *ap1, void *ptr1,
1086
+ void *ap2, void *ptr2, boolean8_t *m)
1087
+ {
1088
+ CArray *ca1 = (CArray *) ap1;
1089
+ CArray *ca2 = (CArray *) ap2;
1090
+ char *p1 = (char *) ptr1;
1091
+ char *p2 = (char *) ptr2;
1092
+ ca_size_t i = 0;
1093
+
1094
+ if ( m == NULL ) {
1095
+ ca_cast_block(n, ap1, ptr1, ap2, ptr2);
1096
+ return;
1097
+ }
1098
+ if ( ca1->data_type != CA_OBJECT ) {
1099
+ ca_cast_block_with_mask(n, ap1, ptr1, ap2, ptr2, m);
1100
+ return;
1101
+ }
1102
+ while ( i < n ) {
1103
+ ca_size_t j;
1104
+ if ( m[i] ) {
1105
+ i++;
1106
+ continue;
1107
+ }
1108
+ for ( j = i; j < n && ! m[j]; j++ ) {
1109
+ }
1110
+ ca_cast_block(j - i, ap1, p1 + i * ca1->bytes, ap2, p2 + i * ca2->bytes);
1111
+ i = j;
1112
+ }
1113
+ }
1114
+
1024
1115
  VALUE
1025
1116
  ca_ptr2obj (void *ap, void *ptr)
1026
1117
  {
@@ -1147,32 +1238,32 @@ rb_ca_face_numeric_projection (VALUE self, CArray *ca)
1147
1238
 
1148
1239
  if ( ! rb_respond_to(self, id_to_numeric) ) {
1149
1240
  rb_raise(rb_eTypeError,
1150
- "%s declares no numeric conversion: define #to_numeric to say "
1241
+ "%"PRIsVALUE" declares no numeric conversion: define #to_numeric to say "
1151
1242
  "how its values become numbers, or take the surface with "
1152
1243
  "to_type(:object) / the storage with #parent",
1153
- rb_obj_classname(self));
1244
+ rb_obj_class(self));
1154
1245
  }
1155
1246
 
1156
1247
  num = rb_funcall(self, id_to_numeric, 0);
1157
1248
 
1158
1249
  if ( ! rb_obj_is_carray(num) ) {
1159
1250
  rb_raise(rb_eTypeError,
1160
- "%s#to_numeric must return a CArray (got %s)",
1161
- rb_obj_classname(self), rb_obj_classname(num));
1251
+ "%"PRIsVALUE"#to_numeric must return a CArray (got %"PRIsVALUE")",
1252
+ rb_obj_class(self), rb_obj_class(num));
1162
1253
  }
1163
1254
 
1164
1255
  TypedData_Get_Struct(num, CArray, &carray_data_type, cn);
1165
1256
 
1166
1257
  if ( ca_is_face(cn) ) {
1167
1258
  rb_raise(rb_eTypeError,
1168
- "%s#to_numeric must return a plain CArray, not a Face (got %s)",
1169
- rb_obj_classname(self), rb_obj_classname(num));
1259
+ "%"PRIsVALUE"#to_numeric must return a plain CArray, not a Face (got %"PRIsVALUE")",
1260
+ rb_obj_class(self), rb_obj_class(num));
1170
1261
  }
1171
1262
 
1172
1263
  if ( cn->elements != ca->elements ) {
1173
1264
  rb_raise(rb_eArgError,
1174
- "%s#to_numeric returned %lld elements, expected %lld",
1175
- rb_obj_classname(self),
1265
+ "%"PRIsVALUE"#to_numeric returned %lld elements, expected %lld",
1266
+ rb_obj_class(self),
1176
1267
  (long long) cn->elements, (long long) ca->elements);
1177
1268
  }
1178
1269
 
@@ -1584,15 +1675,15 @@ ca_type_adapt_view (VALUE obj, VALUE rtype, int8_t data_type, int mode)
1584
1675
  return rb_ca_to_type_internal(1, args, obj);
1585
1676
  case CA_ADAPT_WRITABLE:
1586
1677
  rb_raise(rb_eTypeError,
1587
- "%s has no writable view in another data_type: the writes "
1678
+ "%"PRIsVALUE" has no writable view in another data_type: the writes "
1588
1679
  "would land on the storage its surface hides -- wrap "
1589
1680
  "#parent to reach that storage",
1590
- rb_obj_classname(obj));
1681
+ rb_obj_class(obj));
1591
1682
  default:
1592
1683
  rb_raise(rb_eTypeError,
1593
- "%s has no view of its values in another data_type: "
1684
+ "%"PRIsVALUE" has no view of its values in another data_type: "
1594
1685
  "#to_type gives the values, #parent the raw storage",
1595
- rb_obj_classname(obj));
1686
+ rb_obj_class(obj));
1596
1687
  }
1597
1688
  }
1598
1689
 
@@ -2158,7 +2249,7 @@ rb_ca_cast (volatile VALUE self)
2158
2249
  string semantics those bodies implement (min-width memcmp with a length
2159
2250
  tiebreak); this is only about a scalar standing in for a cell. */
2160
2251
  static int
2161
- ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
2252
+ ca_fixlen_scalar_operand (volatile VALUE *scalar, volatile VALUE reference)
2162
2253
  {
2163
2254
  CArray *cr;
2164
2255
  /* A String is the only operand that means a cell value here. A Regexp
@@ -2183,6 +2274,24 @@ ca_fixlen_scalar_operand (volatile VALUE *scalar, VALUE reference)
2183
2274
  return 1;
2184
2275
  }
2185
2276
 
2277
+ /* UNDEF as the scalar side of an operation with an array: a masked
2278
+ scalar of the array's own data_type and width. UNDEF has no value, so it
2279
+ cannot decide the type of the result; read as a Ruby object it would make
2280
+ an integer, boolean or fixlen operation answer an object array, while a
2281
+ float one kept its type. An operation the data type does not take
2282
+ (fixlen `+`) is refused as for any other operand. */
2283
+ static int
2284
+ ca_undef_scalar_operand (volatile VALUE *scalar, volatile VALUE reference)
2285
+ {
2286
+ CArray *cr;
2287
+ if ( *scalar != CA_UNDEF || ! rb_obj_is_carray(reference) ) {
2288
+ return 0;
2289
+ }
2290
+ TypedData_Get_Struct(reference, CArray, &carray_data_type, cr);
2291
+ *scalar = rb_cscalar_new_with_value(cr->data_type, cr->bytes, CA_UNDEF);
2292
+ return 1;
2293
+ }
2294
+
2186
2295
  /* Where a Ruby Integer falls against the range of integer data type `dt`:
2187
2296
  -1 below it, 1 above it, 0 inside. Anything but an Integer, and a
2188
2297
  non-integer `dt`, answer 0. */
@@ -2249,12 +2358,22 @@ ca_obj2integer_fitting (VALUE v, int8_t data_type)
2249
2358
  return integer;
2250
2359
  }
2251
2360
 
2361
+ VALUE
2362
+ ca_obj2integer_store (CArray *dst, VALUE v, int8_t data_type)
2363
+ {
2364
+ CArray *field = dst ? ca_bitfield_beneath(dst) : NULL;
2365
+ if ( field ) {
2366
+ return ca_bitfield_wrap_integer(field, v);
2367
+ }
2368
+ return ca_obj2integer_fitting(v, data_type);
2369
+ }
2370
+
2252
2371
  /* A Ruby Integer operand against an integer array is taken in the array's
2253
2372
  own data type, refused when it does not fit (ca_check_integer_fits).
2254
2373
  Widening instead would make the result's type depend on a scalar's
2255
2374
  value. A Float, a Face and an object array keep the coercion below. */
2256
2375
  static int
2257
- ca_integer_scalar_operand (volatile VALUE *scalar, VALUE reference)
2376
+ ca_integer_scalar_operand (volatile VALUE *scalar, volatile VALUE reference)
2258
2377
  {
2259
2378
  CArray *cr;
2260
2379
  if ( ! RB_INTEGER_TYPE_P(*scalar) || ! rb_obj_is_carray(reference) ) {
@@ -2278,7 +2397,7 @@ ca_integer_scalar_operand (volatile VALUE *scalar, VALUE reference)
2278
2397
  promoted together. Against an object array, a Face or a fixlen array an
2279
2398
  Array stays one value. */
2280
2399
  static int
2281
- ca_array_operand (volatile VALUE *ary, VALUE reference, int both)
2400
+ ca_array_operand (volatile VALUE *ary, volatile VALUE reference, int both)
2282
2401
  {
2283
2402
  CArray *cr;
2284
2403
  volatile VALUE flat, probe_self, probe;
@@ -2368,13 +2487,105 @@ ca_operand_from_memory_view (VALUE obj)
2368
2487
  its class. A Face reports the data type of its storage ("fixlen" for a
2369
2488
  time, a categorical, a record or a string column), which says nothing
2370
2489
  about what the operand is. */
2371
- static const char *
2490
+ static VALUE
2372
2491
  ca_coerce_operand_name (VALUE obj, CArray *ca)
2373
2492
  {
2374
2493
  if ( ca_is_face(ca) ) {
2375
- return rb_obj_classname(obj);
2494
+ return rb_obj_class(obj);
2495
+ }
2496
+ return rb_str_new_cstr(ca_type_name[ca->data_type]);
2497
+ }
2498
+
2499
+ int
2500
+ ca_value_foreign_to (CArray *ca, VALUE v)
2501
+ {
2502
+ if ( ca_is_face(ca) || ca->data_type == CA_OBJECT || ca->data_type == CA_FIXLEN ) {
2503
+ return 0;
2504
+ }
2505
+ if ( v == Qtrue || v == Qfalse || v == CA_UNDEF || rb_obj_is_carray(v) ) {
2506
+ return 0;
2507
+ }
2508
+ if ( RTEST(rb_obj_is_kind_of(v, rb_cNumeric)) || RB_TYPE_P(v, T_ARRAY) ) {
2509
+ return 0;
2510
+ }
2511
+ if ( rb_respond_to(v, rb_intern("to_ca")) || rb_memory_view_available_p(v) ) {
2512
+ return 0;
2513
+ }
2514
+ return 1;
2515
+ }
2516
+
2517
+ VALUE
2518
+ ca_truth_as_number (CArray *ca, VALUE v)
2519
+ {
2520
+ if ( ( v == Qtrue || v == Qfalse ) && ! ca_is_face(ca) &&
2521
+ ( ca_is_integer_type(ca) || ca_is_float_type(ca) ||
2522
+ ca_is_complex_type(ca) ) ) {
2523
+ return INT2FIX(v == Qtrue);
2376
2524
  }
2377
- return ca_type_name[ca->data_type];
2525
+ return v;
2526
+ }
2527
+
2528
+ /* The name Ruby's coercion error gives a value: nil and a Symbol by
2529
+ themselves, anything else by its class. */
2530
+ static VALUE
2531
+ ca_foreign_value_name (VALUE v)
2532
+ {
2533
+ if ( NIL_P(v) || SYMBOL_P(v) ) {
2534
+ return rb_inspect(v);
2535
+ }
2536
+ return rb_class_name(CLASS_OF(v));
2537
+ }
2538
+
2539
+ /* The Ruby class whose operator the array's cells answer for. */
2540
+ static const char *
2541
+ ca_cell_class_name (CArray *ca)
2542
+ {
2543
+ if ( ca_is_float_type(ca) ) return "Float";
2544
+ if ( ca_is_complex_type(ca) ) return "Complex";
2545
+ return "Integer";
2546
+ }
2547
+
2548
+ void
2549
+ ca_refuse_foreign_operand (VALUE v, volatile VALUE array)
2550
+ {
2551
+ CArray *ca;
2552
+ if ( ! rb_obj_is_carray(array) ) {
2553
+ return;
2554
+ }
2555
+ GetCArray(array, ca);
2556
+ if ( ca_value_foreign_to(ca, v) ) {
2557
+ rb_raise(rb_eTypeError, "%s: %" PRIsVALUE " can't be coerced into %s",
2558
+ ca_calling_method_name(), ca_foreign_value_name(v),
2559
+ ca_cell_class_name(ca));
2560
+ }
2561
+ }
2562
+
2563
+ void
2564
+ ca_refuse_foreign_order (VALUE v, volatile VALUE array)
2565
+ {
2566
+ CArray *ca;
2567
+ if ( ! rb_obj_is_carray(array) ) {
2568
+ return;
2569
+ }
2570
+ GetCArray(array, ca);
2571
+ if ( ca_value_foreign_to(ca, v) ) {
2572
+ rb_raise(rb_eArgError, "%s: comparison of %s with %" PRIsVALUE " failed",
2573
+ ca_calling_method_name(), ca_cell_class_name(ca),
2574
+ ca_foreign_value_name(v));
2575
+ }
2576
+ }
2577
+
2578
+ /* true and false are the numbers 0 and 1 to an operator, as a boolean
2579
+ array is: an integer array reads them through ca_value_to_data_type, and
2580
+ a float or complex array reads them here rather than through Float(). */
2581
+ static int
2582
+ ca_truth_scalar_operand (volatile VALUE *scalar)
2583
+ {
2584
+ if ( *scalar == Qtrue || *scalar == Qfalse ) {
2585
+ *scalar = rb_cscalar_new_with_value(CA_BOOLEAN, 0, *scalar);
2586
+ return 1;
2587
+ }
2588
+ return 0;
2378
2589
  }
2379
2590
 
2380
2591
  void
@@ -2402,6 +2613,7 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2402
2613
 
2403
2614
  if ( ! rb_obj_is_carray(*self) ) {
2404
2615
  self_is_object = 1;
2616
+ ca_refuse_foreign_operand(*self, *other);
2405
2617
  if ( rb_ca_is_object_type(*other) ) {
2406
2618
  *self = rb_cscalar_new_with_value(CA_OBJECT, 0, *self);
2407
2619
  }
@@ -2414,12 +2626,18 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2414
2626
  *self = rb_cscalar_new_with_value(CA_CMPLX128, 0, *self);
2415
2627
  }
2416
2628
  #endif
2629
+ else if ( ca_undef_scalar_operand(self, *other) ) {
2630
+ /* the array's own data_type; see the helper above */
2631
+ }
2417
2632
  else if ( ca_fixlen_scalar_operand(self, *other) ) {
2418
2633
  /* width taken from the fixlen reference; see the helper above */
2419
2634
  }
2420
2635
  else if ( ca_integer_scalar_operand(self, *other) ) {
2421
2636
  /* the array's own integer type; see the helper above */
2422
2637
  }
2638
+ else if ( ca_truth_scalar_operand(self) ) {
2639
+ /* boolean, promoted with the array below */
2640
+ }
2423
2641
  else if ( rb_ca_is_float_type(*other) ) {
2424
2642
  *self = rb_cscalar_new_with_value(CA_FLOAT64, 0, *self);
2425
2643
  }
@@ -2435,6 +2653,7 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2435
2653
 
2436
2654
  if ( ! rb_obj_is_carray(*other) ) {
2437
2655
  other_is_object = 1;
2656
+ ca_refuse_foreign_operand(*other, *self);
2438
2657
 
2439
2658
  if ( rb_ca_is_object_type(*self) ) {
2440
2659
  *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
@@ -2448,12 +2667,18 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2448
2667
  *other = rb_cscalar_new_with_value(CA_CMPLX128, 0, *other);
2449
2668
  }
2450
2669
  #endif
2670
+ else if ( ca_undef_scalar_operand(other, *self) ) {
2671
+ /* the array's own data_type; see the helper above */
2672
+ }
2451
2673
  else if ( ca_fixlen_scalar_operand(other, *self) ) {
2452
2674
  /* width taken from the fixlen reference; see the helper above */
2453
2675
  }
2454
2676
  else if ( ca_integer_scalar_operand(other, *self) ) {
2455
2677
  /* the array's own integer type; see the helper above */
2456
2678
  }
2679
+ else if ( ca_truth_scalar_operand(other) ) {
2680
+ /* boolean, promoted with the array below */
2681
+ }
2457
2682
  else if ( rb_ca_is_float_type(*self) ) {
2458
2683
  *other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
2459
2684
  }
@@ -2526,11 +2751,55 @@ rb_ca_cast_self_or_other (volatile VALUE *self, volatile VALUE *other)
2526
2751
  /* A data type the operation does not take, as `sqrt!` on an integer
2527
2752
  array is refused (CArray::DataTypeError is a TypeError). */
2528
2753
  rb_raise(rb_eCADataTypeError,
2529
- "can't coerce carray with data_types of '%s' and '%s'",
2754
+ "can't coerce carray with data_types of '%"PRIsVALUE"' and '%"PRIsVALUE"'",
2530
2755
  ca_coerce_operand_name(*self, ca),
2531
2756
  ca_coerce_operand_name(*other, cb));
2532
2757
  }
2533
2758
 
2759
+ /* The three operands of a three-operand expression at their common data_type.
2760
+ Pairs find that type, and they find it for operands that are not arrays
2761
+ yet. An array then goes to it in one step: taken through the pairs, it
2762
+ would pass through the type of the first pair (an int8 -1 becomes 255 in
2763
+ uint8 and stays 255 in uint64), and the answer would depend on the order
2764
+ of the operands. The arrays are then brought to one shape together
2765
+ (the size-1 broadcast of the pairs), after the cast: the cast starts from
2766
+ the operand as given, so a shape the pairs settled on is set again here. */
2767
+ void
2768
+ rb_ca_cast_three (volatile VALUE *v1, volatile VALUE *v2, volatile VALUE *v3)
2769
+ {
2770
+ volatile VALUE original[3];
2771
+ volatile VALUE *cast[3];
2772
+ CArray *ca;
2773
+ int8_t common;
2774
+ int i;
2775
+
2776
+ original[0] = *v1;
2777
+ original[1] = *v2;
2778
+ original[2] = *v3;
2779
+ cast[0] = v1;
2780
+ cast[1] = v2;
2781
+ cast[2] = v3;
2782
+
2783
+ rb_ca_cast_self_or_other(v1, v2);
2784
+ rb_ca_cast_self_or_other(v1, v3);
2785
+ rb_ca_cast_self_or_other(v2, v3);
2786
+ rb_ca_cast_self_or_other(v1, v2);
2787
+
2788
+ TypedData_Get_Struct(*v1, CArray, &carray_data_type, ca);
2789
+ common = ca->data_type;
2790
+ for ( i = 0; i < 3; i++ ) {
2791
+ if ( ! rb_obj_is_carray(original[i]) ) continue;
2792
+ TypedData_Get_Struct(original[i], CArray, &carray_data_type, ca);
2793
+ *cast[i] = ( ca->data_type != common && ! ca_is_face(ca) )
2794
+ ? rb_ca_wrap_readonly(original[i], INT2NUM(common))
2795
+ : original[i];
2796
+ }
2797
+ ca_broadcast_pair(v1, v2);
2798
+ ca_broadcast_pair(v1, v3);
2799
+ ca_broadcast_pair(v2, v3);
2800
+ ca_broadcast_pair(v1, v2);
2801
+ }
2802
+
2534
2803
  /* Refuses a pair of arrays with no common data_type in the words of
2535
2804
  rb_ca_cast_self_or_other (the eager operators'), and returns otherwise
2536
2805
  without casting either. A lazy builder calls it before it works out
@@ -2927,10 +3196,10 @@ rb_ca_s_promote_list (int argc, VALUE *argv, VALUE klass)
2927
3196
  TypedData_Get_Struct(elem, CArray, &carray_data_type, ca);
2928
3197
  if ( ca_is_face(ca) ) {
2929
3198
  rb_raise(rb_eArgError,
2930
- "promote_list: data_type %s cannot be applied to a list "
3199
+ "promote_list: data_type %"PRIsVALUE" cannot be applied to a list "
2931
3200
  "containing Face elements (= Face cannot be coerced to "
2932
3201
  "a primitive without losing identity)",
2933
- RSTRING_PTR(rb_inspect(data_type)));
3202
+ rb_inspect(data_type));
2934
3203
  }
2935
3204
  }
2936
3205
  {
@@ -2998,12 +3267,17 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
2998
3267
  ca_array_operand(other, *self, 0);
2999
3268
 
3000
3269
  if ( ! rb_obj_is_carray(*other) ) {
3270
+ ca_refuse_foreign_operand(*other, *self);
3001
3271
  if ( rb_ca_is_object_type(*self) ) {
3002
3272
  *other = rb_cscalar_new_with_value(CA_OBJECT, 0, *other);
3003
3273
  }
3004
- else if ( ca_fixlen_scalar_operand(other, *self) ) {
3274
+ else if ( ca_undef_scalar_operand(other, *self) ||
3275
+ ca_fixlen_scalar_operand(other, *self) ) {
3005
3276
  return; /* already the receiver's data_type and width */
3006
3277
  }
3278
+ else if ( ca_truth_scalar_operand(other) ) {
3279
+ /* boolean, promoted with the array below */
3280
+ }
3007
3281
  else if ( rb_ca_is_float_type(*self) ) {
3008
3282
  *other = rb_cscalar_new_with_value(CA_FLOAT64, 0, *other);
3009
3283
  }
@@ -3042,7 +3316,7 @@ rb_ca_cast_other (VALUE *self, volatile VALUE *other)
3042
3316
  /* A data type the operation does not take, as `sqrt!` on an integer
3043
3317
  array is refused (CArray::DataTypeError is a TypeError). */
3044
3318
  rb_raise(rb_eCADataTypeError,
3045
- "can't coerce carray with data_types of '%s' and '%s'",
3319
+ "can't coerce carray with data_types of '%"PRIsVALUE"' and '%"PRIsVALUE"'",
3046
3320
  ca_coerce_operand_name(*self, ca),
3047
3321
  ca_coerce_operand_name(*other, cb));
3048
3322
  }
@@ -3205,8 +3479,8 @@ ca_cast_impl (int8_t data_type, int argc, VALUE *argv)
3205
3479
  if ( argc == 2 && ! RTEST(rb_obj_is_kind_of(v, rb_cRange)) ) {
3206
3480
  rb_raise(rb_eArgError,
3207
3481
  "a step (the second argument) is only accepted "
3208
- "when the first argument is a Range (got %s)",
3209
- rb_obj_classname(v));
3482
+ "when the first argument is a Range (got %"PRIsVALUE")",
3483
+ rb_obj_class(v));
3210
3484
  }
3211
3485
 
3212
3486
  if ( TYPE(v) == T_ARRAY ) {
@@ -3359,18 +3633,18 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
3359
3633
  }
3360
3634
  bytes = ( maxlen > 0 ) ? maxlen : 1; /* all empty: one NUL byte */
3361
3635
  } else {
3362
- bytes = NUM2SIZE(bytes_v);
3636
+ bytes = ca_integer_arg(bytes_v, "bytes", NULL);
3363
3637
  }
3364
3638
  shape = rb_funcall(rb_cCArray, id_guess_array_shape_cast, 1, v);
3365
3639
  ndim = RARRAY_LEN(shape);
3366
- for ( i = 0; i < ndim; i++ ) dim[i] = NUM2SIZE(rb_ary_entry(shape, i));
3640
+ for ( i = 0; i < ndim; i++ ) dim[i] = ca_integer_arg(rb_ary_entry(shape, i), "a dimension", NULL);
3367
3641
  obj = rb_carray_new(CA_FIXLEN, (int8_t) ndim, dim, bytes, NULL);
3368
3642
  rb_ca_store_all(obj, v);
3369
3643
  return obj;
3370
3644
  }
3371
3645
  else if ( NIL_P(v) ) {
3372
3646
  ca_size_t dim0 = 0;
3373
- ca_size_t bytes = NIL_P(bytes_v) ? 1 : NUM2SIZE(bytes_v);
3647
+ ca_size_t bytes = NIL_P(bytes_v) ? 1 : ca_integer_arg(bytes_v, "bytes", NULL);
3374
3648
  return rb_carray_new(CA_FIXLEN, 1, &dim0, bytes, NULL);
3375
3649
  }
3376
3650
  else {
@@ -3387,7 +3661,7 @@ rb_ca_cast_fixlen (int argc, VALUE *argv, VALUE self)
3387
3661
  check reports it. */
3388
3662
  ca_size_t bytes = 0;
3389
3663
  if ( ! NIL_P(bytes_v) ) {
3390
- bytes = NUM2SIZE(bytes_v);
3664
+ bytes = ca_integer_arg(bytes_v, "bytes", NULL);
3391
3665
  }
3392
3666
  else if ( RB_TYPE_P(v, T_STRING) ) {
3393
3667
  bytes = ( RSTRING_LEN(v) > 0 ) ? RSTRING_LEN(v) : 1;
@@ -371,7 +371,29 @@ puts
371
371
  lo_cmp = ( type2 == CA_INT64 ) ? ">=" : ">"
372
372
  fits = "( v #{lo_cmp} #{lo} && v < #{hi} )"
373
373
  fits = "( #{fits} && ! isnan(cimag(q1[k])) )" if complex
374
- nan_check = <<-END_CHECK.gsub(/^ {6}/, '')
374
+ # The cells of a bit field view keep a float's integer part modulo
375
+ # 2 ** bits, as a Float stored on its own does (ca_obj2integer_store).
376
+ unless complex
377
+ num = [CA_UINT8, CA_UINT16, CA_UINT32, CA_UINT64].include?(type2) ? "rb_num2ull" : "NUM2LL"
378
+ nan_check << <<-END_FIELD.gsub(/^ {8}/, '')
379
+ if ( a2 && ca_bitfield_beneath(a2) ) {
380
+ for (k=0; k<n; k++) {
381
+ double v = (double) q1[k];
382
+ if ( m && m[k] ) {
383
+ continue;
384
+ }
385
+ if ( ! isfinite(v) ) {
386
+ rb_raise(rb_eFloatDomainError, "%s: %s cannot be converted to %s",
387
+ ca_calling_method_name(), isinf(v) ? "an infinity" : "NaN",
388
+ ca_type_name[#{type_const[type2]}]);
389
+ }
390
+ q2[k] = (#{ctype2}) #{num}(ca_obj2integer_store(a2, rb_float_new(v), #{type_const[type2]}));
391
+ }
392
+ return;
393
+ }
394
+ END_FIELD
395
+ end
396
+ nan_check << <<-END_CHECK.gsub(/^ {6}/, '')
375
397
  for (k=0; k<n; k++) {
376
398
  double v = (double) #{real};
377
399
  if ( ( ! m || ! m[k] ) && ! #{fits} ) {
@@ -537,18 +559,28 @@ OBJECT.each do |type1|
537
559
  # Ruby literal. Complex keeps its own reader.
538
560
  if (INTEGER+FLOAT).include?(type2)
539
561
  type_name = "CA_" + ctype2.sub(/_t\z/, "").upcase
562
+ # A number other than an Integer that does not fit an integer type
563
+ # is read as missing (ca_obj_number_fits_integer); an Integer keeps
564
+ # its low bytes.
565
+ fits = INTEGER.include?(type2) ?
566
+ "ca_obj_number_fits_integer(*p1, #{type_name}) && " : ""
540
567
  read_ok = "( RB_TYPE_P(*p1, T_STRING) ? " \
541
568
  "ca_decimal_string_to(*p1, #{type_name}, p2) : " \
542
- "( #{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 ) )"
569
+ "( #{fits}#{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 ) )"
543
570
  # A store refuses an integer the cell cannot hold
544
- # (ca_obj2integer_fitting); to_type, above, keeps the C conversion.
571
+ # (ca_obj2integer_store); to_type, above, keeps the C conversion.
545
572
  store_conv = if INTEGER.include?(type2)
546
573
  num = [CA_UINT8, CA_UINT16, CA_UINT32, CA_UINT64].include?(type2) ? "rb_num2ull" : "NUM2LL"
547
- "#{num}(ca_obj2integer_fitting(*p1, #{type_name}))"
574
+ "#{num}(ca_obj2integer_store(a2, *p1, #{type_name}))"
548
575
  else
549
576
  "#{conv}(*p1)"
550
577
  end
551
- read = "if ( RB_TYPE_P(*p1, T_STRING) ) { " \
578
+ # The cells of a bit field view read a String through
579
+ # ca_obj2integer_store too (it keeps the value modulo 2 ** bits).
580
+ str_test = INTEGER.include?(type2) ?
581
+ "RB_TYPE_P(*p1, T_STRING) && ! ( a2 && ca_bitfield_beneath(a2) )" :
582
+ "RB_TYPE_P(*p1, T_STRING)"
583
+ read = "if ( #{str_test} ) { " \
552
584
  "ca_decimal_string_store(*p1, #{type_name}, p2); } " \
553
585
  "else { *p2 = (#{ctype2}) #{store_conv}; }"
554
586
  else