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
data/ext/ca_obj_face.h CHANGED
@@ -4,16 +4,12 @@
4
4
 
5
5
  Face mechanism — shared op helper signatures + lift/strip entry points.
6
6
 
7
- Phase 1 (= PROPOSAL_CAFACE_PHASE_1.md): skeleton.
8
- Phase 2 (= PROPOSAL_CAFACE_PHASE_2.md F.2.1): replace shared op helpers
9
- with thin-forward to parent.
10
-
11
7
  This header provides signatures for (1) shared op helpers (= thin-forward
12
8
  for storage ops, alias-based since Face is data-layout identical to
13
9
  parent), (2) `rb_ca_face_template` (struct duplicate + parent swap),
14
10
  (3) `ca_face_lift` (= wrap hook at the tail of user-facing access
15
- methods), (4) `ca_strip_face` (= Face-stripping helper at kernel_iterator
16
- entry).
11
+ methods), (4) `ca_strip_face` (= Face-stripping helper for code that
12
+ must see the storage).
17
13
 
18
14
  A Face is a "mask of a semantic type" (= identity layered on a storage
19
15
  type such as int64, with no value conversion), sibling to CAFake which
@@ -57,20 +53,27 @@ void ca_face_xfer_all (void *ap, void *data, int dir);
57
53
 
58
54
  /* -- lift / strip helpers -- */
59
55
 
60
- /* Struct duplicate + parent + shape swap (= MEMO §4.3; consumed by Face
61
- subclass lift / clone / dup machinery in Phase 2). */
56
+ /* Struct duplicate + parent + shape swap. The primitive under
57
+ ca_face_lift; also called directly where a result is re-wrapped under
58
+ a Face without going through a view (partition, generated reduce). */
62
59
  VALUE rb_ca_face_template (VALUE original_face, CArray *new_parent,
63
60
  ca_size_t *new_dim);
64
61
 
65
- /* At the tail of user-facing access methods, `if parent is a Face, wrap
66
- the result as a Face`. Deployed in Phase 1 for `ca[...]`
67
- (= rb_ca_aref / rb_ca_store); planned for block / refer / reshape /
68
- transpose / sort etc. in Phase 2. */
62
+ /* At the tail of view-creating methods, `if the receiver is a Face, wrap
63
+ the result as a Face`. Reached through CA_FACE_LIFT_IF_FACE, which
64
+ each view-creating method deploys at its return path. */
69
65
  VALUE ca_face_lift (VALUE view, VALUE face_parent);
70
66
 
71
- /* Follow the Face flag down to parent, e.g. at kernel_iterator entry.
72
- No call sites in Phase 1; wired into SRC_* path init_l2 in Phase 2
73
- (F.2.6). */
67
+ /* Lift a fresh array `result` (one a reduction, a scan or a partition built
68
+ from the Face's storage) into the Face `face`: the same Face class over
69
+ `result`, carrying the subclass tail, `result`'s mask and the state
70
+ copy_state carries. `result` stays reachable through the new Face. */
71
+ VALUE ca_face_relift_entity (VALUE face, VALUE result);
72
+
73
+ /* Follow the Face flag down to the first non-Face parent, for code that
74
+ must talk to the storage (store, mask, MemoryView export). The kernel
75
+ iterator strips Faces at entry with its own loop, which also strips
76
+ lazy markers. */
74
77
  CArray *ca_strip_face (CArray *src);
75
78
 
76
79
  /* VALUE-level counterpart: walks the Face parent ivar chain to the root
@@ -101,15 +104,15 @@ void Init_ca_face (void);
101
104
  extern int8_t CA_OBJ_RECORD;
102
105
  VALUE rb_ca_record_get_data_class (CArray *ca);
103
106
 
104
- /* -- Convenience macro for view-creating method deployment (F.2.13) --
107
+ /* CA_OBJ_STRING identifies CAString, read by the store path
108
+ (carray_access.c) to send an array source through the write hook. */
109
+ extern int8_t CA_OBJ_STRING;
110
+
111
+ /* -- Convenience macro for view-creating method deployment --
105
112
  Insert at the tail of each view-creating Ruby method (= rb_ca_transpose
106
113
  / rb_ca_reshape / etc.) just before return. `ca` is self's CArray *,
107
114
  `obj` is the view result, `self` is the calling VALUE. Achieves Face
108
- transparency in a single C-level line, subclass-agnostic.
109
-
110
- Macroises the pattern hand-written at the tail of `rb_ca_fetch_method`
111
- in Phase 1; applied uniformly to view-creating methods from Phase 2
112
- F.2.13 onward. */
115
+ transparency in a single C-level line, subclass-agnostic. */
113
116
  #define CA_FACE_LIFT_IF_FACE(obj, self, ca) do { \
114
117
  if ( ca_is_face(ca) && rb_obj_is_kind_of((obj), rb_cCArray) ) { \
115
118
  (obj) = ca_face_lift((obj), (self)); \
@@ -127,14 +130,13 @@ VALUE rb_ca_record_get_data_class (CArray *ca);
127
130
 
128
131
  The flag test comes first and covers both bits in one mask, so an
129
132
  ordinary array leaves through a single AND. That matters: `[]` is the
130
- hottest method this is deployed on (see devel/bench_index_percall.rb).
133
+ hottest method this is deployed on.
131
134
 
132
135
  NOT interchangeable with CA_FACE_LIFT_IF_FACE. Face is lifted at ~24
133
136
  sites, including ones a marker must not follow it through -- `copy` owns
134
137
  its data, `sort` reorders values, `value` and `strip_mask` change what
135
138
  the mask means. Deploy this only where the result is a view whose shape
136
- was fixed at construction and which only moves positions
137
- (PROPOSAL_LAZY_MARKER_LIFT section 4). */
139
+ was fixed at construction and which only moves positions. */
138
140
  #define CA_WRAPPER_LIFT(obj, self, ca) do { \
139
141
  if ( ca_test_flag((ca), CA_FLAG_IS_FACE | CA_FLAG_IS_LAZY_MARKER) \
140
142
  && rb_obj_is_kind_of((obj), rb_cCArray) ) { \
@@ -147,10 +149,10 @@ VALUE ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca);
147
149
  /* -- Scalar fetch decode hook (storage -> surface) --
148
150
  On the scalar-return path (= tail of rb_ca_fetch_index /
149
151
  rb_ca_fetch_addr), if a Face-derived subclass defines a
150
- `storage_to_scalar(raw_value)` Ruby callback, invoke it. This is a
152
+ `storage_to_element(raw_value)` Ruby callback, invoke it. This is a
151
153
  decode (copy the storage value out and construct a new value object),
152
154
  not a wrap (a zero-copy lens over live memory). Its write-direction
153
- counterpart is `scalar_to_storage` (below).
155
+ counterpart is `element_to_storage` (below).
154
156
 
155
157
  Use cases:
156
158
  - `dt[i]` for CATime / CATimedelta → Scalar decode
@@ -163,39 +165,39 @@ VALUE ca_wrapper_lift (VALUE view, VALUE wrapper, void *wrapper_ca);
163
165
  - !is_a?(CArray): CArray results go through the lift path
164
166
  (= CA_FACE_LIFT_IF_FACE)
165
167
  - !UNDEF: don't decode the masked-element sentinel
166
- - respond_to?(:storage_to_scalar): activates once the subclass adopts
168
+ - respond_to?(:storage_to_element): activates once the subclass adopts
167
169
  the convention */
168
- /* Face-local C-level dispatch table for storage_to_scalar, separate
170
+ /* Face-local C-level dispatch table for storage_to_element, separate
169
171
  from the global ca_operation_function_t (no API change to existing
170
172
  subsystems). A Face subclass that wants the per-cell scalar fetch hot
171
173
  path to skip rb_funcall registers its C function via
172
- ca_face_register_storage_to_scalar(obj_type, fn) at Init time.
174
+ ca_face_register_storage_to_element(obj_type, fn) at Init time.
173
175
  Unregistered obj_types (= external gem Faces that only define the Ruby
174
176
  method) fall through to the rb_funcall branch. The Ruby
175
- `storage_to_scalar` method is still defined as a regular method so
177
+ `storage_to_element` method is still defined as a regular method so
176
178
  user-facing Ruby code may call it directly. */
177
- typedef VALUE (*ca_face_storage_to_scalar_fn)(VALUE self, VALUE raw);
179
+ typedef VALUE (*ca_face_storage_to_element_fn)(VALUE self, VALUE raw);
178
180
 
179
- extern ca_face_storage_to_scalar_fn ca_face_storage_to_scalar_table[];
181
+ extern ca_face_storage_to_element_fn ca_face_storage_to_element_table[];
180
182
 
181
- void ca_face_register_storage_to_scalar (int obj_type,
182
- ca_face_storage_to_scalar_fn fn);
183
+ void ca_face_register_storage_to_element (int obj_type,
184
+ ca_face_storage_to_element_fn fn);
183
185
 
184
186
  /* -- Scalar store encode hook (surface -> storage), mirror of the decode --
185
- The write-direction counterpart of storage_to_scalar. Given a surface
187
+ The write-direction counterpart of storage_to_element. Given a surface
186
188
  value object (a Scalar / Time / DateTime), a Face-owned function returns
187
189
  a storage-domain value (for datetime/timedelta: an Integer in self's
188
190
  unit) that the storage cast in rb_ca_obj2ptr can consume directly. A
189
191
  Face that needs no conversion (surface == storage) simply does not
190
192
  register. Faces may either register a C fast-path function here or
191
- define the Ruby method `scalar_to_storage`; the C table is consulted
193
+ define the Ruby method `element_to_storage`; the C table is consulted
192
194
  first, then the Ruby fallback. */
193
- typedef VALUE (*ca_face_scalar_to_storage_fn)(VALUE self, VALUE surface);
195
+ typedef VALUE (*ca_face_element_to_storage_fn)(VALUE self, VALUE surface);
194
196
 
195
- extern ca_face_scalar_to_storage_fn ca_face_scalar_to_storage_table[];
197
+ extern ca_face_element_to_storage_fn ca_face_element_to_storage_table[];
196
198
 
197
- void ca_face_register_scalar_to_storage (int obj_type,
198
- ca_face_scalar_to_storage_fn fn);
199
+ void ca_face_register_element_to_storage (int obj_type,
200
+ ca_face_element_to_storage_fn fn);
199
201
 
200
202
  /* Single source of truth for the surface -> storage-domain conversion.
201
203
  Returns `obj` unchanged when `ca` is not a Face or when no hook is
@@ -203,7 +205,7 @@ void ca_face_register_scalar_to_storage (int obj_type,
203
205
  existing storage cast). Otherwise returns the storage-domain value the
204
206
  Face produced. Called from rb_ca_obj2ptr (single-cell / fill / masked /
205
207
  range stores) and from the Array-of-scalars bulk store branch. */
206
- VALUE ca_face_scalar_to_storage (VALUE self, CArray *ca, VALUE obj);
208
+ VALUE ca_face_element_to_storage (VALUE self, CArray *ca, VALUE obj);
207
209
 
208
210
  /* -- F.S0: Face state homogeneity check (= prerequisite for multi-Face APIs
209
211
  such as CAStack lift) --
@@ -259,6 +261,19 @@ void ca_face_register_state_portable (int obj_type, int portable);
259
261
  (= falls through to default). */
260
262
  int ca_face_state_portable (int obj_type, VALUE klass);
261
263
 
264
+ /* Check a list of arrays about to be combined into one (CAStack, CAMeld,
265
+ promote_list). Returns the Face class every element shares, or Qnil
266
+ when none of them is a Face; the combined array is then lifted into
267
+ that class. Raises ArgumentError for a mix of Face and non-Face arrays
268
+ or of two Face classes, for two or more of a Face whose state is not
269
+ portable, and for elements whose state differs from the first one's.
270
+ `who` names the caller at the head of the message. */
271
+ VALUE ca_face_list_class (VALUE list, const char *who);
272
+
273
+ /* A Face array's storage-side parent, one level down; any other array
274
+ as it is. */
275
+ VALUE ca_face_strip_one (VALUE v);
276
+
262
277
  /* Bring a Face *operand* into the reference's storage space, or refuse.
263
278
 
264
279
  The gate asks `fz_face_descend`'s question -- "is your storage your
@@ -272,20 +287,69 @@ int ca_face_state_portable (int obj_type, VALUE klass);
272
287
  cells *are* the values it shows. Anything else -- a byte range, a code, a
273
288
  tick -- is refused rather than compared as bytes. Non-Face operands are
274
289
  returned untouched. `name` opens the message. */
290
+ /* Refuse to order (verb "order") or count by value (verb "count") a Face
291
+ whose storage does not hold its values in order, naming the conversion. */
292
+ NORETURN(void ca_face_refuse_order (const char *name, VALUE face,
293
+ const char *verb));
294
+
295
+ /* The gate of every family that orders, compares, searches or hashes a Face
296
+ reference: returns when the Face is ORDERABLE_STORAGE, refuses otherwise
297
+ (ca_face_refuse_order). Call this rather than testing the flag. */
298
+ void ca_face_require_orderable (VALUE face, const char *name,
299
+ const char *verb);
300
+
301
+ /* Whether a Face is not ORDERABLE and answers #order itself (CAConstString,
302
+ CARecord), so a family that orders by a key takes that order instead of
303
+ the storage. */
304
+ int ca_face_orders_by_itself (VALUE face);
305
+
306
+ /* The conversion a refusal of a Face whose cells encode its values points
307
+ at (#to_string for a string Face, to_type(:object) for any other). */
308
+ const char *ca_face_conversion_hint (VALUE face);
309
+
310
+ /* The method that gives the storage under a Face (#ticks, #codes), or NULL
311
+ when the Face has none of those. */
312
+ const char *ca_face_storage_method (VALUE face);
313
+
314
+ /* Raise eclass naming a Face that does not define the numeric operation
315
+ `name`; returns when self is not a Face. See ca_obj_face.c. */
316
+ void ca_face_refuse_numeric (VALUE self, const char *name, VALUE eclass);
317
+
275
318
  VALUE ca_face_operand_descend (VALUE operand, const char *name);
276
319
 
277
- #define CA_FACE_STORAGE_TO_SCALAR_IF_FACE(obj, self, ca) do { \
320
+ /* Bring an operand into the storage space of a Face reference (a record's
321
+ own data_class, a COMPARABLE Face's plain values, or the reference's
322
+ to_comparable), refusing what the reference cannot read. See
323
+ ca_obj_face.c. */
324
+ VALUE ca_face_reconcile_operand (VALUE reference, VALUE operand,
325
+ const char *name);
326
+
327
+ /* `==` (strict = 0) / `eql?` (strict = 1) when an operand is a Face other
328
+ than a record array. See ca_obj_face.c. */
329
+ int ca_face_equal (VALUE va, VALUE vb, int strict);
330
+
331
+ /* The storage value of a cell read through a Face. A gated (CA_FIXLEN)
332
+ surface over a numeric storage delivers the cell as its bytes; they are
333
+ read back as the storage data_type (a boolean as true / false). A
334
+ fixlen or object storage, and anything not a String, comes back as it
335
+ came. This is what a Ruby storage_to_element receives, and the element
336
+ of a Face that defines none. A C function registered for the obj_type
337
+ receives the cell as it was read, the bytes under a gated surface. */
338
+ VALUE ca_face_storage_value (CArray *ca, VALUE raw);
339
+
340
+ #define CA_FACE_STORAGE_TO_ELEMENT_IF_FACE(obj, self, ca) do { \
278
341
  if ( ca_is_face(ca) && (obj) != CA_UNDEF && (obj) != Qnil \
279
342
  && ! rb_obj_is_kind_of((obj), rb_cCArray) ) { \
280
- ca_face_storage_to_scalar_fn _decode_fn = ca_face_storage_to_scalar_table[(ca)->obj_type]; \
343
+ ca_face_storage_to_element_fn _decode_fn = ca_face_storage_to_element_table[(ca)->obj_type]; \
281
344
  if ( _decode_fn != NULL ) { \
282
345
  (obj) = _decode_fn((self), (obj)); \
283
346
  } \
284
347
  else { \
285
- static ID _id_storage_to_scalar = 0; \
286
- if ( _id_storage_to_scalar == 0 ) _id_storage_to_scalar = rb_intern("storage_to_scalar"); \
287
- if ( rb_respond_to((self), _id_storage_to_scalar) ) { \
288
- (obj) = rb_funcall((self), _id_storage_to_scalar, 1, (obj)); \
348
+ static ID _id_storage_to_element = 0; \
349
+ (obj) = ca_face_storage_value((ca), (obj)); \
350
+ if ( _id_storage_to_element == 0 ) _id_storage_to_element = rb_intern("storage_to_element"); \
351
+ if ( rb_respond_to((self), _id_storage_to_element) ) { \
352
+ (obj) = rb_funcall((self), _id_storage_to_element, 1, (obj)); \
289
353
  } \
290
354
  } \
291
355
  } \
data/ext/ca_obj_fake.c CHANGED
@@ -78,8 +78,14 @@ ca_fake_setup (CAFake *ca, CArray *parent, int8_t data_type, ca_size_t bytes)
78
78
 
79
79
  /* check arguments */
80
80
 
81
- CA_CHECK_DATA_TYPE(data_type);
82
- CA_CHECK_BYTES(data_type, bytes);
81
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
82
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
83
+
84
+ /* ca == NULL asks for the checks above only, so that a constructor can
85
+ run them before it allocates. */
86
+ if ( ca == NULL ) {
87
+ return 0;
88
+ }
83
89
 
84
90
  ndim = parent->ndim;
85
91
  dim = parent->dim;
@@ -103,9 +109,6 @@ ca_fake_setup (CAFake *ca, CArray *parent, int8_t data_type, ca_size_t bytes)
103
109
 
104
110
  memcpy(ca->dim, dim, ndim * sizeof(ca_size_t));
105
111
 
106
- if ( ca_has_mask(parent) ) {
107
- ca_create_mask(ca);
108
- }
109
112
 
110
113
  if ( ca_is_scalar(parent) ) {
111
114
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -117,8 +120,11 @@ ca_fake_setup (CAFake *ca, CArray *parent, int8_t data_type, ca_size_t bytes)
117
120
  CAFake *
118
121
  ca_fake_new (CArray *parent, int8_t data_type, ca_size_t bytes)
119
122
  {
120
- CAFake *ca = (CAFake *) ca_array_alloc(CA_OBJ_FAKE, parent->ndim);
123
+ CAFake *ca;
124
+ ca_fake_setup(NULL, parent, data_type, bytes);
125
+ ca = (CAFake *) ca_array_alloc(CA_OBJ_FAKE, parent->ndim);
121
126
  ca_fake_setup(ca, parent, data_type, bytes);
127
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
122
128
  return ca;
123
129
  }
124
130
 
@@ -154,8 +160,8 @@ static void
154
160
  ca_fake_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
155
161
  {
156
162
  CAFake *ca = (CAFake *) ap;
157
- char sbuf[32];
158
- char *v = (ca->parent->bytes <= 32) ? sbuf : xmalloc(ca->parent->bytes);
163
+ volatile VALUE holder;
164
+ char *v = ALLOCV_N(char, holder, ca->parent->bytes);
159
165
  if ( dir == CA_XFER_GET ) {
160
166
  ca_fetch_index(ca->parent, idx, v);
161
167
  ca_ptr2ptr(ca->parent, v, ca, data);
@@ -164,7 +170,7 @@ ca_fake_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
164
170
  ca_ptr2ptr(ca, data, ca->parent, v);
165
171
  ca_store_index(ca->parent, idx, v);
166
172
  }
167
- if ( v != sbuf ) xfree(v);
173
+ ALLOCV_END(holder);
168
174
  }
169
175
 
170
176
  /* Batched address gather/scatter. CAFake is a 1:1 reinterpret-cast
@@ -237,6 +243,7 @@ static void
237
243
  ca_fake_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
238
244
  ca_size_t *strides, void *data, int dir)
239
245
  {
246
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
240
247
  CAFake *ca = (CAFake *) ap;
241
248
  int8_t ndim = ca->ndim;
242
249
  ca_size_t pstrides[CA_RANK_MAX];
@@ -276,18 +283,7 @@ ca_fake_func_allocate (void *ap)
276
283
  {
277
284
  CAFake *ca = (CAFake *) ap;
278
285
  ca_attach(ca->parent);
279
- ca->ptr = xmalloc(ca_length(ca));
280
-
281
- /* CAREFUL: CA_OBJECT storage must contain valid VALUEs before GC can
282
- scan it, so seed with Fixnum 0 rather than leaving raw xmalloc bytes. */
283
- if ( ca->data_type == CA_OBJECT ) {
284
- VALUE *p = (VALUE *) ca->ptr;
285
- VALUE zero = SIZE2NUM(0);
286
- ca_size_t i;
287
- for (i=0; i<ca->elements; i++) {
288
- *p++ = zero;
289
- }
290
- }
286
+ ca->ptr = ca_alloc_cells((CArray *) ca);
291
287
  }
292
288
 
293
289
  static void
@@ -295,17 +291,7 @@ ca_fake_func_attach (void *ap)
295
291
  {
296
292
  CAFake *ca = (CAFake *) ap;
297
293
  ca_attach(ca->parent);
298
- ca->ptr = xmalloc(ca_length(ca));
299
-
300
- /* CAREFUL: same VALUE-seed rule as ca_fake_func_allocate. */
301
- if ( ca->data_type == CA_OBJECT ) {
302
- VALUE *p = (VALUE *) ca->ptr;
303
- VALUE zero = SIZE2NUM(0);
304
- ca_size_t i;
305
- for (i=0; i<ca->elements; i++) {
306
- *p++ = zero;
307
- }
308
- }
294
+ ca->ptr = ca_alloc_cells((CArray *) ca);
309
295
 
310
296
  if ( ca->parent->mask ) {
311
297
  ca_cast_block_with_mask(ca->elements, ca->parent, ca->parent->ptr,
@@ -365,17 +351,11 @@ static void
365
351
  ca_fake_func_fill_data (void *ap, void *ptr)
366
352
  {
367
353
  CAFake *ca = (CAFake *) ap;
368
- if ( ca->parent->bytes <= 32 ) {
369
- char v[32];
370
- ca_ptr2ptr(ca, ptr, ca->parent, v);
371
- ca_fill(ca->parent, v);
372
- }
373
- else {
374
- char *v = xmalloc(ca->parent->bytes);
375
- ca_ptr2ptr(ca, ptr, ca->parent, v);
376
- ca_fill(ca->parent, v);
377
- xfree(v);
378
- }
354
+ volatile VALUE holder;
355
+ char *v = ALLOCV_N(char, holder, ca->parent->bytes);
356
+ ca_ptr2ptr(ca, ptr, ca->parent, v);
357
+ ca_fill(ca->parent, v);
358
+ ALLOCV_END(holder);
379
359
  }
380
360
 
381
361
  /* Same as fill_data, with a region: convert the one value once and pass the
@@ -389,47 +369,22 @@ ca_fake_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
389
369
  ca_size_t *counts, ca_size_t *steps, void *ptr)
390
370
  {
391
371
  CAFake *ca = (CAFake *) ap;
392
- if ( ca->parent->bytes <= 32 ) {
393
- char v[32];
394
- ca_ptr2ptr(ca, ptr, ca->parent, v);
395
- ca_fill_stride(ca->parent, base, ndim, counts, steps, v);
396
- }
397
- else {
398
- char *v = xmalloc(ca->parent->bytes);
399
- ca_ptr2ptr(ca, ptr, ca->parent, v);
400
- ca_fill_stride(ca->parent, base, ndim, counts, steps, v);
401
- xfree(v);
402
- }
372
+ volatile VALUE holder;
373
+ char *v = ALLOCV_N(char, holder, ca->parent->bytes);
374
+ ca_ptr2ptr(ca, ptr, ca->parent, v);
375
+ ca_fill_stride(ca->parent, base, ndim, counts, steps, v);
376
+ ALLOCV_END(holder);
403
377
  }
404
378
 
405
379
  static void
406
380
  ca_fake_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
407
381
  {
408
382
  CAFake *ca = (CAFake *) ap;
409
- if ( ca->parent->bytes <= 32 ) {
410
- char v[32];
411
- ca_ptr2ptr(ca, ptr, ca->parent, v);
412
- ca_fill_addrs(ca->parent, n, addrs, v);
413
- }
414
- else {
415
- char *v = xmalloc(ca->parent->bytes);
416
- ca_ptr2ptr(ca, ptr, ca->parent, v);
417
- ca_fill_addrs(ca->parent, n, addrs, v);
418
- xfree(v);
419
- }
420
- }
421
-
422
- static void
423
- ca_fake_func_create_mask (void *ap)
424
- {
425
- CAFake *ca = (CAFake *) ap;
426
- ca_update_mask(ca->parent);
427
- if ( ! ca->parent->mask ) {
428
- ca_create_mask(ca->parent);
429
- }
430
- ca->mask =
431
- (CArray *) ca_refer_new(ca->parent->mask,
432
- CA_BOOLEAN, ca->ndim, ca->dim, 0, 0);
383
+ volatile VALUE holder;
384
+ char *v = ALLOCV_N(char, holder, ca->parent->bytes);
385
+ ca_ptr2ptr(ca, ptr, ca->parent, v);
386
+ ca_fill_addrs(ca->parent, n, addrs, v);
387
+ ALLOCV_END(holder);
433
388
  }
434
389
 
435
390
  ca_operation_function_t ca_fake_func = {
@@ -442,7 +397,7 @@ ca_operation_function_t ca_fake_func = {
442
397
  ca_fake_func_sync,
443
398
  ca_fake_func_detach,
444
399
  ca_fake_func_fill_data,
445
- ca_fake_func_create_mask,
400
+ ca_view_func_create_mask,
446
401
  ca_fake_func_xfer_index,
447
402
  ca_fake_func_xfer_addrs,
448
403
  NULL, /* fold_stride: never-fold (transform boundary) */
@@ -522,12 +477,14 @@ rb_ca_fake_initialize_copy (VALUE self, VALUE other)
522
477
  CAFake *ca, *cs;
523
478
 
524
479
  TypedData_Get_Struct(self, CAFake, &cafake_data_type, ca);
480
+ ca_check_uninitialized(ca);
525
481
  TypedData_Get_Struct(other, CAFake, &cafake_data_type, cs);
526
482
 
527
483
  if ( ca_func[CA_OBJ_FAKE].pool_init ) {
528
484
  ca_array_pool_alloc(ca, CA_OBJ_FAKE, cs->parent->ndim);
529
485
  }
530
486
  ca_fake_setup(ca, cs->parent, cs->data_type, cs->bytes);
487
+ ca_view_inherit_mask((VALUE) ca);
531
488
 
532
489
  return self;
533
490
  }
data/ext/ca_obj_farray.c CHANGED
@@ -7,6 +7,7 @@
7
7
  ---------------------------------------------------------------------------- */
8
8
 
9
9
  #include "carray.h"
10
+ #include "carray_internal.h" /* ca_view_inherit_mask */
10
11
 
11
12
  extern ca_operation_function_t ca_stride_func;
12
13
 
@@ -46,9 +47,9 @@ ca_farray_setup (CAStride *ca, CArray *parent)
46
47
  strides[i] = parent_byte_stride[ndim - 1 - i];
47
48
  }
48
49
 
49
- ca_stride_setup(ca, CA_OBJ_FARRAY, parent,
50
- parent->data_type, parent->bytes,
51
- ndim, newdim, strides, 0);
50
+ ca_stride_setup_view(ca, CA_OBJ_FARRAY, parent,
51
+ parent->data_type, parent->bytes,
52
+ ndim, newdim, strides, 0);
52
53
 
53
54
  if (ca_is_scalar(parent)) {
54
55
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -59,8 +60,10 @@ ca_farray_setup (CAStride *ca, CArray *parent)
59
60
  CAStride *
60
61
  ca_farray_new (CArray *parent)
61
62
  {
63
+ /* check: the parent's shape, reversed, is already valid */
62
64
  CAStride *ca = (CAStride *) ca_array_alloc(CA_OBJ_FARRAY, parent->ndim);
63
65
  ca_farray_setup(ca, parent);
66
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
64
67
  return ca;
65
68
  }
66
69
 
@@ -92,6 +95,7 @@ rb_ca_farray_initialize_copy (VALUE self, VALUE other)
92
95
  {
93
96
  CAStride *ca, *cs;
94
97
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
98
+ ca_check_uninitialized(ca);
95
99
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
96
100
  if ( ca_func[CA_OBJ_FARRAY].pool_init ) {
97
101
  ca_array_pool_alloc(ca, CA_OBJ_FARRAY, cs->ndim);
data/ext/ca_obj_field.c CHANGED
@@ -32,18 +32,32 @@ ca_field_setup (CAStride *ca, CArray *parent,
32
32
  ca_size_t strides[CA_RANK_MAX];
33
33
  int8_t i;
34
34
 
35
- CA_CHECK_DATA_TYPE(data_type);
36
- CA_CHECK_BYTES(data_type, bytes);
35
+ CA_CHECK_DATA_TYPE_GIVEN(data_type);
36
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
37
37
 
38
38
  if ( offset < 0 ) {
39
- rb_raise(rb_eRuntimeError, "negative offset");
39
+ rb_raise(rb_eArgError, "negative offset");
40
40
  }
41
41
  if ( data_type == CA_OBJECT ) {
42
42
  rb_raise(rb_eCADataTypeError,
43
43
  "CA_OBJECT can not to be a data_type for CAField");
44
44
  }
45
+ if ( ca_is_object_type(parent) ) {
46
+ rb_raise(rb_eCADataTypeError,
47
+ "a field can not be taken from an object array");
48
+ }
49
+ /* A boolean cell holds 0 or 1, and a field of a numeric array is
50
+ written as that number. A record's boolean member is a field of a
51
+ fixlen array, whose member stores keep it 0 or 1. */
52
+ if ( data_type == CA_BOOLEAN && parent->data_type != CA_BOOLEAN
53
+ && parent->data_type != CA_FIXLEN ) {
54
+ rb_raise(rb_eCADataTypeError,
55
+ "%s: a field of a %s array can't be read as boolean (its bytes "
56
+ "need not be 0 or 1); compare it instead, e.g. ne(0)",
57
+ ca_calling_method_name(), ca_type_name[parent->data_type]);
58
+ }
45
59
  if ( parent->bytes < offset + bytes ) {
46
- rb_raise(rb_eRuntimeError, "offset or bytes out of range");
60
+ rb_raise(rb_eArgError, "offset or bytes out of range");
47
61
  }
48
62
 
49
63
  /* strides[k] = parent->bytes × Π_{i>k} parent->dim[i]. Same shape
@@ -57,9 +71,15 @@ ca_field_setup (CAStride *ca, CArray *parent,
57
71
  }
58
72
  }
59
73
 
60
- ca_stride_setup(ca, CA_OBJ_FIELD, parent,
61
- data_type, bytes,
62
- parent->ndim, parent->dim, strides, offset);
74
+ /* ca == NULL asks for the checks above only, so that a constructor can
75
+ run them before it allocates. */
76
+ if ( ca == NULL ) {
77
+ return 0;
78
+ }
79
+
80
+ ca_stride_setup_view(ca, CA_OBJ_FIELD, parent,
81
+ data_type, bytes,
82
+ parent->ndim, parent->dim, strides, offset);
63
83
 
64
84
  return 0;
65
85
  }
@@ -67,8 +87,11 @@ ca_field_setup (CAStride *ca, CArray *parent,
67
87
  CAStride *
68
88
  ca_field_new (CArray *parent, ca_size_t offset, int8_t data_type, ca_size_t bytes)
69
89
  {
70
- CAStride *ca = (CAStride *) ca_array_alloc(CA_OBJ_FIELD, parent->ndim);
90
+ CAStride *ca;
91
+ ca_field_setup(NULL, parent, offset, data_type, bytes);
92
+ ca = (CAStride *) ca_array_alloc(CA_OBJ_FIELD, parent->ndim);
71
93
  ca_field_setup(ca, parent, offset, data_type, bytes);
94
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
72
95
  return ca;
73
96
  }
74
97
 
@@ -160,6 +183,7 @@ rb_ca_field_initialize_copy (VALUE self, VALUE other)
160
183
  CAStride *ca, *cs;
161
184
 
162
185
  TypedData_Get_Struct(self, CAStride, &castride_data_type, ca);
186
+ ca_check_uninitialized(ca);
163
187
  TypedData_Get_Struct(other, CAStride, &castride_data_type, cs);
164
188
 
165
189
  if ( ca_func[CA_OBJ_FIELD].pool_init ) {
@@ -168,6 +192,7 @@ rb_ca_field_initialize_copy (VALUE self, VALUE other)
168
192
  /* Reconstruct from the source's base_offset / data_type / bytes;
169
193
  ca_field_setup recomputes strides from parent's shape. */
170
194
  ca_field_setup(ca, cs->parent, cs->base_offset, cs->data_type, cs->bytes);
195
+ ca_view_inherit_mask((VALUE) ca);
171
196
 
172
197
  return self;
173
198
  }