carray 3.0.6 → 3.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +110 -0
  3. data/README.md +24 -3
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_group.c +6 -6
  6. data/ext/ca_binop_dispatch.c +8 -0
  7. data/ext/ca_binop_dispatch.h +1 -0
  8. data/ext/ca_categorical_iterator.c +7 -7
  9. data/ext/ca_kernel_iterator.h +6 -4
  10. data/ext/ca_obj_array.c +4 -4
  11. data/ext/ca_obj_bincmp.c +19 -3
  12. data/ext/ca_obj_binop.c +36 -11
  13. data/ext/ca_obj_bitarray.c +2 -4
  14. data/ext/ca_obj_bitfield.c +86 -4
  15. data/ext/ca_obj_byte_swap.c +2 -4
  16. data/ext/ca_obj_const_string.c +422 -257
  17. data/ext/ca_obj_face.c +71 -33
  18. data/ext/ca_obj_fake.c +112 -13
  19. data/ext/ca_obj_farray.c +7 -1
  20. data/ext/ca_obj_fixlen_string.c +51 -17
  21. data/ext/ca_obj_grid.c +12 -7
  22. data/ext/ca_obj_meld.c +5 -5
  23. data/ext/ca_obj_monop.c +65 -39
  24. data/ext/ca_obj_object.c +9 -9
  25. data/ext/ca_obj_reduce.c +2 -4
  26. data/ext/ca_obj_refer.c +104 -10
  27. data/ext/ca_obj_repeat.c +1 -1
  28. data/ext/ca_obj_roll.c +2 -4
  29. data/ext/ca_obj_select.c +8 -6
  30. data/ext/ca_obj_select_axis.c +8 -6
  31. data/ext/ca_obj_stack.c +5 -5
  32. data/ext/ca_obj_stride.c +46 -8
  33. data/ext/ca_obj_string.c +2 -2
  34. data/ext/ca_obj_tile.c +2 -4
  35. data/ext/ca_obj_triop.c +15 -12
  36. data/ext/ca_obj_window.c +22 -15
  37. data/ext/ca_op_ipower.c +63 -15
  38. data/ext/ca_op_powi.h +6 -29
  39. data/ext/ca_sort_kernels.h +3 -0
  40. data/ext/ca_sweep_engine.c +90 -23
  41. data/ext/ca_sweep_engine.h +5 -6
  42. data/ext/caframe_csv_reader.c +1 -1
  43. data/ext/carray.h +3 -1
  44. data/ext/carray_access.c +98 -39
  45. data/ext/carray_address_basis.c +98 -24
  46. data/ext/carray_broadcast.c +2 -2
  47. data/ext/carray_call_cfunc.c +5 -8
  48. data/ext/carray_cast.c +311 -37
  49. data/ext/carray_cast_func.rb +37 -5
  50. data/ext/carray_conversion.c +56 -2
  51. data/ext/carray_copy.c +24 -0
  52. data/ext/carray_core.c +69 -6
  53. data/ext/carray_count.c +28 -9
  54. data/ext/carray_element.c +9 -3
  55. data/ext/carray_factorize.c +11 -11
  56. data/ext/carray_histogram.c +2 -2
  57. data/ext/carray_index_classifier.c +7 -5
  58. data/ext/carray_internal.h +94 -0
  59. data/ext/carray_kernels_binop.c +55 -55
  60. data/ext/carray_kernels_init.c +14 -14
  61. data/ext/carray_kernels_monop.c +90 -140
  62. data/ext/carray_lazy.c +16 -1
  63. data/ext/carray_loop.c +9 -2
  64. data/ext/carray_mask.c +118 -11
  65. data/ext/carray_median_percentile.c +13 -8
  66. data/ext/carray_memory_view.c +41 -22
  67. data/ext/carray_operator.c +72 -11
  68. data/ext/carray_order.c +52 -9
  69. data/ext/carray_partition.c +1 -1
  70. data/ext/carray_random.c +1 -1
  71. data/ext/carray_round.c +24 -1
  72. data/ext/carray_scatter.c +4 -0
  73. data/ext/carray_segment.c +1 -1
  74. data/ext/carray_slab.c +13 -4
  75. data/ext/carray_sort.c +6 -3
  76. data/ext/carray_sort_kernel.c +24 -0
  77. data/ext/carray_struct.c +21 -6
  78. data/ext/carray_test.c +85 -39
  79. data/ext/carray_time_text.c +6 -0
  80. data/ext/carray_utils.c +124 -54
  81. data/ext/mk_call_cfunc.rb +6 -11
  82. data/ext/mkkernel.rb +37 -27
  83. data/ext/version.h +4 -4
  84. data/lib/carray/axis_group.rb +9 -6
  85. data/lib/carray/basics.rb +26 -8
  86. data/lib/carray/bincount_nd.rb +8 -2
  87. data/lib/carray/block_iterator.rb +48 -21
  88. data/lib/carray/categorical.rb +21 -8
  89. data/lib/carray/categorical_iterator.rb +2 -1
  90. data/lib/carray/conditional.rb +52 -4
  91. data/lib/carray/const_string.rb +74 -0
  92. data/lib/carray/construct.rb +2 -2
  93. data/lib/carray/core_extensions.rb +19 -68
  94. data/lib/carray/data_type_extension.rb +1 -0
  95. data/lib/carray/fixlen_string.rb +83 -1
  96. data/lib/carray/frame/column_verbs.rb +61 -6
  97. data/lib/carray/frame/concat.rb +50 -6
  98. data/lib/carray/frame/csv_parser.rb +13 -4
  99. data/lib/carray/frame/frame.rb +38 -6
  100. data/lib/carray/frame/group.rb +67 -40
  101. data/lib/carray/frame/io.rb +10 -5
  102. data/lib/carray/frame/join.rb +20 -6
  103. data/lib/carray/frame/records.rb +6 -4
  104. data/lib/carray/frame/reshape.rb +25 -5
  105. data/lib/carray/frame/verbs.rb +78 -25
  106. data/lib/carray/frame/windows.rb +30 -6
  107. data/lib/carray/fuse_source.rb +4 -2
  108. data/lib/carray/iterator.rb +8 -0
  109. data/lib/carray/key_windows.rb +10 -4
  110. data/lib/carray/lazy.rb +12 -17
  111. data/lib/carray/methods/bin.rb +3 -0
  112. data/lib/carray/methods/composition.rb +1 -1
  113. data/lib/carray/methods/factorize.rb +2 -0
  114. data/lib/carray/methods/gather_nd.rb +4 -1
  115. data/lib/carray/methods/is_in.rb +23 -3
  116. data/lib/carray/methods/locate_addr.rb +63 -12
  117. data/lib/carray/methods/repeat.rb +11 -1
  118. data/lib/carray/record_order.rb +35 -6
  119. data/lib/carray/runtime.rb +10 -0
  120. data/lib/carray/segment_iterator.rb +19 -16
  121. data/lib/carray/serialize.rb +22 -0
  122. data/lib/carray/slab_iterator.rb +1 -1
  123. data/lib/carray/stack.rb +3 -3
  124. data/lib/carray/string.rb +6 -6
  125. data/lib/carray/string_operation_extension.rb +25 -4
  126. data/lib/carray/struct_builder.rb +4 -1
  127. data/lib/carray/time.rb +190 -46
  128. data/lib/carray/window_iterator.rb +48 -12
  129. data/yard-stubs/ca_obj_bitfield.rb +4 -1
  130. data/yard-stubs/ca_obj_refer.rb +3 -0
  131. data/yard-stubs/ca_obj_window.rb +2 -1
  132. data/yard-stubs/carray_access.rb +4 -2
  133. data/yard-stubs/carray_cast.rb +6 -0
  134. data/yard-stubs/carray_count.rb +6 -3
  135. data/yard-stubs/carray_math.rb +5 -0
  136. data/yard-stubs/carray_order.rb +6 -0
  137. data/yard-stubs/carray_scatter.rb +2 -1
  138. data/yard-stubs/carray_test.rb +18 -5
  139. metadata +2 -2
@@ -815,7 +815,7 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
815
815
  ca_size_t *cells = (ca_size_t *) (bc + n);
816
816
  int *flags = (int *) (cells + (size_t) n * 2 * CA_RANK_MAX);
817
817
  for ( i = 0; i < n; i++ ) {
818
- VALUE object = rb_ary_entry(arrays, i);
818
+ volatile VALUE object = rb_ary_entry(arrays, i);
819
819
  VALUE starts = NIL_P(box_start) ? Qnil : rb_ary_entry(box_start, i);
820
820
  VALUE counts = NIL_P(box_count) ? Qnil : rb_ary_entry(box_count, i);
821
821
  int8_t k;
@@ -967,6 +967,72 @@ address_basis_tier (VALUE module, VALUE object)
967
967
 
968
968
  /* ------------------------------------------------------------------- */
969
969
 
970
+ /* The call of a sweep, with the parts locked: a view that runs Ruby while
971
+ it hands over its cells (a CAObject) could otherwise resize a part under
972
+ the pointer the slab writes through. */
973
+ typedef struct {
974
+ ca_cslab_r_t function;
975
+ const char *fsync;
976
+ int n;
977
+ const VALUE *arrays;
978
+ void **table;
979
+ volatile VALUE *parts;
980
+ int nparts;
981
+ int nlocked; /* parts[0..nlocked) were considered for a lock */
982
+ } address_basis_sweep_call_t;
983
+
984
+ /* Whether parts[i] is a String to lock: not frozen, and not one that an
985
+ earlier part already is. */
986
+ static int
987
+ address_basis_sweep_locks (address_basis_sweep_call_t *c, int i)
988
+ {
989
+ int k;
990
+ if ( OBJ_FROZEN(c->parts[i]) ) return 0;
991
+ for ( k = 0; k < i; k++ ) {
992
+ if ( c->parts[k] == c->parts[i] ) return 0;
993
+ }
994
+ return 1;
995
+ }
996
+
997
+ static VALUE
998
+ address_basis_sweep_body (VALUE arg)
999
+ {
1000
+ address_basis_sweep_call_t *c = (address_basis_sweep_call_t *) arg;
1001
+ const VALUE *a = c->arrays;
1002
+ for ( ; c->nlocked < c->nparts; c->nlocked++ ) {
1003
+ if ( address_basis_sweep_locks(c, c->nlocked) ) {
1004
+ rb_str_locktmp(c->parts[c->nlocked]);
1005
+ }
1006
+ }
1007
+ switch ( c->n ) {
1008
+ case 1: ca_call_cslab_1_r(c->function, c->fsync, a[0], c->table); break;
1009
+ case 2: ca_call_cslab_2_r(c->function, c->fsync, a[0], a[1], c->table); break;
1010
+ case 3: ca_call_cslab_3_r(c->function, c->fsync, a[0], a[1], a[2], c->table); break;
1011
+ case 4: ca_call_cslab_4_r(c->function, c->fsync, a[0], a[1], a[2], a[3],
1012
+ c->table); break;
1013
+ case 5: ca_call_cslab_5_r(c->function, c->fsync, a[0], a[1], a[2], a[3], a[4],
1014
+ c->table); break;
1015
+ case 6: ca_call_cslab_6_r(c->function, c->fsync, a[0], a[1], a[2], a[3], a[4],
1016
+ a[5], c->table); break;
1017
+ case 7: ca_call_cslab_7_r(c->function, c->fsync, a[0], a[1], a[2], a[3], a[4],
1018
+ a[5], a[6], c->table); break;
1019
+ }
1020
+ return Qnil;
1021
+ }
1022
+
1023
+ static VALUE
1024
+ address_basis_sweep_unlock (VALUE arg)
1025
+ {
1026
+ address_basis_sweep_call_t *c = (address_basis_sweep_call_t *) arg;
1027
+ int i;
1028
+ for ( i = 0; i < c->nlocked; i++ ) {
1029
+ if ( address_basis_sweep_locks(c, i) ) {
1030
+ rb_str_unlocktmp(c->parts[i]);
1031
+ }
1032
+ }
1033
+ return Qnil;
1034
+ }
1035
+
970
1036
  /*
971
1037
  * call-seq:
972
1038
  * CArray::AddressBasis.sweep(function, fsync, arrays, *parts) -> nil
@@ -996,11 +1062,12 @@ address_basis_sweep (int argc, VALUE *argv, VALUE module)
996
1062
  {
997
1063
  volatile VALUE rfunction, rfsync, rarrays;
998
1064
  ca_cslab_r_t function;
999
- const char *fsync;
1065
+ char fsync[8];
1000
1066
  VALUE vholder = 0;
1001
1067
  void **table;
1002
- VALUE *arrays;
1068
+ volatile VALUE arrays[7];
1003
1069
  volatile VALUE *parts;
1070
+ address_basis_sweep_call_t call;
1004
1071
  int i, n, nparts;
1005
1072
 
1006
1073
  rb_check_arity(argc, 3, UNLIMITED_ARGUMENTS);
@@ -1026,10 +1093,16 @@ address_basis_sweep (int argc, VALUE *argv, VALUE module)
1026
1093
  rb_raise(rb_eArgError, "%s: a sweep takes 1 to 7 arrays, got %d",
1027
1094
  ca_calling_method_name(), n);
1028
1095
  }
1029
- fsync = StringValueCStr(rfsync);
1030
- if ( (int) strlen(fsync) != n ) {
1031
- rb_raise(rb_eArgError, "%s: fsync has %d characters for %d arrays",
1032
- ca_calling_method_name(), (int) strlen(fsync), n);
1096
+ {
1097
+ /* Copied: nothing may change it while the sweep reads it. */
1098
+ const char *f = StringValueCStr(rfsync);
1099
+ long len = (long) strlen(f);
1100
+ if ( len != n ) {
1101
+ rb_raise(rb_eArgError, "%s: fsync has %ld characters for %d arrays",
1102
+ ca_calling_method_name(), len, n);
1103
+ }
1104
+ memcpy(fsync, f, (size_t) n);
1105
+ fsync[n] = '\0';
1033
1106
  }
1034
1107
  for ( i = 0; i < n; i++ ) {
1035
1108
  if ( fsync[i] != '0' && fsync[i] != '1' ) {
@@ -1044,7 +1117,11 @@ address_basis_sweep (int argc, VALUE *argv, VALUE module)
1044
1117
  ca_calling_method_name());
1045
1118
  }
1046
1119
 
1047
- arrays = RARRAY_PTR(rarrays);
1120
+ /* Copied onto the machine stack, which pins them: the list itself can be
1121
+ changed by Ruby that runs during the sweep. */
1122
+ for ( i = 0; i < n; i++ ) {
1123
+ arrays[i] = RARRAY_AREF(rarrays, i);
1124
+ }
1048
1125
  for ( i = 0; i < n; i++ ) {
1049
1126
  if ( ! rb_obj_is_kind_of(arrays[i], rb_cCArray) ) {
1050
1127
  rb_raise(rb_eTypeError, "%s: array %d is not a CArray",
@@ -1073,28 +1150,25 @@ address_basis_sweep (int argc, VALUE *argv, VALUE module)
1073
1150
  table[i] = RSTRING_PTR(parts[i]);
1074
1151
  }
1075
1152
 
1076
- switch ( n ) {
1077
- case 1: ca_call_cslab_1_r(function, fsync, arrays[0], table); break;
1078
- case 2: ca_call_cslab_2_r(function, fsync, arrays[0], arrays[1], table); break;
1079
- case 3: ca_call_cslab_3_r(function, fsync, arrays[0], arrays[1], arrays[2],
1080
- table); break;
1081
- case 4: ca_call_cslab_4_r(function, fsync, arrays[0], arrays[1], arrays[2],
1082
- arrays[3], table); break;
1083
- case 5: ca_call_cslab_5_r(function, fsync, arrays[0], arrays[1], arrays[2],
1084
- arrays[3], arrays[4], table); break;
1085
- case 6: ca_call_cslab_6_r(function, fsync, arrays[0], arrays[1], arrays[2],
1086
- arrays[3], arrays[4], arrays[5], table); break;
1087
- case 7: ca_call_cslab_7_r(function, fsync, arrays[0], arrays[1], arrays[2],
1088
- arrays[3], arrays[4], arrays[5], arrays[6],
1089
- table); break;
1090
- }
1153
+ call.function = function;
1154
+ call.fsync = fsync;
1155
+ call.n = n;
1156
+ call.arrays = (const VALUE *) arrays;
1157
+ call.table = table;
1158
+ call.parts = parts;
1159
+ call.nparts = nparts;
1160
+ call.nlocked = 0;
1161
+ rb_ensure(address_basis_sweep_body, (VALUE) &call,
1162
+ address_basis_sweep_unlock, (VALUE) &call);
1091
1163
 
1092
1164
  ALLOCV_END(vholder);
1093
1165
  for ( i = 0; i < nparts; i++ ) {
1094
1166
  RB_GC_GUARD(parts[i]);
1095
1167
  }
1168
+ for ( i = 0; i < n; i++ ) {
1169
+ RB_GC_GUARD(arrays[i]);
1170
+ }
1096
1171
  RB_GC_GUARD(rarrays);
1097
- RB_GC_GUARD(rfsync);
1098
1172
  return Qnil;
1099
1173
  }
1100
1174
 
@@ -184,7 +184,7 @@ NORETURN(static void ca_broadcast_refuse (VALUE self, VALUE other));
184
184
  element counts are equal, .flatten pairs the values in the order
185
185
  they lie. */
186
186
  static void
187
- ca_broadcast_refuse (VALUE self, VALUE other)
187
+ ca_broadcast_refuse (VALUE self, volatile VALUE other)
188
188
  {
189
189
  CArray *ca, *cb;
190
190
  volatile VALUE self_s = rb_inspect(rb_funcall(self, rb_intern("shape"), 0));
@@ -311,7 +311,7 @@ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
311
311
  }
312
312
 
313
313
  for (i = 0; i < target_ndim; i++) {
314
- target_dim[i] = NUM2SIZE(argv[i]);
314
+ target_dim[i] = ca_integer_arg(argv[i], "a dimension", "broadcast_to");
315
315
  if (target_dim[i] < 0) {
316
316
  rb_raise(rb_eArgError,
317
317
  "broadcast_to: negative dim at axis %d", i);
@@ -19,11 +19,9 @@
19
19
  * file-static / global plumbing.
20
20
  *
21
21
  * Attach-safe: INPUT-only operands (= fsync[k] == '0') never call
22
- * ca_attach on the operand or its mask (= alias check + ALLOCV +
22
+ * ca_attach on the operand or its mask (= alias check + xmalloc +
23
23
  * ca_xfer_all for non-alias). OUTPUT operands (= fsync[k] == '1')
24
- * use ca_attach + ca_sync (= legitimate per the refined input-only-
25
- * operand invariant established in PROPOSAL_EAGER_ELEMENTWISE_NO_ATTACH
26
- * and extended in PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA).
24
+ * use ca_attach + ca_sync.
27
25
  *
28
26
  * Slab variants `ca_call_cslab_N` / `ca_call_cslab_N_r` take the chunked
29
27
  * path instead (ca_sweep_acquire_chunked / ca_sweep_next_chunk /
@@ -37,10 +35,9 @@
37
35
  * function to wrap); use cslab when the operand is large, virtual, or the
38
36
  * body is worth vectorising.
39
37
  *
40
- * L0.1 (PROPOSAL_L0_AUTHOR_SURFACE, 2026-06-11): the per-operand acquire
41
- * + broadcast check + mask OR + release lifecycle is now factored out
42
- * into ext/ca_sweep_engine.{c,h} (ca_sweep_acquire / ca_sweep_release). This
43
- * file keeps the arity-dependent inner loop only. ABI unchanged.
38
+ * The per-operand acquire + broadcast check + mask OR + release lifecycle
39
+ * lives in ext/ca_sweep_engine.{c,h} (ca_sweep_acquire / ca_sweep_release).
40
+ * This file keeps the arity-dependent inner loop only.
44
41
  *
45
42
  * --------------------------------------------------------------------------- */
46
43