carray 3.0.2 → 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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +304 -0
  3. data/README.md +3 -4
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +225 -0
  6. data/ext/ca_axis_group.c +177 -99
  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 +66 -71
  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 +663 -214
  14. data/ext/ca_kernel_iterator.h +231 -167
  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 +132 -22
  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 +1 -0
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +96 -25
  25. data/ext/ca_obj_face.c +406 -64
  26. data/ext/ca_obj_face.h +92 -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 +21 -21
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +189 -107
  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 +543 -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 +47 -49
  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 -118
  46. data/ext/ca_obj_stride.c +195 -34
  47. data/ext/ca_obj_string.c +17 -18
  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 +149 -27
  54. data/ext/ca_op_ipower.c +24 -11
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_sort_kernels.h +70 -0
  58. data/ext/ca_sweep_engine.c +102 -79
  59. data/ext/ca_sweep_engine.h +7 -20
  60. data/ext/ca_triop_dispatch.c +4 -1
  61. data/ext/ca_triop_dispatch.h +5 -2
  62. data/ext/caframe_csv_reader.c +463 -0
  63. data/ext/carray.h +70 -27
  64. data/ext/carray_access.c +455 -211
  65. data/ext/carray_address_basis.c +177 -36
  66. data/ext/carray_attribute.c +45 -3
  67. data/ext/carray_bincount.c +32 -2
  68. data/ext/carray_broadcast.c +46 -14
  69. data/ext/carray_call_cfunc.c +0 -28
  70. data/ext/carray_cast.c +1444 -209
  71. data/ext/carray_cast_func.rb +34 -21
  72. data/ext/carray_conversion.c +197 -73
  73. data/ext/carray_copy.c +32 -11
  74. data/ext/carray_core.c +514 -122
  75. data/ext/carray_count.c +140 -87
  76. data/ext/carray_element.c +18 -27
  77. data/ext/carray_factorize.c +569 -277
  78. data/ext/carray_generate.c +76 -40
  79. data/ext/carray_histogram.c +152 -94
  80. data/ext/carray_hold.c +2 -1
  81. data/ext/carray_index_classifier.c +63 -96
  82. data/ext/carray_internal.h +385 -3
  83. data/ext/carray_lazy.c +834 -79
  84. data/ext/carray_loop.c +81 -65
  85. data/ext/carray_mask.c +682 -316
  86. data/ext/carray_math_kernel.h +1 -0
  87. data/ext/carray_median_percentile.c +221 -76
  88. data/ext/carray_memory_view.c +254 -248
  89. data/ext/carray_operator.c +1089 -359
  90. data/ext/carray_order.c +133 -69
  91. data/ext/carray_partition.c +102 -56
  92. data/ext/carray_random.c +273 -239
  93. data/ext/carray_scatter.c +308 -65
  94. data/ext/carray_segment.c +257 -0
  95. data/ext/carray_slab.c +170 -70
  96. data/ext/carray_sort.c +215 -218
  97. data/ext/carray_sort_kernel.c +8 -1
  98. data/ext/carray_struct.c +99 -21
  99. data/ext/carray_test.c +167 -64
  100. data/ext/carray_time_text.c +1182 -0
  101. data/ext/carray_utils.c +363 -98
  102. data/ext/extconf.rb +27 -2
  103. data/ext/mk_call_cfunc.rb +0 -2
  104. data/ext/mk_pow5_table.rb +35 -0
  105. data/ext/mkkernel.rb +1076 -846
  106. data/ext/ruby_carray.c +7 -1
  107. data/ext/version.h +4 -4
  108. data/ext/version.rb +4 -2
  109. data/lib/carray/attribute.rb +39 -0
  110. data/lib/carray/autoload_carray.rb +19 -0
  111. data/lib/carray/autoload_method_extension.rb +6 -0
  112. data/lib/carray/axis_group.rb +174 -26
  113. data/lib/carray/basics.rb +91 -25
  114. data/lib/carray/bincount_nd.rb +6 -0
  115. data/lib/carray/block_iterator.rb +118 -48
  116. data/lib/carray/boolean_reduce.rb +21 -29
  117. data/lib/carray/categorical.rb +94 -26
  118. data/lib/carray/categorical_iterator.rb +333 -826
  119. data/lib/carray/complex.rb +36 -29
  120. data/lib/carray/conditional.rb +94 -7
  121. data/lib/carray/const_string.rb +46 -0
  122. data/lib/carray/frame/concat.rb +157 -6
  123. data/lib/carray/frame/convert.rb +13 -7
  124. data/lib/carray/frame/csv_parser.rb +589 -82
  125. data/lib/carray/frame/describe.rb +79 -0
  126. data/lib/carray/frame/frame.rb +124 -25
  127. data/lib/carray/frame/group.rb +189 -63
  128. data/lib/carray/frame/io.rb +412 -72
  129. data/lib/carray/frame/join.rb +134 -46
  130. data/lib/carray/frame/records.rb +37 -16
  131. data/lib/carray/frame/reshape.rb +448 -0
  132. data/lib/carray/frame/sort.rb +26 -2
  133. data/lib/carray/frame/verbs.rb +715 -48
  134. data/lib/carray/frame.rb +2 -0
  135. data/lib/carray/fuse_source.rb +111 -2
  136. data/lib/carray/fusion.rb +229 -38
  137. data/lib/carray/inspect.rb +29 -11
  138. data/lib/carray/iterator.rb +14 -2
  139. data/lib/carray/lazy.rb +54 -30
  140. data/lib/carray/mask_gap_fill.rb +66 -52
  141. data/lib/carray/math.rb +32 -19
  142. data/lib/carray/meld_reduce.rb +40 -7
  143. data/lib/carray/methods/align_addr.rb +8 -4
  144. data/lib/carray/methods/bincount.rb +2 -2
  145. data/lib/carray/methods/bit_string.rb +14 -3
  146. data/lib/carray/methods/composition.rb +16 -10
  147. data/lib/carray/methods/factorize.rb +2 -2
  148. data/lib/carray/methods/gather_nd.rb +13 -2
  149. data/lib/carray/methods/insert_block.rb +9 -14
  150. data/lib/carray/methods/is_in.rb +117 -4
  151. data/lib/carray/methods/join.rb +1 -1
  152. data/lib/carray/methods/locate_addr.rb +177 -36
  153. data/lib/carray/methods/mode.rb +18 -1
  154. data/lib/carray/methods/repeat.rb +1 -20
  155. data/lib/carray/methods/resize.rb +21 -23
  156. data/lib/carray/methods/snap.rb +34 -12
  157. data/lib/carray/methods/unique.rb +11 -2
  158. data/lib/carray/record_order.rb +208 -0
  159. data/lib/carray/runtime.rb +14 -11
  160. data/lib/carray/segment_iterator.rb +990 -0
  161. data/lib/carray/serialize.rb +197 -27
  162. data/lib/carray/slab_iterator.rb +51 -27
  163. data/lib/carray/stack.rb +10 -4
  164. data/lib/carray/string_operation_extension.rb +4 -3
  165. data/lib/carray/struct.rb +142 -51
  166. data/lib/carray/struct_builder.rb +110 -14
  167. data/lib/carray/table.rb +2 -2
  168. data/lib/carray/time.rb +517 -103
  169. data/lib/carray/window_iterator.rb +127 -72
  170. data/lib/carray.rb +2 -2
  171. data/yard-stubs/ca_obj_array.rb +4 -4
  172. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  173. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  174. data/yard-stubs/ca_obj_fake.rb +1 -1
  175. data/yard-stubs/ca_obj_field.rb +1 -1
  176. data/yard-stubs/ca_obj_refer.rb +3 -3
  177. data/yard-stubs/ca_obj_roll.rb +0 -1
  178. data/yard-stubs/ca_obj_stride.rb +10 -7
  179. data/yard-stubs/ca_obj_transpose.rb +1 -1
  180. data/yard-stubs/ca_obj_window.rb +1 -2
  181. data/yard-stubs/carray_access.rb +5 -4
  182. data/yard-stubs/carray_broadcast.rb +1 -1
  183. data/yard-stubs/carray_cast.rb +78 -43
  184. data/yard-stubs/carray_conversion.rb +13 -1
  185. data/yard-stubs/carray_copy.rb +8 -3
  186. data/yard-stubs/carray_core.rb +3 -3
  187. data/yard-stubs/carray_count.rb +9 -0
  188. data/yard-stubs/carray_lazy.rb +5 -1
  189. data/yard-stubs/carray_loop.rb +4 -1
  190. data/yard-stubs/carray_mask.rb +34 -10
  191. data/yard-stubs/carray_math.rb +25 -13
  192. data/yard-stubs/carray_median_percentile.rb +10 -6
  193. data/yard-stubs/carray_order.rb +34 -13
  194. data/yard-stubs/carray_scatter.rb +10 -3
  195. data/yard-stubs/carray_segment.rb +72 -0
  196. data/yard-stubs/carray_slab.rb +2 -1
  197. data/yard-stubs/carray_sort.rb +43 -3
  198. data/yard-stubs/carray_test.rb +10 -0
  199. data/yard-stubs/carray_utils.rb +0 -26
  200. metadata +11 -19
  201. data/ext/ca_for_each_element.h +0 -239
  202. data/ext/carray_build_flags.h +0 -3
  203. data/ext/carray_config.h +0 -28
  204. data/ext/carray_kernels_bincmp.c +0 -4446
  205. data/ext/carray_kernels_binop.c +0 -11001
  206. data/ext/carray_kernels_init.c +0 -1131
  207. data/ext/carray_kernels_map.c +0 -3467
  208. data/ext/carray_kernels_moncmp.c +0 -2097
  209. data/ext/carray_kernels_monop.c +0 -18313
  210. data/ext/carray_kernels_reduce_aggregate.c +0 -26005
  211. data/ext/carray_kernels_reduce_boolean.c +0 -330
  212. data/ext/carray_kernels_reduce_cumulative.c +0 -14862
  213. data/ext/carray_kernels_reduce_extreme.c +0 -17494
  214. data/ext/carray_kernels_reduce_variance.c +0 -3910
  215. data/ext/carray_kernels_scan.c +0 -3693
  216. data/ext/carray_kernels_search.c +0 -32218
  217. data/ext/carray_kernels_sort.c +0 -10626
  218. 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 = {
@@ -1427,7 +1519,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1427
1519
  cbounds = StringValuePtr(rbounds);
1428
1520
  if ( rfval == CA_UNDEF && strncmp(cbounds, "fill", 4)
1429
1521
  && strncmp(cbounds, "mask", 4) ) {
1430
- rb_raise(rb_eRuntimeError, "conflicted bounds and fill_value");
1522
+ rb_raise(rb_eArgError, "conflicted bounds and fill_value");
1431
1523
  }
1432
1524
  if ( ! strncmp(cbounds, "ruby", 4) ) {
1433
1525
  bounds = CA_BOUNDS_RUBY;
@@ -1458,7 +1550,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1458
1550
  bounds = CA_BOUNDS_FILL;
1459
1551
  }
1460
1552
  else {
1461
- rb_raise(rb_eRuntimeError,
1553
+ rb_raise(rb_eArgError,
1462
1554
  "unknown option value '%s' for :bounds", cbounds);
1463
1555
  }
1464
1556
  break;
@@ -1466,7 +1558,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1466
1558
  bounds = NUM2INT(rbounds);
1467
1559
  break;
1468
1560
  default:
1469
- rb_raise(rb_eRuntimeError, "invalid option value for :bounds");
1561
+ rb_raise(rb_eArgError, "invalid option value for :bounds");
1470
1562
  }
1471
1563
  }
1472
1564
 
@@ -1491,6 +1583,7 @@ rb_ca_window_initialize_copy (VALUE self, VALUE other)
1491
1583
  CAWindow *ca, *cs;
1492
1584
 
1493
1585
  TypedData_Get_Struct(self, CAWindow, &cawindow_data_type, ca);
1586
+ ca_check_uninitialized(ca);
1494
1587
  TypedData_Get_Struct(other, CAWindow, &cawindow_data_type, cs);
1495
1588
 
1496
1589
  /* `self` came from rb_ca_window_s_allocate (TypedData_Make_Struct,
@@ -1588,6 +1681,34 @@ rb_ca_window_get_bounds (VALUE self)
1588
1681
  return SIZE2NUM(cw->bounds[0]);
1589
1682
  }
1590
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
+
1591
1712
  #define rb_cw_get_attr_ary(name) \
1592
1713
  rb_cw_## name (VALUE self) \
1593
1714
  { \
@@ -1688,6 +1809,7 @@ Init_ca_obj_window (void)
1688
1809
  /* No `count` accessor: the per-axis window widths are what `shape`
1689
1810
  already answers, and the name belongs to CArray#count. */
1690
1811
  rb_define_method(rb_cCAWindow, "start", rb_cw_start, 0);
1812
+ rb_define_method(rb_cCAWindow, "__axis_bounds__", rb_ca_window_axis_bounds, 0);
1691
1813
  rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
1692
1814
 
1693
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
  }
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