carray 3.0.6 → 3.0.7

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +110 -0
  3. data/README.md +24 -3
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_group.c +6 -6
  6. data/ext/ca_binop_dispatch.c +8 -0
  7. data/ext/ca_binop_dispatch.h +1 -0
  8. data/ext/ca_categorical_iterator.c +7 -7
  9. data/ext/ca_kernel_iterator.h +6 -4
  10. data/ext/ca_obj_array.c +4 -4
  11. data/ext/ca_obj_bincmp.c +19 -3
  12. data/ext/ca_obj_binop.c +36 -11
  13. data/ext/ca_obj_bitarray.c +2 -4
  14. data/ext/ca_obj_bitfield.c +86 -4
  15. data/ext/ca_obj_byte_swap.c +2 -4
  16. data/ext/ca_obj_const_string.c +422 -257
  17. data/ext/ca_obj_face.c +71 -33
  18. data/ext/ca_obj_fake.c +112 -13
  19. data/ext/ca_obj_farray.c +7 -1
  20. data/ext/ca_obj_fixlen_string.c +51 -17
  21. data/ext/ca_obj_grid.c +12 -7
  22. data/ext/ca_obj_meld.c +5 -5
  23. data/ext/ca_obj_monop.c +65 -39
  24. data/ext/ca_obj_object.c +9 -9
  25. data/ext/ca_obj_reduce.c +2 -4
  26. data/ext/ca_obj_refer.c +104 -10
  27. data/ext/ca_obj_repeat.c +1 -1
  28. data/ext/ca_obj_roll.c +2 -4
  29. data/ext/ca_obj_select.c +8 -6
  30. data/ext/ca_obj_select_axis.c +8 -6
  31. data/ext/ca_obj_stack.c +5 -5
  32. data/ext/ca_obj_stride.c +46 -8
  33. data/ext/ca_obj_string.c +2 -2
  34. data/ext/ca_obj_tile.c +2 -4
  35. data/ext/ca_obj_triop.c +15 -12
  36. data/ext/ca_obj_window.c +22 -15
  37. data/ext/ca_op_ipower.c +63 -15
  38. data/ext/ca_op_powi.h +6 -29
  39. data/ext/ca_sort_kernels.h +3 -0
  40. data/ext/ca_sweep_engine.c +90 -23
  41. data/ext/ca_sweep_engine.h +5 -6
  42. data/ext/caframe_csv_reader.c +1 -1
  43. data/ext/carray.h +3 -1
  44. data/ext/carray_access.c +98 -39
  45. data/ext/carray_address_basis.c +98 -24
  46. data/ext/carray_broadcast.c +2 -2
  47. data/ext/carray_call_cfunc.c +5 -8
  48. data/ext/carray_cast.c +311 -37
  49. data/ext/carray_cast_func.rb +37 -5
  50. data/ext/carray_conversion.c +56 -2
  51. data/ext/carray_copy.c +24 -0
  52. data/ext/carray_core.c +69 -6
  53. data/ext/carray_count.c +28 -9
  54. data/ext/carray_element.c +9 -3
  55. data/ext/carray_factorize.c +11 -11
  56. data/ext/carray_histogram.c +2 -2
  57. data/ext/carray_index_classifier.c +7 -5
  58. data/ext/carray_internal.h +94 -0
  59. data/ext/carray_kernels_binop.c +55 -55
  60. data/ext/carray_kernels_init.c +14 -14
  61. data/ext/carray_kernels_monop.c +90 -140
  62. data/ext/carray_lazy.c +16 -1
  63. data/ext/carray_loop.c +9 -2
  64. data/ext/carray_mask.c +118 -11
  65. data/ext/carray_median_percentile.c +13 -8
  66. data/ext/carray_memory_view.c +41 -22
  67. data/ext/carray_operator.c +72 -11
  68. data/ext/carray_order.c +52 -9
  69. data/ext/carray_partition.c +1 -1
  70. data/ext/carray_random.c +1 -1
  71. data/ext/carray_round.c +24 -1
  72. data/ext/carray_scatter.c +4 -0
  73. data/ext/carray_segment.c +1 -1
  74. data/ext/carray_slab.c +13 -4
  75. data/ext/carray_sort.c +6 -3
  76. data/ext/carray_sort_kernel.c +24 -0
  77. data/ext/carray_struct.c +21 -6
  78. data/ext/carray_test.c +85 -39
  79. data/ext/carray_time_text.c +6 -0
  80. data/ext/carray_utils.c +124 -54
  81. data/ext/mk_call_cfunc.rb +6 -11
  82. data/ext/mkkernel.rb +37 -27
  83. data/ext/version.h +4 -4
  84. data/lib/carray/axis_group.rb +9 -6
  85. data/lib/carray/basics.rb +26 -8
  86. data/lib/carray/bincount_nd.rb +8 -2
  87. data/lib/carray/block_iterator.rb +48 -21
  88. data/lib/carray/categorical.rb +21 -8
  89. data/lib/carray/categorical_iterator.rb +2 -1
  90. data/lib/carray/conditional.rb +52 -4
  91. data/lib/carray/const_string.rb +74 -0
  92. data/lib/carray/construct.rb +2 -2
  93. data/lib/carray/core_extensions.rb +19 -68
  94. data/lib/carray/data_type_extension.rb +1 -0
  95. data/lib/carray/fixlen_string.rb +83 -1
  96. data/lib/carray/frame/column_verbs.rb +61 -6
  97. data/lib/carray/frame/concat.rb +50 -6
  98. data/lib/carray/frame/csv_parser.rb +13 -4
  99. data/lib/carray/frame/frame.rb +38 -6
  100. data/lib/carray/frame/group.rb +67 -40
  101. data/lib/carray/frame/io.rb +10 -5
  102. data/lib/carray/frame/join.rb +20 -6
  103. data/lib/carray/frame/records.rb +6 -4
  104. data/lib/carray/frame/reshape.rb +25 -5
  105. data/lib/carray/frame/verbs.rb +78 -25
  106. data/lib/carray/frame/windows.rb +30 -6
  107. data/lib/carray/fuse_source.rb +4 -2
  108. data/lib/carray/iterator.rb +8 -0
  109. data/lib/carray/key_windows.rb +10 -4
  110. data/lib/carray/lazy.rb +12 -17
  111. data/lib/carray/methods/bin.rb +3 -0
  112. data/lib/carray/methods/composition.rb +1 -1
  113. data/lib/carray/methods/factorize.rb +2 -0
  114. data/lib/carray/methods/gather_nd.rb +4 -1
  115. data/lib/carray/methods/is_in.rb +23 -3
  116. data/lib/carray/methods/locate_addr.rb +63 -12
  117. data/lib/carray/methods/repeat.rb +11 -1
  118. data/lib/carray/record_order.rb +35 -6
  119. data/lib/carray/runtime.rb +10 -0
  120. data/lib/carray/segment_iterator.rb +19 -16
  121. data/lib/carray/serialize.rb +22 -0
  122. data/lib/carray/slab_iterator.rb +1 -1
  123. data/lib/carray/stack.rb +3 -3
  124. data/lib/carray/string.rb +6 -6
  125. data/lib/carray/string_operation_extension.rb +25 -4
  126. data/lib/carray/struct_builder.rb +4 -1
  127. data/lib/carray/time.rb +190 -46
  128. data/lib/carray/window_iterator.rb +48 -12
  129. data/yard-stubs/ca_obj_bitfield.rb +4 -1
  130. data/yard-stubs/ca_obj_refer.rb +3 -0
  131. data/yard-stubs/ca_obj_window.rb +2 -1
  132. data/yard-stubs/carray_access.rb +4 -2
  133. data/yard-stubs/carray_cast.rb +6 -0
  134. data/yard-stubs/carray_count.rb +6 -3
  135. data/yard-stubs/carray_math.rb +5 -0
  136. data/yard-stubs/carray_order.rb +6 -0
  137. data/yard-stubs/carray_scatter.rb +2 -1
  138. data/yard-stubs/carray_test.rb +18 -5
  139. metadata +2 -2
@@ -195,6 +195,23 @@ ca_to_a_universal (VALUE arg)
195
195
  return Qnil;
196
196
  }
197
197
 
198
+ /* An array with no cells still has the nesting of its axes up to the first
199
+ zero-length one: (3, 0) is three empty rows, (2, 0, 4) two empty rows. */
200
+ static VALUE
201
+ ca_to_a_empty_nesting (CArray *ca, int32_t level)
202
+ {
203
+ volatile VALUE ary;
204
+ ca_size_t i;
205
+
206
+ ary = rb_ary_new2(ca->dim[level]);
207
+ if ( level < ca->ndim - 1 ) {
208
+ for (i=0; i<ca->dim[level]; i++) {
209
+ rb_ary_store(ary, i, ca_to_a_empty_nesting(ca, level + 1));
210
+ }
211
+ }
212
+ return ary;
213
+ }
214
+
198
215
  VALUE
199
216
  rb_ca_to_a (VALUE self)
200
217
  {
@@ -203,6 +220,9 @@ rb_ca_to_a (VALUE self)
203
220
  int data_type, fast_eligible;
204
221
 
205
222
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
223
+ if ( ca->elements == 0 && ca->ndim > 0 ) {
224
+ return ca_to_a_empty_nesting(ca, 0);
225
+ }
206
226
  ary = rb_ca_is_empty(self) ? rb_ary_new() : rb_ary_new2(ca->dim[0]);
207
227
 
208
228
  /* Once attached, ca->ptr is a contig row-major buffer (alias for
@@ -375,6 +395,28 @@ rb_ca_convert (int argc, VALUE *argv, VALUE self)
375
395
  return obj;
376
396
  }
377
397
 
398
+ /* The transfer of dump_binary into a String. The String is locked while
399
+ the bytes go in: a view that runs Ruby to make its cells (a CAObject)
400
+ could otherwise resize it under the pointer being written. */
401
+ typedef struct {
402
+ CArray *ca;
403
+ VALUE io;
404
+ } ca_dump_into_string_t;
405
+
406
+ static VALUE
407
+ ca_dump_into_string_body (VALUE arg)
408
+ {
409
+ ca_dump_into_string_t *d = (ca_dump_into_string_t *) arg;
410
+ ca_copy_data(d->ca, RSTRING_PTR(d->io));
411
+ return Qnil;
412
+ }
413
+
414
+ static VALUE
415
+ ca_dump_into_string_unlock (VALUE io)
416
+ {
417
+ return rb_str_unlocktmp(io);
418
+ }
419
+
378
420
  /* CArray#dump_binary([io]) — write self's raw element bytes to io in
379
421
  * row-major order.
380
422
  *
@@ -411,7 +453,17 @@ rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
411
453
  if ( ca_length(ca) != RSTRING_LEN(io) ) {
412
454
  rb_str_resize(io, ca_length(ca));
413
455
  }
414
- ca_copy_data(ca, RSTRING_PTR(io));
456
+ /* the bytes are written behind Ruby's back: drop the cached code
457
+ range, or the string keeps answering 7-bit for any contents */
458
+ rb_str_modify(io);
459
+ {
460
+ ca_dump_into_string_t d;
461
+ d.ca = ca;
462
+ d.io = io;
463
+ rb_str_locktmp(io);
464
+ rb_ensure(ca_dump_into_string_body, (VALUE) &d,
465
+ ca_dump_into_string_unlock, io);
466
+ }
415
467
  break;
416
468
  case T_FILE: {
417
469
  rb_io_t *iop;
@@ -487,8 +539,10 @@ rb_ca_load_binary (VALUE self, VALUE io)
487
539
  "%s: data size mismatch (got %" PRId64 " bytes, expected %" PRId64 ")",
488
540
  ca_calling_method_name(), (ca_size_t) RSTRING_LEN(io), (ca_size_t) ca_length(ca));
489
541
  }
542
+ /* A copy shares the bytes until either side changes: a view that runs
543
+ Ruby while it stores (a CAObject) cannot then move them. */
544
+ io = rb_str_dup(io);
490
545
  if ( ca->data_type == CA_BOOLEAN ) {
491
- io = rb_str_dup(io);
492
546
  rb_str_modify(io);
493
547
  ca_boolean_normalize_bytes(RSTRING_PTR(io), ca->elements);
494
548
  }
data/ext/carray_copy.c CHANGED
@@ -61,6 +61,30 @@ ca_fill_or_detach (int n, CArray **list, VALUE (*fill)(VALUE), VALUE arg)
61
61
  }
62
62
  }
63
63
 
64
+ typedef struct {
65
+ CArray **list;
66
+ int32_t n;
67
+ } ca_attach_list_arg;
68
+
69
+ static VALUE
70
+ ca_attach_list_fill (VALUE arg)
71
+ {
72
+ ca_attach_list_arg *a = (ca_attach_list_arg *) arg;
73
+ ca_attach_all(a->list, a->n);
74
+ return Qnil;
75
+ }
76
+
77
+ char *
78
+ ca_alloc_cells_then_attach (CArray *ca, int32_t n, CArray **parents)
79
+ {
80
+ char *buf = ca_alloc_cells(ca);
81
+ ca_attach_list_arg a;
82
+ a.list = parents;
83
+ a.n = n;
84
+ ca_fill_or_xfree(buf, ca_attach_list_fill, (VALUE) &a);
85
+ return buf;
86
+ }
87
+
64
88
  VALUE
65
89
  ca_view_inherit_mask (VALUE view)
66
90
  {
data/ext/carray_core.c CHANGED
@@ -954,15 +954,29 @@ ca_refuse_cells_reaching_evaluation (ca_size_t n, const VALUE *cells)
954
954
  }
955
955
  }
956
956
 
957
+ static VALUE
958
+ ca_computing_start (VALUE arg)
959
+ {
960
+ return ca_computing_next((ca_computing_t *) arg);
961
+ }
962
+
957
963
  /* Runs body(arg), a computation over ops[0..n), with each object array
958
964
  among them recorded as computed over. Raises when one of them is
959
965
  already being computed over by the same method: a cell's value, or an
960
- element's operation, led the computation back into it. */
966
+ element's operation, led the computation back into it. A computation
967
+ over object cells calls methods of the cells, so it counts as a walk into
968
+ them (ca_cell_walk_run). */
961
969
  VALUE
962
970
  ca_computing_run (int n, CArray **ops, VALUE (*body)(VALUE), VALUE arg)
963
971
  {
964
972
  ca_computing_t c;
973
+ int k;
965
974
  c.n = n; c.ops = ops; c.kind = CA_RECURSION_COMPUTE; c.k = 0; c.body = body; c.arg = arg;
975
+ for (k=0; k<n; k++) {
976
+ if ( ops[k] && ca_is_object_type(ops[k]) ) {
977
+ return ca_cell_walk_run(ca_computing_start, (VALUE) &c);
978
+ }
979
+ }
966
980
  return ca_computing_next(&c);
967
981
  }
968
982
 
@@ -985,6 +999,55 @@ ca_recursion_probe (VALUE key, VALUE arg, int recursive)
985
999
  return recursive ? Qtrue : Qfalse;
986
1000
  }
987
1001
 
1002
+ /* A walk into the cells of an object array (#hash, #==, a nested dump) goes
1003
+ on into any array it finds there. An array holding itself is found by
1004
+ the records above, but a cell can also give a new array each time it is
1005
+ opened (a lazy expression over an array that holds it), and then the walk
1006
+ never meets an array it has seen. So the depth of these walks is
1007
+ limited. It is counted for each fiber, not in the arrays. */
1008
+
1009
+ #define CA_CELL_NESTING_MAX 256
1010
+
1011
+ typedef struct {
1012
+ VALUE thread;
1013
+ VALUE before;
1014
+ } ca_cell_nesting_t;
1015
+
1016
+ static VALUE
1017
+ ca_cell_nesting_leave (VALUE varg)
1018
+ {
1019
+ ca_cell_nesting_t *t = (ca_cell_nesting_t *) varg;
1020
+ rb_thread_local_aset(t->thread, rb_intern("carray_cell_nesting"), t->before);
1021
+ return Qnil;
1022
+ }
1023
+
1024
+ VALUE
1025
+ ca_cell_walk_run (VALUE (*body)(VALUE), VALUE arg)
1026
+ {
1027
+ ca_cell_nesting_t t;
1028
+ long depth;
1029
+
1030
+ t.thread = rb_thread_current();
1031
+ if ( OBJ_FROZEN(t.thread) ) { /* it can not hold the count */
1032
+ return body(arg);
1033
+ }
1034
+ t.before = rb_thread_local_aref(t.thread, rb_intern("carray_cell_nesting"));
1035
+ depth = NIL_P(t.before) ? 0 : FIX2LONG(t.before);
1036
+ if ( depth >= CA_CELL_NESTING_MAX ) {
1037
+ rb_raise(rb_eArgError, "%s: object cells nested too deep: more than %d levels",
1038
+ ca_calling_method_name(), CA_CELL_NESTING_MAX);
1039
+ }
1040
+ rb_thread_local_aset(t.thread, rb_intern("carray_cell_nesting"), LONG2FIX(depth + 1));
1041
+ return rb_ensure(body, arg, ca_cell_nesting_leave, (VALUE) &t);
1042
+ }
1043
+
1044
+ static VALUE
1045
+ ca_yield_nil (VALUE arg)
1046
+ {
1047
+ (void) arg;
1048
+ return rb_yield(Qnil);
1049
+ }
1050
+
988
1051
  static VALUE
989
1052
  ca_refuse_reentry_step (VALUE self, VALUE name, int recursive)
990
1053
  {
@@ -993,14 +1056,14 @@ ca_refuse_reentry_step (VALUE self, VALUE name, int recursive)
993
1056
  rb_raise(rb_eArgError, "%" PRIsVALUE ": cyclic reference is not allowed in CArray",
994
1057
  name);
995
1058
  }
996
- return rb_yield(Qnil);
1059
+ return ca_cell_walk_run(ca_yield_nil, Qnil);
997
1060
  }
998
1061
 
999
1062
  /* refuse_reentry(name) { ... } -- runs the block, refusing as cyclic a
1000
1063
  second call for the same array from inside it (rb_exec_recursive, by
1001
- the receiver). Ruby code that walks the cells of an object array and
1002
- comes back to the array through a cell, such as the nested dump of a
1003
- view, goes through this. */
1064
+ the receiver), and counting it as a walk into cells. Ruby code that
1065
+ walks the cells of an object array and comes back to the array through a
1066
+ cell, such as the nested dump of a view, goes through this. */
1004
1067
  static VALUE
1005
1068
  rb_ca_refuse_reentry (VALUE self, VALUE name)
1006
1069
  {
@@ -1015,7 +1078,7 @@ ca_test_cyclic_check (void *ap, void *ptr)
1015
1078
  {
1016
1079
  CArray *ca = (CArray *) ap;
1017
1080
  if ( ca_is_object_type(ca) ) {
1018
- VALUE rval = *(VALUE *) ptr;
1081
+ volatile VALUE rval = *(VALUE *) ptr;
1019
1082
  if ( rb_obj_is_carray(rval) ) {
1020
1083
  CArray *cv;
1021
1084
  TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
data/ext/carray_count.c CHANGED
@@ -82,7 +82,7 @@ ca_count_each_body (VALUE arg)
82
82
  /* Extract vk as a scalar VALUE via flat addr. rb_ca_fetch_addr
83
83
  takes a ca_size_t addr (not a Ruby VALUE). */
84
84
  VALUE vk = rb_ca_fetch_addr(c->rval, k);
85
- VALUE sub;
85
+ volatile VALUE sub;
86
86
  /* A masked query cell asks nothing: its count is masked. Passing it
87
87
  on would ask count(UNDEF), the count of self's masked cells. */
88
88
  if ( vk == CA_UNDEF ) {
@@ -154,7 +154,14 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
154
154
  }
155
155
  }
156
156
 
157
- volatile VALUE rval = argv[0];
157
+ /* true and false count the cells holding 1 and 0 of a numeric array */
158
+ volatile VALUE rval = ca_truth_as_number(src, argv[0]);
159
+ if ( rval != argv[0] ) {
160
+ VALUE *nargv = ALLOCA_N(VALUE, argc);
161
+ MEMCPY(nargv, argv, VALUE, argc);
162
+ nargv[0] = rval;
163
+ argv = nargv;
164
+ }
158
165
 
159
166
  /* count(UNDEF) == count_masked: UNDEF is mask-state vocabulary, not a
160
167
  value to compare against. Forward, dropping the UNDEF from argv. */
@@ -162,6 +169,17 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
162
169
  return rb_ca_count_masked(argc - 1, argv + 1, self);
163
170
  }
164
171
 
172
+ /* An array that can not hold the value (nil, a String) counts no cell
173
+ for it: the cells that matched, none, are counted the way count(true)
174
+ counts a mask. */
175
+ if ( ca_query_matches_nothing(src, rval) && ! ca_is_complex_type(src) ) {
176
+ VALUE *nargv = ALLOCA_N(VALUE, argc);
177
+ MEMCPY(nargv, argv, VALUE, argc);
178
+ nargv[0] = Qtrue;
179
+ return rb_ca_count(argc, nargv,
180
+ rb_funcall(self, rb_intern("eq"), 1, rval));
181
+ }
182
+
165
183
  /* Face gate, mirroring the search / linear family (ext/carray_order.c):
166
184
  descend an ORDERABLE Face to its storage so the equality runs on the
167
185
  numeric storage, and let the reference reconcile the query into its own
@@ -284,7 +302,7 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
284
302
  }
285
303
 
286
304
  /* Allocate output i64 CArray. */
287
- VALUE vout = rb_funcall(rb_cCArray, rb_intern("new"), 2,
305
+ volatile VALUE vout = rb_funcall(rb_cCArray, rb_intern("new"), 2,
288
306
  INT2NUM(CA_INT64),
289
307
  rb_ary_new4(out_ndim,
290
308
  ({ VALUE *tmp = ALLOCA_N(VALUE, out_ndim);
@@ -348,16 +366,17 @@ rb_ca_count (int argc, VALUE *argv, VALUE self)
348
366
  iv);
349
367
  } else {
350
368
  rb_raise(rb_eTypeError,
351
- "count(v) on boolean array: v must be true / false / 1 / 0, got %s",
352
- rb_obj_classname(rval));
369
+ "count(v) on boolean array: v must be true / false / 1 / 0, got %"PRIsVALUE"",
370
+ rb_obj_class(rval));
353
371
  }
354
372
  } else {
355
- /* true / false are the boolean array's own domain, not a number --
356
- except in an object array, where they are ordinary stored values. */
373
+ /* An integer, float or complex array has read true / false as 1 / 0
374
+ above (ca_truth_as_number); an object array stores them as values.
375
+ Any other array that reaches here can not count them. */
357
376
  if ( ( rval == Qtrue || rval == Qfalse ) && src->data_type != CA_OBJECT ) {
358
377
  rb_raise(rb_eTypeError,
359
- "count(v) on numeric array: v must be numeric, got %s",
360
- rb_obj_classname(rval));
378
+ "count(v) on numeric array: v must be numeric, got %"PRIsVALUE"",
379
+ rb_obj_class(rval));
361
380
  }
362
381
  /* The query is compared in the type it and the array match in, as `eq`
363
382
  compares (ca_query_match_type): 1.5 does not match 1, and an Integer
data/ext/carray_element.c CHANGED
@@ -38,22 +38,28 @@ elem_index_value (VALUE v)
38
38
  }
39
39
  }
40
40
 
41
+ ca_size_t
42
+ ca_index_key_value (VALUE v)
43
+ {
44
+ return elem_index_value(v);
45
+ }
46
+
41
47
  /* T_ARRAY index parser. ridx is assumed already known to be T_ARRAY.
42
48
  Direct VALUE * access + FIXNUM_P fast path eliminates rb_ary_entry
43
49
  bounds check and NUM2SIZE Bignum branching for the common case. */
44
50
  static inline void
45
51
  elem_parse_idx_array (CArray *ca, VALUE rary, ca_size_t *idx)
46
52
  {
47
- const VALUE *iarr;
48
53
  int8_t ndim = ca->ndim;
49
54
  int8_t i;
50
55
  if ( RARRAY_LEN(rary) != ndim ) {
51
56
  rb_raise(rb_eIndexError, "%ld indices given for a carray of ndim %i",
52
57
  (long) RARRAY_LEN(rary), (int) ndim);
53
58
  }
54
- iarr = RARRAY_CONST_PTR(rary);
55
59
  for (i=0; i<ndim; i++) {
56
- ca_size_t k = elem_index_value(iarr[i]);
60
+ /* Read each entry afresh: converting one can run Ruby that changes the
61
+ Array (an entry gone reads as nil, which is refused). */
62
+ ca_size_t k = elem_index_value(rb_ary_entry(rary, i));
57
63
  CA_CHECK_INDEX(k, ca->dim[i]);
58
64
  idx[i] = k;
59
65
  }
@@ -818,7 +818,7 @@ static VALUE
818
818
  fz_factorize_appearance_body (VALUE arg)
819
819
  {
820
820
  fz_frame *fr = (fz_frame *) arg;
821
- VALUE self = fr->self;
821
+ volatile VALUE self = fr->self;
822
822
  CArray *ca;
823
823
  volatile VALUE face;
824
824
  fr->self = self = fz_face_descend(self, &face, "categorize");
@@ -843,7 +843,7 @@ fz_factorize_appearance_body (VALUE arg)
843
843
  ca_size_t N = ca->elements;
844
844
 
845
845
  /* uint32 code scratch, same shape as self; narrowed once k is known. */
846
- VALUE vu32 = rb_carray_new(CA_UINT32, ca->ndim, ca->dim, 0, NULL);
846
+ volatile VALUE vu32 = rb_carray_new(CA_UINT32, ca->ndim, ca->dim, 0, NULL);
847
847
  CArray *cu32;
848
848
  TypedData_Get_Struct(vu32, CArray, &carray_data_type, cu32);
849
849
 
@@ -1028,7 +1028,7 @@ static VALUE
1028
1028
  fz_mask_duplicates_body (VALUE arg)
1029
1029
  {
1030
1030
  fz_frame *fr = (fz_frame *) arg;
1031
- VALUE self = fr->self;
1031
+ volatile VALUE self = fr->self;
1032
1032
  VALUE vaxis = fr->a;
1033
1033
  CArray *ca;
1034
1034
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
@@ -1189,7 +1189,7 @@ static VALUE
1189
1189
  fz_unique_flat_body (VALUE arg)
1190
1190
  {
1191
1191
  fz_frame *fr = (fz_frame *) arg;
1192
- VALUE self = fr->self;
1192
+ volatile VALUE self = fr->self;
1193
1193
  CArray *ca;
1194
1194
  volatile VALUE face;
1195
1195
  fr->self = self = fz_face_descend(self, &face, "unique");
@@ -1429,7 +1429,7 @@ static VALUE
1429
1429
  fz_is_in_body (VALUE arg)
1430
1430
  {
1431
1431
  fz_frame *fr = (fz_frame *) arg;
1432
- VALUE self = fr->self;
1432
+ volatile VALUE self = fr->self;
1433
1433
  VALUE rvalues = fr->a;
1434
1434
  CArray *ca, *cv;
1435
1435
  volatile VALUE face;
@@ -1592,7 +1592,7 @@ static VALUE
1592
1592
  fz_locate_addr_body (VALUE arg)
1593
1593
  {
1594
1594
  fz_frame *fr = (fz_frame *) arg;
1595
- VALUE self = fr->self;
1595
+ volatile VALUE self = fr->self;
1596
1596
  VALUE rref = fr->a;
1597
1597
  CArray *ca, *cr;
1598
1598
  /* Here the *reference* is the argument (self is the query being placed on
@@ -1859,7 +1859,7 @@ static VALUE
1859
1859
  fz_set_relation_body (VALUE arg)
1860
1860
  {
1861
1861
  fz_frame *fr = (fz_frame *) arg;
1862
- VALUE self = fr->self;
1862
+ volatile VALUE self = fr->self;
1863
1863
  VALUE rother = fr->a;
1864
1864
  int keep_when_hit = fr->i;
1865
1865
  CArray *ca, *co;
@@ -2055,7 +2055,7 @@ static VALUE
2055
2055
  fz_set_union_body (VALUE arg)
2056
2056
  {
2057
2057
  fz_frame *fr = (fz_frame *) arg;
2058
- VALUE self = fr->self;
2058
+ volatile VALUE self = fr->self;
2059
2059
  VALUE rother = fr->a;
2060
2060
  CArray *ca, *co;
2061
2061
  volatile VALUE face;
@@ -2149,7 +2149,7 @@ static VALUE
2149
2149
  fz_value_counts_flat_body (VALUE arg)
2150
2150
  {
2151
2151
  fz_frame *fr = (fz_frame *) arg;
2152
- VALUE self = fr->self;
2152
+ volatile VALUE self = fr->self;
2153
2153
  CArray *ca;
2154
2154
  volatile VALUE face;
2155
2155
  fr->self = self = fz_face_descend(self, &face, "value_counts");
@@ -2325,7 +2325,7 @@ static VALUE
2325
2325
  fz_nunique_body (VALUE arg)
2326
2326
  {
2327
2327
  fz_frame *fr = (fz_frame *) arg;
2328
- VALUE self = fr->self;
2328
+ volatile VALUE self = fr->self;
2329
2329
  VALUE vaxis = fr->a;
2330
2330
  VALUE vkeep = fr->b;
2331
2331
  CArray *ca;
@@ -2472,7 +2472,7 @@ static VALUE
2472
2472
  fz_is_mode_body (VALUE arg)
2473
2473
  {
2474
2474
  fz_frame *fr = (fz_frame *) arg;
2475
- VALUE self = fr->self;
2475
+ volatile VALUE self = fr->self;
2476
2476
  VALUE vaxis = fr->a;
2477
2477
  CArray *ca;
2478
2478
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
@@ -437,7 +437,7 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
437
437
  }
438
438
 
439
439
  for ( k = 0; k < M; k++ ) {
440
- VALUE e = RARRAY_AREF(redges, k);
440
+ volatile VALUE e = RARRAY_AREF(redges, k);
441
441
  GetCArray(e, edge_ca[k]);
442
442
  histbin_check_edge_mask(edge_ca[k], "histogram");
443
443
  }
@@ -528,7 +528,7 @@ bincount_nd_label_u64 (uint64_t x)
528
528
  } while (0)
529
529
 
530
530
  static VALUE
531
- rb_ca_bincount_nd_count_ki (VALUE self, VALUE rcounts, VALUE rweights)
531
+ rb_ca_bincount_nd_count_ki (VALUE self, VALUE rcounts, volatile VALUE rweights)
532
532
  {
533
533
  CArray *ca, *cc, *cw = NULL;
534
534
  long M, nf, k;
@@ -322,15 +322,15 @@ ca_classifier_check_reserved_symbol (VALUE sym)
322
322
  {
323
323
  const char *name;
324
324
  if ( ! SYMBOL_P(sym) ) return;
325
- name = rb_id2name(SYM2ID(sym));
325
+ name = rb_id2name(SYM2ID(sym)); /* name: its first two bytes are read at once */
326
326
  if ( name != NULL
327
327
  && name[0] != '\0' && name[1] == '\0'
328
328
  && ( ( name[0] >= 'a' && name[0] <= 'z' )
329
329
  || ( name[0] >= 'A' && name[0] <= 'Z' ) )
330
330
  && name[0] != '_' /* :_ is iterator marker, handled separately */ ) {
331
331
  rb_raise(rb_eIndexError,
332
- "symbol :%s is reserved",
333
- name);
332
+ "symbol :%"PRIsVALUE" is reserved",
333
+ rb_sym2str(sym));
334
334
  }
335
335
  }
336
336
 
@@ -1005,7 +1005,7 @@ rb_ca_scan_index_v2 (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
1005
1005
  also fall through here and are raised later by the per-axis
1006
1006
  dispatcher's SYMBOL_P branch. */
1007
1007
  if ( SYMBOL_P(argv[0]) ) {
1008
- const char *name = rb_id2name(SYM2ID(argv[0]));
1008
+ const char *name = rb_id2name(SYM2ID(argv[0])); /* name: read at once by strlen */
1009
1009
  if ( name != NULL && strlen(name) > 1 ) {
1010
1010
  info->type = CA_REG_METHOD_CALL;
1011
1011
  info->symbol = argv[0];
@@ -1069,7 +1069,7 @@ rb_ca_scan_index_v2 (int ca_ndim, ca_size_t *ca_dim, ca_size_t ca_elements,
1069
1069
  downstream introspection. */
1070
1070
 
1071
1071
  static VALUE
1072
- rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, VALUE ridx)
1072
+ rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, volatile VALUE ridx)
1073
1073
  {
1074
1074
  CAIndexInfo info;
1075
1075
  ca_size_t dim[CA_RANK_MAX];
@@ -1079,6 +1079,8 @@ rb_ca_s_scan_index_v2 (VALUE self, VALUE rdim, VALUE ridx)
1079
1079
 
1080
1080
  Check_Type(rdim, T_ARRAY);
1081
1081
  Check_Type(ridx, T_ARRAY);
1082
+ /* Converting an entry can run Ruby that changes the Array: read a copy. */
1083
+ ridx = rb_ary_dup(ridx);
1082
1084
 
1083
1085
  ndim = (int) RARRAY_LEN(rdim);
1084
1086
  elements = 1;
@@ -24,6 +24,8 @@
24
24
  #ifndef CARRAY_INTERNAL_H
25
25
  #define CARRAY_INTERNAL_H
26
26
 
27
+ #include "ruby/thread_native.h" /* rb_nativethread_lock_t */
28
+
27
29
  #include "carray.h"
28
30
  #include <math.h> /* isnan, for CA_OBJ_ISNAN */
29
31
 
@@ -85,6 +87,7 @@ void ca_lazy_arena_enter (void);
85
87
  void ca_lazy_arena_exit (void);
86
88
  void *ca_lazy_arena_acquire (ca_size_t bytes);
87
89
  void *ca_lazy_arena_acquire_object (ca_size_t n_elements);
90
+ void ca_lazy_arena_untag_objects (void *ptr);
88
91
  void ca_lazy_arena_release (void *ptr);
89
92
  VALUE ca_lazy_arena_protect (VALUE (*body)(VALUE),
90
93
  VALUE (*cleanup)(VALUE), VALUE arg);
@@ -145,6 +148,18 @@ ca_boolean_normalize_bytes (void *ptr, ca_size_t n)
145
148
  }
146
149
  }
147
150
 
151
+ /* A buffer for n cells of data_type, each bytes long: object cells start
152
+ as nil. */
153
+ static inline char *
154
+ ca_alloc_cells_of (int8_t data_type, ca_size_t elements, ca_size_t bytes)
155
+ {
156
+ char *p = (char *) xmalloc(elements > 0 ? elements * bytes : 1);
157
+ if ( data_type == CA_OBJECT ) {
158
+ ca_object_cells_clear(p, elements);
159
+ }
160
+ return p;
161
+ }
162
+
148
163
  static inline char *
149
164
  ca_alloc_cells (const CArray *ca)
150
165
  {
@@ -237,6 +252,17 @@ void ca_fill_or_free (CArray *co, VALUE (*fill)(VALUE), VALUE arg);
237
252
  void ca_fill_or_xfree (void *buf, VALUE (*fill)(VALUE), VALUE arg);
238
253
  void ca_fill_or_detach (int n, CArray **list, VALUE (*fill)(VALUE), VALUE arg);
239
254
 
255
+ /* The buffer of a view's own cells, for an attach or allocate slot that
256
+ attaches parents[0..n-1] and then works in a buffer of its own. The
257
+ buffer is allocated before the parents are attached, and freed if
258
+ attaching them raises: a slot that raises before it publishes ca->ptr
259
+ gives ca_attach no detach slot to call, and a parent left attached keeps
260
+ reading and writing the copy it materialised instead of its root. The
261
+ caller publishes the result as ca->ptr. utils/check_attach_then_alloc.rb
262
+ finds a slot that allocates after attaching. */
263
+
264
+ char *ca_alloc_cells_then_attach (CArray *ca, int32_t n, CArray **parents);
265
+
240
266
  /* A view takes its parent's mask by asking the parent whether it has one,
241
267
  and a parent that is a CAObject answers in Ruby and can raise. A view's
242
268
  setup therefore does not ask: its constructor calls this under
@@ -360,6 +386,7 @@ VALUE ca_lazy_settle_scalar (VALUE operand, int was_scalar);
360
386
  of one view all take the same branch. */
361
387
 
362
388
  int ca_parent_lends_no_memory (void *ap);
389
+ void rb_ca_cast_three (volatile VALUE *v1, volatile VALUE *v2, volatile VALUE *v3);
363
390
 
364
391
  /* Transfers of the descriptor views (CAGrid, CASelect, CASelectAxis,
365
392
  CAWindow) whose parent holds no ptr (ca_axis_dispatch.c).
@@ -433,6 +460,13 @@ CAReduce *ca_reduce_new (CArray *carray, ca_size_t count, ca_size_t offset);
433
460
  void ca_broadcast_to_destination (VALUE dst, volatile VALUE *src);
434
461
  VALUE rb_ary_flatten_for_elements (VALUE ary, ca_size_t elements, void *ap);
435
462
 
463
+ /* carray_access.c */
464
+ void ca_refuse_complex_into_real (CArray *ca, CArray *cv);
465
+
466
+ /* carray_cast.c */
467
+ void ca_cast_block_skip_masked (ca_size_t n, void *ap1, void *ptr1,
468
+ void *ap2, void *ptr2, boolean8_t *m);
469
+
436
470
  /* carray_utils.c */
437
471
  const char *ca_calling_method_name (void);
438
472
  VALUE ca_answer_as_caller (VALUE (*body)(VALUE), VALUE arg);
@@ -440,13 +474,26 @@ long ca_integer_arg (VALUE v, const char *arg, const char *name);
440
474
  /* 1 with the position of an index key (an Integer, or a Float with no
441
475
  fraction while exact), 2 for an Integer past int64, 0 otherwise. */
442
476
  int ca_index_key_position (VALUE v, ca_size_t *out);
477
+ ca_size_t ca_index_key_value (VALUE v);
443
478
  void ca_refuse_without_common_type (VALUE self, VALUE other);
444
479
  ca_size_t ca_shape_elements (int8_t ndim, const ca_size_t *dim, ca_size_t bytes);
445
480
  void ca_check_index_array (VALUE v);
446
481
  VALUE ca_order_key (VALUE v, const char *name);
447
482
  void ca_check_integer_fits (VALUE v, int8_t data_type);
448
483
  VALUE ca_obj2integer_fitting (VALUE v, int8_t data_type);
484
+ /* A Ruby value stored into an integer cell of `dst`: refused when it does
485
+ not fit (ca_obj2integer_fitting), except into the cells of a bit field
486
+ view (ca_bitfield_beneath), which keep it modulo 2 ** bits
487
+ (ca_integer_wrap_bits). */
488
+ VALUE ca_obj2integer_store (CArray *dst, VALUE v, int8_t data_type);
489
+ CArray *ca_bitfield_beneath (CArray *ca);
490
+ VALUE ca_bitfield_wrap_integer (CArray *ca, VALUE v);
491
+ /* v as an Integer modulo 2 ** bits; with sign_extend, in
492
+ -2 ** (bits - 1) ... 2 ** (bits - 1) - 1. A String is read as a
493
+ decimal integer, any other value through Integer() (1.5 is 1). */
494
+ VALUE ca_integer_wrap_bits (VALUE v, int bits, int sign_extend);
449
495
  int ca_integer_range_side (VALUE v, int8_t data_type);
496
+ int ca_obj_number_fits_integer (VALUE v, int8_t data_type);
450
497
  int ca_bincmp_integer_prepare (volatile VALUE *self, volatile VALUE *other,
451
498
  int op_id, int *signed_side);
452
499
  int ca_bincmp_answer_when_negative (int op_id, int signed_side);
@@ -481,6 +528,11 @@ VALUE ca_computing_run_nodes (int n, CArray **ops, VALUE (*body)(VALUE), VALUE a
481
528
  /* Refuses as cyclic a cell among cells[0..n) that is an array reaching a
482
529
  lazy node being evaluated: computing it would come back into the node. */
483
530
  void ca_refuse_cells_reaching_evaluation (ca_size_t n, const VALUE *cells);
531
+ /* Runs body(arg), a walk into the cells of an object array, one level deeper
532
+ in this fiber; past the limit it raises ArgumentError. A cell can give a
533
+ new array each time it is opened, which the records above never meet
534
+ twice. */
535
+ VALUE ca_cell_walk_run (VALUE (*body)(VALUE), VALUE arg);
484
536
 
485
537
  /* Registers a view type whose transfers only move cells between its parents
486
538
  and the caller (an index view: CAGrid, CASelect, CAWindow, CAStack, ...),
@@ -845,6 +897,40 @@ ca_query_match_applies (CArray *ref, VALUE query)
845
897
  return 1;
846
898
  }
847
899
 
900
+ /* A Ruby value an integer, float, complex or boolean array can not hold:
901
+ anything but a Numeric, true, false and UNDEF that does not make an
902
+ array (an Array, a #to_ca, a memory view). nil, a String, a Symbol and
903
+ other objects are foreign. An object or fixlen array and a Face hold or
904
+ read such values, so nothing is foreign to them (ca_cast.c). */
905
+ int ca_value_foreign_to (CArray *ca, VALUE v);
906
+
907
+ /* An operator refuses a foreign value as Float#+ does (TypeError), and an
908
+ ordering refuses it as Float#< does (ArgumentError). `array` is the
909
+ CArray operand (ca_cast.c). */
910
+ void ca_refuse_foreign_operand (VALUE v, VALUE array);
911
+ void ca_refuse_foreign_order (VALUE v, VALUE array);
912
+
913
+ /* true and false as the numbers 1 and 0 for a value query on an integer,
914
+ float or complex array; any other value, or array, is returned as is
915
+ (ca_cast.c). */
916
+ VALUE ca_truth_as_number (CArray *ca, VALUE v);
917
+
918
+ /* eq / ne when no cell can match (carray_operator.c). */
919
+ VALUE ca_bincmp_no_match (VALUE self, int ne);
920
+
921
+ /* A value an array can not hold matches no cell as a value query: eq, ne,
922
+ count and search answer as they do for an Integer outside the array's
923
+ type. nil is such a value for every array but an object one, which
924
+ holds nil and is asked. */
925
+ static inline int
926
+ ca_query_matches_nothing (CArray *ca, VALUE query)
927
+ {
928
+ if ( NIL_P(query) ) {
929
+ return ca->data_type != CA_OBJECT;
930
+ }
931
+ return ca_value_foreign_to(ca, query);
932
+ }
933
+
848
934
  /* Equality of two object cells, as the float lanes answer it: Ruby's `==`,
849
935
  except that a Float NaN equals nothing, itself included. rb_equal alone
850
936
  answers true for the same object, so whether two NaN cells matched would
@@ -986,4 +1072,12 @@ int ca_index_key_is_scalar (VALUE arg);
986
1072
  /* Whether this runs in the main Ractor (carray_utils.c). */
987
1073
  int ca_in_main_ractor (void);
988
1074
 
1075
+ /* Take a native lock that guards a table shared by every Ractor, waiting
1076
+ without the GVL (carray_utils.c). A Ractor that waits for the lock while
1077
+ it holds its GVL cannot stop for a GC, so one that holds the lock and
1078
+ allocates (a GC) would wait for it, and it for the lock. The lock is only
1079
+ ever taken outside the wait, so an interrupt that raises there leaves it
1080
+ free. The lock must not be held across a call that can raise. */
1081
+ void ca_native_lock_without_gvl (rb_nativethread_lock_t *lock);
1082
+
989
1083
  #endif /* CARRAY_INTERNAL_H */