carray 3.0.4 → 3.0.6

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +438 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_dispatch.c +19 -20
  7. data/ext/ca_axis_group.c +1 -1
  8. data/ext/ca_categorical_iterator.c +34 -27
  9. data/ext/ca_compare.c +4 -4
  10. data/ext/ca_composite_dispatch.c +9 -9
  11. data/ext/ca_kernel_iterator.c +122 -237
  12. data/ext/ca_kernel_iterator.h +522 -337
  13. data/ext/ca_obj_array.c +69 -19
  14. data/ext/ca_obj_bincmp.c +10 -1
  15. data/ext/ca_obj_binop.c +11 -1
  16. data/ext/ca_obj_bitarray.c +5 -1
  17. data/ext/ca_obj_bitfield.c +60 -43
  18. data/ext/ca_obj_byte_swap.c +4 -1
  19. data/ext/ca_obj_const_string.c +15 -3
  20. data/ext/ca_obj_face.c +44 -1
  21. data/ext/ca_obj_fake.c +3 -1
  22. data/ext/ca_obj_field.c +13 -3
  23. data/ext/ca_obj_grid.c +219 -17
  24. data/ext/ca_obj_meld.c +69 -113
  25. data/ext/ca_obj_moncmp.c +9 -1
  26. data/ext/ca_obj_monop.c +86 -12
  27. data/ext/ca_obj_object.c +118 -32
  28. data/ext/ca_obj_record.c +3 -0
  29. data/ext/ca_obj_reduce.c +19 -1
  30. data/ext/ca_obj_refer.c +80 -26
  31. data/ext/ca_obj_remap.c +69 -10
  32. data/ext/ca_obj_roll.c +27 -6
  33. data/ext/ca_obj_select.c +38 -6
  34. data/ext/ca_obj_select_axis.c +1 -0
  35. data/ext/ca_obj_shift.c +32 -7
  36. data/ext/ca_obj_stack.c +311 -111
  37. data/ext/ca_obj_stride.c +159 -64
  38. data/ext/ca_obj_string.c +27 -2
  39. data/ext/ca_obj_tile.c +28 -7
  40. data/ext/ca_obj_transpose.c +8 -4
  41. data/ext/ca_obj_triop.c +12 -1
  42. data/ext/ca_obj_window.c +80 -50
  43. data/ext/ca_op_ipower.c +12 -12
  44. data/ext/ca_sort_kernels.h +6 -3
  45. data/ext/caframe_csv_reader.c +1 -1
  46. data/ext/carray.h +35 -1
  47. data/ext/carray_access.c +43 -67
  48. data/ext/carray_address_basis.c +134 -0
  49. data/ext/carray_attribute.c +32 -0
  50. data/ext/carray_broadcast.c +3 -4
  51. data/ext/carray_build_flags.h +1 -1
  52. data/ext/carray_cast.c +251 -93
  53. data/ext/carray_cast_func.rb +56 -26
  54. data/ext/carray_conversion.c +11 -7
  55. data/ext/carray_core.c +814 -72
  56. data/ext/carray_count.c +6 -0
  57. data/ext/carray_element.c +22 -13
  58. data/ext/carray_factorize.c +20 -20
  59. data/ext/carray_generate.c +8 -2
  60. data/ext/carray_histogram.c +26 -4
  61. data/ext/carray_index_classifier.c +4 -4
  62. data/ext/carray_internal.h +159 -12
  63. data/ext/carray_kernels_bincmp.c +2174 -170
  64. data/ext/carray_kernels_binop.c +25653 -5487
  65. data/ext/carray_kernels_init.c +8 -8
  66. data/ext/carray_kernels_moncmp.c +96 -96
  67. data/ext/carray_kernels_monop.c +12253 -5235
  68. data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
  69. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  70. data/ext/carray_kernels_reduce_cumulative.c +2442 -882
  71. data/ext/carray_kernels_reduce_extreme.c +5658 -1661
  72. data/ext/carray_kernels_reduce_variance.c +2534 -402
  73. data/ext/carray_kernels_scan.c +368 -368
  74. data/ext/carray_kernels_search.c +4551 -604
  75. data/ext/carray_kernels_sort.c +659 -751
  76. data/ext/carray_kernels_triop.c +114 -114
  77. data/ext/carray_key_windows.c +4 -0
  78. data/ext/carray_lazy.c +47 -0
  79. data/ext/carray_loop.c +1 -1
  80. data/ext/carray_mask.c +175 -161
  81. data/ext/carray_median_percentile.c +4 -4
  82. data/ext/carray_memory_view.c +15 -9
  83. data/ext/carray_operator.c +152 -49
  84. data/ext/carray_order.c +230 -10
  85. data/ext/carray_random.c +22 -19
  86. data/ext/carray_scatter.c +24 -7
  87. data/ext/carray_slab.c +128 -29
  88. data/ext/carray_sort.c +224 -16
  89. data/ext/carray_sort_kernel.c +5 -7
  90. data/ext/carray_struct.c +35 -43
  91. data/ext/carray_test.c +74 -19
  92. data/ext/carray_time_text.c +6 -4
  93. data/ext/carray_utils.c +63 -21
  94. data/ext/extconf.rb +11 -0
  95. data/ext/mkkernel.rb +546 -199
  96. data/ext/ruby_carray.c +4 -1
  97. data/ext/version.h +4 -4
  98. data/lib/carray/attribute.rb +42 -5
  99. data/lib/carray/autoload_carray.rb +3 -3
  100. data/lib/carray/autoload_method_extension.rb +5 -3
  101. data/lib/carray/axis_group.rb +13 -7
  102. data/lib/carray/basics.rb +28 -8
  103. data/lib/carray/block_iterator.rb +17 -3
  104. data/lib/carray/categorical.rb +35 -23
  105. data/lib/carray/categorical_iterator.rb +8 -8
  106. data/lib/carray/complex.rb +2 -2
  107. data/lib/carray/conditional.rb +3 -2
  108. data/lib/carray/const_string.rb +10 -0
  109. data/lib/carray/data_type_extension.rb +8 -1
  110. data/lib/carray/fixlen_string.rb +41 -2
  111. data/lib/carray/frame/column_verbs.rb +48 -16
  112. data/lib/carray/frame/concat.rb +17 -3
  113. data/lib/carray/frame/convert.rb +19 -0
  114. data/lib/carray/frame/csv_parser.rb +32 -32
  115. data/lib/carray/frame/describe.rb +4 -2
  116. data/lib/carray/frame/frame.rb +405 -85
  117. data/lib/carray/frame/group.rb +777 -64
  118. data/lib/carray/frame/io.rb +212 -72
  119. data/lib/carray/frame/join.rb +146 -37
  120. data/lib/carray/frame/records.rb +3 -3
  121. data/lib/carray/frame/reshape.rb +89 -11
  122. data/lib/carray/frame/sort.rb +57 -9
  123. data/lib/carray/frame/verbs.rb +384 -49
  124. data/lib/carray/frame/windows.rb +44 -6
  125. data/lib/carray/fuse_source.rb +31 -2
  126. data/lib/carray/inspect.rb +7 -2
  127. data/lib/carray/iterator.rb +32 -0
  128. data/lib/carray/lazy.rb +52 -8
  129. data/lib/carray/mask_gap_fill.rb +37 -17
  130. data/lib/carray/meld_reduce.rb +1 -1
  131. data/lib/carray/methods/choose.rb +3 -2
  132. data/lib/carray/methods/is_in.rb +8 -1
  133. data/lib/carray/methods/meshgrid.rb +3 -1
  134. data/lib/carray/runtime.rb +47 -8
  135. data/lib/carray/segment_iterator.rb +35 -16
  136. data/lib/carray/serialize.rb +53 -19
  137. data/lib/carray/stack.rb +33 -18
  138. data/lib/carray/string.rb +8 -0
  139. data/lib/carray/string_operation_extension.rb +13 -5
  140. data/lib/carray/struct_builder.rb +5 -3
  141. data/lib/carray/time.rb +112 -68
  142. data/lib/carray/window_iterator.rb +16 -4
  143. data/yard-stubs/ca_obj_array.rb +26 -1
  144. data/yard-stubs/ca_obj_transpose.rb +5 -4
  145. data/yard-stubs/carray_attribute.rb +3 -1
  146. data/yard-stubs/carray_cast.rb +10 -5
  147. data/yard-stubs/carray_conversion.rb +13 -3
  148. data/yard-stubs/carray_element.rb +7 -6
  149. data/yard-stubs/carray_mask.rb +28 -4
  150. data/yard-stubs/carray_math.rb +45 -20
  151. data/yard-stubs/carray_memory_view.rb +7 -0
  152. data/yard-stubs/carray_order.rb +100 -4
  153. data/yard-stubs/carray_scatter.rb +7 -5
  154. data/yard-stubs/carray_test.rb +7 -4
  155. metadata +18 -4
data/ext/ca_obj_window.c CHANGED
@@ -801,16 +801,40 @@ ca_window_create_bounds_mask (VALUE view)
801
801
  return Qnil;
802
802
  }
803
803
 
804
+ typedef struct {
805
+ CAWindow *ca;
806
+ CArray *parent;
807
+ ca_size_t *start;
808
+ ca_size_t *count;
809
+ uint8_t *bounds;
810
+ char *fill;
811
+ } ca_window_new_arg;
812
+
813
+ static VALUE
814
+ ca_window_new_setup (VALUE varg)
815
+ {
816
+ ca_window_new_arg *a = (ca_window_new_arg *) varg;
817
+ ca_window_setup(a->ca, a->parent, a->start, a->count, a->bounds, a->fill);
818
+ return Qnil;
819
+ }
820
+
821
+ /* The setup allocates the fill value after the struct and its pool: when
822
+ that fails, the struct goes too. */
804
823
  CAWindow *
805
824
  ca_window_new (CArray *parent,
806
825
  ca_size_t *start, ca_size_t *count, uint8_t *bounds, char *fill)
807
826
  {
808
- CAWindow *ca;
827
+ ca_window_new_arg a;
809
828
  ca_window_setup(NULL, parent, start, count, bounds, fill);
810
- ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
811
- ca_window_setup(ca, parent, start, count, bounds, fill);
812
- ca_fill_or_free((CArray *) ca, ca_window_create_bounds_mask, (VALUE) ca);
813
- return ca;
829
+ a.ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
830
+ a.parent = parent;
831
+ a.start = start;
832
+ a.count = count;
833
+ a.bounds = bounds;
834
+ a.fill = fill;
835
+ ca_fill_or_free((CArray *) a.ca, ca_window_new_setup, (VALUE) &a);
836
+ ca_fill_or_free((CArray *) a.ca, ca_window_create_bounds_mask, (VALUE) a.ca);
837
+ return a.ca;
814
838
  }
815
839
 
816
840
  static void
@@ -1674,51 +1698,56 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1674
1698
  if ( SYMBOL_P(rbounds) ) {
1675
1699
  rbounds = rb_sym2str(rbounds);
1676
1700
  }
1677
- switch ( TYPE(rbounds) ) {
1678
- case T_STRING:
1679
- cbounds = StringValuePtr(rbounds);
1680
- if ( rfval == CA_UNDEF && strncmp(cbounds, "fill", 4)
1681
- && strncmp(cbounds, "mask", 4) ) {
1682
- rb_raise(rb_eArgError, "conflicted bounds and fill_value");
1683
- }
1684
- if ( ! strncmp(cbounds, "ruby", 4) ) {
1685
- bounds = CA_BOUNDS_RUBY;
1686
- }
1687
- else if ( ! strncmp(cbounds, "strict", 6) ) {
1688
- bounds = CA_BOUNDS_STRICT;
1689
- }
1690
- else if ( ! strncmp(cbounds, "nearest", 7) ) {
1691
- bounds = CA_BOUNDS_NEAREST;
1692
- }
1693
- else if ( ! strncmp(cbounds, "periodic", 8) ) {
1694
- rb_raise(rb_eArgError,
1695
- "bounds=>'periodic' removed in 3.0; "
1696
- "use CArray#roll(...) for cyclic shift "
1697
- "(returns a CARoll view)");
1698
- }
1699
- else if ( ! strncmp(cbounds, "reflect", 7) ) {
1700
- rb_raise(rb_eArgError,
1701
- "bounds=>'reflect' removed in 3.0; "
1702
- "there is no view-based alternative");
1703
- }
1704
- else if ( ! strncmp(cbounds, "mask", 4) ) {
1705
- rb_warn("CAWindow option :bounds=>\"mask\" will be obsolete");
1706
- rb_warn("use ca.window(..., fill_value: UNDEF)");
1707
- bounds = CA_BOUNDS_MASK;
1708
- }
1709
- else if ( ! strncmp(cbounds, "fill", 4) ) {
1710
- bounds = CA_BOUNDS_FILL;
1711
- }
1712
- else {
1713
- rb_raise(rb_eArgError,
1714
- "unknown option value '%s' for :bounds", cbounds);
1715
- }
1716
- break;
1717
- case T_FIXNUM:
1718
- bounds = NUM2INT(rbounds);
1719
- break;
1720
- default:
1721
- rb_raise(rb_eArgError, "invalid option value for :bounds");
1701
+ if ( ! RB_TYPE_P(rbounds, T_STRING) ) {
1702
+ rb_raise(rb_eTypeError,
1703
+ "window: bounds: must be a Symbol or a String (got %s)",
1704
+ rb_obj_classname(rbounds));
1705
+ }
1706
+ cbounds = StringValueCStr(rbounds);
1707
+ if ( ! strcmp(cbounds, "ruby") ) {
1708
+ bounds = CA_BOUNDS_RUBY;
1709
+ }
1710
+ else if ( ! strcmp(cbounds, "strict") ) {
1711
+ bounds = CA_BOUNDS_STRICT;
1712
+ }
1713
+ else if ( ! strcmp(cbounds, "nearest") ) {
1714
+ bounds = CA_BOUNDS_NEAREST;
1715
+ }
1716
+ else if ( ! strcmp(cbounds, "periodic") ) {
1717
+ rb_raise(rb_eArgError,
1718
+ "bounds=>'periodic' removed in 3.0; "
1719
+ "use CArray#roll(...) for cyclic shift "
1720
+ "(returns a CARoll view)");
1721
+ }
1722
+ else if ( ! strcmp(cbounds, "reflect") ) {
1723
+ rb_raise(rb_eArgError,
1724
+ "bounds=>'reflect' removed in 3.0; "
1725
+ "there is no view-based alternative");
1726
+ }
1727
+ else if ( ! strcmp(cbounds, "mask") ) {
1728
+ rb_warn("CAWindow option :bounds=>\"mask\" will be obsolete");
1729
+ rb_warn("use ca.window(..., fill_value: UNDEF)");
1730
+ bounds = CA_BOUNDS_MASK;
1731
+ }
1732
+ else if ( ! strcmp(cbounds, "fill") ) {
1733
+ bounds = ( rfval == CA_UNDEF ) ? CA_BOUNDS_MASK : CA_BOUNDS_FILL;
1734
+ }
1735
+ else {
1736
+ rb_raise(rb_eArgError,
1737
+ "window: unknown bounds: '%s'", cbounds);
1738
+ }
1739
+ /* A fill value says what the cells outside the array are; the other
1740
+ policies say something else about them. */
1741
+ if ( rfval != CA_UNSPECIFIED
1742
+ && bounds != CA_BOUNDS_FILL && bounds != CA_BOUNDS_MASK ) {
1743
+ rb_raise(rb_eArgError,
1744
+ "window: fill_value: is for bounds: :fill, not :%s", cbounds);
1745
+ }
1746
+ if ( rfval != CA_UNSPECIFIED && rfval != CA_UNDEF
1747
+ && bounds == CA_BOUNDS_MASK ) {
1748
+ rb_raise(rb_eArgError,
1749
+ "window: fill_value: %+"PRIsVALUE" conflicts with bounds: :mask "
1750
+ "(use fill_value: UNDEF to mask the cells outside)", rfval);
1722
1751
  }
1723
1752
  }
1724
1753
 
@@ -1953,6 +1982,7 @@ Init_ca_obj_window (void)
1953
1982
  &cawindow_data_type,
1954
1983
  rb_cCAWindowMask,
1955
1984
  &cawindow_mask_data_type, &ca_window_func, sizeof(ca_window_func));
1985
+ ca_register_cell_moving_view(CA_OBJ_WINDOW);
1956
1986
  rb_define_const(rb_cObject, "CA_OBJ_WINDOW", INT2NUM(CA_OBJ_WINDOW));
1957
1987
 
1958
1988
  rb_define_method(rb_cCArray, "window", rb_ca_window, -1);
data/ext/ca_op_ipower.c CHANGED
@@ -110,9 +110,9 @@ ca_binop_func_t ca_binop_ipower[CA_NTYPE] = {
110
110
 
111
111
  static void
112
112
  ca_ipower_float32_t (ca_size_t n, boolean8_t *m,
113
- char *ptr1, int32_t ipow, char *ptr2)
113
+ char *ptr1, int64_t ipow, char *ptr2)
114
114
  {
115
- float32_t *p1 = (float32_t *) ptr1, *p2 = (float32_t *) ptr2;
115
+ ca_u_float32_t *p1 = (ca_u_float32_t *) ptr1, *p2 = (ca_u_float32_t *) ptr2;
116
116
  if ( m ) {
117
117
  while (n--) {
118
118
  if ( ! *m++ ) { *p2 = op_powi_float32_t(*p1, ipow); }
@@ -125,9 +125,9 @@ ca_ipower_float32_t (ca_size_t n, boolean8_t *m,
125
125
 
126
126
  static void
127
127
  ca_ipower_float64_t (ca_size_t n, boolean8_t *m,
128
- char *ptr1, int32_t ipow, char *ptr2)
128
+ char *ptr1, int64_t ipow, char *ptr2)
129
129
  {
130
- float64_t *p1 = (float64_t *) ptr1, *p2 = (float64_t *) ptr2;
130
+ ca_u_float64_t *p1 = (ca_u_float64_t *) ptr1, *p2 = (ca_u_float64_t *) ptr2;
131
131
  if ( m ) {
132
132
  while (n--) {
133
133
  if ( ! *m++ ) { *p2 = op_powi_float64_t(*p1, ipow); }
@@ -140,9 +140,9 @@ ca_ipower_float64_t (ca_size_t n, boolean8_t *m,
140
140
 
141
141
  static void
142
142
  ca_ipower_cmplx64_t (ca_size_t n, boolean8_t *m,
143
- char *ptr1, int32_t ipow, char *ptr2)
143
+ char *ptr1, int64_t ipow, char *ptr2)
144
144
  {
145
- cmplx64_t *p1 = (cmplx64_t *) ptr1, *p2 = (cmplx64_t *) ptr2;
145
+ ca_u_cmplx64_t *p1 = (ca_u_cmplx64_t *) ptr1, *p2 = (ca_u_cmplx64_t *) ptr2;
146
146
  if ( m ) {
147
147
  while (n--) {
148
148
  if ( ! *m++ ) { *p2 = op_powi_cmplx64_t(*p1, ipow); }
@@ -155,9 +155,9 @@ ca_ipower_cmplx64_t (ca_size_t n, boolean8_t *m,
155
155
 
156
156
  static void
157
157
  ca_ipower_cmplx128_t (ca_size_t n, boolean8_t *m,
158
- char *ptr1, int32_t ipow, char *ptr2)
158
+ char *ptr1, int64_t ipow, char *ptr2)
159
159
  {
160
- cmplx128_t *p1 = (cmplx128_t *) ptr1, *p2 = (cmplx128_t *) ptr2;
160
+ ca_u_cmplx128_t *p1 = (ca_u_cmplx128_t *) ptr1, *p2 = (ca_u_cmplx128_t *) ptr2;
161
161
  if ( m ) {
162
162
  while (n--) {
163
163
  if ( ! *m++ ) { *p2 = op_powi_cmplx128_t(*p1, ipow); }
@@ -195,10 +195,10 @@ rb_ca_ipower (VALUE self, VALUE other)
195
195
  {
196
196
  volatile VALUE obj;
197
197
  CArray *ca, *co;
198
- int32_t ipow;
198
+ int64_t ipow;
199
199
  boolean8_t *m;
200
200
 
201
- ipow = NUM2INT(other);
201
+ ipow = NUM2LL(other);
202
202
 
203
203
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
204
204
 
@@ -252,10 +252,10 @@ static VALUE
252
252
  rb_ca_ipower_bang (VALUE self, VALUE other)
253
253
  {
254
254
  CArray *ca;
255
- int32_t ipow;
255
+ int64_t ipow;
256
256
  boolean8_t *m;
257
257
 
258
- ipow = NUM2INT(other);
258
+ ipow = NUM2LL(other);
259
259
 
260
260
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
261
261
 
@@ -62,11 +62,14 @@ void ca_sort_merge_f64 (double *a, double *aux, ca_size_t n);
62
62
  ca_size_t ca_partition_nan_f32 (float32_t *a, ca_size_t n);
63
63
  ca_size_t ca_partition_nan_f64 (double *a, ca_size_t n);
64
64
 
65
- /* P.4: pair variant of NaN pre-partition for float argsort kernels. */
65
+ /* Pair variant of NaN pre-partition for float argsort kernels. scratch
66
+ holds n pairs; its contents on return are unspecified. */
66
67
  struct ca_pair_f32;
67
68
  struct ca_pair_f64;
68
- ca_size_t ca_partition_nan_pair_f32 (struct ca_pair_f32 *a, ca_size_t n);
69
- ca_size_t ca_partition_nan_pair_f64 (struct ca_pair_f64 *a, ca_size_t n);
69
+ ca_size_t ca_partition_nan_pair_f32 (struct ca_pair_f32 *a, ca_size_t n,
70
+ struct ca_pair_f32 *scratch);
71
+ ca_size_t ca_partition_nan_pair_f64 (struct ca_pair_f64 *a, ca_size_t n,
72
+ struct ca_pair_f64 *scratch);
70
73
 
71
74
  /* P.9: value-level quickselect for partition_copy.
72
75
  Reorders a[0..n) so that a[kth] is exact + left/right regions
@@ -1,4 +1,4 @@
1
- /* CSV body reader for CAFrame.from_csv.
1
+ /* CSV body reader for CAFrame.read_csv.
2
2
 
3
3
  CArray.__csv_read_body_as_string_cells__(text, sep, quote, ncol, keep)
4
4
  -> [ncol, cells, records]
data/ext/carray.h CHANGED
@@ -173,6 +173,39 @@ typedef int8_t boolean8_t;
173
173
  #define CA_ALIGN_CMPLX128 offsetof(struct { char c; cmplx128_t x; }, x)
174
174
  #define CA_ALIGN_OBJECT offsetof(struct { char c; VALUE x; }, x)
175
175
 
176
+ /* Cell types that may sit at any byte. A view's cells need not be aligned
177
+ to their size: a struct member at offset 1, a refer with a byte offset,
178
+ a wrapped external buffer. Reading a cell through a plain `double *`
179
+ there is undefined (x86 vector code may assume the alignment), so a
180
+ kernel reads and writes cells through these. Same size and value as the
181
+ plain type; only the alignment the compiler may assume is 1. */
182
+ #if defined(__GNUC__) || defined(__clang__)
183
+ # define CA_UNALIGNED __attribute__((aligned(1)))
184
+ #else
185
+ # define CA_UNALIGNED
186
+ #endif
187
+ typedef boolean8_t ca_u_boolean8_t;
188
+ typedef int8_t ca_u_int8_t;
189
+ typedef uint8_t ca_u_uint8_t;
190
+ typedef int16_t ca_u_int16_t CA_UNALIGNED;
191
+ typedef uint16_t ca_u_uint16_t CA_UNALIGNED;
192
+ typedef int32_t ca_u_int32_t CA_UNALIGNED;
193
+ typedef uint32_t ca_u_uint32_t CA_UNALIGNED;
194
+ typedef int64_t ca_u_int64_t CA_UNALIGNED;
195
+ typedef uint64_t ca_u_uint64_t CA_UNALIGNED;
196
+ typedef float32_t ca_u_float32_t CA_UNALIGNED;
197
+ typedef float64_t ca_u_float64_t CA_UNALIGNED;
198
+ typedef cmplx64_t ca_u_cmplx64_t CA_UNALIGNED;
199
+ typedef cmplx128_t ca_u_cmplx128_t CA_UNALIGNED;
200
+ typedef VALUE ca_u_VALUE CA_UNALIGNED;
201
+
202
+ typedef ca_u_float32_t ca_u_float;
203
+ typedef ca_u_float64_t ca_u_double;
204
+
205
+ /* CA_U(float64_t) is ca_u_float64_t (and CA_U(double) ca_u_double): for a
206
+ macro that takes the cell type. */
207
+ #define CA_U(type) ca_u_##type
208
+
176
209
  /* -------------------------------------------------------------------- */
177
210
 
178
211
  #define CA_OBJ_TYPE_MAX 256
@@ -204,7 +237,8 @@ typedef int8_t boolean8_t;
204
237
  routines that walk a single ->parent test this flag and instead fold over
205
238
  the parents[] exposed by the CAMultiParent layout convention. */
206
239
  #define CA_FLAG_MULTI_PARENTS 32
207
- #define CA_FLAG_CYCLE_CHECK 64
240
+ /* bit 64 (formerly CA_FLAG_CYCLE_CHECK) is free: a cyclic read is found
241
+ without writing to the array (ca_test_cyclic_check). */
208
242
  #define CA_FLAG_IS_FACE 128
209
243
  /* Face opt-in ordering/search flags.
210
244
  A Face declares that its numeric storage may be descended to for kernel
data/ext/carray_access.c CHANGED
@@ -193,6 +193,14 @@ rb_ca_fill (VALUE self, VALUE rval)
193
193
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
194
194
 
195
195
  if ( ca_is_empty(ca) ) {
196
+ /* No cell to fill, but a value no cell could hold is refused, as an
197
+ assignment to the empty array refuses it. */
198
+ if ( rval != CA_UNDEF && ca->bytes > 0 ) {
199
+ volatile VALUE holder;
200
+ char *fval = ALLOCV_N(char, holder, ca->bytes);
201
+ rb_ca_obj2ptr(self, rval, fval);
202
+ ALLOCV_END(holder);
203
+ }
196
204
  return self; /* empty = no-op fill; return self for chaining */
197
205
  }
198
206
 
@@ -884,9 +892,9 @@ rb_ca_index_restruct_block (int16_t *ndimp, ca_size_t *shrink, ca_size_t *dim,
884
892
 
885
893
  offset = 0;
886
894
 
887
- if ( idx[0] == -1 ) {
888
- j = 0;
889
- while ( idx[++j] ) {
895
+ if ( ndim0 > 0 && idx[0] == -1 ) {
896
+ /* j = the number of leading axes collapsed by a scalar index */
897
+ for (j=1; j<ndim0 && idx[j] == -1; j++) {
890
898
  ;
891
899
  }
892
900
 
@@ -1365,6 +1373,7 @@ rb_ca_fetch_newaxis (int argc, VALUE *argv, VALUE self, CArray *ca)
1365
1373
  element, which is what the shape rules then hold it to. */
1366
1374
  if ( nscalar == nclean ) {
1367
1375
  VALUE blocks[CA_RANK_MAX];
1376
+ ca_check_rank_fits(nunder, NULL); /* the result has the :_ axes only */
1368
1377
  for (i = 0; i < nclean; i++) {
1369
1378
  blocks[i] = rb_assoc_new(clean[i], INT2FIX(1));
1370
1379
  }
@@ -1379,6 +1388,10 @@ rb_ca_fetch_newaxis (int argc, VALUE *argv, VALUE self, CArray *ca)
1379
1388
 
1380
1389
  TypedData_Get_Struct(base, CArray, &carray_data_type, cb);
1381
1390
 
1391
+ /* The result has the base's axes and one for each :_, before any is
1392
+ written into final_dims. */
1393
+ ca_check_rank_fits((long) nunder + cb->ndim, NULL);
1394
+
1382
1395
  /* Reconstruct final shape: walk original argv. :_ -> size-1, scalar
1383
1396
  (Integer) -> dropped (skip), else -> base.dim[cursor]. A key gives one
1384
1397
  axis, except an integer CArray read alone (a mapping), which gives as
@@ -1541,75 +1554,37 @@ rb_ca_fetch_slab_sigil (int argc, VALUE *argv, VALUE self)
1541
1554
  return rb_funcall(klass, rb_intern("new"), 2, base, slab_axes);
1542
1555
  }
1543
1556
 
1557
+ /* A CScalar is one cell and takes no index: s[] and s[0] name that cell,
1558
+ anything else is refused. */
1559
+
1560
+ static void
1561
+ rb_cs_check_index (int argc, VALUE *argv, const char *op)
1562
+ {
1563
+ if ( argc == 0 ) {
1564
+ return;
1565
+ }
1566
+ if ( argc == 1 && FIXNUM_P(argv[0]) && FIX2LONG(argv[0]) == 0 ) {
1567
+ return;
1568
+ }
1569
+ rb_raise(rb_eArgError,
1570
+ "CScalar%s takes no index other than [] or [0]", op);
1571
+ }
1572
+
1544
1573
  static VALUE
1545
1574
  rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
1546
1575
  {
1547
- volatile VALUE obj = Qnil;
1548
- CArray *ca;
1549
- CAIndexInfo info;
1550
-
1551
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1552
-
1553
- info.range_check = 0;
1554
- rb_ca_scan_index(ca->ndim, ca->dim, ca->elements, argc, argv, &info);
1576
+ rb_cs_check_index(argc, argv, "#[]");
1577
+ return rb_ca_fetch_addr(self, 0);
1578
+ }
1555
1579
 
1556
- switch ( info.type ) {
1557
- case CA_REG_ADDRESS_COMPLEX:
1558
- obj = rb_ca_fetch_addr(self, 0);
1559
- break;
1560
- case CA_REG_ADDRESS:
1561
- obj = rb_ca_fetch_addr(self, 0);
1562
- break;
1563
- case CA_REG_FLATTEN:
1564
- obj = self; /* rb_funcall(self, rb_intern("refer"), 0); */
1565
- break;
1566
- case CA_REG_POINT:
1567
- obj = rb_ca_fetch_addr(self, 0);
1568
- break;
1569
- case CA_REG_ALL:
1570
- obj = self; /* rb_funcall(self, rb_intern("refer"), 0); */
1571
- break;
1572
- case CA_REG_BLOCK:
1573
- obj = self; /* rb_funcall(self, rb_intern("refer"), 0); */
1574
- break;
1575
- case CA_REG_SELECT:
1576
- obj = rb_ca_select_new(self, argv[0]);
1577
- break;
1578
- case CA_REG_ITERATOR:
1579
- obj = rb_ca_slab_iter_new(self, &info);
1580
- break;
1581
- case CA_REG_REPEAT:
1582
- obj = rb_ca_repeat(argc, argv, self);
1583
- break;
1584
- case CA_REG_MAPPING:
1585
- obj = rb_ca_fancy_index_chain(self, argv[0]);
1586
- break;
1587
- case CA_REG_GRID:
1588
- obj = rb_ca_grid(argc, argv, self);
1589
- break;
1590
- case CA_REG_METHOD_CALL: {
1591
- volatile VALUE idx;
1592
- idx = rb_funcallv_public(self, SYM2ID(info.symbol), argc-1, argv+1);
1593
- obj = rb_ca_fetch(self, idx);
1594
- break;
1595
- }
1596
- case CA_REG_MEMBER: {
1597
- volatile VALUE data_class = rb_ca_data_class(self);
1598
- if ( ! NIL_P(data_class) ) {
1599
- obj = rb_ca_face_field(self, info.symbol);
1600
- break;
1601
- }
1602
- else {
1603
- rb_raise(rb_eIndexError,
1604
- "can't refer member of carray doesn't have data_class");
1605
- }
1606
- break;
1607
- }
1608
- default:
1609
- rb_raise(rb_eIndexError, "invalid index specified");
1610
- }
1580
+ static VALUE rb_ca_store_method (int argc, VALUE *argv, VALUE self);
1611
1581
 
1612
- return obj;
1582
+ static VALUE
1583
+ rb_cs_store_method (int argc, VALUE *argv, VALUE self)
1584
+ {
1585
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
1586
+ rb_cs_check_index(argc - 1, argv, "#[]=");
1587
+ return rb_ca_store_method(argc, argv, self);
1613
1588
  }
1614
1589
 
1615
1590
  /* Recursively convert a store rvalue's surface value objects into
@@ -2430,6 +2405,7 @@ Init_carray_access (void)
2430
2405
  rb_define_method(rb_cCArray, "[]=", rb_ca_store_method, -1);
2431
2406
 
2432
2407
  rb_define_method(rb_cCScalar, "[]", rb_cs_fetch_method, -1);
2408
+ rb_define_method(rb_cCScalar, "[]=", rb_cs_store_method, -1);
2433
2409
 
2434
2410
  rb_define_method(rb_cCArray, "fill", rb_ca_fill, 1);
2435
2411
  rb_define_method(rb_cCArray, "fill_copy", rb_ca_fill_copy, 1);
@@ -965,6 +965,139 @@ address_basis_tier (VALUE module, VALUE object)
965
965
  return INT2NUM(tier_for(ca));
966
966
  }
967
967
 
968
+ /* ------------------------------------------------------------------- */
969
+
970
+ /*
971
+ * call-seq:
972
+ * CArray::AddressBasis.sweep(function, fsync, arrays, *parts) -> nil
973
+ *
974
+ * Runs ca_call_cslab_N_r over `arrays` with the slab function at the address
975
+ * `function`, and hands it as `userdata` a table of pointers to the bytes of
976
+ * each of `parts`, in order.
977
+ *
978
+ * This is what a consumer did through Fiddle: copy the parts into memory
979
+ * from malloc, write the table in front of them, and call the family member
980
+ * for the arity. The copy was there because a String's bytes may be moved
981
+ * by GC compaction, and the sweep allocates -- so a collection can run
982
+ * between taking an address and the slab reading it. It is not needed
983
+ * here: every part is also held in an array on the machine stack for the
984
+ * length of this call, and an object referenced from there is pinned. The
985
+ * VM stack is not enough by itself -- a splat of 128 or more arguments
986
+ * reaches a C method as a heap array, whose elements compaction moves.
987
+ * The machine stack is why the parts are limited to 1024.
988
+ *
989
+ * A part that is not frozen is the slab's to write (an error slot), and is
990
+ * made unshared first so the write lands in that String alone. A frozen
991
+ * part is read only. Each part has to start on an 8-byte boundary, since a
992
+ * slab reads doubles and int64s out of them.
993
+ */
994
+ static VALUE
995
+ address_basis_sweep (int argc, VALUE *argv, VALUE module)
996
+ {
997
+ volatile VALUE rfunction, rfsync, rarrays;
998
+ ca_cslab_r_t function;
999
+ const char *fsync;
1000
+ VALUE vholder = 0;
1001
+ void **table;
1002
+ VALUE *arrays;
1003
+ volatile VALUE *parts;
1004
+ int i, n, nparts;
1005
+
1006
+ rb_check_arity(argc, 3, UNLIMITED_ARGUMENTS);
1007
+ rfunction = argv[0];
1008
+ rfsync = argv[1];
1009
+ rarrays = argv[2];
1010
+ nparts = argc - 3;
1011
+
1012
+ if ( nparts > 1024 ) {
1013
+ rb_raise(rb_eArgError, "%s: a sweep takes at most 1024 parts, got %d",
1014
+ ca_calling_method_name(), nparts);
1015
+ }
1016
+ /* Held on the machine stack, which the GC scans conservatively and so
1017
+ pins. argv is not written: it may be the storage of a heap array. */
1018
+ parts = ALLOCA_N(VALUE, nparts > 0 ? nparts : 1);
1019
+ for ( i = 0; i < nparts; i++ ) {
1020
+ parts[i] = argv[3 + i];
1021
+ }
1022
+
1023
+ Check_Type(rarrays, T_ARRAY);
1024
+ n = (int) RARRAY_LEN(rarrays);
1025
+ if ( n < 1 || n > 7 ) {
1026
+ rb_raise(rb_eArgError, "%s: a sweep takes 1 to 7 arrays, got %d",
1027
+ ca_calling_method_name(), n);
1028
+ }
1029
+ fsync = StringValueCStr(rfsync);
1030
+ if ( (int) strlen(fsync) != n ) {
1031
+ rb_raise(rb_eArgError, "%s: fsync has %d characters for %d arrays",
1032
+ ca_calling_method_name(), (int) strlen(fsync), n);
1033
+ }
1034
+ for ( i = 0; i < n; i++ ) {
1035
+ if ( fsync[i] != '0' && fsync[i] != '1' ) {
1036
+ rb_raise(rb_eArgError,
1037
+ "%s: fsync character %d is '%c', not '0' (read) or '1' (written)",
1038
+ ca_calling_method_name(), i, fsync[i]);
1039
+ }
1040
+ }
1041
+ function = (ca_cslab_r_t) (uintptr_t) NUM2ULL(rfunction);
1042
+ if ( ! function ) {
1043
+ rb_raise(rb_eArgError, "%s: the slab function's address is zero",
1044
+ ca_calling_method_name());
1045
+ }
1046
+
1047
+ arrays = RARRAY_PTR(rarrays);
1048
+ for ( i = 0; i < n; i++ ) {
1049
+ if ( ! rb_obj_is_kind_of(arrays[i], rb_cCArray) ) {
1050
+ rb_raise(rb_eTypeError, "%s: array %d is not a CArray",
1051
+ ca_calling_method_name(), i);
1052
+ }
1053
+ }
1054
+
1055
+ for ( i = 0; i < nparts; i++ ) {
1056
+ VALUE part = parts[i];
1057
+ StringValue(part);
1058
+ parts[i] = part;
1059
+ if ( ! OBJ_FROZEN(part) ) {
1060
+ rb_str_modify(part);
1061
+ }
1062
+ if ( (uintptr_t) RSTRING_PTR(part) & 7 ) {
1063
+ rb_raise(rb_eArgError, "%s: part %d does not start on an 8-byte boundary",
1064
+ ca_calling_method_name(), i);
1065
+ }
1066
+ }
1067
+
1068
+ /* Taken after every check, so a refusal has nothing to free. The sweep
1069
+ itself can raise (a shape that will not broadcast); then the table is
1070
+ left to ALLOCV's own holder, which the GC reclaims. */
1071
+ table = ALLOCV_N(void *, vholder, nparts > 0 ? nparts : 1);
1072
+ for ( i = 0; i < nparts; i++ ) {
1073
+ table[i] = RSTRING_PTR(parts[i]);
1074
+ }
1075
+
1076
+ switch ( n ) {
1077
+ case 1: ca_call_cslab_1_r(function, fsync, arrays[0], table); break;
1078
+ case 2: ca_call_cslab_2_r(function, fsync, arrays[0], arrays[1], table); break;
1079
+ case 3: ca_call_cslab_3_r(function, fsync, arrays[0], arrays[1], arrays[2],
1080
+ table); break;
1081
+ case 4: ca_call_cslab_4_r(function, fsync, arrays[0], arrays[1], arrays[2],
1082
+ arrays[3], table); break;
1083
+ case 5: ca_call_cslab_5_r(function, fsync, arrays[0], arrays[1], arrays[2],
1084
+ arrays[3], arrays[4], table); break;
1085
+ case 6: ca_call_cslab_6_r(function, fsync, arrays[0], arrays[1], arrays[2],
1086
+ arrays[3], arrays[4], arrays[5], table); break;
1087
+ case 7: ca_call_cslab_7_r(function, fsync, arrays[0], arrays[1], arrays[2],
1088
+ arrays[3], arrays[4], arrays[5], arrays[6],
1089
+ table); break;
1090
+ }
1091
+
1092
+ ALLOCV_END(vholder);
1093
+ for ( i = 0; i < nparts; i++ ) {
1094
+ RB_GC_GUARD(parts[i]);
1095
+ }
1096
+ RB_GC_GUARD(rarrays);
1097
+ RB_GC_GUARD(rfsync);
1098
+ return Qnil;
1099
+ }
1100
+
968
1101
  /* ------------------------------------------------------------------- */
969
1102
  /* Init_carray_address_basis */
970
1103
  /* ------------------------------------------------------------------- */
@@ -978,6 +1111,7 @@ Init_carray_address_basis (void)
978
1111
  rb_define_singleton_method(mAddressBasis, "classify",
979
1112
  address_basis_classify, 1);
980
1113
  rb_define_singleton_method(mAddressBasis, "tier", address_basis_tier, 1);
1114
+ rb_define_singleton_method(mAddressBasis, "sweep", address_basis_sweep, -1);
981
1115
 
982
1116
  rb_define_const(mAddressBasis, "TIER_ENTITY", INT2NUM(TIER_ENTITY));
983
1117
  rb_define_const(mAddressBasis, "TIER_STRIDE", INT2NUM(TIER_STRIDE));
@@ -223,6 +223,14 @@ ca_is_readonly (void *ap)
223
223
  return 1;
224
224
  }
225
225
  }
226
+ if ( ca_test_flag(ca, CA_FLAG_FOLDED) ) {
227
+ /* a folded reshape: its source is not on the parent chain */
228
+ CArray *src = ca_fold_source(ca);
229
+ if ( src && ca_is_readonly(src) ) {
230
+ ca_set_flag(ca, CA_FLAG_READ_ONLY);
231
+ return 1;
232
+ }
233
+ }
226
234
  return 0; /* all test -> false */
227
235
  }
228
236
  }
@@ -520,10 +528,34 @@ rb_ca_inherit_attr (VALUE dst, VALUE src)
520
528
  it up after this (an ivar, a lift that moves it onto another parent), and
521
529
  writes through it are refused by ca_is_readonly, which walks to the
522
530
  frozen root and finds CA_FLAG_READ_ONLY there. */
531
+ static void
532
+ ca_note_view_of_lent (CArray *p)
533
+ {
534
+ if ( ca_test_flag(p, CA_FLAG_LENT) ) {
535
+ ca_set_flag(p, CA_FLAG_LENT_VIEWED);
536
+ }
537
+ }
538
+
523
539
  VALUE
524
540
  rb_ca_set_parent (VALUE self, VALUE obj)
525
541
  {
526
542
  rb_ivar_set(self, id_parent, obj);
543
+ /* A view of an array lent to a CAObject hook outlives the hook: tell the
544
+ array, so that it keeps its cells when the hook returns. A view of
545
+ several arrays names one here and holds the rest in parents[]. */
546
+ if ( rb_obj_is_carray(obj) ) {
547
+ ca_note_view_of_lent((CArray *) DATA_PTR(obj));
548
+ }
549
+ if ( rb_obj_is_carray(self) ) {
550
+ CArray *ca = (CArray *) DATA_PTR(self);
551
+ if ( ca_test_flag(ca, CA_FLAG_MULTI_PARENTS) ) {
552
+ CAMultiParent *mp = (CAMultiParent *) ca;
553
+ int32_t k;
554
+ for ( k = 0; k < mp->n_parents; k++ ) {
555
+ ca_note_view_of_lent(mp->parents[k]);
556
+ }
557
+ }
558
+ }
527
559
  return obj;
528
560
  }
529
561
 
@@ -85,13 +85,12 @@ ca_broadcast_to_destination (VALUE dst, volatile VALUE *src)
85
85
  for ( i = 0; agree && i < dst_ndim; i++ ) {
86
86
  if ( dst_dim[i] != src_dim[i] ) agree = 0;
87
87
  }
88
- if ( ! agree ) ca_broadcast_refuse_write(dst, *src);
89
- return;
88
+ if ( agree ) return;
90
89
  }
91
90
 
92
91
  /* A size-1 axis repeated onto an axis of length 0 leaves the source
93
- larger than an empty destination; the axes say it is a repeat all
94
- the same. */
92
+ larger than an empty destination, or as large when it is empty too
93
+ ((1,0) onto (2,0)); the axes say it is a repeat all the same. */
95
94
  if ( ( cs->elements < cd->elements || cd->elements == 0 )
96
95
  && cs->ndim == cd->ndim ) {
97
96
  int i;