carray 3.0.1 → 3.0.3

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_window.c CHANGED
@@ -30,6 +30,7 @@
30
30
  #include "carray.h"
31
31
  #include "ca_composite_dispatch.h"
32
32
  #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE, used by rb_ca_window */
33
+ #include "carray_internal.h" /* ca_axis_view_attach_owned */
33
34
 
34
35
  /* should not be static variable as used by CAIteratorWindow */
35
36
 
@@ -82,11 +83,23 @@ ca_window_pool_init (void *ap, int8_t ndim)
82
83
  ca->dim = ca->count; /* alias; ca_window_setup re-sets */
83
84
  }
84
85
 
86
+ /* A window over an object array keeps its fill value, a VALUE, in a
87
+ buffer of its own, so it marks it; ca_mark covers only ca->ptr. */
88
+ void
89
+ ca_window_mark (void *ap)
90
+ {
91
+ CAWindow *ca = (CAWindow *) ap;
92
+ ca_mark(ca);
93
+ if ( ca->fill != NULL && ca_is_object_type(ca) ) {
94
+ rb_gc_mark(*(VALUE *) ca->fill);
95
+ }
96
+ }
97
+
85
98
  const rb_data_type_t cawindow_data_type = {
86
99
  .parent = &caview_data_type,
87
100
  .wrap_struct_name = "CAWindow",
88
101
  .function = {
89
- .dmark = ca_mark,
102
+ .dmark = ca_window_mark,
90
103
  .dfree = ca_free,
91
104
  .dsize = ca_window_dsize,
92
105
  .dcompact = NULL
@@ -314,6 +327,7 @@ static void
314
327
  ca_window_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
315
328
  ca_size_t *strides, void *data, int dir)
316
329
  {
330
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
317
331
  CAWindow *w = (CAWindow *) ap;
318
332
  CArray *parent = w->parent;
319
333
  int8_t ndim = w->ndim;
@@ -667,11 +681,17 @@ ca_window_setup (CAWindow *ca, CArray *parent,
667
681
 
668
682
  elements = 1;
669
683
  for (i=0; i<ndim; i++) {
670
- if ( count[i] <= 0 ) {
684
+ if ( count[i] < 0 ) { /* zero is an empty window */
671
685
  rb_raise(rb_eIndexError,
672
- "invalid size for %i-th dimension (negative or zero)", i);
686
+ "invalid size for %i-th dimension (negative)", i);
673
687
  }
674
- elements *= count[i];
688
+ }
689
+ elements = ca_shape_elements(ndim, count, bytes);
690
+
691
+ /* ca == NULL asks for the checks above only, so that a constructor can
692
+ run them before it allocates. */
693
+ if ( ca == NULL ) {
694
+ return 0;
675
695
  }
676
696
 
677
697
  ca->obj_type = CA_OBJ_WINDOW;
@@ -746,7 +766,9 @@ CAWindow *
746
766
  ca_window_new (CArray *parent,
747
767
  ca_size_t *start, ca_size_t *count, uint8_t *bounds, char *fill)
748
768
  {
749
- CAWindow *ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
769
+ CAWindow *ca;
770
+ ca_window_setup(NULL, parent, start, count, bounds, fill);
771
+ ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
750
772
  ca_window_setup(ca, parent, start, count, bounds, fill);
751
773
  return ca;
752
774
  }
@@ -952,13 +974,52 @@ ca_window_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
952
974
  ALLOCV_END(h1);
953
975
  }
954
976
 
977
+ /* Whether this window over a parent with no memory to lend owns its buffer
978
+ rather than attaching the parent. Only FILL / MASK bounds qualify: their
979
+ xfer_stride hands the parent one region per row, where the other bounds
980
+ go cell by cell -- for a Ruby-backed parent, a call per cell, which costs
981
+ more than producing the parent once. Both inputs are fixed for the
982
+ life of the view, so attach, sync and detach take the same branch. */
983
+ static int
984
+ ca_window_owns_buffer (CAWindow *ca)
985
+ {
986
+ int8_t k;
987
+ for ( k = 0; k < ca->ndim; k++ ) {
988
+ if ( ca->bounds[k] != CA_BOUNDS_FILL && ca->bounds[k] != CA_BOUNDS_MASK ) {
989
+ return 0;
990
+ }
991
+ }
992
+ return ca_parent_lends_no_memory(ca->parent);
993
+ }
994
+
995
+ /* The parent's storage the alias path points into: inner axes full and
996
+ interior, so the window is one contiguous run of the attached parent. */
997
+ static char *
998
+ ca_window_alias_ptr (CAWindow *ca)
999
+ {
1000
+ ca_size_t parent_row_stride = ca->bytes;
1001
+ int8_t k;
1002
+ for (k = ca->ndim - 1; k >= 1; k--) parent_row_stride *= ca->parent->dim[k];
1003
+ return ca->parent->ptr + ca->start[0] * parent_row_stride;
1004
+ }
1005
+
1006
+ /* Agrees with attach on the alias path: sync has nothing to write back
1007
+ and detach frees nothing there, so a buffer of our own would take the
1008
+ writes and be dropped. */
955
1009
  static void
956
1010
  ca_window_func_allocate (void *ap)
957
1011
  {
958
1012
  CAWindow *ca = (CAWindow *) ap;
1013
+ if ( ca_window_owns_buffer(ca) ) {
1014
+ ca->ptr = xmalloc(ca_length(ca));
1015
+ return;
1016
+ }
959
1017
  ca_attach(ca->parent);
960
- /* ca->ptr = ALLOC_N(char, ca_length(ca)); */
961
- ca->ptr = xmalloc(ca_length(ca));
1018
+ if ( ca->embed_alias_eligible ) {
1019
+ ca->ptr = ca_window_alias_ptr(ca);
1020
+ return;
1021
+ }
1022
+ ca->ptr = xmalloc(ca_length(ca));
962
1023
  }
963
1024
 
964
1025
  /* The engine paths below emit a per-axis descriptor (ca_window_describe_axes)
@@ -973,6 +1034,10 @@ static void
973
1034
  ca_window_func_attach (void *ap)
974
1035
  {
975
1036
  CAWindow *ca = (CAWindow *) ap;
1037
+ if ( ca_window_owns_buffer(ca) ) {
1038
+ ca_axis_view_attach_owned(ca);
1039
+ return;
1040
+ }
976
1041
  ca_attach(ca->parent);
977
1042
  if ( ca->embed_alias_eligible ) {
978
1043
  /* Alias path: inner axes full + interior, so the embedded region is a
@@ -981,10 +1046,7 @@ ca_window_func_attach (void *ap)
981
1046
  CAREFUL: sync and detach must agree with this — sync has nothing to
982
1047
  scatter back (the writes already landed in the parent) and detach must
983
1048
  not xfree a pointer it does not own. */
984
- ca_size_t parent_row_stride = ca->bytes;
985
- int8_t k;
986
- for (k = ca->ndim - 1; k >= 1; k--) parent_row_stride *= ca->parent->dim[k];
987
- ca->ptr = ca->parent->ptr + ca->start[0] * parent_row_stride;
1049
+ ca->ptr = ca_window_alias_ptr(ca);
988
1050
  } else if ( ca->embed_eligible ) {
989
1051
  /* Embed path: allocate, then 1 fill + 1 strided memcpy. */
990
1052
  ca_size_t out_len = ca->elements * ca->bytes;
@@ -1005,6 +1067,10 @@ static void
1005
1067
  ca_window_func_sync (void *ap)
1006
1068
  {
1007
1069
  CAWindow *ca = (CAWindow *) ap;
1070
+ if ( ca_window_owns_buffer(ca) ) {
1071
+ ca_axis_view_sync_owned(ca);
1072
+ return;
1073
+ }
1008
1074
  if ( ca->embed_alias_eligible ) {
1009
1075
  /* Alias path: ca->ptr aliases the parent, so the writes already landed
1010
1076
  in parent storage. Nothing to scatter back. */
@@ -1025,6 +1091,11 @@ static void
1025
1091
  ca_window_func_detach (void *ap)
1026
1092
  {
1027
1093
  CAWindow *ca = (CAWindow *) ap;
1094
+ if ( ca_window_owns_buffer(ca) ) {
1095
+ xfree(ca->ptr);
1096
+ ca->ptr = NULL;
1097
+ return;
1098
+ }
1028
1099
  /* Alias path: ca->ptr aliases parent storage; it is not ours to xfree. */
1029
1100
  if ( ! ca->embed_alias_eligible ) {
1030
1101
  xfree(ca->ptr);
@@ -1117,9 +1188,25 @@ ca_window_func_xfer_all (void *ap, void *data, int dir)
1117
1188
  }
1118
1189
  }
1119
1190
 
1120
- /* Cold parent with nothing to lend: materialise it into a scratch buffer
1121
- via ca_xfer_all, then run the normal fast path with the scratch standing
1122
- in for parent->ptr. */
1191
+ /* A parent with no memory to lend is asked for the cells of the window
1192
+ only, through xfer_stride over the whole view, when the bounds let that
1193
+ go row by row (see ca_window_owns_buffer). */
1194
+ if ( ca_window_owns_buffer(ca) ) {
1195
+ ca_size_t starts[CA_RANK_MAX], strides[CA_RANK_MAX], s;
1196
+ int8_t k;
1197
+ s = ca->bytes;
1198
+ for ( k = ca->ndim - 1; k >= 0; k-- ) {
1199
+ starts[k] = 0;
1200
+ strides[k] = s;
1201
+ s *= ca->dim[k];
1202
+ }
1203
+ ca_window_func_xfer_stride(ca, starts, ca->dim, strides, data, dir);
1204
+ return;
1205
+ }
1206
+
1207
+ /* Any other cold parent: materialise it into a scratch buffer via
1208
+ ca_xfer_all, then run the normal fast path with the scratch standing in
1209
+ for parent->ptr. */
1123
1210
  {
1124
1211
  volatile VALUE holder;
1125
1212
  CArray *parent = ca->parent;
@@ -1137,12 +1224,14 @@ ca_window_func_xfer_all (void *ap, void *data, int dir)
1137
1224
 
1138
1225
  ca_window_func_run_fast_path(ca, (char *) data, dir);
1139
1226
 
1227
+ /* Put parent->ptr back before the PUT: the PUT can raise (a lazy
1228
+ backing's sync failing), and the scratch is gone once this
1229
+ frame is. */
1230
+ parent->ptr = parent_ptr_saved;
1140
1231
  if ( dir == CA_XFER_PUT ) {
1141
1232
  /* Push back scratch (modified by scatter) to parent. */
1142
1233
  ca_xfer_all(parent, parent_scratch, CA_XFER_PUT);
1143
1234
  }
1144
-
1145
- parent->ptr = parent_ptr_saved;
1146
1235
  ALLOCV_END(holder);
1147
1236
  }
1148
1237
  }
@@ -1238,8 +1327,7 @@ ca_window_func_fill_data (void *ap, void *ptr)
1238
1327
  ca_attach(ca->parent);
1239
1328
  ca_axis_dispatch_fill_value(ca->parent, pdims, desc, ca->ndim, ca->bytes,
1240
1329
  ca->elements, ptr);
1241
- ca_sync(ca->parent);
1242
- ca_detach(ca->parent);
1330
+ ca_sync_detach(ca->parent);
1243
1331
  }
1244
1332
 
1245
1333
  static void
@@ -1251,10 +1339,7 @@ ca_window_func_create_mask (void *ap)
1251
1339
  int8_t i;
1252
1340
  int any_mask;
1253
1341
 
1254
- ca_update_mask(ca->parent);
1255
- if ( ! ca->parent->mask ) {
1256
- ca_create_mask(ca->parent);
1257
- }
1342
+ ca_create_mask(ca->parent);
1258
1343
 
1259
1344
  /* Any MASK axis of the view becomes FILL in the mask sub-view, with the
1260
1345
  mask cell forced to 1 (= "masked"). Other axes keep their policy. When
@@ -1270,8 +1355,15 @@ ca_window_func_create_mask (void *ap)
1270
1355
  }
1271
1356
  fill = any_mask ? 1 : 0;
1272
1357
 
1273
- ca->mask = (CArray *) ca_window_new(ca->parent->mask,
1274
- ca->start, ca->count, mbounds, (char*)&fill);
1358
+ /* The mask has the view's own type, so CAShift (which shares this table)
1359
+ gets a CAShiftMask. */
1360
+ {
1361
+ CAWindow *m = (CAWindow *) ca_array_alloc(ca->obj_type, ca->ndim);
1362
+ ca_window_setup(m, ca->parent->mask,
1363
+ ca->start, ca->count, mbounds, (char*)&fill);
1364
+ m->obj_type = ca->obj_type;
1365
+ ca->mask = (CArray *) m;
1366
+ }
1275
1367
  }
1276
1368
 
1277
1369
  ca_operation_function_t ca_window_func = {
@@ -1416,12 +1508,18 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1416
1508
  }
1417
1509
 
1418
1510
  if ( ! NIL_P(rbounds) ) {
1511
+ /* A Symbol says the same thing as the String, and is what the window
1512
+ iterator (CArray#windows) is given -- accept both so the two spellings
1513
+ of one policy do not diverge. */
1514
+ if ( SYMBOL_P(rbounds) ) {
1515
+ rbounds = rb_sym2str(rbounds);
1516
+ }
1419
1517
  switch ( TYPE(rbounds) ) {
1420
1518
  case T_STRING:
1421
1519
  cbounds = StringValuePtr(rbounds);
1422
1520
  if ( rfval == CA_UNDEF && strncmp(cbounds, "fill", 4)
1423
1521
  && strncmp(cbounds, "mask", 4) ) {
1424
- rb_raise(rb_eRuntimeError, "conflicted bounds and fill_value");
1522
+ rb_raise(rb_eArgError, "conflicted bounds and fill_value");
1425
1523
  }
1426
1524
  if ( ! strncmp(cbounds, "ruby", 4) ) {
1427
1525
  bounds = CA_BOUNDS_RUBY;
@@ -1452,7 +1550,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1452
1550
  bounds = CA_BOUNDS_FILL;
1453
1551
  }
1454
1552
  else {
1455
- rb_raise(rb_eRuntimeError,
1553
+ rb_raise(rb_eArgError,
1456
1554
  "unknown option value '%s' for :bounds", cbounds);
1457
1555
  }
1458
1556
  break;
@@ -1460,7 +1558,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1460
1558
  bounds = NUM2INT(rbounds);
1461
1559
  break;
1462
1560
  default:
1463
- rb_raise(rb_eRuntimeError, "invalid option value for :bounds");
1561
+ rb_raise(rb_eArgError, "invalid option value for :bounds");
1464
1562
  }
1465
1563
  }
1466
1564
 
@@ -1485,6 +1583,7 @@ rb_ca_window_initialize_copy (VALUE self, VALUE other)
1485
1583
  CAWindow *ca, *cs;
1486
1584
 
1487
1585
  TypedData_Get_Struct(self, CAWindow, &cawindow_data_type, ca);
1586
+ ca_check_uninitialized(ca);
1488
1587
  TypedData_Get_Struct(other, CAWindow, &cawindow_data_type, cs);
1489
1588
 
1490
1589
  /* `self` came from rb_ca_window_s_allocate (TypedData_Make_Struct,
@@ -1582,6 +1681,34 @@ rb_ca_window_get_bounds (VALUE self)
1582
1681
  return SIZE2NUM(cw->bounds[0]);
1583
1682
  }
1584
1683
 
1684
+ /* The boundary rule on each axis, one Symbol per axis. `bounds` answers
1685
+ for axis 0 only, which is all CArray#window sets; a shift with `roll:`
1686
+ on some axes sets them one by one. */
1687
+ static VALUE
1688
+ rb_ca_window_axis_bounds (VALUE self)
1689
+ {
1690
+ volatile VALUE ary;
1691
+ CAWindow *cw;
1692
+ const char *name;
1693
+ int8_t i;
1694
+ TypedData_Get_Struct(self, CAWindow, &cawindow_data_type, cw);
1695
+ ary = rb_ary_new2(cw->ndim);
1696
+ for (i=0; i<cw->ndim; i++) {
1697
+ switch ( cw->bounds[i] ) {
1698
+ case CA_BOUNDS_RUBY: name = "ruby"; break;
1699
+ case CA_BOUNDS_STRICT: name = "strict"; break;
1700
+ case CA_BOUNDS_NEAREST: name = "nearest"; break;
1701
+ case CA_BOUNDS_PERIODIC: name = "periodic"; break;
1702
+ case CA_BOUNDS_REFLECT: name = "reflect"; break;
1703
+ case CA_BOUNDS_FILL: name = "fill"; break;
1704
+ case CA_BOUNDS_MASK: name = "mask"; break;
1705
+ default: name = "unknown"; break;
1706
+ }
1707
+ rb_ary_store(ary, i, ID2SYM(rb_intern(name)));
1708
+ }
1709
+ return ary;
1710
+ }
1711
+
1585
1712
  #define rb_cw_get_attr_ary(name) \
1586
1713
  rb_cw_## name (VALUE self) \
1587
1714
  { \
@@ -1597,7 +1724,6 @@ rb_ca_window_get_bounds (VALUE self)
1597
1724
  }
1598
1725
 
1599
1726
  static VALUE rb_cw_get_attr_ary(start);
1600
- static VALUE rb_cw_get_attr_ary(count);
1601
1727
  static VALUE rb_cw_get_attr_ary(size0);
1602
1728
 
1603
1729
  #ifdef CARRAY_DEV_BUILD
@@ -1680,8 +1806,10 @@ Init_ca_obj_window (void)
1680
1806
 
1681
1807
  rb_define_method(rb_cCAWindow, "bounds", rb_ca_window_get_bounds, 0);
1682
1808
 
1809
+ /* No `count` accessor: the per-axis window widths are what `shape`
1810
+ already answers, and the name belongs to CArray#count. */
1683
1811
  rb_define_method(rb_cCAWindow, "start", rb_cw_start, 0);
1684
- rb_define_method(rb_cCAWindow, "count", rb_cw_count, 0);
1812
+ rb_define_method(rb_cCAWindow, "__axis_bounds__", rb_ca_window_axis_bounds, 0);
1685
1813
  rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
1686
1814
 
1687
1815
  #ifdef CARRAY_DEV_BUILD
data/ext/ca_op_ipower.c CHANGED
@@ -168,6 +168,19 @@ ca_ipower_cmplx128_t (ca_size_t n, boolean8_t *m,
168
168
  while (n--) { (*p2) = op_powi_cmplx128_t(*p1, ipow); p1++; p2++; }
169
169
  }
170
170
 
171
+ /* The data types the ipower kernels cover; checked before any window
172
+ opens, so the switches inside cannot fall through to a raise. */
173
+ static int
174
+ ca_ipower_type_ok (CArray *ca)
175
+ {
176
+ switch ( ca->data_type ) {
177
+ case CA_FLOAT32: case CA_FLOAT64: case CA_CMPLX64: case CA_CMPLX128:
178
+ return 1;
179
+ default:
180
+ return 0;
181
+ }
182
+ }
183
+
171
184
  /* Eager Float/Complex ** Integer producing a fresh entity output.
172
185
  * ca is input-only, co is the write target. Mirrors rb_ca_call_monop
173
186
  * (see carray_math* / carray_kernels.c) so operand attach is elided:
@@ -189,6 +202,10 @@ rb_ca_ipower (VALUE self, VALUE other)
189
202
 
190
203
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
191
204
 
205
+ if ( ! ca_ipower_type_ok(ca) ) {
206
+ rb_raise(rb_eCADataTypeError, "invalid data type for ipower");
207
+ }
208
+
192
209
  co = ca_has_mask(ca) ? ca_template_safe(ca) : ca_template(ca);
193
210
  obj = ca_wrap_struct(co);
194
211
 
@@ -196,7 +213,7 @@ rb_ca_ipower (VALUE self, VALUE other)
196
213
  m = ( co->mask ) ? (boolean8_t *)co->mask->ptr : NULL;
197
214
 
198
215
  if ( ca_attach_is_alias(ca) ) {
199
- ca_attach(ca);
216
+ ca_attach(ca); /* window: nothing raises inside */
200
217
  switch ( ca->data_type ) {
201
218
  case CA_FLOAT32:
202
219
  ca_ipower_float32_t(ca->elements, m, ca->ptr, ipow, co->ptr); break;
@@ -206,8 +223,6 @@ rb_ca_ipower (VALUE self, VALUE other)
206
223
  ca_ipower_cmplx64_t(ca->elements, m, ca->ptr, ipow, co->ptr); break;
207
224
  case CA_CMPLX128:
208
225
  ca_ipower_cmplx128_t(ca->elements, m, ca->ptr, ipow, co->ptr); break;
209
- default:
210
- rb_raise(rb_eCADataTypeError, "invalid data type for ipower");
211
226
  }
212
227
  ca_detach(ca);
213
228
  }
@@ -226,9 +241,6 @@ rb_ca_ipower (VALUE self, VALUE other)
226
241
  ca_ipower_cmplx64_t(ca->elements, m, p1, ipow, co->ptr); break;
227
242
  case CA_CMPLX128:
228
243
  ca_ipower_cmplx128_t(ca->elements, m, p1, ipow, co->ptr); break;
229
- default:
230
- ALLOCV_END(h1);
231
- rb_raise(rb_eCADataTypeError, "invalid data type for ipower");
232
244
  }
233
245
  ALLOCV_END(h1);
234
246
  }
@@ -247,7 +259,11 @@ rb_ca_ipower_bang (VALUE self, VALUE other)
247
259
 
248
260
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
249
261
 
250
- ca_attach(ca);
262
+ if ( ! ca_ipower_type_ok(ca) ) {
263
+ rb_raise(rb_eRuntimeError, "invalid data type for ipower");
264
+ }
265
+
266
+ ca_attach(ca); /* window: nothing raises inside until ca_sync_detach */
251
267
 
252
268
  m = ( ca->mask ) ? (boolean8_t *)ca->mask->ptr : NULL;
253
269
 
@@ -260,12 +276,9 @@ rb_ca_ipower_bang (VALUE self, VALUE other)
260
276
  ca_ipower_cmplx64_t(ca->elements, m, ca->ptr, ipow, ca->ptr); break;
261
277
  case CA_CMPLX128:
262
278
  ca_ipower_cmplx128_t(ca->elements, m, ca->ptr, ipow, ca->ptr); break;
263
- default:
264
- rb_raise(rb_eRuntimeError, "invalid data type for ipower");
265
279
  }
266
280
 
267
- ca_sync(ca);
268
- ca_detach(ca);
281
+ ca_sync_detach(ca);
269
282
 
270
283
  return self;
271
284
  }
@@ -273,8 +286,7 @@ rb_ca_ipower_bang (VALUE self, VALUE other)
273
286
  /* CArray#pow(other) (alias `**`) — Float/Complex ** Integer takes the
274
287
  * ipower fast path in this file; everything else falls through to the
275
288
  * mkkernel-generated general pow/cpow (rb_ca_power in
276
- * ext/carray_kernels.c). Non-bang variant preserves UnboundRepeat
277
- * wrapping on the result. */
289
+ * ext/carray_kernels.c). */
278
290
  static VALUE rb_ca_pow (VALUE self, VALUE other)
279
291
  {
280
292
  volatile VALUE obj;
data/ext/ca_op_powi.h CHANGED
@@ -23,9 +23,19 @@
23
23
  #include "carray.h"
24
24
  #include <stdint.h>
25
25
 
26
- #define op_powi(type) \
26
+ /* The text between the two markers below is also handed, as it stands, to
27
+ an evaluator that compiles a kernel body calling op_powi_<type>
28
+ (CArray.__kernel_helpers__, written into the build by mkkernel.rb). It
29
+ may use only <stdint.h>, float32_t / float64_t and ca_zerodiv: what such
30
+ an evaluator's C declares. The complex instantiations stay outside. */
31
+
32
+ /* BEGIN kernel helpers */
33
+
34
+ /* x raised to a non-negative power, by binary exponentiation. The power
35
+ is unsigned so that the magnitude of INT64_MIN is representable. */
36
+ #define op_powi_magnitude(type) \
27
37
  static inline type \
28
- op_powi_## type (type x, int64_t p) \
38
+ op_powi_mag_## type (type x, uint64_t p) \
29
39
  { \
30
40
  type r=1; \
31
41
  \
@@ -35,53 +45,70 @@ op_powi_## type (type x, int64_t p) \
35
45
  case 0: return 1; \
36
46
  case 1: return x; \
37
47
  } \
38
- if (p<0) { \
39
- type den = op_powi_## type(x, -p); \
40
- if (den==0) ca_zerodiv(); \
41
- return 1/den; \
42
- }\
43
48
  while (p) { \
44
- if ( (p%2) == 1 ) r *= x; \
49
+ if ( p & 1 ) r *= x; \
45
50
  x *= x; \
46
- p /= 2; \
51
+ p >>= 1; \
47
52
  } \
48
53
  return r; \
49
54
  }
50
55
 
51
- #define op_powi_fc(type) \
56
+ /* An integer to a negative power is 1/x^|p| in integer division, which is
57
+ decided by x alone: 0 has no reciprocal, 1 and -1 keep their magnitude,
58
+ anything larger truncates to 0. Answering it that way, rather than by
59
+ computing x^|p|, keeps a power that overflows -- 2 ** -64 -- from wrapping
60
+ to a zero divisor. */
61
+ #define op_powi(type) \
62
+ op_powi_magnitude(type) \
52
63
  static inline type \
53
64
  op_powi_## type (type x, int64_t p) \
54
65
  { \
55
- type r=1; \
56
- \
57
- switch(p) { \
58
- case 2: return x*x; \
59
- case 3: return x*x*x; \
60
- case 0: return 1; \
61
- case 1: return x; \
66
+ if ( p < 0 ) { \
67
+ if ( x == 0 ) ca_zerodiv(); \
68
+ if ( x == 1 ) return 1; \
69
+ if ( x == (type) -1 ) return ( p % 2 ) ? x : 1; \
70
+ return 0; \
62
71
  } \
63
- if (p<0) { \
64
- type den = op_powi_## type(x, -p); \
65
- return 1/den; \
66
- }\
67
- while (p) { \
68
- if ( (p%2) == 1 ) r *= x; \
69
- x *= x; \
70
- p /= 2; \
72
+ return op_powi_mag_## type(x, (uint64_t) p); \
73
+ }
74
+
75
+ /* An unsigned x is never -1; (type) -1 is its largest value. */
76
+ #define op_powi_u(type) \
77
+ op_powi_magnitude(type) \
78
+ static inline type \
79
+ op_powi_## type (type x, int64_t p) \
80
+ { \
81
+ if ( p < 0 ) { \
82
+ if ( x == 0 ) ca_zerodiv(); \
83
+ return ( x == 1 ) ? 1 : 0; \
71
84
  } \
72
- return r; \
85
+ return op_powi_mag_## type(x, (uint64_t) p); \
86
+ }
87
+
88
+ #define op_powi_fc(type) \
89
+ op_powi_magnitude(type) \
90
+ static inline type \
91
+ op_powi_## type (type x, int64_t p) \
92
+ { \
93
+ if ( p < 0 ) { \
94
+ return 1 / op_powi_mag_## type(x, (uint64_t) 0 - (uint64_t) p); \
95
+ } \
96
+ return op_powi_mag_## type(x, (uint64_t) p); \
73
97
  }
74
98
 
75
99
  op_powi(int8_t)
76
- op_powi(uint8_t)
100
+ op_powi_u(uint8_t)
77
101
  op_powi(int16_t)
78
- op_powi(uint16_t)
102
+ op_powi_u(uint16_t)
79
103
  op_powi(int32_t)
80
- op_powi(uint32_t)
104
+ op_powi_u(uint32_t)
81
105
  op_powi(int64_t)
82
- op_powi(uint64_t)
106
+ op_powi_u(uint64_t)
83
107
  op_powi_fc(float32_t)
84
108
  op_powi_fc(float64_t)
109
+
110
+ /* END kernel helpers */
111
+
85
112
  op_powi_fc(cmplx64_t)
86
113
  op_powi_fc(cmplx128_t)
87
114