carray 3.0.1 → 3.0.2

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +520 -0
  3. data/README.md +2 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +33 -4
  6. data/ext/ca_axis_group.c +202 -96
  7. data/ext/ca_categorical_iterator.c +108 -54
  8. data/ext/ca_kernel_iterator.c +317 -51
  9. data/ext/ca_kernel_iterator.h +142 -35
  10. data/ext/ca_obj_array.c +62 -20
  11. data/ext/ca_obj_block.c +4 -4
  12. data/ext/ca_obj_const_string.c +85 -26
  13. data/ext/ca_obj_face.c +24 -0
  14. data/ext/ca_obj_face.h +15 -0
  15. data/ext/ca_obj_fixlen_string.c +18 -5
  16. data/ext/ca_obj_meld.c +123 -25
  17. data/ext/ca_obj_object.c +8 -0
  18. data/ext/ca_obj_select.c +49 -34
  19. data/ext/ca_obj_stack.c +3 -8
  20. data/ext/ca_obj_stride.c +72 -1
  21. data/ext/ca_obj_string.c +8 -4
  22. data/ext/ca_obj_window.c +8 -2
  23. data/ext/ca_op_ipower.c +1 -2
  24. data/ext/ca_rng_normal.h +42 -0
  25. data/ext/ca_rng_xoshiro256pp.h +105 -0
  26. data/ext/ca_sweep_engine.c +307 -143
  27. data/ext/ca_sweep_engine.h +26 -5
  28. data/ext/carray.h +21 -2
  29. data/ext/carray_access.c +32 -20
  30. data/ext/carray_address_basis.c +590 -0
  31. data/ext/carray_broadcast.c +3 -3
  32. data/ext/carray_call_cfunc.c +667 -483
  33. data/ext/carray_cast.c +115 -41
  34. data/ext/carray_copy.c +55 -30
  35. data/ext/carray_core.c +83 -3
  36. data/ext/carray_count.c +9 -10
  37. data/ext/carray_factorize.c +46 -25
  38. data/ext/carray_internal.h +17 -0
  39. data/ext/carray_kernels_reduce_aggregate.c +168 -0
  40. data/ext/carray_kernels_reduce_cumulative.c +270 -1
  41. data/ext/carray_kernels_reduce_extreme.c +554 -8
  42. data/ext/carray_kernels_scan.c +4 -4
  43. data/ext/carray_kernels_search.c +94 -14
  44. data/ext/carray_loop.c +7 -1
  45. data/ext/carray_mask.c +23 -8
  46. data/ext/carray_median_percentile.c +55 -0
  47. data/ext/carray_operator.c +4 -4
  48. data/ext/carray_order.c +1 -1
  49. data/ext/carray_random.c +384 -40
  50. data/ext/carray_slab.c +13 -0
  51. data/ext/carray_sort.c +20 -22
  52. data/ext/mk_call_cfunc.rb +103 -116
  53. data/ext/mkkernel.rb +297 -29
  54. data/ext/ruby_carray.c +10 -1
  55. data/ext/version.h +4 -4
  56. data/lib/carray/autoload_carray.rb +5 -3
  57. data/lib/carray/autoload_method_extension.rb +12 -0
  58. data/lib/carray/axis_group.rb +77 -0
  59. data/lib/carray/basics.rb +4 -0
  60. data/lib/carray/block_iterator.rb +92 -16
  61. data/lib/carray/categorical.rb +150 -33
  62. data/lib/carray/categorical_iterator.rb +207 -80
  63. data/lib/carray/const_string.rb +131 -27
  64. data/lib/carray/construct.rb +40 -0
  65. data/lib/carray/data_type_extension.rb +3 -0
  66. data/lib/carray/data_type_limits.rb +91 -0
  67. data/lib/carray/fixlen_string.rb +1 -1
  68. data/lib/carray/frame/csv_parser.rb +11 -4
  69. data/lib/carray/frame/frame.rb +81 -10
  70. data/lib/carray/frame/group.rb +36 -3
  71. data/lib/carray/frame/io.rb +67 -15
  72. data/lib/carray/frame/records.rb +18 -4
  73. data/lib/carray/frame/verbs.rb +14 -11
  74. data/lib/carray/inspect.rb +42 -9
  75. data/lib/carray/iterator.rb +143 -0
  76. data/lib/carray/lazy.rb +0 -37
  77. data/lib/carray/mask_gap_fill.rb +3 -1
  78. data/lib/carray/methods/discovery_along.rb +74 -0
  79. data/lib/carray/methods/factorize.rb +50 -0
  80. data/lib/carray/methods/is_in.rb +13 -2
  81. data/lib/carray/methods/locate_addr.rb +75 -2
  82. data/lib/carray/methods/mask_duplicates.rb +35 -1
  83. data/lib/carray/methods/nunique.rb +22 -1
  84. data/lib/carray/methods/repeat.rb +110 -0
  85. data/lib/carray/methods/unique.rb +41 -1
  86. data/lib/carray/rng.rb +86 -0
  87. data/lib/carray/slab_iterator.rb +58 -13
  88. data/lib/carray/string_operation_extension.rb +5 -1
  89. data/lib/carray/time.rb +18 -2
  90. data/lib/carray/window_iterator.rb +142 -20
  91. data/lib/carray.rb +2 -0
  92. data/yard-stubs/ca_obj_block.rb +2 -7
  93. data/yard-stubs/ca_obj_window.rb +10 -2
  94. data/yard-stubs/carray_access.rb +1 -1
  95. data/yard-stubs/carray_broadcast.rb +1 -1
  96. data/yard-stubs/carray_core.rb +0 -80
  97. data/yard-stubs/carray_count.rb +7 -2
  98. data/yard-stubs/carray_lazy.rb +205 -0
  99. data/yard-stubs/carray_math.rb +1486 -3
  100. data/yard-stubs/carray_median_percentile.rb +16 -2
  101. data/yard-stubs/carray_order.rb +9 -69
  102. data/yard-stubs/carray_slab.rb +9 -7
  103. data/yard-stubs/carray_sort.rb +7 -5
  104. metadata +9 -1
@@ -48,14 +48,78 @@
48
48
  #include "ca_sweep_engine.h"
49
49
  #include <string.h>
50
50
 
51
- /* The chunk's iteration mask, or NULL when no INPUT operand carried one.
52
- m0 is chunk-sized and re-gathered per chunk by ca_sweep_next_chunk, so
53
- it is already the slice -- one byte per cell, indexed 0..chunk_n-1
54
- alongside base[] and stride[]. */
55
- static const boolean8_t *
56
- ca_sweep_chunk_mask (ca_sweep_state_t *st)
57
- {
58
- return st->m0;
51
+ /* Chunk walk for the ca_call_cslab_N family, run by ca_sweep_run_chunked
52
+ so that a callback raising part way through gives back what the engine
53
+ holds. Hands the author one chunk at a time. base[] is rewritten per
54
+ chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points at the
55
+ arena scratch the chunk was just gathered into, which is packed, so
56
+ stride[] is the element size and the author's inner loop sees
57
+ contiguous data. m0 is the chunk's iteration mask, or NULL when no
58
+ INPUT operand carried one: chunk-sized and re-gathered per chunk, so it
59
+ is already the slice -- one byte per cell, indexed 0..chunk_n-1
60
+ alongside base[] and stride[]. The arity does not appear here: the
61
+ operands reach the callback through base[] / stride[]. */
62
+ typedef struct {
63
+ ca_sweep_state_t *st;
64
+ ca_cslab_t func; /* ca_call_cslab_N */
65
+ ca_cslab_r_t func_r; /* ca_call_cslab_N_r */
66
+ void *userdata;
67
+ } ca_cslab_ctx_t;
68
+
69
+ static VALUE
70
+ ca_cslab_walk (VALUE arg)
71
+ {
72
+ ca_cslab_ctx_t *c = (ca_cslab_ctx_t *) arg;
73
+ ca_sweep_state_t *st = c->st;
74
+ while ( ca_sweep_next_chunk(st) ) {
75
+ c->func(st->base, st->stride, st->chunk_n, st->m0);
76
+ }
77
+ return Qnil;
78
+ }
79
+
80
+ static VALUE
81
+ ca_cslab_r_walk (VALUE arg)
82
+ {
83
+ ca_cslab_ctx_t *c = (ca_cslab_ctx_t *) arg;
84
+ ca_sweep_state_t *st = c->st;
85
+ while ( ca_sweep_next_chunk(st) ) {
86
+ c->func_r(st->base, st->stride, st->chunk_n, st->m0, c->userdata);
87
+ }
88
+ return Qnil;
89
+ }
90
+
91
+ typedef struct {
92
+ ca_sweep_state_t *st;
93
+ void (*func)(void *p0);
94
+ void *userdata;
95
+ } ca_call_cfunc_1_ctx_t;
96
+
97
+ static VALUE
98
+ ca_call_cfunc_1_walk (VALUE arg)
99
+ {
100
+ ca_call_cfunc_1_ctx_t *c = (ca_call_cfunc_1_ctx_t *) arg;
101
+ ca_sweep_state_t *st = c->st;
102
+ char *p[1];
103
+ ca_size_t k;
104
+ int k_op;
105
+ if ( st->m0 ) {
106
+ for ( k = 0; k < st->n_kernel; k++ ) {
107
+ if ( ! st->m0[k] ) {
108
+ for ( k_op = 0; k_op < 1; k_op++ ) {
109
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
110
+ }
111
+ c->func(p[0]);
112
+ }
113
+ }
114
+ } else {
115
+ for ( k = 0; k < st->n_kernel; k++ ) {
116
+ for ( k_op = 0; k_op < 1; k_op++ ) {
117
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
118
+ }
119
+ c->func(p[0]);
120
+ }
121
+ }
122
+ return Qnil;
59
123
  }
60
124
 
61
125
  VALUE
@@ -68,13 +132,13 @@ ca_call_cfunc_1 (void (*func)(void *p0), const char *fsync,
68
132
  char *owned_buf[1];
69
133
  int attached[1];
70
134
  ca_sweep_state_t state;
71
- int k_op;
135
+ ca_call_cfunc_1_ctx_t ctx;
72
136
 
73
137
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
74
138
 
75
139
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
76
- broadcast shape check, mask OR across INPUTs, mask propagate to
77
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
140
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
141
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
78
142
  state.n_ops = 1;
79
143
  state.fsync = fsync;
80
144
  state.cx = cx;
@@ -87,32 +151,46 @@ ca_call_cfunc_1 (void (*func)(void *p0), const char *fsync,
87
151
 
88
152
  ca_sweep_acquire(&state);
89
153
 
90
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
91
- {
92
- char *p[1];
93
- ca_size_t k;
94
- if ( state.m0 ) {
95
- for ( k = 0; k < state.n_kernel; k++ ) {
96
- if ( ! state.m0[k] ) {
97
- for ( k_op = 0; k_op < 1; k_op++ ) {
98
- p[k_op] = base[k_op] + k * stride[k_op];
99
- }
100
- func(p[0]);
154
+ ctx.st = &state;
155
+ ctx.func = func;
156
+ ctx.userdata = NULL;
157
+ ca_sweep_run(&state, ca_call_cfunc_1_walk, (VALUE) &ctx);
158
+
159
+ return rcx0;
160
+ }
161
+
162
+ typedef struct {
163
+ ca_sweep_state_t *st;
164
+ void (*func)(void *p0, void *p1);
165
+ void *userdata;
166
+ } ca_call_cfunc_2_ctx_t;
167
+
168
+ static VALUE
169
+ ca_call_cfunc_2_walk (VALUE arg)
170
+ {
171
+ ca_call_cfunc_2_ctx_t *c = (ca_call_cfunc_2_ctx_t *) arg;
172
+ ca_sweep_state_t *st = c->st;
173
+ char *p[2];
174
+ ca_size_t k;
175
+ int k_op;
176
+ if ( st->m0 ) {
177
+ for ( k = 0; k < st->n_kernel; k++ ) {
178
+ if ( ! st->m0[k] ) {
179
+ for ( k_op = 0; k_op < 2; k_op++ ) {
180
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
101
181
  }
182
+ c->func(p[0], p[1]);
102
183
  }
103
- } else {
104
- for ( k = 0; k < state.n_kernel; k++ ) {
105
- for ( k_op = 0; k_op < 1; k_op++ ) {
106
- p[k_op] = base[k_op] + k * stride[k_op];
107
- }
108
- func(p[0]);
184
+ }
185
+ } else {
186
+ for ( k = 0; k < st->n_kernel; k++ ) {
187
+ for ( k_op = 0; k_op < 2; k_op++ ) {
188
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
109
189
  }
190
+ c->func(p[0], p[1]);
110
191
  }
111
192
  }
112
-
113
- ca_sweep_release(&state);
114
-
115
- return rcx0;
193
+ return Qnil;
116
194
  }
117
195
 
118
196
  VALUE
@@ -125,14 +203,14 @@ ca_call_cfunc_2 (void (*func)(void *p0, void *p1), const char *fsync,
125
203
  char *owned_buf[2];
126
204
  int attached[2];
127
205
  ca_sweep_state_t state;
128
- int k_op;
206
+ ca_call_cfunc_2_ctx_t ctx;
129
207
 
130
208
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
131
209
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
132
210
 
133
211
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
134
- broadcast shape check, mask OR across INPUTs, mask propagate to
135
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
212
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
213
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
136
214
  state.n_ops = 2;
137
215
  state.fsync = fsync;
138
216
  state.cx = cx;
@@ -145,32 +223,46 @@ ca_call_cfunc_2 (void (*func)(void *p0, void *p1), const char *fsync,
145
223
 
146
224
  ca_sweep_acquire(&state);
147
225
 
148
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
149
- {
150
- char *p[2];
151
- ca_size_t k;
152
- if ( state.m0 ) {
153
- for ( k = 0; k < state.n_kernel; k++ ) {
154
- if ( ! state.m0[k] ) {
155
- for ( k_op = 0; k_op < 2; k_op++ ) {
156
- p[k_op] = base[k_op] + k * stride[k_op];
157
- }
158
- func(p[0], p[1]);
226
+ ctx.st = &state;
227
+ ctx.func = func;
228
+ ctx.userdata = NULL;
229
+ ca_sweep_run(&state, ca_call_cfunc_2_walk, (VALUE) &ctx);
230
+
231
+ return rcx0;
232
+ }
233
+
234
+ typedef struct {
235
+ ca_sweep_state_t *st;
236
+ void (*func)(void *p0, void *p1, void *p2);
237
+ void *userdata;
238
+ } ca_call_cfunc_3_ctx_t;
239
+
240
+ static VALUE
241
+ ca_call_cfunc_3_walk (VALUE arg)
242
+ {
243
+ ca_call_cfunc_3_ctx_t *c = (ca_call_cfunc_3_ctx_t *) arg;
244
+ ca_sweep_state_t *st = c->st;
245
+ char *p[3];
246
+ ca_size_t k;
247
+ int k_op;
248
+ if ( st->m0 ) {
249
+ for ( k = 0; k < st->n_kernel; k++ ) {
250
+ if ( ! st->m0[k] ) {
251
+ for ( k_op = 0; k_op < 3; k_op++ ) {
252
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
159
253
  }
254
+ c->func(p[0], p[1], p[2]);
160
255
  }
161
- } else {
162
- for ( k = 0; k < state.n_kernel; k++ ) {
163
- for ( k_op = 0; k_op < 2; k_op++ ) {
164
- p[k_op] = base[k_op] + k * stride[k_op];
165
- }
166
- func(p[0], p[1]);
256
+ }
257
+ } else {
258
+ for ( k = 0; k < st->n_kernel; k++ ) {
259
+ for ( k_op = 0; k_op < 3; k_op++ ) {
260
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
167
261
  }
262
+ c->func(p[0], p[1], p[2]);
168
263
  }
169
264
  }
170
-
171
- ca_sweep_release(&state);
172
-
173
- return rcx0;
265
+ return Qnil;
174
266
  }
175
267
 
176
268
  VALUE
@@ -183,15 +275,15 @@ ca_call_cfunc_3 (void (*func)(void *p0, void *p1, void *p2), const char *fsync,
183
275
  char *owned_buf[3];
184
276
  int attached[3];
185
277
  ca_sweep_state_t state;
186
- int k_op;
278
+ ca_call_cfunc_3_ctx_t ctx;
187
279
 
188
280
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
189
281
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
190
282
  TypedData_Get_Struct(rcx2, CArray, &carray_data_type, cx[2]);
191
283
 
192
284
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
193
- broadcast shape check, mask OR across INPUTs, mask propagate to
194
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
285
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
286
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
195
287
  state.n_ops = 3;
196
288
  state.fsync = fsync;
197
289
  state.cx = cx;
@@ -204,32 +296,46 @@ ca_call_cfunc_3 (void (*func)(void *p0, void *p1, void *p2), const char *fsync,
204
296
 
205
297
  ca_sweep_acquire(&state);
206
298
 
207
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
208
- {
209
- char *p[3];
210
- ca_size_t k;
211
- if ( state.m0 ) {
212
- for ( k = 0; k < state.n_kernel; k++ ) {
213
- if ( ! state.m0[k] ) {
214
- for ( k_op = 0; k_op < 3; k_op++ ) {
215
- p[k_op] = base[k_op] + k * stride[k_op];
216
- }
217
- func(p[0], p[1], p[2]);
299
+ ctx.st = &state;
300
+ ctx.func = func;
301
+ ctx.userdata = NULL;
302
+ ca_sweep_run(&state, ca_call_cfunc_3_walk, (VALUE) &ctx);
303
+
304
+ return rcx0;
305
+ }
306
+
307
+ typedef struct {
308
+ ca_sweep_state_t *st;
309
+ void (*func)(void *p0, void *p1, void *p2, void *p3);
310
+ void *userdata;
311
+ } ca_call_cfunc_4_ctx_t;
312
+
313
+ static VALUE
314
+ ca_call_cfunc_4_walk (VALUE arg)
315
+ {
316
+ ca_call_cfunc_4_ctx_t *c = (ca_call_cfunc_4_ctx_t *) arg;
317
+ ca_sweep_state_t *st = c->st;
318
+ char *p[4];
319
+ ca_size_t k;
320
+ int k_op;
321
+ if ( st->m0 ) {
322
+ for ( k = 0; k < st->n_kernel; k++ ) {
323
+ if ( ! st->m0[k] ) {
324
+ for ( k_op = 0; k_op < 4; k_op++ ) {
325
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
218
326
  }
327
+ c->func(p[0], p[1], p[2], p[3]);
219
328
  }
220
- } else {
221
- for ( k = 0; k < state.n_kernel; k++ ) {
222
- for ( k_op = 0; k_op < 3; k_op++ ) {
223
- p[k_op] = base[k_op] + k * stride[k_op];
224
- }
225
- func(p[0], p[1], p[2]);
329
+ }
330
+ } else {
331
+ for ( k = 0; k < st->n_kernel; k++ ) {
332
+ for ( k_op = 0; k_op < 4; k_op++ ) {
333
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
226
334
  }
335
+ c->func(p[0], p[1], p[2], p[3]);
227
336
  }
228
337
  }
229
-
230
- ca_sweep_release(&state);
231
-
232
- return rcx0;
338
+ return Qnil;
233
339
  }
234
340
 
235
341
  VALUE
@@ -242,7 +348,7 @@ ca_call_cfunc_4 (void (*func)(void *p0, void *p1, void *p2, void *p3), const cha
242
348
  char *owned_buf[4];
243
349
  int attached[4];
244
350
  ca_sweep_state_t state;
245
- int k_op;
351
+ ca_call_cfunc_4_ctx_t ctx;
246
352
 
247
353
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
248
354
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -250,8 +356,8 @@ ca_call_cfunc_4 (void (*func)(void *p0, void *p1, void *p2, void *p3), const cha
250
356
  TypedData_Get_Struct(rcx3, CArray, &carray_data_type, cx[3]);
251
357
 
252
358
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
253
- broadcast shape check, mask OR across INPUTs, mask propagate to
254
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
359
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
360
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
255
361
  state.n_ops = 4;
256
362
  state.fsync = fsync;
257
363
  state.cx = cx;
@@ -264,32 +370,46 @@ ca_call_cfunc_4 (void (*func)(void *p0, void *p1, void *p2, void *p3), const cha
264
370
 
265
371
  ca_sweep_acquire(&state);
266
372
 
267
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
268
- {
269
- char *p[4];
270
- ca_size_t k;
271
- if ( state.m0 ) {
272
- for ( k = 0; k < state.n_kernel; k++ ) {
273
- if ( ! state.m0[k] ) {
274
- for ( k_op = 0; k_op < 4; k_op++ ) {
275
- p[k_op] = base[k_op] + k * stride[k_op];
276
- }
277
- func(p[0], p[1], p[2], p[3]);
373
+ ctx.st = &state;
374
+ ctx.func = func;
375
+ ctx.userdata = NULL;
376
+ ca_sweep_run(&state, ca_call_cfunc_4_walk, (VALUE) &ctx);
377
+
378
+ return rcx0;
379
+ }
380
+
381
+ typedef struct {
382
+ ca_sweep_state_t *st;
383
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4);
384
+ void *userdata;
385
+ } ca_call_cfunc_5_ctx_t;
386
+
387
+ static VALUE
388
+ ca_call_cfunc_5_walk (VALUE arg)
389
+ {
390
+ ca_call_cfunc_5_ctx_t *c = (ca_call_cfunc_5_ctx_t *) arg;
391
+ ca_sweep_state_t *st = c->st;
392
+ char *p[5];
393
+ ca_size_t k;
394
+ int k_op;
395
+ if ( st->m0 ) {
396
+ for ( k = 0; k < st->n_kernel; k++ ) {
397
+ if ( ! st->m0[k] ) {
398
+ for ( k_op = 0; k_op < 5; k_op++ ) {
399
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
278
400
  }
401
+ c->func(p[0], p[1], p[2], p[3], p[4]);
279
402
  }
280
- } else {
281
- for ( k = 0; k < state.n_kernel; k++ ) {
282
- for ( k_op = 0; k_op < 4; k_op++ ) {
283
- p[k_op] = base[k_op] + k * stride[k_op];
284
- }
285
- func(p[0], p[1], p[2], p[3]);
403
+ }
404
+ } else {
405
+ for ( k = 0; k < st->n_kernel; k++ ) {
406
+ for ( k_op = 0; k_op < 5; k_op++ ) {
407
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
286
408
  }
409
+ c->func(p[0], p[1], p[2], p[3], p[4]);
287
410
  }
288
411
  }
289
-
290
- ca_sweep_release(&state);
291
-
292
- return rcx0;
412
+ return Qnil;
293
413
  }
294
414
 
295
415
  VALUE
@@ -302,7 +422,7 @@ ca_call_cfunc_5 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4),
302
422
  char *owned_buf[5];
303
423
  int attached[5];
304
424
  ca_sweep_state_t state;
305
- int k_op;
425
+ ca_call_cfunc_5_ctx_t ctx;
306
426
 
307
427
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
308
428
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -311,8 +431,8 @@ ca_call_cfunc_5 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4),
311
431
  TypedData_Get_Struct(rcx4, CArray, &carray_data_type, cx[4]);
312
432
 
313
433
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
314
- broadcast shape check, mask OR across INPUTs, mask propagate to
315
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
434
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
435
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
316
436
  state.n_ops = 5;
317
437
  state.fsync = fsync;
318
438
  state.cx = cx;
@@ -325,32 +445,46 @@ ca_call_cfunc_5 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4),
325
445
 
326
446
  ca_sweep_acquire(&state);
327
447
 
328
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
329
- {
330
- char *p[5];
331
- ca_size_t k;
332
- if ( state.m0 ) {
333
- for ( k = 0; k < state.n_kernel; k++ ) {
334
- if ( ! state.m0[k] ) {
335
- for ( k_op = 0; k_op < 5; k_op++ ) {
336
- p[k_op] = base[k_op] + k * stride[k_op];
337
- }
338
- func(p[0], p[1], p[2], p[3], p[4]);
448
+ ctx.st = &state;
449
+ ctx.func = func;
450
+ ctx.userdata = NULL;
451
+ ca_sweep_run(&state, ca_call_cfunc_5_walk, (VALUE) &ctx);
452
+
453
+ return rcx0;
454
+ }
455
+
456
+ typedef struct {
457
+ ca_sweep_state_t *st;
458
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4, void *p5);
459
+ void *userdata;
460
+ } ca_call_cfunc_6_ctx_t;
461
+
462
+ static VALUE
463
+ ca_call_cfunc_6_walk (VALUE arg)
464
+ {
465
+ ca_call_cfunc_6_ctx_t *c = (ca_call_cfunc_6_ctx_t *) arg;
466
+ ca_sweep_state_t *st = c->st;
467
+ char *p[6];
468
+ ca_size_t k;
469
+ int k_op;
470
+ if ( st->m0 ) {
471
+ for ( k = 0; k < st->n_kernel; k++ ) {
472
+ if ( ! st->m0[k] ) {
473
+ for ( k_op = 0; k_op < 6; k_op++ ) {
474
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
339
475
  }
476
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5]);
340
477
  }
341
- } else {
342
- for ( k = 0; k < state.n_kernel; k++ ) {
343
- for ( k_op = 0; k_op < 5; k_op++ ) {
344
- p[k_op] = base[k_op] + k * stride[k_op];
345
- }
346
- func(p[0], p[1], p[2], p[3], p[4]);
478
+ }
479
+ } else {
480
+ for ( k = 0; k < st->n_kernel; k++ ) {
481
+ for ( k_op = 0; k_op < 6; k_op++ ) {
482
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
347
483
  }
484
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5]);
348
485
  }
349
486
  }
350
-
351
- ca_sweep_release(&state);
352
-
353
- return rcx0;
487
+ return Qnil;
354
488
  }
355
489
 
356
490
  VALUE
@@ -363,7 +497,7 @@ ca_call_cfunc_6 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4,
363
497
  char *owned_buf[6];
364
498
  int attached[6];
365
499
  ca_sweep_state_t state;
366
- int k_op;
500
+ ca_call_cfunc_6_ctx_t ctx;
367
501
 
368
502
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
369
503
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -373,8 +507,8 @@ ca_call_cfunc_6 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4,
373
507
  TypedData_Get_Struct(rcx5, CArray, &carray_data_type, cx[5]);
374
508
 
375
509
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
376
- broadcast shape check, mask OR across INPUTs, mask propagate to
377
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
510
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
511
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
378
512
  state.n_ops = 6;
379
513
  state.fsync = fsync;
380
514
  state.cx = cx;
@@ -387,32 +521,46 @@ ca_call_cfunc_6 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4,
387
521
 
388
522
  ca_sweep_acquire(&state);
389
523
 
390
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
391
- {
392
- char *p[6];
393
- ca_size_t k;
394
- if ( state.m0 ) {
395
- for ( k = 0; k < state.n_kernel; k++ ) {
396
- if ( ! state.m0[k] ) {
397
- for ( k_op = 0; k_op < 6; k_op++ ) {
398
- p[k_op] = base[k_op] + k * stride[k_op];
399
- }
400
- func(p[0], p[1], p[2], p[3], p[4], p[5]);
524
+ ctx.st = &state;
525
+ ctx.func = func;
526
+ ctx.userdata = NULL;
527
+ ca_sweep_run(&state, ca_call_cfunc_6_walk, (VALUE) &ctx);
528
+
529
+ return rcx0;
530
+ }
531
+
532
+ typedef struct {
533
+ ca_sweep_state_t *st;
534
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4, void *p5, void *p6);
535
+ void *userdata;
536
+ } ca_call_cfunc_7_ctx_t;
537
+
538
+ static VALUE
539
+ ca_call_cfunc_7_walk (VALUE arg)
540
+ {
541
+ ca_call_cfunc_7_ctx_t *c = (ca_call_cfunc_7_ctx_t *) arg;
542
+ ca_sweep_state_t *st = c->st;
543
+ char *p[7];
544
+ ca_size_t k;
545
+ int k_op;
546
+ if ( st->m0 ) {
547
+ for ( k = 0; k < st->n_kernel; k++ ) {
548
+ if ( ! st->m0[k] ) {
549
+ for ( k_op = 0; k_op < 7; k_op++ ) {
550
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
401
551
  }
552
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
402
553
  }
403
- } else {
404
- for ( k = 0; k < state.n_kernel; k++ ) {
405
- for ( k_op = 0; k_op < 6; k_op++ ) {
406
- p[k_op] = base[k_op] + k * stride[k_op];
407
- }
408
- func(p[0], p[1], p[2], p[3], p[4], p[5]);
554
+ }
555
+ } else {
556
+ for ( k = 0; k < st->n_kernel; k++ ) {
557
+ for ( k_op = 0; k_op < 7; k_op++ ) {
558
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
409
559
  }
560
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
410
561
  }
411
562
  }
412
-
413
- ca_sweep_release(&state);
414
-
415
- return rcx0;
563
+ return Qnil;
416
564
  }
417
565
 
418
566
  VALUE
@@ -425,7 +573,7 @@ ca_call_cfunc_7 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4,
425
573
  char *owned_buf[7];
426
574
  int attached[7];
427
575
  ca_sweep_state_t state;
428
- int k_op;
576
+ ca_call_cfunc_7_ctx_t ctx;
429
577
 
430
578
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
431
579
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -436,8 +584,8 @@ ca_call_cfunc_7 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4,
436
584
  TypedData_Get_Struct(rcx6, CArray, &carray_data_type, cx[6]);
437
585
 
438
586
  /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
439
- broadcast shape check, mask OR across INPUTs, mask propagate to
440
- OUTPUTs. Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
587
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
588
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
441
589
  state.n_ops = 7;
442
590
  state.fsync = fsync;
443
591
  state.cx = cx;
@@ -450,30 +598,10 @@ ca_call_cfunc_7 (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4,
450
598
 
451
599
  ca_sweep_acquire(&state);
452
600
 
453
- /* inner loop: advance per-cell ptrs and invoke user kernel func */
454
- {
455
- char *p[7];
456
- ca_size_t k;
457
- if ( state.m0 ) {
458
- for ( k = 0; k < state.n_kernel; k++ ) {
459
- if ( ! state.m0[k] ) {
460
- for ( k_op = 0; k_op < 7; k_op++ ) {
461
- p[k_op] = base[k_op] + k * stride[k_op];
462
- }
463
- func(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
464
- }
465
- }
466
- } else {
467
- for ( k = 0; k < state.n_kernel; k++ ) {
468
- for ( k_op = 0; k_op < 7; k_op++ ) {
469
- p[k_op] = base[k_op] + k * stride[k_op];
470
- }
471
- func(p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
472
- }
473
- }
474
- }
475
-
476
- ca_sweep_release(&state);
601
+ ctx.st = &state;
602
+ ctx.func = func;
603
+ ctx.userdata = NULL;
604
+ ca_sweep_run(&state, ca_call_cfunc_7_walk, (VALUE) &ctx);
477
605
 
478
606
  return rcx0;
479
607
  }
@@ -867,6 +995,40 @@ ca_call_cfunc_3_3 (int8_t dty1, int8_t dty2, int8_t dty3, int8_t dtx1, int8_t dt
867
995
  /* `void *userdata` parameter forwarded to every per-cell invocation. */
868
996
  /* -------------------------------------------------------------------- */
869
997
 
998
+ typedef struct {
999
+ ca_sweep_state_t *st;
1000
+ void (*func)(void *p0, void *userdata);
1001
+ void *userdata;
1002
+ } ca_call_cfunc_1_r_ctx_t;
1003
+
1004
+ static VALUE
1005
+ ca_call_cfunc_1_r_walk (VALUE arg)
1006
+ {
1007
+ ca_call_cfunc_1_r_ctx_t *c = (ca_call_cfunc_1_r_ctx_t *) arg;
1008
+ ca_sweep_state_t *st = c->st;
1009
+ char *p[1];
1010
+ ca_size_t k;
1011
+ int k_op;
1012
+ if ( st->m0 ) {
1013
+ for ( k = 0; k < st->n_kernel; k++ ) {
1014
+ if ( ! st->m0[k] ) {
1015
+ for ( k_op = 0; k_op < 1; k_op++ ) {
1016
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1017
+ }
1018
+ c->func(p[0], c->userdata);
1019
+ }
1020
+ }
1021
+ } else {
1022
+ for ( k = 0; k < st->n_kernel; k++ ) {
1023
+ for ( k_op = 0; k_op < 1; k_op++ ) {
1024
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1025
+ }
1026
+ c->func(p[0], c->userdata);
1027
+ }
1028
+ }
1029
+ return Qnil;
1030
+ }
1031
+
870
1032
  VALUE
871
1033
  ca_call_cfunc_1_r (void (*func)(void *p0, void *userdata), const char *fsync,
872
1034
  VALUE rcx0,
@@ -878,12 +1040,13 @@ ca_call_cfunc_1_r (void (*func)(void *p0, void *userdata), const char *fsync,
878
1040
  char *owned_buf[1];
879
1041
  int attached[1];
880
1042
  ca_sweep_state_t state;
881
- int k_op;
1043
+ ca_call_cfunc_1_r_ctx_t ctx;
882
1044
 
883
1045
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
884
1046
 
885
- /* sweep engine: same lifecycle as ca_call_cfunc_1; the difference is
886
- the per-cell `func(...)` call has `userdata` as its last argument. */
1047
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1048
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1049
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
887
1050
  state.n_ops = 1;
888
1051
  state.fsync = fsync;
889
1052
  state.cx = cx;
@@ -896,31 +1059,46 @@ ca_call_cfunc_1_r (void (*func)(void *p0, void *userdata), const char *fsync,
896
1059
 
897
1060
  ca_sweep_acquire(&state);
898
1061
 
899
- {
900
- char *p[1];
901
- ca_size_t k;
902
- if ( state.m0 ) {
903
- for ( k = 0; k < state.n_kernel; k++ ) {
904
- if ( ! state.m0[k] ) {
905
- for ( k_op = 0; k_op < 1; k_op++ ) {
906
- p[k_op] = base[k_op] + k * stride[k_op];
907
- }
908
- func(p[0], userdata);
1062
+ ctx.st = &state;
1063
+ ctx.func = func;
1064
+ ctx.userdata = userdata;
1065
+ ca_sweep_run(&state, ca_call_cfunc_1_r_walk, (VALUE) &ctx);
1066
+
1067
+ return rcx0;
1068
+ }
1069
+
1070
+ typedef struct {
1071
+ ca_sweep_state_t *st;
1072
+ void (*func)(void *p0, void *p1, void *userdata);
1073
+ void *userdata;
1074
+ } ca_call_cfunc_2_r_ctx_t;
1075
+
1076
+ static VALUE
1077
+ ca_call_cfunc_2_r_walk (VALUE arg)
1078
+ {
1079
+ ca_call_cfunc_2_r_ctx_t *c = (ca_call_cfunc_2_r_ctx_t *) arg;
1080
+ ca_sweep_state_t *st = c->st;
1081
+ char *p[2];
1082
+ ca_size_t k;
1083
+ int k_op;
1084
+ if ( st->m0 ) {
1085
+ for ( k = 0; k < st->n_kernel; k++ ) {
1086
+ if ( ! st->m0[k] ) {
1087
+ for ( k_op = 0; k_op < 2; k_op++ ) {
1088
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
909
1089
  }
1090
+ c->func(p[0], p[1], c->userdata);
910
1091
  }
911
- } else {
912
- for ( k = 0; k < state.n_kernel; k++ ) {
913
- for ( k_op = 0; k_op < 1; k_op++ ) {
914
- p[k_op] = base[k_op] + k * stride[k_op];
915
- }
916
- func(p[0], userdata);
1092
+ }
1093
+ } else {
1094
+ for ( k = 0; k < st->n_kernel; k++ ) {
1095
+ for ( k_op = 0; k_op < 2; k_op++ ) {
1096
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
917
1097
  }
1098
+ c->func(p[0], p[1], c->userdata);
918
1099
  }
919
1100
  }
920
-
921
- ca_sweep_release(&state);
922
-
923
- return rcx0;
1101
+ return Qnil;
924
1102
  }
925
1103
 
926
1104
  VALUE
@@ -934,13 +1112,14 @@ ca_call_cfunc_2_r (void (*func)(void *p0, void *p1, void *userdata), const char
934
1112
  char *owned_buf[2];
935
1113
  int attached[2];
936
1114
  ca_sweep_state_t state;
937
- int k_op;
1115
+ ca_call_cfunc_2_r_ctx_t ctx;
938
1116
 
939
1117
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
940
1118
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
941
1119
 
942
- /* sweep engine: same lifecycle as ca_call_cfunc_2; the difference is
943
- the per-cell `func(...)` call has `userdata` as its last argument. */
1120
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1121
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1122
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
944
1123
  state.n_ops = 2;
945
1124
  state.fsync = fsync;
946
1125
  state.cx = cx;
@@ -953,31 +1132,46 @@ ca_call_cfunc_2_r (void (*func)(void *p0, void *p1, void *userdata), const char
953
1132
 
954
1133
  ca_sweep_acquire(&state);
955
1134
 
956
- {
957
- char *p[2];
958
- ca_size_t k;
959
- if ( state.m0 ) {
960
- for ( k = 0; k < state.n_kernel; k++ ) {
961
- if ( ! state.m0[k] ) {
962
- for ( k_op = 0; k_op < 2; k_op++ ) {
963
- p[k_op] = base[k_op] + k * stride[k_op];
964
- }
965
- func(p[0], p[1], userdata);
1135
+ ctx.st = &state;
1136
+ ctx.func = func;
1137
+ ctx.userdata = userdata;
1138
+ ca_sweep_run(&state, ca_call_cfunc_2_r_walk, (VALUE) &ctx);
1139
+
1140
+ return rcx0;
1141
+ }
1142
+
1143
+ typedef struct {
1144
+ ca_sweep_state_t *st;
1145
+ void (*func)(void *p0, void *p1, void *p2, void *userdata);
1146
+ void *userdata;
1147
+ } ca_call_cfunc_3_r_ctx_t;
1148
+
1149
+ static VALUE
1150
+ ca_call_cfunc_3_r_walk (VALUE arg)
1151
+ {
1152
+ ca_call_cfunc_3_r_ctx_t *c = (ca_call_cfunc_3_r_ctx_t *) arg;
1153
+ ca_sweep_state_t *st = c->st;
1154
+ char *p[3];
1155
+ ca_size_t k;
1156
+ int k_op;
1157
+ if ( st->m0 ) {
1158
+ for ( k = 0; k < st->n_kernel; k++ ) {
1159
+ if ( ! st->m0[k] ) {
1160
+ for ( k_op = 0; k_op < 3; k_op++ ) {
1161
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
966
1162
  }
1163
+ c->func(p[0], p[1], p[2], c->userdata);
967
1164
  }
968
- } else {
969
- for ( k = 0; k < state.n_kernel; k++ ) {
970
- for ( k_op = 0; k_op < 2; k_op++ ) {
971
- p[k_op] = base[k_op] + k * stride[k_op];
972
- }
973
- func(p[0], p[1], userdata);
1165
+ }
1166
+ } else {
1167
+ for ( k = 0; k < st->n_kernel; k++ ) {
1168
+ for ( k_op = 0; k_op < 3; k_op++ ) {
1169
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
974
1170
  }
1171
+ c->func(p[0], p[1], p[2], c->userdata);
975
1172
  }
976
1173
  }
977
-
978
- ca_sweep_release(&state);
979
-
980
- return rcx0;
1174
+ return Qnil;
981
1175
  }
982
1176
 
983
1177
  VALUE
@@ -991,14 +1185,15 @@ ca_call_cfunc_3_r (void (*func)(void *p0, void *p1, void *p2, void *userdata), c
991
1185
  char *owned_buf[3];
992
1186
  int attached[3];
993
1187
  ca_sweep_state_t state;
994
- int k_op;
1188
+ ca_call_cfunc_3_r_ctx_t ctx;
995
1189
 
996
1190
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
997
1191
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
998
1192
  TypedData_Get_Struct(rcx2, CArray, &carray_data_type, cx[2]);
999
1193
 
1000
- /* sweep engine: same lifecycle as ca_call_cfunc_3; the difference is
1001
- the per-cell `func(...)` call has `userdata` as its last argument. */
1194
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1195
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1196
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
1002
1197
  state.n_ops = 3;
1003
1198
  state.fsync = fsync;
1004
1199
  state.cx = cx;
@@ -1011,31 +1206,46 @@ ca_call_cfunc_3_r (void (*func)(void *p0, void *p1, void *p2, void *userdata), c
1011
1206
 
1012
1207
  ca_sweep_acquire(&state);
1013
1208
 
1014
- {
1015
- char *p[3];
1016
- ca_size_t k;
1017
- if ( state.m0 ) {
1018
- for ( k = 0; k < state.n_kernel; k++ ) {
1019
- if ( ! state.m0[k] ) {
1020
- for ( k_op = 0; k_op < 3; k_op++ ) {
1021
- p[k_op] = base[k_op] + k * stride[k_op];
1022
- }
1023
- func(p[0], p[1], p[2], userdata);
1209
+ ctx.st = &state;
1210
+ ctx.func = func;
1211
+ ctx.userdata = userdata;
1212
+ ca_sweep_run(&state, ca_call_cfunc_3_r_walk, (VALUE) &ctx);
1213
+
1214
+ return rcx0;
1215
+ }
1216
+
1217
+ typedef struct {
1218
+ ca_sweep_state_t *st;
1219
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *userdata);
1220
+ void *userdata;
1221
+ } ca_call_cfunc_4_r_ctx_t;
1222
+
1223
+ static VALUE
1224
+ ca_call_cfunc_4_r_walk (VALUE arg)
1225
+ {
1226
+ ca_call_cfunc_4_r_ctx_t *c = (ca_call_cfunc_4_r_ctx_t *) arg;
1227
+ ca_sweep_state_t *st = c->st;
1228
+ char *p[4];
1229
+ ca_size_t k;
1230
+ int k_op;
1231
+ if ( st->m0 ) {
1232
+ for ( k = 0; k < st->n_kernel; k++ ) {
1233
+ if ( ! st->m0[k] ) {
1234
+ for ( k_op = 0; k_op < 4; k_op++ ) {
1235
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1024
1236
  }
1237
+ c->func(p[0], p[1], p[2], p[3], c->userdata);
1025
1238
  }
1026
- } else {
1027
- for ( k = 0; k < state.n_kernel; k++ ) {
1028
- for ( k_op = 0; k_op < 3; k_op++ ) {
1029
- p[k_op] = base[k_op] + k * stride[k_op];
1030
- }
1031
- func(p[0], p[1], p[2], userdata);
1239
+ }
1240
+ } else {
1241
+ for ( k = 0; k < st->n_kernel; k++ ) {
1242
+ for ( k_op = 0; k_op < 4; k_op++ ) {
1243
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1032
1244
  }
1245
+ c->func(p[0], p[1], p[2], p[3], c->userdata);
1033
1246
  }
1034
1247
  }
1035
-
1036
- ca_sweep_release(&state);
1037
-
1038
- return rcx0;
1248
+ return Qnil;
1039
1249
  }
1040
1250
 
1041
1251
  VALUE
@@ -1049,15 +1259,16 @@ ca_call_cfunc_4_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *us
1049
1259
  char *owned_buf[4];
1050
1260
  int attached[4];
1051
1261
  ca_sweep_state_t state;
1052
- int k_op;
1262
+ ca_call_cfunc_4_r_ctx_t ctx;
1053
1263
 
1054
1264
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1055
1265
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
1056
1266
  TypedData_Get_Struct(rcx2, CArray, &carray_data_type, cx[2]);
1057
1267
  TypedData_Get_Struct(rcx3, CArray, &carray_data_type, cx[3]);
1058
1268
 
1059
- /* sweep engine: same lifecycle as ca_call_cfunc_4; the difference is
1060
- the per-cell `func(...)` call has `userdata` as its last argument. */
1269
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1270
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1271
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
1061
1272
  state.n_ops = 4;
1062
1273
  state.fsync = fsync;
1063
1274
  state.cx = cx;
@@ -1070,31 +1281,46 @@ ca_call_cfunc_4_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *us
1070
1281
 
1071
1282
  ca_sweep_acquire(&state);
1072
1283
 
1073
- {
1074
- char *p[4];
1075
- ca_size_t k;
1076
- if ( state.m0 ) {
1077
- for ( k = 0; k < state.n_kernel; k++ ) {
1078
- if ( ! state.m0[k] ) {
1079
- for ( k_op = 0; k_op < 4; k_op++ ) {
1080
- p[k_op] = base[k_op] + k * stride[k_op];
1081
- }
1082
- func(p[0], p[1], p[2], p[3], userdata);
1284
+ ctx.st = &state;
1285
+ ctx.func = func;
1286
+ ctx.userdata = userdata;
1287
+ ca_sweep_run(&state, ca_call_cfunc_4_r_walk, (VALUE) &ctx);
1288
+
1289
+ return rcx0;
1290
+ }
1291
+
1292
+ typedef struct {
1293
+ ca_sweep_state_t *st;
1294
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4, void *userdata);
1295
+ void *userdata;
1296
+ } ca_call_cfunc_5_r_ctx_t;
1297
+
1298
+ static VALUE
1299
+ ca_call_cfunc_5_r_walk (VALUE arg)
1300
+ {
1301
+ ca_call_cfunc_5_r_ctx_t *c = (ca_call_cfunc_5_r_ctx_t *) arg;
1302
+ ca_sweep_state_t *st = c->st;
1303
+ char *p[5];
1304
+ ca_size_t k;
1305
+ int k_op;
1306
+ if ( st->m0 ) {
1307
+ for ( k = 0; k < st->n_kernel; k++ ) {
1308
+ if ( ! st->m0[k] ) {
1309
+ for ( k_op = 0; k_op < 5; k_op++ ) {
1310
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1083
1311
  }
1312
+ c->func(p[0], p[1], p[2], p[3], p[4], c->userdata);
1084
1313
  }
1085
- } else {
1086
- for ( k = 0; k < state.n_kernel; k++ ) {
1087
- for ( k_op = 0; k_op < 4; k_op++ ) {
1088
- p[k_op] = base[k_op] + k * stride[k_op];
1089
- }
1090
- func(p[0], p[1], p[2], p[3], userdata);
1314
+ }
1315
+ } else {
1316
+ for ( k = 0; k < st->n_kernel; k++ ) {
1317
+ for ( k_op = 0; k_op < 5; k_op++ ) {
1318
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1091
1319
  }
1320
+ c->func(p[0], p[1], p[2], p[3], p[4], c->userdata);
1092
1321
  }
1093
1322
  }
1094
-
1095
- ca_sweep_release(&state);
1096
-
1097
- return rcx0;
1323
+ return Qnil;
1098
1324
  }
1099
1325
 
1100
1326
  VALUE
@@ -1108,7 +1334,7 @@ ca_call_cfunc_5_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1108
1334
  char *owned_buf[5];
1109
1335
  int attached[5];
1110
1336
  ca_sweep_state_t state;
1111
- int k_op;
1337
+ ca_call_cfunc_5_r_ctx_t ctx;
1112
1338
 
1113
1339
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1114
1340
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1116,8 +1342,9 @@ ca_call_cfunc_5_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1116
1342
  TypedData_Get_Struct(rcx3, CArray, &carray_data_type, cx[3]);
1117
1343
  TypedData_Get_Struct(rcx4, CArray, &carray_data_type, cx[4]);
1118
1344
 
1119
- /* sweep engine: same lifecycle as ca_call_cfunc_5; the difference is
1120
- the per-cell `func(...)` call has `userdata` as its last argument. */
1345
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1346
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1347
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
1121
1348
  state.n_ops = 5;
1122
1349
  state.fsync = fsync;
1123
1350
  state.cx = cx;
@@ -1130,31 +1357,46 @@ ca_call_cfunc_5_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1130
1357
 
1131
1358
  ca_sweep_acquire(&state);
1132
1359
 
1133
- {
1134
- char *p[5];
1135
- ca_size_t k;
1136
- if ( state.m0 ) {
1137
- for ( k = 0; k < state.n_kernel; k++ ) {
1138
- if ( ! state.m0[k] ) {
1139
- for ( k_op = 0; k_op < 5; k_op++ ) {
1140
- p[k_op] = base[k_op] + k * stride[k_op];
1141
- }
1142
- func(p[0], p[1], p[2], p[3], p[4], userdata);
1360
+ ctx.st = &state;
1361
+ ctx.func = func;
1362
+ ctx.userdata = userdata;
1363
+ ca_sweep_run(&state, ca_call_cfunc_5_r_walk, (VALUE) &ctx);
1364
+
1365
+ return rcx0;
1366
+ }
1367
+
1368
+ typedef struct {
1369
+ ca_sweep_state_t *st;
1370
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4, void *p5, void *userdata);
1371
+ void *userdata;
1372
+ } ca_call_cfunc_6_r_ctx_t;
1373
+
1374
+ static VALUE
1375
+ ca_call_cfunc_6_r_walk (VALUE arg)
1376
+ {
1377
+ ca_call_cfunc_6_r_ctx_t *c = (ca_call_cfunc_6_r_ctx_t *) arg;
1378
+ ca_sweep_state_t *st = c->st;
1379
+ char *p[6];
1380
+ ca_size_t k;
1381
+ int k_op;
1382
+ if ( st->m0 ) {
1383
+ for ( k = 0; k < st->n_kernel; k++ ) {
1384
+ if ( ! st->m0[k] ) {
1385
+ for ( k_op = 0; k_op < 6; k_op++ ) {
1386
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1143
1387
  }
1388
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5], c->userdata);
1144
1389
  }
1145
- } else {
1146
- for ( k = 0; k < state.n_kernel; k++ ) {
1147
- for ( k_op = 0; k_op < 5; k_op++ ) {
1148
- p[k_op] = base[k_op] + k * stride[k_op];
1149
- }
1150
- func(p[0], p[1], p[2], p[3], p[4], userdata);
1390
+ }
1391
+ } else {
1392
+ for ( k = 0; k < st->n_kernel; k++ ) {
1393
+ for ( k_op = 0; k_op < 6; k_op++ ) {
1394
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1151
1395
  }
1396
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5], c->userdata);
1152
1397
  }
1153
1398
  }
1154
-
1155
- ca_sweep_release(&state);
1156
-
1157
- return rcx0;
1399
+ return Qnil;
1158
1400
  }
1159
1401
 
1160
1402
  VALUE
@@ -1168,7 +1410,7 @@ ca_call_cfunc_6_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1168
1410
  char *owned_buf[6];
1169
1411
  int attached[6];
1170
1412
  ca_sweep_state_t state;
1171
- int k_op;
1413
+ ca_call_cfunc_6_r_ctx_t ctx;
1172
1414
 
1173
1415
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1174
1416
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1177,8 +1419,9 @@ ca_call_cfunc_6_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1177
1419
  TypedData_Get_Struct(rcx4, CArray, &carray_data_type, cx[4]);
1178
1420
  TypedData_Get_Struct(rcx5, CArray, &carray_data_type, cx[5]);
1179
1421
 
1180
- /* sweep engine: same lifecycle as ca_call_cfunc_6; the difference is
1181
- the per-cell `func(...)` call has `userdata` as its last argument. */
1422
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1423
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1424
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
1182
1425
  state.n_ops = 6;
1183
1426
  state.fsync = fsync;
1184
1427
  state.cx = cx;
@@ -1191,31 +1434,46 @@ ca_call_cfunc_6_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1191
1434
 
1192
1435
  ca_sweep_acquire(&state);
1193
1436
 
1194
- {
1195
- char *p[6];
1196
- ca_size_t k;
1197
- if ( state.m0 ) {
1198
- for ( k = 0; k < state.n_kernel; k++ ) {
1199
- if ( ! state.m0[k] ) {
1200
- for ( k_op = 0; k_op < 6; k_op++ ) {
1201
- p[k_op] = base[k_op] + k * stride[k_op];
1202
- }
1203
- func(p[0], p[1], p[2], p[3], p[4], p[5], userdata);
1437
+ ctx.st = &state;
1438
+ ctx.func = func;
1439
+ ctx.userdata = userdata;
1440
+ ca_sweep_run(&state, ca_call_cfunc_6_r_walk, (VALUE) &ctx);
1441
+
1442
+ return rcx0;
1443
+ }
1444
+
1445
+ typedef struct {
1446
+ ca_sweep_state_t *st;
1447
+ void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4, void *p5, void *p6, void *userdata);
1448
+ void *userdata;
1449
+ } ca_call_cfunc_7_r_ctx_t;
1450
+
1451
+ static VALUE
1452
+ ca_call_cfunc_7_r_walk (VALUE arg)
1453
+ {
1454
+ ca_call_cfunc_7_r_ctx_t *c = (ca_call_cfunc_7_r_ctx_t *) arg;
1455
+ ca_sweep_state_t *st = c->st;
1456
+ char *p[7];
1457
+ ca_size_t k;
1458
+ int k_op;
1459
+ if ( st->m0 ) {
1460
+ for ( k = 0; k < st->n_kernel; k++ ) {
1461
+ if ( ! st->m0[k] ) {
1462
+ for ( k_op = 0; k_op < 7; k_op++ ) {
1463
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1204
1464
  }
1465
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], c->userdata);
1205
1466
  }
1206
- } else {
1207
- for ( k = 0; k < state.n_kernel; k++ ) {
1208
- for ( k_op = 0; k_op < 6; k_op++ ) {
1209
- p[k_op] = base[k_op] + k * stride[k_op];
1210
- }
1211
- func(p[0], p[1], p[2], p[3], p[4], p[5], userdata);
1467
+ }
1468
+ } else {
1469
+ for ( k = 0; k < st->n_kernel; k++ ) {
1470
+ for ( k_op = 0; k_op < 7; k_op++ ) {
1471
+ p[k_op] = st->base[k_op] + k * st->stride[k_op];
1212
1472
  }
1473
+ c->func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], c->userdata);
1213
1474
  }
1214
1475
  }
1215
-
1216
- ca_sweep_release(&state);
1217
-
1218
- return rcx0;
1476
+ return Qnil;
1219
1477
  }
1220
1478
 
1221
1479
  VALUE
@@ -1229,7 +1487,7 @@ ca_call_cfunc_7_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1229
1487
  char *owned_buf[7];
1230
1488
  int attached[7];
1231
1489
  ca_sweep_state_t state;
1232
- int k_op;
1490
+ ca_call_cfunc_7_r_ctx_t ctx;
1233
1491
 
1234
1492
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1235
1493
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1239,8 +1497,9 @@ ca_call_cfunc_7_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1239
1497
  TypedData_Get_Struct(rcx5, CArray, &carray_data_type, cx[5]);
1240
1498
  TypedData_Get_Struct(rcx6, CArray, &carray_data_type, cx[6]);
1241
1499
 
1242
- /* sweep engine: same lifecycle as ca_call_cfunc_7; the difference is
1243
- the per-cell `func(...)` call has `userdata` as its last argument. */
1500
+ /* sweep engine: per-operand acquire (alias / xmalloc + ca_xfer_all),
1501
+ operand pairing, mask OR across INPUTs, mask propagate to OUTPUTs.
1502
+ Lifecycle template lives in ext/ca_sweep_engine.{c,h}. */
1244
1503
  state.n_ops = 7;
1245
1504
  state.fsync = fsync;
1246
1505
  state.cx = cx;
@@ -1253,29 +1512,10 @@ ca_call_cfunc_7_r (void (*func)(void *p0, void *p1, void *p2, void *p3, void *p4
1253
1512
 
1254
1513
  ca_sweep_acquire(&state);
1255
1514
 
1256
- {
1257
- char *p[7];
1258
- ca_size_t k;
1259
- if ( state.m0 ) {
1260
- for ( k = 0; k < state.n_kernel; k++ ) {
1261
- if ( ! state.m0[k] ) {
1262
- for ( k_op = 0; k_op < 7; k_op++ ) {
1263
- p[k_op] = base[k_op] + k * stride[k_op];
1264
- }
1265
- func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], userdata);
1266
- }
1267
- }
1268
- } else {
1269
- for ( k = 0; k < state.n_kernel; k++ ) {
1270
- for ( k_op = 0; k_op < 7; k_op++ ) {
1271
- p[k_op] = base[k_op] + k * stride[k_op];
1272
- }
1273
- func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], userdata);
1274
- }
1275
- }
1276
- }
1277
-
1278
- ca_sweep_release(&state);
1515
+ ctx.st = &state;
1516
+ ctx.func = func;
1517
+ ctx.userdata = userdata;
1518
+ ca_sweep_run(&state, ca_call_cfunc_7_r_walk, (VALUE) &ctx);
1279
1519
 
1280
1520
  return rcx0;
1281
1521
  }
@@ -1676,6 +1916,7 @@ ca_call_cslab_1 (ca_cslab_t func, const char *fsync,
1676
1916
  char *owned_buf[1];
1677
1917
  int attached[1];
1678
1918
  ca_sweep_state_t state;
1919
+ ca_cslab_ctx_t ctx;
1679
1920
 
1680
1921
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1681
1922
 
@@ -1698,16 +1939,11 @@ ca_call_cslab_1 (ca_cslab_t func, const char *fsync,
1698
1939
 
1699
1940
  ca_sweep_acquire_chunked(&state);
1700
1941
 
1701
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
1702
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
1703
- at the arena scratch the chunk was just gathered into, which is
1704
- packed, so stride[] is the element size and the author's inner loop
1705
- sees contiguous data. */
1706
- while ( ca_sweep_next_chunk(&state) ) {
1707
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
1708
- }
1709
-
1710
- ca_sweep_release_chunked(&state);
1942
+ ctx.st = &state;
1943
+ ctx.func = func;
1944
+ ctx.func_r = NULL;
1945
+ ctx.userdata = NULL;
1946
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
1711
1947
 
1712
1948
  return rcx0;
1713
1949
  }
@@ -1723,6 +1959,7 @@ ca_call_cslab_2 (ca_cslab_t func, const char *fsync,
1723
1959
  char *owned_buf[2];
1724
1960
  int attached[2];
1725
1961
  ca_sweep_state_t state;
1962
+ ca_cslab_ctx_t ctx;
1726
1963
 
1727
1964
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1728
1965
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1746,16 +1983,11 @@ ca_call_cslab_2 (ca_cslab_t func, const char *fsync,
1746
1983
 
1747
1984
  ca_sweep_acquire_chunked(&state);
1748
1985
 
1749
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
1750
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
1751
- at the arena scratch the chunk was just gathered into, which is
1752
- packed, so stride[] is the element size and the author's inner loop
1753
- sees contiguous data. */
1754
- while ( ca_sweep_next_chunk(&state) ) {
1755
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
1756
- }
1757
-
1758
- ca_sweep_release_chunked(&state);
1986
+ ctx.st = &state;
1987
+ ctx.func = func;
1988
+ ctx.func_r = NULL;
1989
+ ctx.userdata = NULL;
1990
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
1759
1991
 
1760
1992
  return rcx0;
1761
1993
  }
@@ -1771,6 +2003,7 @@ ca_call_cslab_3 (ca_cslab_t func, const char *fsync,
1771
2003
  char *owned_buf[3];
1772
2004
  int attached[3];
1773
2005
  ca_sweep_state_t state;
2006
+ ca_cslab_ctx_t ctx;
1774
2007
 
1775
2008
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1776
2009
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1795,16 +2028,11 @@ ca_call_cslab_3 (ca_cslab_t func, const char *fsync,
1795
2028
 
1796
2029
  ca_sweep_acquire_chunked(&state);
1797
2030
 
1798
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
1799
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
1800
- at the arena scratch the chunk was just gathered into, which is
1801
- packed, so stride[] is the element size and the author's inner loop
1802
- sees contiguous data. */
1803
- while ( ca_sweep_next_chunk(&state) ) {
1804
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
1805
- }
1806
-
1807
- ca_sweep_release_chunked(&state);
2031
+ ctx.st = &state;
2032
+ ctx.func = func;
2033
+ ctx.func_r = NULL;
2034
+ ctx.userdata = NULL;
2035
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
1808
2036
 
1809
2037
  return rcx0;
1810
2038
  }
@@ -1820,6 +2048,7 @@ ca_call_cslab_4 (ca_cslab_t func, const char *fsync,
1820
2048
  char *owned_buf[4];
1821
2049
  int attached[4];
1822
2050
  ca_sweep_state_t state;
2051
+ ca_cslab_ctx_t ctx;
1823
2052
 
1824
2053
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1825
2054
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1845,16 +2074,11 @@ ca_call_cslab_4 (ca_cslab_t func, const char *fsync,
1845
2074
 
1846
2075
  ca_sweep_acquire_chunked(&state);
1847
2076
 
1848
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
1849
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
1850
- at the arena scratch the chunk was just gathered into, which is
1851
- packed, so stride[] is the element size and the author's inner loop
1852
- sees contiguous data. */
1853
- while ( ca_sweep_next_chunk(&state) ) {
1854
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
1855
- }
1856
-
1857
- ca_sweep_release_chunked(&state);
2077
+ ctx.st = &state;
2078
+ ctx.func = func;
2079
+ ctx.func_r = NULL;
2080
+ ctx.userdata = NULL;
2081
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
1858
2082
 
1859
2083
  return rcx0;
1860
2084
  }
@@ -1870,6 +2094,7 @@ ca_call_cslab_5 (ca_cslab_t func, const char *fsync,
1870
2094
  char *owned_buf[5];
1871
2095
  int attached[5];
1872
2096
  ca_sweep_state_t state;
2097
+ ca_cslab_ctx_t ctx;
1873
2098
 
1874
2099
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1875
2100
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1896,16 +2121,11 @@ ca_call_cslab_5 (ca_cslab_t func, const char *fsync,
1896
2121
 
1897
2122
  ca_sweep_acquire_chunked(&state);
1898
2123
 
1899
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
1900
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
1901
- at the arena scratch the chunk was just gathered into, which is
1902
- packed, so stride[] is the element size and the author's inner loop
1903
- sees contiguous data. */
1904
- while ( ca_sweep_next_chunk(&state) ) {
1905
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
1906
- }
1907
-
1908
- ca_sweep_release_chunked(&state);
2124
+ ctx.st = &state;
2125
+ ctx.func = func;
2126
+ ctx.func_r = NULL;
2127
+ ctx.userdata = NULL;
2128
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
1909
2129
 
1910
2130
  return rcx0;
1911
2131
  }
@@ -1921,6 +2141,7 @@ ca_call_cslab_6 (ca_cslab_t func, const char *fsync,
1921
2141
  char *owned_buf[6];
1922
2142
  int attached[6];
1923
2143
  ca_sweep_state_t state;
2144
+ ca_cslab_ctx_t ctx;
1924
2145
 
1925
2146
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1926
2147
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -1948,16 +2169,11 @@ ca_call_cslab_6 (ca_cslab_t func, const char *fsync,
1948
2169
 
1949
2170
  ca_sweep_acquire_chunked(&state);
1950
2171
 
1951
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
1952
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
1953
- at the arena scratch the chunk was just gathered into, which is
1954
- packed, so stride[] is the element size and the author's inner loop
1955
- sees contiguous data. */
1956
- while ( ca_sweep_next_chunk(&state) ) {
1957
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
1958
- }
1959
-
1960
- ca_sweep_release_chunked(&state);
2172
+ ctx.st = &state;
2173
+ ctx.func = func;
2174
+ ctx.func_r = NULL;
2175
+ ctx.userdata = NULL;
2176
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
1961
2177
 
1962
2178
  return rcx0;
1963
2179
  }
@@ -1973,6 +2189,7 @@ ca_call_cslab_7 (ca_cslab_t func, const char *fsync,
1973
2189
  char *owned_buf[7];
1974
2190
  int attached[7];
1975
2191
  ca_sweep_state_t state;
2192
+ ca_cslab_ctx_t ctx;
1976
2193
 
1977
2194
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
1978
2195
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2001,16 +2218,11 @@ ca_call_cslab_7 (ca_cslab_t func, const char *fsync,
2001
2218
 
2002
2219
  ca_sweep_acquire_chunked(&state);
2003
2220
 
2004
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2005
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2006
- at the arena scratch the chunk was just gathered into, which is
2007
- packed, so stride[] is the element size and the author's inner loop
2008
- sees contiguous data. */
2009
- while ( ca_sweep_next_chunk(&state) ) {
2010
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state));
2011
- }
2012
-
2013
- ca_sweep_release_chunked(&state);
2221
+ ctx.st = &state;
2222
+ ctx.func = func;
2223
+ ctx.func_r = NULL;
2224
+ ctx.userdata = NULL;
2225
+ ca_sweep_run_chunked(&state, ca_cslab_walk, (VALUE) &ctx);
2014
2226
 
2015
2227
  return rcx0;
2016
2228
  }
@@ -2027,6 +2239,7 @@ ca_call_cslab_1_r (ca_cslab_r_t func, const char *fsync,
2027
2239
  char *owned_buf[1];
2028
2240
  int attached[1];
2029
2241
  ca_sweep_state_t state;
2242
+ ca_cslab_ctx_t ctx;
2030
2243
 
2031
2244
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2032
2245
 
@@ -2049,16 +2262,11 @@ ca_call_cslab_1_r (ca_cslab_r_t func, const char *fsync,
2049
2262
 
2050
2263
  ca_sweep_acquire_chunked(&state);
2051
2264
 
2052
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2053
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2054
- at the arena scratch the chunk was just gathered into, which is
2055
- packed, so stride[] is the element size and the author's inner loop
2056
- sees contiguous data. */
2057
- while ( ca_sweep_next_chunk(&state) ) {
2058
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2059
- }
2060
-
2061
- ca_sweep_release_chunked(&state);
2265
+ ctx.st = &state;
2266
+ ctx.func = NULL;
2267
+ ctx.func_r = func;
2268
+ ctx.userdata = userdata;
2269
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2062
2270
 
2063
2271
  return rcx0;
2064
2272
  }
@@ -2075,6 +2283,7 @@ ca_call_cslab_2_r (ca_cslab_r_t func, const char *fsync,
2075
2283
  char *owned_buf[2];
2076
2284
  int attached[2];
2077
2285
  ca_sweep_state_t state;
2286
+ ca_cslab_ctx_t ctx;
2078
2287
 
2079
2288
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2080
2289
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2098,16 +2307,11 @@ ca_call_cslab_2_r (ca_cslab_r_t func, const char *fsync,
2098
2307
 
2099
2308
  ca_sweep_acquire_chunked(&state);
2100
2309
 
2101
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2102
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2103
- at the arena scratch the chunk was just gathered into, which is
2104
- packed, so stride[] is the element size and the author's inner loop
2105
- sees contiguous data. */
2106
- while ( ca_sweep_next_chunk(&state) ) {
2107
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2108
- }
2109
-
2110
- ca_sweep_release_chunked(&state);
2310
+ ctx.st = &state;
2311
+ ctx.func = NULL;
2312
+ ctx.func_r = func;
2313
+ ctx.userdata = userdata;
2314
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2111
2315
 
2112
2316
  return rcx0;
2113
2317
  }
@@ -2124,6 +2328,7 @@ ca_call_cslab_3_r (ca_cslab_r_t func, const char *fsync,
2124
2328
  char *owned_buf[3];
2125
2329
  int attached[3];
2126
2330
  ca_sweep_state_t state;
2331
+ ca_cslab_ctx_t ctx;
2127
2332
 
2128
2333
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2129
2334
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2148,16 +2353,11 @@ ca_call_cslab_3_r (ca_cslab_r_t func, const char *fsync,
2148
2353
 
2149
2354
  ca_sweep_acquire_chunked(&state);
2150
2355
 
2151
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2152
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2153
- at the arena scratch the chunk was just gathered into, which is
2154
- packed, so stride[] is the element size and the author's inner loop
2155
- sees contiguous data. */
2156
- while ( ca_sweep_next_chunk(&state) ) {
2157
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2158
- }
2159
-
2160
- ca_sweep_release_chunked(&state);
2356
+ ctx.st = &state;
2357
+ ctx.func = NULL;
2358
+ ctx.func_r = func;
2359
+ ctx.userdata = userdata;
2360
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2161
2361
 
2162
2362
  return rcx0;
2163
2363
  }
@@ -2174,6 +2374,7 @@ ca_call_cslab_4_r (ca_cslab_r_t func, const char *fsync,
2174
2374
  char *owned_buf[4];
2175
2375
  int attached[4];
2176
2376
  ca_sweep_state_t state;
2377
+ ca_cslab_ctx_t ctx;
2177
2378
 
2178
2379
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2179
2380
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2199,16 +2400,11 @@ ca_call_cslab_4_r (ca_cslab_r_t func, const char *fsync,
2199
2400
 
2200
2401
  ca_sweep_acquire_chunked(&state);
2201
2402
 
2202
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2203
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2204
- at the arena scratch the chunk was just gathered into, which is
2205
- packed, so stride[] is the element size and the author's inner loop
2206
- sees contiguous data. */
2207
- while ( ca_sweep_next_chunk(&state) ) {
2208
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2209
- }
2210
-
2211
- ca_sweep_release_chunked(&state);
2403
+ ctx.st = &state;
2404
+ ctx.func = NULL;
2405
+ ctx.func_r = func;
2406
+ ctx.userdata = userdata;
2407
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2212
2408
 
2213
2409
  return rcx0;
2214
2410
  }
@@ -2225,6 +2421,7 @@ ca_call_cslab_5_r (ca_cslab_r_t func, const char *fsync,
2225
2421
  char *owned_buf[5];
2226
2422
  int attached[5];
2227
2423
  ca_sweep_state_t state;
2424
+ ca_cslab_ctx_t ctx;
2228
2425
 
2229
2426
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2230
2427
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2251,16 +2448,11 @@ ca_call_cslab_5_r (ca_cslab_r_t func, const char *fsync,
2251
2448
 
2252
2449
  ca_sweep_acquire_chunked(&state);
2253
2450
 
2254
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2255
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2256
- at the arena scratch the chunk was just gathered into, which is
2257
- packed, so stride[] is the element size and the author's inner loop
2258
- sees contiguous data. */
2259
- while ( ca_sweep_next_chunk(&state) ) {
2260
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2261
- }
2262
-
2263
- ca_sweep_release_chunked(&state);
2451
+ ctx.st = &state;
2452
+ ctx.func = NULL;
2453
+ ctx.func_r = func;
2454
+ ctx.userdata = userdata;
2455
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2264
2456
 
2265
2457
  return rcx0;
2266
2458
  }
@@ -2277,6 +2469,7 @@ ca_call_cslab_6_r (ca_cslab_r_t func, const char *fsync,
2277
2469
  char *owned_buf[6];
2278
2470
  int attached[6];
2279
2471
  ca_sweep_state_t state;
2472
+ ca_cslab_ctx_t ctx;
2280
2473
 
2281
2474
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2282
2475
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2304,16 +2497,11 @@ ca_call_cslab_6_r (ca_cslab_r_t func, const char *fsync,
2304
2497
 
2305
2498
  ca_sweep_acquire_chunked(&state);
2306
2499
 
2307
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2308
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2309
- at the arena scratch the chunk was just gathered into, which is
2310
- packed, so stride[] is the element size and the author's inner loop
2311
- sees contiguous data. */
2312
- while ( ca_sweep_next_chunk(&state) ) {
2313
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2314
- }
2315
-
2316
- ca_sweep_release_chunked(&state);
2500
+ ctx.st = &state;
2501
+ ctx.func = NULL;
2502
+ ctx.func_r = func;
2503
+ ctx.userdata = userdata;
2504
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2317
2505
 
2318
2506
  return rcx0;
2319
2507
  }
@@ -2330,6 +2518,7 @@ ca_call_cslab_7_r (ca_cslab_r_t func, const char *fsync,
2330
2518
  char *owned_buf[7];
2331
2519
  int attached[7];
2332
2520
  ca_sweep_state_t state;
2521
+ ca_cslab_ctx_t ctx;
2333
2522
 
2334
2523
  TypedData_Get_Struct(rcx0, CArray, &carray_data_type, cx[0]);
2335
2524
  TypedData_Get_Struct(rcx1, CArray, &carray_data_type, cx[1]);
@@ -2358,16 +2547,11 @@ ca_call_cslab_7_r (ca_cslab_r_t func, const char *fsync,
2358
2547
 
2359
2548
  ca_sweep_acquire_chunked(&state);
2360
2549
 
2361
- /* outer loop: hand the author one chunk at a time. base[] is rewritten
2362
- per chunk by ca_sweep_next_chunk -- for a non-alias INPUT it points
2363
- at the arena scratch the chunk was just gathered into, which is
2364
- packed, so stride[] is the element size and the author's inner loop
2365
- sees contiguous data. */
2366
- while ( ca_sweep_next_chunk(&state) ) {
2367
- func(base, stride, state.chunk_n, ca_sweep_chunk_mask(&state), userdata);
2368
- }
2369
-
2370
- ca_sweep_release_chunked(&state);
2550
+ ctx.st = &state;
2551
+ ctx.func = NULL;
2552
+ ctx.func_r = func;
2553
+ ctx.userdata = userdata;
2554
+ ca_sweep_run_chunked(&state, ca_cslab_r_walk, (VALUE) &ctx);
2371
2555
 
2372
2556
  return rcx0;
2373
2557
  }