carray 3.0.3 → 3.0.4

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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. 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,19 +780,25 @@ 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
- }
761
-
762
- return 0;
801
+ return Qnil;
763
802
  }
764
803
 
765
804
  CAWindow *
@@ -770,6 +809,7 @@ ca_window_new (CArray *parent,
770
809
  ca_window_setup(NULL, parent, start, count, bounds, fill);
771
810
  ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
772
811
  ca_window_setup(ca, parent, start, count, bounds, fill);
812
+ ca_fill_or_free((CArray *) ca, ca_window_create_bounds_mask, (VALUE) ca);
773
813
  return ca;
774
814
  }
775
815
 
@@ -779,6 +819,7 @@ free_ca_window (void *ap)
779
819
  CAWindow *ca = (CAWindow *) ap;
780
820
  if ( ca != NULL ) {
781
821
  ca_free(ca->mask);
822
+ ca_free(ca->mask_standin);
782
823
  xfree(ca->fill); /* always separate (bytes-sized) */
783
824
  if ( ca->_pool ) {
784
825
  /* bounds/start/count/size0/embed_* all live in ca->_pool. */
@@ -818,7 +859,39 @@ static void *
818
859
  ca_window_func_clone (void *ap)
819
860
  {
820
861
  CAWindow *ca = (CAWindow *) ap;
821
- return ca_window_new(ca->parent, ca->start, ca->count, ca->bounds, ca->fill);
862
+ CAWindow *cp = ca_window_new(ca->parent, ca->start, ca->count, ca->bounds,
863
+ ca->fill);
864
+ cp->mask_owner = ca->mask_owner;
865
+ return cp;
866
+ }
867
+
868
+ /* A mask window over its owner's stand-in (ca_mask_standin_current): what
869
+ it reads from now on. */
870
+ static void
871
+ ca_window_mask_current (CAWindow *ca)
872
+ {
873
+ CAWindow *o = (CAWindow *) ca->mask_owner;
874
+ if ( o != NULL ) {
875
+ ca->parent = ca_mask_standin_current((CArray *) ca, ca->parent, o->parent,
876
+ o->mask_standin);
877
+ }
878
+ }
879
+
880
+ static int
881
+ ca_window_mask_reads_standin (CAWindow *ca)
882
+ {
883
+ CAWindow *o = (CAWindow *) ca->mask_owner;
884
+ return o != NULL && o->mask_standin != NULL && ca->parent == o->mask_standin;
885
+ }
886
+
887
+ /* After a write that may have put a true into the stand-in: it goes on to
888
+ the parent's mask. */
889
+ static void
890
+ ca_window_mask_settle (CAWindow *ca)
891
+ {
892
+ if ( ca_window_mask_reads_standin(ca) ) {
893
+ ca_mask_standin_settle(((CAWindow *) ca->mask_owner)->parent, ca->parent);
894
+ }
822
895
  }
823
896
 
824
897
  /* Per-cell access. GET and PUT share the bound-normalised index walk; an OOB
@@ -828,6 +901,7 @@ static void
828
901
  ca_window_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
829
902
  {
830
903
  CAWindow *ca = (CAWindow *) ap;
904
+ ca_window_mask_current(ca);
831
905
  ca_size_t *start = ca->start;
832
906
  ca_size_t *size0 = ca->size0;
833
907
  ca_size_t idx0[CA_RANK_MAX];
@@ -856,6 +930,7 @@ ca_window_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
856
930
  void *data, int dir)
857
931
  {
858
932
  CAWindow *ca = (CAWindow *) ap;
933
+ ca_window_mask_current(ca);
859
934
  ca_size_t *start = ca->start;
860
935
  ca_size_t *size0 = ca->size0;
861
936
  char *d = (char *) data;
@@ -1010,8 +1085,9 @@ static void
1010
1085
  ca_window_func_allocate (void *ap)
1011
1086
  {
1012
1087
  CAWindow *ca = (CAWindow *) ap;
1088
+ ca_window_mask_current(ca);
1013
1089
  if ( ca_window_owns_buffer(ca) ) {
1014
- ca->ptr = xmalloc(ca_length(ca));
1090
+ ca->ptr = ca_alloc_cells((CArray *) ca);
1015
1091
  return;
1016
1092
  }
1017
1093
  ca_attach(ca->parent);
@@ -1019,7 +1095,7 @@ ca_window_func_allocate (void *ap)
1019
1095
  ca->ptr = ca_window_alias_ptr(ca);
1020
1096
  return;
1021
1097
  }
1022
- ca->ptr = xmalloc(ca_length(ca));
1098
+ ca->ptr = ca_alloc_cells((CArray *) ca);
1023
1099
  }
1024
1100
 
1025
1101
  /* The engine paths below emit a per-axis descriptor (ca_window_describe_axes)
@@ -1034,6 +1110,7 @@ static void
1034
1110
  ca_window_func_attach (void *ap)
1035
1111
  {
1036
1112
  CAWindow *ca = (CAWindow *) ap;
1113
+ ca_window_mask_current(ca);
1037
1114
  if ( ca_window_owns_buffer(ca) ) {
1038
1115
  ca_axis_view_attach_owned(ca);
1039
1116
  return;
@@ -1049,8 +1126,7 @@ ca_window_func_attach (void *ap)
1049
1126
  ca->ptr = ca_window_alias_ptr(ca);
1050
1127
  } else if ( ca->embed_eligible ) {
1051
1128
  /* 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);
1129
+ ca->ptr = ca_alloc_cells((CArray *) ca);
1054
1130
  ca_window_attach_embed(ca, ca->ptr);
1055
1131
  } else {
1056
1132
  /* Fallback: PERIODIC / REFLECT / NEAREST / RUBY / STRICT go through
@@ -1085,6 +1161,7 @@ ca_window_func_sync (void *ap)
1085
1161
  ca->elements, ca->ptr);
1086
1162
  }
1087
1163
  ca_sync(ca->parent);
1164
+ ca_window_mask_settle(ca);
1088
1165
  }
1089
1166
 
1090
1167
  static void
@@ -1149,6 +1226,7 @@ static void
1149
1226
  ca_window_func_xfer_all (void *ap, void *data, int dir)
1150
1227
  {
1151
1228
  CAWindow *ca = (CAWindow *) ap;
1229
+ ca_window_mask_current(ca);
1152
1230
  if ( ca->parent->ptr ) {
1153
1231
  ca_window_func_run_fast_path(ca, (char *) data, dir);
1154
1232
  return;
@@ -1250,6 +1328,7 @@ static void
1250
1328
  ca_window_func_fill_data (void *ap, void *ptr)
1251
1329
  {
1252
1330
  CAWindow *ca = (CAWindow *) ap;
1331
+ ca_window_mask_current(ca);
1253
1332
 
1254
1333
  /* embed_eligible (= no PERIODIC/REFLECT) covers both interior-only
1255
1334
  windows (embed_covers_all == 1) and OOB-bearing ones such as a CAShift
@@ -1334,12 +1413,26 @@ static void
1334
1413
  ca_window_func_create_mask (void *ap)
1335
1414
  {
1336
1415
  CAWindow *ca = (CAWindow *) ap;
1416
+ CArray *pmask;
1337
1417
  boolean8_t fill;
1338
1418
  uint8_t mbounds[CA_RANK_MAX];
1339
1419
  int8_t i;
1340
1420
  int any_mask;
1341
1421
 
1342
- ca_create_mask(ca->parent);
1422
+ /* The mask lies over the parent's mask, or, while the parent has none,
1423
+ over an all-false stand-in this window holds: masking the
1424
+ out-of-bounds cells gives the parent no mask
1425
+ (ca_mask_standin_new). */
1426
+ if ( ca_has_mask(ca->parent) ) {
1427
+ ca_create_mask(ca->parent);
1428
+ pmask = ca->parent->mask;
1429
+ }
1430
+ else {
1431
+ if ( ca->mask_standin == NULL ) {
1432
+ ca->mask_standin = ca_mask_standin_new(ca->parent);
1433
+ }
1434
+ pmask = ca->mask_standin;
1435
+ }
1343
1436
 
1344
1437
  /* Any MASK axis of the view becomes FILL in the mask sub-view, with the
1345
1438
  mask cell forced to 1 (= "masked"). Other axes keep their policy. When
@@ -1358,14 +1451,76 @@ ca_window_func_create_mask (void *ap)
1358
1451
  /* The mask has the view's own type, so CAShift (which shares this table)
1359
1452
  gets a CAShiftMask. */
1360
1453
  {
1454
+ /* check: the mask window copies its own window's checked ranges */
1361
1455
  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;
1456
+ ca_window_setup(m, pmask, ca->start, ca->count, mbounds, (char*)&fill);
1457
+ m->obj_type = ca->obj_type;
1458
+ m->mask_owner = (CArray *) ca;
1459
+ if ( pmask == ca->mask_standin ) {
1460
+ /* writes inside an attach window reach the stand-in through the
1461
+ sync, where they can give way to the parent's mask */
1462
+ m->embed_alias_eligible = 0;
1463
+ }
1365
1464
  ca->mask = (CArray *) m;
1366
1465
  }
1367
1466
  }
1368
1467
 
1468
+ /* The table's write slots: on the mask of a window still reading a
1469
+ stand-in, a write that may have put a true into it ends with the settle
1470
+ (ca_mask_standin_settle). */
1471
+ static void
1472
+ ca_window_put_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
1473
+ {
1474
+ ca_window_func_xfer_index(ap, idx, data, dir);
1475
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1476
+ && ca_mask_any_true(data, 1) ) {
1477
+ ca_window_mask_settle((CAWindow *) ap);
1478
+ }
1479
+ }
1480
+
1481
+ static void
1482
+ ca_window_put_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *data,
1483
+ int dir)
1484
+ {
1485
+ ca_window_func_xfer_addrs(ap, n, addrs, data, dir);
1486
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1487
+ && ca_mask_any_true(data, n) ) {
1488
+ ca_window_mask_settle((CAWindow *) ap);
1489
+ }
1490
+ }
1491
+
1492
+ static void
1493
+ ca_window_put_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
1494
+ ca_size_t *strides, void *data, int dir)
1495
+ {
1496
+ ca_window_func_xfer_stride(ap, starts, counts, strides, data, dir);
1497
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1498
+ && ca_mask_any_true(data,
1499
+ ca_shape_elements(((CArray *) ap)->ndim, counts, 1)) ) {
1500
+ ca_window_mask_settle((CAWindow *) ap);
1501
+ }
1502
+ }
1503
+
1504
+ static void
1505
+ ca_window_put_xfer_all (void *ap, void *data, int dir)
1506
+ {
1507
+ ca_window_func_xfer_all(ap, data, dir);
1508
+ if ( dir == CA_XFER_PUT && ca_window_mask_reads_standin((CAWindow *) ap)
1509
+ && ca_mask_any_true(data, ((CArray *) ap)->elements) ) {
1510
+ ca_window_mask_settle((CAWindow *) ap);
1511
+ }
1512
+ }
1513
+
1514
+ static void
1515
+ ca_window_put_fill_data (void *ap, void *ptr)
1516
+ {
1517
+ ca_window_func_fill_data(ap, ptr);
1518
+ if ( ca_window_mask_reads_standin((CAWindow *) ap)
1519
+ && ca_mask_any_true(ptr, 1) ) {
1520
+ ca_window_mask_settle((CAWindow *) ap);
1521
+ }
1522
+ }
1523
+
1369
1524
  ca_operation_function_t ca_window_func = {
1370
1525
  -1, /* CA_OBJ_WINDOW */
1371
1526
  CA_VIEW_ARRAY,
@@ -1375,13 +1530,13 @@ ca_operation_function_t ca_window_func = {
1375
1530
  ca_window_func_attach,
1376
1531
  ca_window_func_sync,
1377
1532
  ca_window_func_detach,
1378
- ca_window_func_fill_data,
1533
+ ca_window_put_fill_data,
1379
1534
  ca_window_func_create_mask,
1380
- ca_window_func_xfer_index,
1381
- ca_window_func_xfer_addrs,
1535
+ ca_window_put_xfer_index,
1536
+ ca_window_put_xfer_addrs,
1382
1537
  ca_window_func_fold_stride,
1383
- ca_window_func_xfer_stride,
1384
- ca_window_func_xfer_all,
1538
+ ca_window_put_xfer_stride,
1539
+ ca_window_put_xfer_all,
1385
1540
  };
1386
1541
 
1387
1542
  /* ------------------------------------------------------------------- */
@@ -1401,6 +1556,7 @@ ca_window_describe_axes (void *ap, ca_axis_desc_t *out,
1401
1556
  ca_size_t *out_parent_dims)
1402
1557
  {
1403
1558
  CAWindow *ca = (CAWindow *) ap;
1559
+ ca_window_mask_current(ca);
1404
1560
  int8_t k;
1405
1561
  for ( k = 0; k < ca->ndim; k++ ) {
1406
1562
  out_parent_dims[k] = ca->parent->dim[k];
@@ -1502,9 +1658,13 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1502
1658
  bounds = CA_BOUNDS_MASK;
1503
1659
  }
1504
1660
  else {
1505
- rcs = rb_cscalar_new_with_value(ca->data_type, ca->bytes, rfval);
1661
+ /* The fill is a value of the array (a String for a CAString, an
1662
+ instant for a time array): rb_ca_obj2ptr writes it as one cell of
1663
+ the storage, through the Face. */
1664
+ rcs = rb_cscalar_new(ca_strip_face(ca)->data_type, ca->bytes, NULL);
1506
1665
  TypedData_Get_Struct(rcs, CScalar, &cscalar_data_type, cs);
1507
1666
  fill = cs->ptr;
1667
+ rb_ca_obj2ptr(self, rfval, fill);
1508
1668
  }
1509
1669
 
1510
1670
  if ( ! NIL_P(rbounds) ) {
@@ -1593,6 +1753,10 @@ rb_ca_window_initialize_copy (VALUE self, VALUE other)
1593
1753
  ca_array_pool_alloc(ca, CA_OBJ_WINDOW, cs->ndim);
1594
1754
  }
1595
1755
  ca_window_setup(ca, cs->parent, cs->start, cs->count, cs->bounds, cs->fill);
1756
+ ca_window_create_bounds_mask((VALUE) ca);
1757
+ /* a copy of a mask over a stand-in gives way to the parent's mask as
1758
+ the original does */
1759
+ ca->mask_owner = cs->mask_owner;
1596
1760
 
1597
1761
  return self;
1598
1762
  }
@@ -1809,7 +1973,7 @@ Init_ca_obj_window (void)
1809
1973
  /* No `count` accessor: the per-axis window widths are what `shape`
1810
1974
  already answers, and the name belongs to CArray#count. */
1811
1975
  rb_define_method(rb_cCAWindow, "start", rb_cw_start, 0);
1812
- rb_define_method(rb_cCAWindow, "__axis_bounds__", rb_ca_window_axis_bounds, 0);
1976
+ rb_define_method(rb_cCAWindow, "__boundary_rule_of_each_axis__", rb_ca_window_axis_bounds, 0);
1813
1977
  rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
1814
1978
 
1815
1979
  #ifdef CARRAY_DEV_BUILD
@@ -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
@@ -39,6 +39,85 @@ ca_csv_at (const char *s, long n, long p, const char *t, long tlen)
39
39
  return p + tlen <= n && memcmp(s + p, t, tlen) == 0;
40
40
  }
41
41
 
42
+ /* The coderange of UTF-8 text, as rb_enc_str_coderange answers it: 7BIT,
43
+ VALID, or BROKEN for an invalid sequence (a stray continuation byte, an
44
+ overlong form, a surrogate, past U+10FFFF, or a sequence cut short).
45
+ Runs of ASCII are passed over 8 bytes at a time, which Ruby's scan does
46
+ not do once it has met a multibyte character. */
47
+ static int
48
+ ca_csv_utf8_coderange (const unsigned char *s, long n)
49
+ {
50
+ long i = 0;
51
+ int ascii = 1;
52
+ while ( i < n ) {
53
+ unsigned c, c1;
54
+ while ( i + 8 <= n ) {
55
+ uint64_t w;
56
+ memcpy(&w, s + i, 8);
57
+ if ( w & 0x8080808080808080ULL ) {
58
+ break;
59
+ }
60
+ i += 8;
61
+ }
62
+ if ( i >= n ) {
63
+ break;
64
+ }
65
+ c = s[i];
66
+ if ( c < 0x80 ) {
67
+ i += 1;
68
+ continue;
69
+ }
70
+ ascii = 0;
71
+ if ( c < 0xC2 || c > 0xF4 ) {
72
+ return ENC_CODERANGE_BROKEN;
73
+ }
74
+ if ( c < 0xE0 ) {
75
+ if ( i + 1 >= n || ( s[i + 1] & 0xC0 ) != 0x80 ) {
76
+ return ENC_CODERANGE_BROKEN;
77
+ }
78
+ i += 2;
79
+ continue;
80
+ }
81
+ if ( i + 1 >= n ) {
82
+ return ENC_CODERANGE_BROKEN;
83
+ }
84
+ c1 = s[i + 1];
85
+ if ( ( c1 & 0xC0 ) != 0x80
86
+ || ( c == 0xE0 && c1 < 0xA0 ) || ( c == 0xED && c1 > 0x9F )
87
+ || ( c == 0xF0 && c1 < 0x90 ) || ( c == 0xF4 && c1 > 0x8F ) ) {
88
+ return ENC_CODERANGE_BROKEN;
89
+ }
90
+ if ( c < 0xF0 ) {
91
+ if ( i + 2 >= n || ( s[i + 2] & 0xC0 ) != 0x80 ) {
92
+ return ENC_CODERANGE_BROKEN;
93
+ }
94
+ i += 3;
95
+ continue;
96
+ }
97
+ if ( i + 3 >= n || ( s[i + 2] & 0xC0 ) != 0x80 || ( s[i + 3] & 0xC0 ) != 0x80 ) {
98
+ return ENC_CODERANGE_BROKEN;
99
+ }
100
+ i += 4;
101
+ }
102
+ return ascii ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID;
103
+ }
104
+
105
+ /* The coderange of the text, computed here for UTF-8 and cached on the
106
+ String as Ruby would cache it, so the Ruby reader's later String#count on
107
+ the same chunk does not scan it again. */
108
+ static int
109
+ ca_csv_text_coderange (VALUE text, rb_encoding *enc)
110
+ {
111
+ int cr = ENC_CODERANGE(text);
112
+ if ( cr != ENC_CODERANGE_UNKNOWN || enc != rb_utf8_encoding() ) {
113
+ return rb_enc_str_coderange(text);
114
+ }
115
+ cr = ca_csv_utf8_coderange((const unsigned char *) RSTRING_PTR(text),
116
+ RSTRING_LEN(text));
117
+ ENC_CODERANGE_SET(text, cr);
118
+ return cr;
119
+ }
120
+
42
121
  /* The end of the line content that starts at p: the position of its "\n",
43
122
  or n; *next is where the following line starts. A "\r" before the "\n",
44
123
  or at the end of the text, is not content. */
@@ -311,7 +390,7 @@ ca_csv_check_reader_args (VALUE text, VALUE vsep, VALUE vquote, VALUE vncol,
311
390
  *ncol = NUM2LONG(vncol);
312
391
  enc = rb_enc_get(text);
313
392
  if ( ( enc != rb_utf8_encoding() && enc != rb_usascii_encoding() )
314
- || rb_enc_str_coderange(text) == ENC_CODERANGE_BROKEN || *ncol < 0 ) {
393
+ || ca_csv_text_coderange(text, enc) == ENC_CODERANGE_BROKEN || *ncol < 0 ) {
315
394
  return 0;
316
395
  }
317
396
  return RSTRING_LEN(vsep) >= 1 && RSTRING_LEN(vquote) >= 1;