carray 3.0.5 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +233 -0
- data/README.md +1 -1
- data/carray.gemspec +3 -2
- data/ext/ca_axis_dispatch.c +6 -0
- data/ext/ca_axis_group.c +1 -1
- data/ext/ca_categorical_iterator.c +7 -7
- data/ext/ca_kernel_iterator.c +116 -231
- data/ext/ca_kernel_iterator.h +410 -254
- data/ext/ca_obj_bincmp.c +9 -1
- data/ext/ca_obj_binop.c +10 -1
- data/ext/ca_obj_bitfield.c +2 -0
- data/ext/ca_obj_byte_swap.c +2 -0
- data/ext/ca_obj_face.c +2 -0
- data/ext/ca_obj_fake.c +3 -1
- data/ext/ca_obj_grid.c +167 -12
- data/ext/ca_obj_meld.c +69 -113
- data/ext/ca_obj_moncmp.c +9 -1
- data/ext/ca_obj_monop.c +40 -2
- data/ext/ca_obj_object.c +54 -20
- data/ext/ca_obj_reduce.c +15 -1
- data/ext/ca_obj_refer.c +65 -20
- data/ext/ca_obj_remap.c +69 -10
- data/ext/ca_obj_roll.c +1 -0
- data/ext/ca_obj_select.c +4 -1
- data/ext/ca_obj_select_axis.c +1 -0
- data/ext/ca_obj_shift.c +1 -0
- data/ext/ca_obj_stack.c +310 -111
- data/ext/ca_obj_stride.c +131 -45
- data/ext/ca_obj_string.c +18 -2
- data/ext/ca_obj_tile.c +1 -0
- data/ext/ca_obj_triop.c +9 -1
- data/ext/ca_obj_window.c +1 -0
- data/ext/ca_op_ipower.c +8 -8
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +2 -1
- data/ext/carray_access.c +27 -64
- data/ext/carray_address_basis.c +134 -0
- data/ext/carray_attribute.c +8 -0
- data/ext/carray_broadcast.c +3 -4
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_cast.c +8 -11
- data/ext/carray_conversion.c +9 -5
- data/ext/carray_core.c +811 -72
- data/ext/carray_element.c +13 -9
- data/ext/carray_histogram.c +25 -3
- data/ext/carray_internal.h +147 -12
- data/ext/carray_kernels_bincmp.c +2007 -3
- data/ext/carray_kernels_binop.c +25365 -5199
- data/ext/carray_kernels_init.c +8 -8
- data/ext/carray_kernels_monop.c +10696 -3678
- data/ext/carray_kernels_reduce_aggregate.c +4429 -702
- data/ext/carray_kernels_reduce_boolean.c +1533 -15
- data/ext/carray_kernels_reduce_cumulative.c +1808 -248
- data/ext/carray_kernels_reduce_extreme.c +4508 -511
- data/ext/carray_kernels_reduce_variance.c +2284 -152
- data/ext/carray_kernels_scan.c +240 -240
- data/ext/carray_kernels_search.c +4211 -264
- data/ext/carray_kernels_sort.c +367 -450
- data/ext/carray_lazy.c +47 -0
- data/ext/carray_loop.c +1 -1
- data/ext/carray_mask.c +130 -139
- data/ext/carray_median_percentile.c +4 -4
- data/ext/carray_memory_view.c +13 -7
- data/ext/carray_operator.c +147 -44
- data/ext/carray_order.c +3 -2
- data/ext/carray_random.c +4 -1
- data/ext/carray_slab.c +97 -21
- data/ext/carray_sort.c +1 -1
- data/ext/carray_test.c +74 -19
- data/ext/carray_time_text.c +2 -2
- data/ext/extconf.rb +11 -0
- data/ext/mkkernel.rb +346 -94
- data/ext/ruby_carray.c +4 -1
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +25 -1
- data/lib/carray/autoload_carray.rb +3 -3
- data/lib/carray/autoload_method_extension.rb +5 -3
- data/lib/carray/axis_group.rb +13 -7
- data/lib/carray/basics.rb +1 -1
- data/lib/carray/block_iterator.rb +17 -3
- data/lib/carray/categorical.rb +6 -8
- data/lib/carray/categorical_iterator.rb +2 -2
- data/lib/carray/complex.rb +2 -2
- data/lib/carray/conditional.rb +3 -2
- data/lib/carray/frame/column_verbs.rb +45 -14
- data/lib/carray/frame/convert.rb +19 -0
- data/lib/carray/frame/csv_parser.rb +32 -32
- data/lib/carray/frame/describe.rb +4 -2
- data/lib/carray/frame/frame.rb +399 -78
- data/lib/carray/frame/group.rb +679 -53
- data/lib/carray/frame/io.rb +209 -71
- data/lib/carray/frame/join.rb +146 -37
- data/lib/carray/frame/records.rb +3 -3
- data/lib/carray/frame/reshape.rb +89 -11
- data/lib/carray/frame/sort.rb +57 -9
- data/lib/carray/frame/verbs.rb +384 -49
- data/lib/carray/frame/windows.rb +44 -6
- data/lib/carray/inspect.rb +7 -2
- data/lib/carray/iterator.rb +32 -0
- data/lib/carray/lazy.rb +17 -8
- data/lib/carray/mask_gap_fill.rb +37 -17
- data/lib/carray/meld_reduce.rb +1 -1
- data/lib/carray/methods/choose.rb +3 -2
- data/lib/carray/methods/meshgrid.rb +3 -1
- data/lib/carray/runtime.rb +47 -8
- data/lib/carray/segment_iterator.rb +23 -8
- data/lib/carray/serialize.rb +34 -17
- data/lib/carray/stack.rb +18 -6
- data/lib/carray/time.rb +5 -0
- data/lib/carray/window_iterator.rb +16 -4
- data/yard-stubs/ca_obj_array.rb +26 -1
- data/yard-stubs/carray_cast.rb +8 -5
- data/yard-stubs/carray_conversion.rb +8 -2
- data/yard-stubs/carray_mask.rb +20 -1
- data/yard-stubs/carray_math.rb +31 -16
- data/yard-stubs/carray_memory_view.rb +7 -0
- data/yard-stubs/carray_test.rb +7 -4
- metadata +18 -4
data/ext/ca_obj_monop.c
CHANGED
|
@@ -453,8 +453,9 @@ pull_leaf_with_optional_cast (CArray *leaf, uint16_t innermost_op,
|
|
|
453
453
|
/* Evaluate (GET) or write (PUT, writable views only) the cells a request
|
|
454
454
|
names; `data` holds them packed. */
|
|
455
455
|
static void
|
|
456
|
-
|
|
456
|
+
ca_monop_eval_cells (void *node, const ca_lazy_req_t *req, void *data, int dir)
|
|
457
457
|
{
|
|
458
|
+
CAMonOp *mo = (CAMonOp *) node;
|
|
458
459
|
uint16_t op_chain[CA_MAX_LAZY_DEPTH];
|
|
459
460
|
int chain_len = 0;
|
|
460
461
|
CArray *leaf;
|
|
@@ -641,6 +642,26 @@ ca_monop_eval (CAMonOp *mo, const ca_lazy_req_t *req, void *data, int dir)
|
|
|
641
642
|
}
|
|
642
643
|
}
|
|
643
644
|
|
|
645
|
+
/* A chain is evaluated from its leaf without evaluating the nodes under
|
|
646
|
+
the top one, so those nodes are recorded with it: a cell that holds an
|
|
647
|
+
expression over one of them is caught when it comes back, before a
|
|
648
|
+
longer chain over the same cells is built. */
|
|
649
|
+
static void
|
|
650
|
+
ca_monop_eval (CAMonOp *mo, const ca_lazy_req_t *req, void *data, int dir)
|
|
651
|
+
{
|
|
652
|
+
CArray *chain[CA_MAX_LAZY_DEPTH];
|
|
653
|
+
CArray *leaf = mo->parent;
|
|
654
|
+
int nchain = 0;
|
|
655
|
+
while ( nchain < CA_MAX_LAZY_DEPTH &&
|
|
656
|
+
( leaf->obj_type == CA_OBJ_MONOP ||
|
|
657
|
+
leaf->obj_type == CA_OBJ_LAZY_MARKER ) ) {
|
|
658
|
+
chain[nchain++] = leaf;
|
|
659
|
+
leaf = ((CAView *) leaf)->parent;
|
|
660
|
+
}
|
|
661
|
+
ca_lazy_eval_recorded(mo, 1, &leaf, nchain, chain, ca_monop_eval_cells,
|
|
662
|
+
req, data, dir);
|
|
663
|
+
}
|
|
664
|
+
|
|
644
665
|
static void
|
|
645
666
|
ca_monop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
646
667
|
ca_size_t *strides, void *data, int dir)
|
|
@@ -776,7 +797,7 @@ ca_monop_func_sync (void *ap)
|
|
|
776
797
|
if ( ca->mask ) {
|
|
777
798
|
ca_cast_block_with_mask(ca->elements, ca, ca->ptr,
|
|
778
799
|
ca->parent, ca->parent->ptr,
|
|
779
|
-
(boolean8_t *) ca->
|
|
800
|
+
(boolean8_t *) ca->mask->ptr);
|
|
780
801
|
}
|
|
781
802
|
else {
|
|
782
803
|
ca_cast_block(ca->elements, ca, ca->ptr, ca->parent, ca->parent->ptr);
|
|
@@ -790,7 +811,9 @@ ca_monop_func_sync (void *ap)
|
|
|
790
811
|
ca_byte_swap_buffer(ca->data_type, ca->bytes, ca->elements,
|
|
791
812
|
ca->parent->ptr);
|
|
792
813
|
}
|
|
814
|
+
ca_view_pass_mask_to_parent(ca);
|
|
793
815
|
ca_sync(ca->parent);
|
|
816
|
+
ca_view_sync_mask_after_parent(ca);
|
|
794
817
|
}
|
|
795
818
|
|
|
796
819
|
static void
|
|
@@ -847,6 +870,21 @@ ca_monop_func_create_mask (void *ap)
|
|
|
847
870
|
}
|
|
848
871
|
}
|
|
849
872
|
|
|
873
|
+
/* For a writable cast: 1 and the data type it writes its parent in. 0 for
|
|
874
|
+
any other array. */
|
|
875
|
+
int
|
|
876
|
+
ca_monop_writable_cast_target (CArray *ca, int8_t *target)
|
|
877
|
+
{
|
|
878
|
+
CAMonOp *mo = (CAMonOp *) ca;
|
|
879
|
+
if ( ca->obj_type != CA_OBJ_MONOP
|
|
880
|
+
|| ! ca_monop_is_writable_view(mo->op_id)
|
|
881
|
+
|| ! ca_monop_is_cast(mo->op_id) ) {
|
|
882
|
+
return 0;
|
|
883
|
+
}
|
|
884
|
+
*target = mo->parent->data_type;
|
|
885
|
+
return 1;
|
|
886
|
+
}
|
|
887
|
+
|
|
850
888
|
ca_operation_function_t ca_monop_func = {
|
|
851
889
|
-1, /* CA_OBJ_MONOP, set at install time */
|
|
852
890
|
CA_VIEW_ARRAY,
|
data/ext/ca_obj_object.c
CHANGED
|
@@ -249,7 +249,7 @@ ca_object_lend_restore (VALUE varg)
|
|
|
249
249
|
return Qnil;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
static
|
|
252
|
+
static VALUE
|
|
253
253
|
ca_object_call_lending (CAObject *ca, void *ptr, const char *mid)
|
|
254
254
|
{
|
|
255
255
|
ca_object_lend_t l;
|
|
@@ -272,7 +272,7 @@ ca_object_call_lending (CAObject *ca, void *ptr, const char *mid)
|
|
|
272
272
|
data->ptr = (char *) ptr;
|
|
273
273
|
rb_ensure(ca_object_lend_body, (VALUE) &l,
|
|
274
274
|
ca_object_lend_restore, (VALUE) &l);
|
|
275
|
-
|
|
275
|
+
return l.wrap;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
/* Calls recv.mid(*argv), where some of argv are transient wraps of a
|
|
@@ -889,11 +889,10 @@ ca_object_mask_bytes (CAObject *ca)
|
|
|
889
889
|
return (boolean8_t *) ca->mask->ptr;
|
|
890
890
|
}
|
|
891
891
|
|
|
892
|
-
/* Whether the mask of this object comes from its mask_* hooks.
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
value fetched clears the cell. */
|
|
892
|
+
/* Whether the mask of this object comes from its mask_* hooks. A fetched
|
|
893
|
+
value says nothing about the mask either way: a cell masked -- by the
|
|
894
|
+
hooks, or without hooks by a write of UNDEF or `mask =` -- stays masked
|
|
895
|
+
when its value is read, and only a fetcher answering UNDEF marks one. */
|
|
897
896
|
static int
|
|
898
897
|
ca_object_mask_from_hooks (CAObject *ca)
|
|
899
898
|
{
|
|
@@ -922,9 +921,6 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
|
|
|
922
921
|
}
|
|
923
922
|
}
|
|
924
923
|
else {
|
|
925
|
-
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
926
|
-
ca_object_mask_bytes(ca)[addr] = 0;
|
|
927
|
-
}
|
|
928
924
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
929
925
|
}
|
|
930
926
|
}
|
|
@@ -944,9 +940,6 @@ ca_object_xfer_addr_one (CAObject *ca, ca_size_t addr, void *ptr, int dir)
|
|
|
944
940
|
}
|
|
945
941
|
}
|
|
946
942
|
else {
|
|
947
|
-
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
948
|
-
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
|
|
949
|
-
}
|
|
950
943
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
951
944
|
}
|
|
952
945
|
}
|
|
@@ -990,9 +983,6 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
|
|
|
990
983
|
}
|
|
991
984
|
}
|
|
992
985
|
else {
|
|
993
|
-
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
994
|
-
ca_object_mask_bytes(ca)[ca_index2addr(ca->mask, idx)] = 0;
|
|
995
|
-
}
|
|
996
986
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
997
987
|
}
|
|
998
988
|
}
|
|
@@ -1008,9 +998,6 @@ ca_object_xfer_index_one (CAObject *ca, ca_size_t *idx, void *ptr, int dir)
|
|
|
1008
998
|
}
|
|
1009
999
|
}
|
|
1010
1000
|
else {
|
|
1011
|
-
if ( ! ca_object_mask_from_hooks(ca) && ca_has_mask(ca) ) {
|
|
1012
|
-
ca_object_mask_bytes(ca)[addr] = 0;
|
|
1013
|
-
}
|
|
1014
1001
|
rb_ca_obj2ptr(ca->self, rval, ptr);
|
|
1015
1002
|
}
|
|
1016
1003
|
}
|
|
@@ -1094,6 +1081,34 @@ ca_object_copy_bare_restore (VALUE arg)
|
|
|
1094
1081
|
return Qnil;
|
|
1095
1082
|
}
|
|
1096
1083
|
|
|
1084
|
+
/* copy_data of an object with no mask yet: an UNDEF the call writes lands
|
|
1085
|
+
on a mask of the wrap's own, which the wrap takes away with it. The
|
|
1086
|
+
cells it marks are masked on the object, as a fetcher answering UNDEF
|
|
1087
|
+
masks its cell, so a bulk read and a cell read give the same answer. */
|
|
1088
|
+
static void
|
|
1089
|
+
ca_object_adopt_undef_cells (CAObject *ca, VALUE wrap)
|
|
1090
|
+
{
|
|
1091
|
+
CArray *wm = ((CArray *) DATA_PTR(wrap))->mask;
|
|
1092
|
+
boolean8_t *bits;
|
|
1093
|
+
ca_size_t i, n;
|
|
1094
|
+
if ( wm == NULL || wm->ptr == NULL ) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
n = ( wm->elements < ca->elements ) ? wm->elements : ca->elements;
|
|
1098
|
+
for ( i = 0; i < n && ! wm->ptr[i]; i++ ) {
|
|
1099
|
+
;
|
|
1100
|
+
}
|
|
1101
|
+
if ( i == n ) {
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
ca_create_mask(ca);
|
|
1105
|
+
bits = ca_object_mask_bytes(ca);
|
|
1106
|
+
for ( ; i < n; i++ ) {
|
|
1107
|
+
if ( wm->ptr[i] ) bits[i] = 1;
|
|
1108
|
+
}
|
|
1109
|
+
RB_GC_GUARD(wrap);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1097
1112
|
static void
|
|
1098
1113
|
ca_object_dispatch_copy (CAObject *ca, void *ptr)
|
|
1099
1114
|
{
|
|
@@ -1108,7 +1123,26 @@ ca_object_dispatch_copy (CAObject *ca, void *ptr)
|
|
|
1108
1123
|
ca_object_copy_bare_restore, (VALUE) &c);
|
|
1109
1124
|
return;
|
|
1110
1125
|
}
|
|
1111
|
-
|
|
1126
|
+
if ( ca->data->mask != NULL ) {
|
|
1127
|
+
/* Without hooks the mask is the object's own: a store of the values
|
|
1128
|
+
into the array copy_data is handed (d[] = src) would clear it, so
|
|
1129
|
+
the cells it held masked are masked again after the call, beside
|
|
1130
|
+
those the call marks. */
|
|
1131
|
+
CArray *m = ca->data->mask;
|
|
1132
|
+
volatile VALUE vkept = rb_str_new(m->ptr, (long) m->elements);
|
|
1133
|
+
const char *kept;
|
|
1134
|
+
ca_size_t i;
|
|
1135
|
+
ca_object_call_lending(ca, ptr, "copy_data");
|
|
1136
|
+
kept = RSTRING_PTR(vkept);
|
|
1137
|
+
m = ca->data->mask;
|
|
1138
|
+
for ( i = 0; m != NULL && i < m->elements; i++ ) {
|
|
1139
|
+
if ( kept[i] ) m->ptr[i] = 1;
|
|
1140
|
+
}
|
|
1141
|
+
RB_GC_GUARD(vkept);
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
ca_object_adopt_undef_cells(ca,
|
|
1145
|
+
ca_object_call_lending(ca, ptr, "copy_data"));
|
|
1112
1146
|
}
|
|
1113
1147
|
else {
|
|
1114
1148
|
ca_size_t addr;
|
data/ext/ca_obj_reduce.c
CHANGED
|
@@ -127,7 +127,11 @@ ca_reduce_func_clone (void *ap)
|
|
|
127
127
|
/* addr-list logic lives in xfer_addrs: GET = OR-reduce `count` adjacent parent
|
|
128
128
|
bytes per addr; PUT = broadcast the value to all `count` parent cells.
|
|
129
129
|
fetch_addr/store_addr forward (n==1), xfer_index = index2addr then xfer_addrs.
|
|
130
|
-
|
|
130
|
+
|
|
131
|
+
A true PUT onto a cell that already reads true leaves the parent cells
|
|
132
|
+
as they are. Every sync of a view over a CAReduce sends back its cells,
|
|
133
|
+
changed or not; broadcasting an unchanged true would mask the parent
|
|
134
|
+
cells under it that were not masked. */
|
|
131
135
|
static void
|
|
132
136
|
ca_reduce_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
133
137
|
void *data, int dir)
|
|
@@ -147,6 +151,16 @@ ca_reduce_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
147
151
|
*(char*)cell = v;
|
|
148
152
|
}
|
|
149
153
|
else {
|
|
154
|
+
if ( *(char *) cell ) {
|
|
155
|
+
char q, v = 0;
|
|
156
|
+
for (i=0; i<ca->count; i++) {
|
|
157
|
+
ca_fetch_addr(ca->parent, addr*ca->count + i + ca->offset, &q);
|
|
158
|
+
if ( q ) { v = 1; break; }
|
|
159
|
+
}
|
|
160
|
+
if ( v ) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
150
164
|
for (i=0; i<ca->count; i++) {
|
|
151
165
|
ca_store_addr(ca->parent, addr*ca->count + i + ca->offset, cell);
|
|
152
166
|
}
|
data/ext/ca_obj_refer.c
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
#include "carray.h"
|
|
17
17
|
#include "carray_internal.h" /* per-obj_type view constructors */
|
|
18
18
|
#include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE for CARecord parent */
|
|
19
|
+
#include "ruby/thread_native.h"
|
|
19
20
|
|
|
20
21
|
extern ca_operation_function_t ca_stride_func;
|
|
21
22
|
|
|
@@ -145,9 +146,10 @@ ca_refer_setup (CARefer *ca, CArray *parent,
|
|
|
145
146
|
ca_stride_setup_view((CAStride *) ca, CA_OBJ_REFER, parent,
|
|
146
147
|
data_type, bytes, ndim, dim, strides, base_offset);
|
|
147
148
|
|
|
148
|
-
/* A refer of a scalar stays one only while it
|
|
149
|
-
narrower elements it is an array of
|
|
150
|
-
|
|
149
|
+
/* A refer of a scalar stays one only while it is one cell along one
|
|
150
|
+
axis, as a scalar is: read as narrower elements it is an array of
|
|
151
|
+
several, and read under another shape it is an array of that shape. */
|
|
152
|
+
if (ca_is_scalar(parent) && ca->elements == 1 && ca->ndim == 1) {
|
|
151
153
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
152
154
|
}
|
|
153
155
|
return 0;
|
|
@@ -336,6 +338,59 @@ ca_keep_chain_flags (CArray *view, CArray *src)
|
|
|
336
338
|
}
|
|
337
339
|
}
|
|
338
340
|
|
|
341
|
+
/* The sources of folded views (CA_FLAG_FOLDED), keyed by the view. Views are
|
|
342
|
+
made and freed in any Ractor, so the table is taken under a lock. */
|
|
343
|
+
static st_table *ca_fold_sources;
|
|
344
|
+
static rb_nativethread_lock_t ca_fold_lock;
|
|
345
|
+
|
|
346
|
+
void
|
|
347
|
+
ca_fold_note_source (CArray *view, CArray *src)
|
|
348
|
+
{
|
|
349
|
+
rb_native_mutex_lock(&ca_fold_lock);
|
|
350
|
+
st_insert(ca_fold_sources, (st_data_t) view, (st_data_t) src);
|
|
351
|
+
rb_native_mutex_unlock(&ca_fold_lock);
|
|
352
|
+
ca_set_flag(view, CA_FLAG_FOLDED);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
CArray *
|
|
356
|
+
ca_fold_source (CArray *view)
|
|
357
|
+
{
|
|
358
|
+
st_data_t src = 0;
|
|
359
|
+
rb_native_mutex_lock(&ca_fold_lock);
|
|
360
|
+
st_lookup(ca_fold_sources, (st_data_t) view, &src);
|
|
361
|
+
rb_native_mutex_unlock(&ca_fold_lock);
|
|
362
|
+
return (CArray *) src;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
void
|
|
366
|
+
ca_fold_forget (CArray *view)
|
|
367
|
+
{
|
|
368
|
+
st_data_t key = (st_data_t) view;
|
|
369
|
+
rb_native_mutex_lock(&ca_fold_lock);
|
|
370
|
+
st_delete(ca_fold_sources, &key, NULL);
|
|
371
|
+
rb_native_mutex_unlock(&ca_fold_lock);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* Builds the folded view of `ca` for reshape / flatten: a CAStride over
|
|
375
|
+
`root`. When `ca` is not `root` itself, it is recorded as the view's
|
|
376
|
+
source. */
|
|
377
|
+
static VALUE
|
|
378
|
+
ca_reshape_folded (VALUE self, CArray *ca, CArray *root, int8_t ndim,
|
|
379
|
+
ca_size_t *dim, ca_size_t *strides, ca_size_t base)
|
|
380
|
+
{
|
|
381
|
+
volatile VALUE obj;
|
|
382
|
+
CAStride *cs = ca_stride_new(CA_OBJ_STRIDE, root, ca->data_type, ca->bytes,
|
|
383
|
+
ndim, dim, strides, base);
|
|
384
|
+
ca_keep_chain_flags((CArray *) cs, ca);
|
|
385
|
+
obj = ca_wrap_struct(cs);
|
|
386
|
+
rb_ca_set_parent(obj, self);
|
|
387
|
+
if ( root != ca ) {
|
|
388
|
+
ca_fold_note_source((CArray *) cs, ca);
|
|
389
|
+
}
|
|
390
|
+
CA_WRAPPER_LIFT(obj, self, ca);
|
|
391
|
+
return obj;
|
|
392
|
+
}
|
|
393
|
+
|
|
339
394
|
static int
|
|
340
395
|
ca_reshape_try_strides (CArray *parent,
|
|
341
396
|
const ca_size_t *new_dim,
|
|
@@ -721,15 +776,8 @@ rb_ca_reshape (int argc, VALUE *argv, VALUE self)
|
|
|
721
776
|
ca_size_t out_base;
|
|
722
777
|
if (ca_reshape_try_strides(ca, new_dim, (int8_t) argc,
|
|
723
778
|
&out_root, out_strides, &out_base)) {
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
(int8_t) argc, new_dim,
|
|
727
|
-
out_strides, out_base);
|
|
728
|
-
ca_keep_chain_flags((CArray *) cs, ca);
|
|
729
|
-
obj = ca_wrap_struct(cs);
|
|
730
|
-
rb_ca_set_parent(obj, self);
|
|
731
|
-
CA_WRAPPER_LIFT(obj, self, ca);
|
|
732
|
-
return obj;
|
|
779
|
+
return ca_reshape_folded(self, ca, out_root, (int8_t) argc, new_dim,
|
|
780
|
+
out_strides, out_base);
|
|
733
781
|
}
|
|
734
782
|
}
|
|
735
783
|
|
|
@@ -760,14 +808,8 @@ rb_ca_flatten (VALUE self)
|
|
|
760
808
|
ca_size_t out_strides[1];
|
|
761
809
|
ca_size_t out_base;
|
|
762
810
|
if (ca_reshape_try_strides(ca, dim, 1, &out_root, out_strides, &out_base)) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
1, dim, out_strides, out_base);
|
|
766
|
-
ca_keep_chain_flags((CArray *) cs, ca);
|
|
767
|
-
obj = ca_wrap_struct(cs);
|
|
768
|
-
rb_ca_set_parent(obj, self);
|
|
769
|
-
CA_WRAPPER_LIFT(obj, self, ca);
|
|
770
|
-
return obj;
|
|
811
|
+
return ca_reshape_folded(self, ca, out_root, 1, dim,
|
|
812
|
+
out_strides, out_base);
|
|
771
813
|
}
|
|
772
814
|
}
|
|
773
815
|
|
|
@@ -847,6 +889,9 @@ Init_ca_obj_refer (void)
|
|
|
847
889
|
/* rb_cCARefer, CA_OBJ_REFER are defined in ruby_carray.c /
|
|
848
890
|
carray_core.c. Build the custom op table and override the
|
|
849
891
|
baseline registration installed by Init_carray_core. */
|
|
892
|
+
ca_fold_sources = st_init_numtable();
|
|
893
|
+
rb_native_mutex_initialize(&ca_fold_lock);
|
|
894
|
+
|
|
850
895
|
ca_refer_func = ca_stride_func;
|
|
851
896
|
ca_refer_func.free_object = free_ca_refer;
|
|
852
897
|
ca_refer_func.clone = ca_refer_func_clone;
|
data/ext/ca_obj_remap.c
CHANGED
|
@@ -304,8 +304,9 @@ ca_remap_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
|
304
304
|
|
|
305
305
|
paddrs = ALLOCV_N(ca_size_t, holder, n);
|
|
306
306
|
ca_xfer_addrs(ca->idx, n, addrs, paddrs, CA_XFER_GET);
|
|
307
|
-
/* idx is read
|
|
308
|
-
|
|
307
|
+
/* idx is read-only once the view holds it, but its values are still
|
|
308
|
+
checked on every transfer (the private without_read_only_flag can
|
|
309
|
+
lift the flag): negative counts from the end, out of range raises
|
|
309
310
|
before the parent is touched. */
|
|
310
311
|
for ( i = 0; i < n; i++ ) {
|
|
311
312
|
CA_CHECK_INDEX(paddrs[i], ca->parent->elements);
|
|
@@ -366,9 +367,19 @@ ca_remap_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
366
367
|
ALLOCV_END(holder);
|
|
367
368
|
}
|
|
368
369
|
|
|
369
|
-
/* xfer_all: whole-view delivery.
|
|
370
|
-
|
|
371
|
-
|
|
370
|
+
/* xfer_all: whole-view delivery. The whole view reads every cell of idx
|
|
371
|
+
in order, so when idx holds its cells in memory those cells are the
|
|
372
|
+
parent addresses: they are checked in one pass, a negative one counting
|
|
373
|
+
from the end of the parent.
|
|
374
|
+
|
|
375
|
+
idx itself is handed to the parent only when the parent holds its cells
|
|
376
|
+
in memory and shares no root with idx: that transfer is a plain copy, so
|
|
377
|
+
no Ruby runs while the parent reads the list and a scatter cannot
|
|
378
|
+
rewrite it. Any other parent (a view, a CAObject whose hooks run Ruby)
|
|
379
|
+
gets a copy of the addresses taken in the checking pass, so nothing it
|
|
380
|
+
does can change an address after it was checked, or change idx.
|
|
381
|
+
Without idx in memory, the sequential view-flat addresses [0..elements)
|
|
382
|
+
go through xfer_addrs.
|
|
372
383
|
|
|
373
384
|
No ca_attach(parent) / ca_attach(idx). */
|
|
374
385
|
static void
|
|
@@ -382,6 +393,46 @@ ca_remap_func_xfer_all (void *ap, void *data, int dir)
|
|
|
382
393
|
|
|
383
394
|
if ( n == 0 ) return;
|
|
384
395
|
|
|
396
|
+
if ( ca->idx->ptr ) {
|
|
397
|
+
ca_size_t *iaddrs = (ca_size_t *) ca->idx->ptr;
|
|
398
|
+
ca_size_t pn = ca->parent->elements;
|
|
399
|
+
ca_size_t *paddrs;
|
|
400
|
+
|
|
401
|
+
if ( ca->parent->ptr && ! ca_shares_root(ca->parent, ca->idx) ) {
|
|
402
|
+
int lendable = 1;
|
|
403
|
+
for ( i = 0; i < n; i++ ) {
|
|
404
|
+
ca_size_t a = iaddrs[i];
|
|
405
|
+
if ( a < 0 ) {
|
|
406
|
+
lendable = 0;
|
|
407
|
+
a += pn;
|
|
408
|
+
}
|
|
409
|
+
if ( a < 0 || a >= pn ) {
|
|
410
|
+
ca_index_out_of_range(iaddrs[i], pn, "index");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if ( lendable ) {
|
|
414
|
+
ca_xfer_addrs(ca->parent, n, iaddrs, data, dir);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
paddrs = ALLOCV_N(ca_size_t, holder, n);
|
|
420
|
+
for ( i = 0; i < n; i++ ) {
|
|
421
|
+
ca_size_t a = iaddrs[i];
|
|
422
|
+
if ( a < 0 ) {
|
|
423
|
+
a += pn;
|
|
424
|
+
}
|
|
425
|
+
if ( a < 0 || a >= pn ) {
|
|
426
|
+
ALLOCV_END(holder);
|
|
427
|
+
ca_index_out_of_range(iaddrs[i], pn, "index");
|
|
428
|
+
}
|
|
429
|
+
paddrs[i] = a;
|
|
430
|
+
}
|
|
431
|
+
ca_xfer_addrs(ca->parent, n, paddrs, data, dir);
|
|
432
|
+
ALLOCV_END(holder);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
|
|
385
436
|
vaddrs = ALLOCV_N(ca_size_t, holder, n);
|
|
386
437
|
for ( i = 0; i < n; i++ ) vaddrs[i] = i;
|
|
387
438
|
ca_remap_func_xfer_addrs(ca, n, vaddrs, data, dir);
|
|
@@ -417,7 +468,13 @@ ca_operation_function_t ca_remap_func = {
|
|
|
417
468
|
carray_partition.c). Callers are expected to have already checked the
|
|
418
469
|
routing preconditions (same shape, idx data_type == CA_SIZE);
|
|
419
470
|
ca_remap_setup raises ArgumentError on mismatch as a defensive
|
|
420
|
-
fallback.
|
|
471
|
+
fallback.
|
|
472
|
+
|
|
473
|
+
The view takes rmapper over: every caller hands a fresh array no one
|
|
474
|
+
else holds, and it is marked read-only here, so the mapping a view was
|
|
475
|
+
made with cannot be rewritten through #mapper. CAGrid and CASelect
|
|
476
|
+
keep their indices where Ruby cannot reach them; this is the same
|
|
477
|
+
promise for an index array that stays visible. */
|
|
421
478
|
VALUE
|
|
422
479
|
rb_ca_remap_new (VALUE cary, VALUE rmapper)
|
|
423
480
|
{
|
|
@@ -437,13 +494,14 @@ rb_ca_remap_new (VALUE cary, VALUE rmapper)
|
|
|
437
494
|
covers the view's. ca->idx is a raw pointer into idx's struct;
|
|
438
495
|
keeping rmapper reachable through the view keeps it alive. */
|
|
439
496
|
rb_ivar_set(obj, rb_intern("remap_idx"), rmapper);
|
|
497
|
+
rb_ca_set_read_only_flag(rmapper);
|
|
440
498
|
return obj;
|
|
441
499
|
}
|
|
442
500
|
|
|
443
|
-
/*
|
|
444
|
-
|
|
445
|
-
copy of mapper taken at the call, so a later change to mapper
|
|
446
|
-
not reach the view. Companion to
|
|
501
|
+
/* Accessor for the per-cell index CArray that defines this CARemap's
|
|
502
|
+
mapping: the array the view reads, itself read-only. For ca[mapper]
|
|
503
|
+
it is a copy of mapper taken at the call, so a later change to mapper
|
|
504
|
+
does not reach the view. Companion to
|
|
447
505
|
CABlock#start / CAStride#strides / CAWindow#count etc. — the view
|
|
448
506
|
hierarchy is preserved so each named view class exposes its own
|
|
449
507
|
defining semantic state. */
|
|
@@ -526,6 +584,7 @@ Init_ca_obj_remap (void)
|
|
|
526
584
|
rb_cCARemapMask,
|
|
527
585
|
&caremap_mask_data_type,
|
|
528
586
|
&ca_remap_func, sizeof(ca_remap_func));
|
|
587
|
+
ca_register_cell_moving_view(CA_OBJ_REMAP);
|
|
529
588
|
|
|
530
589
|
/* Defining semantic state accessor — companion to CABlock#start /
|
|
531
590
|
CAStride#strides / CAWindow#count. The hierarchy-preserving
|
data/ext/ca_obj_roll.c
CHANGED
|
@@ -733,6 +733,7 @@ Init_ca_obj_roll (void)
|
|
|
733
733
|
&caroll_data_type,
|
|
734
734
|
rb_cCARollMask,
|
|
735
735
|
&caroll_mask_data_type, &ca_roll_func, sizeof(ca_roll_func));
|
|
736
|
+
ca_register_cell_moving_view(CA_OBJ_ROLL);
|
|
736
737
|
rb_define_const(rb_cObject, "CA_OBJ_ROLL", INT2NUM(CA_OBJ_ROLL));
|
|
737
738
|
|
|
738
739
|
rb_define_method(rb_cCArray, "roll", rb_ca_roll, -1);
|
data/ext/ca_obj_select.c
CHANGED
|
@@ -205,7 +205,9 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
|
|
|
205
205
|
ca->dim = &(ca->_dim);
|
|
206
206
|
ca->dim[0] = ca->elements;
|
|
207
207
|
|
|
208
|
-
|
|
208
|
+
/* A selection of a scalar is one only while it picks the cell: a scalar
|
|
209
|
+
is one cell along one axis. */
|
|
210
|
+
if ( ca_is_scalar(snapshot) && ca->elements == 1 ) {
|
|
209
211
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
210
212
|
}
|
|
211
213
|
|
|
@@ -668,6 +670,7 @@ rb_cm_initialize_copy (VALUE self, VALUE other)
|
|
|
668
670
|
void
|
|
669
671
|
Init_ca_obj_select (void)
|
|
670
672
|
{
|
|
673
|
+
ca_register_cell_moving_view(CA_OBJ_SELECT);
|
|
671
674
|
/* rb_cCASelect and CA_OBJ_SELECT are defined in ruby_carray.c;
|
|
672
675
|
this file only registers the constant + allocator. */
|
|
673
676
|
rb_define_const(rb_cObject, "CA_OBJ_SELECT", INT2NUM(CA_OBJ_SELECT));
|
data/ext/ca_obj_select_axis.c
CHANGED
|
@@ -1238,6 +1238,7 @@ Init_ca_obj_select_axis (void)
|
|
|
1238
1238
|
rb_cCASelectAxisMask,
|
|
1239
1239
|
&caselectaxis_mask_data_type,
|
|
1240
1240
|
&ca_select_axis_func, sizeof(ca_select_axis_func));
|
|
1241
|
+
ca_register_cell_moving_view(CA_OBJ_SELECT_AXIS);
|
|
1241
1242
|
rb_define_const(rb_cObject, "CA_OBJ_SELECT_AXIS", INT2NUM(CA_OBJ_SELECT_AXIS));
|
|
1242
1243
|
|
|
1243
1244
|
rb_define_alloc_func(rb_cCASelectAxis, rb_ca_select_axis_s_allocate);
|
data/ext/ca_obj_shift.c
CHANGED
|
@@ -363,6 +363,7 @@ Init_ca_obj_shift (void)
|
|
|
363
363
|
&cashift_data_type,
|
|
364
364
|
rb_cCAShiftMask,
|
|
365
365
|
&cashift_mask_data_type, &ca_shift_func, sizeof(ca_shift_func));
|
|
366
|
+
ca_register_cell_moving_view(CA_OBJ_SHIFT);
|
|
366
367
|
rb_define_const(rb_cObject, "CA_OBJ_SHIFT", INT2NUM(CA_OBJ_SHIFT));
|
|
367
368
|
|
|
368
369
|
rb_define_method(rb_cCArray, "shift", rb_ca_shift, -1);
|