carray 3.0.4 → 3.0.6

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +438 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_dispatch.c +19 -20
  7. data/ext/ca_axis_group.c +1 -1
  8. data/ext/ca_categorical_iterator.c +34 -27
  9. data/ext/ca_compare.c +4 -4
  10. data/ext/ca_composite_dispatch.c +9 -9
  11. data/ext/ca_kernel_iterator.c +122 -237
  12. data/ext/ca_kernel_iterator.h +522 -337
  13. data/ext/ca_obj_array.c +69 -19
  14. data/ext/ca_obj_bincmp.c +10 -1
  15. data/ext/ca_obj_binop.c +11 -1
  16. data/ext/ca_obj_bitarray.c +5 -1
  17. data/ext/ca_obj_bitfield.c +60 -43
  18. data/ext/ca_obj_byte_swap.c +4 -1
  19. data/ext/ca_obj_const_string.c +15 -3
  20. data/ext/ca_obj_face.c +44 -1
  21. data/ext/ca_obj_fake.c +3 -1
  22. data/ext/ca_obj_field.c +13 -3
  23. data/ext/ca_obj_grid.c +219 -17
  24. data/ext/ca_obj_meld.c +69 -113
  25. data/ext/ca_obj_moncmp.c +9 -1
  26. data/ext/ca_obj_monop.c +86 -12
  27. data/ext/ca_obj_object.c +118 -32
  28. data/ext/ca_obj_record.c +3 -0
  29. data/ext/ca_obj_reduce.c +19 -1
  30. data/ext/ca_obj_refer.c +80 -26
  31. data/ext/ca_obj_remap.c +69 -10
  32. data/ext/ca_obj_roll.c +27 -6
  33. data/ext/ca_obj_select.c +38 -6
  34. data/ext/ca_obj_select_axis.c +1 -0
  35. data/ext/ca_obj_shift.c +32 -7
  36. data/ext/ca_obj_stack.c +311 -111
  37. data/ext/ca_obj_stride.c +159 -64
  38. data/ext/ca_obj_string.c +27 -2
  39. data/ext/ca_obj_tile.c +28 -7
  40. data/ext/ca_obj_transpose.c +8 -4
  41. data/ext/ca_obj_triop.c +12 -1
  42. data/ext/ca_obj_window.c +80 -50
  43. data/ext/ca_op_ipower.c +12 -12
  44. data/ext/ca_sort_kernels.h +6 -3
  45. data/ext/caframe_csv_reader.c +1 -1
  46. data/ext/carray.h +35 -1
  47. data/ext/carray_access.c +43 -67
  48. data/ext/carray_address_basis.c +134 -0
  49. data/ext/carray_attribute.c +32 -0
  50. data/ext/carray_broadcast.c +3 -4
  51. data/ext/carray_build_flags.h +1 -1
  52. data/ext/carray_cast.c +251 -93
  53. data/ext/carray_cast_func.rb +56 -26
  54. data/ext/carray_conversion.c +11 -7
  55. data/ext/carray_core.c +814 -72
  56. data/ext/carray_count.c +6 -0
  57. data/ext/carray_element.c +22 -13
  58. data/ext/carray_factorize.c +20 -20
  59. data/ext/carray_generate.c +8 -2
  60. data/ext/carray_histogram.c +26 -4
  61. data/ext/carray_index_classifier.c +4 -4
  62. data/ext/carray_internal.h +159 -12
  63. data/ext/carray_kernels_bincmp.c +2174 -170
  64. data/ext/carray_kernels_binop.c +25653 -5487
  65. data/ext/carray_kernels_init.c +8 -8
  66. data/ext/carray_kernels_moncmp.c +96 -96
  67. data/ext/carray_kernels_monop.c +12253 -5235
  68. data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
  69. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  70. data/ext/carray_kernels_reduce_cumulative.c +2442 -882
  71. data/ext/carray_kernels_reduce_extreme.c +5658 -1661
  72. data/ext/carray_kernels_reduce_variance.c +2534 -402
  73. data/ext/carray_kernels_scan.c +368 -368
  74. data/ext/carray_kernels_search.c +4551 -604
  75. data/ext/carray_kernels_sort.c +659 -751
  76. data/ext/carray_kernels_triop.c +114 -114
  77. data/ext/carray_key_windows.c +4 -0
  78. data/ext/carray_lazy.c +47 -0
  79. data/ext/carray_loop.c +1 -1
  80. data/ext/carray_mask.c +175 -161
  81. data/ext/carray_median_percentile.c +4 -4
  82. data/ext/carray_memory_view.c +15 -9
  83. data/ext/carray_operator.c +152 -49
  84. data/ext/carray_order.c +230 -10
  85. data/ext/carray_random.c +22 -19
  86. data/ext/carray_scatter.c +24 -7
  87. data/ext/carray_slab.c +128 -29
  88. data/ext/carray_sort.c +224 -16
  89. data/ext/carray_sort_kernel.c +5 -7
  90. data/ext/carray_struct.c +35 -43
  91. data/ext/carray_test.c +74 -19
  92. data/ext/carray_time_text.c +6 -4
  93. data/ext/carray_utils.c +63 -21
  94. data/ext/extconf.rb +11 -0
  95. data/ext/mkkernel.rb +546 -199
  96. data/ext/ruby_carray.c +4 -1
  97. data/ext/version.h +4 -4
  98. data/lib/carray/attribute.rb +42 -5
  99. data/lib/carray/autoload_carray.rb +3 -3
  100. data/lib/carray/autoload_method_extension.rb +5 -3
  101. data/lib/carray/axis_group.rb +13 -7
  102. data/lib/carray/basics.rb +28 -8
  103. data/lib/carray/block_iterator.rb +17 -3
  104. data/lib/carray/categorical.rb +35 -23
  105. data/lib/carray/categorical_iterator.rb +8 -8
  106. data/lib/carray/complex.rb +2 -2
  107. data/lib/carray/conditional.rb +3 -2
  108. data/lib/carray/const_string.rb +10 -0
  109. data/lib/carray/data_type_extension.rb +8 -1
  110. data/lib/carray/fixlen_string.rb +41 -2
  111. data/lib/carray/frame/column_verbs.rb +48 -16
  112. data/lib/carray/frame/concat.rb +17 -3
  113. data/lib/carray/frame/convert.rb +19 -0
  114. data/lib/carray/frame/csv_parser.rb +32 -32
  115. data/lib/carray/frame/describe.rb +4 -2
  116. data/lib/carray/frame/frame.rb +405 -85
  117. data/lib/carray/frame/group.rb +777 -64
  118. data/lib/carray/frame/io.rb +212 -72
  119. data/lib/carray/frame/join.rb +146 -37
  120. data/lib/carray/frame/records.rb +3 -3
  121. data/lib/carray/frame/reshape.rb +89 -11
  122. data/lib/carray/frame/sort.rb +57 -9
  123. data/lib/carray/frame/verbs.rb +384 -49
  124. data/lib/carray/frame/windows.rb +44 -6
  125. data/lib/carray/fuse_source.rb +31 -2
  126. data/lib/carray/inspect.rb +7 -2
  127. data/lib/carray/iterator.rb +32 -0
  128. data/lib/carray/lazy.rb +52 -8
  129. data/lib/carray/mask_gap_fill.rb +37 -17
  130. data/lib/carray/meld_reduce.rb +1 -1
  131. data/lib/carray/methods/choose.rb +3 -2
  132. data/lib/carray/methods/is_in.rb +8 -1
  133. data/lib/carray/methods/meshgrid.rb +3 -1
  134. data/lib/carray/runtime.rb +47 -8
  135. data/lib/carray/segment_iterator.rb +35 -16
  136. data/lib/carray/serialize.rb +53 -19
  137. data/lib/carray/stack.rb +33 -18
  138. data/lib/carray/string.rb +8 -0
  139. data/lib/carray/string_operation_extension.rb +13 -5
  140. data/lib/carray/struct_builder.rb +5 -3
  141. data/lib/carray/time.rb +112 -68
  142. data/lib/carray/window_iterator.rb +16 -4
  143. data/yard-stubs/ca_obj_array.rb +26 -1
  144. data/yard-stubs/ca_obj_transpose.rb +5 -4
  145. data/yard-stubs/carray_attribute.rb +3 -1
  146. data/yard-stubs/carray_cast.rb +10 -5
  147. data/yard-stubs/carray_conversion.rb +13 -3
  148. data/yard-stubs/carray_element.rb +7 -6
  149. data/yard-stubs/carray_mask.rb +28 -4
  150. data/yard-stubs/carray_math.rb +45 -20
  151. data/yard-stubs/carray_memory_view.rb +7 -0
  152. data/yard-stubs/carray_order.rb +100 -4
  153. data/yard-stubs/carray_scatter.rb +7 -5
  154. data/yard-stubs/carray_test.rb +7 -4
  155. metadata +18 -4
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
@@ -291,9 +291,11 @@ ca_bincmp_try_leaf_inplace (CArray *op, int8_t common_dt,
291
291
 
292
292
  /* Evaluate the cells a request names into `data` (packed, n cells). */
293
293
  static void
294
- ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
294
+ ca_bincmp_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
295
295
  {
296
+ CABinCmp *bc = (CABinCmp *) node;
296
297
  ca_size_t slab_n = req->n;
298
+ (void) dir;
297
299
  int8_t k;
298
300
  void *left_scratch, *right_scratch;
299
301
  ca_size_t left_bytes, right_bytes;
@@ -437,6 +439,12 @@ ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
437
439
  if ( ! left_is_inplace ) ca_lazy_arena_release(left_scratch);
438
440
  }
439
441
 
442
+ static void
443
+ ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
444
+ {
445
+ ca_lazy_eval_recorded(bc, 2, bc->operands, 0, NULL, ca_bincmp_eval_cells, req, data, CA_XFER_GET);
446
+ }
447
+
440
448
  static void
441
449
  ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
442
450
  ca_size_t *strides, void *data, int dir)
@@ -647,6 +655,7 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
647
655
  r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
648
656
  }
649
657
 
658
+ ca_refuse_without_common_type(l_resolved, r_resolved);
650
659
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
651
660
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
652
661
 
data/ext/ca_obj_binop.c CHANGED
@@ -249,9 +249,11 @@ ca_size_t ca_binop_materialise_call_count = 0;
249
249
 
250
250
  /* Evaluate the cells a request names into `data` (packed, n cells). */
251
251
  static void
252
- ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
252
+ ca_binop_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
253
253
  {
254
+ CABinOp *bo = (CABinOp *) node;
254
255
  ca_size_t slab_n = req->n;
256
+ (void) dir;
255
257
  int8_t k;
256
258
  void *scratch;
257
259
  volatile VALUE holder;
@@ -350,6 +352,13 @@ ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
350
352
  ca_lazy_arena_release(scratch);
351
353
  }
352
354
 
355
+ static void
356
+ ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
357
+ {
358
+ ca_lazy_eval_recorded(bo, 2, bo->operands, 0, NULL, ca_binop_eval_cells,
359
+ req, data, CA_XFER_GET);
360
+ }
361
+
353
362
  static void
354
363
  ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
355
364
  ca_size_t *strides, void *data, int dir)
@@ -569,6 +578,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
569
578
  r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
570
579
  }
571
580
 
581
+ ca_refuse_without_common_type(l_resolved, r_resolved);
572
582
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
573
583
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
574
584
 
@@ -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
@@ -467,7 +480,9 @@ ca_bitfield_func_sync (void *ap)
467
480
  {
468
481
  CABitfield *ca = (CABitfield *) ap;
469
482
  ca_bitfield_sync(ca);
483
+ ca_view_pass_mask_to_parent(ca);
470
484
  ca_sync(ca->parent);
485
+ ca_view_sync_mask_after_parent(ca);
471
486
  }
472
487
 
473
488
  static void
@@ -666,8 +681,10 @@ rb_ca_bitfield (int argc, VALUE *argv, VALUE self)
666
681
 
667
682
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
668
683
 
669
- if ( TYPE(rrange) == T_FIXNUM ) {
670
- offset = NUM2INT(rrange);
684
+ if ( RB_INTEGER_TYPE_P(rrange) ) {
685
+ /* A bit of a cell: negative from the last. One beyond any cell is
686
+ refused by the setup's range check, as an offset past the cell is. */
687
+ offset = RB_FIXNUM_P(rrange) ? FIX2LONG(rrange) : CA_LENGTH_MAX;
671
688
  if ( offset < 0 ) {
672
689
  offset += ca->bytes * 8;
673
690
  }
@@ -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
@@ -490,7 +491,9 @@ ca_byte_swap_func_sync (void *ap)
490
491
  ca_byte_swap_apply(ca, tmp);
491
492
  memcpy(ca->parent->ptr, tmp, ca_length(ca));
492
493
  ALLOCV_END(holder);
494
+ ca_view_pass_mask_to_parent(ca);
493
495
  ca_sync(ca->parent);
496
+ ca_view_sync_mask_after_parent(ca);
494
497
  }
495
498
 
496
499
  static void
@@ -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
@@ -49,7 +49,9 @@ ca_face_sync (void *ap)
49
49
  {
50
50
  CAView *cav = (CAView *) ap;
51
51
  /* alias means no copy-back is needed; parent sync propagates */
52
+ ca_view_pass_mask_to_parent(cav);
52
53
  ca_sync(cav->parent);
54
+ ca_view_sync_mask_after_parent(cav);
53
55
  }
54
56
 
55
57
  void
@@ -281,7 +283,8 @@ ca_face_lift (VALUE view, VALUE face_parent)
281
283
  handled by builder-side pre-strip. data_type above stays a full strip
282
284
  (surface concern, §8 #7) — the parent pointer is the structural concern
283
285
  (§8.3); the two axes are deliberately separate. */
284
- if ( ((CAView *) view_ca)->parent == fp
286
+ if ( ca_is_view(view_ca) /* an entity (a copy) has no parent field */
287
+ && ((CAView *) view_ca)->parent == fp
285
288
  && ! ca_test_flag(view_ca, CA_FLAG_MULTI_PARENTS) ) {
286
289
  ((CAView *) view_ca)->parent = ((CAView *) fp)->parent; /* C pointer: one level */
287
290
  rb_ca_set_parent(view, rb_ca_parent(face_parent)); /* @parent ivar: lockstep */
@@ -1233,6 +1236,25 @@ ca_face_reconcile_comparison (volatile VALUE *pself, volatile VALUE *pother)
1233
1236
  return;
1234
1237
  }
1235
1238
 
1239
+ /* Two string arrays of different kinds (CAString, CAFixlenString,
1240
+ CAConstString) or of different cell widths hold their strings in
1241
+ different storage: the padded bytes of one are not the bytes of the
1242
+ other. They are compared by their strings. */
1243
+ if ( RTEST(rb_obj_is_carray(other)) ) {
1244
+ static ID id_to_string = 0;
1245
+ CArray *oc;
1246
+ if ( id_to_string == 0 ) id_to_string = rb_intern("to_string");
1247
+ TypedData_Get_Struct(other, CArray, &carray_data_type, oc);
1248
+ if ( ca_is_face(oc) && rb_respond_to(self, id_to_string)
1249
+ && rb_respond_to(other, id_to_string)
1250
+ && ( rb_obj_class(self) != rb_obj_class(other)
1251
+ || sc->bytes != oc->bytes ) ) {
1252
+ *pself = rb_ca_strip_face_value(rb_funcall(self, id_to_string, 0));
1253
+ *pother = rb_ca_strip_face_value(rb_funcall(other, id_to_string, 0));
1254
+ return;
1255
+ }
1256
+ }
1257
+
1236
1258
  storage = ca_strip_face(sc);
1237
1259
  if ( storage->data_type == CA_FIXLEN ) {
1238
1260
  /* genuine fixlen semantics: memcmp is the correct comparison, so self
@@ -1262,6 +1284,26 @@ ca_face_reconcile_comparison (volatile VALUE *pself, volatile VALUE *pother)
1262
1284
  }
1263
1285
  }
1264
1286
 
1287
+ /* A Face's parent, the array its values are stored in, is handed out as a
1288
+ read-only view: a write through it would change the Face's values
1289
+ without the Face's conversion (a tick count stored into a time, bytes
1290
+ into a record). The storage is written through the Face's own named
1291
+ methods (CATime#ticks), which take it with face_storage. */
1292
+ static VALUE
1293
+ rb_ca_face_parent (VALUE self)
1294
+ {
1295
+ volatile VALUE st = rb_ca_parent(self), view;
1296
+ CArray *cs, *cv;
1297
+ if ( NIL_P(st) ) {
1298
+ return st;
1299
+ }
1300
+ TypedData_Get_Struct(st, CArray, &carray_data_type, cs);
1301
+ view = rb_ca_refer_new(st, cs->data_type, cs->ndim, cs->dim, cs->bytes, 0);
1302
+ TypedData_Get_Struct(view, CArray, &carray_data_type, cv);
1303
+ ca_set_flag(cv, CA_FLAG_READ_ONLY);
1304
+ return view;
1305
+ }
1306
+
1265
1307
  void
1266
1308
  Init_ca_face (void)
1267
1309
  {
@@ -1271,6 +1313,7 @@ Init_ca_face (void)
1271
1313
  ahead of this Init) — CAFace inherits from it. */
1272
1314
  rb_cCAFace = rb_define_class("CAFace", rb_cCAView);
1273
1315
  rb_define_alloc_func(rb_cCAFace, rb_ca_face_s_allocate_forbidden);
1316
+ rb_define_method(rb_cCAFace, "parent", rb_ca_face_parent, 0);
1274
1317
 
1275
1318
  /* Initialise the portable table to -1 for every slot so dispatch
1276
1319
  can distinguish "explicitly registered 0" (CAConstString) from
data/ext/ca_obj_fake.c CHANGED
@@ -310,12 +310,14 @@ ca_fake_func_sync (void *ap)
310
310
  ca_update_mask(ca);
311
311
  if ( ca->mask ) {
312
312
  ca_cast_block_with_mask(ca->elements, ca, ca->ptr, ca->parent, ca->parent->ptr,
313
- (boolean8_t *)ca->parent->mask->ptr);
313
+ (boolean8_t *)ca->mask->ptr);
314
314
  }
315
315
  else {
316
316
  ca_cast_block(ca->elements, ca, ca->ptr, ca->parent, ca->parent->ptr);
317
317
  }
318
+ ca_view_pass_mask_to_parent(ca);
318
319
  ca_sync(ca->parent);
320
+ ca_view_sync_mask_after_parent(ca);
319
321
  }
320
322
 
321
323
  static void
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++) {