carray 3.0.1 → 3.0.3
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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_sort.c
CHANGED
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
#include "ruby.h"
|
|
10
10
|
#include "carray.h"
|
|
11
|
-
#include "ca_for_buffer.h" /*
|
|
11
|
+
#include "ca_for_buffer.h" /* rb_ca_call_with_buffer */
|
|
12
12
|
#include "ca_kernel_iterator.h" /* CA_FOR_EACH_FIBER_INOUT (sort_copy) */
|
|
13
13
|
#include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
|
|
14
14
|
#include "ca_sort_kernels.h" /* ca_sort_quick_* / ca_sort_merge_* / ca_partition_nan_* */
|
|
15
15
|
#include "ca_compare.h" /* ca_elem_cmp[] -- shared element comparators */
|
|
16
|
+
#include "carray_internal.h" /* ca_attach_window */
|
|
16
17
|
#include <math.h>
|
|
17
18
|
#include <float.h>
|
|
18
19
|
|
|
@@ -93,6 +94,40 @@ sort_addr_cmp (struct sort_addr_key *a, struct sort_addr_key *b)
|
|
|
93
94
|
return ( ia > ib ) ? 1 : -1; /* for stable sort */
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
/* An object key compares through <=>, which can raise, and a raise must
|
|
98
|
+
not unwind through libc's mergesort / qsort. Those keys sort with this
|
|
99
|
+
mergesort instead, whose frames hold nothing; the numeric ones keep
|
|
100
|
+
libc's, which their comparisons cannot leave. */
|
|
101
|
+
static void
|
|
102
|
+
sort_addr_merge (struct sort_addr_key *a, struct sort_addr_key *aux,
|
|
103
|
+
ca_size_t n, int (*cmp)(const void *, const void *))
|
|
104
|
+
CA_SORT_MERGE_BY_CMP(struct sort_addr_key)
|
|
105
|
+
|
|
106
|
+
typedef struct {
|
|
107
|
+
struct sort_addr_key *data;
|
|
108
|
+
struct sort_addr_key *aux; /* NULL: no object key, libc sorts */
|
|
109
|
+
ca_size_t elements;
|
|
110
|
+
} sort_addr_run_t;
|
|
111
|
+
|
|
112
|
+
static VALUE
|
|
113
|
+
sort_addr_run (VALUE arg)
|
|
114
|
+
{
|
|
115
|
+
sort_addr_run_t *r = (sort_addr_run_t *) arg;
|
|
116
|
+
if ( r->aux ) {
|
|
117
|
+
sort_addr_merge(r->data, r->aux, r->elements,
|
|
118
|
+
(int (*)(const void*,const void*)) sort_addr_cmp);
|
|
119
|
+
return Qnil;
|
|
120
|
+
}
|
|
121
|
+
#ifdef HAVE_MERGESORT
|
|
122
|
+
mergesort(r->data, r->elements, sizeof(struct sort_addr_key),
|
|
123
|
+
(int (*)(const void*,const void*)) sort_addr_cmp);
|
|
124
|
+
#else
|
|
125
|
+
qsort(r->data, r->elements, sizeof(struct sort_addr_key),
|
|
126
|
+
(int (*)(const void*,const void*)) sort_addr_cmp);
|
|
127
|
+
#endif
|
|
128
|
+
return Qnil;
|
|
129
|
+
}
|
|
130
|
+
|
|
96
131
|
/* CArray.sort_addr(*args, masked_position: :last) — multi-key lex
|
|
97
132
|
* sort. Returns a 1-D CA_SIZE array of indices that sorts the
|
|
98
133
|
* arguments in priority order (a > b > c):
|
|
@@ -104,34 +139,25 @@ sort_addr_cmp (struct sort_addr_key *a, struct sort_addr_key *b)
|
|
|
104
139
|
* an incomparable sentinel clustered at masked_position: (:last
|
|
105
140
|
* default, or :first); ties are broken by original index (stable). */
|
|
106
141
|
static VALUE
|
|
107
|
-
|
|
142
|
+
rb_ca_s_sort_addr_kw (int argc, VALUE *argv, VALUE ropt, VALUE self)
|
|
108
143
|
{
|
|
109
144
|
volatile VALUE out;
|
|
110
145
|
CArray *co;
|
|
111
|
-
struct cmp_base *base;
|
|
146
|
+
struct cmp_base base_s, *base = &base_s;
|
|
112
147
|
struct sort_addr_key *data;
|
|
148
|
+
volatile VALUE hlist = 0, hdata = 0, haux = 0, hmodes = 0;
|
|
149
|
+
sort_addr_run_t run;
|
|
150
|
+
char *modes;
|
|
151
|
+
int has_object = 0;
|
|
113
152
|
ca_size_t elements;
|
|
114
153
|
ca_size_t *q;
|
|
115
154
|
int j;
|
|
116
155
|
ca_size_t i;
|
|
117
156
|
|
|
118
|
-
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
119
157
|
VALUE vmasked_position = Qnil;
|
|
120
158
|
rb_scan_options(ropt, "masked_position", &vmasked_position);
|
|
121
|
-
int masked_last = 1
|
|
122
|
-
|
|
123
|
-
static ID sym_first = 0, sym_last = 0;
|
|
124
|
-
if ( !sym_first ) sym_first = rb_intern("first");
|
|
125
|
-
if ( !sym_last ) sym_last = rb_intern("last");
|
|
126
|
-
ID mp_id = SYM2ID(vmasked_position);
|
|
127
|
-
if ( mp_id == sym_last ) masked_last = 1;
|
|
128
|
-
else if ( mp_id == sym_first ) masked_last = 0;
|
|
129
|
-
else {
|
|
130
|
-
rb_raise(rb_eArgError,
|
|
131
|
-
"sort_addr: unknown masked_position %s (expected :first or :last)",
|
|
132
|
-
rb_id2name(mp_id));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
159
|
+
int masked_last = NIL_P(vmasked_position) ? 1
|
|
160
|
+
: ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
|
|
135
161
|
|
|
136
162
|
if ( argc <= 0 ) {
|
|
137
163
|
rb_raise(rb_eArgError, "no arg given");
|
|
@@ -146,53 +172,68 @@ rb_ca_s_sort_addr (int argc, VALUE *argv, VALUE self)
|
|
|
146
172
|
if ( elements != NUM2SIZE(rb_ca_elements(argv[j])) ) {
|
|
147
173
|
rb_raise(rb_eArgError, "elements mismatch");
|
|
148
174
|
}
|
|
149
|
-
/* Face gate:
|
|
150
|
-
/ template output on
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
175
|
+
/* Face gate: an ORDERABLE Face sorts by its storage, so it descends to
|
|
176
|
+
it (attach / comparator / template output then run on plain storage,
|
|
177
|
+
which also avoids a face-lifted NULL-ptr index output). A fixlen
|
|
178
|
+
storage that is not ORDERABLE (CAConstString's offsets, a record's
|
|
179
|
+
bytes) has no order in its bytes; the Face's own order stands in for
|
|
180
|
+
it, as a dense rank, so ties stay ties for the next key. A Face that
|
|
181
|
+
has no order (CARecord without order_by:) raises there. Any other
|
|
182
|
+
storage raises here. */
|
|
155
183
|
TypedData_Get_Struct(argv[j], CArray, &carray_data_type, ca_j);
|
|
156
184
|
if ( ca_is_face(ca_j) ) {
|
|
157
185
|
int orderable = ca_test_flag(ca_j, CA_FLAG_FACE_ORDERABLE_STORAGE);
|
|
158
186
|
VALUE stripped = rb_ca_strip_face_value(argv[j]);
|
|
159
187
|
CArray *sc;
|
|
160
188
|
TypedData_Get_Struct(stripped, CArray, &carray_data_type, sc);
|
|
161
|
-
if ( sc->data_type
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
189
|
+
if ( sc->data_type == CA_FIXLEN && ! orderable ) {
|
|
190
|
+
VALUE opts = rb_hash_new();
|
|
191
|
+
rb_hash_aset(opts, ID2SYM(rb_intern("method")), ID2SYM(rb_intern("dense")));
|
|
192
|
+
argv[j] = rb_funcallv_kw(argv[j], rb_intern("order"), 1, &opts,
|
|
193
|
+
RB_PASS_KEYWORDS);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if ( ! orderable ) {
|
|
197
|
+
ca_face_refuse_order("sort_addr", argv[j], "order");
|
|
166
198
|
}
|
|
167
199
|
argv[j] = stripped;
|
|
168
200
|
}
|
|
201
|
+
{
|
|
202
|
+
CArray *k;
|
|
203
|
+
TypedData_Get_Struct(argv[j], CArray, &carray_data_type, k);
|
|
204
|
+
if ( ca_is_complex_type(k) ) {
|
|
205
|
+
rb_raise(rb_eCADataTypeError,
|
|
206
|
+
"sort_addr: a %s key has no order (complex numbers are not "
|
|
207
|
+
"ordered); sort by its real part, imaginary part or abs",
|
|
208
|
+
ca_type_name[k->data_type]);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
169
211
|
}
|
|
170
212
|
|
|
171
|
-
|
|
213
|
+
/* Scratch the unwind collects: the keys are read inside an attach
|
|
214
|
+
window, and a comparison of object keys can raise. */
|
|
172
215
|
base->n = argc;
|
|
173
216
|
base->masked_last = masked_last;
|
|
174
|
-
base->ca =
|
|
217
|
+
base->ca = ALLOCV_N(CArray *, hlist, base->n);
|
|
218
|
+
modes = ALLOCV_N(char, hmodes, argc + 1);
|
|
175
219
|
|
|
176
220
|
for (j=0; j<argc; j++) {
|
|
177
|
-
CArray
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
ca_attach(ca);
|
|
221
|
+
TypedData_Get_Struct(argv[j], CArray, &carray_data_type, base->ca[j]);
|
|
222
|
+
has_object |= ( base->ca[j]->data_type == CA_OBJECT );
|
|
223
|
+
modes[j] = 'r';
|
|
181
224
|
}
|
|
225
|
+
modes[argc] = '\0';
|
|
182
226
|
|
|
183
|
-
data =
|
|
227
|
+
data = ALLOCV_N(struct sort_addr_key, hdata, elements);
|
|
184
228
|
for (i=0; i<elements; i++) {
|
|
185
229
|
data[i].i = i;
|
|
186
230
|
data[i].base = base;
|
|
187
231
|
}
|
|
188
232
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
qsort(data, elements, sizeof(struct sort_addr_key),
|
|
194
|
-
(int (*)(const void*,const void*)) sort_addr_cmp);
|
|
195
|
-
#endif
|
|
233
|
+
run.data = data;
|
|
234
|
+
run.aux = has_object ? ALLOCV_N(struct sort_addr_key, haux, elements) : NULL;
|
|
235
|
+
run.elements = elements;
|
|
236
|
+
ca_attach_window(argc, base->ca, modes, sort_addr_run, (VALUE) &run);
|
|
196
237
|
|
|
197
238
|
out = rb_ca_template_with_type(argv[0], INT2NUM(CA_SIZE), INT2NUM(0));
|
|
198
239
|
TypedData_Get_Struct(out, CArray, &carray_data_type, co);
|
|
@@ -203,27 +244,26 @@ rb_ca_s_sort_addr (int argc, VALUE *argv, VALUE self)
|
|
|
203
244
|
q++;
|
|
204
245
|
}
|
|
205
246
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
xfree(data);
|
|
211
|
-
xfree(base->ca);
|
|
212
|
-
xfree(base);
|
|
247
|
+
ALLOCV_END(haux);
|
|
248
|
+
ALLOCV_END(hdata);
|
|
249
|
+
ALLOCV_END(hmodes);
|
|
250
|
+
ALLOCV_END(hlist);
|
|
213
251
|
|
|
214
252
|
return out;
|
|
215
253
|
}
|
|
216
254
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
255
|
+
static VALUE
|
|
256
|
+
rb_ca_s_sort_addr (int argc, VALUE *argv, VALUE self)
|
|
257
|
+
{
|
|
258
|
+
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
259
|
+
return rb_ca_s_sort_addr_kw(argc, argv, ropt, self);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Internal sort_addr kernel entries (C-level only, no Ruby binding;
|
|
263
|
+
* defined in the generated carray_kernels_sort.c). The _quick and
|
|
264
|
+
* _stable variants implement the kind: dispatch; both take an explicit
|
|
265
|
+
* masked_last so `sort` / `sort_copy` can pass the masked_position:
|
|
266
|
+
* kwarg through (see MkKernel.sort in mkkernel.rb). */
|
|
227
267
|
extern VALUE rb_ca_sort_addr_ki_quick_mp (VALUE self, VALUE vaxis, int masked_last);
|
|
228
268
|
extern VALUE rb_ca_sort_addr_ki_stable_mp (VALUE self, VALUE vaxis, int masked_last);
|
|
229
269
|
extern VALUE rb_ca_remap_new (VALUE cary, VALUE rmapper); /* ca_obj_remap.c (sort view) */
|
|
@@ -274,16 +314,12 @@ rb_ca_sort_addr_c (VALUE self, VALUE axis, int stable, int masked_last)
|
|
|
274
314
|
if ( NIL_P(axis) ) {
|
|
275
315
|
/* Legacy flat: equivalent to CArray.sort_addr(self, masked_position:).
|
|
276
316
|
kind: ignored for now (the flat path uses qsort/mergesort
|
|
277
|
-
internally).
|
|
278
|
-
|
|
279
|
-
type-checks the last positional arg, not rb_keyword_given_p), so
|
|
280
|
-
this raw C call is safe unlike the rb_scan_args "1:" pattern used
|
|
281
|
-
elsewhere in this file. */
|
|
282
|
-
VALUE kw = rb_hash_new();
|
|
317
|
+
internally). */
|
|
318
|
+
volatile VALUE kw = rb_hash_new();
|
|
283
319
|
rb_hash_aset(kw, ID2SYM(rb_intern("masked_position")),
|
|
284
320
|
masked_last ? ID2SYM(rb_intern("last")) : ID2SYM(rb_intern("first")));
|
|
285
|
-
VALUE flat_argv[
|
|
286
|
-
return
|
|
321
|
+
VALUE flat_argv[1] = { self };
|
|
322
|
+
return rb_ca_s_sort_addr_kw(1, flat_argv, kw, rb_cCArray);
|
|
287
323
|
}
|
|
288
324
|
return stable ? rb_ca_sort_addr_ki_stable_mp(self, axis, masked_last)
|
|
289
325
|
: rb_ca_sort_addr_ki_quick_mp (self, axis, masked_last);
|
|
@@ -302,35 +338,11 @@ rb_ca_sort_addr (int argc, VALUE *argv, VALUE self)
|
|
|
302
338
|
rb_scan_args(argc, argv, "0:", &opts);
|
|
303
339
|
rb_scan_options(opts, "axis,kind,masked_position", &axis, &kind, &vmasked_position);
|
|
304
340
|
|
|
305
|
-
int do_stable = 0
|
|
306
|
-
|
|
307
|
-
static ID sym_quick = 0, sym_stable = 0;
|
|
308
|
-
if ( ! sym_quick ) sym_quick = rb_intern("quick");
|
|
309
|
-
if ( ! sym_stable ) sym_stable = rb_intern("stable");
|
|
310
|
-
ID kind_id = SYM2ID(kind);
|
|
311
|
-
if ( kind_id == sym_quick ) do_stable = 0;
|
|
312
|
-
else if ( kind_id == sym_stable ) do_stable = 1;
|
|
313
|
-
else {
|
|
314
|
-
rb_raise(rb_eArgError,
|
|
315
|
-
"sort_addr: unknown kind %s (expected :quick or :stable)",
|
|
316
|
-
rb_id2name(kind_id));
|
|
317
|
-
}
|
|
318
|
-
}
|
|
341
|
+
int do_stable = NIL_P(kind) ? 0
|
|
342
|
+
: ca_symbol_choice(kind, "kind", "quick", "stable", NULL);
|
|
319
343
|
|
|
320
|
-
int masked_last = 1
|
|
321
|
-
|
|
322
|
-
static ID sym_first = 0, sym_last = 0;
|
|
323
|
-
if ( !sym_first ) sym_first = rb_intern("first");
|
|
324
|
-
if ( !sym_last ) sym_last = rb_intern("last");
|
|
325
|
-
ID mp_id = SYM2ID(vmasked_position);
|
|
326
|
-
if ( mp_id == sym_last ) masked_last = 1;
|
|
327
|
-
else if ( mp_id == sym_first ) masked_last = 0;
|
|
328
|
-
else {
|
|
329
|
-
rb_raise(rb_eArgError,
|
|
330
|
-
"sort_addr: unknown masked_position %s (expected :first or :last)",
|
|
331
|
-
rb_id2name(mp_id));
|
|
332
|
-
}
|
|
333
|
-
}
|
|
344
|
+
int masked_last = NIL_P(vmasked_position) ? 1
|
|
345
|
+
: ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
|
|
334
346
|
|
|
335
347
|
return rb_ca_sort_addr_c(self, axis, do_stable, masked_last);
|
|
336
348
|
}
|
|
@@ -362,12 +374,58 @@ rb_ca_sort_addr (int argc, VALUE *argv, VALUE self)
|
|
|
362
374
|
*
|
|
363
375
|
* indices data_type: any integer kind (zero-copy if already CA_SIZE).
|
|
364
376
|
* Negative indices: Python-style (-1 = last), normalized internally.
|
|
365
|
-
* OOB indices: raises
|
|
377
|
+
* OOB indices: raises IndexError. Default axis: 0; negative axis
|
|
366
378
|
* Python-style.
|
|
367
379
|
*
|
|
368
380
|
* Returns: CArray of CA_SIZE, same shape as indices.
|
|
369
381
|
*/
|
|
370
382
|
|
|
383
|
+
typedef struct {
|
|
384
|
+
CArray *idx_ca;
|
|
385
|
+
ca_size_t *out_ptr;
|
|
386
|
+
ca_size_t *strides;
|
|
387
|
+
int axis;
|
|
388
|
+
ca_size_t axis_size;
|
|
389
|
+
boolean8_t *mask; /* the indices' mask, or NULL */
|
|
390
|
+
} axis2addr_ctx_t;
|
|
391
|
+
|
|
392
|
+
/* Body of rb_ca_axis2addr_c: one flat address per index cell. */
|
|
393
|
+
static void
|
|
394
|
+
axis2addr_body (void *user_data, void *ptr, ca_size_t n)
|
|
395
|
+
{
|
|
396
|
+
axis2addr_ctx_t *c = (axis2addr_ctx_t *) user_data;
|
|
397
|
+
ca_size_t *idx_ptr = (ca_size_t *) ptr;
|
|
398
|
+
int ndim = c->idx_ca->ndim;
|
|
399
|
+
ca_size_t coord[CA_RANK_MAX];
|
|
400
|
+
|
|
401
|
+
for ( int8_t j = 0; j < ndim; j++ ) coord[j] = 0;
|
|
402
|
+
for ( ca_size_t k = 0; k < n; k++ ) {
|
|
403
|
+
/* A masked index has no address: the cell keeps the mask (copied from
|
|
404
|
+
the indices) and is skipped here, its stored value unread. */
|
|
405
|
+
if ( c->mask && c->mask[k] ) {
|
|
406
|
+
c->out_ptr[k] = 0;
|
|
407
|
+
goto advance;
|
|
408
|
+
}
|
|
409
|
+
ca_size_t norm = ca_index_in_range(idx_ptr[k], c->axis_size, "index");
|
|
410
|
+
/* Compute flat addr: sum c_j * stride_j (with c_axis = norm). */
|
|
411
|
+
ca_size_t addr = 0;
|
|
412
|
+
for ( int8_t j = 0; j < ndim; j++ ) {
|
|
413
|
+
if ( j == c->axis ) {
|
|
414
|
+
addr += norm * c->strides[j];
|
|
415
|
+
} else {
|
|
416
|
+
addr += coord[j] * c->strides[j];
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
c->out_ptr[k] = addr;
|
|
420
|
+
advance:
|
|
421
|
+
/* Advance coord row-major (last axis ticks fastest). */
|
|
422
|
+
for ( int8_t j = (int8_t)(ndim - 1); j >= 0; j-- ) {
|
|
423
|
+
if ( ++coord[j] < c->idx_ca->dim[j] ) break;
|
|
424
|
+
coord[j] = 0;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
371
429
|
/* C-callable entry: skip rb_scan_args (call-frame state dependency).
|
|
372
430
|
* vaxis = Qnil treated as axis 0; Integer is taken as-is (negative
|
|
373
431
|
* axis normalized internally).
|
|
@@ -385,27 +443,27 @@ rb_ca_axis2addr_c (VALUE self, VALUE vindices, VALUE vaxis)
|
|
|
385
443
|
TypedData_Get_Struct(vindices, CArray, &carray_data_type, idx_ca);
|
|
386
444
|
|
|
387
445
|
/* axis normalization + range check. */
|
|
388
|
-
int axis_raw = NIL_P(vaxis) ? 0 :
|
|
446
|
+
int axis_raw = NIL_P(vaxis) ? 0 : (int) ca_axis_integer(vaxis, NULL);
|
|
389
447
|
int axis = (axis_raw < 0) ? ((int) ca->ndim + axis_raw) : axis_raw;
|
|
390
448
|
if ( axis < 0 || axis >= ca->ndim ) {
|
|
391
|
-
rb_raise(
|
|
392
|
-
"
|
|
393
|
-
axis_raw, (int) ca->ndim);
|
|
449
|
+
rb_raise(rb_eArgError,
|
|
450
|
+
"%s: axis %d out of range for ndim %d",
|
|
451
|
+
ca_calling_method_name(), axis_raw, (int) ca->ndim);
|
|
394
452
|
}
|
|
395
453
|
|
|
396
454
|
/* Shape rule: indices.ndim == self.ndim, dims match except at axis. */
|
|
397
455
|
if ( idx_ca->ndim != ca->ndim ) {
|
|
398
456
|
rb_raise(rb_eArgError,
|
|
399
|
-
"
|
|
400
|
-
(int) idx_ca->ndim, (int) ca->ndim);
|
|
457
|
+
"%s: indices.ndim (%d) must equal self.ndim (%d)",
|
|
458
|
+
ca_calling_method_name(), (int) idx_ca->ndim, (int) ca->ndim);
|
|
401
459
|
}
|
|
402
460
|
for ( int8_t j = 0; j < ca->ndim; j++ ) {
|
|
403
461
|
if ( j == axis ) continue;
|
|
404
462
|
if ( idx_ca->dim[j] != ca->dim[j] ) {
|
|
405
463
|
rb_raise(rb_eArgError,
|
|
406
|
-
"
|
|
464
|
+
"%s: indices.dim[%d] (%lld) must equal "
|
|
407
465
|
"self.dim[%d] (%lld)",
|
|
408
|
-
(int) j, (long long) idx_ca->dim[j],
|
|
466
|
+
ca_calling_method_name(), (int) j, (long long) idx_ca->dim[j],
|
|
409
467
|
(int) j, (long long) ca->dim[j]);
|
|
410
468
|
}
|
|
411
469
|
}
|
|
@@ -414,8 +472,8 @@ rb_ca_axis2addr_c (VALUE self, VALUE vindices, VALUE vaxis)
|
|
|
414
472
|
(zero-copy when already CA_SIZE via to_type identity). */
|
|
415
473
|
if ( ! ca_is_integer_type(idx_ca) ) {
|
|
416
474
|
rb_raise(rb_eArgError,
|
|
417
|
-
"
|
|
418
|
-
(int) idx_ca->data_type);
|
|
475
|
+
"%s: indices data_type must be integer kind (got %d)",
|
|
476
|
+
ca_calling_method_name(), (int) idx_ca->data_type);
|
|
419
477
|
}
|
|
420
478
|
volatile VALUE vidx_cast = vindices;
|
|
421
479
|
CArray *idx_cast = idx_ca;
|
|
@@ -439,59 +497,26 @@ rb_ca_axis2addr_c (VALUE self, VALUE vindices, VALUE vaxis)
|
|
|
439
497
|
rb_ca_template_with_type(vidx_cast, INT2NUM(CA_SIZE), INT2NUM(0));
|
|
440
498
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, out_ca);
|
|
441
499
|
|
|
442
|
-
/* out_ca is a freshly allocated entity
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
ca_size_t n;
|
|
461
|
-
CA_WITH_BUFFER(idx_cast, ca_size_t, idx_ptr, n) {
|
|
462
|
-
for ( int8_t j = 0; j < ndim; j++ ) coord[j] = 0;
|
|
463
|
-
for ( ca_size_t k = 0; k < n; k++ ) {
|
|
464
|
-
/* Negative normalize + OOB check (raises on out-of-bounds). */
|
|
465
|
-
ca_size_t raw = idx_ptr[k];
|
|
466
|
-
ca_size_t norm = (raw < 0) ? (raw + axis_size) : raw;
|
|
467
|
-
if ( norm < 0 || norm >= axis_size ) {
|
|
468
|
-
bad_k = k; bad_raw = raw;
|
|
469
|
-
break;
|
|
470
|
-
}
|
|
471
|
-
/* Compute flat addr: sum c_j * stride_j (with c_axis = norm). */
|
|
472
|
-
ca_size_t addr = 0;
|
|
473
|
-
for ( int8_t j = 0; j < ndim; j++ ) {
|
|
474
|
-
if ( j == axis ) {
|
|
475
|
-
addr += norm * strides[j];
|
|
476
|
-
} else {
|
|
477
|
-
addr += coord[j] * strides[j];
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
out_ptr[k] = addr;
|
|
481
|
-
/* Advance coord row-major (last axis ticks fastest). */
|
|
482
|
-
for ( int8_t j = (int8_t)(ndim - 1); j >= 0; j-- ) {
|
|
483
|
-
if ( ++coord[j] < idx_cast->dim[j] ) break;
|
|
484
|
-
coord[j] = 0;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
if ( bad_k >= 0 ) {
|
|
490
|
-
rb_raise(rb_eRangeError,
|
|
491
|
-
"axis2addr: indices[%lld] = %lld out of range [0, %lld) "
|
|
492
|
-
"(after negative normalize)",
|
|
493
|
-
(long long) bad_k, (long long) bad_raw, (long long) axis_size);
|
|
500
|
+
/* out_ca is a freshly allocated entity of the indices' shape and cell
|
|
501
|
+
width, so the indices are copied into it (a view is gathered without
|
|
502
|
+
being attached) and turned into addresses in place: cell k is read
|
|
503
|
+
before it is written. */
|
|
504
|
+
axis2addr_ctx_t ctx;
|
|
505
|
+
ctx.idx_ca = idx_cast;
|
|
506
|
+
ctx.out_ptr = (ca_size_t *) out_ca->ptr;
|
|
507
|
+
ctx.strides = strides;
|
|
508
|
+
ctx.axis = axis;
|
|
509
|
+
ctx.axis_size = axis_size;
|
|
510
|
+
ctx.mask = NULL;
|
|
511
|
+
|
|
512
|
+
ca_copy_data(idx_cast, out_ca->ptr);
|
|
513
|
+
/* A masked index gives a masked address: readers propagate it (UNDEF in
|
|
514
|
+
that cell), writers skip it. */
|
|
515
|
+
if ( ca_has_mask(idx_cast) ) {
|
|
516
|
+
ca_copy_mask_overlay(out_ca, out_ca->elements, 1, idx_cast);
|
|
517
|
+
ctx.mask = (boolean8_t *) out_ca->mask->ptr;
|
|
494
518
|
}
|
|
519
|
+
axis2addr_body(&ctx, out_ca->ptr, out_ca->elements);
|
|
495
520
|
|
|
496
521
|
return vout;
|
|
497
522
|
}
|
|
@@ -548,50 +573,24 @@ rb_ca_axis2addr (int argc, VALUE *argv, VALUE self)
|
|
|
548
573
|
* numeric, both no-axis and axis: forms.
|
|
549
574
|
*/
|
|
550
575
|
static VALUE
|
|
551
|
-
|
|
576
|
+
rb_ca_sorted_view_kw (VALUE rkw, VALUE self)
|
|
552
577
|
{
|
|
553
|
-
VALUE rkw = Qnil;
|
|
554
578
|
VALUE vaxis = Qnil;
|
|
555
579
|
VALUE vkind = Qnil;
|
|
556
580
|
VALUE vmasked_position = Qnil;
|
|
557
581
|
|
|
558
|
-
/*
|
|
559
|
-
rb_scan_args(argc, argv, "0:", &rkw);
|
|
582
|
+
/* `sort` accepts `axis:`, `kind:`, `masked_position:`. */
|
|
560
583
|
rb_scan_options(rkw, "axis,kind,masked_position", &vaxis, &vkind, &vmasked_position);
|
|
561
584
|
|
|
562
585
|
/* Resolve kind: -> do_stable. :quick (default) = introsort; :stable
|
|
563
586
|
= bottom-up mergesort. Both share the same pair layout and produce
|
|
564
587
|
identical orderings; only the algorithm differs. */
|
|
565
|
-
int do_stable = 0
|
|
566
|
-
|
|
567
|
-
static ID sym_quick = 0, sym_stable = 0;
|
|
568
|
-
if ( !sym_quick ) sym_quick = rb_intern("quick");
|
|
569
|
-
if ( !sym_stable ) sym_stable = rb_intern("stable");
|
|
570
|
-
ID kind_id = SYM2ID(vkind);
|
|
571
|
-
if ( kind_id == sym_quick ) do_stable = 0;
|
|
572
|
-
else if ( kind_id == sym_stable ) do_stable = 1;
|
|
573
|
-
else {
|
|
574
|
-
rb_raise(rb_eArgError,
|
|
575
|
-
"sort: unknown kind %s (expected :quick or :stable)",
|
|
576
|
-
rb_id2name(kind_id));
|
|
577
|
-
}
|
|
578
|
-
}
|
|
588
|
+
int do_stable = NIL_P(vkind) ? 0
|
|
589
|
+
: ca_symbol_choice(vkind, "kind", "quick", "stable", NULL);
|
|
579
590
|
|
|
580
591
|
/* Resolve masked_position: -> masked_last. :last (default) or :first. */
|
|
581
|
-
int masked_last = 1
|
|
582
|
-
|
|
583
|
-
static ID sym_first = 0, sym_last = 0;
|
|
584
|
-
if ( !sym_first ) sym_first = rb_intern("first");
|
|
585
|
-
if ( !sym_last ) sym_last = rb_intern("last");
|
|
586
|
-
ID mp_id = SYM2ID(vmasked_position);
|
|
587
|
-
if ( mp_id == sym_last ) masked_last = 1;
|
|
588
|
-
else if ( mp_id == sym_first ) masked_last = 0;
|
|
589
|
-
else {
|
|
590
|
-
rb_raise(rb_eArgError,
|
|
591
|
-
"sort: unknown masked_position %s (expected :first or :last)",
|
|
592
|
-
rb_id2name(mp_id));
|
|
593
|
-
}
|
|
594
|
-
}
|
|
592
|
+
int masked_last = NIL_P(vmasked_position) ? 1
|
|
593
|
+
: ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
|
|
595
594
|
|
|
596
595
|
CArray *ca;
|
|
597
596
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -600,7 +599,7 @@ rb_ca_sorted_view (int argc, VALUE *argv, VALUE self)
|
|
|
600
599
|
before mask handling: rb_ca_flatten re-propagates the mask field
|
|
601
600
|
from the parent, so any mask stripping must happen on the post-
|
|
602
601
|
flatten target. */
|
|
603
|
-
VALUE target;
|
|
602
|
+
volatile VALUE target; /* cat points into it; the walk can run a GC */
|
|
604
603
|
VALUE vaxis_use;
|
|
605
604
|
if ( NIL_P(vaxis) ) {
|
|
606
605
|
target = rb_ca_flatten(self);
|
|
@@ -628,6 +627,14 @@ rb_ca_sorted_view (int argc, VALUE *argv, VALUE self)
|
|
|
628
627
|
}
|
|
629
628
|
}
|
|
630
629
|
|
|
630
|
+
static VALUE
|
|
631
|
+
rb_ca_sorted_view (int argc, VALUE *argv, VALUE self)
|
|
632
|
+
{
|
|
633
|
+
VALUE rkw = Qnil;
|
|
634
|
+
rb_scan_args(argc, argv, "0:", &rkw);
|
|
635
|
+
return rb_ca_sorted_view_kw(rkw, self);
|
|
636
|
+
}
|
|
637
|
+
|
|
631
638
|
/* sort_copy(axis: nil, kind: :quick, masked_position: :last) — eager
|
|
632
639
|
* counterpart to {sort}. Returns a fresh entity CArray of the same
|
|
633
640
|
* shape and data_type as self, with elements sorted along the given
|
|
@@ -639,12 +646,20 @@ rb_ca_sorted_view (int argc, VALUE *argv, VALUE self)
|
|
|
639
646
|
* fiber, no pair struct, no view layer. This fast path is numeric-only
|
|
640
647
|
* and mask-free (CA_KERNEL_NO_MASK below).
|
|
641
648
|
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
649
|
+
* Everything the fast path does not cover -- any data_type outside
|
|
650
|
+
* CA_INT8..CA_FLOAT64 (fixlen, boolean, complex, object), and masked
|
|
651
|
+
* input of any type -- delegates to {sort} + copy rather than duplicate
|
|
652
|
+
* the fixlen dialect / the object comparator / the mask-position split
|
|
653
|
+
* in this per-fiber loop; masked_position: is forwarded unchanged.
|
|
654
|
+
* Masked cells keep their masked-ness (the view's remap gather carries
|
|
655
|
+
* the mask bit through, and .copy materializes it), clustered at
|
|
656
|
+
* masked_position: within each fiber -- same contract as {sort}.
|
|
657
|
+
*
|
|
658
|
+
* So sort_copy answers for exactly what sort answers for, which is what
|
|
659
|
+
* being its eager counterpart means. It once refused everything the
|
|
660
|
+
* fast path could not take: object and boolean sorted through {sort}
|
|
661
|
+
* but not through this, and complex reported its refusal in two
|
|
662
|
+
* different ways depending on which of the pair was asked.
|
|
648
663
|
*/
|
|
649
664
|
static VALUE
|
|
650
665
|
rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
@@ -659,36 +674,28 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
659
674
|
|
|
660
675
|
/* Resolve kind:: :quick (default) = portable textbook quicksort,
|
|
661
676
|
:stable = portable textbook bottom-up mergesort. */
|
|
662
|
-
int do_stable = 0
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
if ( kind_id == sym_quick ) do_stable = 0;
|
|
669
|
-
else if ( kind_id == sym_stable ) do_stable = 1;
|
|
670
|
-
else {
|
|
671
|
-
rb_raise(rb_eArgError,
|
|
672
|
-
"sort_copy: unknown kind %s (expected :quick or :stable)",
|
|
673
|
-
rb_id2name(kind_id));
|
|
674
|
-
}
|
|
677
|
+
int do_stable = NIL_P(vkind) ? 0
|
|
678
|
+
: ca_symbol_choice(vkind, "kind", "quick", "stable", NULL);
|
|
679
|
+
/* The unmasked path below has no use for masked_position:, but a value
|
|
680
|
+
sort would refuse is refused here too. */
|
|
681
|
+
if ( ! NIL_P(vmasked_position) ) {
|
|
682
|
+
ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
|
|
675
683
|
}
|
|
676
684
|
|
|
677
685
|
CArray *ca;
|
|
678
686
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
679
687
|
|
|
680
|
-
/*
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
if (
|
|
685
|
-
|
|
688
|
+
/* The per-fiber path below covers unmasked CA_INT8..CA_FLOAT64 only.
|
|
689
|
+
Everything else goes to {sort} (which handles the fixlen dialect,
|
|
690
|
+
the object comparator and the masked_position split) + copy, for the
|
|
691
|
+
same shape/class contract as the fast path. */
|
|
692
|
+
if ( ca->data_type < CA_INT8 || ca->data_type > CA_FLOAT64
|
|
693
|
+
|| ca_has_mask(ca) ) {
|
|
694
|
+
volatile VALUE sv_kw = rb_hash_new();
|
|
686
695
|
if ( !NIL_P(vaxis) ) rb_hash_aset(sv_kw, ID2SYM(rb_intern("axis")), vaxis);
|
|
687
696
|
if ( !NIL_P(vkind) ) rb_hash_aset(sv_kw, ID2SYM(rb_intern("kind")), vkind);
|
|
688
697
|
if ( !NIL_P(vmasked_position) ) rb_hash_aset(sv_kw, ID2SYM(rb_intern("masked_position")), vmasked_position);
|
|
689
|
-
VALUE
|
|
690
|
-
int sv_argc = ( NIL_P(vaxis) && NIL_P(vkind) && NIL_P(vmasked_position) ) ? 0 : 1;
|
|
691
|
-
VALUE obj = rb_ca_copy(rb_ca_sorted_view(sv_argc, sv_argv, self));
|
|
698
|
+
VALUE obj = rb_ca_copy(rb_ca_sorted_view_kw(sv_kw, self));
|
|
692
699
|
CA_FACE_LIFT_IF_FACE(obj, self, ca);
|
|
693
700
|
return obj;
|
|
694
701
|
}
|
|
@@ -696,7 +703,7 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
696
703
|
/* Build target view (flatten for no-arg, identity for axis: kwarg).
|
|
697
704
|
Unmasked past this point (guarded above), so no mask handling is
|
|
698
705
|
needed here -- see the analogous block in rb_ca_sorted_view. */
|
|
699
|
-
VALUE target;
|
|
706
|
+
volatile VALUE target; /* cat points into it; the walk can run a GC */
|
|
700
707
|
VALUE vaxis_use;
|
|
701
708
|
if ( NIL_P(vaxis) ) {
|
|
702
709
|
target = rb_ca_flatten(self);
|
|
@@ -710,23 +717,8 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
710
717
|
TypedData_Get_Struct(target, CArray, &carray_data_type, cat);
|
|
711
718
|
|
|
712
719
|
/* Normalize axis (negative -> +ndim, range check). */
|
|
713
|
-
int axis =
|
|
714
|
-
|
|
715
|
-
if ( axis < 0 || axis >= cat->ndim ) {
|
|
716
|
-
rb_raise(rb_eArgError, "sort_copy: axis %d out of range for ndim %d",
|
|
717
|
-
NUM2INT(vaxis_use), cat->ndim);
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/* data_type check: ALL_NUMERIC only (CA_INT8..CA_FLOAT64).
|
|
721
|
-
Complex / object are rejected here; CA_OBJECT goes through the
|
|
722
|
-
axis: lift in rb_ca_sorted_view, and complex sort semantics
|
|
723
|
-
differ enough that we do not pick a default. */
|
|
724
|
-
if ( cat->data_type < CA_INT8 || cat->data_type > CA_FLOAT64 ) {
|
|
725
|
-
rb_raise(rb_eCADataTypeError,
|
|
726
|
-
"sort_copy: data_type %d not supported "
|
|
727
|
-
"(expected one of: i8, u8, i16, u16, i32, u32, i64, u64, f32, f64)",
|
|
728
|
-
cat->data_type);
|
|
729
|
-
}
|
|
720
|
+
int axis = rb_ca_normalize_axis_for_ndim(ca_axis_integer(vaxis_use, NULL),
|
|
721
|
+
cat->ndim, NULL);
|
|
730
722
|
|
|
731
723
|
/* Allocate output: same shape and data_type as target
|
|
732
724
|
(bytes=0 = preserve native bytes). */
|
|
@@ -751,8 +743,10 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
751
743
|
the fiber loop and reused across fibers (all fibers share the
|
|
752
744
|
same axis length and data_type). */
|
|
753
745
|
void *aux = NULL;
|
|
746
|
+
volatile VALUE aux_holder = 0; /* 0, not Qnil: ALLOCV_END reads a non-zero holder */
|
|
754
747
|
if ( do_stable ) {
|
|
755
|
-
aux =
|
|
748
|
+
aux = ALLOCV_N(char, aux_holder,
|
|
749
|
+
(size_t) cat->dim[axis] * (size_t) bytes);
|
|
756
750
|
}
|
|
757
751
|
CA_FOR_EACH_FIBER_INOUT(st_in, st_out, cat, cao, (int8_t) axis,
|
|
758
752
|
CA_KERNEL_NO_MASK, pi, po, n) {
|
|
@@ -808,8 +802,9 @@ rb_ca_sort_copy (int argc, VALUE *argv, VALUE self)
|
|
|
808
802
|
}
|
|
809
803
|
}
|
|
810
804
|
}
|
|
811
|
-
|
|
805
|
+
ALLOCV_END(aux_holder);
|
|
812
806
|
|
|
807
|
+
RB_GC_GUARD(target);
|
|
813
808
|
return vout;
|
|
814
809
|
}
|
|
815
810
|
|