carray 3.0.3 → 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.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. 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);
@@ -1767,8 +1771,11 @@ rb_ca_ptr2ptr (VALUE ra1, void *ptr1, VALUE ra2, void *ptr2)
1767
1771
  }
1768
1772
 
1769
1773
 
1774
+ /* A cell's bytes as the value of self's data type before the last two
1775
+ steps of ca[i]: a boolean is 0 or 1 and a Face cell is its storage
1776
+ value. The element readers call this, check the mask, then decode. */
1770
1777
  VALUE
1771
- rb_ca_ptr2obj (VALUE self, void *ptr)
1778
+ rb_ca_ptr2obj_storage (VALUE self, void *ptr)
1772
1779
  {
1773
1780
  volatile VALUE obj;
1774
1781
  static CArray dummy;
@@ -1784,6 +1791,20 @@ rb_ca_ptr2obj (VALUE self, void *ptr)
1784
1791
  }
1785
1792
  }
1786
1793
 
1794
+ VALUE
1795
+ rb_ca_ptr2obj (VALUE self, void *ptr)
1796
+ {
1797
+ CArray *ca;
1798
+ VALUE obj = rb_ca_ptr2obj_storage(self, ptr);
1799
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1800
+ CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(obj, self, ca);
1801
+ if ( ca->data_type == CA_BOOLEAN &&
1802
+ ( obj == INT2FIX(0) || obj == INT2FIX(1) ) ) {
1803
+ obj = ( obj == INT2FIX(1) ) ? Qtrue : Qfalse;
1804
+ }
1805
+ return obj;
1806
+ }
1807
+
1787
1808
  /* Surface -> storage-domain conversion for a Face store (mirror of the
1788
1809
  storage_to_element read hook). Non-Face `ca` returns `obj` unchanged, so
1789
1810
  the non-Face store path is untouched. For a Face, the per-obj_type C
@@ -1853,7 +1874,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1853
1874
  if ( rb_obj_is_carray(obj) ) { /* obj == carray */
1854
1875
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1855
1876
  if ( ca_is_readonly(ca) ) {
1856
- rb_raise(rb_eRuntimeError, "can not modify read-only array");
1877
+ ca_refuse_read_only();
1857
1878
  }
1858
1879
  if ( NIL_P(rtype) ) {
1859
1880
  data_type = ca->data_type;
@@ -1891,7 +1912,7 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1891
1912
  }
1892
1913
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
1893
1914
  if ( ca_is_readonly(ca) ) {
1894
- rb_raise(rb_eRuntimeError, "can not modify read-only array");
1915
+ ca_refuse_read_only();
1895
1916
  }
1896
1917
  if ( NIL_P(rtype) ) {
1897
1918
  data_type = ca->data_type;
@@ -1905,12 +1926,9 @@ rb_ca_wrap_writable (VALUE arg, VALUE rtype)
1905
1926
  }
1906
1927
  }
1907
1928
  else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
1908
- obj = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
1929
+ obj = ca_mv_wrap(obj, Qnil, rb_cCAWrap, -1,
1930
+ NIL_P(rtype) ? -1 : rb_ca_guess_type(rtype), 1);
1909
1931
  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
1932
  if ( NIL_P(rtype) ) {
1915
1933
  data_type = ca->data_type;
1916
1934
  }
@@ -2029,7 +2047,8 @@ rb_ca_wrap_readonly (VALUE arg, VALUE rtype)
2029
2047
  }
2030
2048
  }
2031
2049
  else if ( rb_memory_view_available_p(obj) ) { /* MemoryView producer */
2032
- obj = rb_funcall(rb_cCArray, rb_intern("wrap_memory_view"), 1, obj);
2050
+ obj = ca_mv_wrap(obj, Qnil, rb_cCAWrap, -1,
2051
+ NIL_P(rtype) ? -1 : rb_ca_guess_type(rtype), 0);
2033
2052
  TypedData_Get_Struct(obj, CArray, &carray_data_type, ca);
2034
2053
  if ( NIL_P(rtype) ) {
2035
2054
  data_type = ca->data_type;
@@ -2171,6 +2190,36 @@ ca_check_integer_fits (VALUE v, int8_t dt)
2171
2190
  }
2172
2191
  }
2173
2192
 
2193
+ /* The store reader for an integer cell: the value as an Integer, refused
2194
+ when it does not fit the cell's type, as an operator refuses it. A
2195
+ store raises where an array cast (to_type) keeps the C conversion. A
2196
+ non-Integer goes through Integer() (1.5 is 1; nil and NaN raise). */
2197
+ VALUE
2198
+ ca_obj2integer_fitting (VALUE v, int8_t data_type)
2199
+ {
2200
+ VALUE integer = RB_INTEGER_TYPE_P(v) ? v : rb_Integer(v);
2201
+ if ( FIXNUM_P(integer) ) {
2202
+ long x = FIX2LONG(integer);
2203
+ int fits;
2204
+ switch ( data_type ) {
2205
+ case CA_INT8: fits = ( x >= INT8_MIN && x <= INT8_MAX ); break;
2206
+ case CA_UINT8: fits = ( x >= 0 && x <= UINT8_MAX ); break;
2207
+ case CA_INT16: fits = ( x >= INT16_MIN && x <= INT16_MAX ); break;
2208
+ case CA_UINT16: fits = ( x >= 0 && x <= UINT16_MAX ); break;
2209
+ case CA_INT32: fits = ( x >= INT32_MIN && x <= INT32_MAX ); break;
2210
+ case CA_UINT32: fits = ( x >= 0 && (unsigned long) x <= UINT32_MAX ); break;
2211
+ case CA_INT64: fits = 1; break;
2212
+ case CA_UINT64: fits = ( x >= 0 ); break;
2213
+ default: fits = 1; break;
2214
+ }
2215
+ if ( fits ) {
2216
+ return integer;
2217
+ }
2218
+ }
2219
+ ca_check_integer_fits(integer, data_type);
2220
+ return integer;
2221
+ }
2222
+
2174
2223
  /* A Ruby Integer operand against an integer array is taken in the array's
2175
2224
  own data type, refused when it does not fit (ca_check_integer_fits).
2176
2225
  Widening instead would make the result's type depend on a scalar's
@@ -2425,7 +2474,7 @@ ca_arg_to_data_type (VALUE obj)
2425
2474
  else {
2426
2475
  data_type = ca_value_to_data_type(obj);
2427
2476
  }
2428
- CA_CHECK_DATA_TYPE(data_type);
2477
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
2429
2478
  if ( ! ca_valid[data_type] ) {
2430
2479
  rb_raise(rb_eArgError,
2431
2480
  "data type '%s' is not valid in this build",
@@ -2465,6 +2514,9 @@ int8_t
2465
2514
  ca_promote_type (int8_t a, int8_t b)
2466
2515
  {
2467
2516
  int test;
2517
+ if ( a <= CA_NONE || a >= CA_NTYPE || b <= CA_NONE || b >= CA_NTYPE ) {
2518
+ rb_raise(rb_eArgError, "invalid data_type id (%i, %i)", (int) a, (int) b);
2519
+ }
2468
2520
  if ( a == b ) {
2469
2521
  return a;
2470
2522
  }
@@ -2521,6 +2573,49 @@ ca_value_match_type (int8_t t, int8_t a, int8_t b)
2521
2573
  }
2522
2574
  }
2523
2575
 
2576
+ /* The type a value query and a reference of type `ref` are compared in,
2577
+ by equality or order, as `eq` compares them: the reference is read
2578
+ through a view of that type, so the query is never cut to the
2579
+ reference's type (3.9 does not match 3, -1 does not read as 255).
2580
+ A Float query takes the type the operators give it beside the
2581
+ reference; an Integer query keeps the reference's type when it fits and
2582
+ otherwise the type its value needs, where it matches nothing; a CArray
2583
+ query takes the type the two arrays match in (the common type, widened
2584
+ by ca_value_match_type). Beside a reference that is not a number, a
2585
+ scalar query keeps the reference's type. */
2586
+ int8_t
2587
+ ca_query_match_type (int8_t ref, VALUE query)
2588
+ {
2589
+ int ref_int = ( ref >= CA_INT8 && ref <= CA_UINT64 );
2590
+ int ref_float = ( ref == CA_FLOAT32 || ref == CA_FLOAT64 );
2591
+ if ( rb_obj_is_carray(query) ) {
2592
+ CArray *q;
2593
+ TypedData_Get_Struct(query, CArray, &carray_data_type, q);
2594
+ return ca_value_match_type(ca_promote_type(ref, q->data_type), ref,
2595
+ q->data_type);
2596
+ }
2597
+ if ( ! ref_int && ! ref_float && ref != CA_BOOLEAN ) {
2598
+ return ref;
2599
+ }
2600
+ if ( RB_FLOAT_TYPE_P(query) ) {
2601
+ return ca_promote_scalar_type(ref, query, CA_FLOAT64);
2602
+ }
2603
+ if ( RB_INTEGER_TYPE_P(query) ) {
2604
+ return ref_int ? ca_promote_scalar_type(ref, query, CA_INT64) : ref;
2605
+ }
2606
+ return ref;
2607
+ }
2608
+
2609
+ /* ca.query_match_type(query) -- ca_query_match_type with self as the
2610
+ reference, for the set family and locate_addr. */
2611
+ static VALUE
2612
+ rb_ca_query_match_type (VALUE self, VALUE query)
2613
+ {
2614
+ CArray *ca;
2615
+ GetCArray(self, ca);
2616
+ return rb_ca_data_type_to_sym(ca_query_match_type(ca->data_type, query));
2617
+ }
2618
+
2524
2619
  /* ca.value_match_type(t, other_type) -- ca_value_match_type with self's
2525
2620
  data type as the first operand, for the set family and locate_addr. */
2526
2621
  static VALUE
@@ -2553,13 +2648,23 @@ ca_arg_is_scalar (VALUE obj)
2553
2648
  by the rule the operators apply: a scalar of the same kind takes the
2554
2649
  array's type (0.1 beside float32 is float32, 1 beside int8 is int8); one
2555
2650
  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. */
2651
+ does not fit the array's integer type takes a type that holds it and the
2652
+ array's values (int64, or object where no integer type does), where an
2653
+ operator would raise RangeError. */
2558
2654
  int8_t
2559
2655
  ca_promote_scalar_type (int8_t at, VALUE obj, int8_t st)
2560
2656
  {
2561
2657
  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);
2658
+ int8_t vt;
2659
+ if ( ca_integer_range_side(obj, at) == 0 ) {
2660
+ return at;
2661
+ }
2662
+ /* The type the value needs, widened so that the array's values are
2663
+ kept beside it (a uint64 array and -1 meet in object). */
2664
+ vt = ( ca_integer_range_side(obj, CA_INT64) == 0 ) ? CA_INT64
2665
+ : ( ca_integer_range_side(obj, CA_UINT64) == 0 ) ? CA_UINT64
2666
+ : CA_OBJECT;
2667
+ return ca_value_match_type(ca_promote_type(at, vt), at, vt);
2563
2668
  }
2564
2669
  if ( ca_cast_table2[st][at] >= 0 ) {
2565
2670
  return at;
@@ -2606,6 +2711,8 @@ rb_ca_s_result_type (int argc, VALUE *argv, VALUE klass)
2606
2711
  cur = ( cur < 0 ) ? t : ca_promote_scalar_type(cur, argv[i], t);
2607
2712
  }
2608
2713
  }
2714
+ /* argv points into rest, and classifying an argument can allocate */
2715
+ RB_GC_GUARD(rest);
2609
2716
  /* Return Symbol for family consistency with
2610
2717
  CArray.value_to_data_type and ca.data_type. */
2611
2718
  return rb_ca_data_type_to_sym(cur);
@@ -2859,14 +2966,23 @@ rb_ca_clip_uint64 (VALUE self)
2859
2966
  uint64_t *op = (uint64_t *) out->ptr;
2860
2967
  ca_size_t n = ca->elements;
2861
2968
  const double LIMIT = 18446744073709551616.0; /* 2^64, exact in f64 */
2969
+ boolean8_t *m = ca_has_mask(src) ? (boolean8_t *) src->mask->ptr : NULL; /* attached with src */
2970
+ int found_nan = 0;
2862
2971
  for ( ca_size_t i = 0; i < n; i++ ) {
2863
2972
  double v = sp[i];
2864
- if ( v != v ) op[i] = 0; /* NaN -> 0 */
2973
+ if ( v != v ) { /* NaN has no integer: refused below */
2974
+ op[i] = 0;
2975
+ if ( ! m || ! m[i] ) found_nan = 1;
2976
+ }
2865
2977
  else if ( v >= LIMIT ) op[i] = UINT64_MAX;
2866
2978
  else if ( v <= 0.0 ) op[i] = 0;
2867
2979
  else op[i] = (uint64_t) v;
2868
2980
  }
2869
2981
  ca_detach(src);
2982
+ if ( found_nan ) {
2983
+ rb_raise(rb_eFloatDomainError, "%s: NaN cannot be converted to uint64",
2984
+ ca_calling_method_name());
2985
+ }
2870
2986
  if ( ca_has_mask(ca) ) {
2871
2987
  ca_copy_mask(out, ca);
2872
2988
  }
@@ -2889,7 +3005,7 @@ rb_ca_clip_uint64 (VALUE self)
2889
3005
  Numeric -> CScalar, or #to_ca when the object answers it
2890
3006
  String -> the whitespace / `,` / `;` / `_`->UNDEF parser, which reads
2891
3007
  far more naturally in Ruby and so is the one branch that
2892
- calls back out to it (CArray.__cast_string__ in
3008
+ calls back out to it (CArray.cast_string in
2893
3009
  carray/basics.rb, eager-loaded). It receives the data_type
2894
3010
  as a Symbol.
2895
3011
 
@@ -3541,6 +3657,8 @@ Init_carray_cast (void)
3541
3657
  "result_type", rb_ca_s_result_type, -1);
3542
3658
  rb_define_private_method(rb_cCArray,
3543
3659
  "value_match_type", rb_ca_value_match_type, 2);
3660
+ rb_define_private_method(rb_cCArray,
3661
+ "query_match_type", rb_ca_query_match_type, 1);
3544
3662
 
3545
3663
  rb_define_singleton_method(rb_cCArray,
3546
3664
  "promote_list", rb_ca_s_promote_list, -1);
@@ -3554,7 +3672,7 @@ Init_carray_cast (void)
3554
3672
  classes registered in ext/carray_data_type.c. */
3555
3673
  id_new_cast = rb_intern("new");
3556
3674
  id_guess_array_shape_cast = rb_intern("guess_array_shape");
3557
- id_cast_string = rb_intern("__cast_string__");
3675
+ id_cast_string = rb_intern("cast_string");
3558
3676
  id_to_ca_cast = rb_intern("to_ca");
3559
3677
  id_length_cast = rb_intern("length");
3560
3678
  id_begin_cast = rb_intern("begin");
@@ -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 = {
@@ -300,7 +302,8 @@ puts
300
302
  *p2 = q;
301
303
  }
302
304
  else {
303
- rb_raise(rb_eRangeError, "out of range to cast to boolean (0 or 1)");
305
+ rb_raise(rb_eRangeError, "%s: out of range to cast to boolean (0 or 1)",
306
+ ca_calling_method_name());
304
307
  }
305
308
  }
306
309
  p1++; p2++; m++;
@@ -313,7 +316,8 @@ puts
313
316
  *p2 = q;
314
317
  }
315
318
  else {
316
- rb_raise(rb_eRangeError, "out of range to cast to boolean (0 or 1)");
319
+ rb_raise(rb_eRangeError, "%s: out of range to cast to boolean (0 or 1)",
320
+ ca_calling_method_name());
317
321
  }
318
322
  p1++; p2++;
319
323
  }
@@ -332,7 +336,34 @@ puts
332
336
  ctype1 = ctype[type1]
333
337
  ctype2 = ctype[type2]
334
338
  CA_CAST_TABLE[type1][type2] = "ca_cast_#{ctype1}_#{ctype2}"
335
- puts <<-END_DEF .gsub(/^ {6}/, '')
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)
336
367
  static void
337
368
  ca_cast_#{ctype1}_#{ctype2}(ca_size_t n, CArray *a1, void *ptr1, CArray *a2, void *ptr2, boolean8_t *m)
338
369
  {
@@ -341,6 +372,7 @@ puts
341
372
  #{ctype2} *q2 = ptr2;
342
373
  #{ctype2} *p2 = q2;
343
374
  ca_size_t k;
375
+ @@NAN_CHECK@@
344
376
  if ( m ) {
345
377
  boolean8_t *pm = m;
346
378
  for (k=0; k<n; k++) {
@@ -348,7 +380,7 @@ puts
348
380
  if ( ! *pm ) {
349
381
  p1 = q1 + k;
350
382
  p2 = q2 + k;
351
- *p2 = (#{ctype2}) *p1;
383
+ *p2 = (#{ctype2}) @@VIA@@*p1;
352
384
  }
353
385
  }
354
386
  }
@@ -356,7 +388,7 @@ puts
356
388
  for (k=0; k<n; k++) {
357
389
  p1 = q1 + k;
358
390
  p2 = q2 + k;
359
- *p2 = (#{ctype2}) *p1;
391
+ *p2 = (#{ctype2}) @@VIA@@*p1;
360
392
  }
361
393
  }
362
394
  return;
@@ -478,9 +510,17 @@ OBJECT.each do |type1|
478
510
  read_ok = "( RB_TYPE_P(*p1, T_STRING) ? " \
479
511
  "ca_decimal_string_to(*p1, #{type_name}, p2) : " \
480
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
481
521
  read = "if ( RB_TYPE_P(*p1, T_STRING) ) { " \
482
522
  "ca_decimal_string_store(*p1, #{type_name}, p2); } " \
483
- "else { *p2 = (#{ctype2}) #{conv}(*p1); }"
523
+ "else { *p2 = (#{ctype2}) #{store_conv}; }"
484
524
  else
485
525
  read_ok = "( #{conv_ok}(*p1, &tmp) ? ( *p2 = (#{ctype2}) tmp, 1 ) : 0 )"
486
526
  read = "*p2 = (#{ctype2}) #{conv}(*p1);"
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
- CA_CHECK_DATA_TYPE(data_type);
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
- CA_CHECK_DATA_TYPE(data_type);
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
- CA_CHECK_DATA_TYPE(data_type);
88
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
88
89
  return INT2NUM(data_type);
89
90
  }
90
91
 
@@ -0,0 +1,28 @@
1
+ #ifndef CARRAY_CONFIG_H
2
+ #define CARRAY_CONFIG_H
3
+ #define HAVE_SYS_TYPES_H 1
4
+ #define HAVE_STDINT_H 1
5
+ #define HAVE_TYPE_INT8_T 1
6
+ #define HAVE_TYPE_UINT8_T 1
7
+ #define HAVE_TYPE_INT16_T 1
8
+ #define HAVE_TYPE_UINT16_T 1
9
+ #define HAVE_TYPE_INT32_T 1
10
+ #define HAVE_TYPE_UINT32_T 1
11
+ #define HAVE_TYPE_INT64_T 1
12
+ #define HAVE_TYPE_UINT64_T 1
13
+ #define HAVE_TYPE_LONG_LONG 1
14
+ #define HAVE_TYPE_FLOAT 1
15
+ #define HAVE_TYPE_DOUBLE 1
16
+ #define HAVE_COMPLEX_H 1
17
+ #define HAVE_TYPE_FLOAT_COMPLEX 1
18
+ #define HAVE_TYPE_DOUBLE_COMPLEX 1
19
+ #define HAVE_TGMATH_H 1
20
+ #define HAVE_ATAN2 1
21
+ #define HAVE_HYPOT 1
22
+ #define HAVE_LGAMMA 1
23
+ #define HAVE_EXPM1 1
24
+ #define HAVE_MERGESORT 1
25
+ #define HAVE_STRPTIME 1
26
+ #define HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT 1
27
+ #define HAVE_RUBY_MEMORY_VIEW_H 1
28
+ #endif
@@ -480,10 +480,16 @@ rb_ca_load_binary (VALUE self, VALUE io)
480
480
  case T_STRING:
481
481
  if ( ca_length(ca) != RSTRING_LEN(io) ) {
482
482
  rb_raise(rb_eArgError,
483
- "data size mismatch (got %" PRId64 " bytes, expected %" PRId64 ")",
484
- (ca_size_t) RSTRING_LEN(io), (ca_size_t) ca_length(ca));
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);
485
490
  }
486
491
  ca_sync_data(ca, RSTRING_PTR(io));
492
+ RB_GC_GUARD(io);
487
493
  return self;
488
494
  break;
489
495
  default:
@@ -511,6 +517,9 @@ rb_ca_load_binary (VALUE self, VALUE io)
511
517
  memcpy(ca->ptr + off, RSTRING_PTR(r), want);
512
518
  off += want;
513
519
  }
520
+ if ( ca->data_type == CA_BOOLEAN ) {
521
+ ca_boolean_normalize_bytes(ca->ptr, ca->elements);
522
+ }
514
523
  ca_sync_detach(ca);
515
524
  }
516
525
  else {
@@ -540,7 +549,7 @@ rb_ca_load_binary (VALUE self, VALUE io)
540
549
  to float. Its digits are those of the decimal (at most 9, which a double
541
550
  holds), so Float#to_s writes them. */
542
551
  static double
543
- ca_float32_shortest (float x)
552
+ ca_double_of_shortest_decimal_of_float32 (float x)
544
553
  {
545
554
  char buf[32];
546
555
  int lo = 1, hi = 9;
@@ -576,7 +585,7 @@ ca_float32_shortest (float x)
576
585
  double its shortest decimal reads as, for to_csv to write that decimal.
577
586
  The mask is kept. */
578
587
  static VALUE
579
- rb_ca_shortest_float64 (VALUE self)
588
+ rb_ca_widen_keeping_shortest_decimal (VALUE self)
580
589
  {
581
590
  volatile VALUE out, holder = 0;
582
591
  CArray *ca, *co;
@@ -591,7 +600,7 @@ rb_ca_shortest_float64 (VALUE self)
591
600
  type = CA_CMPLX128;
592
601
  }
593
602
  else {
594
- rb_raise(rb_eCADataTypeError, "__shortest_float64__ takes float32 or cmplx64");
603
+ rb_raise(rb_eCADataTypeError, "__widen_keeping_shortest_decimal__ takes float32 or cmplx64");
595
604
  }
596
605
  n = ca->elements * (ca->data_type == CA_CMPLX64 ? 2 : 1);
597
606
  out = rb_carray_new_safe(type, ca->ndim, ca->dim, 0, NULL);
@@ -601,7 +610,7 @@ rb_ca_shortest_float64 (VALUE self)
601
610
  double *dst = (double *) co->ptr;
602
611
  ca_copy_data(ca, (char *) src);
603
612
  for (i = 0; i < n; i++) {
604
- dst[i] = ca_float32_shortest(src[i]);
613
+ dst[i] = ca_double_of_shortest_decimal_of_float32(src[i]);
605
614
  }
606
615
  ALLOCV_END(holder);
607
616
  }
@@ -627,7 +636,7 @@ Init_carray_conversion (void)
627
636
  rb_define_method(rb_cCArray, "dump_binary", rb_ca_dump_binary, -1);
628
637
  rb_define_method(rb_cCArray, "to_s", rb_ca_to_s, 0);
629
638
  rb_define_method(rb_cCArray, "load_binary", rb_ca_load_binary, 1);
630
- rb_define_method(rb_cCArray, "__shortest_float64__", rb_ca_shortest_float64, 0);
639
+ rb_define_method(rb_cCArray, "__widen_keeping_shortest_decimal__", rb_ca_widen_keeping_shortest_decimal, 0);
631
640
 
632
641
  /* CAREFUL: do not bind #to_ary — implicit array coercion in Ruby core
633
642
  (splat / multiple assignment / Array()) then triggers on any CArray
data/ext/carray_copy.c CHANGED
@@ -36,6 +36,42 @@ ca_fill_or_free (CArray *co, VALUE (*fill)(VALUE), VALUE arg)
36
36
  }
37
37
  }
38
38
 
39
+ void
40
+ ca_fill_or_xfree (void *buf, VALUE (*fill)(VALUE), VALUE arg)
41
+ {
42
+ int tag = 0;
43
+ rb_protect(fill, arg, &tag);
44
+ if ( tag ) {
45
+ xfree(buf);
46
+ rb_jump_tag(tag);
47
+ }
48
+ }
49
+
50
+ void
51
+ ca_fill_or_detach (int n, CArray **list, VALUE (*fill)(VALUE), VALUE arg)
52
+ {
53
+ int tag = 0;
54
+ int k;
55
+ rb_protect(fill, arg, &tag);
56
+ if ( tag ) {
57
+ for ( k = 0; k < n; k++ ) {
58
+ ca_detach(list[k]);
59
+ }
60
+ rb_jump_tag(tag);
61
+ }
62
+ }
63
+
64
+ VALUE
65
+ ca_view_inherit_mask (VALUE view)
66
+ {
67
+ CArray *ca = (CArray *) view;
68
+ CArray *parent = ((CAView *) ca)->parent;
69
+ if ( parent && ca_has_mask(parent) ) {
70
+ ca_create_mask(ca);
71
+ }
72
+ return Qnil;
73
+ }
74
+
39
75
  static VALUE
40
76
  ca_copy_fill (VALUE arg)
41
77
  {
@@ -173,7 +209,7 @@ rb_ca_to_ca (int argc, VALUE *argv, VALUE self)
173
209
  CArray *ca;
174
210
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
175
211
  if ( ca_is_readonly(ca) ) {
176
- rb_raise(rb_eRuntimeError, "can not modify read-only array");
212
+ ca_refuse_read_only();
177
213
  }
178
214
  }
179
215
  return self;
@@ -220,7 +256,7 @@ CArray *
220
256
  ca_template_safe2 (void *ap, int8_t data_type, ca_size_t bytes)
221
257
  {
222
258
  CArray *ca = (CArray *) ap;
223
- CA_CHECK_DATA_TYPE(data_type);
259
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
224
260
  if ( ca_is_scalar(ca) ) {
225
261
  return (CArray*) cscalar_new(data_type, bytes, NULL);
226
262
  }
@@ -261,6 +297,19 @@ rb_ca_template_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
261
297
  obj = ca_wrap_struct(co);
262
298
  }
263
299
 
300
+ /* Preserve the Face identity only for a same-type template (no explicit
301
+ * retype). A retype (template(:boolean)) is a different-typed buffer and
302
+ * must not be re-wrapped as the Face. A same-type template of a Face with
303
+ * a valid blank form (CARecord carries its data_class through the struct
304
+ * tail; identity Faces alias same-type storage) is lifted so the class is
305
+ * preserved. A Face with no valid blank form (CAConstString's content-
306
+ * defined offset+buffer) overrides `template` in Ruby to return a plain
307
+ * array instead of a broken same-class shell. The lift comes before the
308
+ * block initialiser so its values are stored through the Face. */
309
+ if ( NIL_P(rtype) ) {
310
+ CA_FACE_LIFT_IF_FACE(obj, self, ca);
311
+ }
312
+
264
313
  if ( rb_block_given_p() ) {
265
314
  if ( rb_proc_arity(rb_block_proc()) == 0 ) {
266
315
  volatile VALUE rval = rb_yield_values2(0, NULL);
@@ -283,18 +332,6 @@ rb_ca_template_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
283
332
  }
284
333
  }
285
334
 
286
- /* Preserve the Face identity only for a same-type template (no explicit
287
- * retype). A retype (template(:boolean)) is a different-typed buffer and
288
- * must not be re-wrapped as the Face. A same-type template of a Face with
289
- * a valid blank form (CARecord carries its data_class through the struct
290
- * tail; identity Faces alias same-type storage) is lifted so the class is
291
- * preserved. A Face with no valid blank form (CAConstString's content-
292
- * defined offset+buffer) overrides `template` in Ruby to return a plain
293
- * array instead of a broken same-class shell. */
294
- if ( NIL_P(rtype) ) {
295
- CA_FACE_LIFT_IF_FACE(obj, self, ca);
296
- }
297
-
298
335
  return obj;
299
336
  }
300
337