carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
@@ -193,10 +193,11 @@ 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
- rb_raise(rb_eCADataTypeError, "object array can't be byte-swapped");
199
+ rb_raise(rb_eCADataTypeError, "%s: an object array can't be byte-swapped",
200
+ ca_calling_method_name());
200
201
  }
201
202
 
202
203
  /* ca == NULL asks for the checks above only, so that a constructor can
@@ -223,9 +224,6 @@ ca_byte_swap_setup (CAByteSwap *ca, CArray *parent, VALUE data_class)
223
224
  ca->nosync = 0;
224
225
  ca->data_class = data_class; /* Qnil if parent has no data_class */
225
226
 
226
- if ( ca_has_mask(parent) ) {
227
- ca_create_mask(ca);
228
- }
229
227
  if ( ca_is_scalar(parent) ) {
230
228
  ca_set_flag(ca, CA_FLAG_SCALAR);
231
229
  }
@@ -240,6 +238,7 @@ ca_byte_swap_new (CArray *parent, VALUE data_class)
240
238
  ca_byte_swap_setup(NULL, parent, data_class);
241
239
  ca = (CAByteSwap *) ca_array_alloc(CA_OBJ_BYTE_SWAP, parent->ndim);
242
240
  ca_byte_swap_setup(ca, parent, data_class);
241
+ ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
243
242
  return ca;
244
243
  }
245
244
 
@@ -464,7 +463,7 @@ ca_byte_swap_func_allocate (void *ap)
464
463
  {
465
464
  CAByteSwap *ca = (CAByteSwap *) ap;
466
465
  ca_attach(ca->parent);
467
- ca->ptr = xmalloc(ca_length(ca));
466
+ ca->ptr = ca_alloc_cells((CArray *) ca);
468
467
  }
469
468
 
470
469
  static void
@@ -472,7 +471,7 @@ ca_byte_swap_func_attach (void *ap)
472
471
  {
473
472
  CAByteSwap *ca = (CAByteSwap *) ap;
474
473
  ca_attach(ca->parent);
475
- ca->ptr = xmalloc(ca_length(ca));
474
+ ca->ptr = ca_alloc_cells((CArray *) ca);
476
475
  memcpy(ca->ptr, ca->parent->ptr, ca_length(ca));
477
476
  ca_byte_swap_apply(ca, ca->ptr);
478
477
  }
@@ -664,6 +663,7 @@ rb_ca_byte_swap_initialize_copy (VALUE self, VALUE other)
664
663
  ca_array_pool_alloc(ca, CA_OBJ_BYTE_SWAP, cs->parent->ndim);
665
664
  }
666
665
  ca_byte_swap_setup(ca, cs->parent, cs->data_class);
666
+ ca_view_inherit_mask((VALUE) ca);
667
667
  return self;
668
668
  }
669
669
 
@@ -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);
@@ -827,19 +837,31 @@ rb_ca_const_string_eq (VALUE self, VALUE other)
827
837
  ca_const_string_scan_end(&b);
828
838
  return vout;
829
839
  }
840
+ /* Another array is compared cell by cell as Strings, where a CAString
841
+ reconciles it (an object array of Strings, a fixlen or a CAString). */
842
+ if ( rb_obj_is_carray(other) ) {
843
+ return rb_funcall(rb_ca_const_string_to_string(self), rb_intern("eq"), 1,
844
+ other);
845
+ }
830
846
  return ca_const_string_predicate(self, other, CA_TEXT_EQ);
831
847
  }
832
848
 
833
- /* CAConstString#count(value): number of (non-masked) elements byte-equal to value. */
849
+ /* CAConstString#count(value): number of (non-masked) elements byte-equal to
850
+ value. With no value, the number of non-masked elements, as CArray#count
851
+ answers. */
834
852
  static VALUE
835
- rb_ca_const_string_count (VALUE self, VALUE query)
853
+ rb_ca_const_string_count (int argc, VALUE *argv, VALUE self)
836
854
  {
837
855
  ca_const_string_scan_t s;
838
856
  const char *qp, *p;
839
857
  long qlen;
840
858
  int64_t len;
841
859
  ca_size_t i, c = 0;
860
+ VALUE query;
842
861
 
862
+ if ( rb_scan_args(argc, argv, "01", &query) == 0 ) {
863
+ return rb_funcall(self, rb_intern("count_not_masked"), 0);
864
+ }
843
865
  if ( TYPE(query) != T_STRING ) {
844
866
  query = rb_obj_as_string(query);
845
867
  }
@@ -894,13 +916,12 @@ rb_ca_const_string_search (VALUE self, VALUE query)
894
916
  byte-for-byte faithful to `to_object.sort` with no collation
895
917
  loss. */
896
918
 
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
-
919
+ /* The scan is passed to the comparator, not held in a static: Ractors
920
+ sort at the same time. */
901
921
  static int
902
- ca_const_string_byte_cmp (const void *a, const void *b)
922
+ ca_const_string_byte_cmp (const void *a, const void *b, void *ctx)
903
923
  {
924
+ ca_const_string_scan_t *scan = (ca_const_string_scan_t *) ctx;
904
925
  ca_size_t ia = *(const ca_size_t *) a;
905
926
  ca_size_t ib = *(const ca_size_t *) b;
906
927
  /* sort raises on masked input, so record() always sets these here; the
@@ -908,13 +929,21 @@ ca_const_string_byte_cmp (const void *a, const void *b)
908
929
  const char *pa = NULL, *pb = NULL;
909
930
  int64_t la = 0, lb = 0;
910
931
  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);
932
+ ca_const_string_record(scan, ia, &pa, &la);
933
+ ca_const_string_record(scan, ib, &pb, &lb);
913
934
  c = memcmp(pa, pb, (size_t) (la < lb ? la : lb));
914
935
  if ( c != 0 ) return c;
915
936
  return (la > lb) - (la < lb);
916
937
  }
917
938
 
939
+ static int
940
+ ca_const_string_index_cmp (const void *a, const void *b)
941
+ {
942
+ ca_size_t ia = *(const ca_size_t *) a;
943
+ ca_size_t ib = *(const ca_size_t *) b;
944
+ return (ia > ib) - (ia < ib);
945
+ }
946
+
918
947
  /* compute the ascending sort permutation; raises on masked input (matches
919
948
  base CArray#sort). caller xfree()s the returned index array. */
920
949
  static ca_size_t *
@@ -928,9 +957,19 @@ ca_const_string_sort_perm (ca_const_string_scan_t *s)
928
957
  }
929
958
  idx = ALLOC_N(ca_size_t, s->n);
930
959
  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;
960
+ ruby_qsort(idx, (size_t) s->n, sizeof(ca_size_t), ca_const_string_byte_cmp, s);
961
+ /* qsort is not stable. Equal strings keep their order, as CArray's own
962
+ sort does, so each run of them is put back in position order. Breaking
963
+ the tie inside the comparator instead doubles the sort on columns with
964
+ many repeats. */
965
+ for ( i = 0; i < s->n; ) {
966
+ ca_size_t j = i + 1;
967
+ while ( j < s->n && ca_const_string_byte_cmp(&idx[i], &idx[j], s) == 0 ) j++;
968
+ if ( j - i > 1 ) {
969
+ qsort(idx + i, (size_t) (j - i), sizeof(ca_size_t), ca_const_string_index_cmp);
970
+ }
971
+ i = j;
972
+ }
934
973
  return idx;
935
974
  }
936
975
 
@@ -1005,6 +1044,128 @@ ca_const_string_extremum (VALUE self, int want_max)
1005
1044
  static VALUE rb_ca_const_string_min (VALUE self) { return ca_const_string_extremum(self, 0); }
1006
1045
  static VALUE rb_ca_const_string_max (VALUE self) { return ca_const_string_extremum(self, 1); }
1007
1046
 
1047
+ /* ------------------------------------------------------------------- */
1048
+ /* Native factorize: categorize's discovery pass, read from the bytes. The
1049
+ storage cells are byte ranges, so the fixlen lane of
1050
+ CArray#__factorize_appearance__ would tell ranges apart, not strings. A
1051
+ String is made per distinct value only, after the scan's window closes. */
1052
+
1053
+ static uint64_t
1054
+ ca_const_string_hash_bytes (const char *p, int64_t len)
1055
+ {
1056
+ uint64_t h = 1469598103934665603ULL; /* FNV-1a */
1057
+ int64_t i;
1058
+ for ( i = 0; i < len; i++ ) {
1059
+ h ^= (unsigned char) p[i];
1060
+ h *= 1099511628211ULL;
1061
+ }
1062
+ return h;
1063
+ }
1064
+
1065
+ /* CAConstString#__factorize_appearance__ -> [codes, levels], as the CArray
1066
+ method answers: codes are the narrowest unsigned type holding the k codes
1067
+ and the type-max sentinel, which masked cells store; levels are the k
1068
+ distinct Strings in first-appearance order. */
1069
+ static VALUE
1070
+ rb_ca_const_string_factorize_appearance (VALUE self)
1071
+ {
1072
+ ca_const_string_scan_t s;
1073
+ CAConstString *ca;
1074
+ volatile VALUE vcodes, levels;
1075
+ CArray *co;
1076
+ uint32_t *codes, *slot;
1077
+ int64_t *lev_start, *lev_len;
1078
+ size_t cap = 16, mask_bits;
1079
+ ca_size_t n, i, k = 0;
1080
+ int8_t code_dt;
1081
+ VALUE slot_holder = 0, start_holder = 0, len_holder = 0;
1082
+
1083
+ TypedData_Get_Struct(self, CAConstString, &catext_data_type, ca);
1084
+ n = ca->elements;
1085
+ if ( (uint64_t) n >= 0xFFFFFFFFULL ) {
1086
+ rb_raise(rb_eArgError, "categorize: too many elements for uint32 codes");
1087
+ }
1088
+ while ( cap < (size_t) n * 2 ) {
1089
+ cap <<= 1;
1090
+ }
1091
+ mask_bits = cap - 1;
1092
+ /* Everything the scan writes is allocated before its window opens, and
1093
+ held by the collector: opening the window reads the offsets, which
1094
+ can raise for a parent that answers in Ruby. */
1095
+ vcodes = rb_carray_new(CA_UINT32, ca->ndim, ca->dim, 0, NULL);
1096
+ TypedData_Get_Struct(vcodes, CArray, &carray_data_type, co);
1097
+ codes = (uint32_t *) co->ptr;
1098
+ slot = ALLOCV_N(uint32_t, slot_holder, cap); /* code + 1; 0 is empty */
1099
+ MEMZERO(slot, uint32_t, cap);
1100
+ lev_start = ALLOCV_N(int64_t, start_holder, n > 0 ? n : 1);
1101
+ lev_len = ALLOCV_N(int64_t, len_holder, n > 0 ? n : 1);
1102
+
1103
+ ca_const_string_scan_begin(self, &s);
1104
+ for ( i = 0; i < s.n; i++ ) {
1105
+ const char *p;
1106
+ int64_t len;
1107
+ size_t j;
1108
+ if ( ! ca_const_string_record(&s, i, &p, &len) ) {
1109
+ codes[i] = 0xFFFFFFFFu;
1110
+ continue;
1111
+ }
1112
+ j = (size_t) ca_const_string_hash_bytes(p, len) & mask_bits;
1113
+ for (;;) {
1114
+ uint32_t c = slot[j];
1115
+ if ( c == 0 ) {
1116
+ lev_start[k] = (int64_t) (p - s.buf);
1117
+ lev_len[k] = len;
1118
+ slot[j] = (uint32_t) (k + 1);
1119
+ codes[i] = (uint32_t) k;
1120
+ k++;
1121
+ break;
1122
+ }
1123
+ if ( lev_len[c - 1] == len && memcmp(s.buf + lev_start[c - 1], p, (size_t) len) == 0 ) {
1124
+ codes[i] = c - 1;
1125
+ break;
1126
+ }
1127
+ j = (j + 1) & mask_bits;
1128
+ }
1129
+ }
1130
+ ca_const_string_scan_end(&s);
1131
+ ALLOCV_END(slot_holder);
1132
+
1133
+ /* The buffer is the column's frozen String, alive past the window. */
1134
+ levels = rb_ary_new_capa(k);
1135
+ {
1136
+ const char *buf = RSTRING_PTR(ca->buffer);
1137
+ rb_encoding *enc = rb_enc_from_index(ca->encoding_id);
1138
+ for ( i = 0; i < k; i++ ) {
1139
+ rb_ary_push(levels, rb_enc_str_new(buf + lev_start[i], lev_len[i], enc));
1140
+ }
1141
+ }
1142
+ ALLOCV_END(start_holder);
1143
+ ALLOCV_END(len_holder);
1144
+
1145
+ if ( k <= 0xFF ) { code_dt = CA_UINT8; }
1146
+ else if ( k <= 0xFFFF ) { code_dt = CA_UINT16; }
1147
+ else { code_dt = CA_UINT32; }
1148
+ if ( code_dt != CA_UINT32 ) {
1149
+ VALUE vnarrow = rb_carray_new(code_dt, ca->ndim, ca->dim, 0, NULL);
1150
+ CArray *cn;
1151
+ TypedData_Get_Struct(vnarrow, CArray, &carray_data_type, cn);
1152
+ if ( code_dt == CA_UINT8 ) {
1153
+ uint8_t *cp = (uint8_t *) cn->ptr;
1154
+ for ( i = 0; i < n; i++ ) {
1155
+ cp[i] = codes[i] == 0xFFFFFFFFu ? (uint8_t) 0xFF : (uint8_t) codes[i];
1156
+ }
1157
+ }
1158
+ else {
1159
+ uint16_t *cp = (uint16_t *) cn->ptr;
1160
+ for ( i = 0; i < n; i++ ) {
1161
+ cp[i] = codes[i] == 0xFFFFFFFFu ? (uint16_t) 0xFFFF : (uint16_t) codes[i];
1162
+ }
1163
+ }
1164
+ vcodes = vnarrow;
1165
+ }
1166
+ return rb_ary_new3(2, vcodes, levels);
1167
+ }
1168
+
1008
1169
  /* ------------------------------------------------------------------- */
1009
1170
 
1010
1171
  static VALUE
@@ -1028,6 +1189,7 @@ rb_ca_const_string_initialize_copy (VALUE self, VALUE other)
1028
1189
  ca_array_pool_alloc(ca, CA_OBJ_CONST_STRING, cs->parent->ndim);
1029
1190
  }
1030
1191
  ca_const_string_setup(ca, cs->parent, cs->buffer, cs->encoding_id);
1192
+ ca_view_inherit_mask((VALUE) ca);
1031
1193
  return self;
1032
1194
  }
1033
1195
 
@@ -1066,7 +1228,7 @@ Init_ca_obj_const_string (void)
1066
1228
  /* native byte ops (§3.7) */
1067
1229
  rb_define_method(rb_cCAConstString, "byte_length", rb_ca_const_string_byte_length, 0);
1068
1230
  rb_define_method(rb_cCAConstString, "eq", rb_ca_const_string_eq, 1);
1069
- rb_define_method(rb_cCAConstString, "count", rb_ca_const_string_count, 1);
1231
+ rb_define_method(rb_cCAConstString, "count", rb_ca_const_string_count, -1);
1070
1232
  rb_define_method(rb_cCAConstString, "start_with?", rb_ca_const_string_start_with, 1);
1071
1233
  rb_define_method(rb_cCAConstString, "end_with?", rb_ca_const_string_end_with, 1);
1072
1234
  rb_define_method(rb_cCAConstString, "include?", rb_ca_const_string_include, 1);
@@ -1080,10 +1242,14 @@ Init_ca_obj_const_string (void)
1080
1242
  /* Native flat sort permutation / min / max (§3.7), byte-memcmp
1081
1243
  comparator. The public ordering surface is built on these in
1082
1244
  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);
1245
+ rb_define_private_method(rb_cCAConstString, "sort_addr_by_bytes",
1246
+ rb_ca_const_string_sort_index, 0);
1247
+ rb_define_private_method(rb_cCAConstString, "min_string_by_bytes",
1248
+ rb_ca_const_string_min, 0);
1249
+ rb_define_private_method(rb_cCAConstString, "__factorize_appearance__",
1250
+ rb_ca_const_string_factorize_appearance, 0);
1251
+ rb_define_private_method(rb_cCAConstString, "max_string_by_bytes",
1252
+ rb_ca_const_string_max, 0);
1087
1253
 
1088
1254
  /* Y-pilot: Face-local C-level fast path for per-cell scalar fetch. */
1089
1255
  ca_face_register_storage_to_element(CA_OBJ_CONST_STRING, rb_ca_const_string_storage_to_element);