carray 3.0.4 → 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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +205 -0
  3. data/carray.gemspec +1 -1
  4. data/ext/ca_array_pool.c +25 -1
  5. data/ext/ca_axis_dispatch.c +13 -20
  6. data/ext/ca_categorical_iterator.c +27 -20
  7. data/ext/ca_compare.c +4 -4
  8. data/ext/ca_composite_dispatch.c +9 -9
  9. data/ext/ca_kernel_iterator.c +6 -6
  10. data/ext/ca_kernel_iterator.h +112 -83
  11. data/ext/ca_obj_array.c +69 -19
  12. data/ext/ca_obj_bincmp.c +1 -0
  13. data/ext/ca_obj_binop.c +1 -0
  14. data/ext/ca_obj_bitarray.c +5 -1
  15. data/ext/ca_obj_bitfield.c +58 -43
  16. data/ext/ca_obj_byte_swap.c +2 -1
  17. data/ext/ca_obj_const_string.c +15 -3
  18. data/ext/ca_obj_face.c +42 -1
  19. data/ext/ca_obj_field.c +13 -3
  20. data/ext/ca_obj_grid.c +52 -5
  21. data/ext/ca_obj_monop.c +46 -10
  22. data/ext/ca_obj_object.c +64 -12
  23. data/ext/ca_obj_record.c +3 -0
  24. data/ext/ca_obj_reduce.c +4 -0
  25. data/ext/ca_obj_refer.c +18 -9
  26. data/ext/ca_obj_roll.c +26 -6
  27. data/ext/ca_obj_select.c +34 -5
  28. data/ext/ca_obj_shift.c +31 -7
  29. data/ext/ca_obj_stack.c +1 -0
  30. data/ext/ca_obj_stride.c +28 -19
  31. data/ext/ca_obj_string.c +11 -2
  32. data/ext/ca_obj_tile.c +27 -7
  33. data/ext/ca_obj_transpose.c +8 -4
  34. data/ext/ca_obj_triop.c +3 -0
  35. data/ext/ca_obj_window.c +79 -50
  36. data/ext/ca_op_ipower.c +4 -4
  37. data/ext/ca_sort_kernels.h +6 -3
  38. data/ext/carray.h +33 -0
  39. data/ext/carray_access.c +16 -3
  40. data/ext/carray_attribute.c +24 -0
  41. data/ext/carray_cast.c +243 -82
  42. data/ext/carray_cast_func.rb +56 -26
  43. data/ext/carray_conversion.c +2 -2
  44. data/ext/carray_core.c +3 -0
  45. data/ext/carray_count.c +6 -0
  46. data/ext/carray_element.c +9 -4
  47. data/ext/carray_factorize.c +20 -20
  48. data/ext/carray_generate.c +8 -2
  49. data/ext/carray_histogram.c +1 -1
  50. data/ext/carray_index_classifier.c +4 -4
  51. data/ext/carray_internal.h +12 -0
  52. data/ext/carray_kernels_bincmp.c +168 -168
  53. data/ext/carray_kernels_binop.c +900 -900
  54. data/ext/carray_kernels_init.c +4 -4
  55. data/ext/carray_kernels_moncmp.c +96 -96
  56. data/ext/carray_kernels_monop.c +1984 -1984
  57. data/ext/carray_kernels_reduce_aggregate.c +1733 -1733
  58. data/ext/carray_kernels_reduce_cumulative.c +642 -642
  59. data/ext/carray_kernels_reduce_extreme.c +1150 -1150
  60. data/ext/carray_kernels_reduce_variance.c +258 -258
  61. data/ext/carray_kernels_scan.c +128 -128
  62. data/ext/carray_kernels_search.c +340 -340
  63. data/ext/carray_kernels_sort.c +295 -304
  64. data/ext/carray_kernels_triop.c +114 -114
  65. data/ext/carray_key_windows.c +4 -0
  66. data/ext/carray_mask.c +45 -22
  67. data/ext/carray_memory_view.c +2 -2
  68. data/ext/carray_operator.c +5 -5
  69. data/ext/carray_order.c +227 -8
  70. data/ext/carray_random.c +18 -18
  71. data/ext/carray_scatter.c +24 -7
  72. data/ext/carray_slab.c +32 -9
  73. data/ext/carray_sort.c +224 -16
  74. data/ext/carray_sort_kernel.c +5 -7
  75. data/ext/carray_struct.c +35 -43
  76. data/ext/carray_time_text.c +4 -2
  77. data/ext/carray_utils.c +63 -21
  78. data/ext/mkkernel.rb +210 -115
  79. data/ext/version.h +4 -4
  80. data/lib/carray/attribute.rb +17 -4
  81. data/lib/carray/basics.rb +27 -7
  82. data/lib/carray/categorical.rb +30 -16
  83. data/lib/carray/categorical_iterator.rb +6 -6
  84. data/lib/carray/const_string.rb +10 -0
  85. data/lib/carray/data_type_extension.rb +8 -1
  86. data/lib/carray/fixlen_string.rb +41 -2
  87. data/lib/carray/frame/column_verbs.rb +4 -3
  88. data/lib/carray/frame/concat.rb +17 -3
  89. data/lib/carray/frame/frame.rb +6 -7
  90. data/lib/carray/frame/group.rb +100 -13
  91. data/lib/carray/frame/io.rb +3 -1
  92. data/lib/carray/fuse_source.rb +31 -2
  93. data/lib/carray/lazy.rb +35 -0
  94. data/lib/carray/methods/is_in.rb +8 -1
  95. data/lib/carray/segment_iterator.rb +12 -8
  96. data/lib/carray/serialize.rb +19 -2
  97. data/lib/carray/stack.rb +15 -12
  98. data/lib/carray/string.rb +8 -0
  99. data/lib/carray/string_operation_extension.rb +13 -5
  100. data/lib/carray/struct_builder.rb +5 -3
  101. data/lib/carray/time.rb +107 -68
  102. data/yard-stubs/ca_obj_transpose.rb +5 -4
  103. data/yard-stubs/carray_attribute.rb +3 -1
  104. data/yard-stubs/carray_cast.rb +2 -0
  105. data/yard-stubs/carray_conversion.rb +5 -1
  106. data/yard-stubs/carray_element.rb +7 -6
  107. data/yard-stubs/carray_mask.rb +8 -3
  108. data/yard-stubs/carray_math.rb +14 -4
  109. data/yard-stubs/carray_order.rb +100 -4
  110. data/yard-stubs/carray_scatter.rb +7 -5
  111. metadata +1 -1
data/ext/ca_obj_tile.c CHANGED
@@ -108,6 +108,8 @@ ca_tile_setup (CATile *ca, CArray *parent, ca_size_t *reps)
108
108
  ca->parent = parent;
109
109
  ca->attach = 0;
110
110
  ca->nosync = 0;
111
+ ca->reps = NULL; /* set before either allocation can raise */
112
+ ca->dim = NULL;
111
113
  ca->reps = ALLOC_N(ca_size_t, ndim);
112
114
  ca->dim = ALLOC_N(ca_size_t, ndim);
113
115
 
@@ -120,15 +122,33 @@ ca_tile_setup (CATile *ca, CArray *parent, ca_size_t *reps)
120
122
  return 0;
121
123
  }
122
124
 
125
+ typedef struct {
126
+ CATile *ca;
127
+ CArray *parent;
128
+ ca_size_t *reps;
129
+ } ca_tile_new_arg;
130
+
131
+ static VALUE
132
+ ca_tile_new_setup (VALUE varg)
133
+ {
134
+ ca_tile_new_arg *a = (ca_tile_new_arg *) varg;
135
+ ca_tile_setup(a->ca, a->parent, a->reps);
136
+ return Qnil;
137
+ }
138
+
139
+ /* The setup allocates reps and dim after the struct: when either fails,
140
+ the struct goes too. */
123
141
  CATile *
124
142
  ca_tile_new (CArray *parent, ca_size_t *reps)
125
143
  {
126
- CATile *ca;
144
+ ca_tile_new_arg a;
127
145
  ca_tile_setup(NULL, parent, reps);
128
- ca = ALLOC(CATile);
129
- ca_tile_setup(ca, parent, reps);
130
- ca_fill_or_free((CArray *) ca, ca_view_inherit_mask, (VALUE) ca);
131
- return ca;
146
+ a.ca = ALLOC(CATile);
147
+ a.parent = parent;
148
+ a.reps = reps;
149
+ ca_fill_or_free((CArray *) a.ca, ca_tile_new_setup, (VALUE) &a);
150
+ ca_fill_or_free((CArray *) a.ca, ca_view_inherit_mask, (VALUE) a.ca);
151
+ return a.ca;
132
152
  }
133
153
 
134
154
  static void
@@ -548,7 +568,7 @@ rb_ca_tile (int argc, VALUE *argv, VALUE self)
548
568
  len, ca->ndim);
549
569
  }
550
570
  for ( i = 0; i < ca->ndim; i++ ) {
551
- reps[i] = NUM2SIZE(rb_ary_entry(ary, i));
571
+ reps[i] = ca_integer_arg(rb_ary_entry(ary, i), "a repeat count", NULL);
552
572
  }
553
573
  }
554
574
  else {
@@ -559,7 +579,7 @@ rb_ca_tile (int argc, VALUE *argv, VALUE self)
559
579
  ca->ndim, argc);
560
580
  }
561
581
  for ( i = 0; i < ca->ndim; i++ ) {
562
- reps[i] = NUM2SIZE(argv[i]);
582
+ reps[i] = ca_integer_arg(argv[i], "a repeat count", NULL);
563
583
  }
564
584
  }
565
585
 
@@ -42,8 +42,8 @@ ca_trans_setup (CAStride *ca, CArray *parent, ca_size_t *imap)
42
42
  "specified %i-th dimension number out of range", i);
43
43
  }
44
44
  if (map[idim] != -1) {
45
- rb_raise(rb_eArgError,
46
- "specified %i-th dimension number is duplicated", i);
45
+ rb_raise(rb_eArgError, "%s: axis %" PRId64 " is given twice",
46
+ ca_calling_method_name(), (int64_t) idim);
47
47
  }
48
48
  map[idim] = i;
49
49
  newdim[i] = dim0[idim];
@@ -120,10 +120,14 @@ rb_ca_trans (int argc, VALUE *argv, VALUE self)
120
120
  for (i = 0; i < ca->ndim; i++) imap[i] = ca->ndim - i - 1;
121
121
  }
122
122
  else if (argc == ca->ndim) {
123
- for (i = 0; i < ca->ndim; i++) imap[i] = NUM2SIZE(argv[i]);
123
+ /* Each axis read as every axis argument is: negative from the end. */
124
+ for (i = 0; i < ca->ndim; i++) {
125
+ imap[i] = ca_normalize_axis_arg(argv[i], ca->ndim, NULL);
126
+ }
124
127
  }
125
128
  else {
126
- rb_raise(rb_eArgError, "# of arguments should be equal to ndim");
129
+ rb_raise(rb_eArgError, "%s: %d axes given for ndim %d",
130
+ ca_calling_method_name(), argc, (int) ca->ndim);
127
131
  }
128
132
 
129
133
  obj = rb_ca_trans_new(self, imap);
data/ext/ca_obj_triop.c CHANGED
@@ -542,6 +542,9 @@ rb_ca_triop_build (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
542
542
  r3 = ca_lazy_settle_scalar(r3, r3_scalar);
543
543
  }
544
544
 
545
+ ca_refuse_without_common_type(r1, r2);
546
+ ca_refuse_without_common_type(r1, r3);
547
+ ca_refuse_without_common_type(r2, r3);
545
548
  TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
546
549
  TypedData_Get_Struct(r2, CArray, &carray_data_type, op2);
547
550
  TypedData_Get_Struct(r3, CArray, &carray_data_type, op3);
data/ext/ca_obj_window.c CHANGED
@@ -801,16 +801,40 @@ ca_window_create_bounds_mask (VALUE view)
801
801
  return Qnil;
802
802
  }
803
803
 
804
+ typedef struct {
805
+ CAWindow *ca;
806
+ CArray *parent;
807
+ ca_size_t *start;
808
+ ca_size_t *count;
809
+ uint8_t *bounds;
810
+ char *fill;
811
+ } ca_window_new_arg;
812
+
813
+ static VALUE
814
+ ca_window_new_setup (VALUE varg)
815
+ {
816
+ ca_window_new_arg *a = (ca_window_new_arg *) varg;
817
+ ca_window_setup(a->ca, a->parent, a->start, a->count, a->bounds, a->fill);
818
+ return Qnil;
819
+ }
820
+
821
+ /* The setup allocates the fill value after the struct and its pool: when
822
+ that fails, the struct goes too. */
804
823
  CAWindow *
805
824
  ca_window_new (CArray *parent,
806
825
  ca_size_t *start, ca_size_t *count, uint8_t *bounds, char *fill)
807
826
  {
808
- CAWindow *ca;
827
+ ca_window_new_arg a;
809
828
  ca_window_setup(NULL, parent, start, count, bounds, fill);
810
- ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
811
- ca_window_setup(ca, parent, start, count, bounds, fill);
812
- ca_fill_or_free((CArray *) ca, ca_window_create_bounds_mask, (VALUE) ca);
813
- return ca;
829
+ a.ca = (CAWindow *) ca_array_alloc(CA_OBJ_WINDOW, parent->ndim);
830
+ a.parent = parent;
831
+ a.start = start;
832
+ a.count = count;
833
+ a.bounds = bounds;
834
+ a.fill = fill;
835
+ ca_fill_or_free((CArray *) a.ca, ca_window_new_setup, (VALUE) &a);
836
+ ca_fill_or_free((CArray *) a.ca, ca_window_create_bounds_mask, (VALUE) a.ca);
837
+ return a.ca;
814
838
  }
815
839
 
816
840
  static void
@@ -1674,51 +1698,56 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
1674
1698
  if ( SYMBOL_P(rbounds) ) {
1675
1699
  rbounds = rb_sym2str(rbounds);
1676
1700
  }
1677
- switch ( TYPE(rbounds) ) {
1678
- case T_STRING:
1679
- cbounds = StringValuePtr(rbounds);
1680
- if ( rfval == CA_UNDEF && strncmp(cbounds, "fill", 4)
1681
- && strncmp(cbounds, "mask", 4) ) {
1682
- rb_raise(rb_eArgError, "conflicted bounds and fill_value");
1683
- }
1684
- if ( ! strncmp(cbounds, "ruby", 4) ) {
1685
- bounds = CA_BOUNDS_RUBY;
1686
- }
1687
- else if ( ! strncmp(cbounds, "strict", 6) ) {
1688
- bounds = CA_BOUNDS_STRICT;
1689
- }
1690
- else if ( ! strncmp(cbounds, "nearest", 7) ) {
1691
- bounds = CA_BOUNDS_NEAREST;
1692
- }
1693
- else if ( ! strncmp(cbounds, "periodic", 8) ) {
1694
- rb_raise(rb_eArgError,
1695
- "bounds=>'periodic' removed in 3.0; "
1696
- "use CArray#roll(...) for cyclic shift "
1697
- "(returns a CARoll view)");
1698
- }
1699
- else if ( ! strncmp(cbounds, "reflect", 7) ) {
1700
- rb_raise(rb_eArgError,
1701
- "bounds=>'reflect' removed in 3.0; "
1702
- "there is no view-based alternative");
1703
- }
1704
- else if ( ! strncmp(cbounds, "mask", 4) ) {
1705
- rb_warn("CAWindow option :bounds=>\"mask\" will be obsolete");
1706
- rb_warn("use ca.window(..., fill_value: UNDEF)");
1707
- bounds = CA_BOUNDS_MASK;
1708
- }
1709
- else if ( ! strncmp(cbounds, "fill", 4) ) {
1710
- bounds = CA_BOUNDS_FILL;
1711
- }
1712
- else {
1713
- rb_raise(rb_eArgError,
1714
- "unknown option value '%s' for :bounds", cbounds);
1715
- }
1716
- break;
1717
- case T_FIXNUM:
1718
- bounds = NUM2INT(rbounds);
1719
- break;
1720
- default:
1721
- rb_raise(rb_eArgError, "invalid option value for :bounds");
1701
+ if ( ! RB_TYPE_P(rbounds, T_STRING) ) {
1702
+ rb_raise(rb_eTypeError,
1703
+ "window: bounds: must be a Symbol or a String (got %s)",
1704
+ rb_obj_classname(rbounds));
1705
+ }
1706
+ cbounds = StringValueCStr(rbounds);
1707
+ if ( ! strcmp(cbounds, "ruby") ) {
1708
+ bounds = CA_BOUNDS_RUBY;
1709
+ }
1710
+ else if ( ! strcmp(cbounds, "strict") ) {
1711
+ bounds = CA_BOUNDS_STRICT;
1712
+ }
1713
+ else if ( ! strcmp(cbounds, "nearest") ) {
1714
+ bounds = CA_BOUNDS_NEAREST;
1715
+ }
1716
+ else if ( ! strcmp(cbounds, "periodic") ) {
1717
+ rb_raise(rb_eArgError,
1718
+ "bounds=>'periodic' removed in 3.0; "
1719
+ "use CArray#roll(...) for cyclic shift "
1720
+ "(returns a CARoll view)");
1721
+ }
1722
+ else if ( ! strcmp(cbounds, "reflect") ) {
1723
+ rb_raise(rb_eArgError,
1724
+ "bounds=>'reflect' removed in 3.0; "
1725
+ "there is no view-based alternative");
1726
+ }
1727
+ else if ( ! strcmp(cbounds, "mask") ) {
1728
+ rb_warn("CAWindow option :bounds=>\"mask\" will be obsolete");
1729
+ rb_warn("use ca.window(..., fill_value: UNDEF)");
1730
+ bounds = CA_BOUNDS_MASK;
1731
+ }
1732
+ else if ( ! strcmp(cbounds, "fill") ) {
1733
+ bounds = ( rfval == CA_UNDEF ) ? CA_BOUNDS_MASK : CA_BOUNDS_FILL;
1734
+ }
1735
+ else {
1736
+ rb_raise(rb_eArgError,
1737
+ "window: unknown bounds: '%s'", cbounds);
1738
+ }
1739
+ /* A fill value says what the cells outside the array are; the other
1740
+ policies say something else about them. */
1741
+ if ( rfval != CA_UNSPECIFIED
1742
+ && bounds != CA_BOUNDS_FILL && bounds != CA_BOUNDS_MASK ) {
1743
+ rb_raise(rb_eArgError,
1744
+ "window: fill_value: is for bounds: :fill, not :%s", cbounds);
1745
+ }
1746
+ if ( rfval != CA_UNSPECIFIED && rfval != CA_UNDEF
1747
+ && bounds == CA_BOUNDS_MASK ) {
1748
+ rb_raise(rb_eArgError,
1749
+ "window: fill_value: %+"PRIsVALUE" conflicts with bounds: :mask "
1750
+ "(use fill_value: UNDEF to mask the cells outside)", rfval);
1722
1751
  }
1723
1752
  }
1724
1753
 
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
data/ext/carray.h CHANGED
@@ -173,6 +173,39 @@ typedef int8_t boolean8_t;
173
173
  #define CA_ALIGN_CMPLX128 offsetof(struct { char c; cmplx128_t x; }, x)
174
174
  #define CA_ALIGN_OBJECT offsetof(struct { char c; VALUE x; }, x)
175
175
 
176
+ /* Cell types that may sit at any byte. A view's cells need not be aligned
177
+ to their size: a struct member at offset 1, a refer with a byte offset,
178
+ a wrapped external buffer. Reading a cell through a plain `double *`
179
+ there is undefined (x86 vector code may assume the alignment), so a
180
+ kernel reads and writes cells through these. Same size and value as the
181
+ plain type; only the alignment the compiler may assume is 1. */
182
+ #if defined(__GNUC__) || defined(__clang__)
183
+ # define CA_UNALIGNED __attribute__((aligned(1)))
184
+ #else
185
+ # define CA_UNALIGNED
186
+ #endif
187
+ typedef boolean8_t ca_u_boolean8_t;
188
+ typedef int8_t ca_u_int8_t;
189
+ typedef uint8_t ca_u_uint8_t;
190
+ typedef int16_t ca_u_int16_t CA_UNALIGNED;
191
+ typedef uint16_t ca_u_uint16_t CA_UNALIGNED;
192
+ typedef int32_t ca_u_int32_t CA_UNALIGNED;
193
+ typedef uint32_t ca_u_uint32_t CA_UNALIGNED;
194
+ typedef int64_t ca_u_int64_t CA_UNALIGNED;
195
+ typedef uint64_t ca_u_uint64_t CA_UNALIGNED;
196
+ typedef float32_t ca_u_float32_t CA_UNALIGNED;
197
+ typedef float64_t ca_u_float64_t CA_UNALIGNED;
198
+ typedef cmplx64_t ca_u_cmplx64_t CA_UNALIGNED;
199
+ typedef cmplx128_t ca_u_cmplx128_t CA_UNALIGNED;
200
+ typedef VALUE ca_u_VALUE CA_UNALIGNED;
201
+
202
+ typedef ca_u_float32_t ca_u_float;
203
+ typedef ca_u_float64_t ca_u_double;
204
+
205
+ /* CA_U(float64_t) is ca_u_float64_t (and CA_U(double) ca_u_double): for a
206
+ macro that takes the cell type. */
207
+ #define CA_U(type) ca_u_##type
208
+
176
209
  /* -------------------------------------------------------------------- */
177
210
 
178
211
  #define CA_OBJ_TYPE_MAX 256
data/ext/carray_access.c CHANGED
@@ -193,6 +193,14 @@ rb_ca_fill (VALUE self, VALUE rval)
193
193
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
194
194
 
195
195
  if ( ca_is_empty(ca) ) {
196
+ /* No cell to fill, but a value no cell could hold is refused, as an
197
+ assignment to the empty array refuses it. */
198
+ if ( rval != CA_UNDEF && ca->bytes > 0 ) {
199
+ volatile VALUE holder;
200
+ char *fval = ALLOCV_N(char, holder, ca->bytes);
201
+ rb_ca_obj2ptr(self, rval, fval);
202
+ ALLOCV_END(holder);
203
+ }
196
204
  return self; /* empty = no-op fill; return self for chaining */
197
205
  }
198
206
 
@@ -884,9 +892,9 @@ rb_ca_index_restruct_block (int16_t *ndimp, ca_size_t *shrink, ca_size_t *dim,
884
892
 
885
893
  offset = 0;
886
894
 
887
- if ( idx[0] == -1 ) {
888
- j = 0;
889
- while ( idx[++j] ) {
895
+ if ( ndim0 > 0 && idx[0] == -1 ) {
896
+ /* j = the number of leading axes collapsed by a scalar index */
897
+ for (j=1; j<ndim0 && idx[j] == -1; j++) {
890
898
  ;
891
899
  }
892
900
 
@@ -1365,6 +1373,7 @@ rb_ca_fetch_newaxis (int argc, VALUE *argv, VALUE self, CArray *ca)
1365
1373
  element, which is what the shape rules then hold it to. */
1366
1374
  if ( nscalar == nclean ) {
1367
1375
  VALUE blocks[CA_RANK_MAX];
1376
+ ca_check_rank_fits(nunder, NULL); /* the result has the :_ axes only */
1368
1377
  for (i = 0; i < nclean; i++) {
1369
1378
  blocks[i] = rb_assoc_new(clean[i], INT2FIX(1));
1370
1379
  }
@@ -1379,6 +1388,10 @@ rb_ca_fetch_newaxis (int argc, VALUE *argv, VALUE self, CArray *ca)
1379
1388
 
1380
1389
  TypedData_Get_Struct(base, CArray, &carray_data_type, cb);
1381
1390
 
1391
+ /* The result has the base's axes and one for each :_, before any is
1392
+ written into final_dims. */
1393
+ ca_check_rank_fits((long) nunder + cb->ndim, NULL);
1394
+
1382
1395
  /* Reconstruct final shape: walk original argv. :_ -> size-1, scalar
1383
1396
  (Integer) -> dropped (skip), else -> base.dim[cursor]. A key gives one
1384
1397
  axis, except an integer CArray read alone (a mapping), which gives as
@@ -520,10 +520,34 @@ rb_ca_inherit_attr (VALUE dst, VALUE src)
520
520
  it up after this (an ivar, a lift that moves it onto another parent), and
521
521
  writes through it are refused by ca_is_readonly, which walks to the
522
522
  frozen root and finds CA_FLAG_READ_ONLY there. */
523
+ static void
524
+ ca_note_view_of_lent (CArray *p)
525
+ {
526
+ if ( ca_test_flag(p, CA_FLAG_LENT) ) {
527
+ ca_set_flag(p, CA_FLAG_LENT_VIEWED);
528
+ }
529
+ }
530
+
523
531
  VALUE
524
532
  rb_ca_set_parent (VALUE self, VALUE obj)
525
533
  {
526
534
  rb_ivar_set(self, id_parent, obj);
535
+ /* A view of an array lent to a CAObject hook outlives the hook: tell the
536
+ array, so that it keeps its cells when the hook returns. A view of
537
+ several arrays names one here and holds the rest in parents[]. */
538
+ if ( rb_obj_is_carray(obj) ) {
539
+ ca_note_view_of_lent((CArray *) DATA_PTR(obj));
540
+ }
541
+ if ( rb_obj_is_carray(self) ) {
542
+ CArray *ca = (CArray *) DATA_PTR(self);
543
+ if ( ca_test_flag(ca, CA_FLAG_MULTI_PARENTS) ) {
544
+ CAMultiParent *mp = (CAMultiParent *) ca;
545
+ int32_t k;
546
+ for ( k = 0; k < mp->n_parents; k++ ) {
547
+ ca_note_view_of_lent(mp->parents[k]);
548
+ }
549
+ }
550
+ }
527
551
  return obj;
528
552
  }
529
553