carray 3.0.2 → 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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
@@ -25,6 +25,15 @@
25
25
  #define CARRAY_INTERNAL_H
26
26
 
27
27
  #include "carray.h"
28
+ #include <math.h> /* isnan, for CA_OBJ_ISNAN */
29
+
30
+ /* ---- properties a copy or a folded view must carry (ca_obj_refer.c) -------
31
+
32
+ Copies VALUE_ARRAY (dropping any mask), READ_ONLY and MASK_ARRAY from
33
+ `src` onto `view` when `src` has them, for arrays whose C parent chain
34
+ does not pass through `src`. Used by the folded reshape / flatten and by
35
+ CArray#initialize_dup / #initialize_clone. */
36
+ void ca_keep_chain_flags (CArray *view, CArray *src);
28
37
 
29
38
  /* ---- bulk bit pack / unpack (ca_obj_bitarray.c) --------------------------
30
39
 
@@ -54,13 +63,20 @@ void ca_bit_pack (const boolean8_t *src, ca_size_t elements, ca_size_t pbytes,
54
63
  The pool is global static state, so this is single-owner by construction.
55
64
  Thread-safety is a non-goal: operating on one array family from more than
56
65
  one thread is the caller's responsibility, not something this pool guards
57
- against. */
66
+ against.
67
+
68
+ A region that can raise -- one that transfers from a view, or calls Ruby
69
+ through an object lane -- goes through ca_lazy_arena_protect, never a
70
+ bare _enter / _exit pair: a skipped _exit is process-wide. */
58
71
 
59
72
  void ca_lazy_arena_enter (void);
60
73
  void ca_lazy_arena_exit (void);
61
74
  void *ca_lazy_arena_acquire (ca_size_t bytes);
62
75
  void *ca_lazy_arena_acquire_object (ca_size_t n_elements);
63
76
  void ca_lazy_arena_release (void *ptr);
77
+ VALUE ca_lazy_arena_protect (VALUE (*body)(VALUE),
78
+ VALUE (*cleanup)(VALUE), VALUE arg);
79
+ VALUE ca_lazy_arena_release_held (VALUE arg);
64
80
 
65
81
  /* ---- CA_OBJECT GC guard (carray_lazy.c) ----------------------------------
66
82
 
@@ -77,12 +93,103 @@ void ca_lazy_arena_release (void *ptr);
77
93
  int ca_gc_hold_push (void *ptr, ca_size_t n_elements);
78
94
  void ca_gc_hold_pop_to (int depth);
79
95
 
96
+ /* A buffer of object cells whose lifetime is not nested in the others' --
97
+ a kernel iterator's scratch lives from init to finish, and two walks
98
+ opened together may close in either order. Registered buffers are
99
+ marked until released, in any order; releasing one that was never
100
+ registered does nothing. The cells must be valid VALUEs when it is
101
+ registered. */
102
+ void ca_gc_hold_buffer (void *ptr, ca_size_t n_elements);
103
+ void ca_gc_release_buffer (void *ptr);
104
+
105
+ /* Object cells are marked strictly (rb_gc_mark, which trusts what it is
106
+ given) as soon as anything can see their buffer: a view's ca->ptr from
107
+ the moment it is set (ca_mark), a held buffer from the moment it is held.
108
+ A fresh buffer that will carry object cells is therefore filled with
109
+ valid VALUEs before it is published, whether or not the code that fills
110
+ it can call Ruby. A buffer for an array's cells is allocated with
111
+ ca_alloc_cells; other fresh VALUE buffers are cleared with
112
+ ca_object_cells_clear before they are held. utils/check_cell_buffers.rb
113
+ finds a ptr allocated any other way. */
114
+ static inline void
115
+ ca_object_cells_clear (void *ptr, ca_size_t n_elements)
116
+ {
117
+ VALUE *p = (VALUE *) ptr;
118
+ while ( n_elements-- > 0 ) {
119
+ *p++ = Qnil;
120
+ }
121
+ }
122
+
123
+ /* A boolean cell holds 0 or 1. Bytes copied in from outside (a String or
124
+ an IO through load_binary, a MemoryView) are read as true when non-zero,
125
+ so every reader of the array sees one value; an array that shares
126
+ another's bytes cannot be held to this, and is refused instead. */
127
+ static inline void
128
+ ca_boolean_normalize_bytes (void *ptr, ca_size_t n)
129
+ {
130
+ uint8_t *p = (uint8_t *) ptr;
131
+ for ( ca_size_t i = 0; i < n; i++ ) {
132
+ p[i] = ( p[i] != 0 );
133
+ }
134
+ }
135
+
136
+ static inline char *
137
+ ca_alloc_cells (const CArray *ca)
138
+ {
139
+ char *p = (char *) xmalloc(ca_length(ca));
140
+ if ( ca->data_type == CA_OBJECT ) {
141
+ ca_object_cells_clear(p, ca->elements);
142
+ }
143
+ return p;
144
+ }
145
+
146
+ /* Copy the attributes src shows onto dst (a new entity with src's values). */
147
+ void rb_ca_inherit_attr (VALUE dst, VALUE src);
148
+
149
+ /* Give a dup / clone its own attribute Hash. */
150
+ void rb_ca_own_attr (VALUE self);
151
+
152
+ /* Record the Face a lifted view was taken from, for the attribute walk. */
153
+ void rb_ca_set_lifted_from (VALUE lifted, VALUE face);
154
+
155
+ /* A String read as a decimal number of an integer or float data_type
156
+ (carray_cast.c): _to answers 1 / 0 (UNDEF), _store raises. */
157
+ int ca_decimal_string_to (VALUE str, int8_t data_type, void *out);
158
+ void ca_decimal_string_store (VALUE str, int8_t data_type, void *out);
159
+
160
+ /* Give `ca` a mask holding `m` (one byte per cell) when any cell is set,
161
+ and leave it without one otherwise. */
162
+ static inline void
163
+ ca_mask_from_bytes (CArray *ca, const boolean8_t *m)
164
+ {
165
+ ca_size_t i;
166
+ for (i = 0; i < ca->elements; i++) {
167
+ if ( m[i] ) {
168
+ ca_create_mask(ca);
169
+ memcpy(ca->mask->ptr, m, ca->elements);
170
+ return;
171
+ }
172
+ }
173
+ }
174
+
80
175
  /* ---- Attaching several parents (carray_core.c) ---------------------------
81
176
 
82
- Attach all of list[0..n-1] or none: if one attach raises, those already
83
- attached are detached before the raise propagates. */
177
+ ca_attach_all attaches all of list[0..n-1] or none: if one attach raises,
178
+ those already attached are detached before the raise propagates.
179
+
180
+ ca_sync_all syncs every one of list[0..n-1], carrying on past one that
181
+ raises so that the others still receive what was written, and raises
182
+ the first exception once all have been tried.
183
+
184
+ ca_attach_window opens list[0..n-1] ('r' attach, 'w' attach + sync,
185
+ 'a' allocate + sync), runs body(arg), and closes every array however body
186
+ leaves. Any window inside which Ruby runs or something raises goes
187
+ through it; see the definition for what a raise does to 'w' and 'a'. */
84
188
 
85
189
  void ca_attach_all (CArray **list, int32_t n);
190
+ void ca_sync_all (CArray **list, int32_t n);
191
+ VALUE ca_attach_window (int32_t n, CArray **list, const char *modes,
192
+ VALUE (*body)(VALUE), VALUE arg);
86
193
 
87
194
  /* ---- Filling a result Ruby does not own yet (carray_copy.c) ---------------
88
195
 
@@ -94,6 +201,42 @@ void ca_attach_all (CArray **list, int32_t n);
94
201
 
95
202
  void ca_fill_or_free (CArray *co, VALUE (*fill)(VALUE), VALUE arg);
96
203
 
204
+ /* The same for what else a step that can raise leaves behind: a buffer
205
+ that belongs to nothing yet (freed with xfree), or arrays the caller
206
+ attached for the step (each detached once). A hand-written rb_protect
207
+ outside the files that implement these parts says why it is not one
208
+ of them; utils/check_protect_parts.rb finds one that does not. */
209
+
210
+ void ca_fill_or_xfree (void *buf, VALUE (*fill)(VALUE), VALUE arg);
211
+ void ca_fill_or_detach (int n, CArray **list, VALUE (*fill)(VALUE), VALUE arg);
212
+
213
+ /* A view takes its parent's mask by asking the parent whether it has one,
214
+ and a parent that is a CAObject answers in Ruby and can raise. A view's
215
+ setup therefore does not ask: its constructor calls this under
216
+ ca_fill_or_free once the struct holds everything the setup allocated,
217
+ and an initialize_copy, whose struct Ruby already owns, calls it
218
+ directly. `view` is the CArray * cast to VALUE. */
219
+
220
+ VALUE ca_view_inherit_mask (VALUE view);
221
+
222
+ /* Whether a CAGrid has a hole: a position whose index cell was masked,
223
+ which selects no parent cell. The descriptor engine has no hole, so
224
+ such a grid is delivered through its own transfers. */
225
+ int ca_grid_has_holes (void *ap);
226
+
227
+ /* The same for the mask a CAWindow / CAShift with an axis of MASK bounds
228
+ makes for itself (ca_obj_window.c). */
229
+
230
+ VALUE ca_window_create_bounds_mask (VALUE view);
231
+
232
+ /* ca_stride_setup without asking the parent for its mask; see
233
+ ca_view_inherit_mask. The in-tree subclasses use this. */
234
+
235
+ int ca_stride_setup_view (CAStride *ca, int8_t obj_type, CArray *parent,
236
+ int8_t data_type, ca_size_t bytes,
237
+ int8_t ndim, ca_size_t *dim,
238
+ ca_size_t *strides, ca_size_t base_offset);
239
+
97
240
  /* Non-zero iff the object is an element-wise lazy view (CAMonOp / CABinOp /
98
241
  CABinCmp / CAMonCmp / CALazyMarker). The streaming branch of the
99
242
  mkkernel-generated reduction kernels tests this to decide whether it can
@@ -101,6 +244,98 @@ void ca_fill_or_free (CArray *co, VALUE (*fill)(VALUE), VALUE arg);
101
244
 
102
245
  int ca_is_lazy_view (void *ap);
103
246
 
247
+ /* The mask of an element-wise lazy operation over several operands
248
+ (CABinOp, CABinCmp, CATriOp), computed from the operands' masks on each
249
+ read so that it follows them as the values do; NULL when no operand has
250
+ a mask yet. `mode` is CA_LAZY_MASK_OR, one of the KLEENE modes for
251
+ the boolean `|` and `&`, whose masked cells an unmasked operand can
252
+ decide, or CA_LAZY_MASK_SELECT for select, masked where its condition
253
+ is or where the branch the condition chooses is (carray_lazy.c). */
254
+
255
+ #define CA_LAZY_MASK_OR 0
256
+ #define CA_LAZY_MASK_KLEENE_OR 1
257
+ #define CA_LAZY_MASK_KLEENE_AND 2
258
+ #define CA_LAZY_MASK_SELECT 3
259
+
260
+ CArray *ca_lazy_operation_mask (CArray *operation, int mode);
261
+
262
+ /* The array whose memory a view's cells live in: the entity at the end of
263
+ its parent chain, or the first view that has several parents
264
+ (carray_attribute.c). */
265
+ CArray *ca_root_array (void *ap);
266
+
267
+ /* Whether two arrays' cells live in the same root (carray_attribute.c). */
268
+ int ca_shares_root (void *ap, void *aq);
269
+
270
+ /* The create_mask slot of a view whose cells map one-to-one onto its
271
+ parent's in address order: the mask is the parent's mask seen in the
272
+ view's shape (carray_mask.c). Installed directly in operation tables. */
273
+
274
+ void ca_view_func_create_mask (void *ap);
275
+
276
+ /* Running count of the present cells of any data type along axis (Qnil:
277
+ the flattened array), read off the mask alone (carray_mask.c). The
278
+ cumcount kernel answers with it for a data type it does not load. */
279
+
280
+ VALUE rb_ca_scan_mask_count (VALUE self, VALUE axis);
281
+
282
+ /* The registered expression evaluator's answer for a lazy expression the
283
+ caller is about to compute whole, or Qnil to go on with self (see
284
+ carray_lazy.c). */
285
+
286
+ VALUE ca_lazy_evaluated (VALUE self);
287
+
288
+ /* A request to an element-wise lazy view (CAMonOp, CABinOp, CAMonCmp,
289
+ CABinCmp, CATriOp): either a region of the view's addresses -- the
290
+ xfer_stride form, strides in bytes of the view's cells -- or a list of
291
+ addresses. The view answers either with one evaluation: it pulls each
292
+ operand over the same cells with ca_lazy_req_pull and runs its kernel
293
+ once over the n cells (carray_lazy.c). */
294
+
295
+ typedef struct {
296
+ ca_size_t n;
297
+ ca_size_t *addrs; /* list form when non-NULL */
298
+ ca_size_t *starts, *counts, *strides; /* region form */
299
+ ca_size_t bytes; /* cell width the strides use */
300
+ int8_t ndim;
301
+ } ca_lazy_req_t;
302
+
303
+ void ca_lazy_req_region (ca_lazy_req_t *req, void *view, ca_size_t *starts,
304
+ ca_size_t *counts, ca_size_t *strides);
305
+ void ca_lazy_req_addrs (ca_lazy_req_t *req, ca_size_t n, ca_size_t *addrs);
306
+ int ca_lazy_req_is_packed (const ca_lazy_req_t *req, void *view);
307
+ void ca_lazy_req_pull (void *operand, const ca_lazy_req_t *req,
308
+ void *buf, int dir);
309
+ boolean8_t *ca_lazy_req_mask (const ca_lazy_req_t *req, int n, CArray **ops);
310
+ VALUE ca_lazy_settle_scalar (VALUE operand, int was_scalar);
311
+
312
+ /* Non-zero iff the array a view's cells come from -- the parent, or the
313
+ root a CAStride-family parent folds to -- computes them rather than
314
+ lending memory (ca_obj_stride.c). Depends only on what the arrays are,
315
+ never on whether they are attached, so the attach / sync / detach slots
316
+ of one view all take the same branch. */
317
+
318
+ int ca_parent_lends_no_memory (void *ap);
319
+
320
+ /* Transfers of the descriptor views (CAGrid, CASelect, CASelectAxis,
321
+ CAWindow) whose parent holds no ptr (ca_axis_dispatch.c).
322
+
323
+ ca_axis_view_xfer_all serves an xfer_all slot: `fast` is the view's
324
+ transfer against parent->ptr, and region_ok says whether the view's
325
+ xfer_stride answers a whole-view request without going cell by cell.
326
+ ca_axis_view_attach_owned / ca_axis_view_sync_owned are the attach and
327
+ sync of such a view over a parent with no memory to lend: the view owns
328
+ its buffer and the parent is never attached. attach_owned also serves
329
+ any view that owns its buffer and fills it through its own transfers
330
+ (CARemap, CAStack, CAMeld): it publishes the buffer only once filled. */
331
+
332
+ typedef void (*ca_axis_view_fast_t) (void *ap, char *data, int dir);
333
+
334
+ void ca_axis_view_xfer_all (void *ap, ca_axis_view_fast_t fast,
335
+ int region_ok, void *data, int dir);
336
+ void ca_axis_view_attach_owned (void *ap);
337
+ void ca_axis_view_sync_owned (void *ap);
338
+
104
339
  /* ---- per-obj_type view constructors --------------------------------------
105
340
 
106
341
  Constructors for view types that only carray itself builds. Ruby-side
@@ -129,6 +364,9 @@ void ca_block_sync_base_offset (CABlock *cb);
129
364
  /* ca_obj_select.c */
130
365
  VALUE rb_ca_select_new (VALUE cary, VALUE select);
131
366
  VALUE rb_ca_select_new_share (VALUE cary, VALUE select);
367
+ /* An owned, unmasked copy of a boolean selector: a masked cell becomes
368
+ false. Shared by CASelect and CASelectAxis. */
369
+ CArray *ca_select_snapshot (CArray *select);
132
370
 
133
371
  /* ca_obj_mapping.c */
134
372
  VALUE rb_ca_mapping_new (VALUE cary, CArray *mapper);
@@ -149,5 +387,456 @@ CAReduce *ca_reduce_new (CArray *carray, ca_size_t count, ca_size_t offset);
149
387
 
150
388
  /* carray_broadcast.c */
151
389
  void ca_broadcast_to_destination (VALUE dst, volatile VALUE *src);
390
+ VALUE rb_ary_flatten_for_elements (VALUE ary, ca_size_t elements, void *ap);
391
+
392
+ /* carray_utils.c */
393
+ const char *ca_calling_method_name (void);
394
+ VALUE ca_answer_as_caller (VALUE (*body)(VALUE), VALUE arg);
395
+ long ca_integer_arg (VALUE v, const char *arg, const char *name);
396
+ ca_size_t ca_shape_elements (int8_t ndim, const ca_size_t *dim, ca_size_t bytes);
397
+ void ca_check_index_array (VALUE v);
398
+ VALUE ca_order_key (VALUE v, const char *name);
399
+ void ca_check_integer_fits (VALUE v, int8_t data_type);
400
+ VALUE ca_obj2integer_fitting (VALUE v, int8_t data_type);
401
+ int ca_integer_range_side (VALUE v, int8_t data_type);
402
+ int ca_bincmp_integer_prepare (volatile VALUE *self, volatile VALUE *other,
403
+ int op_id, int *signed_side);
404
+ int ca_bincmp_answer_when_negative (int op_id, int signed_side);
405
+ long ca_axis_integer (VALUE raxis, const char *name);
406
+ /* Refuse a write into a read-only array that is not frozen (carray_test.c);
407
+ every guard calls this rather than raising its own. */
408
+ NORETURN(void ca_refuse_read_only (void));
409
+ /* Refuse an operator with no kernel for `data_type`, naming the method and
410
+ the type (carray_operator.c); the eager operators and the lazy builders. */
411
+ NORETURN(void ca_op_refuse_unimplemented (VALUE operand, int8_t data_type,
412
+ VALUE eclass));
413
+ /* Refuse a rank above CA_RANK_MAX before any dim is written (carray_utils.c). */
414
+ void ca_check_rank_fits (long ndim, const char *name);
415
+ /* The checks of carray.h inside the library, each naming the method the
416
+ user called; the public ones stay as they are for extensions. */
417
+ #define CA_CHECK_DATA_TYPE_GIVEN(data_type) \
418
+ do { \
419
+ int ca_dt_ = (data_type); \
420
+ if ( ca_dt_ <= CA_NONE || ca_dt_ >= CA_NTYPE ) { \
421
+ rb_raise(rb_eArgError, "%s: invalid data_type id %i", \
422
+ ca_calling_method_name(), ca_dt_); \
423
+ } \
424
+ if ( ! ca_valid[ca_dt_] ) { \
425
+ rb_raise(rb_eCADataTypeError, "%s: data_type %s is disabled", \
426
+ ca_calling_method_name(), ca_type_name[ca_dt_]); \
427
+ } \
428
+ } while (0)
429
+
430
+ #define CA_CHECK_DIM_GIVEN(ndim, dim) \
431
+ do { \
432
+ int8_t i_; \
433
+ for (i_ = 0; i_ < (ndim); i_++) { \
434
+ if ( (dim)[i_] < 0 ) { \
435
+ rb_raise(rb_eArgError, "%s: negative size dimension at %i-dim", \
436
+ ca_calling_method_name(), i_); \
437
+ } \
438
+ } \
439
+ } while (0)
440
+
441
+ #define CA_CHECK_BYTES_GIVEN(data_type, bytes) \
442
+ do { \
443
+ if ( (data_type) == CA_FIXLEN ) { \
444
+ if ( (bytes) <= 0 ) { \
445
+ rb_raise(rb_eArgError, \
446
+ "%s: invalid bytes (a fixlen needs bytes: of 1 or more)", \
447
+ ca_calling_method_name()); \
448
+ } \
449
+ } \
450
+ else { \
451
+ (bytes) = ca_sizeof[(data_type)]; \
452
+ if ( (bytes) <= 0 ) { \
453
+ rb_raise(rb_eArgError, "%s: invalid bytes", ca_calling_method_name()); \
454
+ } \
455
+ } \
456
+ } while (0)
457
+
458
+ /* CA_CHECK_RANK inside the library: no axes at all is no shape, and above
459
+ CA_RANK_MAX goes to the part, which names the method. The public macro
460
+ stays as it is for extensions. */
461
+ #define CA_CHECK_RANK_GIVEN(ndim) \
462
+ do { \
463
+ long ca_nd_ = (long) (ndim); \
464
+ if ( ca_nd_ <= 0 ) { \
465
+ rb_raise(rb_eArgError, "invalid ndim"); \
466
+ } \
467
+ ca_check_rank_fits(ca_nd_, NULL); \
468
+ } while (0)
469
+ /* An `axis` argument as an axis in [0, ndim): the rule every entry taking
470
+ an axis from Ruby calls (carray_utils.c). */
471
+ int ca_normalize_axis_arg (VALUE raxis, int ndim, const char *name);
472
+ VALUE ca_fill_as (VALUE fill, int8_t data_type);
473
+ /* ---- Face MemoryView export (ca_obj_face.c) -------------------------------
474
+
475
+ A Face registers 1 when its storage bytes carry its values without the
476
+ Face (CARecord, CAFixlenString); the MemoryView producer refuses every
477
+ other Face. Unregistered Faces are refused. */
478
+
479
+ void ca_face_register_memory_view (int obj_type, int exportable);
480
+ int ca_face_memory_view_exportable (CArray *ca);
481
+
482
+ /* The reference and the operand of a comparison brought into one space (see
483
+ ca_obj_face.c). *pref may be replaced by a converted copy and stays a
484
+ Face; the caller strips it. */
485
+ void ca_face_reconcile_pair (volatile VALUE *pref, volatile VALUE *poperand,
486
+ const char *name);
487
+
488
+ /* ---- Empty regions ---------------------------------------------------------
489
+
490
+ A region with a zero count on some axis has no cells. The per-cell walks
491
+ visit their first cell before they test the counts, so every region
492
+ transfer returns on an empty region before it walks: a zero-cell caller
493
+ buffer has no room for that first cell. */
494
+
495
+ static inline int
496
+ ca_region_is_empty (int8_t ndim, const ca_size_t *counts)
497
+ {
498
+ int8_t k;
499
+ for ( k = 0; k < ndim; k++ ) {
500
+ if ( counts[k] <= 0 ) return 1;
501
+ }
502
+ return 0;
503
+ }
504
+
505
+ /* ---- An index into n places ----------------------------------------------
506
+
507
+ A negative index counts from the end; one outside 0...n after that raises
508
+ IndexError, naming the method the user called, `what` the index is (an
509
+ "index", an "address") and the value given. Every index door decides
510
+ this here. */
511
+
512
+ /* ca_index_out_of_range is declared in carray.h (CA_CHECK_INDEX uses it). */
513
+
514
+ static inline ca_size_t
515
+ ca_index_in_range (ca_size_t idx, ca_size_t n, const char *what)
516
+ {
517
+ ca_size_t i = ( idx < 0 ) ? idx + n : idx;
518
+ if ( i < 0 || i >= n ) {
519
+ ca_index_out_of_range(idx, n, what);
520
+ }
521
+ return i;
522
+ }
523
+
524
+ /* The same for an index on axis `axis` of a multi-axis index. */
525
+ NORETURN(void ca_index_out_of_range_at (ca_size_t idx, ca_size_t n, int axis));
526
+
527
+ static inline ca_size_t
528
+ ca_index_in_range_at (ca_size_t idx, ca_size_t n, int axis)
529
+ {
530
+ ca_size_t i = ( idx < 0 ) ? idx + n : idx;
531
+ if ( i < 0 || i >= n ) {
532
+ ca_index_out_of_range_at(idx, n, axis);
533
+ }
534
+ return i;
535
+ }
536
+
537
+ /* ---- How many cells a result cell needs ---------------------------------
538
+
539
+ A reduction's result cell is UNDEF when fewer cells contribute to it than
540
+ it needs. It needs `least` cells -- 0 for an operation with an identity
541
+ (sum, prod, accumulate, count, wsum: an empty cell is the identity), 1 for
542
+ one without (mean, min, max, median, ...), 2 for a sample variance -- or
543
+ `min_count` cells when that is given and asks for more. A min_count below
544
+ zero means it was not given. Every reduction decides this here. */
545
+
546
+ static inline int
547
+ ca_too_few_present (ca_size_t present, ca_size_t min_count, ca_size_t least)
548
+ {
549
+ return present < ( min_count > least ? min_count : least );
550
+ }
551
+
552
+ long ca_min_count_arg (VALUE v, const char *name);
553
+ VALUE ca_reduce_fill (VALUE result, VALUE fill, int whole);
554
+ int ca_symbol_choice (VALUE v, const char *arg, const char *c0,
555
+ const char *c1, const char *name);
556
+
557
+ /* Return the value of `call`, keeping the array `v` reachable until the call
558
+ has returned. A kernel reads its source through the CArray pointer only,
559
+ so a view made just to be passed in (a flattened or common-type view)
560
+ would otherwise be left to a garbage collection that runs while its
561
+ cells are read: `return kernel(v, ...)` lets the compiler drop `v`. */
562
+ #define CA_RETURN_KEEPING(v, call) do { \
563
+ VALUE ca_kept_result_ = (call); \
564
+ RB_GC_GUARD(v); \
565
+ return ca_kept_result_; \
566
+ } while (0)
567
+
568
+ /* A NaN loses every contest of an extremum (min / max / minmax / the
569
+ positions / the running cummin / cummax / pmin / pmax): it never displaces
570
+ another value, the first number displaces it, and nothing but NaN answers
571
+ NaN. The two tests below are that rule for a typed cell and for an object
572
+ cell (a stored Float NaN); each says whether `v` takes the place of the
573
+ running `acc`. CMP / op is `>` for a maximum, `<` for a minimum. On an
574
+ integer type `v == v` is always true and folds away. */
575
+
576
+ #define CA_EXTREMUM_REPLACES(v, acc, CMP) \
577
+ ( (v) == (v) && ( !((acc) == (acc)) || (v) CMP (acc) ) )
578
+
579
+ #ifndef CA_OBJ_ISNAN
580
+ #define CA_OBJ_ISNAN(v) (RB_FLOAT_TYPE_P(v) && isnan(RFLOAT_VALUE(v)))
581
+ #endif
582
+
583
+ /* A pair `<=>` cannot order: ArgumentError "<method>: comparison of A with
584
+ B failed", naming the method the user called. Every object comparison
585
+ that refuses a pair raises through here. */
586
+ NORETURN(void ca_obj_compare_refused (VALUE a, VALUE b));
587
+
588
+ /* The order of two object cells, by `<=>` as Array#min and #sort take it. */
589
+ static inline int
590
+ ca_obj_cmp (VALUE a, VALUE b)
591
+ {
592
+ VALUE r = rb_funcall(a, rb_intern("<=>"), 1, b);
593
+ if ( NIL_P(r) ) {
594
+ ca_obj_compare_refused(a, b);
595
+ }
596
+ return rb_cmpint(r, a, b);
597
+ }
598
+
599
+ /* The order sort and every order statistic (partition, median,
600
+ percentile, rank, nlargest, the search family) put cells in: a NaN
601
+ after every number, NaN ties NaN. Three-way (-1, 0, 1), ties not
602
+ broken. A descending order keeps NaN after the numbers too, so it
603
+ negates only the comparison of two numbers. ca_partition_nan_*
604
+ (ca_sort_kernels.h) moves the NaN of a float buffer to its tail by
605
+ the same rule; a new order kernel uses these and nothing of its own. */
606
+ #define CA_FLOAT_ORDER_CMP(a, b) \
607
+ ( isnan(a) ? ( isnan(b) ? 0 : 1 ) \
608
+ : ( isnan(b) ? -1 : ( ( (a) > (b) ) - ( (a) < (b) ) ) ) )
609
+
610
+ /* The same order for object cells: a Float NaN after every other value,
611
+ other pairs by `<=>` (ca_obj_cmp, which refuses a pair it cannot
612
+ order). */
613
+ static inline int
614
+ ca_obj_order_cmp (VALUE a, VALUE b)
615
+ {
616
+ int nan_a = CA_OBJ_ISNAN(a), nan_b = CA_OBJ_ISNAN(b);
617
+ if ( nan_a || nan_b ) return nan_a - nan_b;
618
+ return ca_obj_cmp(a, b);
619
+ }
620
+
621
+ /* op names the contest: `<` for a minimum, `>` for a maximum. */
622
+ static inline int
623
+ ca_obj_extremum_replaces (VALUE v, VALUE acc, ID op)
624
+ {
625
+ int c;
626
+ if ( CA_OBJ_ISNAN(v) ) return 0;
627
+ if ( CA_OBJ_ISNAN(acc) ) return 1;
628
+ c = ca_obj_cmp(v, acc);
629
+ return ( op == rb_intern("<") ) ? ( c < 0 ) : ( c > 0 );
630
+ }
631
+
632
+ /* Mask stand-ins. A view whose mask covers a parent that has no mask
633
+ reads an all-false stand-in there instead of giving the parent one:
634
+ asking about the mask, or writing nothing but false into it, gives the
635
+ parent no mask. The stand-in gives way to the parent's own mask once
636
+ the parent has one, or once a true has been written into it. A grid
637
+ with holes, a window or shift that masks its out-of-range cells, and a
638
+ stack or meld with parts that have no mask read their masks this way;
639
+ a new view that does should use these three and nothing of its own.
640
+
641
+ Every entry into the cells of such a mask (each transfer, fill, attach
642
+ and allocate slot, and any walk that reads its parents directly) first
643
+ asks ca_mask_standin_current what to read; every write that may have
644
+ put a true into the stand-in ends with ca_mask_standin_settle. */
645
+
646
+ /* A new stand-in for `parent`: all false, read-only when the parent is. */
647
+ CArray *ca_mask_standin_new (CArray *parent);
648
+
649
+ /* What `mask_view`, now reading `reading` in place of `parent`'s mask,
650
+ should read: the parent's own mask once the parent has one, otherwise
651
+ `reading` unchanged. Also unchanged while mask_view is attached with
652
+ its buffer out. */
653
+ CArray *ca_mask_standin_current (CArray *mask_view, CArray *reading,
654
+ CArray *parent, CArray *standin);
655
+
656
+ /* After a write into `standin`: add any true it now holds to the parent's
657
+ mask (made for it) and clear the stand-in. A parent that can never
658
+ have a mask (a value array, a mask array) refuses a true with
659
+ TypeError, the stand-in cleared. Nothing for a read-only stand-in. */
660
+ void ca_mask_standin_settle (CArray *parent, CArray *standin);
661
+
662
+ /* Whether any of n boolean cells at data is true: whether a write of
663
+ them can have put a true into a stand-in. */
664
+ static inline int
665
+ ca_mask_any_true (const void *data, ca_size_t n)
666
+ {
667
+ const boolean8_t *b = (const boolean8_t *) data;
668
+ ca_size_t i;
669
+ for ( i = 0; i < n; i++ ) {
670
+ if ( b[i] ) return 1;
671
+ }
672
+ return 0;
673
+ }
674
+
675
+ /* The mask a multi-parent view (CAStack, CAMeld) composes for parent `p`:
676
+ p's own mask when it has one, otherwise a stand-in
677
+ (ca_mask_standin_new) stored in *standin for the view to free. The
678
+ stand-in of a value array or a mask array, which can never carry a
679
+ mask, stays in place for good. */
680
+ CArray *ca_multi_parent_mask (CArray *p, CArray **standin);
681
+
682
+ /* ca_mask_standin_current for each part of a multi-parent view's mask.
683
+ `mask` is the view's mask (a CAStack or CAMeld over the parents'
684
+ masks), `parents` / `standins` the view's. */
685
+ void ca_multi_parent_mask_refresh (CArray *mask, CArray **parents,
686
+ CArray **standins, int32_t n);
687
+
688
+ /* Before a write to a multi-parent view's mask: when a parent that can
689
+ never carry a mask (a value array, a mask array) is among the parents,
690
+ run the write `body(arg)` once against blank all-false masks in place of
691
+ every parent's mask and refuse it with that TypeError if it put a true
692
+ into such a parent's part. A refused write then changes no parent.
693
+ Does nothing when no such parent is there. */
694
+ void ca_multi_parent_mask_refuse_first (CArray *mask, CArray **parents,
695
+ CArray **standins, int32_t n,
696
+ VALUE (*body)(VALUE),
697
+ VALUE arg);
698
+
699
+ /* ca_mask_standin_settle for each part of a multi-parent view's mask
700
+ still reading its stand-in, the parts that can have no mask first. */
701
+ void ca_multi_parent_mask_settle (CArray *mask, CArray **parents,
702
+ CArray **standins, int32_t n);
703
+
704
+ /* The common-type rules the operators, result_type and the search family
705
+ share (ext/carray_cast.c): the type a scalar `obj` of type `st` takes
706
+ beside an array of type `at`, and the type two types are matched for
707
+ equality in (a mixed-sign integer pair widened so that each value is
708
+ kept). */
709
+ int8_t ca_promote_scalar_type (int8_t at, VALUE obj, int8_t st);
710
+ int8_t ca_value_match_type (int8_t t, int8_t a, int8_t b);
711
+
712
+ /* Whether a kernel can raise on a cell of type `dt`, so that a masked cell
713
+ must be skipped rather than computed: any op on an object cell (it calls
714
+ Ruby), an integer division, remainder or reciprocal by zero, and an
715
+ integer power of zero to a negative exponent. The eager operators and
716
+ the lazy views (and the plans CArray::Fusion hands an evaluator) ask
717
+ this alone. `op_id` is the kind's op number, or -1 when not known. */
718
+ enum { CA_OP_KIND_MONOP, CA_OP_KIND_BINOP, CA_OP_KIND_TRIOP,
719
+ CA_OP_KIND_MONCMP, CA_OP_KIND_BINCMP };
720
+ int ca_op_raises_on_cell (int kind, int op_id, int8_t dt);
721
+
722
+ /* The type a value query (a Ruby value or a CArray) and a reference of
723
+ type `ref` are compared in, as `eq` compares them: count(v) and the
724
+ search family read the reference through a view of that type. An
725
+ Integer that does not fit `ref` takes the type its value needs, where it
726
+ matches nothing. count(v) and the search family ask it for a numeric
727
+ reference (ca_query_match_applies): a Face query is answered by the Face
728
+ gate first, and a string reference compares in its own type, padding
729
+ included. */
730
+ int8_t ca_query_match_type (int8_t ref, VALUE query);
731
+
732
+ static inline int
733
+ ca_query_match_applies (CArray *ref, VALUE query)
734
+ {
735
+ if ( ! ( ca_is_integer_type(ref) || ca_is_float_type(ref)
736
+ || ref->data_type == CA_BOOLEAN ) ) {
737
+ return 0;
738
+ }
739
+ if ( rb_obj_is_carray(query) ) {
740
+ CArray *q;
741
+ TypedData_Get_Struct(query, CArray, &carray_data_type, q);
742
+ if ( ca_is_face(q) ) {
743
+ return 0;
744
+ }
745
+ }
746
+ return 1;
747
+ }
748
+
749
+ /* Equality of two object cells, as the float lanes answer it: Ruby's `==`,
750
+ except that a Float NaN equals nothing, itself included. rb_equal alone
751
+ answers true for the same object, so whether two NaN cells matched would
752
+ depend on whether they held one Float or two. (The value-hash family --
753
+ unique / is_in / the set operations -- folds every NaN into one value
754
+ instead, in its own hash.) */
755
+ static inline int
756
+ ca_obj_equal (VALUE a, VALUE b)
757
+ {
758
+ if ( CA_OBJ_ISNAN(a) ) return 0;
759
+ return RTEST(rb_equal(a, b));
760
+ }
761
+
762
+ /* ---- fast paths (carray_core.c) --------------------------------------------
763
+
764
+ A fast path answers what a general path also answers, by a different
765
+ algorithm. Each one tests ca_fast_paths_enabled() alongside its own
766
+ condition, so a development build run with CARRAY_GENERAL_PATH=1 in the
767
+ environment takes the general path everywhere and the test suite
768
+ compares the two. A release build has no switch: the test is the
769
+ constant 1 and costs nothing.
770
+
771
+ A branch that only lends a pointer, or drops to memcpy when the data is
772
+ contiguous, runs the same code either way and does not test this.
773
+
774
+ CARRAY_GENERAL_PATH=2 goes one step further for the kernel iterator.
775
+ Besides switching the fast paths off, it makes the iterator deliver
776
+ every source the way it delivers a view it knows nothing about: the
777
+ whole view gathered into scratch through the view's own transfer
778
+ (ca_xfer_all), and on WRITE the changed cells sent back through it.
779
+ That walk keeps no promise of its own -- the view's transfer keeps
780
+ them -- so a run with 2 checks the iterator's other routes against
781
+ it. ca_iter_by_transfer_only() is constant 0 in a release build.
782
+
783
+ ---------------------------------------------------------------------------- */
784
+
785
+ #ifdef CARRAY_DEV_BUILD
786
+ extern int ca_fast_paths_on;
787
+ extern int ca_iter_transfer_only_on;
788
+ #define ca_fast_paths_enabled() (ca_fast_paths_on)
789
+ #define ca_iter_by_transfer_only() (ca_iter_transfer_only_on)
790
+ #else
791
+ #define ca_fast_paths_enabled() (1)
792
+ #define ca_iter_by_transfer_only() (0)
793
+ #endif
794
+
795
+ /* A logical operator between a boolean array and an object array reads the
796
+ boolean cells as true / false (carray_operator.c). Shared by the eager
797
+ binop and the lazy builder. */
798
+ void ca_binop_read_boolean_as_truth (int logical, volatile VALUE *pa,
799
+ volatile VALUE *pb);
800
+
801
+ /* The :linear percentile between the k-th and (k+1)-th of n sorted values,
802
+ lo and hi, at fraction r past the k-th: lo itself when r is 0 or there is
803
+ no (k+1)-th, else lo * (1 - r) + hi * r. A NaN sorts last, so a hi in the
804
+ NaN tail makes the answer NaN unless r is 0. The core's percentile and the
805
+ iterators' per-segment kernels answer through this one expression. */
806
+ static inline double
807
+ ca_percentile_linear (double lo, double hi, double r, ca_size_t k, ca_size_t n)
808
+ {
809
+ if ( r == 0.0 || k + 1 >= n ) return lo;
810
+ return lo * (1.0 - r) + hi * r;
811
+ }
812
+
813
+ /* rb_ca_ptr2obj without the Face decode and the boolean true/false: a
814
+ boolean is 0 or 1 and a Face cell is its storage value. For the element
815
+ readers, which check the mask first and decode after (carray_cast.c). */
816
+ VALUE rb_ca_ptr2obj_storage (VALUE self, void *ptr);
817
+
818
+ /* Wrap a MemoryView producer without copying (carray_memory_view.c).
819
+ explicit_data_type must agree with a typed producer's format and names
820
+ a typeless one's type; typeless_data_type names only a typeless one's
821
+ (-1: none). writable asks the producer for a writable view and raises
822
+ when the source is read-only. wrap_readonly / wrap_writable take
823
+ their operand through this. */
824
+ VALUE ca_mv_wrap (VALUE obj, VALUE mask_obj, VALUE target_class,
825
+ int8_t explicit_data_type, int8_t typeless_data_type,
826
+ int writable);
827
+
828
+ /* The indexer's reading of one non-CArray key along an axis, and of the
829
+ rubber marker (carray_index_classifier.c). grid and CASelectAxis read
830
+ their keys through these, so a key means the same cells on every path. */
831
+ int ca_index_axis_key (VALUE arg, ca_size_t dim, int axis,
832
+ ca_size_t *start, ca_size_t *count, ca_size_t *step);
833
+ long ca_index_expand_rubber (int ndim, long argc, const VALUE *argv, VALUE *out);
834
+ /* Whether a key is a scalar one (an Integer or a Float), which picks one
835
+ cell and drops its axis. Whether it names a cell is checked when the
836
+ key is read. */
837
+ int ca_index_key_is_scalar (VALUE arg);
838
+
839
+ /* Whether this runs in the main Ractor (carray_utils.c). */
840
+ int ca_in_main_ractor (void);
152
841
 
153
842
  #endif /* CARRAY_INTERNAL_H */