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_array.c CHANGED
@@ -144,7 +144,6 @@ carray_setup_i (CArray *ca,
144
144
  CArray *mask, int allocate, int use_calloc, char *adopt_ptr)
145
145
  {
146
146
  ca_size_t elements;
147
- int8_t i;
148
147
  ca_size_t k;
149
148
 
150
149
  /* check arguments */
@@ -295,26 +294,54 @@ carray_new_with_mask (CArray *ca, CArray *mask)
295
294
  return ca;
296
295
  }
297
296
 
297
+ typedef struct {
298
+ CArray *ca;
299
+ int8_t data_type;
300
+ int8_t ndim;
301
+ ca_size_t *dim;
302
+ ca_size_t bytes;
303
+ int use_calloc;
304
+ } carray_new_arg;
305
+
306
+ static VALUE
307
+ carray_new_setup (VALUE varg)
308
+ {
309
+ carray_new_arg *a = (carray_new_arg *) varg;
310
+ carray_setup_i(a->ca, a->data_type, a->ndim, a->dim, a->bytes, NULL,
311
+ 1, a->use_calloc, NULL);
312
+ return Qnil;
313
+ }
314
+
315
+ /* The setup allocates the cells, after the struct: when that fails, the
316
+ struct goes too. */
317
+ static CArray *
318
+ carray_new_i (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
319
+ CArray *mask, int use_calloc)
320
+ {
321
+ carray_new_arg a;
322
+ carray_setup_i(NULL, data_type, ndim, dim, bytes, NULL, 1, use_calloc, NULL);
323
+ a.ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
324
+ a.data_type = data_type;
325
+ a.ndim = ndim;
326
+ a.dim = dim;
327
+ a.bytes = bytes;
328
+ a.use_calloc = use_calloc;
329
+ ca_fill_or_free(a.ca, carray_new_setup, (VALUE) &a);
330
+ return carray_new_with_mask(a.ca, mask);
331
+ }
332
+
298
333
  CArray *
299
334
  carray_new (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
300
335
  CArray *mask)
301
336
  {
302
- CArray *ca;
303
- carray_setup(NULL, data_type, ndim, dim, bytes, NULL);
304
- ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
305
- carray_setup(ca, data_type, ndim, dim, bytes, NULL);
306
- return carray_new_with_mask(ca, mask);
337
+ return carray_new_i(data_type, ndim, dim, bytes, mask, 0);
307
338
  }
308
339
 
309
340
  CArray *
310
341
  carray_new_safe (int8_t data_type, int8_t ndim, ca_size_t *dim, ca_size_t bytes,
311
342
  CArray *mask)
312
343
  {
313
- CArray *ca;
314
- carray_safe_setup(NULL, data_type, ndim, dim, bytes, NULL);
315
- ca = (CArray *) ca_array_alloc(CA_OBJ_ARRAY, ndim);
316
- carray_safe_setup(ca, data_type, ndim, dim, bytes, NULL);
317
- return carray_new_with_mask(ca, mask);
344
+ return carray_new_i(data_type, ndim, dim, bytes, mask, 1);
318
345
  }
319
346
 
320
347
  /* Create an entity that adopts a caller-provided data buffer instead of
@@ -440,13 +467,39 @@ cscalar_setup (CScalar *ca,
440
467
  * constructs a CScalar struct without initialization
441
468
  */
442
469
 
470
+ typedef struct {
471
+ CScalar *ca;
472
+ int8_t data_type;
473
+ ca_size_t bytes;
474
+ } cscalar_new_arg;
475
+
476
+ static VALUE
477
+ cscalar_new_setup (VALUE varg)
478
+ {
479
+ cscalar_new_arg *a = (cscalar_new_arg *) varg;
480
+ cscalar_setup(a->ca, a->data_type, a->bytes, NULL);
481
+ return Qnil;
482
+ }
483
+
484
+ /* The setup allocates the cell after the struct: when that fails, the
485
+ struct goes too. It goes by xfree, not ca_free, because its ptr was
486
+ never set. */
487
+ static CScalar *
488
+ cscalar_new_i (int8_t data_type, ca_size_t bytes)
489
+ {
490
+ cscalar_new_arg a;
491
+ cscalar_setup(NULL, data_type, bytes, NULL);
492
+ a.ca = ALLOC(CScalar);
493
+ a.data_type = data_type;
494
+ a.bytes = bytes;
495
+ ca_fill_or_xfree(a.ca, cscalar_new_setup, (VALUE) &a);
496
+ return a.ca;
497
+ }
498
+
443
499
  CScalar *
444
500
  cscalar_new (int8_t data_type, ca_size_t bytes, CArray *mask)
445
501
  {
446
- CScalar *ca;
447
- cscalar_setup(NULL, data_type, bytes, NULL);
448
- ca = ALLOC(CScalar);
449
- cscalar_setup(ca, data_type, bytes, NULL);
502
+ CScalar *ca = cscalar_new_i(data_type, bytes);
450
503
  return (CScalar *) carray_new_with_mask((CArray *) ca, mask);
451
504
  }
452
505
 
@@ -457,10 +510,7 @@ cscalar_new (int8_t data_type, ca_size_t bytes, CArray *mask)
457
510
  CScalar *
458
511
  cscalar_new2 (int8_t data_type, ca_size_t bytes, char *val)
459
512
  {
460
- CScalar *ca;
461
- cscalar_setup(NULL, data_type, bytes, NULL);
462
- ca = ALLOC(CScalar);
463
- cscalar_setup(ca, data_type, bytes, NULL);
513
+ CScalar *ca = cscalar_new_i(data_type, bytes);
464
514
  memcpy(ca->ptr, val, ca->bytes);
465
515
  return ca;
466
516
  }
data/ext/ca_obj_bincmp.c CHANGED
@@ -647,6 +647,7 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
647
647
  r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
648
648
  }
649
649
 
650
+ ca_refuse_without_common_type(l_resolved, r_resolved);
650
651
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
651
652
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
652
653
 
data/ext/ca_obj_binop.c CHANGED
@@ -569,6 +569,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
569
569
  r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
570
570
  }
571
571
 
572
+ ca_refuse_without_common_type(l_resolved, r_resolved);
572
573
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
573
574
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
574
575
 
@@ -93,7 +93,8 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
93
93
  ca_size_t bitlen, elements;
94
94
 
95
95
  if ( ca_is_complex_type(parent) || ( ca_is_object_type(parent) ) ) {
96
- rb_raise(rb_eCADataTypeError, "invalid data_type for bitarray");
96
+ rb_raise(rb_eCADataTypeError, "%s: can't view the bits of a cell of %s",
97
+ ca_calling_method_name(), ca_type_name[parent->data_type]);
97
98
  }
98
99
 
99
100
  /* The bits of one byte would share that byte's one mask cell, so a bit
@@ -106,6 +107,9 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
106
107
  "use .value.bitarray to read the bits without it");
107
108
  }
108
109
 
110
+ /* The bits add an axis to the parent's. */
111
+ ca_check_rank_fits(parent->ndim + 1, "bitarray");
112
+
109
113
  /* ca == NULL asks for the checks above only, so that a constructor can
110
114
  run them before it allocates. */
111
115
  if ( ca == NULL ) {
@@ -4,10 +4,11 @@
4
4
  cell, exposing it as an unsigned-integer (or boolean, when
5
5
  bitlen == 1) CArray of the same shape as the parent.
6
6
 
7
- Byte-straddling fields are handled by loading up to 8 bytes from
8
- the parent starting at `byte_offset`, masking with `bit_mask`, and
9
- shifting by `bit_offset`. Big-endian hosts adjust byte_offset /
10
- bit_offset so the field selection is invariant to host byte order.
7
+ Bits are counted from the least significant bit of the parent cell
8
+ read as a host-order integer. Byte-straddling fields are handled
9
+ by loading up to 8 bytes, the least significant first, starting
10
+ `byte_offset` bytes above the least significant byte, masking with
11
+ `bit_mask`, and shifting by `bit_offset`.
11
12
 
12
13
  ---------------------------------------------------------------------------- */
13
14
 
@@ -32,7 +33,7 @@ typedef struct {
32
33
  ca_size_t byte_offset;
33
34
  ca_size_t bit_offset;
34
35
  uint64_t bit_mask;
35
- ca_size_t bit_start; /* original offset before endian adjustment */
36
+ ca_size_t bit_start; /* the offset of the field's lowest bit */
36
37
  ca_size_t bit_length; /* width of the field in bits */
37
38
  int8_t sign_extend; /* the field is read as a signed integer */
38
39
  } CABitfield;
@@ -85,6 +86,40 @@ static VALUE rb_cCABitfield;
85
86
  * 8-bit field starting at bit 4 of a 2-byte parent) sees the full
86
87
  * bit_mask. A dbytes-typed cast would silently truncate bit_mask
87
88
  * to `1 << (dbytes * 8)`, dropping the upper bits of the field. */
89
+ /* The `span` bytes of a cell from `lo` bytes above its least
90
+ significant byte, as an integer. On a big-endian host the least
91
+ significant byte is the last one. */
92
+ static inline uint64_t
93
+ bitfield_load (const char *cell, ca_size_t cbytes, ca_size_t lo, ca_size_t span)
94
+ {
95
+ uint64_t v = 0;
96
+ #ifdef WORDS_BIGENDIAN
97
+ ca_size_t j;
98
+ for (j = 0; j < span; j++) {
99
+ v |= (uint64_t) (uint8_t) cell[cbytes - 1 - lo - j] << (8 * j);
100
+ }
101
+ #else
102
+ (void) cbytes;
103
+ memcpy(&v, cell + lo, (size_t) span);
104
+ #endif
105
+ return v;
106
+ }
107
+
108
+ static inline void
109
+ bitfield_save (char *cell, ca_size_t cbytes, ca_size_t lo, ca_size_t span,
110
+ uint64_t v)
111
+ {
112
+ #ifdef WORDS_BIGENDIAN
113
+ ca_size_t j;
114
+ for (j = 0; j < span; j++) {
115
+ cell[cbytes - 1 - lo - j] = (char) (v >> (8 * j));
116
+ }
117
+ #else
118
+ (void) cbytes;
119
+ memcpy(cell + lo, &v, (size_t) span);
120
+ #endif
121
+ }
122
+
88
123
  static void
89
124
  bitfield_fetch(char *dst, ca_size_t dbytes,
90
125
  char *src, ca_size_t sbytes,
@@ -98,13 +133,12 @@ bitfield_fetch(char *dst, ca_size_t dbytes,
98
133
  if (span > 8) span = 8;
99
134
  ca_size_t dwrite = (dbytes > 8) ? 8 : dbytes;
100
135
  for (k = 0; k < elements; k++) {
101
- uint64_t tmp = 0;
102
- memcpy(&tmp, src + k * sbytes + byte_offset, (size_t) span);
136
+ uint64_t tmp = bitfield_load(src + k * sbytes, sbytes, byte_offset, span);
103
137
  uint64_t result = (tmp & bit_mask) >> bit_offset;
104
138
  if ( result & sign ) {
105
139
  result |= ~( ( sign << 1 ) - 1 ); /* the field's top bit is its sign */
106
140
  }
107
- memcpy(dst + k * dbytes, &result, (size_t) dwrite);
141
+ bitfield_save(dst + k * dbytes, dwrite, 0, dwrite, result);
108
142
  }
109
143
  }
110
144
 
@@ -124,12 +158,10 @@ bitfield_store(char *src, ca_size_t sbytes,
124
158
  if (span > 8) span = 8;
125
159
  ca_size_t sread = (sbytes > 8) ? 8 : sbytes;
126
160
  for (k = 0; k < elements; k++) {
127
- uint64_t srcv = 0;
128
- memcpy(&srcv, src + k * sbytes, (size_t) sread);
129
- uint64_t tmp = 0;
130
- memcpy(&tmp, dst + k * dbytes + byte_offset, (size_t) span);
161
+ uint64_t srcv = bitfield_load(src + k * sbytes, sread, 0, sread);
162
+ uint64_t tmp = bitfield_load(dst + k * dbytes, dbytes, byte_offset, span);
131
163
  tmp = (tmp & ~bit_mask) | ((srcv << bit_offset) & bit_mask);
132
- memcpy(dst + k * dbytes + byte_offset, &tmp, (size_t) span);
164
+ bitfield_save(dst + k * dbytes, dbytes, byte_offset, span, tmp);
133
165
  }
134
166
  }
135
167
 
@@ -160,14 +192,16 @@ ca_bitfield_setup (CABitfield *ca, CArray *parent,
160
192
  }
161
193
 
162
194
  if ( offset < 0 || offset + bitlen -1 >= bitsize ) {
163
- rb_raise(rb_eIndexError, "invalid offset for bit field");
195
+ rb_raise(rb_eIndexError, "%s: bits out of range for a cell of %d bits",
196
+ ca_calling_method_name(), (int) bitsize);
164
197
  }
165
198
 
166
199
  /* The bits of an object cell are a reference: writing them would leave
167
200
  the cell pointing nowhere. A complex cell is refused as bitarray
168
201
  refuses it. */
169
202
  if ( ca_is_object_type(parent) || ca_is_complex_type(parent) ) {
170
- rb_raise(rb_eCADataTypeError, "invalid data_type for bitfield");
203
+ rb_raise(rb_eCADataTypeError, "%s: can't view the bits of a cell of %s",
204
+ ca_calling_method_name(), ca_type_name[parent->data_type]);
171
205
  }
172
206
 
173
207
  /* A field is read with one 8-byte load from the byte it starts in. */
@@ -213,32 +247,11 @@ ca_bitfield_setup (CABitfield *ca, CArray *parent,
213
247
  (long long) bitlen, ca_type_name[data_type]);
214
248
  }
215
249
 
216
- if ( ca_endian == CA_BIG_ENDIAN ) {
217
- /* The window is placed by the narrowest width that holds the field,
218
- not by the type it is read as, which may be wider. */
219
- ca_size_t window = ( bitlen <= 8 ) ? 1 : ( bitlen <= 16 ) ? 2 :
220
- ( bitlen <= 32 ) ? 4 : 8;
221
- byte_offset = parent->bytes - offset/8 - window;
222
- bit_offset = offset % 8;
223
- bit_mask = 0;
224
- for (i=0; i<bitlen; i++) {
225
- bit_mask += 1ULL << ( bit_offset + i );
226
- }
227
- if ( byte_offset < 0 ) {
228
- for (i=0; i<-byte_offset; i++) {
229
- bit_mask = bit_mask << 8;
230
- bit_offset += 8;
231
- }
232
- byte_offset = 0;
233
- }
234
- }
235
- else {
236
- byte_offset = offset / 8;
237
- bit_offset = offset % 8;
238
- bit_mask = 0;
239
- for (i=0; i<bitlen; i++) {
240
- bit_mask += 1ULL << ( bit_offset + i );
241
- }
250
+ byte_offset = offset / 8;
251
+ bit_offset = offset % 8;
252
+ bit_mask = 0;
253
+ for (i=0; i<bitlen; i++) {
254
+ bit_mask += 1ULL << ( bit_offset + i );
242
255
  }
243
256
 
244
257
  /* ca == NULL asks for the checks above only, so that a constructor can
@@ -666,8 +679,10 @@ rb_ca_bitfield (int argc, VALUE *argv, VALUE self)
666
679
 
667
680
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
668
681
 
669
- if ( TYPE(rrange) == T_FIXNUM ) {
670
- offset = NUM2INT(rrange);
682
+ if ( RB_INTEGER_TYPE_P(rrange) ) {
683
+ /* A bit of a cell: negative from the last. One beyond any cell is
684
+ refused by the setup's range check, as an offset past the cell is. */
685
+ offset = RB_FIXNUM_P(rrange) ? FIX2LONG(rrange) : CA_LENGTH_MAX;
671
686
  if ( offset < 0 ) {
672
687
  offset += ca->bytes * 8;
673
688
  }
@@ -196,7 +196,8 @@ ca_byte_swap_setup (CAByteSwap *ca, CArray *parent, VALUE data_class)
196
196
  CA_CHECK_DATA_TYPE_GIVEN(parent->data_type);
197
197
 
198
198
  if ( parent->data_type == CA_OBJECT ) {
199
- rb_raise(rb_eCADataTypeError, "object array can't be byte-swapped");
199
+ rb_raise(rb_eCADataTypeError, "%s: an object array can't be byte-swapped",
200
+ ca_calling_method_name());
200
201
  }
201
202
 
202
203
  /* ca == NULL asks for the checks above only, so that a constructor can
@@ -837,19 +837,31 @@ rb_ca_const_string_eq (VALUE self, VALUE other)
837
837
  ca_const_string_scan_end(&b);
838
838
  return vout;
839
839
  }
840
+ /* Another array is compared cell by cell as Strings, where a CAString
841
+ reconciles it (an object array of Strings, a fixlen or a CAString). */
842
+ if ( rb_obj_is_carray(other) ) {
843
+ return rb_funcall(rb_ca_const_string_to_string(self), rb_intern("eq"), 1,
844
+ other);
845
+ }
840
846
  return ca_const_string_predicate(self, other, CA_TEXT_EQ);
841
847
  }
842
848
 
843
- /* CAConstString#count(value): number of (non-masked) elements byte-equal to value. */
849
+ /* CAConstString#count(value): number of (non-masked) elements byte-equal to
850
+ value. With no value, the number of non-masked elements, as CArray#count
851
+ answers. */
844
852
  static VALUE
845
- rb_ca_const_string_count (VALUE self, VALUE query)
853
+ rb_ca_const_string_count (int argc, VALUE *argv, VALUE self)
846
854
  {
847
855
  ca_const_string_scan_t s;
848
856
  const char *qp, *p;
849
857
  long qlen;
850
858
  int64_t len;
851
859
  ca_size_t i, c = 0;
860
+ VALUE query;
852
861
 
862
+ if ( rb_scan_args(argc, argv, "01", &query) == 0 ) {
863
+ return rb_funcall(self, rb_intern("count_not_masked"), 0);
864
+ }
853
865
  if ( TYPE(query) != T_STRING ) {
854
866
  query = rb_obj_as_string(query);
855
867
  }
@@ -1216,7 +1228,7 @@ Init_ca_obj_const_string (void)
1216
1228
  /* native byte ops (§3.7) */
1217
1229
  rb_define_method(rb_cCAConstString, "byte_length", rb_ca_const_string_byte_length, 0);
1218
1230
  rb_define_method(rb_cCAConstString, "eq", rb_ca_const_string_eq, 1);
1219
- rb_define_method(rb_cCAConstString, "count", rb_ca_const_string_count, 1);
1231
+ rb_define_method(rb_cCAConstString, "count", rb_ca_const_string_count, -1);
1220
1232
  rb_define_method(rb_cCAConstString, "start_with?", rb_ca_const_string_start_with, 1);
1221
1233
  rb_define_method(rb_cCAConstString, "end_with?", rb_ca_const_string_end_with, 1);
1222
1234
  rb_define_method(rb_cCAConstString, "include?", rb_ca_const_string_include, 1);
data/ext/ca_obj_face.c CHANGED
@@ -281,7 +281,8 @@ ca_face_lift (VALUE view, VALUE face_parent)
281
281
  handled by builder-side pre-strip. data_type above stays a full strip
282
282
  (surface concern, §8 #7) — the parent pointer is the structural concern
283
283
  (§8.3); the two axes are deliberately separate. */
284
- if ( ((CAView *) view_ca)->parent == fp
284
+ if ( ca_is_view(view_ca) /* an entity (a copy) has no parent field */
285
+ && ((CAView *) view_ca)->parent == fp
285
286
  && ! ca_test_flag(view_ca, CA_FLAG_MULTI_PARENTS) ) {
286
287
  ((CAView *) view_ca)->parent = ((CAView *) fp)->parent; /* C pointer: one level */
287
288
  rb_ca_set_parent(view, rb_ca_parent(face_parent)); /* @parent ivar: lockstep */
@@ -1233,6 +1234,25 @@ ca_face_reconcile_comparison (volatile VALUE *pself, volatile VALUE *pother)
1233
1234
  return;
1234
1235
  }
1235
1236
 
1237
+ /* Two string arrays of different kinds (CAString, CAFixlenString,
1238
+ CAConstString) or of different cell widths hold their strings in
1239
+ different storage: the padded bytes of one are not the bytes of the
1240
+ other. They are compared by their strings. */
1241
+ if ( RTEST(rb_obj_is_carray(other)) ) {
1242
+ static ID id_to_string = 0;
1243
+ CArray *oc;
1244
+ if ( id_to_string == 0 ) id_to_string = rb_intern("to_string");
1245
+ TypedData_Get_Struct(other, CArray, &carray_data_type, oc);
1246
+ if ( ca_is_face(oc) && rb_respond_to(self, id_to_string)
1247
+ && rb_respond_to(other, id_to_string)
1248
+ && ( rb_obj_class(self) != rb_obj_class(other)
1249
+ || sc->bytes != oc->bytes ) ) {
1250
+ *pself = rb_ca_strip_face_value(rb_funcall(self, id_to_string, 0));
1251
+ *pother = rb_ca_strip_face_value(rb_funcall(other, id_to_string, 0));
1252
+ return;
1253
+ }
1254
+ }
1255
+
1236
1256
  storage = ca_strip_face(sc);
1237
1257
  if ( storage->data_type == CA_FIXLEN ) {
1238
1258
  /* genuine fixlen semantics: memcmp is the correct comparison, so self
@@ -1262,6 +1282,26 @@ ca_face_reconcile_comparison (volatile VALUE *pself, volatile VALUE *pother)
1262
1282
  }
1263
1283
  }
1264
1284
 
1285
+ /* A Face's parent, the array its values are stored in, is handed out as a
1286
+ read-only view: a write through it would change the Face's values
1287
+ without the Face's conversion (a tick count stored into a time, bytes
1288
+ into a record). The storage is written through the Face's own named
1289
+ methods (CATime#ticks), which take it with face_storage. */
1290
+ static VALUE
1291
+ rb_ca_face_parent (VALUE self)
1292
+ {
1293
+ volatile VALUE st = rb_ca_parent(self), view;
1294
+ CArray *cs, *cv;
1295
+ if ( NIL_P(st) ) {
1296
+ return st;
1297
+ }
1298
+ TypedData_Get_Struct(st, CArray, &carray_data_type, cs);
1299
+ view = rb_ca_refer_new(st, cs->data_type, cs->ndim, cs->dim, cs->bytes, 0);
1300
+ TypedData_Get_Struct(view, CArray, &carray_data_type, cv);
1301
+ ca_set_flag(cv, CA_FLAG_READ_ONLY);
1302
+ return view;
1303
+ }
1304
+
1265
1305
  void
1266
1306
  Init_ca_face (void)
1267
1307
  {
@@ -1271,6 +1311,7 @@ Init_ca_face (void)
1271
1311
  ahead of this Init) — CAFace inherits from it. */
1272
1312
  rb_cCAFace = rb_define_class("CAFace", rb_cCAView);
1273
1313
  rb_define_alloc_func(rb_cCAFace, rb_ca_face_s_allocate_forbidden);
1314
+ rb_define_method(rb_cCAFace, "parent", rb_ca_face_parent, 0);
1274
1315
 
1275
1316
  /* Initialise the portable table to -1 for every slot so dispatch
1276
1317
  can distinguish "explicitly registered 0" (CAConstString) from
data/ext/ca_obj_field.c CHANGED
@@ -40,11 +40,12 @@ ca_field_setup (CAStride *ca, CArray *parent,
40
40
  }
41
41
  if ( data_type == CA_OBJECT ) {
42
42
  rb_raise(rb_eCADataTypeError,
43
- "CA_OBJECT can not to be a data_type for CAField");
43
+ "%s: a field can't be read as object", ca_calling_method_name());
44
44
  }
45
45
  if ( ca_is_object_type(parent) ) {
46
46
  rb_raise(rb_eCADataTypeError,
47
- "a field can not be taken from an object array");
47
+ "%s: a field can't be taken from an object array",
48
+ ca_calling_method_name());
48
49
  }
49
50
  /* A boolean cell holds 0 or 1, and a field of a numeric array is
50
51
  written as that number. A record's boolean member is a field of a
@@ -105,6 +106,14 @@ rb_ca_field_new (VALUE cary, ca_size_t offset, int8_t data_type, ca_size_t bytes
105
106
  CAStride *ca;
106
107
  rb_check_carray_object(cary);
107
108
  TypedData_Get_Struct(cary, CArray, &carray_data_type, parent);
109
+ /* A record's boolean member is a byte of a fixlen array that other
110
+ fields (a uint8 one, a String store of the record) can write as any
111
+ byte. It is read through a cast to boolean, which refuses a byte
112
+ that is not 0 or 1, as fake(:boolean) does. */
113
+ if ( data_type == CA_BOOLEAN && parent->data_type == CA_FIXLEN ) {
114
+ obj = rb_ca_field_new(cary, offset, CA_UINT8, 1);
115
+ return rb_ca_fake_new(obj, CA_BOOLEAN, 1);
116
+ }
108
117
  ca = ca_field_new(parent, offset, data_type, bytes);
109
118
  obj = ca_wrap_struct(ca);
110
119
  rb_ca_set_parent(obj, cary);
@@ -139,7 +148,7 @@ rb_ca_field (int argc, VALUE *argv, VALUE self)
139
148
  rb_scan_args(argc, argv, "21", (VALUE *) &voffset, (VALUE *) &rtype, (VALUE *) &ropt);
140
149
  rb_scan_options(ropt, "bytes", &rbytes);
141
150
 
142
- offset = NUM2SIZE(voffset);
151
+ offset = ca_integer_arg(voffset, "offset", NULL);
143
152
 
144
153
  if ( rb_obj_is_carray(rtype) ) {
145
154
  CArray *ct;
@@ -149,6 +158,7 @@ rb_ca_field (int argc, VALUE *argv, VALUE self)
149
158
  TypedData_Get_Struct(rtype, CArray, &carray_data_type, ct);
150
159
  data_type = CA_FIXLEN;
151
160
  bytes = ct->bytes * ct->elements;
161
+ ca_check_rank_fits((long) ca->ndim + ct->ndim, "field");
152
162
  obj = rb_ca_field_new(self, offset, data_type, bytes);
153
163
  ndim = ca->ndim + ct->ndim;
154
164
  for (i=0; i<ca->ndim; i++) {
data/ext/ca_obj_grid.c CHANGED
@@ -242,7 +242,9 @@ ca_grid_setup (CAGrid *ca, CArray *parent, int8_t ndim,
242
242
  ca_set_flag(ca, CA_FLAG_SHARE_INDEX);
243
243
  ca->axes = protos;
244
244
  } else {
245
- ca->axes = ALLOC_N(cag_axis_t, ndim);
245
+ /* Zeroed: an axis's indices or holes that cannot be allocated raises
246
+ with the later axes not yet copied, and free_ca_grid reads them. */
247
+ ca->axes = ZALLOC_N(cag_axis_t, ndim);
246
248
  for (k = 0; k < ndim; k++) {
247
249
  ca->axes[k].kind = protos[k].kind;
248
250
  ca->axes[k].count = protos[k].count;
@@ -319,16 +321,38 @@ ca_grid_inherit_mask (VALUE view)
319
321
  return ca_view_inherit_mask(view);
320
322
  }
321
323
 
322
- /* holes_read_masked is the copied grid's: a copy of a mask grid is one. */
324
+ typedef struct {
325
+ CAGrid *ca;
326
+ CArray *parent;
327
+ int8_t ndim;
328
+ cag_axis_t *protos;
329
+ } ca_grid_new_arg;
330
+
331
+ static VALUE
332
+ ca_grid_new_setup (VALUE varg)
333
+ {
334
+ ca_grid_new_arg *a = (ca_grid_new_arg *) varg;
335
+ ca_grid_setup(a->ca, a->parent, a->ndim, a->protos, 0);
336
+ return Qnil;
337
+ }
338
+
339
+ /* holes_read_masked is the copied grid's: a copy of a mask grid is one.
340
+ The setup allocates the axes after the struct and its pool: when that
341
+ fails, the struct goes too. */
323
342
  static CAGrid *
324
343
  ca_grid_new_as (CArray *parent, int8_t ndim, cag_axis_t *protos,
325
344
  int8_t holes_read_masked, CAGrid *mask_owner)
326
345
  {
327
346
  CAGrid *ca;
347
+ ca_grid_new_arg a;
328
348
  ca_grid_check_protos(parent, ndim, protos);
329
349
  /* check: ca_grid_check_protos above */
330
350
  ca = (CAGrid *) ca_array_alloc(CA_OBJ_GRID, ndim);
331
- ca_grid_setup(ca, parent, ndim, protos, 0);
351
+ a.ca = ca;
352
+ a.parent = parent;
353
+ a.ndim = ndim;
354
+ a.protos = protos;
355
+ ca_fill_or_free((CArray *) ca, ca_grid_new_setup, (VALUE) &a);
332
356
  ca->holes_read_masked = holes_read_masked;
333
357
  ca->mask_owner = mask_owner;
334
358
  ca_fill_or_free((CArray *) ca, ca_grid_inherit_mask, (VALUE) ca);
@@ -358,7 +382,7 @@ free_ca_grid (void *ap)
358
382
  if ( ca != NULL ) {
359
383
  ca_free(ca->mask);
360
384
  ca_free(ca->mask_standin);
361
- if ( ! (ca->flags & CA_FLAG_SHARE_INDEX) ) {
385
+ if ( ! (ca->flags & CA_FLAG_SHARE_INDEX) && ca->axes ) {
362
386
  int8_t k;
363
387
  for (k = 0; k < ca->ndim; k++) {
364
388
  if ( ca->axes[k].kind == CAG_AXIS_INDEX && ca->axes[k].indices ) {
@@ -1226,7 +1250,15 @@ rb_ca_grid (int argc, VALUE *argv, VALUE self)
1226
1250
  rb_raise(rb_eArgError, "invalid total ndim of args");
1227
1251
  }
1228
1252
  ref = rb_ca_refer_new(self, ca->data_type, rndim, rdim, ca->bytes, 0);
1229
- return rb_ca_grid(argc, argv, ref);
1253
+ /* An index array that spans several axes picks along the one axis
1254
+ they are joined into, so it is read flat there. */
1255
+ {
1256
+ VALUE flat[CA_RANK_MAX];
1257
+ for (i=0; i<rndim; i++) {
1258
+ flat[i] = rb_obj_is_carray(argv[i]) ? rb_ca_flatten(argv[i]) : argv[i];
1259
+ }
1260
+ return rb_ca_grid(argc, flat, ref);
1261
+ }
1230
1262
  }
1231
1263
 
1232
1264
  /* Dispatch hook: route a boolean on axis 0 with plain keys elsewhere to
@@ -1256,6 +1288,21 @@ rb_ca_grid (int argc, VALUE *argv, VALUE self)
1256
1288
  protos[i].holes = NULL;
1257
1289
  continue;
1258
1290
  }
1291
+ {
1292
+ /* An index array picks cells along its one axis. One of more axes
1293
+ states a shape the axis does not have. */
1294
+ CArray *cs;
1295
+ TypedData_Get_Struct(rval, CArray, &carray_data_type, cs);
1296
+ if ( cs->ndim > 1 ) {
1297
+ volatile VALUE sshape = rb_ary_new();
1298
+ int k;
1299
+ for (k = 0; k < cs->ndim; k++) rb_ary_push(sshape, SIZE2NUM(cs->dim[k]));
1300
+ rb_raise(rb_eArgError,
1301
+ "%s: index array of shape %"PRIsVALUE" on axis %d (an index "
1302
+ "array picks along one axis; use .flatten)",
1303
+ ca_calling_method_name(), sshape, (int) i);
1304
+ }
1305
+ }
1259
1306
  if ( rb_ca_is_boolean_type(rval) ) {
1260
1307
  CArray *cb;
1261
1308
  TypedData_Get_Struct(rval, CArray, &carray_data_type, cb);