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_core.c CHANGED
@@ -323,12 +323,13 @@ ca_install_obj_type (VALUE klass,
323
323
  const ca_operation_function_t *func,
324
324
  size_t func_size)
325
325
  {
326
- int obj_type = ca_obj_num++;
326
+ int obj_type;
327
327
 
328
- if ( ca_obj_num >= CA_OBJ_TYPE_MAX ) {
328
+ /* The obj_type parameters of ca_array_alloc / ca_stride_setup are
329
+ int8_t, so a number of 128 or above cannot be passed to them. */
330
+ if ( ca_obj_num > INT8_MAX || ca_obj_num + 1 >= CA_OBJ_TYPE_MAX ) {
329
331
  rb_raise(rb_eRuntimeError,
330
- "internal: too many CArray object types installed <CA_OBJ_TYPE_MAX = %i>",
331
- CA_OBJ_TYPE_MAX);
332
+ "internal: too many CArray object types installed (an obj_type is numbered below 128)");
332
333
  }
333
334
 
334
335
  if ( func_size > sizeof(ca_operation_function_t) ) {
@@ -338,16 +339,20 @@ ca_install_obj_type (VALUE klass,
338
339
  func_size, sizeof(ca_operation_function_t));
339
340
  }
340
341
 
341
- /* Everything from xfer_index on was appended after the table's first
342
- shape, so a caller may legitimately stop short of it. Anything shorter
343
- than that cannot dispatch at all. */
344
- if ( func_size < offsetof(ca_operation_function_t, xfer_index) ) {
342
+ /* xfer_index, xfer_addrs and xfer_all have no default, so the table
343
+ reaches through xfer_all; the slots after it fall back when NULL. */
344
+ if ( func_size < offsetof(ca_operation_function_t, xfer_all) +
345
+ sizeof(((ca_operation_function_t *) 0)->xfer_all) ) {
345
346
  rb_raise(rb_eRuntimeError,
346
347
  "operation table is too small to dispatch (%zu < %zu)",
347
348
  func_size,
348
- (size_t) offsetof(ca_operation_function_t, xfer_index));
349
+ (size_t) (offsetof(ca_operation_function_t, xfer_all) +
350
+ sizeof(((ca_operation_function_t *) 0)->xfer_all)));
349
351
  }
350
352
 
353
+ /* A refused table takes no number. */
354
+ obj_type = ca_obj_num++;
355
+
351
356
  /* Copy by the caller's length and zero the rest: slots this build knows
352
357
  about but the caller does not are NULL, which every dispatcher already
353
358
  reads as "not provided". */
@@ -557,7 +562,7 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
557
562
  ca_size_t bytes = ca_sizeof[data_type];
558
563
  if ( bytes <= 0 ) {
559
564
  rb_raise(rb_eArgError,
560
- "rb_ca_new_reduced: data_type=%d unsupported (CA_FIXLEN/OBJECT not supported)",
565
+ "rb_ca_new_reduced: data_type=%d has no fixed width (use rb_ca_new_reduced_bytes)",
561
566
  (int) data_type);
562
567
  }
563
568
  return rb_ca_new_reduced_bytes(self, slab_axes, naxes, data_type, bytes, keep_axis);
@@ -565,9 +570,8 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
565
570
 
566
571
  /* ------------------------------------------------------------------- */
567
572
 
568
- /* Parse the variadic axis argument of a reduction kernel into a
569
- sort-ascending
570
- int8_t array, with full validation.
573
+ /* Parse the variadic axis argument of a reduction kernel into an int8_t
574
+ array, with full validation.
571
575
 
572
576
  Accepts:
573
577
  - Integer args: kernel(0, 2, 3) → axes = {0, 2, 3}
@@ -575,8 +579,9 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
575
579
  - Negative axes (Python-style): -1 = innermost, normalised to
576
580
  positive in-range indices before validation
577
581
 
582
+ argc == 0 means every axis (a full reduction).
583
+
578
584
  Validation (raises ArgumentError on failure):
579
- - argc == 0 → no axes given
580
585
  - naxes > ca->ndim → too many axes
581
586
  - any axis out of [0, ca->ndim) → range
582
587
  - duplicate axes → duplicate
@@ -591,6 +596,10 @@ rb_ca_new_reduced (VALUE self, int8_t *slab_axes, int8_t naxes, int32_t data_typ
591
596
  variadic entry (rb_ca_parse_reduce_axes) and the kwarg entry
592
597
  (rb_ca_parse_reduce_axes_kw). ctx names the method in error messages;
593
598
  the two public entries pass the method the user called. */
599
+ /* ctx NULL names the method the user called, looked up only when a
600
+ message is built: the lookup walks the frames. */
601
+ #define CA_CTX_NAME(ctx) ( (ctx) ? (ctx) : ca_calling_method_name() )
602
+
594
603
  static int8_t
595
604
  parse_axes_items (const VALUE *items, int count, CArray *ca,
596
605
  int8_t *out_axes, const char *ctx)
@@ -599,31 +608,25 @@ parse_axes_items (const VALUE *items, int count, CArray *ca,
599
608
  int8_t seen[CA_RANK_MAX];
600
609
 
601
610
  if ( count <= 0 ) {
602
- rb_raise(rb_eArgError, "%s: empty axes array", ctx);
611
+ rb_raise(rb_eArgError, "%s: empty axes array", CA_CTX_NAME(ctx));
603
612
  }
604
- if ( count > CA_RANK_MAX ) {
613
+ if ( count > CA_RANK_MAX ) { /* rank-check: a list of axes, no longer than the rank */
605
614
  rb_raise(rb_eArgError,
606
615
  "%s: too many axes (%d > CA_RANK_MAX=%d)",
607
- ctx, count, CA_RANK_MAX);
616
+ CA_CTX_NAME(ctx), count, CA_RANK_MAX);
608
617
  }
609
618
  if ( count > ca->ndim ) {
610
619
  rb_raise(rb_eArgError,
611
620
  "%s: too many axes (%d > ndim=%d)",
612
- ctx, count, (int) ca->ndim);
621
+ CA_CTX_NAME(ctx), count, (int) ca->ndim);
613
622
  }
614
623
 
615
624
  for ( i = 0; i < CA_RANK_MAX; i++ ) seen[i] = 0;
616
625
  for ( i = 0; i < count; i++ ) {
617
- ca_size_t raw = ca_axis_integer(items[i], NULL);
618
- ca_size_t a = ( raw < 0 ) ? raw + ca->ndim : raw;
619
- if ( a < 0 || a >= ca->ndim ) {
620
- rb_raise(rb_eArgError,
621
- "%s: axis %ld out of range for ndim %d",
622
- ctx, (long) raw, (int) ca->ndim);
623
- }
626
+ ca_size_t a = ca_normalize_axis_arg(items[i], (int) ca->ndim, ctx);
624
627
  if ( seen[a] ) {
625
628
  rb_raise(rb_eArgError,
626
- "%s: duplicate axis %ld", ctx, (long) a);
629
+ "%s: duplicate axis %ld", CA_CTX_NAME(ctx), (long) a);
627
630
  }
628
631
  seen[a] = 1;
629
632
  out_axes[i] = (int8_t) a;
@@ -656,8 +659,7 @@ rb_ca_parse_reduce_axes (int argc, VALUE *argv, CArray *ca, int8_t *out_axes)
656
659
  items = (const VALUE *) RARRAY_CONST_PTR(arr);
657
660
  }
658
661
 
659
- return parse_axes_items(items, count, ca, out_axes,
660
- ca_calling_method_name());
662
+ return parse_axes_items(items, count, ca, out_axes, NULL);
661
663
  }
662
664
 
663
665
  /* Kwarg form of rb_ca_parse_reduce_axes — accepts the `axis:` value as
@@ -698,14 +700,13 @@ rb_ca_parse_reduce_axes_kw_ctx (VALUE axis_val, CArray *ca, int8_t *out_axes,
698
700
  rb_raise(rb_eTypeError,
699
701
  "%s: axis must be nil, an Integer or an Array of Integer "
700
702
  "(got %"PRIsVALUE")",
701
- ctx, rb_obj_class(axis_val));
703
+ CA_CTX_NAME(ctx), rb_obj_class(axis_val));
702
704
  }
703
705
 
704
706
  int8_t
705
707
  rb_ca_parse_reduce_axes_kw (VALUE axis_val, CArray *ca, int8_t *out_axes)
706
708
  {
707
- return rb_ca_parse_reduce_axes_kw_ctx(axis_val, ca, out_axes,
708
- ca_calling_method_name());
709
+ return rb_ca_parse_reduce_axes_kw_ctx(axis_val, ca, out_axes, NULL);
709
710
  }
710
711
 
711
712
  /* ------------------------------------------------------------------- */
@@ -946,7 +947,7 @@ ca_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
946
947
  CArray *ca = (CArray *) ap;
947
948
 
948
949
  if ( dir == CA_XFER_PUT && ca_is_readonly(ca) ) {
949
- rb_raise(rb_eRuntimeError, "can not store data to read-only array");
950
+ ca_refuse_read_only();
950
951
  }
951
952
 
952
953
  /* Fast path: non-CA_OBJECT element type needs no GC protection. */
@@ -1074,7 +1075,7 @@ ca_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data, int dir)
1074
1075
  CArray *ca = (CArray *) ap;
1075
1076
 
1076
1077
  if ( dir == CA_XFER_PUT && ca_is_readonly(ca) ) {
1077
- rb_raise(rb_eRuntimeError, "can not store data to read-only array");
1078
+ ca_refuse_read_only();
1078
1079
  }
1079
1080
 
1080
1081
  /* Fast path: non-CA_OBJECT element type needs no GC protection. */
@@ -1376,6 +1377,7 @@ ca_xfer_strided_walk (char *src_base,
1376
1377
  ca_size_t inner_dst_bytes = counts[ndim-2] * counts[ndim-1] * bytes;
1377
1378
 
1378
1379
  for ( k = 0; k < outer_n; k++ ) idx[k] = 0;
1380
+ /* empty: the walk returns on an empty region at its entry */
1379
1381
  while ( 1 ) {
1380
1382
  ca_size_t soff = 0;
1381
1383
  for ( k = 0; k < outer_n; k++ ) soff += idx[k] * src_strides[k];
@@ -1393,6 +1395,7 @@ ca_xfer_strided_walk (char *src_base,
1393
1395
 
1394
1396
  /* prefix axes [0..slab_start-1] on odometer, slab-sized memcpy per iter. */
1395
1397
  for ( k = 0; k < slab_start; k++ ) idx[k] = 0;
1398
+ /* empty: the walk returns on an empty region at its entry */
1396
1399
  while ( 1 ) {
1397
1400
  ca_size_t soff = 0;
1398
1401
  for ( k = 0; k < slab_start; k++ ) soff += idx[k] * src_strides[k];
@@ -1466,6 +1469,7 @@ ca_xfer_stride_dispatch (CArray *ca, ca_size_t *starts, ca_size_t *counts,
1466
1469
 
1467
1470
  /* fallback: per-cell via byte offset -> flat addr -> index -> xfer_index. */
1468
1471
  for ( k = 0; k < ndim; k++ ) idx[k] = 0;
1472
+ /* empty: its one caller, ca_xfer_stride, returns on an empty region */
1469
1473
  while ( 1 ) {
1470
1474
  ca_size_t soff = base, vidx[CA_RANK_MAX];
1471
1475
  for ( k = 0; k < ndim; k++ ) soff += idx[k] * strides[k];
@@ -1514,7 +1518,7 @@ ca_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
1514
1518
  CArray *ca = (CArray *) ap;
1515
1519
 
1516
1520
  if ( dir == CA_XFER_PUT && ca_is_readonly(ca) ) {
1517
- rb_raise(rb_eRuntimeError, "can not store data to read-only array");
1521
+ ca_refuse_read_only();
1518
1522
  }
1519
1523
 
1520
1524
  if ( ca_region_is_empty(ca->ndim, counts) ) return;
@@ -1607,9 +1611,7 @@ ca_xfer_all (void *ap, void *data, int dir)
1607
1611
  written by nested transfers land inside it. */
1608
1612
  if ( ca->data_type == CA_OBJECT && dir == CA_XFER_GET ) {
1609
1613
  if ( data != (void *) ca->ptr ) {
1610
- VALUE *p = (VALUE *) data;
1611
- ca_size_t i;
1612
- for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
1614
+ ca_object_cells_clear(data, ca->elements);
1613
1615
  }
1614
1616
  guard = ca_gc_hold_push(data, ca->elements);
1615
1617
  }
@@ -1666,23 +1668,32 @@ static long ca_attached_views = 0;
1666
1668
  #define CA_VIEW_ATTACH_STEP(ca, d) do { \
1667
1669
  uint32_t attach_before_ = CAVIEW(ca)->attach; \
1668
1670
  CAVIEW(ca)->attach += (d); \
1669
- ca_attached_views += ( CAVIEW(ca)->attach > 0 ) - ( attach_before_ > 0 ); \
1671
+ __atomic_add_fetch(&ca_attached_views, \
1672
+ ( CAVIEW(ca)->attach > 0 ) - ( attach_before_ > 0 ), \
1673
+ __ATOMIC_RELAXED); \
1670
1674
  } while (0)
1671
1675
 
1672
1676
  static VALUE
1673
1677
  rb_ca_s_attached_views (VALUE klass)
1674
1678
  {
1675
- return LONG2NUM(ca_attached_views);
1679
+ return LONG2NUM(__atomic_load_n(&ca_attached_views, __ATOMIC_RELAXED));
1676
1680
  }
1677
1681
 
1678
1682
  /* Set once at load from CARRAY_GENERAL_PATH; see carray_internal.h. */
1679
1683
  int ca_fast_paths_on = 1;
1684
+ int ca_iter_transfer_only_on = 0;
1680
1685
 
1681
1686
  static VALUE
1682
1687
  rb_ca_s_fast_paths_enabled (VALUE klass)
1683
1688
  {
1684
1689
  return ca_fast_paths_on ? Qtrue : Qfalse;
1685
1690
  }
1691
+
1692
+ static VALUE
1693
+ rb_ca_s_iter_by_transfer_only (VALUE klass)
1694
+ {
1695
+ return ca_iter_transfer_only_on ? Qtrue : Qfalse;
1696
+ }
1686
1697
  #else
1687
1698
  #define CA_VIEW_ATTACH_STEP(ca, d) ( CAVIEW(ca)->attach += (d) )
1688
1699
  #endif
@@ -1753,6 +1764,18 @@ ca_attach_view_first (VALUE arg)
1753
1764
  return Qnil;
1754
1765
  }
1755
1766
 
1767
+ static VALUE
1768
+ ca_attach_mask_step (VALUE arg)
1769
+ {
1770
+ CArray *ca = (CArray *) arg;
1771
+ CArray *mask0 = ca->mask;
1772
+ ca_update_mask(ca);
1773
+ if ( ca->mask == mask0 ) { /* see ca_attach_view_first */
1774
+ ca_attach(ca->mask);
1775
+ }
1776
+ return Qnil;
1777
+ }
1778
+
1756
1779
  /* attach parent's data to ca->ptr */
1757
1780
 
1758
1781
  void
@@ -1797,10 +1820,18 @@ ca_attach (void *ap)
1797
1820
  }
1798
1821
 
1799
1822
  {
1800
- CArray *mask0 = ca->mask;
1801
- ca_update_mask(ca);
1802
- if ( ca->mask == mask0 ) { /* see ca_attach_view_first */
1803
- ca_attach(ca->mask);
1823
+ /* Making the mask can raise (a CAObject's mask hooks); the attach
1824
+ taken above is given back then. */
1825
+ int tag = 0;
1826
+ rb_protect(ca_attach_mask_step, (VALUE) ca, &tag);
1827
+ if ( tag ) {
1828
+ if ( ca_is_view(ca) ) {
1829
+ CA_VIEW_ATTACH_STEP(ca, -1);
1830
+ }
1831
+ else {
1832
+ ca_func[ca->obj_type].detach(ap);
1833
+ }
1834
+ rb_jump_tag(tag);
1804
1835
  }
1805
1836
  }
1806
1837
  }
@@ -1887,7 +1918,10 @@ ca_sync_all (CArray **list, int32_t n)
1887
1918
  even when body raised or broke out -- the cells body wrote reach the
1888
1919
  parent, as they would for an entity, which has no separate buffer. An
1889
1920
  'a' array is not synced after a raise: allocate did not gather, so its
1890
- cells body never wrote hold nothing faithful to push back.
1921
+ cells body never wrote hold nothing faithful to push back. Allocate
1922
+ clears the mask as it opens, and an entity (or the parent under a view)
1923
+ has no separate mask to fall back on, so the mask of an 'a' array is
1924
+ copied before it opens and written back when body raises.
1891
1925
 
1892
1926
  Every array is detached, in reverse order, whatever happens. body's
1893
1927
  own exception wins over one raised by a sync; when body returned and a
@@ -1903,8 +1937,57 @@ typedef struct {
1903
1937
  volatile VALUE sync_err;
1904
1938
  VALUE (*body)(VALUE);
1905
1939
  VALUE arg;
1940
+ volatile VALUE masks; /* per array: the mask bytes of an 'a' array, or nil */
1906
1941
  } ca_window_ctx_t;
1907
1942
 
1943
+ /* Copy the masks of the 'a' arrays before they open. */
1944
+ static void
1945
+ ca_attach_window_save_masks (ca_window_ctx_t *w)
1946
+ {
1947
+ int32_t k;
1948
+ w->masks = Qnil;
1949
+ for ( k = 0; k < w->n; k++ ) {
1950
+ CArray *ca = w->list[k];
1951
+ if ( w->modes[k] != 'a' || ! ca || ! ca_has_mask(ca) ) {
1952
+ continue;
1953
+ }
1954
+ if ( NIL_P(w->masks) ) {
1955
+ w->masks = rb_ary_new_capa(w->n);
1956
+ }
1957
+ ca_update_mask(ca);
1958
+ {
1959
+ VALUE buf = rb_str_new(NULL, (long) ca->elements);
1960
+ ca_copy_data(ca->mask, RSTRING_PTR(buf));
1961
+ rb_ary_store(w->masks, k, buf);
1962
+ }
1963
+ }
1964
+ }
1965
+
1966
+ /* Write the copied masks back, once every array is detached. */
1967
+ static void
1968
+ ca_attach_window_restore_masks (ca_window_ctx_t *w)
1969
+ {
1970
+ int32_t k;
1971
+ if ( NIL_P(w->masks) ) {
1972
+ return;
1973
+ }
1974
+ for ( k = 0; k < w->n; k++ ) {
1975
+ VALUE buf = rb_ary_entry(w->masks, k);
1976
+ CArray *ca = w->list[k];
1977
+ if ( NIL_P(buf) ) {
1978
+ continue;
1979
+ }
1980
+ ca_update_mask(ca);
1981
+ if ( ! ca->mask ) {
1982
+ ca_create_mask(ca);
1983
+ }
1984
+ ca_xfer_all(ca->mask, RSTRING_PTR(buf), CA_XFER_PUT);
1985
+ /* held only by w->masks, where compaction can move it; the write may
1986
+ call into Ruby (a CAObject's mask hooks) */
1987
+ RB_GC_GUARD(buf);
1988
+ }
1989
+ }
1990
+
1908
1991
  static VALUE
1909
1992
  ca_attach_window_open (VALUE varg)
1910
1993
  {
@@ -1963,6 +2046,9 @@ ca_attach_window_close (VALUE varg)
1963
2046
  ca_detach(ca);
1964
2047
  }
1965
2048
  }
2049
+ if ( ! w->body_done ) {
2050
+ ca_attach_window_restore_masks(w);
2051
+ }
1966
2052
  return Qnil;
1967
2053
  }
1968
2054
 
@@ -1983,6 +2069,7 @@ ca_attach_window (int32_t n, CArray **list, const char *modes,
1983
2069
  w.sync_err = Qnil;
1984
2070
  w.body = body;
1985
2071
  w.arg = arg;
2072
+ ca_attach_window_save_masks(&w);
1986
2073
 
1987
2074
  rb_protect(ca_attach_window_open, (VALUE) &w, &tag);
1988
2075
  if ( tag ) {
@@ -1992,6 +2079,7 @@ ca_attach_window (int32_t n, CArray **list, const char *modes,
1992
2079
  ca_detach(w.list[w.opened]);
1993
2080
  }
1994
2081
  }
2082
+ ca_attach_window_restore_masks(&w);
1995
2083
  rb_jump_tag(tag);
1996
2084
  }
1997
2085
 
@@ -2004,7 +2092,7 @@ ca_attach_window (int32_t n, CArray **list, const char *modes,
2004
2092
  return result;
2005
2093
  }
2006
2094
 
2007
- /* attach parent's data to ca->ptr */
2095
+ /* re-gather an attached view's buffer from its parent */
2008
2096
 
2009
2097
  void
2010
2098
  ca_update (void *ap)
@@ -2022,7 +2110,7 @@ ca_update (void *ap)
2022
2110
  }
2023
2111
  else {
2024
2112
  rb_raise(rb_eRuntimeError,
2025
- "[BUG] ca_update() called for not-attached virtal array");
2113
+ "[BUG] ca_update() called for not-attached virtual array");
2026
2114
  }
2027
2115
 
2028
2116
  }
@@ -2048,8 +2136,7 @@ ca_sync (void *ap)
2048
2136
  }
2049
2137
 
2050
2138
  if ( ca_is_readonly(ca) ) {
2051
- rb_raise(rb_eRuntimeError,
2052
- "can not modify read-only array");
2139
+ ca_refuse_read_only();
2053
2140
  }
2054
2141
 
2055
2142
  /* Only a mask that exists can hold writes: one made inside the window
@@ -2259,8 +2346,7 @@ ca_sync_data (void *ap, char *ptr)
2259
2346
  CArray *ca = (CArray *) ap;
2260
2347
 
2261
2348
  if ( ca_is_readonly(ca) ) {
2262
- rb_raise(rb_eRuntimeError,
2263
- "can not sync data to read-only array");
2349
+ ca_refuse_read_only();
2264
2350
  }
2265
2351
 
2266
2352
  if ( ca_is_view(ca) && CAVIEW(ca)->nosync ) {
@@ -2281,8 +2367,7 @@ ca_fill_data (void *ap, void *aptr)
2281
2367
  char *ptr = (char *) aptr;
2282
2368
 
2283
2369
  if ( ca_is_readonly(ca) ) {
2284
- rb_raise(rb_eRuntimeError,
2285
- "can not fill data to read-only array");
2370
+ ca_refuse_read_only();
2286
2371
  }
2287
2372
 
2288
2373
  if ( ca_is_view(ca) ) { /* view array */
@@ -2314,7 +2399,10 @@ ca_fill_stride_default (void *ap, ca_size_t base, int8_t ndim,
2314
2399
  ca_size_t idx[CA_RANK_MAX];
2315
2400
  int8_t k;
2316
2401
 
2402
+ if ( ca_region_is_empty(ndim, counts) ) return;
2403
+
2317
2404
  for ( k = 0; k < ndim; k++ ) idx[k] = 0;
2405
+ /* empty: the function returns on an empty region at its entry */
2318
2406
  while ( 1 ) {
2319
2407
  ca_size_t addr = base, vidx[CA_RANK_MAX];
2320
2408
  for ( k = 0; k < ndim; k++ ) addr += idx[k] * steps[k];
@@ -2333,7 +2421,7 @@ ca_fill_stride (void *ap, ca_size_t base, int8_t ndim,
2333
2421
  CArray *ca = (CArray *) ap;
2334
2422
 
2335
2423
  if ( ca_is_readonly(ca) ) {
2336
- rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
2424
+ ca_refuse_read_only();
2337
2425
  }
2338
2426
 
2339
2427
  if ( ca_region_is_empty(ndim, counts) ) return;
@@ -2429,6 +2517,7 @@ ca_fill_stride_via_addrs (void *ap, ca_size_t base, int8_t ndim,
2429
2517
  idx[k] = 0;
2430
2518
  }
2431
2519
 
2520
+ /* empty: an axis of count 0 returns above */
2432
2521
  while ( 1 ) {
2433
2522
  ca_size_t addr = base;
2434
2523
  for ( k = 0; k < ndim; k++ ) addr += idx[k] * steps[k];
@@ -2452,7 +2541,7 @@ ca_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
2452
2541
  CArray *ca = (CArray *) ap;
2453
2542
 
2454
2543
  if ( ca_is_readonly(ca) ) {
2455
- rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
2544
+ ca_refuse_read_only();
2456
2545
  }
2457
2546
 
2458
2547
  if ( ca_func[ca->obj_type].fill_addrs ) {
@@ -2483,7 +2572,7 @@ ca_fill (void *ap, void *aptr)
2483
2572
  char *ptr = (char *) aptr;
2484
2573
 
2485
2574
  if ( ca_is_readonly(ca) ) {
2486
- rb_raise(rb_eRuntimeError, "can not fill data to read-only array");
2575
+ ca_refuse_read_only();
2487
2576
  }
2488
2577
 
2489
2578
  ca_fill_data(ap, ptr);
@@ -2992,9 +3081,12 @@ Init_carray_core (void)
2992
3081
  {
2993
3082
  const char *general = getenv("CARRAY_GENERAL_PATH");
2994
3083
  ca_fast_paths_on = !( general && general[0] && strcmp(general, "0") );
3084
+ ca_iter_transfer_only_on = ( general && ! strcmp(general, "2") );
2995
3085
  }
2996
3086
  rb_define_singleton_method(rb_cCArray, "__fast_paths_enabled__",
2997
3087
  rb_ca_s_fast_paths_enabled, 0);
3088
+ rb_define_singleton_method(rb_cCArray, "__iter_by_transfer_only__",
3089
+ rb_ca_s_iter_by_transfer_only, 0);
2998
3090
  #endif
2999
3091
 
3000
3092
  rb_define_method(rb_cCArray, "members", rb_ca_members, 0);
data/ext/carray_count.c CHANGED
@@ -82,8 +82,16 @@ ca_count_each_body (VALUE arg)
82
82
  /* Extract vk as a scalar VALUE via flat addr. rb_ca_fetch_addr
83
83
  takes a ca_size_t addr (not a Ruby VALUE). */
84
84
  VALUE vk = rb_ca_fetch_addr(c->rval, k);
85
- inner_argv[0] = vk;
86
- VALUE sub = rb_ca_count(inner_call_argc, inner_argv, c->self);
85
+ VALUE sub;
86
+ /* A masked query cell asks nothing: its count is masked. Passing it
87
+ on would ask count(UNDEF), the count of self's masked cells. */
88
+ if ( vk == CA_UNDEF ) {
89
+ sub = CA_UNDEF;
90
+ }
91
+ else {
92
+ inner_argv[0] = vk;
93
+ sub = rb_ca_count(inner_call_argc, inner_argv, c->self);
94
+ }
87
95
 
88
96
  /* Place sub into output[..., k] slot.
89
97
  Output stride for v-axis = 1, base stride = v_elements. */
@@ -169,15 +177,21 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
169
177
  rval = ca_face_element_to_storage(self, src, rval);
170
178
  }
171
179
  else {
172
- if ( src->obj_type != CA_OBJ_RECORD
173
- && ! ca_test_flag(src, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
174
- ca_face_refuse_order("count(v)", self, "count");
180
+ if ( src->obj_type != CA_OBJ_RECORD ) {
181
+ ca_face_require_orderable(self, "count(v)", "count");
175
182
  }
176
- rval = ca_face_reconcile_operand(self, rval, "count(v)");
177
- /* to_comparable lifts a scalar query to a length-1 array; unwrap it so
183
+ {
184
+ volatile VALUE ref = self, query = rval;
185
+ ca_face_reconcile_pair(&ref, &query, "count(v)");
186
+ self = ref;
187
+ rval = query;
188
+ }
189
+ /* The reconcile lifts a scalar query to a length-1 array; unwrap it so
178
190
  a scalar query still answers with a count rather than a length-1
179
- array from the broadcast branch below. */
180
- if ( query_was_scalar && rb_obj_is_carray(rval) ) {
191
+ array from the broadcast branch below. A Ruby Array is a list of
192
+ queries and stays one, like a CArray query. */
193
+ if ( query_was_scalar && ! RB_TYPE_P(argv[0], T_ARRAY)
194
+ && rb_obj_is_carray(rval) ) {
181
195
  rval = rb_ca_fetch_addr(rval, 0);
182
196
  }
183
197
  }
@@ -210,12 +224,11 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
210
224
  CArray *cv;
211
225
  GetCArray(rval, cv);
212
226
 
213
- /* A query of a wider type than an integer array is counted in the type
214
- the two share, as `eq` compares: each v[k] below is then a value of
215
- that type, not one truncated to the array's. */
216
- if ( ca_is_integer_type(src) &&
217
- ( ca_is_integer_type(cv) || ca_is_float_type(cv) ) ) {
218
- int8_t qt = ca_promote_type(src->data_type, cv->data_type);
227
+ /* The array is counted in the type it and v match in, as `eq` compares
228
+ (ca_query_match_type): each v[k] below is then a value of that type,
229
+ not one cut to the array's. */
230
+ if ( ca_query_match_applies(src, rval) ) {
231
+ int8_t qt = ca_query_match_type(src->data_type, rval);
219
232
  if ( qt != src->data_type ) {
220
233
  self = rb_ca_wrap_readonly(self, INT2NUM(qt));
221
234
  GetCArray(self, src);
@@ -341,11 +354,28 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
341
354
  "count(v) on numeric array: v must be numeric, got %s",
342
355
  rb_obj_classname(rval));
343
356
  }
344
- /* A Float query on an integer array is compared as a float, as `eq`
345
- compares and `search` searches: 1.5 must not match 1. An Integer
346
- query keeps the array's type and is refused when it does not fit. */
347
- if ( ca_is_integer_type(src) && RB_FLOAT_TYPE_P(rval) ) {
348
- self = rb_ca_wrap_readonly(self, INT2NUM(CA_FLOAT64));
357
+ /* The query is compared in the type it and the array match in, as `eq`
358
+ compares (ca_query_match_type): 1.5 does not match 1, and an Integer
359
+ the array's type cannot hold matches nothing. */
360
+ if ( ca_is_integer_type(src) && ! RB_INTEGER_TYPE_P(rval)
361
+ && ! RB_FLOAT_TYPE_P(rval) && ! RB_TYPE_P(rval, T_COMPLEX)
362
+ && rb_obj_is_kind_of(rval, rb_cNumeric) ) {
363
+ /* A Rational or BigDecimal query: an integral one is the Integer it
364
+ equals; any other is compared as a float, like a Float query,
365
+ rather than cut to the array's type. */
366
+ VALUE ival = rb_funcall(rval, rb_intern("to_i"), 0);
367
+ VALUE *nargv = ALLOCA_N(VALUE, argc);
368
+ MEMCPY(nargv, argv, VALUE, argc);
369
+ nargv[0] = RTEST(rb_funcall(rval, rb_intern("=="), 1, ival))
370
+ ? ival : rb_funcall(rval, rb_intern("to_f"), 0);
371
+ argv = nargv;
372
+ rval = nargv[0];
373
+ }
374
+ if ( ca_query_match_applies(src, rval) ) {
375
+ int8_t qt = ca_query_match_type(src->data_type, rval);
376
+ if ( qt != src->data_type ) {
377
+ self = rb_ca_wrap_readonly(self, INT2NUM(qt));
378
+ }
349
379
  }
350
380
  /* Pass full argv; count_equal_ki pops argv[0] as value_arg. */
351
381
  return rb_ca_count_equal_ki(argc, argv, self);