carray 3.0.2 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +304 -0
  3. data/README.md +3 -4
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +225 -0
  6. data/ext/ca_axis_group.c +177 -99
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +66 -71
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +663 -214
  14. data/ext/ca_kernel_iterator.h +231 -167
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +132 -22
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +1 -0
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +96 -25
  25. data/ext/ca_obj_face.c +406 -64
  26. data/ext/ca_obj_face.h +92 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +21 -21
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +189 -107
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +543 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +47 -49
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -118
  46. data/ext/ca_obj_stride.c +195 -34
  47. data/ext/ca_obj_string.c +17 -18
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +149 -27
  54. data/ext/ca_op_ipower.c +24 -11
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_sort_kernels.h +70 -0
  58. data/ext/ca_sweep_engine.c +102 -79
  59. data/ext/ca_sweep_engine.h +7 -20
  60. data/ext/ca_triop_dispatch.c +4 -1
  61. data/ext/ca_triop_dispatch.h +5 -2
  62. data/ext/caframe_csv_reader.c +463 -0
  63. data/ext/carray.h +70 -27
  64. data/ext/carray_access.c +455 -211
  65. data/ext/carray_address_basis.c +177 -36
  66. data/ext/carray_attribute.c +45 -3
  67. data/ext/carray_bincount.c +32 -2
  68. data/ext/carray_broadcast.c +46 -14
  69. data/ext/carray_call_cfunc.c +0 -28
  70. data/ext/carray_cast.c +1444 -209
  71. data/ext/carray_cast_func.rb +34 -21
  72. data/ext/carray_conversion.c +197 -73
  73. data/ext/carray_copy.c +32 -11
  74. data/ext/carray_core.c +514 -122
  75. data/ext/carray_count.c +140 -87
  76. data/ext/carray_element.c +18 -27
  77. data/ext/carray_factorize.c +569 -277
  78. data/ext/carray_generate.c +76 -40
  79. data/ext/carray_histogram.c +152 -94
  80. data/ext/carray_hold.c +2 -1
  81. data/ext/carray_index_classifier.c +63 -96
  82. data/ext/carray_internal.h +385 -3
  83. data/ext/carray_lazy.c +834 -79
  84. data/ext/carray_loop.c +81 -65
  85. data/ext/carray_mask.c +682 -316
  86. data/ext/carray_math_kernel.h +1 -0
  87. data/ext/carray_median_percentile.c +221 -76
  88. data/ext/carray_memory_view.c +254 -248
  89. data/ext/carray_operator.c +1089 -359
  90. data/ext/carray_order.c +133 -69
  91. data/ext/carray_partition.c +102 -56
  92. data/ext/carray_random.c +273 -239
  93. data/ext/carray_scatter.c +308 -65
  94. data/ext/carray_segment.c +257 -0
  95. data/ext/carray_slab.c +170 -70
  96. data/ext/carray_sort.c +215 -218
  97. data/ext/carray_sort_kernel.c +8 -1
  98. data/ext/carray_struct.c +99 -21
  99. data/ext/carray_test.c +167 -64
  100. data/ext/carray_time_text.c +1182 -0
  101. data/ext/carray_utils.c +363 -98
  102. data/ext/extconf.rb +27 -2
  103. data/ext/mk_call_cfunc.rb +0 -2
  104. data/ext/mk_pow5_table.rb +35 -0
  105. data/ext/mkkernel.rb +1076 -846
  106. data/ext/ruby_carray.c +7 -1
  107. data/ext/version.h +4 -4
  108. data/ext/version.rb +4 -2
  109. data/lib/carray/attribute.rb +39 -0
  110. data/lib/carray/autoload_carray.rb +19 -0
  111. data/lib/carray/autoload_method_extension.rb +6 -0
  112. data/lib/carray/axis_group.rb +174 -26
  113. data/lib/carray/basics.rb +91 -25
  114. data/lib/carray/bincount_nd.rb +6 -0
  115. data/lib/carray/block_iterator.rb +118 -48
  116. data/lib/carray/boolean_reduce.rb +21 -29
  117. data/lib/carray/categorical.rb +94 -26
  118. data/lib/carray/categorical_iterator.rb +333 -826
  119. data/lib/carray/complex.rb +36 -29
  120. data/lib/carray/conditional.rb +94 -7
  121. data/lib/carray/const_string.rb +46 -0
  122. data/lib/carray/frame/concat.rb +157 -6
  123. data/lib/carray/frame/convert.rb +13 -7
  124. data/lib/carray/frame/csv_parser.rb +589 -82
  125. data/lib/carray/frame/describe.rb +79 -0
  126. data/lib/carray/frame/frame.rb +124 -25
  127. data/lib/carray/frame/group.rb +189 -63
  128. data/lib/carray/frame/io.rb +412 -72
  129. data/lib/carray/frame/join.rb +134 -46
  130. data/lib/carray/frame/records.rb +37 -16
  131. data/lib/carray/frame/reshape.rb +448 -0
  132. data/lib/carray/frame/sort.rb +26 -2
  133. data/lib/carray/frame/verbs.rb +715 -48
  134. data/lib/carray/frame.rb +2 -0
  135. data/lib/carray/fuse_source.rb +111 -2
  136. data/lib/carray/fusion.rb +229 -38
  137. data/lib/carray/inspect.rb +29 -11
  138. data/lib/carray/iterator.rb +14 -2
  139. data/lib/carray/lazy.rb +54 -30
  140. data/lib/carray/mask_gap_fill.rb +66 -52
  141. data/lib/carray/math.rb +32 -19
  142. data/lib/carray/meld_reduce.rb +40 -7
  143. data/lib/carray/methods/align_addr.rb +8 -4
  144. data/lib/carray/methods/bincount.rb +2 -2
  145. data/lib/carray/methods/bit_string.rb +14 -3
  146. data/lib/carray/methods/composition.rb +16 -10
  147. data/lib/carray/methods/factorize.rb +2 -2
  148. data/lib/carray/methods/gather_nd.rb +13 -2
  149. data/lib/carray/methods/insert_block.rb +9 -14
  150. data/lib/carray/methods/is_in.rb +117 -4
  151. data/lib/carray/methods/join.rb +1 -1
  152. data/lib/carray/methods/locate_addr.rb +177 -36
  153. data/lib/carray/methods/mode.rb +18 -1
  154. data/lib/carray/methods/repeat.rb +1 -20
  155. data/lib/carray/methods/resize.rb +21 -23
  156. data/lib/carray/methods/snap.rb +34 -12
  157. data/lib/carray/methods/unique.rb +11 -2
  158. data/lib/carray/record_order.rb +208 -0
  159. data/lib/carray/runtime.rb +14 -11
  160. data/lib/carray/segment_iterator.rb +990 -0
  161. data/lib/carray/serialize.rb +197 -27
  162. data/lib/carray/slab_iterator.rb +51 -27
  163. data/lib/carray/stack.rb +10 -4
  164. data/lib/carray/string_operation_extension.rb +4 -3
  165. data/lib/carray/struct.rb +142 -51
  166. data/lib/carray/struct_builder.rb +110 -14
  167. data/lib/carray/table.rb +2 -2
  168. data/lib/carray/time.rb +517 -103
  169. data/lib/carray/window_iterator.rb +127 -72
  170. data/lib/carray.rb +2 -2
  171. data/yard-stubs/ca_obj_array.rb +4 -4
  172. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  173. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  174. data/yard-stubs/ca_obj_fake.rb +1 -1
  175. data/yard-stubs/ca_obj_field.rb +1 -1
  176. data/yard-stubs/ca_obj_refer.rb +3 -3
  177. data/yard-stubs/ca_obj_roll.rb +0 -1
  178. data/yard-stubs/ca_obj_stride.rb +10 -7
  179. data/yard-stubs/ca_obj_transpose.rb +1 -1
  180. data/yard-stubs/ca_obj_window.rb +1 -2
  181. data/yard-stubs/carray_access.rb +5 -4
  182. data/yard-stubs/carray_broadcast.rb +1 -1
  183. data/yard-stubs/carray_cast.rb +78 -43
  184. data/yard-stubs/carray_conversion.rb +13 -1
  185. data/yard-stubs/carray_copy.rb +8 -3
  186. data/yard-stubs/carray_core.rb +3 -3
  187. data/yard-stubs/carray_count.rb +9 -0
  188. data/yard-stubs/carray_lazy.rb +5 -1
  189. data/yard-stubs/carray_loop.rb +4 -1
  190. data/yard-stubs/carray_mask.rb +34 -10
  191. data/yard-stubs/carray_math.rb +25 -13
  192. data/yard-stubs/carray_median_percentile.rb +10 -6
  193. data/yard-stubs/carray_order.rb +34 -13
  194. data/yard-stubs/carray_scatter.rb +10 -3
  195. data/yard-stubs/carray_segment.rb +72 -0
  196. data/yard-stubs/carray_slab.rb +2 -1
  197. data/yard-stubs/carray_sort.rb +43 -3
  198. data/yard-stubs/carray_test.rb +10 -0
  199. data/yard-stubs/carray_utils.rb +0 -26
  200. metadata +11 -19
  201. data/ext/ca_for_each_element.h +0 -239
  202. data/ext/carray_build_flags.h +0 -3
  203. data/ext/carray_config.h +0 -28
  204. data/ext/carray_kernels_bincmp.c +0 -4446
  205. data/ext/carray_kernels_binop.c +0 -11001
  206. data/ext/carray_kernels_init.c +0 -1131
  207. data/ext/carray_kernels_map.c +0 -3467
  208. data/ext/carray_kernels_moncmp.c +0 -2097
  209. data/ext/carray_kernels_monop.c +0 -18313
  210. data/ext/carray_kernels_reduce_aggregate.c +0 -26005
  211. data/ext/carray_kernels_reduce_boolean.c +0 -330
  212. data/ext/carray_kernels_reduce_cumulative.c +0 -14862
  213. data/ext/carray_kernels_reduce_extreme.c +0 -17494
  214. data/ext/carray_kernels_reduce_variance.c +0 -3910
  215. data/ext/carray_kernels_scan.c +0 -3693
  216. data/ext/carray_kernels_search.c +0 -32218
  217. data/ext/carray_kernels_sort.c +0 -10626
  218. data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_time.c CHANGED
@@ -14,6 +14,7 @@
14
14
  --------------------------------------------------------------------------- */
15
15
 
16
16
  #include "carray.h"
17
+ #include "carray_internal.h"
17
18
  #include "ca_obj_face.h"
18
19
 
19
20
  /* unit enum (base epoch is 1970-01-01) */
@@ -36,7 +37,7 @@ enum {
36
37
  typedef struct {
37
38
  /* === CAView prefix === */
38
39
  int16_t obj_type;
39
- int8_t data_type; /* fixed to CA_INT64 */
40
+ int8_t data_type; /* surface: CA_FIXLEN (storage is the int64 parent) */
40
41
  int8_t ndim;
41
42
  int32_t flags; /* CA_FLAG_IS_FACE set */
42
43
  ca_size_t bytes; /* fixed to sizeof(int64_t) */
@@ -182,6 +183,12 @@ ca_time_setup (CATime *ca, CArray *parent, int8_t unit, int64_t count)
182
183
  "CATime requires int64 storage (parent.data_type != CA_INT64)");
183
184
  }
184
185
 
186
+ /* ca == NULL asks for the checks above only, so that a constructor can
187
+ run them before it allocates. */
188
+ if ( ca == NULL ) {
189
+ return 0;
190
+ }
191
+
185
192
  ca->obj_type = CA_OBJ_TIME;
186
193
  /* The surface data_type is CA_FIXLEN, not CA_INT64: this routes
187
194
  mkkernel dispatch onto the ca_*_not_implement stubs so numeric
@@ -227,7 +234,9 @@ ca_time_setup (CATime *ca, CArray *parent, int8_t unit, int64_t count)
227
234
  CATime *
228
235
  ca_time_new (CArray *parent, int8_t unit, int64_t count)
229
236
  {
230
- CATime *ca = (CATime *) ca_array_alloc(CA_OBJ_TIME, parent->ndim);
237
+ CATime *ca;
238
+ ca_time_setup(NULL, parent, unit, count);
239
+ ca = (CATime *) ca_array_alloc(CA_OBJ_TIME, parent->ndim);
231
240
  ca_time_setup(ca, parent, unit, count);
232
241
  return ca;
233
242
  }
@@ -266,18 +275,6 @@ ca_time_func_allocate (void *ap)
266
275
  ca->ptr = ca->parent->ptr;
267
276
  }
268
277
 
269
- static void
270
- ca_time_func_create_mask (void *ap)
271
- {
272
- CATime *ca = (CATime *) ap;
273
- ca_update_mask(ca->parent);
274
- if ( ! ca->parent->mask ) {
275
- ca_create_mask(ca->parent);
276
- }
277
- ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
278
- CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
279
- }
280
-
281
278
  ca_operation_function_t ca_time_func = {
282
279
  -1, /* CA_OBJ_TIME — filled by ca_install_obj_type */
283
280
  CA_VIEW_ARRAY,
@@ -288,7 +285,7 @@ ca_operation_function_t ca_time_func = {
288
285
  ca_face_sync,
289
286
  ca_face_detach,
290
287
  ca_face_fill_data,
291
- ca_time_func_create_mask,
288
+ ca_view_func_create_mask,
292
289
  ca_face_xfer_index,
293
290
  ca_face_xfer_addrs,
294
291
  NULL, /* fold_stride: identity Face is not foldable */
@@ -422,16 +419,16 @@ rb_ca_time_unit (VALUE self)
422
419
  return ca_time_resolution(ca->count, ca->unit);
423
420
  }
424
421
 
425
- /* storage_to_scalar implemented in C to avoid per-cell Ruby method dispatch
426
- on the fetch hot path. CAREFUL: there must be no Ruby `storage_to_scalar`
422
+ /* storage_to_element implemented in C to avoid per-cell Ruby method dispatch
423
+ on the fetch hot path. CAREFUL: there must be no Ruby `storage_to_element`
427
424
  def in lib/carray/time.rb — require order would let a Ruby version
428
- shadow this C method (the Ruby `scalar_to_storage` write hook is a
425
+ shadow this C method (the Ruby `element_to_storage` write hook is a
429
426
  distinct method and does not collide).
430
427
  Since the Face surface is CA_FIXLEN, fetch delivers an 8-byte raw
431
428
  String. Decode it as the parent int64 (= storage), then construct
432
429
  CATime::Element(epoch, unit). */
433
430
  static VALUE
434
- rb_ca_time_storage_to_scalar (VALUE self, VALUE raw)
431
+ rb_ca_time_storage_to_element (VALUE self, VALUE raw)
435
432
  {
436
433
  CATime *ca;
437
434
  CATimeElement *s;
@@ -443,7 +440,7 @@ rb_ca_time_storage_to_scalar (VALUE self, VALUE raw)
443
440
  if ( TYPE(raw) == T_STRING ) {
444
441
  if ( RSTRING_LEN(raw) != (long) sizeof(int64_t) ) {
445
442
  rb_raise(rb_eArgError,
446
- "CATime#storage_to_scalar: expected %lu bytes, got %ld",
443
+ "CATime#storage_to_element: expected %lu bytes, got %ld",
447
444
  (unsigned long) sizeof(int64_t), RSTRING_LEN(raw));
448
445
  }
449
446
  memcpy(&epoch, RSTRING_PTR(raw), sizeof(int64_t));
@@ -476,6 +473,7 @@ rb_ca_time_initialize_copy (VALUE self, VALUE other)
476
473
  {
477
474
  CATime *ca, *cs;
478
475
  TypedData_Get_Struct(self, CATime, &catime_data_type, ca);
476
+ ca_check_uninitialized(ca);
479
477
  TypedData_Get_Struct(other, CATime, &catime_data_type, cs);
480
478
  if ( ca_func[CA_OBJ_TIME].pool_init ) {
481
479
  ca_array_pool_alloc(ca, CA_OBJ_TIME, cs->parent->ndim);
@@ -517,12 +515,12 @@ Init_ca_obj_time (void)
517
515
  rb_define_singleton_method(rb_cCATime, "__wrap__",
518
516
  rb_ca_time_wrap_method, 2);
519
517
  rb_define_method(rb_cCATime, "unit", rb_ca_time_unit, 0);
520
- rb_define_method(rb_cCATime, "storage_to_scalar",
521
- rb_ca_time_storage_to_scalar, 1);
522
- /* Registers the C-level fast path so CA_FACE_STORAGE_TO_SCALAR_IF_FACE can
518
+ rb_define_method(rb_cCATime, "storage_to_element",
519
+ rb_ca_time_storage_to_element, 1);
520
+ /* Registers the C-level fast path so CA_FACE_STORAGE_TO_ELEMENT_IF_FACE can
523
521
  skip rb_funcall on the hot path. */
524
- ca_face_register_storage_to_scalar(CA_OBJ_TIME,
525
- rb_ca_time_storage_to_scalar);
522
+ ca_face_register_storage_to_element(CA_OBJ_TIME,
523
+ rb_ca_time_storage_to_element);
526
524
  ca_face_register_state_compatible(CA_OBJ_TIME,
527
525
  ca_time_state_compatible);
528
526
  /* unit is pure metadata (= no per-parent buffer), so the Face wrap can
@@ -14,6 +14,7 @@
14
14
  --------------------------------------------------------------------------- */
15
15
 
16
16
  #include "carray.h"
17
+ #include "carray_internal.h"
17
18
  #include "ca_obj_face.h"
18
19
 
19
20
  /* The unit enum is shared with CATime (= same unit system).
@@ -26,7 +27,7 @@ extern void ca_time_extract_unit (VALUE unit, int8_t *base, int64_t *count);
26
27
  typedef struct {
27
28
  /* === CAView prefix === */
28
29
  int16_t obj_type;
29
- int8_t data_type; /* fixed to CA_INT64 */
30
+ int8_t data_type; /* surface: CA_FIXLEN (storage is the int64 parent) */
30
31
  int8_t ndim;
31
32
  int32_t flags; /* CA_FLAG_IS_FACE set */
32
33
  ca_size_t bytes; /* fixed to sizeof(int64_t) */
@@ -161,6 +162,12 @@ ca_timedelta_setup (CATimedelta *ca, CArray *parent, int8_t unit, int64_t count)
161
162
  "CATimedelta requires int64 storage (parent.data_type != CA_INT64)");
162
163
  }
163
164
 
165
+ /* ca == NULL asks for the checks above only, so that a constructor can
166
+ run them before it allocates. */
167
+ if ( ca == NULL ) {
168
+ return 0;
169
+ }
170
+
164
171
  ca->obj_type = CA_OBJ_TIMEDELTA;
165
172
  /* NonNumeric surface (the FIXLEN gate), like CATime: the storage is a
166
173
  count of `count x unit` ticks, and letting the numeric kernels read it
@@ -208,7 +215,9 @@ ca_timedelta_setup (CATimedelta *ca, CArray *parent, int8_t unit, int64_t count)
208
215
  CATimedelta *
209
216
  ca_timedelta_new (CArray *parent, int8_t unit, int64_t count)
210
217
  {
211
- CATimedelta *ca = (CATimedelta *) ca_array_alloc(CA_OBJ_TIMEDELTA, parent->ndim);
218
+ CATimedelta *ca;
219
+ ca_timedelta_setup(NULL, parent, unit, count);
220
+ ca = (CATimedelta *) ca_array_alloc(CA_OBJ_TIMEDELTA, parent->ndim);
212
221
  ca_timedelta_setup(ca, parent, unit, count);
213
222
  return ca;
214
223
  }
@@ -246,18 +255,6 @@ ca_timedelta_func_allocate (void *ap)
246
255
  ca->ptr = ca->parent->ptr;
247
256
  }
248
257
 
249
- static void
250
- ca_timedelta_func_create_mask (void *ap)
251
- {
252
- CATimedelta *ca = (CATimedelta *) ap;
253
- ca_update_mask(ca->parent);
254
- if ( ! ca->parent->mask ) {
255
- ca_create_mask(ca->parent);
256
- }
257
- ca->mask = (CArray *) ca_refer_new(ca->parent->mask,
258
- CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
259
- }
260
-
261
258
  ca_operation_function_t ca_timedelta_func = {
262
259
  -1, /* CA_OBJ_TIMEDELTA — filled by ca_install_obj_type */
263
260
  CA_VIEW_ARRAY,
@@ -268,7 +265,7 @@ ca_operation_function_t ca_timedelta_func = {
268
265
  ca_face_sync,
269
266
  ca_face_detach,
270
267
  ca_face_fill_data,
271
- ca_timedelta_func_create_mask,
268
+ ca_view_func_create_mask,
272
269
  ca_face_xfer_index,
273
270
  ca_face_xfer_addrs,
274
271
  NULL, /* fold_stride */
@@ -330,6 +327,7 @@ rb_ca_timedelta_initialize_copy (VALUE self, VALUE other)
330
327
  {
331
328
  CATimedelta *ca, *cs;
332
329
  TypedData_Get_Struct(self, CATimedelta, &catimedelta_data_type, ca);
330
+ ca_check_uninitialized(ca);
333
331
  TypedData_Get_Struct(other, CATimedelta, &catimedelta_data_type, cs);
334
332
  if ( ca_func[CA_OBJ_TIMEDELTA].pool_init ) {
335
333
  ca_array_pool_alloc(ca, CA_OBJ_TIMEDELTA, cs->parent->ndim);
@@ -338,12 +336,12 @@ rb_ca_timedelta_initialize_copy (VALUE self, VALUE other)
338
336
  return self;
339
337
  }
340
338
 
341
- /* storage_to_scalar implemented in C to avoid per-cell Ruby method dispatch
339
+ /* storage_to_element implemented in C to avoid per-cell Ruby method dispatch
342
340
  on the fetch hot path. Accepts either an Integer (INT64 surface fetch)
343
341
  or an 8-byte String (FIXLEN surface fetch); decodes the parent int64
344
342
  and constructs CATimedelta::Element(value, unit). */
345
343
  static VALUE
346
- rb_ca_timedelta_storage_to_scalar (VALUE self, VALUE raw)
344
+ rb_ca_timedelta_storage_to_element (VALUE self, VALUE raw)
347
345
  {
348
346
  CATimedelta *ca;
349
347
  CATimedeltaElement *s;
@@ -355,7 +353,7 @@ rb_ca_timedelta_storage_to_scalar (VALUE self, VALUE raw)
355
353
  if ( TYPE(raw) == T_STRING ) {
356
354
  if ( RSTRING_LEN(raw) != (long) sizeof(int64_t) ) {
357
355
  rb_raise(rb_eArgError,
358
- "CATimedelta#storage_to_scalar: expected %lu bytes, got %ld",
356
+ "CATimedelta#storage_to_element: expected %lu bytes, got %ld",
359
357
  (unsigned long) sizeof(int64_t), RSTRING_LEN(raw));
360
358
  }
361
359
  memcpy(&value, RSTRING_PTR(raw), sizeof(int64_t));
@@ -408,17 +406,17 @@ Init_ca_obj_timedelta (void)
408
406
  rb_define_singleton_method(rb_cCATimedelta, "__wrap__",
409
407
  rb_ca_timedelta_wrap_method, 2);
410
408
  rb_define_method(rb_cCATimedelta, "unit", rb_ca_timedelta_unit, 0);
411
- rb_define_method(rb_cCATimedelta, "storage_to_scalar",
412
- rb_ca_timedelta_storage_to_scalar, 1);
413
- /* Registers the state-compatibility predicate so CA_FACE_STORAGE_TO_SCALAR_IF_FACE
409
+ rb_define_method(rb_cCATimedelta, "storage_to_element",
410
+ rb_ca_timedelta_storage_to_element, 1);
411
+ /* Registers the state-compatibility predicate so CA_FACE_STORAGE_TO_ELEMENT_IF_FACE
414
412
  can skip rb_funcall on the hot path. */
415
413
  ca_face_register_state_compatible(CA_OBJ_TIMEDELTA,
416
414
  ca_timedelta_state_compatible);
417
415
  /* unit is pure metadata, no per-parent buffer; multi-parent Face lift
418
416
  is safe (portable = 1). */
419
417
  ca_face_register_state_portable(CA_OBJ_TIMEDELTA, 1);
420
- ca_face_register_storage_to_scalar(CA_OBJ_TIMEDELTA,
421
- rb_ca_timedelta_storage_to_scalar);
418
+ ca_face_register_storage_to_element(CA_OBJ_TIMEDELTA,
419
+ rb_ca_timedelta_storage_to_element);
422
420
 
423
421
  /* CATimedelta::Element as a C-backed TypedData class. The Ruby-side
424
422
  definition in lib/carray/time.rb keeps Comparable + to_seconds /
@@ -37,11 +37,11 @@ ca_trans_setup (CAStride *ca, CArray *parent, ca_size_t *imap)
37
37
  for (i = 0; i < ndim; i++) {
38
38
  idim = imap[i];
39
39
  if (idim < 0 || idim >= ndim) {
40
- rb_raise(rb_eRuntimeError,
40
+ rb_raise(rb_eArgError,
41
41
  "specified %i-th dimension number out of range", i);
42
42
  }
43
43
  if (map[idim] != -1) {
44
- rb_raise(rb_eRuntimeError,
44
+ rb_raise(rb_eArgError,
45
45
  "specified %i-th dimension number is duplicated", i);
46
46
  }
47
47
  map[idim] = i;
@@ -58,6 +58,12 @@ ca_trans_setup (CAStride *ca, CArray *parent, ca_size_t *imap)
58
58
  strides[i] = parent_byte_stride[imap[i]];
59
59
  }
60
60
 
61
+ /* ca == NULL asks for the checks above only, so that a constructor can
62
+ run them before it allocates. */
63
+ if ( ca == NULL ) {
64
+ return 0;
65
+ }
66
+
61
67
  ca_stride_setup(ca, CA_OBJ_TRANSPOSE, parent,
62
68
  parent->data_type, parent->bytes,
63
69
  ndim, newdim, strides, 0);
@@ -67,7 +73,9 @@ ca_trans_setup (CAStride *ca, CArray *parent, ca_size_t *imap)
67
73
  CAStride *
68
74
  ca_trans_new (CArray *parent, ca_size_t *imap)
69
75
  {
70
- CAStride *ca = (CAStride *) ca_array_alloc(CA_OBJ_TRANSPOSE, parent->ndim);
76
+ CAStride *ca;
77
+ ca_trans_setup(NULL, parent, imap);
78
+ ca = (CAStride *) ca_array_alloc(CA_OBJ_TRANSPOSE, parent->ndim);
71
79
  ca_trans_setup(ca, parent, imap);
72
80
  return ca;
73
81
  }
@@ -126,6 +134,7 @@ rb_ca_trans_initialize_copy (VALUE self, VALUE other)
126
134
  {
127
135
  CAStride *ca, *cs;
128
136
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
137
+ ca_check_uninitialized(ca);
129
138
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
130
139
  if ( ca_func[CA_OBJ_TRANSPOSE].pool_init ) {
131
140
  ca_array_pool_alloc(ca, CA_OBJ_TRANSPOSE, cs->ndim);
data/ext/ca_obj_triop.c CHANGED
@@ -20,9 +20,9 @@
20
20
  op1), src2 == scratch2, src3 == scratch3.
21
21
 
22
22
  Mask handling: none of the currently-defined triops (fma / fms /
23
- clip) trap on integer zero divisor, so m=NULL always at the
24
- kernel walk (SIMD fast path). Output mask is a blind OR of
25
- operand masks (create_mask time).
23
+ clip / select) trap on integer zero divisor, so m=NULL always at the
24
+ kernel walk (SIMD fast path). Output mask is the OR of the operand
25
+ masks, except for select (create_mask time).
26
26
 
27
27
  Cross-ndim promotion: intentional design rejection, mirroring
28
28
  CABinOp. Callers must reshape explicitly.
@@ -33,6 +33,7 @@
33
33
  #include "carray_internal.h" /* ca_lazy_arena_* */
34
34
  #include "ca_triop_dispatch.h"
35
35
  #include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE */
36
+ #include "carray_math_kernel.h" /* ca_triop_not_implement */
36
37
 
37
38
  extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
38
39
  ca_size_t *target_dim);
@@ -41,7 +42,6 @@ int8_t CA_OBJ_TRIOP;
41
42
  VALUE rb_cCATriOp;
42
43
 
43
44
  extern int8_t CA_OBJ_LAZY_MARKER;
44
- extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
45
45
 
46
46
  /* ------------------------------------------------------------------- */
47
47
  /* CATriOp struct */
@@ -222,25 +222,6 @@ ca_triop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
222
222
  ca_triop_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
223
223
  }
224
224
 
225
- static void
226
- ca_triop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
227
- void *data, int dir)
228
- {
229
- CATriOp *ca = (CATriOp *) ap;
230
- ca_size_t i;
231
- char *out = (char *) data;
232
-
233
- if ( dir != CA_XFER_GET ) {
234
- rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_addrs PUT)");
235
- }
236
-
237
- for ( i = 0; i < n; i++ ) {
238
- ca_size_t idx[CA_RANK_MAX];
239
- ca_addr2index((CArray *)ca, addrs[i], idx);
240
- ca_triop_func_xfer_index(ca, idx, out + i * ca->bytes, CA_XFER_GET);
241
- }
242
- }
243
-
244
225
  /* Test / observability counters (mirror CABinOp's counters). */
245
226
  ca_size_t ca_triop_scratch_acquire_count = 0;
246
227
  ca_size_t ca_triop_materialise_call_count = 0;
@@ -249,8 +230,7 @@ ca_size_t ca_triop_materialise_call_count = 0;
249
230
  be broadcast at step=0). Returns the scratch pointer; updates
250
231
  *step_out to 0 (scalar) or 1 (same-shape). */
251
232
  static void *
252
- pull_operand (CArray *op, int is_scalar, ca_size_t *starts,
253
- ca_size_t *counts, ca_size_t slab_n, int8_t ndim,
233
+ pull_operand (CArray *op, int is_scalar, const ca_lazy_req_t *req,
254
234
  ca_size_t *step_out)
255
235
  {
256
236
  void *scratch;
@@ -274,54 +254,40 @@ pull_operand (CArray *op, int is_scalar, ca_size_t *starts,
274
254
  *step_out = 0;
275
255
  }
276
256
  else {
277
- ca_size_t op_strides[CA_RANK_MAX];
278
- ca_size_t s = bytes;
279
- for ( k = ndim - 1; k >= 0; k-- ) {
280
- op_strides[k] = s;
281
- s *= counts[k];
282
- }
283
257
  scratch = ( op->data_type == CA_OBJECT )
284
- ? ca_lazy_arena_acquire_object(slab_n)
285
- : ca_lazy_arena_acquire(slab_n * bytes);
258
+ ? ca_lazy_arena_acquire_object(req->n)
259
+ : ca_lazy_arena_acquire(req->n * bytes);
286
260
  ca_triop_scratch_acquire_count++;
287
- ca_xfer_stride(op, starts, counts, op_strides, scratch, CA_XFER_GET);
261
+ ca_lazy_req_pull(op, req, scratch, CA_XFER_GET);
288
262
  *step_out = 1;
289
263
  }
290
264
  return scratch;
291
265
  }
292
266
 
267
+ /* Evaluate the cells a request names into `data` (packed, n cells). */
293
268
  static void
294
- ca_triop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
295
- ca_size_t *strides, void *data, int dir)
269
+ ca_triop_eval (CATriOp *to, const ca_lazy_req_t *req, void *data)
296
270
  {
297
- CATriOp *to = (CATriOp *) ap;
298
- ca_size_t slab_n;
299
- int8_t k;
271
+ ca_size_t slab_n = req->n;
300
272
  void *scratch2, *scratch3;
301
273
  ca_size_t op2_step, op3_step;
302
274
 
303
- if ( dir != CA_XFER_GET ) {
304
- rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_stride PUT)");
305
- }
306
275
  ca_triop_materialise_call_count++;
307
276
 
308
- slab_n = 1;
309
- for ( k = 0; k < to->ndim; k++ ) slab_n *= counts[k];
310
-
311
277
  /* Step 1: pull op1 into the output buffer. */
312
- ca_xfer_stride(to->parent, starts, counts, strides, data, CA_XFER_GET);
278
+ ca_lazy_req_pull(to->parent, req, data, CA_XFER_GET);
313
279
 
314
280
  /* Step 2: pull op2 into an arena scratch. */
315
- scratch2 = pull_operand(to->op2, to->op2_is_scalar, starts, counts,
316
- slab_n, to->ndim, &op2_step);
281
+ scratch2 = pull_operand(to->op2, to->op2_is_scalar, req, &op2_step);
317
282
 
318
283
  /* Step 3: pull op3 into another arena scratch. */
319
- scratch3 = pull_operand(to->op3, to->op3_is_scalar, starts, counts,
320
- slab_n, to->ndim, &op3_step);
284
+ scratch3 = pull_operand(to->op3, to->op3_is_scalar, req, &op3_step);
321
285
 
322
- /* Step 4: apply the kernel. ptr1 == ptr4 (in-place op1); no
323
- currently-defined triop traps, so m=NULL. */
286
+ /* Step 4: apply the kernel. ptr1 == ptr4 (in-place op1). No numeric
287
+ triop traps, so m=NULL; object cells call Ruby, and skip the masked
288
+ cells as the eager triop does. */
324
289
  {
290
+ boolean8_t *slab_mask = NULL;
325
291
  ca_triop_func_t fn = ca_triop_kernel_lookup_vvv(to->op_id, to->data_type);
326
292
  if ( fn == NULL ) {
327
293
  ca_lazy_arena_release(scratch3);
@@ -330,17 +296,51 @@ ca_triop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
330
296
  "CATriOp: kernel not implemented (op_id=%u data_type=%d)",
331
297
  (unsigned) to->op_id, (int) to->data_type);
332
298
  }
333
- fn(slab_n, NULL,
299
+ if ( to->data_type == CA_OBJECT ) {
300
+ CArray *ops[3];
301
+ ops[0] = to->parent;
302
+ ops[1] = to->op2;
303
+ ops[2] = to->op3;
304
+ slab_mask = ca_lazy_req_mask(req, 3, ops);
305
+ }
306
+ fn(slab_n, slab_mask,
334
307
  (char *)data, 1, /* src1 == dst (op1, in-place) */
335
308
  (char *)scratch2, op2_step, /* src2 (op2) */
336
309
  (char *)scratch3, op3_step, /* src3 (op3) */
337
310
  (char *)data, 1); /* dst */
311
+ if ( slab_mask ) ca_lazy_arena_release(slab_mask);
338
312
  }
339
313
 
340
314
  ca_lazy_arena_release(scratch3);
341
315
  ca_lazy_arena_release(scratch2);
342
316
  }
343
317
 
318
+ static void
319
+ ca_triop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
320
+ ca_size_t *strides, void *data, int dir)
321
+ {
322
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
323
+ ca_lazy_req_t req;
324
+ if ( dir != CA_XFER_GET ) {
325
+ rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_stride PUT)");
326
+ }
327
+ ca_lazy_req_region(&req, ap, starts, counts, strides);
328
+ ca_triop_eval((CATriOp *) ap, &req, data);
329
+ }
330
+
331
+ /* An address list is evaluated in one pass, as a region is. */
332
+ static void
333
+ ca_triop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
334
+ void *data, int dir)
335
+ {
336
+ ca_lazy_req_t req;
337
+ if ( dir != CA_XFER_GET ) {
338
+ rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_addrs PUT)");
339
+ }
340
+ ca_lazy_req_addrs(&req, n, addrs);
341
+ ca_triop_eval((CATriOp *) ap, &req, data);
342
+ }
343
+
344
344
  static void
345
345
  ca_triop_func_xfer_all (void *ap, void *data, int dir)
346
346
  {
@@ -419,61 +419,16 @@ ca_triop_func_fill_data (void *ap, void *ptr)
419
419
  rb_raise(rb_eRuntimeError, "CATriOp is read-only (fill_data)");
420
420
  }
421
421
 
422
- /* Build out.mask. Blind OR of the three operand masks — none of the
423
- currently-defined triops carry a Kleene 3-valued fixup. */
422
+ /* Build out.mask on each read (CAMaskOfOperands): the three operands'
423
+ masks ORed, except for select, which is masked where the condition is
424
+ or where the branch it chooses is. */
424
425
  static void
425
426
  ca_triop_func_create_mask (void *ap)
426
427
  {
427
428
  CATriOp *to = (CATriOp *) ap;
428
- CArray *op1 = to->parent;
429
- CArray *op2 = to->op2;
430
- CArray *op3 = to->op3;
431
- boolean8_t *dst, *m1, *m2, *m3;
432
- ca_size_t i, n;
433
- int has1, has2, has3;
434
-
435
- has1 = ca_has_mask(op1);
436
- has2 = ca_has_mask(op2);
437
- has3 = ca_has_mask(op3);
438
- if ( ! has1 && ! has2 && ! has3 ) return;
439
-
440
- /* Exactly one masked operand: the answer is that operand's mask, cell
441
- for cell. Share it rather than allocating a copy per node. */
442
- if ( has1 + has2 + has3 == 1 ) {
443
- CArray *src = has1 ? op1 : ( has2 ? op2 : op3 );
444
- if ( src->elements == to->elements ) {
445
- to->mask = (CArray *) ca_refer_new(src->mask, CA_BOOLEAN,
446
- to->ndim, to->dim, 0, 0);
447
- return;
448
- }
449
- }
450
-
451
- to->mask = (CArray *) carray_new(CA_BOOLEAN, to->ndim, to->dim, 0, NULL);
452
- dst = (boolean8_t *) to->mask->ptr;
453
- n = to->elements;
454
-
455
- /* The masks are what is read here; attaching the operand instead
456
- materialises the whole subexpression under it. */
457
- if ( has1 ) ca_attach(op1->mask);
458
- if ( has2 ) ca_attach(op2->mask);
459
- if ( has3 ) ca_attach(op3->mask);
460
-
461
- m1 = has1 ? (boolean8_t *) op1->mask->ptr : NULL;
462
- m2 = has2 ? (boolean8_t *) op2->mask->ptr : NULL;
463
- m3 = has3 ? (boolean8_t *) op3->mask->ptr : NULL;
464
-
465
- for ( i = 0; i < n; i++ ) {
466
- ca_size_t i2 = to->op2_is_scalar ? 0 : i;
467
- ca_size_t i3 = to->op3_is_scalar ? 0 : i;
468
- boolean8_t a = m1 ? m1[i] : 0;
469
- boolean8_t b = m2 ? m2[i2] : 0;
470
- boolean8_t c = m3 ? m3[i3] : 0;
471
- dst[i] = (boolean8_t) ( a | b | c );
472
- }
473
-
474
- if ( has3 ) ca_detach(op3->mask);
475
- if ( has2 ) ca_detach(op2->mask);
476
- if ( has1 ) ca_detach(op1->mask);
429
+ int mode = ( to->op_id == CA_TRIOP_SELECT ) ? CA_LAZY_MASK_SELECT
430
+ : CA_LAZY_MASK_OR;
431
+ to->mask = ca_lazy_operation_mask((CArray *) to, mode);
477
432
  }
478
433
 
479
434
  ca_operation_function_t ca_triop_func = {
@@ -574,21 +529,32 @@ rb_ca_triop_build (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
574
529
  r2 = collapse_marker(cary2);
575
530
  r3 = collapse_marker(cary3);
576
531
 
577
- /* Promote non-CArray Ruby values (e.g. clip's Numeric bounds) to
578
- CScalars carrying an existing operand's data_type. */
579
- if ( ! rb_obj_is_carray(r1) || ! rb_obj_is_carray(r2) || ! rb_obj_is_carray(r3) ) {
580
- /* Find an anchor CArray for scalar promotion. */
581
- CArray *anchor = NULL;
582
- if ( rb_obj_is_carray(r1) ) TypedData_Get_Struct(r1, CArray, &carray_data_type, anchor);
583
- else if ( rb_obj_is_carray(r2) ) TypedData_Get_Struct(r2, CArray, &carray_data_type, anchor);
584
- else if ( rb_obj_is_carray(r3) ) TypedData_Get_Struct(r3, CArray, &carray_data_type, anchor);
585
- if ( anchor == NULL ) {
532
+ /* select takes its branches already typed (CArray#then_else makes a
533
+ scalar branch a CScalar of the result type); the condition is boolean
534
+ and takes no part in the promotion. */
535
+ if ( op_id == CA_TRIOP_SELECT ) {
536
+ if ( ! rb_obj_is_carray(r1) || ! rb_obj_is_carray(r2) || ! rb_obj_is_carray(r3) ) {
537
+ rb_raise(rb_eArgError, "CATriOp: select takes three CArrays");
538
+ }
539
+ r2 = ca_lazy_settle_scalar(r2, RTEST(rb_obj_is_cscalar(r2)));
540
+ r3 = ca_lazy_settle_scalar(r3, RTEST(rb_obj_is_cscalar(r3)));
541
+ }
542
+ /* Scalar operands (clip's Numeric bounds, a CScalar) are wrapped and
543
+ promoted pairwise in the order the eager triop uses. */
544
+ else if ( ! rb_obj_is_carray(r1) || ! rb_obj_is_carray(r2) || ! rb_obj_is_carray(r3) ||
545
+ rb_obj_is_cscalar(r2) || rb_obj_is_cscalar(r3) ) {
546
+ if ( ! rb_obj_is_carray(r1) ) {
586
547
  rb_raise(rb_eArgError,
587
- "CATriOp: at least one operand must be a CArray");
548
+ "CATriOp: the first operand must be a CArray");
588
549
  }
589
- if ( ! rb_obj_is_carray(r1) ) r1 = ca_lazy_wrap_scalar(r1, anchor);
590
- if ( ! rb_obj_is_carray(r2) ) r2 = ca_lazy_wrap_scalar(r2, anchor);
591
- if ( ! rb_obj_is_carray(r3) ) r3 = ca_lazy_wrap_scalar(r3, anchor);
550
+ int r2_scalar = ! rb_obj_is_carray(r2) || rb_obj_is_cscalar(r2);
551
+ int r3_scalar = ! rb_obj_is_carray(r3) || rb_obj_is_cscalar(r3);
552
+ rb_ca_cast_self_or_other(&r1, &r2);
553
+ rb_ca_cast_self_or_other(&r1, &r3);
554
+ rb_ca_cast_self_or_other(&r2, &r3);
555
+ rb_ca_cast_self_or_other(&r1, &r2);
556
+ r2 = ca_lazy_settle_scalar(r2, r2_scalar);
557
+ r3 = ca_lazy_settle_scalar(r3, r3_scalar);
592
558
  }
593
559
 
594
560
  TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
@@ -599,6 +565,19 @@ rb_ca_triop_build (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
599
565
  ca_triop_kernel_input_data_types(op_id,
600
566
  op1->data_type, op2->data_type, op3->data_type,
601
567
  &dt1, &dt2, &dt3);
568
+
569
+ /* All boolean, and no boolean kernel (fma / fms): read the operands as
570
+ their 0/1 storage in int64, as rb_ca_call_triop does. */
571
+ if ( dt1 == CA_BOOLEAN &&
572
+ ca_triop_kernel_lookup_vvv(op_id, CA_BOOLEAN) == ca_triop_not_implement ) {
573
+ dt1 = dt2 = dt3 = CA_INT64;
574
+ }
575
+
576
+ /* No kernel for that data_type: raise as the eager triop does. */
577
+ if ( ca_triop_kernel_lookup_vvv(op_id, dt1) == ca_triop_not_implement ) {
578
+ rb_raise(rb_eCADataTypeError,
579
+ "invalid data_type for triop (not implemented)");
580
+ }
602
581
  r1 = insert_cast(r1, dt1, &op1);
603
582
  r2 = insert_cast(r2, dt2, &op2);
604
583
  r3 = insert_cast(r3, dt3, &op3);
@@ -668,6 +647,17 @@ rb_ca_triop_s_build (VALUE klass, VALUE cary1, VALUE cary2, VALUE cary3,
668
647
  return rb_ca_triop_build(cary1, cary2, cary3, op_id);
669
648
  }
670
649
 
650
+ /* Whether this node's kernel skips the cells its operands mask, rather
651
+ than computing them: a kernel that can raise on a cell or calls Ruby
652
+ for it. CArray::Fusion reads it so a plan carries the same rule. */
653
+ static VALUE
654
+ rb_ca_triop_trapping (VALUE self)
655
+ {
656
+ CArray *ca;
657
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
658
+ return ( ca->data_type == CA_OBJECT ) ? Qtrue : Qfalse;
659
+ }
660
+
671
661
  static VALUE
672
662
  rb_ca_triop_op_id (VALUE self)
673
663
  {
@@ -731,6 +721,7 @@ rb_ca_triop_initialize_copy (VALUE self, VALUE other)
731
721
  {
732
722
  CATriOp *ca, *cs;
733
723
  TypedData_Get_Struct(self, CATriOp, &catriop_data_type, ca);
724
+ ca_check_uninitialized(ca);
734
725
  TypedData_Get_Struct(other, CATriOp, &catriop_data_type, cs);
735
726
  if ( ca_func[CA_OBJ_TRIOP].pool_init ) {
736
727
  ca_array_pool_alloc(ca, CA_OBJ_TRIOP, cs->parent->ndim);
@@ -758,6 +749,7 @@ Init_ca_obj_triop (void)
758
749
  rb_define_const(rb_cCATriOp, "OP_FMA", INT2NUM(CA_TRIOP_FMA));
759
750
  rb_define_const(rb_cCATriOp, "OP_FMS", INT2NUM(CA_TRIOP_FMS));
760
751
  rb_define_const(rb_cCATriOp, "OP_CLIP", INT2NUM(CA_TRIOP_CLIP));
752
+ rb_define_const(rb_cCATriOp, "OP_SELECT", INT2NUM(CA_TRIOP_SELECT));
761
753
 
762
754
  rb_define_alloc_func(rb_cCATriOp, rb_ca_triop_s_allocate);
763
755
  rb_define_method(rb_cCATriOp, "initialize_copy",
@@ -768,6 +760,7 @@ Init_ca_obj_triop (void)
768
760
 
769
761
  rb_define_method(rb_cCATriOp, "__op_id__",
770
762
  rb_ca_triop_op_id, 0);
763
+ rb_define_method(rb_cCATriOp, "__trapping__", rb_ca_triop_trapping, 0);
771
764
  rb_define_method(rb_cCATriOp, "__triop_op2__",
772
765
  rb_ca_triop_op2, 0);
773
766
  rb_define_method(rb_cCATriOp, "__triop_op3__",