carray 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_window.c CHANGED
@@ -268,10 +268,19 @@ ca_window_compose_fold (void *win_ap,
268
268
  for the window-over-parent mapping (ca_window_compose_fold) and composes
269
269
  f through it (ca_stride_compose_through). Declines (returns 0) when the
270
270
  window is not interior-only, making the window the fold boundary. */
271
+ static void ca_window_mask_current (CAWindow *ca);
272
+ static int ca_window_mask_reads_standin (CAWindow *ca);
273
+
271
274
  static int
272
275
  ca_window_func_fold_stride (void *ap, ca_fold_t *f, void **next_parent)
273
276
  {
274
277
  CAWindow *w = (CAWindow *) ap;
278
+ ca_window_mask_current(w);
279
+ /* A write folded through to a stand-in would bypass the settle in this
280
+ window's write slots. */
281
+ if ( ca_window_mask_reads_standin(w) ) {
282
+ return 0;
283
+ }
275
284
  ca_size_t synth_strides[CA_RANK_MAX];
276
285
  ca_size_t synth_base;
277
286
  ca_size_t *synth_dim;
@@ -329,6 +338,7 @@ ca_window_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
329
338
  {
330
339
  if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
331
340
  CAWindow *w = (CAWindow *) ap;
341
+ ca_window_mask_current(w);
332
342
  CArray *parent = w->parent;
333
343
  int8_t ndim = w->ndim;
334
344
  int8_t inner = ndim - 1;
@@ -369,6 +379,7 @@ ca_window_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
369
379
  ca_size_t idx[CA_RANK_MAX], doff = 0, base = 0;
370
380
  for (k = 0; k < ndim; k++) base += starts[k] * wnative[k];
371
381
  for (k = 0; k < ndim; k++) idx[k] = 0;
382
+ /* empty: the slot returns on an empty region at its entry */
372
383
  while (1) {
373
384
  ca_size_t woff = base, widx[CA_RANK_MAX];
374
385
  for (k = 0; k < ndim; k++) woff += idx[k] * strides[k];
@@ -672,7 +683,6 @@ ca_window_setup (CAWindow *ca, CArray *parent,
672
683
  ca_size_t *dim;
673
684
  ca_size_t bytes, elements;
674
685
  int i;
675
- int any_mask;
676
686
 
677
687
  data_type = parent->data_type;
678
688
  ndim = parent->ndim;
@@ -688,6 +698,27 @@ ca_window_setup (CAWindow *ca, CArray *parent,
688
698
  }
689
699
  elements = ca_shape_elements(ndim, count, bytes);
690
700
 
701
+ /* Under "ruby" or "strict" an index outside the parent raises. The
702
+ parent's shape is fixed, so a window that reaches outside it would raise
703
+ on every whole read or write, and a write would have changed the cells
704
+ before the one that raised. It is refused here instead. */
705
+ for (i=0; i<ndim; i++) {
706
+ ca_size_t lo, hi, size = dim[i];
707
+ if ( count[i] == 0 ) {
708
+ continue;
709
+ }
710
+ lo = start[i];
711
+ hi = start[i] + count[i] - 1;
712
+ if ( bounds[i] == CA_BOUNDS_STRICT ) {
713
+ if ( lo < 0 ) ca_index_out_of_range(lo, size, "index");
714
+ if ( hi >= size ) ca_index_out_of_range(hi, size, "index");
715
+ }
716
+ else if ( bounds[i] == CA_BOUNDS_RUBY ) {
717
+ if ( lo < -size ) ca_index_out_of_range(lo, size, "index");
718
+ if ( hi >= size ) ca_index_out_of_range(hi, size, "index");
719
+ }
720
+ }
721
+
691
722
  /* ca == NULL asks for the checks above only, so that a constructor can
692
723
  run them before it allocates. */
693
724
  if ( ca == NULL ) {
@@ -707,6 +738,8 @@ ca_window_setup (CAWindow *ca, CArray *parent,
707
738
  ca->parent = parent;
708
739
  ca->attach = 0;
709
740
  ca->nosync = 0;
741
+ ca->mask_standin = NULL;
742
+ ca->mask_owner = NULL;
710
743
  /* Pool path: bounds/start/count/size0/embed_* are already wired into
711
744
  ca->_pool by ca_window_pool_init. Legacy path: ALLOC_N each. `fill`
712
745
  is bytes-sized (not ndim) so it stays on its own ALLOC_N in both
@@ -747,30 +780,61 @@ ca_window_setup (CAWindow *ca, CArray *parent,
747
780
  }
748
781
  }
749
782
 
750
- /* Mask is needed if ANY axis uses MASK policy (per-axis). */
751
- any_mask = 0;
752
- for (i=0; i<ndim; i++) {
783
+ return 0;
784
+ }
785
+
786
+ /* A window with an axis of MASK bounds has a mask of its own. Making it
787
+ asks the parent for its mask, which can raise (a CAObject answers in
788
+ Ruby), so the constructor makes it after the setup under
789
+ ca_fill_or_free; see ca_view_inherit_mask. */
790
+ VALUE
791
+ ca_window_create_bounds_mask (VALUE view)
792
+ {
793
+ CAWindow *ca = (CAWindow *) view;
794
+ int8_t i;
795
+ for (i = 0; i < ca->ndim; i++) {
753
796
  if ( ca->bounds[i] == CA_BOUNDS_MASK ) {
754
- any_mask = 1;
797
+ ca_create_mask((CArray *) ca);
755
798
  break;
756
799
  }
757
800
  }
758
- if ( any_mask ) {
759
- ca_create_mask(ca);
760
- }
801
+ return Qnil;
802
+ }
761
803
 
762
- return 0;
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;
763
819
  }
764
820
 
821
+ /* The setup allocates the fill value after the struct and its pool: when
822
+ that fails, the struct goes too. */
765
823
  CAWindow *
766
824
  ca_window_new (CArray *parent,
767
825
  ca_size_t *start, ca_size_t *count, uint8_t *bounds, char *fill)
768
826
  {
769
- CAWindow *ca;
827
+ ca_window_new_arg a;
770
828
  ca_window_setup(NULL, parent, start, count, bounds, fill);
771
- ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
772
- ca_window_setup(ca, parent, start, count, bounds, fill);
773
- 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;
774
838
  }
775
839
 
776
840
  static void
@@ -779,6 +843,7 @@ free_ca_window (void *ap)
779
843
  CAWindow *ca = (CAWindow *) ap;
780
844
  if ( ca != NULL ) {
781
845
  ca_free(ca->mask);
846
+ ca_free(ca->mask_standin);
782
847
  xfree(ca->fill); /* always separate (bytes-sized) */
783
848
  if ( ca->_pool ) {
784
849
  /* bounds/start/count/size0/embed_* all live in ca->_pool. */
@@ -818,7 +883,39 @@ static void *
818
883
  ca_window_func_clone (void *ap)
819
884
  {
820
885
  CAWindow *ca = (CAWindow *) ap;
821
- return ca_window_new(ca->parent, ca->start, ca->count, ca->bounds, ca->fill);
886
+ CAWindow *cp = ca_window_new(ca->parent, ca->start, ca->count, ca->bounds,
887
+ ca->fill);
888
+ cp->mask_owner = ca->mask_owner;
889
+ return cp;
890
+ }
891
+
892
+ /* A mask window over its owner's stand-in (ca_mask_standin_current): what
893
+ it reads from now on. */
894
+ static void
895
+ ca_window_mask_current (CAWindow *ca)
896
+ {
897
+ CAWindow *o = (CAWindow *) ca->mask_owner;
898
+ if ( o != NULL ) {
899
+ ca->parent = ca_mask_standin_current((CArray *) ca, ca->parent, o->parent,
900
+ o->mask_standin);
901
+ }
902
+ }
903
+
904
+ static int
905
+ ca_window_mask_reads_standin (CAWindow *ca)
906
+ {
907
+ CAWindow *o = (CAWindow *) ca->mask_owner;
908
+ return o != NULL && o->mask_standin != NULL && ca->parent == o->mask_standin;
909
+ }
910
+
911
+ /* After a write that may have put a true into the stand-in: it goes on to
912
+ the parent's mask. */
913
+ static void
914
+ ca_window_mask_settle (CAWindow *ca)
915
+ {
916
+ if ( ca_window_mask_reads_standin(ca) ) {
917
+ ca_mask_standin_settle(((CAWindow *) ca->mask_owner)->parent, ca->parent);
918
+ }
822
919
  }
823
920
 
824
921
  /* Per-cell access. GET and PUT share the bound-normalised index walk; an OOB
@@ -828,6 +925,7 @@ static void
828
925
  ca_window_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
829
926
  {
830
927
  CAWindow *ca = (CAWindow *) ap;
928
+ ca_window_mask_current(ca);
831
929
  ca_size_t *start = ca->start;
832
930
  ca_size_t *size0 = ca->size0;
833
931
  ca_size_t idx0[CA_RANK_MAX];
@@ -856,6 +954,7 @@ ca_window_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
856
954
  void *data, int dir)
857
955
  {
858
956
  CAWindow *ca = (CAWindow *) ap;
957
+ ca_window_mask_current(ca);
859
958
  ca_size_t *start = ca->start;
860
959
  ca_size_t *size0 = ca->size0;
861
960
  char *d = (char *) data;
@@ -1010,8 +1109,9 @@ static void
1010
1109
  ca_window_func_allocate (void *ap)
1011
1110
  {
1012
1111
  CAWindow *ca = (CAWindow *) ap;
1112
+ ca_window_mask_current(ca);
1013
1113
  if ( ca_window_owns_buffer(ca) ) {
1014
- ca->ptr = xmalloc(ca_length(ca));
1114
+ ca->ptr = ca_alloc_cells((CArray *) ca);
1015
1115
  return;
1016
1116
  }
1017
1117
  ca_attach(ca->parent);
@@ -1019,7 +1119,7 @@ ca_window_func_allocate (void *ap)
1019
1119
  ca->ptr = ca_window_alias_ptr(ca);
1020
1120
  return;
1021
1121
  }
1022
- ca->ptr = xmalloc(ca_length(ca));
1122
+ ca->ptr = ca_alloc_cells((CArray *) ca);
1023
1123
  }
1024
1124
 
1025
1125
  /* The engine paths below emit a per-axis descriptor (ca_window_describe_axes)
@@ -1034,6 +1134,7 @@ static void
1034
1134
  ca_window_func_attach (void *ap)
1035
1135
  {
1036
1136
  CAWindow *ca = (CAWindow *) ap;
1137
+ ca_window_mask_current(ca);
1037
1138
  if ( ca_window_owns_buffer(ca) ) {
1038
1139
  ca_axis_view_attach_owned(ca);
1039
1140
  return;
@@ -1049,8 +1150,7 @@ ca_window_func_attach (void *ap)
1049
1150
  ca->ptr = ca_window_alias_ptr(ca);
1050
1151
  } else if ( ca->embed_eligible ) {
1051
1152
  /* Embed path: allocate, then 1 fill + 1 strided memcpy. */
1052
- ca_size_t out_len = ca->elements * ca->bytes;
1053
- ca->ptr = xmalloc(out_len > 0 ? out_len : 1);
1153
+ ca->ptr = ca_alloc_cells((CArray *) ca);
1054
1154
  ca_window_attach_embed(ca, ca->ptr);
1055
1155
  } else {
1056
1156
  /* Fallback: PERIODIC / REFLECT / NEAREST / RUBY / STRICT go through
@@ -1085,6 +1185,7 @@ ca_window_func_sync (void *ap)
1085
1185
  ca->elements, ca->ptr);
1086
1186
  }
1087
1187
  ca_sync(ca->parent);
1188
+ ca_window_mask_settle(ca);
1088
1189
  }
1089
1190
 
1090
1191
  static void
@@ -1149,6 +1250,7 @@ static void
1149
1250
  ca_window_func_xfer_all (void *ap, void *data, int dir)
1150
1251
  {
1151
1252
  CAWindow *ca = (CAWindow *) ap;
1253
+ ca_window_mask_current(ca);
1152
1254
  if ( ca->parent->ptr ) {
1153
1255
  ca_window_func_run_fast_path(ca, (char *) data, dir);
1154
1256
  return;
@@ -1250,6 +1352,7 @@ static void
1250
1352
  ca_window_func_fill_data (void *ap, void *ptr)
1251
1353
  {
1252
1354
  CAWindow *ca = (CAWindow *) ap;
1355
+ ca_window_mask_current(ca);
1253
1356
 
1254
1357
  /* embed_eligible (= no PERIODIC/REFLECT) covers both interior-only
1255
1358
  windows (embed_covers_all == 1) and OOB-bearing ones such as a CAShift
@@ -1334,12 +1437,26 @@ static void
1334
1437
  ca_window_func_create_mask (void *ap)
1335
1438
  {
1336
1439
  CAWindow *ca = (CAWindow *) ap;
1440
+ CArray *pmask;
1337
1441
  boolean8_t fill;
1338
1442
  uint8_t mbounds[CA_RANK_MAX];
1339
1443
  int8_t i;
1340
1444
  int any_mask;
1341
1445
 
1342
- ca_create_mask(ca->parent);
1446
+ /* The mask lies over the parent's mask, or, while the parent has none,
1447
+ over an all-false stand-in this window holds: masking the
1448
+ out-of-bounds cells gives the parent no mask
1449
+ (ca_mask_standin_new). */
1450
+ if ( ca_has_mask(ca->parent) ) {
1451
+ ca_create_mask(ca->parent);
1452
+ pmask = ca->parent->mask;
1453
+ }
1454
+ else {
1455
+ if ( ca->mask_standin == NULL ) {
1456
+ ca->mask_standin = ca_mask_standin_new(ca->parent);
1457
+ }
1458
+ pmask = ca->mask_standin;
1459
+ }
1343
1460
 
1344
1461
  /* Any MASK axis of the view becomes FILL in the mask sub-view, with the
1345
1462
  mask cell forced to 1 (= "masked"). Other axes keep their policy. When
@@ -1358,14 +1475,76 @@ ca_window_func_create_mask (void *ap)
1358
1475
  /* The mask has the view's own type, so CAShift (which shares this table)
1359
1476
  gets a CAShiftMask. */
1360
1477
  {
1478
+ /* check: the mask window copies its own window's checked ranges */
1361
1479
  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;
1480
+ ca_window_setup(m, pmask, ca->start, ca->count, mbounds, (char*)&fill);
1481
+ m->obj_type = ca->obj_type;
1482
+ m->mask_owner = (CArray *) ca;
1483
+ if ( pmask == ca->mask_standin ) {
1484
+ /* writes inside an attach window reach the stand-in through the
1485
+ sync, where they can give way to the parent's mask */
1486
+ m->embed_alias_eligible = 0;
1487
+ }
1365
1488
  ca->mask = (CArray *) m;
1366
1489
  }
1367
1490
  }
1368
1491
 
1492
+ /* The table's write slots: on the mask of a window still reading a
1493
+ stand-in, a write that may have put a true into it ends with the settle
1494
+ (ca_mask_standin_settle). */
1495
+ static void
1496
+ ca_window_put_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
1497
+ {
1498
+ ca_window_func_xfer_index(ap, idx, data, dir);
1499
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1500
+ && ca_mask_any_true(data, 1) ) {
1501
+ ca_window_mask_settle((CAWindow *) ap);
1502
+ }
1503
+ }
1504
+
1505
+ static void
1506
+ ca_window_put_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data,
1507
+ int dir)
1508
+ {
1509
+ ca_window_func_xfer_addrs(ap, n, addrs, data, dir);
1510
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1511
+ && ca_mask_any_true(data, n) ) {
1512
+ ca_window_mask_settle((CAWindow *) ap);
1513
+ }
1514
+ }
1515
+
1516
+ static void
1517
+ ca_window_put_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
1518
+ ca_size_t *strides, void *data, int dir)
1519
+ {
1520
+ ca_window_func_xfer_stride(ap, starts, counts, strides, data, dir);
1521
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1522
+ && ca_mask_any_true(data,
1523
+ ca_shape_elements(((CArray *) ap)->ndim, counts, 1)) ) {
1524
+ ca_window_mask_settle((CAWindow *) ap);
1525
+ }
1526
+ }
1527
+
1528
+ static void
1529
+ ca_window_put_xfer_all (void *ap, void *data, int dir)
1530
+ {
1531
+ ca_window_func_xfer_all(ap, data, dir);
1532
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1533
+ && ca_mask_any_true(data, ((CArray *) ap)->elements) ) {
1534
+ ca_window_mask_settle((CAWindow *) ap);
1535
+ }
1536
+ }
1537
+
1538
+ static void
1539
+ ca_window_put_fill_data (void *ap, void *ptr)
1540
+ {
1541
+ ca_window_func_fill_data(ap, ptr);
1542
+ if ( ca_window_mask_reads_standin((CAWindow *) ap)
1543
+ && ca_mask_any_true(ptr, 1) ) {
1544
+ ca_window_mask_settle((CAWindow *) ap);
1545
+ }
1546
+ }
1547
+
1369
1548
  ca_operation_function_t ca_window_func = {
1370
1549
  -1, /* CA_OBJ_WINDOW */
1371
1550
  CA_VIEW_ARRAY,
@@ -1375,13 +1554,13 @@ ca_operation_function_t ca_window_func = {
1375
1554
  ca_window_func_attach,
1376
1555
  ca_window_func_sync,
1377
1556
  ca_window_func_detach,
1378
- ca_window_func_fill_data,
1557
+ ca_window_put_fill_data,
1379
1558
  ca_window_func_create_mask,
1380
- ca_window_func_xfer_index,
1381
- ca_window_func_xfer_addrs,
1559
+ ca_window_put_xfer_index,
1560
+ ca_window_put_xfer_addrs,
1382
1561
  ca_window_func_fold_stride,
1383
- ca_window_func_xfer_stride,
1384
- ca_window_func_xfer_all,
1562
+ ca_window_put_xfer_stride,
1563
+ ca_window_put_xfer_all,
1385
1564
  };
1386
1565
 
1387
1566
  /* ------------------------------------------------------------------- */
@@ -1401,6 +1580,7 @@ ca_window_describe_axes (void *ap, ca_axis_desc_t *out,
1401
1580
  ca_size_t *out_parent_dims)
1402
1581
  {
1403
1582
  CAWindow *ca = (CAWindow *) ap;
1583
+ ca_window_mask_current(ca);
1404
1584
  int8_t k;
1405
1585
  for ( k = 0; k < ca->ndim; k++ ) {
1406
1586
  out_parent_dims[k] = ca->parent->dim[k];
@@ -1502,9 +1682,13 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1502
1682
  bounds = CA_BOUNDS_MASK;
1503
1683
  }
1504
1684
  else {
1505
- rcs = rb_cscalar_new_with_value(ca->data_type, ca->bytes, rfval);
1685
+ /* The fill is a value of the array (a String for a CAString, an
1686
+ instant for a time array): rb_ca_obj2ptr writes it as one cell of
1687
+ the storage, through the Face. */
1688
+ rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
1506
1689
  TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cs);
1507
1690
  fill = cs->ptr;
1691
+ rb_ca_obj2ptr(self, rfval, fill);
1508
1692
  }
1509
1693
 
1510
1694
  if ( ! NIL_P(rbounds) ) {
@@ -1514,51 +1698,56 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1514
1698
  if ( SYMBOL_P(rbounds) ) {
1515
1699
  rbounds = rb_sym2str(rbounds);
1516
1700
  }
1517
- switch ( TYPE(rbounds) ) {
1518
- case T_STRING:
1519
- cbounds = StringValuePtr(rbounds);
1520
- if ( rfval == CA_UNDEF && strncmp(cbounds, "fill", 4)
1521
- && strncmp(cbounds, "mask", 4) ) {
1522
- rb_raise(rb_eArgError, "conflicted bounds and fill_value");
1523
- }
1524
- if ( ! strncmp(cbounds, "ruby", 4) ) {
1525
- bounds = CA_BOUNDS_RUBY;
1526
- }
1527
- else if ( ! strncmp(cbounds, "strict", 6) ) {
1528
- bounds = CA_BOUNDS_STRICT;
1529
- }
1530
- else if ( ! strncmp(cbounds, "nearest", 7) ) {
1531
- bounds = CA_BOUNDS_NEAREST;
1532
- }
1533
- else if ( ! strncmp(cbounds, "periodic", 8) ) {
1534
- rb_raise(rb_eArgError,
1535
- "bounds=>'periodic' removed in 3.0; "
1536
- "use CArray#roll(...) for cyclic shift "
1537
- "(returns a CARoll view)");
1538
- }
1539
- else if ( ! strncmp(cbounds, "reflect", 7) ) {
1540
- rb_raise(rb_eArgError,
1541
- "bounds=>'reflect' removed in 3.0; "
1542
- "there is no view-based alternative");
1543
- }
1544
- else if ( ! strncmp(cbounds, "mask", 4) ) {
1545
- rb_warn("CAWindow option :bounds=>\"mask\" will be obsolete");
1546
- rb_warn("use ca.window(..., fill_value: UNDEF)");
1547
- bounds = CA_BOUNDS_MASK;
1548
- }
1549
- else if ( ! strncmp(cbounds, "fill", 4) ) {
1550
- bounds = CA_BOUNDS_FILL;
1551
- }
1552
- else {
1553
- rb_raise(rb_eArgError,
1554
- "unknown option value '%s' for :bounds", cbounds);
1555
- }
1556
- break;
1557
- case T_FIXNUM:
1558
- bounds = NUM2INT(rbounds);
1559
- break;
1560
- default:
1561
- 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);
1562
1751
  }
1563
1752
  }
1564
1753
 
@@ -1593,6 +1782,10 @@ rb_ca_window_initialize_copy (VALUE self, VALUE other)
1593
1782
  ca_array_pool_alloc(ca, CA_OBJ_WINDOW, cs->ndim);
1594
1783
  }
1595
1784
  ca_window_setup(ca, cs->parent, cs->start, cs->count, cs->bounds, cs->fill);
1785
+ ca_window_create_bounds_mask((VALUE) ca);
1786
+ /* a copy of a mask over a stand-in gives way to the parent's mask as
1787
+ the original does */
1788
+ ca->mask_owner = cs->mask_owner;
1596
1789
 
1597
1790
  return self;
1598
1791
  }
@@ -1809,7 +2002,7 @@ Init_ca_obj_window (void)
1809
2002
  /* No `count` accessor: the per-axis window widths are what `shape`
1810
2003
  already answers, and the name belongs to CArray#count. */
1811
2004
  rb_define_method(rb_cCAWindow, "start", rb_cw_start, 0);
1812
- rb_define_method(rb_cCAWindow, "__axis_bounds__", rb_ca_window_axis_bounds, 0);
2005
+ rb_define_method(rb_cCAWindow, "__boundary_rule_of_each_axis__", rb_ca_window_axis_bounds, 0);
1813
2006
  rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
1814
2007
 
1815
2008
  #ifdef CARRAY_DEV_BUILD
data/ext/ca_op_ipower.c CHANGED
@@ -112,7 +112,7 @@ static void
112
112
  ca_ipower_float32_t (ca_size_t n, boolean8_t *m,
113
113
  char *ptr1, int32_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); }
@@ -127,7 +127,7 @@ static void
127
127
  ca_ipower_float64_t (ca_size_t n, boolean8_t *m,
128
128
  char *ptr1, int32_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); }
@@ -142,7 +142,7 @@ static void
142
142
  ca_ipower_cmplx64_t (ca_size_t n, boolean8_t *m,
143
143
  char *ptr1, int32_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); }
@@ -157,7 +157,7 @@ static void
157
157
  ca_ipower_cmplx128_t (ca_size_t n, boolean8_t *m,
158
158
  char *ptr1, int32_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); }
@@ -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
@@ -42,9 +42,9 @@ ca_sweep_refuse_shapes (CArray *a, CArray *b)
42
42
  volatile VALUE sa = ca_sweep_shape_str(a);
43
43
  volatile VALUE sb = ca_sweep_shape_str(b);
44
44
  rb_raise(rb_eArgError,
45
- "shape mismatch between operands (%s and %s); a scalar pairs "
45
+ "%s: shape mismatch between operands (%s and %s); a scalar pairs "
46
46
  "with any array, two arrays only when their shapes agree",
47
- StringValueCStr(sa), StringValueCStr(sb));
47
+ ca_calling_method_name(), StringValueCStr(sa), StringValueCStr(sb));
48
48
  }
49
49
 
50
50
  int