carray 3.0.2 → 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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- 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 +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- 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 +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -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 +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -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 +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- 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 +149 -27
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +102 -79
- data/ext/ca_sweep_engine.h +7 -20
- 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 +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- 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 +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- 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 +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- 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 +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- 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 +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- 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/factorize.rb +2 -2
- 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 +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/record_order.rb +208 -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 +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- 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 +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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_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 +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- 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 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -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 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_factorize.c
CHANGED
|
@@ -102,15 +102,113 @@
|
|
|
102
102
|
discovery surface rather than this gate (see
|
|
103
103
|
devel/PROPOSAL_DISCOVERY_FAMILY_FACE_GATE.md §4). */
|
|
104
104
|
|
|
105
|
+
/* The value-hash family decides whether two cells hold the same value: every
|
|
106
|
+
NaN is one value, and -0.0 is the same value as +0.0. A float cell's key
|
|
107
|
+
is the bytes of its canonical form (one NaN, +0.0 for a zero), so equal
|
|
108
|
+
values have equal keys; fz_canonical_* writes that form back as a value. */
|
|
109
|
+
#define FZ_NAN_KEY_DOUBLE 0x7ff8000000000000ULL
|
|
110
|
+
#define FZ_NAN_KEY_FLOAT 0x7fc00000UL
|
|
111
|
+
|
|
112
|
+
static inline uint64_t
|
|
113
|
+
fz_key_double (double v)
|
|
114
|
+
{
|
|
115
|
+
uint64_t b;
|
|
116
|
+
if ( v != v ) return FZ_NAN_KEY_DOUBLE;
|
|
117
|
+
if ( v == 0.0 ) v = 0.0;
|
|
118
|
+
memcpy(&b, &v, sizeof(b));
|
|
119
|
+
return b;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static inline uint64_t
|
|
123
|
+
fz_key_float (float v)
|
|
124
|
+
{
|
|
125
|
+
uint32_t b;
|
|
126
|
+
if ( v != v ) return FZ_NAN_KEY_FLOAT;
|
|
127
|
+
if ( v == 0.0f ) v = 0.0f;
|
|
128
|
+
memcpy(&b, &v, sizeof(b));
|
|
129
|
+
return (uint64_t) b;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static inline double
|
|
133
|
+
fz_canonical_double (double v)
|
|
134
|
+
{
|
|
135
|
+
uint64_t b = fz_key_double(v);
|
|
136
|
+
memcpy(&v, &b, sizeof(v));
|
|
137
|
+
return v;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static inline float
|
|
141
|
+
fz_canonical_float (float v)
|
|
142
|
+
{
|
|
143
|
+
uint32_t b = (uint32_t) fz_key_float(v);
|
|
144
|
+
memcpy(&v, &b, sizeof(v));
|
|
145
|
+
return v;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* For the kernel macros, which take the cell type T. */
|
|
149
|
+
#define FZ_FLOAT_KEY(T, v) \
|
|
150
|
+
_Generic((T) 0, float: fz_key_float, double: fz_key_double)(v)
|
|
151
|
+
|
|
152
|
+
/* A complex array as hash keys: its cells as fixlen blobs of the same
|
|
153
|
+
width, each component written so that equal values have equal bytes
|
|
154
|
+
(-0.0 as 0.0, every NaN as one NaN), with the mask kept. The fixlen lane
|
|
155
|
+
then answers equality for complex values. */
|
|
156
|
+
static VALUE
|
|
157
|
+
fz_complex_key (VALUE self)
|
|
158
|
+
{
|
|
159
|
+
volatile VALUE out;
|
|
160
|
+
CArray *ca, *co;
|
|
161
|
+
ca_size_t i, n;
|
|
162
|
+
GetCArray(self, ca);
|
|
163
|
+
out = rb_carray_new(CA_FIXLEN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
164
|
+
GetCArray(out, co);
|
|
165
|
+
ca_copy_data(ca, co->ptr);
|
|
166
|
+
n = 2 * ca->elements;
|
|
167
|
+
if ( ca->data_type == CA_CMPLX128 ) {
|
|
168
|
+
double *p = (double *) co->ptr;
|
|
169
|
+
for ( i = 0; i < n; i++ ) p[i] = fz_canonical_double(p[i]);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
float *p = (float *) co->ptr;
|
|
173
|
+
for ( i = 0; i < n; i++ ) p[i] = fz_canonical_float(p[i]);
|
|
174
|
+
}
|
|
175
|
+
if ( ca_has_mask(ca) ) {
|
|
176
|
+
ca_copy_mask(co, ca);
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* The members whose output carries no values (a mask, a count) read a
|
|
182
|
+
complex array through its keys and need nothing back. */
|
|
183
|
+
static VALUE
|
|
184
|
+
fz_complex_as_key (VALUE self)
|
|
185
|
+
{
|
|
186
|
+
CArray *ca;
|
|
187
|
+
GetCArray(self, ca);
|
|
188
|
+
if ( ! ca_is_face(ca) && ca_is_complex_type(ca) ) {
|
|
189
|
+
return fz_complex_key(self);
|
|
190
|
+
}
|
|
191
|
+
return self;
|
|
192
|
+
}
|
|
193
|
+
|
|
105
194
|
/* Descend `self` when it is an ORDERABLE Face; *pface keeps the pre-strip Face
|
|
106
|
-
for the re-lift (Qnil when there is nothing to put back).
|
|
195
|
+
for the re-lift (Qnil when there is nothing to put back). A complex array
|
|
196
|
+
is turned into hash keys (fz_complex_key) and *pface keeps it, so the
|
|
197
|
+
re-lift reads the values back as complex. */
|
|
107
198
|
static VALUE
|
|
108
199
|
fz_face_descend (VALUE self, volatile VALUE *pface, const char *name)
|
|
109
200
|
{
|
|
110
201
|
CArray *ca;
|
|
111
202
|
GetCArray(self, ca);
|
|
203
|
+
if ( ! ca_is_face(ca) && ca_is_complex_type(ca) ) {
|
|
204
|
+
*pface = self;
|
|
205
|
+
return fz_complex_key(self);
|
|
206
|
+
}
|
|
112
207
|
if ( ca_is_face(ca) ) {
|
|
113
|
-
|
|
208
|
+
/* A record is its bytes: two records are the same value exactly when
|
|
209
|
+
their bytes are, so the fixlen lane answers for it. */
|
|
210
|
+
if ( ca_test_flag(ca, CA_FLAG_FACE_ORDERABLE_STORAGE)
|
|
211
|
+
|| ca->obj_type == CA_OBJ_RECORD ) {
|
|
114
212
|
*pface = self;
|
|
115
213
|
return rb_ca_strip_face_value(self);
|
|
116
214
|
}
|
|
@@ -123,23 +221,18 @@ fz_face_descend (VALUE self, volatile VALUE *pface, const char *name)
|
|
|
123
221
|
argument. */
|
|
124
222
|
rb_raise(rb_eArgError,
|
|
125
223
|
"%s: %s is not orderable by storage (a cell encodes the value "
|
|
126
|
-
"rather than being it); convert it first --
|
|
127
|
-
"
|
|
128
|
-
name, rb_obj_classname(self));
|
|
224
|
+
"rather than being it); convert it first -- %s -- or pass "
|
|
225
|
+
".parent to work in storage space",
|
|
226
|
+
name, rb_obj_classname(self), ca_face_conversion_hint(self));
|
|
129
227
|
}
|
|
130
228
|
*pface = Qnil;
|
|
131
229
|
return self;
|
|
132
230
|
}
|
|
133
231
|
|
|
134
232
|
/* Bring `operand` into the space of `reference` (the *pre-strip* Face) and
|
|
135
|
-
descend it, so both sides hash in one storage space
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
space for the same value -- so a reference that defines it reconciles any
|
|
139
|
-
operand type through it (and refuses what it cannot convert, which is how a
|
|
140
|
-
bare storage number stays out). A reference with one space only (COMPARABLE,
|
|
141
|
-
or a Face with no unit algebra at all, e.g. CAString) has nothing to
|
|
142
|
-
reconcile between: descending both sides is the whole job. */
|
|
233
|
+
descend it, so both sides hash in one storage space
|
|
234
|
+
(ca_face_reconcile_operand). A complex reference instead turns the
|
|
235
|
+
operand into keys of its own complex type. */
|
|
143
236
|
static VALUE
|
|
144
237
|
fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
145
238
|
{
|
|
@@ -148,22 +241,37 @@ fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
|
148
241
|
return operand;
|
|
149
242
|
}
|
|
150
243
|
GetCArray(reference, ca);
|
|
151
|
-
if ( !
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
244
|
+
if ( ! ca_is_face(ca) ) {
|
|
245
|
+
/* A complex reference: the operand becomes keys of the same kind, in the
|
|
246
|
+
reference's complex type. */
|
|
247
|
+
CArray *op;
|
|
248
|
+
if ( ! rb_obj_is_carray(operand) ) {
|
|
249
|
+
return operand;
|
|
250
|
+
}
|
|
251
|
+
GetCArray(operand, op);
|
|
252
|
+
if ( op->data_type != ca->data_type ) {
|
|
253
|
+
operand = rb_ca_to_type(operand, INT2NUM(ca->data_type), Qnil);
|
|
254
|
+
}
|
|
255
|
+
return fz_complex_key(operand);
|
|
156
256
|
}
|
|
157
|
-
return
|
|
257
|
+
return ca_face_reconcile_operand(reference, operand, name);
|
|
158
258
|
}
|
|
159
259
|
|
|
160
|
-
/* Put the Face back on a value-carrying output
|
|
260
|
+
/* Put the Face back on a value-carrying output, or read complex keys back
|
|
261
|
+
as complex values. */
|
|
161
262
|
static VALUE
|
|
162
263
|
fz_face_relift (VALUE out, VALUE face)
|
|
163
264
|
{
|
|
265
|
+
CArray *cf, *co;
|
|
164
266
|
if ( NIL_P(face) ) {
|
|
165
267
|
return out;
|
|
166
268
|
}
|
|
269
|
+
GetCArray(face, cf);
|
|
270
|
+
if ( ! ca_is_face(cf) ) {
|
|
271
|
+
GetCArray(out, co);
|
|
272
|
+
return rb_ca_copy(rb_ca_refer_new(out, cf->data_type, co->ndim, co->dim,
|
|
273
|
+
cf->bytes, 0));
|
|
274
|
+
}
|
|
167
275
|
return ca_face_lift(out, face);
|
|
168
276
|
}
|
|
169
277
|
|
|
@@ -176,16 +284,95 @@ typedef struct {
|
|
|
176
284
|
VALUE *val; /* object lane only: the interned VALUE, kept for an eql? re-check
|
|
177
285
|
on a hash collision (NULL in the numeric lane, where the widened
|
|
178
286
|
key is lossless so a key match already proves value equality).
|
|
179
|
-
|
|
180
|
-
|
|
287
|
+
A receiver that computes its cells (a CAObject, a lazy
|
|
288
|
+
expression) hands each fiber over in a scratch that is refilled,
|
|
289
|
+
so the owner marks this array (fz_tmp_values). */
|
|
181
290
|
char *raw; /* fixlen lane only: cap*esz bytes, the interned element bytes kept
|
|
182
291
|
for a memcmp re-check on a hash collision (NULL otherwise). */
|
|
183
292
|
int esz; /* fixlen lane: element width in bytes (0 otherwise) */
|
|
293
|
+
int has_val; /* object lane: val is kept (0 otherwise) */
|
|
184
294
|
ca_size_t cap; /* power of two */
|
|
185
295
|
ca_size_t n; /* distinct keys interned so far */
|
|
186
296
|
int shift; /* 64 - log2(cap); the home slot is the top log2(cap) bits */
|
|
297
|
+
VALUE hbuf; /* owner of the tables, one block (fz_tmp_alloc) */
|
|
187
298
|
} fz_hash;
|
|
188
299
|
|
|
300
|
+
/* The tables live in buffers owned by hidden Ruby objects rather than bare
|
|
301
|
+
xmalloc. The object lane calls #hash and #eql? for every cell, and a raise
|
|
302
|
+
there leaves the tables with nothing to free them; the owner is reclaimed
|
|
303
|
+
by the GC once the frame holding it is gone, and frees its buffer then.
|
|
304
|
+
An owner whose buffer keeps VALUEs (fz_tmp_values) marks them: the object
|
|
305
|
+
lane's cells come from a scratch the walk refills, not only from the
|
|
306
|
+
receiver, so nothing else holds the ones already interned. */
|
|
307
|
+
typedef struct {
|
|
308
|
+
char *buf;
|
|
309
|
+
ca_size_t voff; /* byte offset of the VALUE run in buf */
|
|
310
|
+
ca_size_t nvals; /* VALUEs in the run (0: nothing to mark) */
|
|
311
|
+
} fz_buffer;
|
|
312
|
+
|
|
313
|
+
static void
|
|
314
|
+
fz_buffer_mark (void *ptr)
|
|
315
|
+
{
|
|
316
|
+
fz_buffer *b = (fz_buffer *) ptr;
|
|
317
|
+
if ( b->buf && b->nvals > 0 ) {
|
|
318
|
+
VALUE *v = (VALUE *) (b->buf + b->voff);
|
|
319
|
+
ca_size_t i;
|
|
320
|
+
for ( i = 0; i < b->nvals; i++ ) rb_gc_mark(v[i]);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
static void
|
|
325
|
+
fz_buffer_free (void *ptr)
|
|
326
|
+
{
|
|
327
|
+
fz_buffer *b = (fz_buffer *) ptr;
|
|
328
|
+
xfree(b->buf);
|
|
329
|
+
xfree(b);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
static const rb_data_type_t fz_buffer_type = {
|
|
333
|
+
"carray_factorize_buffer",
|
|
334
|
+
{ fz_buffer_mark, fz_buffer_free, NULL, },
|
|
335
|
+
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY,
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
static void *
|
|
339
|
+
fz_tmp_alloc (VALUE *store, size_t bytes)
|
|
340
|
+
{
|
|
341
|
+
fz_buffer *b;
|
|
342
|
+
*store = TypedData_Make_Struct(0, fz_buffer, &fz_buffer_type, b);
|
|
343
|
+
b->buf = (char *) xmalloc(bytes);
|
|
344
|
+
return b->buf;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
static void *
|
|
348
|
+
fz_tmp_realloc (VALUE store, size_t bytes)
|
|
349
|
+
{
|
|
350
|
+
fz_buffer *b = (fz_buffer *) DATA_PTR(store);
|
|
351
|
+
b->buf = (char *) xrealloc(b->buf, bytes);
|
|
352
|
+
return b->buf;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* Mark the n VALUEs at vals (inside store's buffer); they must be valid. */
|
|
356
|
+
static void
|
|
357
|
+
fz_tmp_values (VALUE store, void *vals, ca_size_t n)
|
|
358
|
+
{
|
|
359
|
+
fz_buffer *b = (fz_buffer *) DATA_PTR(store);
|
|
360
|
+
b->voff = (ca_size_t) ((char *) vals - b->buf);
|
|
361
|
+
b->nvals = n;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
static void
|
|
365
|
+
fz_tmp_free (VALUE *store)
|
|
366
|
+
{
|
|
367
|
+
if ( *store ) {
|
|
368
|
+
fz_buffer *b = (fz_buffer *) DATA_PTR(*store);
|
|
369
|
+
b->nvals = 0;
|
|
370
|
+
xfree(b->buf);
|
|
371
|
+
b->buf = NULL;
|
|
372
|
+
*store = 0;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
189
376
|
/* Multiplicative hashing (Knuth, TAOCP vol. 3 sec. 6.4): multiply by
|
|
190
377
|
2^64 / golden-ratio and take the TOP log2(cap) bits of the product -- the
|
|
191
378
|
high bits are where a multiply mixes best (the low bits carry little
|
|
@@ -195,19 +382,49 @@ typedef struct {
|
|
|
195
382
|
#define FZ_GOLDEN 0x9E3779B97F4A7C15ULL
|
|
196
383
|
#define FZ_HOME(h, key) ((ca_size_t) (((uint64_t)(key) * FZ_GOLDEN) >> (h)->shift))
|
|
197
384
|
|
|
385
|
+
/* Points the tables of h at one new block for cap slots: key, then the
|
|
386
|
+
object lane's val, code, used, and the fixlen lane's raw bytes. */
|
|
198
387
|
static void
|
|
199
|
-
|
|
388
|
+
fz_hash_alloc (fz_hash *h, ca_size_t cap)
|
|
389
|
+
{
|
|
390
|
+
int has_val = h->has_val;
|
|
391
|
+
size_t nkey = sizeof(uint64_t) * (size_t) cap;
|
|
392
|
+
size_t nval = has_val ? sizeof(VALUE) * (size_t) cap : 0;
|
|
393
|
+
size_t ncode = sizeof(int32_t) * (size_t) cap;
|
|
394
|
+
size_t nused = sizeof(uint8_t) * (size_t) cap;
|
|
395
|
+
size_t nraw = (size_t) cap * (size_t) h->esz;
|
|
396
|
+
char *b = fz_tmp_alloc(&h->hbuf, nkey + nval + ncode + nused + nraw);
|
|
397
|
+
h->key = (uint64_t *) b; b += nkey;
|
|
398
|
+
h->val = has_val ? (VALUE *) b : NULL; b += nval;
|
|
399
|
+
h->code = (int32_t *) b; b += ncode;
|
|
400
|
+
h->used = (uint8_t *) b; b += nused;
|
|
401
|
+
h->raw = h->esz ? b : NULL;
|
|
402
|
+
h->cap = cap;
|
|
403
|
+
MEMZERO(h->used, uint8_t, cap);
|
|
404
|
+
if ( has_val ) {
|
|
405
|
+
ca_size_t i;
|
|
406
|
+
for ( i = 0; i < cap; i++ ) h->val[i] = Qnil;
|
|
407
|
+
fz_tmp_values(h->hbuf, h->val, cap);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* has_val: the object lane (a slot keeps its VALUE); esz > 0: the fixlen
|
|
412
|
+
lane (a slot keeps esz bytes). */
|
|
413
|
+
static void
|
|
414
|
+
fz_hash_setup (fz_hash *h, int has_val, int esz)
|
|
200
415
|
{
|
|
201
|
-
h->cap = 1024;
|
|
202
416
|
h->shift = 64 - 10; /* log2(1024) = 10 */
|
|
203
417
|
h->n = 0;
|
|
204
|
-
h->
|
|
205
|
-
h->
|
|
206
|
-
h->
|
|
207
|
-
h
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
418
|
+
h->hbuf = 0;
|
|
419
|
+
h->has_val = has_val;
|
|
420
|
+
h->esz = esz;
|
|
421
|
+
fz_hash_alloc(h, 1024);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
static void
|
|
425
|
+
fz_hash_init (fz_hash *h)
|
|
426
|
+
{
|
|
427
|
+
fz_hash_setup(h, 0, 0); /* numeric lane: no re-check needed */
|
|
211
428
|
}
|
|
212
429
|
|
|
213
430
|
/* Object lane: the widened key is `rb_hash` (lossy), so a slot also stores the
|
|
@@ -216,8 +433,7 @@ fz_hash_init (fz_hash *h)
|
|
|
216
433
|
static void
|
|
217
434
|
fz_hash_init_obj (fz_hash *h)
|
|
218
435
|
{
|
|
219
|
-
|
|
220
|
-
h->val = ALLOC_N(VALUE, h->cap);
|
|
436
|
+
fz_hash_setup(h, 1, 0);
|
|
221
437
|
}
|
|
222
438
|
|
|
223
439
|
/* Fixlen lane: the key is a byte-hash of the esz-wide element (lossy), so a slot
|
|
@@ -227,19 +443,18 @@ fz_hash_init_obj (fz_hash *h)
|
|
|
227
443
|
static void
|
|
228
444
|
fz_hash_init_mem (fz_hash *h, int esz)
|
|
229
445
|
{
|
|
230
|
-
|
|
231
|
-
h->esz = esz;
|
|
232
|
-
h->raw = ALLOC_N(char, h->cap * esz);
|
|
446
|
+
fz_hash_setup(h, 0, esz);
|
|
233
447
|
}
|
|
234
448
|
|
|
235
449
|
static void
|
|
236
450
|
fz_hash_free (fz_hash *h)
|
|
237
451
|
{
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
452
|
+
fz_tmp_free(&h->hbuf);
|
|
453
|
+
h->key = NULL;
|
|
454
|
+
h->code = NULL;
|
|
455
|
+
h->used = NULL;
|
|
456
|
+
h->val = NULL;
|
|
457
|
+
h->raw = NULL;
|
|
243
458
|
}
|
|
244
459
|
|
|
245
460
|
/* FNV-1a over esz bytes: a lossy 64-bit key for the fixlen lane. */
|
|
@@ -272,14 +487,10 @@ fz_hash_grow (fz_hash *h)
|
|
|
272
487
|
VALUE *ov = h->val;
|
|
273
488
|
char *orw = h->raw;
|
|
274
489
|
int esz = h->esz;
|
|
275
|
-
h->
|
|
276
|
-
h->
|
|
277
|
-
h->
|
|
278
|
-
h
|
|
279
|
-
h->used = ALLOC_N(uint8_t, newcap);
|
|
280
|
-
if ( ov ) { h->val = ALLOC_N(VALUE, newcap); }
|
|
281
|
-
if ( orw ) { h->raw = ALLOC_N(char, newcap * esz); }
|
|
282
|
-
MEMZERO(h->used, uint8_t, newcap);
|
|
490
|
+
VALUE hold = h->hbuf; /* keeps the old block until it is freed below */
|
|
491
|
+
h->hbuf = 0;
|
|
492
|
+
h->shift -= 1; /* log2(cap) grew by one */
|
|
493
|
+
fz_hash_alloc(h, newcap);
|
|
283
494
|
ca_size_t mask = newcap - 1;
|
|
284
495
|
for ( ca_size_t s = 0; s < oldcap; s++ ) {
|
|
285
496
|
if ( ! ou[s] ) { continue; }
|
|
@@ -291,9 +502,7 @@ fz_hash_grow (fz_hash *h)
|
|
|
291
502
|
if ( ov ) { h->val[slot] = ov[s]; }
|
|
292
503
|
if ( orw ) { memcpy(h->raw + slot * esz, orw + s * esz, esz); }
|
|
293
504
|
}
|
|
294
|
-
|
|
295
|
-
if ( ov ) { xfree(ov); }
|
|
296
|
-
if ( orw ) { xfree(orw); }
|
|
505
|
+
fz_tmp_free(&hold);
|
|
297
506
|
}
|
|
298
507
|
|
|
299
508
|
/* True when v is a Float holding NaN (any bit pattern). */
|
|
@@ -315,7 +524,7 @@ fz_hash_intern_obj (fz_hash *h, VALUE v, int *is_new)
|
|
|
315
524
|
{
|
|
316
525
|
if ( (h->n + 1) * 10 >= h->cap * 7 ) { fz_hash_grow(h); } /* load factor 0.7 */
|
|
317
526
|
int v_nan = fz_is_float_nan(v);
|
|
318
|
-
uint64_t key = v_nan ?
|
|
527
|
+
uint64_t key = v_nan ? FZ_NAN_KEY_DOUBLE
|
|
319
528
|
: (uint64_t) NUM2LL(rb_hash(v));
|
|
320
529
|
ca_size_t mask = h->cap - 1;
|
|
321
530
|
ca_size_t slot = FZ_HOME(h, key);
|
|
@@ -413,7 +622,7 @@ static int
|
|
|
413
622
|
fz_hash_lookup_obj (fz_hash *h, VALUE v, int32_t *code_out)
|
|
414
623
|
{
|
|
415
624
|
int v_nan = fz_is_float_nan(v);
|
|
416
|
-
uint64_t key = v_nan ?
|
|
625
|
+
uint64_t key = v_nan ? FZ_NAN_KEY_DOUBLE
|
|
417
626
|
: (uint64_t) NUM2LL(rb_hash(v));
|
|
418
627
|
ca_size_t mask = h->cap - 1;
|
|
419
628
|
ca_size_t slot = FZ_HOME(h, key);
|
|
@@ -452,23 +661,44 @@ typedef struct {
|
|
|
452
661
|
ca_size_t cap; /* capacity in elements */
|
|
453
662
|
ca_size_t n; /* elements stored */
|
|
454
663
|
int esz; /* element bytes */
|
|
664
|
+
VALUE hp; /* owner of p (see fz_tmp_alloc) */
|
|
665
|
+
int obj; /* p holds VALUEs, marked by hp */
|
|
455
666
|
} fz_levels;
|
|
456
667
|
|
|
668
|
+
/* Fill the VALUE slots from..cap with Qnil and mark all cap of them. */
|
|
457
669
|
static void
|
|
458
|
-
|
|
670
|
+
fz_levels_values (fz_levels *l, ca_size_t from)
|
|
671
|
+
{
|
|
672
|
+
VALUE *v = (VALUE *) l->p;
|
|
673
|
+
ca_size_t i;
|
|
674
|
+
for ( i = from; i < l->cap; i++ ) v[i] = Qnil;
|
|
675
|
+
fz_tmp_values(l->hp, l->p, l->cap);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
static void
|
|
679
|
+
fz_levels_init (fz_levels *l, int esz, int obj)
|
|
459
680
|
{
|
|
460
681
|
l->esz = esz;
|
|
461
682
|
l->cap = 16;
|
|
462
683
|
l->n = 0;
|
|
463
|
-
l->
|
|
684
|
+
l->hp = 0;
|
|
685
|
+
l->obj = obj;
|
|
686
|
+
l->p = fz_tmp_alloc(&l->hp, (size_t) l->cap * esz);
|
|
687
|
+
if ( obj ) {
|
|
688
|
+
fz_levels_values(l, 0);
|
|
689
|
+
}
|
|
464
690
|
}
|
|
465
691
|
|
|
466
692
|
static void
|
|
467
693
|
fz_levels_push (fz_levels *l, const void *e)
|
|
468
694
|
{
|
|
469
695
|
if ( l->n == l->cap ) {
|
|
696
|
+
ca_size_t old = l->cap;
|
|
470
697
|
l->cap <<= 1;
|
|
471
|
-
|
|
698
|
+
l->p = fz_tmp_realloc(l->hp, (size_t) l->cap * l->esz);
|
|
699
|
+
if ( l->obj ) {
|
|
700
|
+
fz_levels_values(l, old);
|
|
701
|
+
}
|
|
472
702
|
}
|
|
473
703
|
memcpy(l->p + l->n * l->esz, e, l->esz);
|
|
474
704
|
l->n++;
|
|
@@ -477,7 +707,35 @@ fz_levels_push (fz_levels *l, const void *e)
|
|
|
477
707
|
static void
|
|
478
708
|
fz_levels_free (fz_levels *l)
|
|
479
709
|
{
|
|
480
|
-
|
|
710
|
+
fz_tmp_free(&l->hp);
|
|
711
|
+
l->p = NULL;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/* ---- the frame a discovery method runs in ---------------------------------
|
|
715
|
+
|
|
716
|
+
The object lane calls #hash and #eql? for every cell, and either can raise
|
|
717
|
+
in the middle of a walk. The walks' states live in this frame, outside the
|
|
718
|
+
method's body, and ca_iter_ensure finishes them however the body leaves;
|
|
719
|
+
the tables have owners the unwind collects (fz_tmp_alloc). Slots 0
|
|
720
|
+
and 1 hold a method's own walks, slot 2 the walk of fz_intern_all. */
|
|
721
|
+
|
|
722
|
+
typedef struct {
|
|
723
|
+
ca_iter_state st[3];
|
|
724
|
+
VALUE self;
|
|
725
|
+
VALUE a;
|
|
726
|
+
VALUE b;
|
|
727
|
+
int i;
|
|
728
|
+
} fz_frame;
|
|
729
|
+
|
|
730
|
+
static VALUE
|
|
731
|
+
fz_run (VALUE (*body)(VALUE), VALUE self, VALUE a, VALUE b, int i)
|
|
732
|
+
{
|
|
733
|
+
fz_frame fr;
|
|
734
|
+
fr.self = self;
|
|
735
|
+
fr.a = a;
|
|
736
|
+
fr.b = b;
|
|
737
|
+
fr.i = i;
|
|
738
|
+
return ca_iter_ensure(3, fr.st, body, (VALUE) &fr);
|
|
481
739
|
}
|
|
482
740
|
|
|
483
741
|
/* @overload __factorize_appearance__
|
|
@@ -497,8 +755,10 @@ fz_levels_free (fz_levels *l)
|
|
|
497
755
|
(row-major flatten) order.
|
|
498
756
|
*/
|
|
499
757
|
static VALUE
|
|
500
|
-
|
|
758
|
+
fz_factorize_appearance_body (VALUE arg)
|
|
501
759
|
{
|
|
760
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
761
|
+
VALUE self = fr->self;
|
|
502
762
|
CArray *ca;
|
|
503
763
|
volatile VALUE face;
|
|
504
764
|
self = fz_face_descend(self, &face, "categorize");
|
|
@@ -532,11 +792,11 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
532
792
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
533
793
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
534
794
|
else { fz_hash_init(&h); }
|
|
535
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
795
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
536
796
|
|
|
537
797
|
int8_t axis = (int8_t) (ca->ndim - 1); /* innermost fiber = row-major flatten */
|
|
538
798
|
|
|
539
|
-
ca_iter_state st_in, st_out;
|
|
799
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
540
800
|
char *p_in, *p_out;
|
|
541
801
|
boolean8_t *m;
|
|
542
802
|
ca_size_t n;
|
|
@@ -558,25 +818,18 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
558
818
|
} while (0)
|
|
559
819
|
|
|
560
820
|
/* Float lane: reproduce `==` with two value-based exceptions matching the
|
|
561
|
-
discovery family -- all NaN collapse to one canonical key (
|
|
821
|
+
discovery family -- all NaN collapse to one canonical key (FZ_FLOAT_KEY),
|
|
562
822
|
and -0.0 == +0.0 (a zero normalizes to +0.0 before the bitwise key). The
|
|
563
823
|
level pushed is the raw first-seen element (an appearance-first NaN / -0.0 is
|
|
564
824
|
kept as-is), so masked source cells store the sentinel. */
|
|
565
|
-
#define FZ_LOOP_FLOAT(T
|
|
825
|
+
#define FZ_LOOP_FLOAT(T) \
|
|
566
826
|
do { \
|
|
567
827
|
const T *ip = (const T *) p_in; \
|
|
568
828
|
uint32_t *op = (uint32_t *) p_out; \
|
|
569
829
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
570
830
|
if ( m && m[i] ) { op[i] = 0xFFFFFFFFu; continue; } \
|
|
571
831
|
T v = ip[i]; \
|
|
572
|
-
uint64_t key;
|
|
573
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
574
|
-
else { \
|
|
575
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
576
|
-
UINT bits; \
|
|
577
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
578
|
-
key = (uint64_t) bits; \
|
|
579
|
-
} \
|
|
832
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
580
833
|
int is_new; \
|
|
581
834
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
582
835
|
if ( is_new ) { fz_levels_push(&lv, &ip[i]); } \
|
|
@@ -615,7 +868,7 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
615
868
|
} \
|
|
616
869
|
} while (0)
|
|
617
870
|
|
|
618
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cu32, axis,
|
|
871
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cu32, axis,
|
|
619
872
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
620
873
|
switch ( dt ) {
|
|
621
874
|
case CA_INT8: FZ_LOOP(int8_t, (int64_t)); break;
|
|
@@ -626,8 +879,8 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
626
879
|
case CA_UINT16: FZ_LOOP(uint16_t, (uint64_t)); break;
|
|
627
880
|
case CA_UINT32: FZ_LOOP(uint32_t, (uint64_t)); break;
|
|
628
881
|
case CA_UINT64: FZ_LOOP(uint64_t, (uint64_t)); break;
|
|
629
|
-
case CA_FLOAT32: FZ_LOOP_FLOAT(float
|
|
630
|
-
case CA_FLOAT64: FZ_LOOP_FLOAT(double
|
|
882
|
+
case CA_FLOAT32: FZ_LOOP_FLOAT(float); break;
|
|
883
|
+
case CA_FLOAT64: FZ_LOOP_FLOAT(double); break;
|
|
631
884
|
case CA_OBJECT: FZ_LOOP_OBJ; break;
|
|
632
885
|
case CA_FIXLEN: FZ_LOOP_MEM; break;
|
|
633
886
|
}
|
|
@@ -686,6 +939,12 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
686
939
|
return rb_ary_new3(2, vcodes, fz_face_relift(vlev, face));
|
|
687
940
|
}
|
|
688
941
|
|
|
942
|
+
static VALUE
|
|
943
|
+
rb_ca_factorize_appearance (VALUE self)
|
|
944
|
+
{
|
|
945
|
+
return fz_run(fz_factorize_appearance_body, self, Qnil, Qnil, 0);
|
|
946
|
+
}
|
|
947
|
+
|
|
689
948
|
/* @overload __mask_duplicates__(axis)
|
|
690
949
|
|
|
691
950
|
INTERNAL (mask_duplicates). Mark each cell whose value duplicates an
|
|
@@ -706,8 +965,11 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
706
965
|
value (so the second and later NaN are duplicates, as in the numeric lane).
|
|
707
966
|
*/
|
|
708
967
|
static VALUE
|
|
709
|
-
|
|
968
|
+
fz_mask_duplicates_body (VALUE arg)
|
|
710
969
|
{
|
|
970
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
971
|
+
VALUE self = fr->self;
|
|
972
|
+
VALUE vaxis = fr->a;
|
|
711
973
|
CArray *ca;
|
|
712
974
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
713
975
|
|
|
@@ -741,7 +1003,7 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
741
1003
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
742
1004
|
else { fz_hash_init(&h); }
|
|
743
1005
|
|
|
744
|
-
ca_iter_state st_in, st_out;
|
|
1006
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
745
1007
|
char *p_in, *p_out;
|
|
746
1008
|
boolean8_t *m;
|
|
747
1009
|
ca_size_t n;
|
|
@@ -764,24 +1026,17 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
764
1026
|
|
|
765
1027
|
/* Float variant: reproduce `==` with two value-based exceptions so the
|
|
766
1028
|
distinct-value judgement matches uniq / the discovery family. All NaN
|
|
767
|
-
collapse to one canonical key (
|
|
1029
|
+
collapse to one canonical key (FZ_FLOAT_KEY), so the second and later
|
|
768
1030
|
NaN in a fiber are duplicates; -0.0 == +0.0, so a zero normalizes to +0.0
|
|
769
1031
|
before the bitwise key. */
|
|
770
|
-
#define MD_LOOP_FLOAT(T
|
|
1032
|
+
#define MD_LOOP_FLOAT(T) \
|
|
771
1033
|
do { \
|
|
772
1034
|
const T *ip = (const T *) p_in; \
|
|
773
1035
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
774
1036
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
775
1037
|
if ( m && m[i] ) { op[i] = 0; continue; } \
|
|
776
1038
|
T v = ip[i]; \
|
|
777
|
-
uint64_t key;
|
|
778
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
779
|
-
else { \
|
|
780
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
781
|
-
UINT bits; \
|
|
782
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
783
|
-
key = (uint64_t) bits; \
|
|
784
|
-
} \
|
|
1039
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
785
1040
|
int is_new; \
|
|
786
1041
|
fz_hash_intern(&h, key, &is_new); \
|
|
787
1042
|
op[i] = is_new ? 0 : 1; \
|
|
@@ -814,7 +1069,7 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
814
1069
|
} \
|
|
815
1070
|
} while (0)
|
|
816
1071
|
|
|
817
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cout, (int8_t) axis,
|
|
1072
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cout, (int8_t) axis,
|
|
818
1073
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
819
1074
|
fz_hash_reset(&h); /* independent seen-set per fiber */
|
|
820
1075
|
switch ( dt ) {
|
|
@@ -826,8 +1081,8 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
826
1081
|
case CA_UINT16: MD_LOOP(uint16_t, (uint64_t)); break;
|
|
827
1082
|
case CA_UINT32: MD_LOOP(uint32_t, (uint64_t)); break;
|
|
828
1083
|
case CA_UINT64: MD_LOOP(uint64_t, (uint64_t)); break;
|
|
829
|
-
case CA_FLOAT32: MD_LOOP_FLOAT(float
|
|
830
|
-
case CA_FLOAT64: MD_LOOP_FLOAT(double
|
|
1084
|
+
case CA_FLOAT32: MD_LOOP_FLOAT(float); break;
|
|
1085
|
+
case CA_FLOAT64: MD_LOOP_FLOAT(double); break;
|
|
831
1086
|
case CA_OBJECT: MD_LOOP_OBJ; break;
|
|
832
1087
|
case CA_FIXLEN: MD_LOOP_MEM; break;
|
|
833
1088
|
}
|
|
@@ -841,6 +1096,12 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
841
1096
|
return vout;
|
|
842
1097
|
}
|
|
843
1098
|
|
|
1099
|
+
static VALUE
|
|
1100
|
+
rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
1101
|
+
{
|
|
1102
|
+
return fz_run(fz_mask_duplicates_body, fz_complex_as_key(self), vaxis, Qnil, 0);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
844
1105
|
/* @overload __unique_flat__
|
|
845
1106
|
|
|
846
1107
|
INTERNAL (CArray#unique). Collect the distinct values of self in
|
|
@@ -865,8 +1126,10 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
865
1126
|
uniform-width binary cells the fixlen seen-set used.
|
|
866
1127
|
*/
|
|
867
1128
|
static VALUE
|
|
868
|
-
|
|
1129
|
+
fz_unique_flat_body (VALUE arg)
|
|
869
1130
|
{
|
|
1131
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1132
|
+
VALUE self = fr->self;
|
|
870
1133
|
CArray *ca;
|
|
871
1134
|
volatile VALUE face;
|
|
872
1135
|
self = fz_face_descend(self, &face, "unique");
|
|
@@ -893,11 +1156,11 @@ rb_ca_unique_flat (VALUE self)
|
|
|
893
1156
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
894
1157
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
895
1158
|
else { fz_hash_init(&h); }
|
|
896
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1159
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
897
1160
|
|
|
898
1161
|
int8_t axis = (int8_t) (ca->ndim - 1); /* innermost fiber; hash not reset =
|
|
899
1162
|
one seen-set over the whole array */
|
|
900
|
-
ca_iter_state st_in;
|
|
1163
|
+
ca_iter_state *st_in = &fr->st[0];
|
|
901
1164
|
char *p_in;
|
|
902
1165
|
boolean8_t *m;
|
|
903
1166
|
ca_size_t n;
|
|
@@ -916,20 +1179,13 @@ rb_ca_unique_flat (VALUE self)
|
|
|
916
1179
|
|
|
917
1180
|
/* Float: NaN collapses to one canonical key; -0.0 / +0.0 share a key. The
|
|
918
1181
|
pushed level is the raw first-seen element. */
|
|
919
|
-
#define UQ_LOOP_FLOAT(T
|
|
1182
|
+
#define UQ_LOOP_FLOAT(T) \
|
|
920
1183
|
do { \
|
|
921
1184
|
const T *ip = (const T *) p_in; \
|
|
922
1185
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
923
1186
|
if ( m && m[i] ) { continue; } \
|
|
924
1187
|
T v = ip[i]; \
|
|
925
|
-
uint64_t key;
|
|
926
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
927
|
-
else { \
|
|
928
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
929
|
-
UINT bits; \
|
|
930
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
931
|
-
key = (uint64_t) bits; \
|
|
932
|
-
} \
|
|
1188
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
933
1189
|
int is_new; \
|
|
934
1190
|
fz_hash_intern(&h, key, &is_new); \
|
|
935
1191
|
if ( is_new ) { fz_levels_push(&lv, &ip[i]); } \
|
|
@@ -964,7 +1220,7 @@ rb_ca_unique_flat (VALUE self)
|
|
|
964
1220
|
} \
|
|
965
1221
|
} while (0)
|
|
966
1222
|
|
|
967
|
-
CA_FOR_EACH_FIBER_MASKED(st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1223
|
+
CA_FOR_EACH_FIBER_MASKED(*st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
968
1224
|
switch ( dt ) {
|
|
969
1225
|
case CA_INT8: UQ_LOOP(int8_t, (int64_t)); break;
|
|
970
1226
|
case CA_INT16: UQ_LOOP(int16_t, (int64_t)); break;
|
|
@@ -974,8 +1230,8 @@ rb_ca_unique_flat (VALUE self)
|
|
|
974
1230
|
case CA_UINT16: UQ_LOOP(uint16_t, (uint64_t)); break;
|
|
975
1231
|
case CA_UINT32: UQ_LOOP(uint32_t, (uint64_t)); break;
|
|
976
1232
|
case CA_UINT64: UQ_LOOP(uint64_t, (uint64_t)); break;
|
|
977
|
-
case CA_FLOAT32: UQ_LOOP_FLOAT(float
|
|
978
|
-
case CA_FLOAT64: UQ_LOOP_FLOAT(double
|
|
1233
|
+
case CA_FLOAT32: UQ_LOOP_FLOAT(float); break;
|
|
1234
|
+
case CA_FLOAT64: UQ_LOOP_FLOAT(double); break;
|
|
979
1235
|
case CA_OBJECT: UQ_LOOP_OBJ; break;
|
|
980
1236
|
case CA_FIXLEN: UQ_LOOP_MEM; break;
|
|
981
1237
|
}
|
|
@@ -1002,6 +1258,12 @@ rb_ca_unique_flat (VALUE self)
|
|
|
1002
1258
|
return fz_face_relift(vlev, face); /* distinct *values*: give the Face back */
|
|
1003
1259
|
}
|
|
1004
1260
|
|
|
1261
|
+
static VALUE
|
|
1262
|
+
rb_ca_unique_flat (VALUE self)
|
|
1263
|
+
{
|
|
1264
|
+
return fz_run(fz_unique_flat_body, self, Qnil, Qnil, 0);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1005
1267
|
/* Intern every non-masked cell of cv into h, one seen-set over the whole array
|
|
1006
1268
|
(the hash is not reset between fibers). When lv is non-NULL, the first-seen
|
|
1007
1269
|
raw element of each distinct value is pushed to it (appearance order), so the
|
|
@@ -1011,11 +1273,10 @@ rb_ca_unique_flat (VALUE self)
|
|
|
1011
1273
|
fixlen byte-hash + memcmp. Used to build the probe set (is_in, set relations)
|
|
1012
1274
|
and to accumulate distinct values (union). */
|
|
1013
1275
|
static void
|
|
1014
|
-
fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
1276
|
+
fz_intern_all (ca_iter_state *st_v, fz_hash *h, CArray *cv, fz_levels *lv)
|
|
1015
1277
|
{
|
|
1016
1278
|
int8_t dt = cv->data_type;
|
|
1017
1279
|
int8_t vaxis = (int8_t) (cv->ndim - 1);
|
|
1018
|
-
ca_iter_state st_v;
|
|
1019
1280
|
char *p_v;
|
|
1020
1281
|
boolean8_t *mv;
|
|
1021
1282
|
ca_size_t nv;
|
|
@@ -1032,20 +1293,13 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1032
1293
|
} \
|
|
1033
1294
|
} while (0)
|
|
1034
1295
|
|
|
1035
|
-
#define FZ_IA_FLOAT(T
|
|
1296
|
+
#define FZ_IA_FLOAT(T) \
|
|
1036
1297
|
do { \
|
|
1037
1298
|
const T *ip = (const T *) p_v; \
|
|
1038
1299
|
for ( ca_size_t i = 0; i < nv; i++ ) { \
|
|
1039
1300
|
if ( mv && mv[i] ) { continue; } \
|
|
1040
1301
|
T v = ip[i]; \
|
|
1041
|
-
uint64_t key;
|
|
1042
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1043
|
-
else { \
|
|
1044
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1045
|
-
UINT bits; \
|
|
1046
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1047
|
-
key = (uint64_t) bits; \
|
|
1048
|
-
} \
|
|
1302
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1049
1303
|
int is_new; \
|
|
1050
1304
|
fz_hash_intern(h, key, &is_new); \
|
|
1051
1305
|
if ( is_new && lv ) { fz_levels_push(lv, &ip[i]); } \
|
|
@@ -1075,7 +1329,7 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1075
1329
|
} \
|
|
1076
1330
|
} while (0)
|
|
1077
1331
|
|
|
1078
|
-
CA_FOR_EACH_FIBER_MASKED(st_v, cv, vaxis, CA_KERNEL_READ, p_v, nv, mv) {
|
|
1332
|
+
CA_FOR_EACH_FIBER_MASKED(*st_v, cv, vaxis, CA_KERNEL_READ, p_v, nv, mv) {
|
|
1079
1333
|
switch ( dt ) {
|
|
1080
1334
|
case CA_INT8: FZ_IA(int8_t, (int64_t)); break;
|
|
1081
1335
|
case CA_INT16: FZ_IA(int16_t, (int64_t)); break;
|
|
@@ -1085,8 +1339,8 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1085
1339
|
case CA_UINT16: FZ_IA(uint16_t, (uint64_t)); break;
|
|
1086
1340
|
case CA_UINT32: FZ_IA(uint32_t, (uint64_t)); break;
|
|
1087
1341
|
case CA_UINT64: FZ_IA(uint64_t, (uint64_t)); break;
|
|
1088
|
-
case CA_FLOAT32: FZ_IA_FLOAT(float
|
|
1089
|
-
case CA_FLOAT64: FZ_IA_FLOAT(double
|
|
1342
|
+
case CA_FLOAT32: FZ_IA_FLOAT(float); break;
|
|
1343
|
+
case CA_FLOAT64: FZ_IA_FLOAT(double); break;
|
|
1090
1344
|
case CA_OBJECT: FZ_IA_OBJ; break;
|
|
1091
1345
|
case CA_FIXLEN: FZ_IA_MEM; break;
|
|
1092
1346
|
}
|
|
@@ -1115,8 +1369,11 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1115
1369
|
fixlen byte equality (byte-hash + memcmp).
|
|
1116
1370
|
*/
|
|
1117
1371
|
static VALUE
|
|
1118
|
-
|
|
1372
|
+
fz_is_in_body (VALUE arg)
|
|
1119
1373
|
{
|
|
1374
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1375
|
+
VALUE self = fr->self;
|
|
1376
|
+
VALUE rvalues = fr->a;
|
|
1120
1377
|
CArray *ca, *cv;
|
|
1121
1378
|
volatile VALUE face;
|
|
1122
1379
|
self = fz_face_descend(self, &face, "is_in");
|
|
@@ -1145,12 +1402,12 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1145
1402
|
GetCArray(rvalues, cv);
|
|
1146
1403
|
if ( cv->data_type != dt ) {
|
|
1147
1404
|
rb_raise(rb_eCADataTypeError,
|
|
1148
|
-
"
|
|
1405
|
+
"is_in: values data type (%s) must match self (%s)",
|
|
1149
1406
|
ca_type_name[cv->data_type], ca_type_name[dt]);
|
|
1150
1407
|
}
|
|
1151
1408
|
if ( dt == CA_FIXLEN && cv->bytes != ca->bytes ) {
|
|
1152
1409
|
rb_raise(rb_eCADataTypeError,
|
|
1153
|
-
"
|
|
1410
|
+
"is_in: a fixlen value is a cell-width blob, so the values "
|
|
1154
1411
|
"must be %ld bytes wide like self, not %ld",
|
|
1155
1412
|
(long) ca->bytes, (long) cv->bytes);
|
|
1156
1413
|
}
|
|
@@ -1164,14 +1421,14 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1164
1421
|
else { fz_hash_init(&h); }
|
|
1165
1422
|
|
|
1166
1423
|
/* ---- Phase 1: build the seen-set from every non-masked cell of `values`. */
|
|
1167
|
-
fz_intern_all(&h, cv, NULL);
|
|
1424
|
+
fz_intern_all(&fr->st[2], &h, cv, NULL);
|
|
1168
1425
|
|
|
1169
1426
|
/* ---- Phase 2: probe every cell of self, writing the boolean membership. */
|
|
1170
1427
|
VALUE vout = rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
1171
1428
|
CArray *cout;
|
|
1172
1429
|
GetCArray(vout, cout);
|
|
1173
1430
|
{
|
|
1174
|
-
ca_iter_state st_in, st_out;
|
|
1431
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
1175
1432
|
char *p_in, *p_out;
|
|
1176
1433
|
boolean8_t *m;
|
|
1177
1434
|
ca_size_t n;
|
|
@@ -1188,21 +1445,14 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1188
1445
|
} \
|
|
1189
1446
|
} while (0)
|
|
1190
1447
|
|
|
1191
|
-
#define IN_PROBE_FLOAT(T
|
|
1448
|
+
#define IN_PROBE_FLOAT(T) \
|
|
1192
1449
|
do { \
|
|
1193
1450
|
const T *ip = (const T *) p_in; \
|
|
1194
1451
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
1195
1452
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1196
1453
|
if ( m && m[i] ) { op[i] = 0; continue; } \
|
|
1197
1454
|
T v = ip[i]; \
|
|
1198
|
-
uint64_t key;
|
|
1199
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1200
|
-
else { \
|
|
1201
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1202
|
-
UINT bits; \
|
|
1203
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1204
|
-
key = (uint64_t) bits; \
|
|
1205
|
-
} \
|
|
1455
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1206
1456
|
op[i] = (boolean8_t) fz_hash_lookup(&h, key, NULL); \
|
|
1207
1457
|
} \
|
|
1208
1458
|
} while (0)
|
|
@@ -1227,7 +1477,7 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1227
1477
|
} \
|
|
1228
1478
|
} while (0)
|
|
1229
1479
|
|
|
1230
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cout, axis,
|
|
1480
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cout, axis,
|
|
1231
1481
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
1232
1482
|
switch ( dt ) {
|
|
1233
1483
|
case CA_INT8: IN_PROBE(int8_t, (int64_t)); break;
|
|
@@ -1238,8 +1488,8 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1238
1488
|
case CA_UINT16: IN_PROBE(uint16_t, (uint64_t)); break;
|
|
1239
1489
|
case CA_UINT32: IN_PROBE(uint32_t, (uint64_t)); break;
|
|
1240
1490
|
case CA_UINT64: IN_PROBE(uint64_t, (uint64_t)); break;
|
|
1241
|
-
case CA_FLOAT32: IN_PROBE_FLOAT(float
|
|
1242
|
-
case CA_FLOAT64: IN_PROBE_FLOAT(double
|
|
1491
|
+
case CA_FLOAT32: IN_PROBE_FLOAT(float); break;
|
|
1492
|
+
case CA_FLOAT64: IN_PROBE_FLOAT(double); break;
|
|
1243
1493
|
case CA_OBJECT: IN_PROBE_OBJ; break;
|
|
1244
1494
|
case CA_FIXLEN: IN_PROBE_MEM; break;
|
|
1245
1495
|
}
|
|
@@ -1259,6 +1509,12 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1259
1509
|
return vout;
|
|
1260
1510
|
}
|
|
1261
1511
|
|
|
1512
|
+
static VALUE
|
|
1513
|
+
rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
1514
|
+
{
|
|
1515
|
+
return fz_run(fz_is_in_body, self, rvalues, Qnil, 0);
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1262
1518
|
/* @overload __locate_addr__(ref)
|
|
1263
1519
|
|
|
1264
1520
|
INTERNAL (CArray#locate_addr, exact hash lane). For each cell of self, the
|
|
@@ -1276,8 +1532,11 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1276
1532
|
appearance order (matching the discovery family); on a `ref` with duplicate
|
|
1277
1533
|
values this is the earliest address, which can differ from the bsearch lane. */
|
|
1278
1534
|
static VALUE
|
|
1279
|
-
|
|
1535
|
+
fz_locate_addr_body (VALUE arg)
|
|
1280
1536
|
{
|
|
1537
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1538
|
+
VALUE self = fr->self;
|
|
1539
|
+
VALUE rref = fr->a;
|
|
1281
1540
|
CArray *ca, *cr;
|
|
1282
1541
|
/* Here the *reference* is the argument (self is the query being placed on
|
|
1283
1542
|
rref), so the gate runs the other way round: rref reconciles self. The
|
|
@@ -1308,9 +1567,16 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1308
1567
|
rb_raise(rb_eArgError, "__locate_addr__: ref must be a CArray");
|
|
1309
1568
|
}
|
|
1310
1569
|
GetCArray(rref, cr);
|
|
1311
|
-
if ( cr->data_type != dt
|
|
1570
|
+
if ( cr->data_type != dt ) {
|
|
1312
1571
|
rb_raise(rb_eCADataTypeError,
|
|
1313
|
-
"
|
|
1572
|
+
"locate_addr: ref data type (%s) must match self (%s)",
|
|
1573
|
+
ca_type_name[cr->data_type], ca_type_name[dt]);
|
|
1574
|
+
}
|
|
1575
|
+
if ( dt == CA_FIXLEN && cr->bytes != ca->bytes ) {
|
|
1576
|
+
rb_raise(rb_eCADataTypeError,
|
|
1577
|
+
"locate_addr: a fixlen value is a cell-width blob, so ref "
|
|
1578
|
+
"must be %ld bytes wide like self, not %ld",
|
|
1579
|
+
(long) ca->bytes, (long) cr->bytes);
|
|
1314
1580
|
}
|
|
1315
1581
|
if ( cr->ndim < 1 ) {
|
|
1316
1582
|
rb_raise(rb_eRuntimeError, "__locate_addr__: ref need ndim >= 1");
|
|
@@ -1325,11 +1591,11 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1325
1591
|
the ref value carrying dense code `code`. Codes are assigned 0,1,2,... in
|
|
1326
1592
|
insertion order, so pushing on is_new fills addr.p in code order. */
|
|
1327
1593
|
fz_levels addr;
|
|
1328
|
-
fz_levels_init(&addr, (int) sizeof(int64_t));
|
|
1594
|
+
fz_levels_init(&addr, (int) sizeof(int64_t), 0);
|
|
1329
1595
|
|
|
1330
1596
|
/* ---- Phase 1: build value -> first-address map from ref (row-major). ----- */
|
|
1331
1597
|
{
|
|
1332
|
-
ca_iter_state st_r;
|
|
1598
|
+
ca_iter_state *st_r = &fr->st[0];
|
|
1333
1599
|
char *p_r;
|
|
1334
1600
|
boolean8_t *mr;
|
|
1335
1601
|
ca_size_t nr;
|
|
@@ -1349,20 +1615,13 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1349
1615
|
} \
|
|
1350
1616
|
} while (0)
|
|
1351
1617
|
|
|
1352
|
-
#define LOC_BUILD_FLOAT(T
|
|
1618
|
+
#define LOC_BUILD_FLOAT(T) \
|
|
1353
1619
|
do { \
|
|
1354
1620
|
const T *ip = (const T *) p_r; \
|
|
1355
1621
|
for ( ca_size_t i = 0; i < nr; i++ ) { \
|
|
1356
1622
|
if ( mr && mr[i] ) { continue; } \
|
|
1357
1623
|
T v = ip[i]; \
|
|
1358
|
-
uint64_t key;
|
|
1359
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1360
|
-
else { \
|
|
1361
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1362
|
-
UINT bits; \
|
|
1363
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1364
|
-
key = (uint64_t) bits; \
|
|
1365
|
-
} \
|
|
1624
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1366
1625
|
int is_new; \
|
|
1367
1626
|
fz_hash_intern(&h, key, &is_new); \
|
|
1368
1627
|
if ( is_new ) { int64_t a = (int64_t) (base + i); \
|
|
@@ -1394,7 +1653,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1394
1653
|
} \
|
|
1395
1654
|
} while (0)
|
|
1396
1655
|
|
|
1397
|
-
CA_FOR_EACH_FIBER_MASKED(st_r, cr, raxis, CA_KERNEL_READ, p_r, nr, mr) {
|
|
1656
|
+
CA_FOR_EACH_FIBER_MASKED(*st_r, cr, raxis, CA_KERNEL_READ, p_r, nr, mr) {
|
|
1398
1657
|
switch ( dt ) {
|
|
1399
1658
|
case CA_INT8: LOC_BUILD(int8_t, (int64_t)); break;
|
|
1400
1659
|
case CA_INT16: LOC_BUILD(int16_t, (int64_t)); break;
|
|
@@ -1404,8 +1663,8 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1404
1663
|
case CA_UINT16: LOC_BUILD(uint16_t, (uint64_t)); break;
|
|
1405
1664
|
case CA_UINT32: LOC_BUILD(uint32_t, (uint64_t)); break;
|
|
1406
1665
|
case CA_UINT64: LOC_BUILD(uint64_t, (uint64_t)); break;
|
|
1407
|
-
case CA_FLOAT32: LOC_BUILD_FLOAT(float
|
|
1408
|
-
case CA_FLOAT64: LOC_BUILD_FLOAT(double
|
|
1666
|
+
case CA_FLOAT32: LOC_BUILD_FLOAT(float); break;
|
|
1667
|
+
case CA_FLOAT64: LOC_BUILD_FLOAT(double); break;
|
|
1409
1668
|
case CA_OBJECT: LOC_BUILD_OBJ; break;
|
|
1410
1669
|
case CA_FIXLEN: LOC_BUILD_MEM; break;
|
|
1411
1670
|
}
|
|
@@ -1422,10 +1681,11 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1422
1681
|
CArray *cout;
|
|
1423
1682
|
GetCArray(vout, cout);
|
|
1424
1683
|
int64_t *out = (int64_t *) cout->ptr;
|
|
1425
|
-
|
|
1684
|
+
volatile VALUE hum = 0;
|
|
1685
|
+
boolean8_t *um = ALLOCV_N(boolean8_t, hum, ca->elements); /* undef flags scratch */
|
|
1426
1686
|
ca_size_t n_undef = 0;
|
|
1427
1687
|
{
|
|
1428
|
-
ca_iter_state st_in;
|
|
1688
|
+
ca_iter_state *st_in = &fr->st[1];
|
|
1429
1689
|
char *p_in;
|
|
1430
1690
|
boolean8_t *m;
|
|
1431
1691
|
ca_size_t n;
|
|
@@ -1446,7 +1706,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1446
1706
|
} \
|
|
1447
1707
|
} while (0)
|
|
1448
1708
|
|
|
1449
|
-
#define LOC_PROBE_FLOAT(T
|
|
1709
|
+
#define LOC_PROBE_FLOAT(T) \
|
|
1450
1710
|
do { \
|
|
1451
1711
|
const T *ip = (const T *) p_in; \
|
|
1452
1712
|
const int64_t *ab = (const int64_t *) addr.p; \
|
|
@@ -1454,14 +1714,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1454
1714
|
ca_size_t o = base + i; \
|
|
1455
1715
|
if ( m && m[i] ) { out[o] = 0; um[o] = 1; n_undef++; continue; } \
|
|
1456
1716
|
T v = ip[i]; \
|
|
1457
|
-
uint64_t key;
|
|
1458
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1459
|
-
else { \
|
|
1460
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1461
|
-
UINT bits; \
|
|
1462
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1463
|
-
key = (uint64_t) bits; \
|
|
1464
|
-
} \
|
|
1717
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1465
1718
|
int32_t code; \
|
|
1466
1719
|
if ( fz_hash_lookup(&h, key, &code) ) { out[o] = ab[code]; um[o] = 0; } \
|
|
1467
1720
|
else { out[o] = 0; um[o] = 1; n_undef++; } \
|
|
@@ -1494,7 +1747,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1494
1747
|
} \
|
|
1495
1748
|
} while (0)
|
|
1496
1749
|
|
|
1497
|
-
CA_FOR_EACH_FIBER_MASKED(st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1750
|
+
CA_FOR_EACH_FIBER_MASKED(*st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1498
1751
|
switch ( dt ) {
|
|
1499
1752
|
case CA_INT8: LOC_PROBE(int8_t, (int64_t)); break;
|
|
1500
1753
|
case CA_INT16: LOC_PROBE(int16_t, (int64_t)); break;
|
|
@@ -1504,8 +1757,8 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1504
1757
|
case CA_UINT16: LOC_PROBE(uint16_t, (uint64_t)); break;
|
|
1505
1758
|
case CA_UINT32: LOC_PROBE(uint32_t, (uint64_t)); break;
|
|
1506
1759
|
case CA_UINT64: LOC_PROBE(uint64_t, (uint64_t)); break;
|
|
1507
|
-
case CA_FLOAT32: LOC_PROBE_FLOAT(float
|
|
1508
|
-
case CA_FLOAT64: LOC_PROBE_FLOAT(double
|
|
1760
|
+
case CA_FLOAT32: LOC_PROBE_FLOAT(float); break;
|
|
1761
|
+
case CA_FLOAT64: LOC_PROBE_FLOAT(double); break;
|
|
1509
1762
|
case CA_OBJECT: LOC_PROBE_OBJ; break;
|
|
1510
1763
|
case CA_FIXLEN: LOC_PROBE_MEM; break;
|
|
1511
1764
|
}
|
|
@@ -1526,11 +1779,17 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1526
1779
|
ca_create_mask(cout);
|
|
1527
1780
|
memcpy(cout->mask->ptr, um, (size_t) ca->elements);
|
|
1528
1781
|
}
|
|
1529
|
-
|
|
1782
|
+
ALLOCV_END(hum);
|
|
1530
1783
|
|
|
1531
1784
|
return vout;
|
|
1532
1785
|
}
|
|
1533
1786
|
|
|
1787
|
+
static VALUE
|
|
1788
|
+
rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
1789
|
+
{
|
|
1790
|
+
return fz_run(fz_locate_addr_body, self, rref, Qnil, 0);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1534
1793
|
/* Shared body of __intersection__ (keep_when_hit = 1) and __difference__
|
|
1535
1794
|
(keep_when_hit = 0): the distinct values of self that are (resp. are not)
|
|
1536
1795
|
present in `other`, in self's first-appearance order, as a 1-D CArray of
|
|
@@ -1540,8 +1799,12 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1540
1799
|
lane (numeric `==` + NaN collapse + -0.0 == +0.0, object hash/eql? + NaN
|
|
1541
1800
|
collapse, fixlen byte equality). */
|
|
1542
1801
|
static VALUE
|
|
1543
|
-
|
|
1802
|
+
fz_set_relation_body (VALUE arg)
|
|
1544
1803
|
{
|
|
1804
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1805
|
+
VALUE self = fr->self;
|
|
1806
|
+
VALUE rother = fr->a;
|
|
1807
|
+
int keep_when_hit = fr->i;
|
|
1545
1808
|
CArray *ca, *co;
|
|
1546
1809
|
volatile VALUE face;
|
|
1547
1810
|
self = fz_face_descend(self, &face, "set relation");
|
|
@@ -1594,15 +1857,15 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1594
1857
|
}
|
|
1595
1858
|
|
|
1596
1859
|
fz_levels lv;
|
|
1597
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1860
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1598
1861
|
|
|
1599
1862
|
/* Build the probe set from every non-masked cell of other. */
|
|
1600
|
-
fz_intern_all(&hoth, co, NULL);
|
|
1863
|
+
fz_intern_all(&fr->st[2], &hoth, co, NULL);
|
|
1601
1864
|
|
|
1602
1865
|
/* Walk self: hself dedups, so each distinct self value is decided once; keep
|
|
1603
1866
|
it when its membership in other equals keep_when_hit. */
|
|
1604
1867
|
int8_t axis = (int8_t) (ca->ndim - 1);
|
|
1605
|
-
ca_iter_state st;
|
|
1868
|
+
ca_iter_state *st = &fr->st[0];
|
|
1606
1869
|
char *p;
|
|
1607
1870
|
boolean8_t *m;
|
|
1608
1871
|
ca_size_t n;
|
|
@@ -1621,20 +1884,13 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1621
1884
|
} \
|
|
1622
1885
|
} while (0)
|
|
1623
1886
|
|
|
1624
|
-
#define SR_FLOAT(T
|
|
1887
|
+
#define SR_FLOAT(T) \
|
|
1625
1888
|
do { \
|
|
1626
1889
|
const T *ip = (const T *) p; \
|
|
1627
1890
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1628
1891
|
if ( m && m[i] ) { continue; } \
|
|
1629
1892
|
T v = ip[i]; \
|
|
1630
|
-
uint64_t key;
|
|
1631
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1632
|
-
else { \
|
|
1633
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1634
|
-
UINT bits; \
|
|
1635
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1636
|
-
key = (uint64_t) bits; \
|
|
1637
|
-
} \
|
|
1893
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1638
1894
|
int is_new; \
|
|
1639
1895
|
fz_hash_intern(&hself, key, &is_new); \
|
|
1640
1896
|
if ( is_new && fz_hash_lookup(&hoth, key, NULL) == keep_when_hit ) { \
|
|
@@ -1670,7 +1926,7 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1670
1926
|
} \
|
|
1671
1927
|
} while (0)
|
|
1672
1928
|
|
|
1673
|
-
CA_FOR_EACH_FIBER_MASKED(st, ca, axis, CA_KERNEL_READ, p, n, m) {
|
|
1929
|
+
CA_FOR_EACH_FIBER_MASKED(*st, ca, axis, CA_KERNEL_READ, p, n, m) {
|
|
1674
1930
|
switch ( dt ) {
|
|
1675
1931
|
case CA_INT8: SR(int8_t, (int64_t)); break;
|
|
1676
1932
|
case CA_INT16: SR(int16_t, (int64_t)); break;
|
|
@@ -1680,8 +1936,8 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1680
1936
|
case CA_UINT16: SR(uint16_t, (uint64_t)); break;
|
|
1681
1937
|
case CA_UINT32: SR(uint32_t, (uint64_t)); break;
|
|
1682
1938
|
case CA_UINT64: SR(uint64_t, (uint64_t)); break;
|
|
1683
|
-
case CA_FLOAT32: SR_FLOAT(float
|
|
1684
|
-
case CA_FLOAT64: SR_FLOAT(double
|
|
1939
|
+
case CA_FLOAT32: SR_FLOAT(float); break;
|
|
1940
|
+
case CA_FLOAT64: SR_FLOAT(double); break;
|
|
1685
1941
|
case CA_OBJECT: SR_OBJ; break;
|
|
1686
1942
|
case CA_FIXLEN: SR_MEM; break;
|
|
1687
1943
|
}
|
|
@@ -1708,6 +1964,12 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1708
1964
|
return fz_face_relift(vlev, face); /* set *values*: give the Face back */
|
|
1709
1965
|
}
|
|
1710
1966
|
|
|
1967
|
+
static VALUE
|
|
1968
|
+
fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
1969
|
+
{
|
|
1970
|
+
return fz_run(fz_set_relation_body, self, rother, Qnil, keep_when_hit);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1711
1973
|
/* @overload __intersection__(other)
|
|
1712
1974
|
INTERNAL (CArray#intersection). 1-D CArray of the distinct values present in
|
|
1713
1975
|
both self and other, in self's first-appearance order. */
|
|
@@ -1733,8 +1995,11 @@ rb_ca_difference (VALUE self, VALUE rother)
|
|
|
1733
1995
|
distinct values first, then other's not-yet-seen ones). Masked cells of
|
|
1734
1996
|
either array do not participate. */
|
|
1735
1997
|
static VALUE
|
|
1736
|
-
|
|
1998
|
+
fz_set_union_body (VALUE arg)
|
|
1737
1999
|
{
|
|
2000
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2001
|
+
VALUE self = fr->self;
|
|
2002
|
+
VALUE rother = fr->a;
|
|
1738
2003
|
CArray *ca, *co;
|
|
1739
2004
|
volatile VALUE face;
|
|
1740
2005
|
self = fz_face_descend(self, &face, "union");
|
|
@@ -1760,8 +2025,16 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1760
2025
|
rb_raise(rb_eArgError, "__union__: other must be a CArray");
|
|
1761
2026
|
}
|
|
1762
2027
|
GetCArray(rother, co);
|
|
1763
|
-
if ( co->data_type != dt
|
|
1764
|
-
rb_raise(rb_eCADataTypeError,
|
|
2028
|
+
if ( co->data_type != dt ) {
|
|
2029
|
+
rb_raise(rb_eCADataTypeError,
|
|
2030
|
+
"union: other data type (%s) must match self (%s)",
|
|
2031
|
+
ca_type_name[co->data_type], ca_type_name[dt]);
|
|
2032
|
+
}
|
|
2033
|
+
if ( dt == CA_FIXLEN && co->bytes != ca->bytes ) {
|
|
2034
|
+
rb_raise(rb_eCADataTypeError,
|
|
2035
|
+
"union: a fixlen value is a cell-width blob, so other "
|
|
2036
|
+
"must be %ld bytes wide like self, not %ld",
|
|
2037
|
+
(long) ca->bytes, (long) co->bytes);
|
|
1765
2038
|
}
|
|
1766
2039
|
if ( co->ndim < 1 ) {
|
|
1767
2040
|
rb_raise(rb_eRuntimeError, "__union__: other need ndim >= 1");
|
|
@@ -1773,10 +2046,10 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1773
2046
|
else { fz_hash_init(&h); }
|
|
1774
2047
|
|
|
1775
2048
|
fz_levels lv;
|
|
1776
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
2049
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1777
2050
|
|
|
1778
|
-
fz_intern_all(&h, ca, &lv); /* self's distinct values, appearance order */
|
|
1779
|
-
fz_intern_all(&h, co, &lv); /* + other's not-yet-seen distinct values */
|
|
2051
|
+
fz_intern_all(&fr->st[2], &h, ca, &lv); /* self's distinct values, appearance order */
|
|
2052
|
+
fz_intern_all(&fr->st[2], &h, co, &lv); /* + other's not-yet-seen distinct values */
|
|
1780
2053
|
|
|
1781
2054
|
ca_size_t k = lv.n;
|
|
1782
2055
|
fz_hash_free(&h);
|
|
@@ -1794,6 +2067,12 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1794
2067
|
return fz_face_relift(vlev, face); /* set *values*: give the Face back */
|
|
1795
2068
|
}
|
|
1796
2069
|
|
|
2070
|
+
static VALUE
|
|
2071
|
+
rb_ca_set_union (VALUE self, VALUE rother)
|
|
2072
|
+
{
|
|
2073
|
+
return fz_run(fz_set_union_body, self, rother, Qnil, 0);
|
|
2074
|
+
}
|
|
2075
|
+
|
|
1797
2076
|
/* @overload __value_counts_flat__
|
|
1798
2077
|
|
|
1799
2078
|
INTERNAL (CArray#value_counts). Collect the distinct values of self in
|
|
@@ -1810,8 +2089,10 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1810
2089
|
collapses every Float NaN to one value (their counts add up, as numeric does).
|
|
1811
2090
|
*/
|
|
1812
2091
|
static VALUE
|
|
1813
|
-
|
|
2092
|
+
fz_value_counts_flat_body (VALUE arg)
|
|
1814
2093
|
{
|
|
2094
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2095
|
+
VALUE self = fr->self;
|
|
1815
2096
|
CArray *ca;
|
|
1816
2097
|
volatile VALUE face;
|
|
1817
2098
|
self = fz_face_descend(self, &face, "value_counts");
|
|
@@ -1839,11 +2120,11 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1839
2120
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
1840
2121
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
1841
2122
|
else { fz_hash_init(&h); }
|
|
1842
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1843
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2123
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
2124
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
1844
2125
|
|
|
1845
2126
|
int8_t axis = (int8_t) (ca->ndim - 1); /* one seen-set over the whole array */
|
|
1846
|
-
ca_iter_state st_in;
|
|
2127
|
+
ca_iter_state *st_in = &fr->st[0];
|
|
1847
2128
|
char *p_in;
|
|
1848
2129
|
boolean8_t *m;
|
|
1849
2130
|
ca_size_t n;
|
|
@@ -1866,20 +2147,13 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1866
2147
|
} \
|
|
1867
2148
|
} while (0)
|
|
1868
2149
|
|
|
1869
|
-
#define VC_LOOP_FLOAT(T
|
|
2150
|
+
#define VC_LOOP_FLOAT(T) \
|
|
1870
2151
|
do { \
|
|
1871
2152
|
const T *ip = (const T *) p_in; \
|
|
1872
2153
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1873
2154
|
if ( m && m[i] ) { continue; } \
|
|
1874
2155
|
T v = ip[i]; \
|
|
1875
|
-
uint64_t key;
|
|
1876
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1877
|
-
else { \
|
|
1878
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1879
|
-
UINT bits; \
|
|
1880
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1881
|
-
key = (uint64_t) bits; \
|
|
1882
|
-
} \
|
|
2156
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1883
2157
|
int is_new; \
|
|
1884
2158
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
1885
2159
|
if ( is_new ) { \
|
|
@@ -1929,7 +2203,7 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1929
2203
|
} \
|
|
1930
2204
|
} while (0)
|
|
1931
2205
|
|
|
1932
|
-
CA_FOR_EACH_FIBER_MASKED(st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
2206
|
+
CA_FOR_EACH_FIBER_MASKED(*st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1933
2207
|
switch ( dt ) {
|
|
1934
2208
|
case CA_INT8: VC_LOOP(int8_t, (int64_t)); break;
|
|
1935
2209
|
case CA_INT16: VC_LOOP(int16_t, (int64_t)); break;
|
|
@@ -1939,8 +2213,8 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1939
2213
|
case CA_UINT16: VC_LOOP(uint16_t, (uint64_t)); break;
|
|
1940
2214
|
case CA_UINT32: VC_LOOP(uint32_t, (uint64_t)); break;
|
|
1941
2215
|
case CA_UINT64: VC_LOOP(uint64_t, (uint64_t)); break;
|
|
1942
|
-
case CA_FLOAT32: VC_LOOP_FLOAT(float
|
|
1943
|
-
case CA_FLOAT64: VC_LOOP_FLOAT(double
|
|
2216
|
+
case CA_FLOAT32: VC_LOOP_FLOAT(float); break;
|
|
2217
|
+
case CA_FLOAT64: VC_LOOP_FLOAT(double); break;
|
|
1944
2218
|
case CA_OBJECT: VC_LOOP_OBJ; break;
|
|
1945
2219
|
case CA_FIXLEN: VC_LOOP_MEM; break;
|
|
1946
2220
|
}
|
|
@@ -1973,6 +2247,12 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1973
2247
|
return rb_ary_new3(2, fz_face_relift(vlev, face), vcnt);
|
|
1974
2248
|
}
|
|
1975
2249
|
|
|
2250
|
+
static VALUE
|
|
2251
|
+
rb_ca_value_counts_flat (VALUE self)
|
|
2252
|
+
{
|
|
2253
|
+
return fz_run(fz_value_counts_flat_body, self, Qnil, Qnil, 0);
|
|
2254
|
+
}
|
|
2255
|
+
|
|
1976
2256
|
/* @overload __nunique__(axis, keep_axis)
|
|
1977
2257
|
|
|
1978
2258
|
INTERNAL (CArray#nunique). Count the distinct values along axis, one linear
|
|
@@ -1985,8 +2265,12 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1985
2265
|
Ruby Hash distinctness; the object lane also collapses every Float NaN to one.
|
|
1986
2266
|
*/
|
|
1987
2267
|
static VALUE
|
|
1988
|
-
|
|
2268
|
+
fz_nunique_body (VALUE arg)
|
|
1989
2269
|
{
|
|
2270
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2271
|
+
VALUE self = fr->self;
|
|
2272
|
+
VALUE vaxis = fr->a;
|
|
2273
|
+
VALUE vkeep = fr->b;
|
|
1990
2274
|
CArray *ca;
|
|
1991
2275
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1992
2276
|
|
|
@@ -2023,8 +2307,8 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2023
2307
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
2024
2308
|
else { fz_hash_init(&h); }
|
|
2025
2309
|
|
|
2026
|
-
ca_iter_state st;
|
|
2027
|
-
int rc = ca_iter_state_init_l2(
|
|
2310
|
+
ca_iter_state *st = &fr->st[0];
|
|
2311
|
+
int rc = ca_iter_state_init_l2(st, ca, CA_SLAB_AXES, &ax, 1, 0);
|
|
2028
2312
|
if ( rc != CA_ITER_OK ) {
|
|
2029
2313
|
fz_hash_free(&h);
|
|
2030
2314
|
rb_raise(rb_eRuntimeError, "__nunique__: kernel_iterator init failed rc=%d", rc);
|
|
@@ -2040,17 +2324,10 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2040
2324
|
-0.0 before the bitwise key. */
|
|
2041
2325
|
#define NU_INT(WIDEN) \
|
|
2042
2326
|
do { int _n; fz_hash_intern(&h, (uint64_t) ((WIDEN) v), &_n); } while (0)
|
|
2043
|
-
#define NU_FLOAT(T
|
|
2327
|
+
#define NU_FLOAT(T) \
|
|
2044
2328
|
do { \
|
|
2045
2329
|
T _v = v; \
|
|
2046
|
-
uint64_t _key;
|
|
2047
|
-
if ( _v != _v ) { _key = (NANKEY); } \
|
|
2048
|
-
else { \
|
|
2049
|
-
if ( _v == (T) 0 ) { _v = (T) 0; } \
|
|
2050
|
-
UINT _b; \
|
|
2051
|
-
memcpy(&_b, &_v, sizeof(_b)); \
|
|
2052
|
-
_key = (uint64_t) _b; \
|
|
2053
|
-
} \
|
|
2330
|
+
uint64_t _key = FZ_FLOAT_KEY(T, _v); \
|
|
2054
2331
|
int _n; fz_hash_intern(&h, _key, &_n); \
|
|
2055
2332
|
} while (0)
|
|
2056
2333
|
/* Object: intern the VALUE via the object lane (v is bound by the macro). */
|
|
@@ -2062,43 +2339,43 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2062
2339
|
each esz-wide element via the fixlen lane. */
|
|
2063
2340
|
#define NU_MEM_WALK \
|
|
2064
2341
|
do { \
|
|
2065
|
-
int8_t K = st
|
|
2342
|
+
int8_t K = st->slab_ndim; \
|
|
2066
2343
|
ca_size_t idx[CA_RANK_MAX] = { 0 }; \
|
|
2067
|
-
ca_size_t total = st
|
|
2344
|
+
ca_size_t total = st->slab_elements; \
|
|
2068
2345
|
for ( ca_size_t e = 0; e < total; e++ ) { \
|
|
2069
2346
|
ca_size_t doff = 0, moff = 0; \
|
|
2070
2347
|
for ( int8_t kk = 0; kk < K; kk++ ) { \
|
|
2071
|
-
doff += idx[kk] * st
|
|
2072
|
-
moff += idx[kk] * st
|
|
2348
|
+
doff += idx[kk] * st->slab_strides[kk]; \
|
|
2349
|
+
moff += idx[kk] * st->slab_mask_strides[kk]; \
|
|
2073
2350
|
} \
|
|
2074
2351
|
if ( ! (m && m[moff]) ) { \
|
|
2075
2352
|
int _n; fz_hash_intern_mem(&h, p + doff, &_n); \
|
|
2076
2353
|
} \
|
|
2077
2354
|
for ( int8_t kk = (int8_t)(K - 1); kk >= 0; kk-- ) { \
|
|
2078
|
-
if ( ++idx[kk] < st
|
|
2355
|
+
if ( ++idx[kk] < st->slab_dims[kk] ) break; \
|
|
2079
2356
|
idx[kk] = 0; \
|
|
2080
2357
|
} \
|
|
2081
2358
|
} \
|
|
2082
2359
|
} while (0)
|
|
2083
2360
|
|
|
2084
|
-
while ( ca_iter_state_next_slab_axes(
|
|
2361
|
+
while ( ca_iter_state_next_slab_axes(st, &p, &m) ) {
|
|
2085
2362
|
fz_hash_reset(&h); /* independent seen-set per fiber */
|
|
2086
2363
|
switch ( dt ) {
|
|
2087
|
-
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2088
|
-
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2089
|
-
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2090
|
-
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2091
|
-
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2092
|
-
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2093
|
-
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2094
|
-
case CA_UINT64: CA_SLAB_REDUCE_T(uint64_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2364
|
+
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2365
|
+
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2366
|
+
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2367
|
+
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2368
|
+
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2369
|
+
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2370
|
+
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2371
|
+
case CA_UINT64: CA_SLAB_REDUCE_T(uint64_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2095
2372
|
case CA_FLOAT32:
|
|
2096
|
-
CA_SLAB_REDUCE_T(float, st, p, m, dummy, 0, NU_FLOAT(float
|
|
2373
|
+
CA_SLAB_REDUCE_T(float, *st, p, m, dummy, 0, NU_FLOAT(float));
|
|
2097
2374
|
break;
|
|
2098
2375
|
case CA_FLOAT64:
|
|
2099
|
-
CA_SLAB_REDUCE_T(double, st, p, m, dummy, 0, NU_FLOAT(double
|
|
2376
|
+
CA_SLAB_REDUCE_T(double, *st, p, m, dummy, 0, NU_FLOAT(double));
|
|
2100
2377
|
break;
|
|
2101
|
-
case CA_OBJECT: CA_SLAB_REDUCE_T(VALUE, st, p, m, dummy, 0, NU_OBJ); break;
|
|
2378
|
+
case CA_OBJECT: CA_SLAB_REDUCE_T(VALUE, *st, p, m, dummy, 0, NU_OBJ); break;
|
|
2102
2379
|
case CA_FIXLEN: NU_MEM_WALK; break;
|
|
2103
2380
|
}
|
|
2104
2381
|
op[out_i++] = (int64_t) h.n;
|
|
@@ -2109,11 +2386,17 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2109
2386
|
#undef NU_MEM_WALK
|
|
2110
2387
|
(void) dummy;
|
|
2111
2388
|
|
|
2112
|
-
ca_iter_state_finish(
|
|
2389
|
+
ca_iter_state_finish(st);
|
|
2113
2390
|
fz_hash_free(&h);
|
|
2114
2391
|
return vout;
|
|
2115
2392
|
}
|
|
2116
2393
|
|
|
2394
|
+
static VALUE
|
|
2395
|
+
rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
2396
|
+
{
|
|
2397
|
+
return fz_run(fz_nunique_body, fz_complex_as_key(self), vaxis, vkeep, 0);
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2117
2400
|
/* @overload __is_mode__(axis)
|
|
2118
2401
|
|
|
2119
2402
|
INTERNAL (CArray#is_mode). Mark each cell that holds a modal value along axis
|
|
@@ -2132,8 +2415,11 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2132
2415
|
Callers pass flat input by flattening first (a single fiber over axis 0).
|
|
2133
2416
|
*/
|
|
2134
2417
|
static VALUE
|
|
2135
|
-
|
|
2418
|
+
fz_is_mode_body (VALUE arg)
|
|
2136
2419
|
{
|
|
2420
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2421
|
+
VALUE self = fr->self;
|
|
2422
|
+
VALUE vaxis = fr->a;
|
|
2137
2423
|
CArray *ca;
|
|
2138
2424
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2139
2425
|
|
|
@@ -2166,9 +2452,9 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2166
2452
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
2167
2453
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
2168
2454
|
else { fz_hash_init(&h); }
|
|
2169
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2455
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
2170
2456
|
|
|
2171
|
-
ca_iter_state st_in, st_out;
|
|
2457
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
2172
2458
|
char *p_in, *p_out;
|
|
2173
2459
|
boolean8_t *m;
|
|
2174
2460
|
ca_size_t n;
|
|
@@ -2201,7 +2487,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2201
2487
|
} while (0)
|
|
2202
2488
|
|
|
2203
2489
|
/* Float: NaN collapses to one canonical key; -0.0 / +0.0 share a key. */
|
|
2204
|
-
#define IM_BODY_FLOAT(T
|
|
2490
|
+
#define IM_BODY_FLOAT(T) \
|
|
2205
2491
|
do { \
|
|
2206
2492
|
const T *ip = (const T *) p_in; \
|
|
2207
2493
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
@@ -2216,14 +2502,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2216
2502
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
2217
2503
|
if ( m && m[i] ) { if ( pass == 1 ) { op[i] = 0; } continue; } \
|
|
2218
2504
|
T v = ip[i]; \
|
|
2219
|
-
uint64_t key;
|
|
2220
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
2221
|
-
else { \
|
|
2222
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
2223
|
-
UINT bits; \
|
|
2224
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
2225
|
-
key = (uint64_t) bits; \
|
|
2226
|
-
} \
|
|
2505
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
2227
2506
|
int is_new; \
|
|
2228
2507
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
2229
2508
|
if ( pass == 0 ) { \
|
|
@@ -2287,7 +2566,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2287
2566
|
} \
|
|
2288
2567
|
} while (0)
|
|
2289
2568
|
|
|
2290
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cout, (int8_t) axis,
|
|
2569
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cout, (int8_t) axis,
|
|
2291
2570
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
2292
2571
|
fz_hash_reset(&h); /* independent frequency table per fiber */
|
|
2293
2572
|
ct.n = 0;
|
|
@@ -2300,8 +2579,8 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2300
2579
|
case CA_UINT16: IM_BODY(uint16_t, (uint64_t)); break;
|
|
2301
2580
|
case CA_UINT32: IM_BODY(uint32_t, (uint64_t)); break;
|
|
2302
2581
|
case CA_UINT64: IM_BODY(uint64_t, (uint64_t)); break;
|
|
2303
|
-
case CA_FLOAT32: IM_BODY_FLOAT(float
|
|
2304
|
-
case CA_FLOAT64: IM_BODY_FLOAT(double
|
|
2582
|
+
case CA_FLOAT32: IM_BODY_FLOAT(float); break;
|
|
2583
|
+
case CA_FLOAT64: IM_BODY_FLOAT(double); break;
|
|
2305
2584
|
case CA_OBJECT: IM_BODY_OBJ; break;
|
|
2306
2585
|
case CA_FIXLEN: IM_BODY_MEM; break;
|
|
2307
2586
|
}
|
|
@@ -2316,6 +2595,12 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2316
2595
|
return vout;
|
|
2317
2596
|
}
|
|
2318
2597
|
|
|
2598
|
+
static VALUE
|
|
2599
|
+
rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
2600
|
+
{
|
|
2601
|
+
return fz_run(fz_is_mode_body, fz_complex_as_key(self), vaxis, Qnil, 0);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2319
2604
|
/* Ascending comparison for the modal-value sort, NaN ordered last so a
|
|
2320
2605
|
collapsed NaN key (at most one per fiber) trails the real values, matching
|
|
2321
2606
|
CArray#sort. */
|
|
@@ -2349,8 +2634,11 @@ static int mode_gt_f64 (double a, double b) { if ( a != a ) return b == b; if (
|
|
|
2349
2634
|
its sign), matching the discovery family.
|
|
2350
2635
|
*/
|
|
2351
2636
|
static VALUE
|
|
2352
|
-
|
|
2637
|
+
fz_mode_axis_body (VALUE arg)
|
|
2353
2638
|
{
|
|
2639
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2640
|
+
VALUE self = fr->self;
|
|
2641
|
+
VALUE vaxis = fr->a;
|
|
2354
2642
|
CArray *ca;
|
|
2355
2643
|
volatile VALUE face;
|
|
2356
2644
|
self = fz_face_descend(self, &face, "mode");
|
|
@@ -2387,20 +2675,21 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2387
2675
|
fz_levels mod; /* per-fiber modal values, collected then sorted (reset) */
|
|
2388
2676
|
fz_levels flat; /* all fibers' modal values concatenated, fiber order */
|
|
2389
2677
|
fz_hash_init(&h);
|
|
2390
|
-
fz_levels_init(&lv, esz);
|
|
2391
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2392
|
-
fz_levels_init(&mod, esz);
|
|
2393
|
-
fz_levels_init(&flat, esz);
|
|
2678
|
+
fz_levels_init(&lv, esz, 0);
|
|
2679
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
2680
|
+
fz_levels_init(&mod, esz, 0);
|
|
2681
|
+
fz_levels_init(&flat, esz, 0);
|
|
2394
2682
|
|
|
2395
|
-
|
|
2683
|
+
volatile VALUE hfoff = 0;
|
|
2684
|
+
ca_size_t *foff = ALLOCV_N(ca_size_t, hfoff, M + 1); /* prefix offsets into flat */
|
|
2396
2685
|
foff[0] = 0;
|
|
2397
2686
|
|
|
2398
2687
|
int8_t ax = (int8_t) axis;
|
|
2399
|
-
ca_iter_state st;
|
|
2400
|
-
int rc = ca_iter_state_init_l2(
|
|
2688
|
+
ca_iter_state *st = &fr->st[0];
|
|
2689
|
+
int rc = ca_iter_state_init_l2(st, ca, CA_SLAB_AXES, &ax, 1, 0);
|
|
2401
2690
|
if ( rc != CA_ITER_OK ) {
|
|
2402
2691
|
fz_hash_free(&h); fz_levels_free(&lv); fz_levels_free(&ct);
|
|
2403
|
-
fz_levels_free(&mod); fz_levels_free(&flat);
|
|
2692
|
+
fz_levels_free(&mod); fz_levels_free(&flat); ALLOCV_END(hfoff);
|
|
2404
2693
|
rb_raise(rb_eRuntimeError, "__mode_axis__: kernel_iterator init failed rc=%d", rc);
|
|
2405
2694
|
}
|
|
2406
2695
|
|
|
@@ -2421,12 +2710,9 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2421
2710
|
fz_levels_push(&ct, &one); } \
|
|
2422
2711
|
else { ((int64_t *) ct.p)[code]++; } \
|
|
2423
2712
|
} while (0)
|
|
2424
|
-
#define MB_FLOAT(T
|
|
2713
|
+
#define MB_FLOAT(T) \
|
|
2425
2714
|
do { \
|
|
2426
|
-
|
|
2427
|
-
if ( vn != vn ) { key = (NANKEY); } \
|
|
2428
|
-
else { if ( vn == (T) 0 ) { vn = (T) 0; } \
|
|
2429
|
-
UINT bits; memcpy(&bits, &vn, sizeof(bits)); key = (uint64_t) bits; } \
|
|
2715
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
2430
2716
|
int is_new; int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
2431
2717
|
if ( is_new ) { int64_t one = 1; fz_levels_push(&lv, &v); \
|
|
2432
2718
|
fz_levels_push(&ct, &one); } \
|
|
@@ -2450,24 +2736,24 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2450
2736
|
for ( ca_size_t x = 0; x < cm; x++ ) { fz_levels_push(&flat, &dp[x]); } \
|
|
2451
2737
|
} while (0)
|
|
2452
2738
|
|
|
2453
|
-
while ( ca_iter_state_next_slab_axes(
|
|
2739
|
+
while ( ca_iter_state_next_slab_axes(st, &p, &m) ) {
|
|
2454
2740
|
fz_hash_reset(&h);
|
|
2455
2741
|
lv.n = 0; ct.n = 0; mod.n = 0;
|
|
2456
2742
|
|
|
2457
2743
|
switch ( dt ) {
|
|
2458
|
-
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2459
|
-
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2460
|
-
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2461
|
-
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2462
|
-
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2463
|
-
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2464
|
-
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2465
|
-
case CA_UINT64: CA_SLAB_REDUCE_T(uint64_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2744
|
+
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2745
|
+
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2746
|
+
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2747
|
+
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2748
|
+
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2749
|
+
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2750
|
+
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2751
|
+
case CA_UINT64: CA_SLAB_REDUCE_T(uint64_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2466
2752
|
case CA_FLOAT32:
|
|
2467
|
-
CA_SLAB_REDUCE_T(float, st, p, m, dummy, 0, MB_FLOAT(float
|
|
2753
|
+
CA_SLAB_REDUCE_T(float, *st, p, m, dummy, 0, MB_FLOAT(float));
|
|
2468
2754
|
break;
|
|
2469
2755
|
case CA_FLOAT64:
|
|
2470
|
-
CA_SLAB_REDUCE_T(double, st, p, m, dummy, 0, MB_FLOAT(double
|
|
2756
|
+
CA_SLAB_REDUCE_T(double, *st, p, m, dummy, 0, MB_FLOAT(double));
|
|
2471
2757
|
break;
|
|
2472
2758
|
}
|
|
2473
2759
|
|
|
@@ -2499,7 +2785,7 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2499
2785
|
#undef MODE_EMIT
|
|
2500
2786
|
(void) dummy;
|
|
2501
2787
|
|
|
2502
|
-
ca_iter_state_finish(
|
|
2788
|
+
ca_iter_state_finish(st);
|
|
2503
2789
|
fz_hash_free(&h);
|
|
2504
2790
|
fz_levels_free(&lv);
|
|
2505
2791
|
fz_levels_free(&ct);
|
|
@@ -2529,10 +2815,16 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2529
2815
|
}
|
|
2530
2816
|
|
|
2531
2817
|
fz_levels_free(&flat);
|
|
2532
|
-
|
|
2818
|
+
ALLOCV_END(hfoff);
|
|
2533
2819
|
return result;
|
|
2534
2820
|
}
|
|
2535
2821
|
|
|
2822
|
+
static VALUE
|
|
2823
|
+
rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
2824
|
+
{
|
|
2825
|
+
return fz_run(fz_mode_axis_body, self, vaxis, Qnil, 0);
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2536
2828
|
void
|
|
2537
2829
|
Init_carray_factorize (void)
|
|
2538
2830
|
{
|