carray 3.0.3 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_binop.c CHANGED
@@ -177,6 +177,7 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
177
177
  CABinOp *
178
178
  ca_binop_new (CArray *left, CArray *right, uint16_t op_id)
179
179
  {
180
+ /* check: the setup checks nothing */
180
181
  CABinOp *ca = (CABinOp *) ca_array_alloc(CA_OBJ_BINOP, left->ndim);
181
182
  ca_binop_setup(ca, left, right, op_id);
182
183
  return ca;
@@ -227,7 +228,7 @@ ca_binop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
227
228
  ca_size_t s;
228
229
 
229
230
  if ( dir != CA_XFER_GET ) {
230
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_index PUT)");
231
+ ca_refuse_read_only();
231
232
  }
232
233
 
233
234
  s = ca->bytes;
@@ -322,7 +323,7 @@ ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
322
323
  boolean8_t *slab_mask = NULL;
323
324
  void *mscratch = NULL;
324
325
 
325
- if ( ca_binop_is_trapping(bo->op_id, bo->data_type) ) {
326
+ if ( ca_op_raises_on_cell(CA_OP_KIND_BINOP, bo->op_id, bo->data_type) ) {
326
327
  CArray *ops[2];
327
328
  ops[0] = bo->parent;
328
329
  ops[1] = bo->right;
@@ -356,7 +357,7 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
356
357
  if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
357
358
  ca_lazy_req_t req;
358
359
  if ( dir != CA_XFER_GET ) {
359
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_stride PUT)");
360
+ ca_refuse_read_only();
360
361
  }
361
362
  ca_lazy_req_region(&req, ap, starts, counts, strides);
362
363
  ca_binop_eval((CABinOp *) ap, &req, data);
@@ -370,7 +371,7 @@ ca_binop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
370
371
  {
371
372
  ca_lazy_req_t req;
372
373
  if ( dir != CA_XFER_GET ) {
373
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_addrs PUT)");
374
+ ca_refuse_read_only();
374
375
  }
375
376
  ca_lazy_req_addrs(&req, n, addrs);
376
377
  ca_binop_eval((CABinOp *) ap, &req, data);
@@ -393,15 +394,7 @@ static void
393
394
  ca_binop_func_allocate (void *ap)
394
395
  {
395
396
  CABinOp *ca = (CABinOp *) ap;
396
- ca->ptr = xmalloc(ca_length(ca));
397
- /* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
398
- soon as the view is, so it must not be handed to the GC as raw
399
- xmalloc garbage. */
400
- if ( ca->data_type == CA_OBJECT ) {
401
- VALUE *p = (VALUE *) ca->ptr;
402
- ca_size_t i;
403
- for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
404
- }
397
+ ca->ptr = ca_alloc_cells((CArray *) ca);
405
398
  }
406
399
 
407
400
  static void
@@ -418,19 +411,11 @@ ca_binop_func_attach (void *ap)
418
411
  int8_t k;
419
412
  ca_size_t s;
420
413
 
421
- ca->ptr = xmalloc(ca_length(ca));
414
+ ca->ptr = ca_alloc_cells((CArray *) ca);
422
415
 
423
416
  s = ca->bytes;
424
417
  for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
425
418
  for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
426
- /* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
427
- soon as the view is, so it must not be handed to the GC as raw
428
- xmalloc garbage. */
429
- if ( ca->data_type == CA_OBJECT ) {
430
- VALUE *p = (VALUE *) ca->ptr;
431
- ca_size_t i;
432
- for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
433
- }
434
419
  ca_binop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
435
420
  }
436
421
 
@@ -452,7 +437,7 @@ NORETURN(static void ca_binop_func_fill_data (void *ap, void *ptr));
452
437
  static void
453
438
  ca_binop_func_fill_data (void *ap, void *ptr)
454
439
  {
455
- rb_raise(rb_eRuntimeError, "CABinOp is read-only (fill_data)");
440
+ ca_refuse_read_only();
456
441
  }
457
442
 
458
443
  /* Build out.mask: the operands' masks ORed on each read (CAMaskOfOperands), so
@@ -605,8 +590,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
605
590
  /* No kernel for that data_type (fixlen arithmetic, ...): raise as the
606
591
  eager binop does, before a view is built over it. */
607
592
  if ( ca_binop_kernel_lookup_vv(op_id, l_in_dt) == ca_binop_not_implement ) {
608
- rb_raise(rb_eCADataTypeError,
609
- "invalid data_type for binop (not implemented)");
593
+ ca_op_refuse_unimplemented(l_cary, l_in_dt, rb_eCADataTypeError);
610
594
  }
611
595
 
612
596
  if ( l_in_dt != l->data_type ) {
@@ -694,6 +678,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
694
678
  static VALUE
695
679
  rb_ca_binop_s_build (VALUE klass, VALUE l_cary, VALUE r_cary, VALUE op_id_val)
696
680
  {
681
+ /* fits: an operation number from the library's own table */
697
682
  uint16_t op_id = (uint16_t) NUM2UINT(op_id_val);
698
683
  (void) klass;
699
684
  return rb_ca_binop_build(l_cary, r_cary, op_id);
@@ -708,7 +693,7 @@ rb_ca_binop_trapping (VALUE self)
708
693
  {
709
694
  CABinOp *bo;
710
695
  TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, bo);
711
- return ca_binop_is_trapping(bo->op_id, bo->data_type) ? Qtrue : Qfalse;
696
+ return ca_op_raises_on_cell(CA_OP_KIND_BINOP, bo->op_id, bo->data_type) ? Qtrue : Qfalse;
712
697
  }
713
698
 
714
699
  static VALUE
@@ -729,6 +714,7 @@ rb_ca_binop_right (VALUE self)
729
714
  }
730
715
 
731
716
  /* Test instrumentation (mirrors CAMonOp counters). */
717
+ #ifdef CARRAY_DEV_BUILD
732
718
  static VALUE
733
719
  rb_ca_binop_s_reset_scratch_counter (VALUE klass)
734
720
  {
@@ -754,6 +740,7 @@ rb_ca_binop_s_materialise_count (VALUE klass)
754
740
  {
755
741
  return SIZE2NUM(ca_binop_materialise_call_count);
756
742
  }
743
+ #endif /* CARRAY_DEV_BUILD */
757
744
 
758
745
  static VALUE
759
746
  rb_ca_binop_s_allocate (VALUE klass)
@@ -834,6 +821,7 @@ Init_ca_obj_binop (void)
834
821
  rb_ca_binop_right, 0);
835
822
 
836
823
  /* Test instrumentation, not user-facing. */
824
+ #ifdef CARRAY_DEV_BUILD
837
825
  rb_define_singleton_method(rb_cCABinOp, "__reset_scratch_counter__",
838
826
  rb_ca_binop_s_reset_scratch_counter, 0);
839
827
  rb_define_singleton_method(rb_cCABinOp, "__scratch_count__",
@@ -842,4 +830,5 @@ Init_ca_obj_binop (void)
842
830
  rb_ca_binop_s_reset_materialise_counter, 0);
843
831
  rb_define_singleton_method(rb_cCABinOp, "__materialise_count__",
844
832
  rb_ca_binop_s_materialise_count, 0);
833
+ #endif
845
834
  }
@@ -98,6 +98,7 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
98
98
 
99
99
  /* The bits of one byte would share that byte's one mask cell, so a bit
100
100
  view takes no masked array and holds no mask of its own. */
101
+ /* mask: the constructor asks first, before it allocates (ca == NULL) */
101
102
  if ( ca_has_mask(parent) ) {
102
103
  rb_raise(rb_eArgError,
103
104
  "bitarray: the array has a mask, which a bit view can not "
@@ -395,7 +396,7 @@ ca_bitarray_func_allocate (void *ap)
395
396
  {
396
397
  CABitarray *ca = (CABitarray *) ap;
397
398
  ca_attach(ca->parent);
398
- ca->ptr = xmalloc(ca_length(ca));
399
+ ca->ptr = ca_alloc_cells((CArray *) ca);
399
400
  }
400
401
 
401
402
  static void
@@ -403,7 +404,7 @@ ca_bitarray_func_attach (void *ap)
403
404
  {
404
405
  CABitarray *ca = (CABitarray *) ap;
405
406
  ca_attach(ca->parent);
406
- ca->ptr = xmalloc(ca_length(ca));
407
+ ca->ptr = ca_alloc_cells((CArray *) ca);
407
408
  ca_bitarray_attach(ca);
408
409
  }
409
410
 
@@ -205,7 +205,7 @@ ca_bitfield_setup (CABitfield *ca, CArray *parent,
205
205
  data_type = CA_UINT64;
206
206
  }
207
207
 
208
- CA_CHECK_BYTES(data_type, bytes);
208
+ CA_CHECK_BYTES_GIVEN(data_type, bytes);
209
209
 
210
210
  if ( bitlen > bytes * 8 ||
211
211
  ( ( data_type == CA_BOOLEAN ) && ( bitlen > 1 ) ) ) {
@@ -273,9 +273,6 @@ ca_bitfield_setup (CABitfield *ca, CArray *parent,
273
273
 
274
274
  memcpy(ca->dim, parent->dim, ndim * sizeof(ca_size_t));
275
275
 
276
- if ( ca_has_mask(parent) ) {
277
- ca_create_mask(ca);
278
- }
279
276
 
280
277
  return 0;
281
278
  }
@@ -288,6 +285,7 @@ ca_bitfield_new (CArray *parent, ca_size_t offset, ca_size_t bitlen,
288
285
  ca_bitfield_setup(NULL, parent, offset, bitlen, data_type);
289
286
  ca = (CABitfield *) ca_array_alloc(CA_OBJ_BITFIELD, parent->ndim);
290
287
  ca_bitfield_setup(ca, parent, offset, bitlen, data_type);
288
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
291
289
  return ca;
292
290
  }
293
291
 
@@ -452,7 +450,7 @@ ca_bitfield_func_allocate (void *ap)
452
450
  {
453
451
  CABitfield *ca = (CABitfield *) ap;
454
452
  ca_attach(ca->parent);
455
- ca->ptr = xmalloc(ca_length(ca));
453
+ ca->ptr = ca_alloc_cells((CArray *) ca);
456
454
  }
457
455
 
458
456
  static void
@@ -460,7 +458,7 @@ ca_bitfield_func_attach (void *ap)
460
458
  {
461
459
  CABitfield *ca = (CABitfield *) ap;
462
460
  ca_attach(ca->parent);
463
- ca->ptr = xmalloc(ca_length(ca));
461
+ ca->ptr = ca_alloc_cells((CArray *) ca);
464
462
  ca_bitfield_attach(ca);
465
463
  }
466
464
 
@@ -708,6 +706,7 @@ rb_ca_bitfield_initialize_copy (VALUE self, VALUE other)
708
706
  }
709
707
  ca_bitfield_setup(ca, cs->parent, cs->bit_start, cs->bit_length,
710
708
  cs->data_type);
709
+ ca_view_inherit_mask((VALUE) ca);
711
710
 
712
711
  return self;
713
712
  }
data/ext/ca_obj_block.c CHANGED
@@ -124,6 +124,12 @@ ca_block_setup (CABlock *ca, CArray *parent, int8_t ndim, ca_size_t *dim,
124
124
  }
125
125
  }
126
126
 
127
+ /* ca == NULL asks for the checks above only, so that a constructor can
128
+ run them before it allocates. */
129
+ if ( ca == NULL ) {
130
+ return 0;
131
+ }
132
+
127
133
  /* strides[k] = step[k] * Pi_{j>k} size0[j] * parent->bytes */
128
134
  suffix = parent->bytes;
129
135
  for (i = ndim - 1; i >= 0; i--) {
@@ -141,10 +147,9 @@ ca_block_setup (CABlock *ca, CArray *parent, int8_t ndim, ca_size_t *dim,
141
147
  }
142
148
  }
143
149
 
144
- /* CAREFUL: the CABlock tail (offset / start / step / count / size0)
145
- must be filled BEFORE ca_stride_setup. ca_stride_setup may auto-
146
- dispatch ca_create_mask when the parent has a mask, and
147
- ca_block_func_create_mask reads those tail fields.
150
+ /* The CABlock tail (offset / start / step / count / size0) is filled
151
+ here; ca_block_func_create_mask reads it when the constructor takes
152
+ the parent's mask (ca_view_inherit_mask) after this setup.
148
153
 
149
154
  Pool path: start/step/count/size0 already point into _pool (wired
150
155
  by ca_block_pool_init); only memcpy the values. Non-pool path:
@@ -161,10 +166,10 @@ ca_block_setup (CABlock *ca, CArray *parent, int8_t ndim, ca_size_t *dim,
161
166
  memcpy(ca->count, count, ndim * sizeof(ca_size_t));
162
167
  memcpy(ca->size0, dim, ndim * sizeof(ca_size_t));
163
168
 
164
- ca_stride_setup((CAStride *) ca, CA_OBJ_BLOCK, parent,
165
- parent->data_type, parent->bytes,
166
- ndim, count, strides,
167
- base_offset_elements * parent->bytes);
169
+ ca_stride_setup_view((CAStride *) ca, CA_OBJ_BLOCK, parent,
170
+ parent->data_type, parent->bytes,
171
+ ndim, count, strides,
172
+ base_offset_elements * parent->bytes);
168
173
 
169
174
  return 0;
170
175
  }
@@ -174,8 +179,11 @@ ca_block_new (CArray *parent, int8_t ndim, ca_size_t *dim,
174
179
  ca_size_t *start, ca_size_t *step, ca_size_t *count,
175
180
  ca_size_t offset)
176
181
  {
177
- CABlock *ca = (CABlock *) ca_array_alloc(CA_OBJ_BLOCK, ndim);
182
+ CABlock *ca;
183
+ ca_block_setup(NULL, parent, ndim, dim, start, step, count, offset);
184
+ ca = (CABlock *) ca_array_alloc(CA_OBJ_BLOCK, ndim);
178
185
  ca_block_setup(ca, parent, ndim, dim, start, step, count, offset);
186
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
179
187
  return ca;
180
188
  }
181
189
 
@@ -265,6 +273,7 @@ rb_cb_initialize_copy (VALUE self, VALUE other)
265
273
  }
266
274
  ca_block_setup(ca, cs->parent, cs->ndim, cs->size0,
267
275
  cs->start, cs->step, cs->count, cs->offset);
276
+ ca_view_inherit_mask((VALUE) ca);
268
277
  rb_ca_set_parent(self, rb_ca_parent(other));
269
278
  return self;
270
279
  }
@@ -193,7 +193,7 @@ VALUE rb_cCAByteSwap;
193
193
  int
194
194
  ca_byte_swap_setup (CAByteSwap *ca, CArray *parent, VALUE data_class)
195
195
  {
196
- CA_CHECK_DATA_TYPE(parent->data_type);
196
+ CA_CHECK_DATA_TYPE_GIVEN(parent->data_type);
197
197
 
198
198
  if ( parent->data_type == CA_OBJECT ) {
199
199
  rb_raise(rb_eCADataTypeError, "object array can't be byte-swapped");
@@ -223,9 +223,6 @@ ca_byte_swap_setup (CAByteSwap *ca, CArray *parent, VALUE data_class)
223
223
  ca->nosync = 0;
224
224
  ca->data_class = data_class; /* Qnil if parent has no data_class */
225
225
 
226
- if ( ca_has_mask(parent) ) {
227
- ca_create_mask(ca);
228
- }
229
226
  if ( ca_is_scalar(parent) ) {
230
227
  ca_set_flag(ca, CA_FLAG_SCALAR);
231
228
  }
@@ -240,6 +237,7 @@ ca_byte_swap_new (CArray *parent, VALUE data_class)
240
237
  ca_byte_swap_setup(NULL, parent, data_class);
241
238
  ca = (CAByteSwap *) ca_array_alloc(CA_OBJ_BYTE_SWAP, parent->ndim);
242
239
  ca_byte_swap_setup(ca, parent, data_class);
240
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
243
241
  return ca;
244
242
  }
245
243
 
@@ -464,7 +462,7 @@ ca_byte_swap_func_allocate (void *ap)
464
462
  {
465
463
  CAByteSwap *ca = (CAByteSwap *) ap;
466
464
  ca_attach(ca->parent);
467
- ca->ptr = xmalloc(ca_length(ca));
465
+ ca->ptr = ca_alloc_cells((CArray *) ca);
468
466
  }
469
467
 
470
468
  static void
@@ -472,7 +470,7 @@ ca_byte_swap_func_attach (void *ap)
472
470
  {
473
471
  CAByteSwap *ca = (CAByteSwap *) ap;
474
472
  ca_attach(ca->parent);
475
- ca->ptr = xmalloc(ca_length(ca));
473
+ ca->ptr = ca_alloc_cells((CArray *) ca);
476
474
  memcpy(ca->ptr, ca->parent->ptr, ca_length(ca));
477
475
  ca_byte_swap_apply(ca, ca->ptr);
478
476
  }
@@ -664,6 +662,7 @@ rb_ca_byte_swap_initialize_copy (VALUE self, VALUE other)
664
662
  ca_array_pool_alloc(ca, CA_OBJ_BYTE_SWAP, cs->parent->ndim);
665
663
  }
666
664
  ca_byte_swap_setup(ca, cs->parent, cs->data_class);
665
+ ca_view_inherit_mask((VALUE) ca);
667
666
  return self;
668
667
  }
669
668
 
@@ -31,6 +31,7 @@
31
31
  --------------------------------------------------------------------------- */
32
32
 
33
33
  #include "carray.h"
34
+ #include "ruby/util.h"
34
35
  #include "carray_internal.h"
35
36
  #include "ca_obj_face.h"
36
37
  #include <ruby/encoding.h>
@@ -122,6 +123,12 @@ ca_const_string_setup (CAConstString *ca, CArray *parent, VALUE buffer, int enco
122
123
  "(parent.data_type must be CA_FIXLEN with bytes == 16)");
123
124
  }
124
125
 
126
+ /* ca == NULL asks for the checks above only, so that a constructor can
127
+ run them before it allocates. */
128
+ if ( ca == NULL ) {
129
+ return 0;
130
+ }
131
+
125
132
  ca->obj_type = CA_OBJ_CONST_STRING;
126
133
  /* FIXLEN surface auto-gates mkkernel numeric dispatch. */
127
134
  ca->data_type = CA_FIXLEN;
@@ -143,9 +150,6 @@ ca_const_string_setup (CAConstString *ca, CArray *parent, VALUE buffer, int enco
143
150
  ca->buffer = buffer;
144
151
  ca->encoding_id = encoding_id;
145
152
 
146
- if ( ca_has_mask(parent) ) {
147
- ca_create_mask((CArray *) ca);
148
- }
149
153
 
150
154
  if ( ca_is_scalar(parent) ) {
151
155
  ca_set_flag(ca, CA_FLAG_SCALAR);
@@ -160,8 +164,11 @@ ca_const_string_setup (CAConstString *ca, CArray *parent, VALUE buffer, int enco
160
164
  CAConstString *
161
165
  ca_const_string_new (CArray *parent, VALUE buffer, int encoding_id)
162
166
  {
163
- CAConstString *ca = (CAConstString *) ca_array_alloc(CA_OBJ_CONST_STRING, parent->ndim);
167
+ CAConstString *ca;
168
+ ca_const_string_setup(NULL, parent, buffer, encoding_id);
169
+ ca = (CAConstString *) ca_array_alloc(CA_OBJ_CONST_STRING, parent->ndim);
164
170
  ca_const_string_setup(ca, parent, buffer, encoding_id);
171
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
165
172
  return ca;
166
173
  }
167
174
 
@@ -574,7 +581,9 @@ rb_ca_const_string_copy (VALUE self)
574
581
 
575
582
  ca_detach((CArray *) ca);
576
583
 
577
- return rb_ca_const_string_wrap(vout, rb_str_freeze(newbuf), ca->encoding_id);
584
+ vout = rb_ca_const_string_wrap(vout, rb_str_freeze(newbuf), ca->encoding_id);
585
+ rb_ca_inherit_attr(vout, self);
586
+ return vout;
578
587
  }
579
588
 
580
589
  /* to_ca descends to the same compacting copy. The result is detached
@@ -649,6 +658,7 @@ ca_const_string_scan_begin_pair (VALUE va, ca_const_string_scan_t *a,
649
658
  ca_const_string_scan_begin(va, a);
650
659
  x.self = vb;
651
660
  x.s = b;
661
+ /* protect: ends the first scan, which is not an array */
652
662
  rb_protect(ca_const_string_scan_begin_body, (VALUE) &x, &tag);
653
663
  if ( tag ) {
654
664
  ca_const_string_scan_end(a);
@@ -894,13 +904,12 @@ rb_ca_const_string_search (VALUE self, VALUE query)
894
904
  byte-for-byte faithful to `to_object.sort` with no collation
895
905
  loss. */
896
906
 
897
- /* qsort comparator context — single-threaded under the GVL (thread-safety is
898
- a non-goal; see project memory), so a file-static context is safe. */
899
- static ca_const_string_scan_t *ca_const_string_sort_ctx;
900
-
907
+ /* The scan is passed to the comparator, not held in a static: Ractors
908
+ sort at the same time. */
901
909
  static int
902
- ca_const_string_byte_cmp (const void *a, const void *b)
910
+ ca_const_string_byte_cmp (const void *a, const void *b, void *ctx)
903
911
  {
912
+ ca_const_string_scan_t *scan = (ca_const_string_scan_t *) ctx;
904
913
  ca_size_t ia = *(const ca_size_t *) a;
905
914
  ca_size_t ib = *(const ca_size_t *) b;
906
915
  /* sort raises on masked input, so record() always sets these here; the
@@ -908,13 +917,21 @@ ca_const_string_byte_cmp (const void *a, const void *b)
908
917
  const char *pa = NULL, *pb = NULL;
909
918
  int64_t la = 0, lb = 0;
910
919
  int c;
911
- ca_const_string_record(ca_const_string_sort_ctx, ia, &pa, &la);
912
- ca_const_string_record(ca_const_string_sort_ctx, ib, &pb, &lb);
920
+ ca_const_string_record(scan, ia, &pa, &la);
921
+ ca_const_string_record(scan, ib, &pb, &lb);
913
922
  c = memcmp(pa, pb, (size_t) (la < lb ? la : lb));
914
923
  if ( c != 0 ) return c;
915
924
  return (la > lb) - (la < lb);
916
925
  }
917
926
 
927
+ static int
928
+ ca_const_string_index_cmp (const void *a, const void *b)
929
+ {
930
+ ca_size_t ia = *(const ca_size_t *) a;
931
+ ca_size_t ib = *(const ca_size_t *) b;
932
+ return (ia > ib) - (ia < ib);
933
+ }
934
+
918
935
  /* compute the ascending sort permutation; raises on masked input (matches
919
936
  base CArray#sort). caller xfree()s the returned index array. */
920
937
  static ca_size_t *
@@ -928,9 +945,19 @@ ca_const_string_sort_perm (ca_const_string_scan_t *s)
928
945
  }
929
946
  idx = ALLOC_N(ca_size_t, s->n);
930
947
  for ( i = 0; i < s->n; i++ ) idx[i] = i;
931
- ca_const_string_sort_ctx = s;
932
- qsort(idx, (size_t) s->n, sizeof(ca_size_t), ca_const_string_byte_cmp);
933
- ca_const_string_sort_ctx = NULL;
948
+ ruby_qsort(idx, (size_t) s->n, sizeof(ca_size_t), ca_const_string_byte_cmp, s);
949
+ /* qsort is not stable. Equal strings keep their order, as CArray's own
950
+ sort does, so each run of them is put back in position order. Breaking
951
+ the tie inside the comparator instead doubles the sort on columns with
952
+ many repeats. */
953
+ for ( i = 0; i < s->n; ) {
954
+ ca_size_t j = i + 1;
955
+ while ( j < s->n && ca_const_string_byte_cmp(&idx[i], &idx[j], s) == 0 ) j++;
956
+ if ( j - i > 1 ) {
957
+ qsort(idx + i, (size_t) (j - i), sizeof(ca_size_t), ca_const_string_index_cmp);
958
+ }
959
+ i = j;
960
+ }
934
961
  return idx;
935
962
  }
936
963
 
@@ -1005,6 +1032,128 @@ ca_const_string_extremum (VALUE self, int want_max)
1005
1032
  static VALUE rb_ca_const_string_min (VALUE self) { return ca_const_string_extremum(self, 0); }
1006
1033
  static VALUE rb_ca_const_string_max (VALUE self) { return ca_const_string_extremum(self, 1); }
1007
1034
 
1035
+ /* ------------------------------------------------------------------- */
1036
+ /* Native factorize: categorize's discovery pass, read from the bytes. The
1037
+ storage cells are byte ranges, so the fixlen lane of
1038
+ CArray#__factorize_appearance__ would tell ranges apart, not strings. A
1039
+ String is made per distinct value only, after the scan's window closes. */
1040
+
1041
+ static uint64_t
1042
+ ca_const_string_hash_bytes (const char *p, int64_t len)
1043
+ {
1044
+ uint64_t h = 1469598103934665603ULL; /* FNV-1a */
1045
+ int64_t i;
1046
+ for ( i = 0; i < len; i++ ) {
1047
+ h ^= (unsigned char) p[i];
1048
+ h *= 1099511628211ULL;
1049
+ }
1050
+ return h;
1051
+ }
1052
+
1053
+ /* CAConstString#__factorize_appearance__ -> [codes, levels], as the CArray
1054
+ method answers: codes are the narrowest unsigned type holding the k codes
1055
+ and the type-max sentinel, which masked cells store; levels are the k
1056
+ distinct Strings in first-appearance order. */
1057
+ static VALUE
1058
+ rb_ca_const_string_factorize_appearance (VALUE self)
1059
+ {
1060
+ ca_const_string_scan_t s;
1061
+ CAConstString *ca;
1062
+ volatile VALUE vcodes, levels;
1063
+ CArray *co;
1064
+ uint32_t *codes, *slot;
1065
+ int64_t *lev_start, *lev_len;
1066
+ size_t cap = 16, mask_bits;
1067
+ ca_size_t n, i, k = 0;
1068
+ int8_t code_dt;
1069
+ VALUE slot_holder = 0, start_holder = 0, len_holder = 0;
1070
+
1071
+ TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
1072
+ n = ca->elements;
1073
+ if ( (uint64_t) n >= 0xFFFFFFFFULL ) {
1074
+ rb_raise(rb_eArgError, "categorize: too many elements for uint32 codes");
1075
+ }
1076
+ while ( cap < (size_t) n * 2 ) {
1077
+ cap <<= 1;
1078
+ }
1079
+ mask_bits = cap - 1;
1080
+ /* Everything the scan writes is allocated before its window opens, and
1081
+ held by the collector: opening the window reads the offsets, which
1082
+ can raise for a parent that answers in Ruby. */
1083
+ vcodes = rb_carray_new(CA_UINT32, ca->ndim, ca->dim, 0, NULL);
1084
+ TypedData_Get_Struct(vcodes, CArray, &carray_data_type, co);
1085
+ codes = (uint32_t *) co->ptr;
1086
+ slot = ALLOCV_N(uint32_t, slot_holder, cap); /* code + 1; 0 is empty */
1087
+ MEMZERO(slot, uint32_t, cap);
1088
+ lev_start = ALLOCV_N(int64_t, start_holder, n > 0 ? n : 1);
1089
+ lev_len = ALLOCV_N(int64_t, len_holder, n > 0 ? n : 1);
1090
+
1091
+ ca_const_string_scan_begin(self, &s);
1092
+ for ( i = 0; i < s.n; i++ ) {
1093
+ const char *p;
1094
+ int64_t len;
1095
+ size_t j;
1096
+ if ( ! ca_const_string_record(&s, i, &p, &len) ) {
1097
+ codes[i] = 0xFFFFFFFFu;
1098
+ continue;
1099
+ }
1100
+ j = (size_t) ca_const_string_hash_bytes(p, len) & mask_bits;
1101
+ for (;;) {
1102
+ uint32_t c = slot[j];
1103
+ if ( c == 0 ) {
1104
+ lev_start[k] = (int64_t) (p - s.buf);
1105
+ lev_len[k] = len;
1106
+ slot[j] = (uint32_t) (k + 1);
1107
+ codes[i] = (uint32_t) k;
1108
+ k++;
1109
+ break;
1110
+ }
1111
+ if ( lev_len[c - 1] == len && memcmp(s.buf + lev_start[c - 1], p, (size_t) len) == 0 ) {
1112
+ codes[i] = c - 1;
1113
+ break;
1114
+ }
1115
+ j = (j + 1) & mask_bits;
1116
+ }
1117
+ }
1118
+ ca_const_string_scan_end(&s);
1119
+ ALLOCV_END(slot_holder);
1120
+
1121
+ /* The buffer is the column's frozen String, alive past the window. */
1122
+ levels = rb_ary_new_capa(k);
1123
+ {
1124
+ const char *buf = RSTRING_PTR(ca->buffer);
1125
+ rb_encoding *enc = rb_enc_from_index(ca->encoding_id);
1126
+ for ( i = 0; i < k; i++ ) {
1127
+ rb_ary_push(levels, rb_enc_str_new(buf + lev_start[i], lev_len[i], enc));
1128
+ }
1129
+ }
1130
+ ALLOCV_END(start_holder);
1131
+ ALLOCV_END(len_holder);
1132
+
1133
+ if ( k <= 0xFF ) { code_dt = CA_UINT8; }
1134
+ else if ( k <= 0xFFFF ) { code_dt = CA_UINT16; }
1135
+ else { code_dt = CA_UINT32; }
1136
+ if ( code_dt != CA_UINT32 ) {
1137
+ VALUE vnarrow = rb_carray_new(code_dt, ca->ndim, ca->dim, 0, NULL);
1138
+ CArray *cn;
1139
+ TypedData_Get_Struct(vnarrow, CArray, &carray_data_type, cn);
1140
+ if ( code_dt == CA_UINT8 ) {
1141
+ uint8_t *cp = (uint8_t *) cn->ptr;
1142
+ for ( i = 0; i < n; i++ ) {
1143
+ cp[i] = codes[i] == 0xFFFFFFFFu ? (uint8_t) 0xFF : (uint8_t) codes[i];
1144
+ }
1145
+ }
1146
+ else {
1147
+ uint16_t *cp = (uint16_t *) cn->ptr;
1148
+ for ( i = 0; i < n; i++ ) {
1149
+ cp[i] = codes[i] == 0xFFFFFFFFu ? (uint16_t) 0xFFFF : (uint16_t) codes[i];
1150
+ }
1151
+ }
1152
+ vcodes = vnarrow;
1153
+ }
1154
+ return rb_ary_new3(2, vcodes, levels);
1155
+ }
1156
+
1008
1157
  /* ------------------------------------------------------------------- */
1009
1158
 
1010
1159
  static VALUE
@@ -1028,6 +1177,7 @@ rb_ca_const_string_initialize_copy (VALUE self, VALUE other)
1028
1177
  ca_array_pool_alloc(ca, CA_OBJ_CONST_STRING, cs->parent->ndim);
1029
1178
  }
1030
1179
  ca_const_string_setup(ca, cs->parent, cs->buffer, cs->encoding_id);
1180
+ ca_view_inherit_mask((VALUE) ca);
1031
1181
  return self;
1032
1182
  }
1033
1183
 
@@ -1080,10 +1230,14 @@ Init_ca_obj_const_string (void)
1080
1230
  /* Native flat sort permutation / min / max (§3.7), byte-memcmp
1081
1231
  comparator. The public ordering surface is built on these in
1082
1232
  lib/carray/const_string.rb; see the comment above their definitions. */
1083
- rb_define_method(rb_cCAConstString, "__sort_addr_bytes__",
1084
- rb_ca_const_string_sort_index, 0);
1085
- rb_define_method(rb_cCAConstString, "__min_bytes__", rb_ca_const_string_min, 0);
1086
- rb_define_method(rb_cCAConstString, "__max_bytes__", rb_ca_const_string_max, 0);
1233
+ rb_define_private_method(rb_cCAConstString, "sort_addr_by_bytes",
1234
+ rb_ca_const_string_sort_index, 0);
1235
+ rb_define_private_method(rb_cCAConstString, "min_string_by_bytes",
1236
+ rb_ca_const_string_min, 0);
1237
+ rb_define_private_method(rb_cCAConstString, "__factorize_appearance__",
1238
+ rb_ca_const_string_factorize_appearance, 0);
1239
+ rb_define_private_method(rb_cCAConstString, "max_string_by_bytes",
1240
+ rb_ca_const_string_max, 0);
1087
1241
 
1088
1242
  /* Y-pilot: Face-local C-level fast path for per-cell scalar fetch. */
1089
1243
  ca_face_register_storage_to_element(CA_OBJ_CONST_STRING, rb_ca_const_string_storage_to_element);