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_factorize.c
CHANGED
|
@@ -102,30 +102,137 @@
|
|
|
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
|
-
fz_face_descend (VALUE self, volatile VALUE *pface)
|
|
199
|
+
fz_face_descend (VALUE self, volatile VALUE *pface, const char *name)
|
|
109
200
|
{
|
|
110
201
|
CArray *ca;
|
|
111
202
|
GetCArray(self, ca);
|
|
112
|
-
if ( ca_is_face(ca) &&
|
|
203
|
+
if ( ! ca_is_face(ca) && ca_is_complex_type(ca) ) {
|
|
113
204
|
*pface = self;
|
|
114
|
-
return
|
|
205
|
+
return fz_complex_key(self);
|
|
206
|
+
}
|
|
207
|
+
if ( ca_is_face(ca) ) {
|
|
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 ) {
|
|
212
|
+
*pface = self;
|
|
213
|
+
return rb_ca_strip_face_value(self);
|
|
214
|
+
}
|
|
215
|
+
/* A Face that cannot be descended must not flow on undescended: whatever
|
|
216
|
+
reads it next reads its storage anyway, which is the encoding rather
|
|
217
|
+
than the values. A Face in this position normally never arrives --
|
|
218
|
+
CAConstString and CACategorical define their own members in Ruby -- but
|
|
219
|
+
the overrides only fire when the Face is the receiver, and this same
|
|
220
|
+
helper descends the *reference* for locate_addr, where it is the
|
|
221
|
+
argument. */
|
|
222
|
+
rb_raise(rb_eArgError,
|
|
223
|
+
"%s: %s is not orderable by storage (a cell encodes the value "
|
|
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));
|
|
115
227
|
}
|
|
116
228
|
*pface = Qnil;
|
|
117
229
|
return self;
|
|
118
230
|
}
|
|
119
231
|
|
|
120
232
|
/* Bring `operand` into the space of `reference` (the *pre-strip* Face) and
|
|
121
|
-
descend it, so both sides hash in one storage space
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
space for the same value -- so a reference that defines it reconciles any
|
|
125
|
-
operand type through it (and refuses what it cannot convert, which is how a
|
|
126
|
-
bare storage number stays out). A reference with one space only (COMPARABLE,
|
|
127
|
-
or a Face with no unit algebra at all, e.g. CAString) has nothing to
|
|
128
|
-
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. */
|
|
129
236
|
static VALUE
|
|
130
237
|
fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
131
238
|
{
|
|
@@ -134,30 +241,37 @@ fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
|
134
241
|
return operand;
|
|
135
242
|
}
|
|
136
243
|
GetCArray(reference, ca);
|
|
137
|
-
if ( !
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
rb_intern("to_comparable"),
|
|
141
|
-
1, operand));
|
|
142
|
-
}
|
|
143
|
-
if ( rb_obj_is_carray(operand) ) {
|
|
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. */
|
|
144
247
|
CArray *op;
|
|
248
|
+
if ( ! rb_obj_is_carray(operand) ) {
|
|
249
|
+
return operand;
|
|
250
|
+
}
|
|
145
251
|
GetCArray(operand, op);
|
|
146
|
-
if (
|
|
147
|
-
|
|
252
|
+
if ( op->data_type != ca->data_type ) {
|
|
253
|
+
operand = rb_ca_to_type(operand, INT2NUM(ca->data_type), Qnil);
|
|
148
254
|
}
|
|
255
|
+
return fz_complex_key(operand);
|
|
149
256
|
}
|
|
150
|
-
(
|
|
151
|
-
return operand;
|
|
257
|
+
return ca_face_reconcile_operand(reference, operand, name);
|
|
152
258
|
}
|
|
153
259
|
|
|
154
|
-
/* 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. */
|
|
155
262
|
static VALUE
|
|
156
263
|
fz_face_relift (VALUE out, VALUE face)
|
|
157
264
|
{
|
|
265
|
+
CArray *cf, *co;
|
|
158
266
|
if ( NIL_P(face) ) {
|
|
159
267
|
return out;
|
|
160
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
|
+
}
|
|
161
275
|
return ca_face_lift(out, face);
|
|
162
276
|
}
|
|
163
277
|
|
|
@@ -170,16 +284,95 @@ typedef struct {
|
|
|
170
284
|
VALUE *val; /* object lane only: the interned VALUE, kept for an eql? re-check
|
|
171
285
|
on a hash collision (NULL in the numeric lane, where the widened
|
|
172
286
|
key is lossless so a key match already proves value equality).
|
|
173
|
-
|
|
174
|
-
|
|
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). */
|
|
175
290
|
char *raw; /* fixlen lane only: cap*esz bytes, the interned element bytes kept
|
|
176
291
|
for a memcmp re-check on a hash collision (NULL otherwise). */
|
|
177
292
|
int esz; /* fixlen lane: element width in bytes (0 otherwise) */
|
|
293
|
+
int has_val; /* object lane: val is kept (0 otherwise) */
|
|
178
294
|
ca_size_t cap; /* power of two */
|
|
179
295
|
ca_size_t n; /* distinct keys interned so far */
|
|
180
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) */
|
|
181
298
|
} fz_hash;
|
|
182
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
|
+
|
|
183
376
|
/* Multiplicative hashing (Knuth, TAOCP vol. 3 sec. 6.4): multiply by
|
|
184
377
|
2^64 / golden-ratio and take the TOP log2(cap) bits of the product -- the
|
|
185
378
|
high bits are where a multiply mixes best (the low bits carry little
|
|
@@ -189,19 +382,49 @@ typedef struct {
|
|
|
189
382
|
#define FZ_GOLDEN 0x9E3779B97F4A7C15ULL
|
|
190
383
|
#define FZ_HOME(h, key) ((ca_size_t) (((uint64_t)(key) * FZ_GOLDEN) >> (h)->shift))
|
|
191
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. */
|
|
192
387
|
static void
|
|
193
|
-
|
|
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)
|
|
194
415
|
{
|
|
195
|
-
h->cap = 1024;
|
|
196
416
|
h->shift = 64 - 10; /* log2(1024) = 10 */
|
|
197
417
|
h->n = 0;
|
|
198
|
-
h->
|
|
199
|
-
h->
|
|
200
|
-
h->
|
|
201
|
-
h
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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 */
|
|
205
428
|
}
|
|
206
429
|
|
|
207
430
|
/* Object lane: the widened key is `rb_hash` (lossy), so a slot also stores the
|
|
@@ -210,8 +433,7 @@ fz_hash_init (fz_hash *h)
|
|
|
210
433
|
static void
|
|
211
434
|
fz_hash_init_obj (fz_hash *h)
|
|
212
435
|
{
|
|
213
|
-
|
|
214
|
-
h->val = ALLOC_N(VALUE, h->cap);
|
|
436
|
+
fz_hash_setup(h, 1, 0);
|
|
215
437
|
}
|
|
216
438
|
|
|
217
439
|
/* Fixlen lane: the key is a byte-hash of the esz-wide element (lossy), so a slot
|
|
@@ -221,19 +443,18 @@ fz_hash_init_obj (fz_hash *h)
|
|
|
221
443
|
static void
|
|
222
444
|
fz_hash_init_mem (fz_hash *h, int esz)
|
|
223
445
|
{
|
|
224
|
-
|
|
225
|
-
h->esz = esz;
|
|
226
|
-
h->raw = ALLOC_N(char, h->cap * esz);
|
|
446
|
+
fz_hash_setup(h, 0, esz);
|
|
227
447
|
}
|
|
228
448
|
|
|
229
449
|
static void
|
|
230
450
|
fz_hash_free (fz_hash *h)
|
|
231
451
|
{
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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;
|
|
237
458
|
}
|
|
238
459
|
|
|
239
460
|
/* FNV-1a over esz bytes: a lossy 64-bit key for the fixlen lane. */
|
|
@@ -266,14 +487,10 @@ fz_hash_grow (fz_hash *h)
|
|
|
266
487
|
VALUE *ov = h->val;
|
|
267
488
|
char *orw = h->raw;
|
|
268
489
|
int esz = h->esz;
|
|
269
|
-
h->
|
|
270
|
-
h->
|
|
271
|
-
h->
|
|
272
|
-
h
|
|
273
|
-
h->used = ALLOC_N(uint8_t, newcap);
|
|
274
|
-
if ( ov ) { h->val = ALLOC_N(VALUE, newcap); }
|
|
275
|
-
if ( orw ) { h->raw = ALLOC_N(char, newcap * esz); }
|
|
276
|
-
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);
|
|
277
494
|
ca_size_t mask = newcap - 1;
|
|
278
495
|
for ( ca_size_t s = 0; s < oldcap; s++ ) {
|
|
279
496
|
if ( ! ou[s] ) { continue; }
|
|
@@ -285,9 +502,7 @@ fz_hash_grow (fz_hash *h)
|
|
|
285
502
|
if ( ov ) { h->val[slot] = ov[s]; }
|
|
286
503
|
if ( orw ) { memcpy(h->raw + slot * esz, orw + s * esz, esz); }
|
|
287
504
|
}
|
|
288
|
-
|
|
289
|
-
if ( ov ) { xfree(ov); }
|
|
290
|
-
if ( orw ) { xfree(orw); }
|
|
505
|
+
fz_tmp_free(&hold);
|
|
291
506
|
}
|
|
292
507
|
|
|
293
508
|
/* True when v is a Float holding NaN (any bit pattern). */
|
|
@@ -309,7 +524,7 @@ fz_hash_intern_obj (fz_hash *h, VALUE v, int *is_new)
|
|
|
309
524
|
{
|
|
310
525
|
if ( (h->n + 1) * 10 >= h->cap * 7 ) { fz_hash_grow(h); } /* load factor 0.7 */
|
|
311
526
|
int v_nan = fz_is_float_nan(v);
|
|
312
|
-
uint64_t key = v_nan ?
|
|
527
|
+
uint64_t key = v_nan ? FZ_NAN_KEY_DOUBLE
|
|
313
528
|
: (uint64_t) NUM2LL(rb_hash(v));
|
|
314
529
|
ca_size_t mask = h->cap - 1;
|
|
315
530
|
ca_size_t slot = FZ_HOME(h, key);
|
|
@@ -407,7 +622,7 @@ static int
|
|
|
407
622
|
fz_hash_lookup_obj (fz_hash *h, VALUE v, int32_t *code_out)
|
|
408
623
|
{
|
|
409
624
|
int v_nan = fz_is_float_nan(v);
|
|
410
|
-
uint64_t key = v_nan ?
|
|
625
|
+
uint64_t key = v_nan ? FZ_NAN_KEY_DOUBLE
|
|
411
626
|
: (uint64_t) NUM2LL(rb_hash(v));
|
|
412
627
|
ca_size_t mask = h->cap - 1;
|
|
413
628
|
ca_size_t slot = FZ_HOME(h, key);
|
|
@@ -446,23 +661,44 @@ typedef struct {
|
|
|
446
661
|
ca_size_t cap; /* capacity in elements */
|
|
447
662
|
ca_size_t n; /* elements stored */
|
|
448
663
|
int esz; /* element bytes */
|
|
664
|
+
VALUE hp; /* owner of p (see fz_tmp_alloc) */
|
|
665
|
+
int obj; /* p holds VALUEs, marked by hp */
|
|
449
666
|
} fz_levels;
|
|
450
667
|
|
|
668
|
+
/* Fill the VALUE slots from..cap with Qnil and mark all cap of them. */
|
|
451
669
|
static void
|
|
452
|
-
|
|
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)
|
|
453
680
|
{
|
|
454
681
|
l->esz = esz;
|
|
455
682
|
l->cap = 16;
|
|
456
683
|
l->n = 0;
|
|
457
|
-
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
|
+
}
|
|
458
690
|
}
|
|
459
691
|
|
|
460
692
|
static void
|
|
461
693
|
fz_levels_push (fz_levels *l, const void *e)
|
|
462
694
|
{
|
|
463
695
|
if ( l->n == l->cap ) {
|
|
696
|
+
ca_size_t old = l->cap;
|
|
464
697
|
l->cap <<= 1;
|
|
465
|
-
|
|
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
|
+
}
|
|
466
702
|
}
|
|
467
703
|
memcpy(l->p + l->n * l->esz, e, l->esz);
|
|
468
704
|
l->n++;
|
|
@@ -471,7 +707,35 @@ fz_levels_push (fz_levels *l, const void *e)
|
|
|
471
707
|
static void
|
|
472
708
|
fz_levels_free (fz_levels *l)
|
|
473
709
|
{
|
|
474
|
-
|
|
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);
|
|
475
739
|
}
|
|
476
740
|
|
|
477
741
|
/* @overload __factorize_appearance__
|
|
@@ -491,11 +755,13 @@ fz_levels_free (fz_levels *l)
|
|
|
491
755
|
(row-major flatten) order.
|
|
492
756
|
*/
|
|
493
757
|
static VALUE
|
|
494
|
-
|
|
758
|
+
fz_factorize_appearance_body (VALUE arg)
|
|
495
759
|
{
|
|
760
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
761
|
+
VALUE self = fr->self;
|
|
496
762
|
CArray *ca;
|
|
497
763
|
volatile VALUE face;
|
|
498
|
-
self = fz_face_descend(self, &face);
|
|
764
|
+
self = fz_face_descend(self, &face, "categorize");
|
|
499
765
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
500
766
|
|
|
501
767
|
int8_t dt = ca->data_type;
|
|
@@ -526,11 +792,11 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
526
792
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
527
793
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
528
794
|
else { fz_hash_init(&h); }
|
|
529
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
795
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
530
796
|
|
|
531
797
|
int8_t axis = (int8_t) (ca->ndim - 1); /* innermost fiber = row-major flatten */
|
|
532
798
|
|
|
533
|
-
ca_iter_state st_in, st_out;
|
|
799
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
534
800
|
char *p_in, *p_out;
|
|
535
801
|
boolean8_t *m;
|
|
536
802
|
ca_size_t n;
|
|
@@ -552,25 +818,18 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
552
818
|
} while (0)
|
|
553
819
|
|
|
554
820
|
/* Float lane: reproduce `==` with two value-based exceptions matching the
|
|
555
|
-
discovery family -- all NaN collapse to one canonical key (
|
|
821
|
+
discovery family -- all NaN collapse to one canonical key (FZ_FLOAT_KEY),
|
|
556
822
|
and -0.0 == +0.0 (a zero normalizes to +0.0 before the bitwise key). The
|
|
557
823
|
level pushed is the raw first-seen element (an appearance-first NaN / -0.0 is
|
|
558
824
|
kept as-is), so masked source cells store the sentinel. */
|
|
559
|
-
#define FZ_LOOP_FLOAT(T
|
|
825
|
+
#define FZ_LOOP_FLOAT(T) \
|
|
560
826
|
do { \
|
|
561
827
|
const T *ip = (const T *) p_in; \
|
|
562
828
|
uint32_t *op = (uint32_t *) p_out; \
|
|
563
829
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
564
830
|
if ( m && m[i] ) { op[i] = 0xFFFFFFFFu; continue; } \
|
|
565
831
|
T v = ip[i]; \
|
|
566
|
-
uint64_t key;
|
|
567
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
568
|
-
else { \
|
|
569
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
570
|
-
UINT bits; \
|
|
571
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
572
|
-
key = (uint64_t) bits; \
|
|
573
|
-
} \
|
|
832
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
574
833
|
int is_new; \
|
|
575
834
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
576
835
|
if ( is_new ) { fz_levels_push(&lv, &ip[i]); } \
|
|
@@ -609,7 +868,7 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
609
868
|
} \
|
|
610
869
|
} while (0)
|
|
611
870
|
|
|
612
|
-
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,
|
|
613
872
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
614
873
|
switch ( dt ) {
|
|
615
874
|
case CA_INT8: FZ_LOOP(int8_t, (int64_t)); break;
|
|
@@ -620,8 +879,8 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
620
879
|
case CA_UINT16: FZ_LOOP(uint16_t, (uint64_t)); break;
|
|
621
880
|
case CA_UINT32: FZ_LOOP(uint32_t, (uint64_t)); break;
|
|
622
881
|
case CA_UINT64: FZ_LOOP(uint64_t, (uint64_t)); break;
|
|
623
|
-
case CA_FLOAT32: FZ_LOOP_FLOAT(float
|
|
624
|
-
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;
|
|
625
884
|
case CA_OBJECT: FZ_LOOP_OBJ; break;
|
|
626
885
|
case CA_FIXLEN: FZ_LOOP_MEM; break;
|
|
627
886
|
}
|
|
@@ -680,6 +939,12 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
680
939
|
return rb_ary_new3(2, vcodes, fz_face_relift(vlev, face));
|
|
681
940
|
}
|
|
682
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
|
+
|
|
683
948
|
/* @overload __mask_duplicates__(axis)
|
|
684
949
|
|
|
685
950
|
INTERNAL (mask_duplicates). Mark each cell whose value duplicates an
|
|
@@ -700,8 +965,11 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
700
965
|
value (so the second and later NaN are duplicates, as in the numeric lane).
|
|
701
966
|
*/
|
|
702
967
|
static VALUE
|
|
703
|
-
|
|
968
|
+
fz_mask_duplicates_body (VALUE arg)
|
|
704
969
|
{
|
|
970
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
971
|
+
VALUE self = fr->self;
|
|
972
|
+
VALUE vaxis = fr->a;
|
|
705
973
|
CArray *ca;
|
|
706
974
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
707
975
|
|
|
@@ -735,7 +1003,7 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
735
1003
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
736
1004
|
else { fz_hash_init(&h); }
|
|
737
1005
|
|
|
738
|
-
ca_iter_state st_in, st_out;
|
|
1006
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
739
1007
|
char *p_in, *p_out;
|
|
740
1008
|
boolean8_t *m;
|
|
741
1009
|
ca_size_t n;
|
|
@@ -758,24 +1026,17 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
758
1026
|
|
|
759
1027
|
/* Float variant: reproduce `==` with two value-based exceptions so the
|
|
760
1028
|
distinct-value judgement matches uniq / the discovery family. All NaN
|
|
761
|
-
collapse to one canonical key (
|
|
1029
|
+
collapse to one canonical key (FZ_FLOAT_KEY), so the second and later
|
|
762
1030
|
NaN in a fiber are duplicates; -0.0 == +0.0, so a zero normalizes to +0.0
|
|
763
1031
|
before the bitwise key. */
|
|
764
|
-
#define MD_LOOP_FLOAT(T
|
|
1032
|
+
#define MD_LOOP_FLOAT(T) \
|
|
765
1033
|
do { \
|
|
766
1034
|
const T *ip = (const T *) p_in; \
|
|
767
1035
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
768
1036
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
769
1037
|
if ( m && m[i] ) { op[i] = 0; continue; } \
|
|
770
1038
|
T v = ip[i]; \
|
|
771
|
-
uint64_t key;
|
|
772
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
773
|
-
else { \
|
|
774
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
775
|
-
UINT bits; \
|
|
776
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
777
|
-
key = (uint64_t) bits; \
|
|
778
|
-
} \
|
|
1039
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
779
1040
|
int is_new; \
|
|
780
1041
|
fz_hash_intern(&h, key, &is_new); \
|
|
781
1042
|
op[i] = is_new ? 0 : 1; \
|
|
@@ -808,7 +1069,7 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
808
1069
|
} \
|
|
809
1070
|
} while (0)
|
|
810
1071
|
|
|
811
|
-
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,
|
|
812
1073
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
813
1074
|
fz_hash_reset(&h); /* independent seen-set per fiber */
|
|
814
1075
|
switch ( dt ) {
|
|
@@ -820,8 +1081,8 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
820
1081
|
case CA_UINT16: MD_LOOP(uint16_t, (uint64_t)); break;
|
|
821
1082
|
case CA_UINT32: MD_LOOP(uint32_t, (uint64_t)); break;
|
|
822
1083
|
case CA_UINT64: MD_LOOP(uint64_t, (uint64_t)); break;
|
|
823
|
-
case CA_FLOAT32: MD_LOOP_FLOAT(float
|
|
824
|
-
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;
|
|
825
1086
|
case CA_OBJECT: MD_LOOP_OBJ; break;
|
|
826
1087
|
case CA_FIXLEN: MD_LOOP_MEM; break;
|
|
827
1088
|
}
|
|
@@ -835,6 +1096,12 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
835
1096
|
return vout;
|
|
836
1097
|
}
|
|
837
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
|
+
|
|
838
1105
|
/* @overload __unique_flat__
|
|
839
1106
|
|
|
840
1107
|
INTERNAL (CArray#unique). Collect the distinct values of self in
|
|
@@ -859,11 +1126,13 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
859
1126
|
uniform-width binary cells the fixlen seen-set used.
|
|
860
1127
|
*/
|
|
861
1128
|
static VALUE
|
|
862
|
-
|
|
1129
|
+
fz_unique_flat_body (VALUE arg)
|
|
863
1130
|
{
|
|
1131
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1132
|
+
VALUE self = fr->self;
|
|
864
1133
|
CArray *ca;
|
|
865
1134
|
volatile VALUE face;
|
|
866
|
-
self = fz_face_descend(self, &face);
|
|
1135
|
+
self = fz_face_descend(self, &face, "unique");
|
|
867
1136
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
868
1137
|
|
|
869
1138
|
int8_t dt = ca->data_type;
|
|
@@ -887,11 +1156,11 @@ rb_ca_unique_flat (VALUE self)
|
|
|
887
1156
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
888
1157
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
889
1158
|
else { fz_hash_init(&h); }
|
|
890
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1159
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
891
1160
|
|
|
892
1161
|
int8_t axis = (int8_t) (ca->ndim - 1); /* innermost fiber; hash not reset =
|
|
893
1162
|
one seen-set over the whole array */
|
|
894
|
-
ca_iter_state st_in;
|
|
1163
|
+
ca_iter_state *st_in = &fr->st[0];
|
|
895
1164
|
char *p_in;
|
|
896
1165
|
boolean8_t *m;
|
|
897
1166
|
ca_size_t n;
|
|
@@ -910,20 +1179,13 @@ rb_ca_unique_flat (VALUE self)
|
|
|
910
1179
|
|
|
911
1180
|
/* Float: NaN collapses to one canonical key; -0.0 / +0.0 share a key. The
|
|
912
1181
|
pushed level is the raw first-seen element. */
|
|
913
|
-
#define UQ_LOOP_FLOAT(T
|
|
1182
|
+
#define UQ_LOOP_FLOAT(T) \
|
|
914
1183
|
do { \
|
|
915
1184
|
const T *ip = (const T *) p_in; \
|
|
916
1185
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
917
1186
|
if ( m && m[i] ) { continue; } \
|
|
918
1187
|
T v = ip[i]; \
|
|
919
|
-
uint64_t key;
|
|
920
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
921
|
-
else { \
|
|
922
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
923
|
-
UINT bits; \
|
|
924
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
925
|
-
key = (uint64_t) bits; \
|
|
926
|
-
} \
|
|
1188
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
927
1189
|
int is_new; \
|
|
928
1190
|
fz_hash_intern(&h, key, &is_new); \
|
|
929
1191
|
if ( is_new ) { fz_levels_push(&lv, &ip[i]); } \
|
|
@@ -958,7 +1220,7 @@ rb_ca_unique_flat (VALUE self)
|
|
|
958
1220
|
} \
|
|
959
1221
|
} while (0)
|
|
960
1222
|
|
|
961
|
-
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) {
|
|
962
1224
|
switch ( dt ) {
|
|
963
1225
|
case CA_INT8: UQ_LOOP(int8_t, (int64_t)); break;
|
|
964
1226
|
case CA_INT16: UQ_LOOP(int16_t, (int64_t)); break;
|
|
@@ -968,8 +1230,8 @@ rb_ca_unique_flat (VALUE self)
|
|
|
968
1230
|
case CA_UINT16: UQ_LOOP(uint16_t, (uint64_t)); break;
|
|
969
1231
|
case CA_UINT32: UQ_LOOP(uint32_t, (uint64_t)); break;
|
|
970
1232
|
case CA_UINT64: UQ_LOOP(uint64_t, (uint64_t)); break;
|
|
971
|
-
case CA_FLOAT32: UQ_LOOP_FLOAT(float
|
|
972
|
-
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;
|
|
973
1235
|
case CA_OBJECT: UQ_LOOP_OBJ; break;
|
|
974
1236
|
case CA_FIXLEN: UQ_LOOP_MEM; break;
|
|
975
1237
|
}
|
|
@@ -996,6 +1258,12 @@ rb_ca_unique_flat (VALUE self)
|
|
|
996
1258
|
return fz_face_relift(vlev, face); /* distinct *values*: give the Face back */
|
|
997
1259
|
}
|
|
998
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
|
+
|
|
999
1267
|
/* Intern every non-masked cell of cv into h, one seen-set over the whole array
|
|
1000
1268
|
(the hash is not reset between fibers). When lv is non-NULL, the first-seen
|
|
1001
1269
|
raw element of each distinct value is pushed to it (appearance order), so the
|
|
@@ -1005,11 +1273,10 @@ rb_ca_unique_flat (VALUE self)
|
|
|
1005
1273
|
fixlen byte-hash + memcmp. Used to build the probe set (is_in, set relations)
|
|
1006
1274
|
and to accumulate distinct values (union). */
|
|
1007
1275
|
static void
|
|
1008
|
-
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)
|
|
1009
1277
|
{
|
|
1010
1278
|
int8_t dt = cv->data_type;
|
|
1011
1279
|
int8_t vaxis = (int8_t) (cv->ndim - 1);
|
|
1012
|
-
ca_iter_state st_v;
|
|
1013
1280
|
char *p_v;
|
|
1014
1281
|
boolean8_t *mv;
|
|
1015
1282
|
ca_size_t nv;
|
|
@@ -1026,20 +1293,13 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1026
1293
|
} \
|
|
1027
1294
|
} while (0)
|
|
1028
1295
|
|
|
1029
|
-
#define FZ_IA_FLOAT(T
|
|
1296
|
+
#define FZ_IA_FLOAT(T) \
|
|
1030
1297
|
do { \
|
|
1031
1298
|
const T *ip = (const T *) p_v; \
|
|
1032
1299
|
for ( ca_size_t i = 0; i < nv; i++ ) { \
|
|
1033
1300
|
if ( mv && mv[i] ) { continue; } \
|
|
1034
1301
|
T v = ip[i]; \
|
|
1035
|
-
uint64_t key;
|
|
1036
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1037
|
-
else { \
|
|
1038
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1039
|
-
UINT bits; \
|
|
1040
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1041
|
-
key = (uint64_t) bits; \
|
|
1042
|
-
} \
|
|
1302
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1043
1303
|
int is_new; \
|
|
1044
1304
|
fz_hash_intern(h, key, &is_new); \
|
|
1045
1305
|
if ( is_new && lv ) { fz_levels_push(lv, &ip[i]); } \
|
|
@@ -1069,7 +1329,7 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1069
1329
|
} \
|
|
1070
1330
|
} while (0)
|
|
1071
1331
|
|
|
1072
|
-
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) {
|
|
1073
1333
|
switch ( dt ) {
|
|
1074
1334
|
case CA_INT8: FZ_IA(int8_t, (int64_t)); break;
|
|
1075
1335
|
case CA_INT16: FZ_IA(int16_t, (int64_t)); break;
|
|
@@ -1079,8 +1339,8 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1079
1339
|
case CA_UINT16: FZ_IA(uint16_t, (uint64_t)); break;
|
|
1080
1340
|
case CA_UINT32: FZ_IA(uint32_t, (uint64_t)); break;
|
|
1081
1341
|
case CA_UINT64: FZ_IA(uint64_t, (uint64_t)); break;
|
|
1082
|
-
case CA_FLOAT32: FZ_IA_FLOAT(float
|
|
1083
|
-
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;
|
|
1084
1344
|
case CA_OBJECT: FZ_IA_OBJ; break;
|
|
1085
1345
|
case CA_FIXLEN: FZ_IA_MEM; break;
|
|
1086
1346
|
}
|
|
@@ -1109,11 +1369,14 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1109
1369
|
fixlen byte equality (byte-hash + memcmp).
|
|
1110
1370
|
*/
|
|
1111
1371
|
static VALUE
|
|
1112
|
-
|
|
1372
|
+
fz_is_in_body (VALUE arg)
|
|
1113
1373
|
{
|
|
1374
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1375
|
+
VALUE self = fr->self;
|
|
1376
|
+
VALUE rvalues = fr->a;
|
|
1114
1377
|
CArray *ca, *cv;
|
|
1115
1378
|
volatile VALUE face;
|
|
1116
|
-
self = fz_face_descend(self, &face);
|
|
1379
|
+
self = fz_face_descend(self, &face, "is_in");
|
|
1117
1380
|
rvalues = fz_face_reconcile(face, rvalues, "is_in");
|
|
1118
1381
|
GetCArray(self, ca);
|
|
1119
1382
|
|
|
@@ -1137,9 +1400,16 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1137
1400
|
rb_raise(rb_eArgError, "__is_in__: values must be a CArray");
|
|
1138
1401
|
}
|
|
1139
1402
|
GetCArray(rvalues, cv);
|
|
1140
|
-
if ( cv->data_type != dt
|
|
1403
|
+
if ( cv->data_type != dt ) {
|
|
1141
1404
|
rb_raise(rb_eCADataTypeError,
|
|
1142
|
-
"
|
|
1405
|
+
"is_in: values data type (%s) must match self (%s)",
|
|
1406
|
+
ca_type_name[cv->data_type], ca_type_name[dt]);
|
|
1407
|
+
}
|
|
1408
|
+
if ( dt == CA_FIXLEN && cv->bytes != ca->bytes ) {
|
|
1409
|
+
rb_raise(rb_eCADataTypeError,
|
|
1410
|
+
"is_in: a fixlen value is a cell-width blob, so the values "
|
|
1411
|
+
"must be %ld bytes wide like self, not %ld",
|
|
1412
|
+
(long) ca->bytes, (long) cv->bytes);
|
|
1143
1413
|
}
|
|
1144
1414
|
if ( cv->ndim < 1 ) {
|
|
1145
1415
|
rb_raise(rb_eRuntimeError, "__is_in__: values need ndim >= 1");
|
|
@@ -1151,14 +1421,14 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1151
1421
|
else { fz_hash_init(&h); }
|
|
1152
1422
|
|
|
1153
1423
|
/* ---- Phase 1: build the seen-set from every non-masked cell of `values`. */
|
|
1154
|
-
fz_intern_all(&h, cv, NULL);
|
|
1424
|
+
fz_intern_all(&fr->st[2], &h, cv, NULL);
|
|
1155
1425
|
|
|
1156
1426
|
/* ---- Phase 2: probe every cell of self, writing the boolean membership. */
|
|
1157
1427
|
VALUE vout = rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
1158
1428
|
CArray *cout;
|
|
1159
1429
|
GetCArray(vout, cout);
|
|
1160
1430
|
{
|
|
1161
|
-
ca_iter_state st_in, st_out;
|
|
1431
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
1162
1432
|
char *p_in, *p_out;
|
|
1163
1433
|
boolean8_t *m;
|
|
1164
1434
|
ca_size_t n;
|
|
@@ -1175,21 +1445,14 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1175
1445
|
} \
|
|
1176
1446
|
} while (0)
|
|
1177
1447
|
|
|
1178
|
-
#define IN_PROBE_FLOAT(T
|
|
1448
|
+
#define IN_PROBE_FLOAT(T) \
|
|
1179
1449
|
do { \
|
|
1180
1450
|
const T *ip = (const T *) p_in; \
|
|
1181
1451
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
1182
1452
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1183
1453
|
if ( m && m[i] ) { op[i] = 0; continue; } \
|
|
1184
1454
|
T v = ip[i]; \
|
|
1185
|
-
uint64_t key;
|
|
1186
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1187
|
-
else { \
|
|
1188
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1189
|
-
UINT bits; \
|
|
1190
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1191
|
-
key = (uint64_t) bits; \
|
|
1192
|
-
} \
|
|
1455
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1193
1456
|
op[i] = (boolean8_t) fz_hash_lookup(&h, key, NULL); \
|
|
1194
1457
|
} \
|
|
1195
1458
|
} while (0)
|
|
@@ -1214,7 +1477,7 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1214
1477
|
} \
|
|
1215
1478
|
} while (0)
|
|
1216
1479
|
|
|
1217
|
-
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,
|
|
1218
1481
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
1219
1482
|
switch ( dt ) {
|
|
1220
1483
|
case CA_INT8: IN_PROBE(int8_t, (int64_t)); break;
|
|
@@ -1225,8 +1488,8 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1225
1488
|
case CA_UINT16: IN_PROBE(uint16_t, (uint64_t)); break;
|
|
1226
1489
|
case CA_UINT32: IN_PROBE(uint32_t, (uint64_t)); break;
|
|
1227
1490
|
case CA_UINT64: IN_PROBE(uint64_t, (uint64_t)); break;
|
|
1228
|
-
case CA_FLOAT32: IN_PROBE_FLOAT(float
|
|
1229
|
-
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;
|
|
1230
1493
|
case CA_OBJECT: IN_PROBE_OBJ; break;
|
|
1231
1494
|
case CA_FIXLEN: IN_PROBE_MEM; break;
|
|
1232
1495
|
}
|
|
@@ -1246,6 +1509,12 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1246
1509
|
return vout;
|
|
1247
1510
|
}
|
|
1248
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
|
+
|
|
1249
1518
|
/* @overload __locate_addr__(ref)
|
|
1250
1519
|
|
|
1251
1520
|
INTERNAL (CArray#locate_addr, exact hash lane). For each cell of self, the
|
|
@@ -1263,15 +1532,18 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1263
1532
|
appearance order (matching the discovery family); on a `ref` with duplicate
|
|
1264
1533
|
values this is the earliest address, which can differ from the bsearch lane. */
|
|
1265
1534
|
static VALUE
|
|
1266
|
-
|
|
1535
|
+
fz_locate_addr_body (VALUE arg)
|
|
1267
1536
|
{
|
|
1537
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1538
|
+
VALUE self = fr->self;
|
|
1539
|
+
VALUE rref = fr->a;
|
|
1268
1540
|
CArray *ca, *cr;
|
|
1269
1541
|
/* Here the *reference* is the argument (self is the query being placed on
|
|
1270
1542
|
rref), so the gate runs the other way round: rref reconciles self. The
|
|
1271
1543
|
output is an address, so nothing is lifted back. */
|
|
1272
1544
|
{
|
|
1273
1545
|
volatile VALUE ref_face;
|
|
1274
|
-
rref = fz_face_descend(rref, &ref_face);
|
|
1546
|
+
rref = fz_face_descend(rref, &ref_face, "locate_addr");
|
|
1275
1547
|
self = fz_face_reconcile(ref_face, self, "locate_addr");
|
|
1276
1548
|
}
|
|
1277
1549
|
GetCArray(self, ca);
|
|
@@ -1295,9 +1567,16 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1295
1567
|
rb_raise(rb_eArgError, "__locate_addr__: ref must be a CArray");
|
|
1296
1568
|
}
|
|
1297
1569
|
GetCArray(rref, cr);
|
|
1298
|
-
if ( cr->data_type != dt
|
|
1570
|
+
if ( cr->data_type != dt ) {
|
|
1299
1571
|
rb_raise(rb_eCADataTypeError,
|
|
1300
|
-
"
|
|
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);
|
|
1301
1580
|
}
|
|
1302
1581
|
if ( cr->ndim < 1 ) {
|
|
1303
1582
|
rb_raise(rb_eRuntimeError, "__locate_addr__: ref need ndim >= 1");
|
|
@@ -1312,11 +1591,11 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1312
1591
|
the ref value carrying dense code `code`. Codes are assigned 0,1,2,... in
|
|
1313
1592
|
insertion order, so pushing on is_new fills addr.p in code order. */
|
|
1314
1593
|
fz_levels addr;
|
|
1315
|
-
fz_levels_init(&addr, (int) sizeof(int64_t));
|
|
1594
|
+
fz_levels_init(&addr, (int) sizeof(int64_t), 0);
|
|
1316
1595
|
|
|
1317
1596
|
/* ---- Phase 1: build value -> first-address map from ref (row-major). ----- */
|
|
1318
1597
|
{
|
|
1319
|
-
ca_iter_state st_r;
|
|
1598
|
+
ca_iter_state *st_r = &fr->st[0];
|
|
1320
1599
|
char *p_r;
|
|
1321
1600
|
boolean8_t *mr;
|
|
1322
1601
|
ca_size_t nr;
|
|
@@ -1336,20 +1615,13 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1336
1615
|
} \
|
|
1337
1616
|
} while (0)
|
|
1338
1617
|
|
|
1339
|
-
#define LOC_BUILD_FLOAT(T
|
|
1618
|
+
#define LOC_BUILD_FLOAT(T) \
|
|
1340
1619
|
do { \
|
|
1341
1620
|
const T *ip = (const T *) p_r; \
|
|
1342
1621
|
for ( ca_size_t i = 0; i < nr; i++ ) { \
|
|
1343
1622
|
if ( mr && mr[i] ) { continue; } \
|
|
1344
1623
|
T v = ip[i]; \
|
|
1345
|
-
uint64_t key;
|
|
1346
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1347
|
-
else { \
|
|
1348
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1349
|
-
UINT bits; \
|
|
1350
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1351
|
-
key = (uint64_t) bits; \
|
|
1352
|
-
} \
|
|
1624
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1353
1625
|
int is_new; \
|
|
1354
1626
|
fz_hash_intern(&h, key, &is_new); \
|
|
1355
1627
|
if ( is_new ) { int64_t a = (int64_t) (base + i); \
|
|
@@ -1381,7 +1653,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1381
1653
|
} \
|
|
1382
1654
|
} while (0)
|
|
1383
1655
|
|
|
1384
|
-
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) {
|
|
1385
1657
|
switch ( dt ) {
|
|
1386
1658
|
case CA_INT8: LOC_BUILD(int8_t, (int64_t)); break;
|
|
1387
1659
|
case CA_INT16: LOC_BUILD(int16_t, (int64_t)); break;
|
|
@@ -1391,8 +1663,8 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1391
1663
|
case CA_UINT16: LOC_BUILD(uint16_t, (uint64_t)); break;
|
|
1392
1664
|
case CA_UINT32: LOC_BUILD(uint32_t, (uint64_t)); break;
|
|
1393
1665
|
case CA_UINT64: LOC_BUILD(uint64_t, (uint64_t)); break;
|
|
1394
|
-
case CA_FLOAT32: LOC_BUILD_FLOAT(float
|
|
1395
|
-
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;
|
|
1396
1668
|
case CA_OBJECT: LOC_BUILD_OBJ; break;
|
|
1397
1669
|
case CA_FIXLEN: LOC_BUILD_MEM; break;
|
|
1398
1670
|
}
|
|
@@ -1409,10 +1681,11 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1409
1681
|
CArray *cout;
|
|
1410
1682
|
GetCArray(vout, cout);
|
|
1411
1683
|
int64_t *out = (int64_t *) cout->ptr;
|
|
1412
|
-
|
|
1684
|
+
volatile VALUE hum = 0;
|
|
1685
|
+
boolean8_t *um = ALLOCV_N(boolean8_t, hum, ca->elements); /* undef flags scratch */
|
|
1413
1686
|
ca_size_t n_undef = 0;
|
|
1414
1687
|
{
|
|
1415
|
-
ca_iter_state st_in;
|
|
1688
|
+
ca_iter_state *st_in = &fr->st[1];
|
|
1416
1689
|
char *p_in;
|
|
1417
1690
|
boolean8_t *m;
|
|
1418
1691
|
ca_size_t n;
|
|
@@ -1433,7 +1706,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1433
1706
|
} \
|
|
1434
1707
|
} while (0)
|
|
1435
1708
|
|
|
1436
|
-
#define LOC_PROBE_FLOAT(T
|
|
1709
|
+
#define LOC_PROBE_FLOAT(T) \
|
|
1437
1710
|
do { \
|
|
1438
1711
|
const T *ip = (const T *) p_in; \
|
|
1439
1712
|
const int64_t *ab = (const int64_t *) addr.p; \
|
|
@@ -1441,14 +1714,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1441
1714
|
ca_size_t o = base + i; \
|
|
1442
1715
|
if ( m && m[i] ) { out[o] = 0; um[o] = 1; n_undef++; continue; } \
|
|
1443
1716
|
T v = ip[i]; \
|
|
1444
|
-
uint64_t key;
|
|
1445
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1446
|
-
else { \
|
|
1447
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1448
|
-
UINT bits; \
|
|
1449
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1450
|
-
key = (uint64_t) bits; \
|
|
1451
|
-
} \
|
|
1717
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1452
1718
|
int32_t code; \
|
|
1453
1719
|
if ( fz_hash_lookup(&h, key, &code) ) { out[o] = ab[code]; um[o] = 0; } \
|
|
1454
1720
|
else { out[o] = 0; um[o] = 1; n_undef++; } \
|
|
@@ -1481,7 +1747,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1481
1747
|
} \
|
|
1482
1748
|
} while (0)
|
|
1483
1749
|
|
|
1484
|
-
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) {
|
|
1485
1751
|
switch ( dt ) {
|
|
1486
1752
|
case CA_INT8: LOC_PROBE(int8_t, (int64_t)); break;
|
|
1487
1753
|
case CA_INT16: LOC_PROBE(int16_t, (int64_t)); break;
|
|
@@ -1491,8 +1757,8 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1491
1757
|
case CA_UINT16: LOC_PROBE(uint16_t, (uint64_t)); break;
|
|
1492
1758
|
case CA_UINT32: LOC_PROBE(uint32_t, (uint64_t)); break;
|
|
1493
1759
|
case CA_UINT64: LOC_PROBE(uint64_t, (uint64_t)); break;
|
|
1494
|
-
case CA_FLOAT32: LOC_PROBE_FLOAT(float
|
|
1495
|
-
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;
|
|
1496
1762
|
case CA_OBJECT: LOC_PROBE_OBJ; break;
|
|
1497
1763
|
case CA_FIXLEN: LOC_PROBE_MEM; break;
|
|
1498
1764
|
}
|
|
@@ -1513,11 +1779,17 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1513
1779
|
ca_create_mask(cout);
|
|
1514
1780
|
memcpy(cout->mask->ptr, um, (size_t) ca->elements);
|
|
1515
1781
|
}
|
|
1516
|
-
|
|
1782
|
+
ALLOCV_END(hum);
|
|
1517
1783
|
|
|
1518
1784
|
return vout;
|
|
1519
1785
|
}
|
|
1520
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
|
+
|
|
1521
1793
|
/* Shared body of __intersection__ (keep_when_hit = 1) and __difference__
|
|
1522
1794
|
(keep_when_hit = 0): the distinct values of self that are (resp. are not)
|
|
1523
1795
|
present in `other`, in self's first-appearance order, as a 1-D CArray of
|
|
@@ -1527,11 +1799,15 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1527
1799
|
lane (numeric `==` + NaN collapse + -0.0 == +0.0, object hash/eql? + NaN
|
|
1528
1800
|
collapse, fixlen byte equality). */
|
|
1529
1801
|
static VALUE
|
|
1530
|
-
|
|
1802
|
+
fz_set_relation_body (VALUE arg)
|
|
1531
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;
|
|
1532
1808
|
CArray *ca, *co;
|
|
1533
1809
|
volatile VALUE face;
|
|
1534
|
-
self = fz_face_descend(self, &face);
|
|
1810
|
+
self = fz_face_descend(self, &face, "set relation");
|
|
1535
1811
|
rother = fz_face_reconcile(face, rother, "set relation");
|
|
1536
1812
|
GetCArray(self, ca);
|
|
1537
1813
|
|
|
@@ -1554,8 +1830,16 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1554
1830
|
rb_raise(rb_eArgError, "set relation: other must be a CArray");
|
|
1555
1831
|
}
|
|
1556
1832
|
GetCArray(rother, co);
|
|
1557
|
-
if ( co->data_type != dt
|
|
1558
|
-
rb_raise(rb_eCADataTypeError,
|
|
1833
|
+
if ( co->data_type != dt ) {
|
|
1834
|
+
rb_raise(rb_eCADataTypeError,
|
|
1835
|
+
"set relation: other data type (%s) must match self (%s)",
|
|
1836
|
+
ca_type_name[co->data_type], ca_type_name[dt]);
|
|
1837
|
+
}
|
|
1838
|
+
if ( dt == CA_FIXLEN && co->bytes != ca->bytes ) {
|
|
1839
|
+
rb_raise(rb_eCADataTypeError,
|
|
1840
|
+
"set relation: a fixlen value is a cell-width blob, so other "
|
|
1841
|
+
"must be %ld bytes wide like self, not %ld",
|
|
1842
|
+
(long) ca->bytes, (long) co->bytes);
|
|
1559
1843
|
}
|
|
1560
1844
|
if ( co->ndim < 1 ) {
|
|
1561
1845
|
rb_raise(rb_eRuntimeError, "set relation: other need ndim >= 1");
|
|
@@ -1573,15 +1857,15 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1573
1857
|
}
|
|
1574
1858
|
|
|
1575
1859
|
fz_levels lv;
|
|
1576
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1860
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1577
1861
|
|
|
1578
1862
|
/* Build the probe set from every non-masked cell of other. */
|
|
1579
|
-
fz_intern_all(&hoth, co, NULL);
|
|
1863
|
+
fz_intern_all(&fr->st[2], &hoth, co, NULL);
|
|
1580
1864
|
|
|
1581
1865
|
/* Walk self: hself dedups, so each distinct self value is decided once; keep
|
|
1582
1866
|
it when its membership in other equals keep_when_hit. */
|
|
1583
1867
|
int8_t axis = (int8_t) (ca->ndim - 1);
|
|
1584
|
-
ca_iter_state st;
|
|
1868
|
+
ca_iter_state *st = &fr->st[0];
|
|
1585
1869
|
char *p;
|
|
1586
1870
|
boolean8_t *m;
|
|
1587
1871
|
ca_size_t n;
|
|
@@ -1600,20 +1884,13 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1600
1884
|
} \
|
|
1601
1885
|
} while (0)
|
|
1602
1886
|
|
|
1603
|
-
#define SR_FLOAT(T
|
|
1887
|
+
#define SR_FLOAT(T) \
|
|
1604
1888
|
do { \
|
|
1605
1889
|
const T *ip = (const T *) p; \
|
|
1606
1890
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1607
1891
|
if ( m && m[i] ) { continue; } \
|
|
1608
1892
|
T v = ip[i]; \
|
|
1609
|
-
uint64_t key;
|
|
1610
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1611
|
-
else { \
|
|
1612
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1613
|
-
UINT bits; \
|
|
1614
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1615
|
-
key = (uint64_t) bits; \
|
|
1616
|
-
} \
|
|
1893
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1617
1894
|
int is_new; \
|
|
1618
1895
|
fz_hash_intern(&hself, key, &is_new); \
|
|
1619
1896
|
if ( is_new && fz_hash_lookup(&hoth, key, NULL) == keep_when_hit ) { \
|
|
@@ -1649,7 +1926,7 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1649
1926
|
} \
|
|
1650
1927
|
} while (0)
|
|
1651
1928
|
|
|
1652
|
-
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) {
|
|
1653
1930
|
switch ( dt ) {
|
|
1654
1931
|
case CA_INT8: SR(int8_t, (int64_t)); break;
|
|
1655
1932
|
case CA_INT16: SR(int16_t, (int64_t)); break;
|
|
@@ -1659,8 +1936,8 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1659
1936
|
case CA_UINT16: SR(uint16_t, (uint64_t)); break;
|
|
1660
1937
|
case CA_UINT32: SR(uint32_t, (uint64_t)); break;
|
|
1661
1938
|
case CA_UINT64: SR(uint64_t, (uint64_t)); break;
|
|
1662
|
-
case CA_FLOAT32: SR_FLOAT(float
|
|
1663
|
-
case CA_FLOAT64: SR_FLOAT(double
|
|
1939
|
+
case CA_FLOAT32: SR_FLOAT(float); break;
|
|
1940
|
+
case CA_FLOAT64: SR_FLOAT(double); break;
|
|
1664
1941
|
case CA_OBJECT: SR_OBJ; break;
|
|
1665
1942
|
case CA_FIXLEN: SR_MEM; break;
|
|
1666
1943
|
}
|
|
@@ -1687,6 +1964,12 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1687
1964
|
return fz_face_relift(vlev, face); /* set *values*: give the Face back */
|
|
1688
1965
|
}
|
|
1689
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
|
+
|
|
1690
1973
|
/* @overload __intersection__(other)
|
|
1691
1974
|
INTERNAL (CArray#intersection). 1-D CArray of the distinct values present in
|
|
1692
1975
|
both self and other, in self's first-appearance order. */
|
|
@@ -1712,11 +1995,14 @@ rb_ca_difference (VALUE self, VALUE rother)
|
|
|
1712
1995
|
distinct values first, then other's not-yet-seen ones). Masked cells of
|
|
1713
1996
|
either array do not participate. */
|
|
1714
1997
|
static VALUE
|
|
1715
|
-
|
|
1998
|
+
fz_set_union_body (VALUE arg)
|
|
1716
1999
|
{
|
|
2000
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2001
|
+
VALUE self = fr->self;
|
|
2002
|
+
VALUE rother = fr->a;
|
|
1717
2003
|
CArray *ca, *co;
|
|
1718
2004
|
volatile VALUE face;
|
|
1719
|
-
self = fz_face_descend(self, &face);
|
|
2005
|
+
self = fz_face_descend(self, &face, "union");
|
|
1720
2006
|
rother = fz_face_reconcile(face, rother, "union");
|
|
1721
2007
|
GetCArray(self, ca);
|
|
1722
2008
|
|
|
@@ -1739,8 +2025,16 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1739
2025
|
rb_raise(rb_eArgError, "__union__: other must be a CArray");
|
|
1740
2026
|
}
|
|
1741
2027
|
GetCArray(rother, co);
|
|
1742
|
-
if ( co->data_type != dt
|
|
1743
|
-
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);
|
|
1744
2038
|
}
|
|
1745
2039
|
if ( co->ndim < 1 ) {
|
|
1746
2040
|
rb_raise(rb_eRuntimeError, "__union__: other need ndim >= 1");
|
|
@@ -1752,10 +2046,10 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1752
2046
|
else { fz_hash_init(&h); }
|
|
1753
2047
|
|
|
1754
2048
|
fz_levels lv;
|
|
1755
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
2049
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1756
2050
|
|
|
1757
|
-
fz_intern_all(&h, ca, &lv); /* self's distinct values, appearance order */
|
|
1758
|
-
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 */
|
|
1759
2053
|
|
|
1760
2054
|
ca_size_t k = lv.n;
|
|
1761
2055
|
fz_hash_free(&h);
|
|
@@ -1773,6 +2067,12 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1773
2067
|
return fz_face_relift(vlev, face); /* set *values*: give the Face back */
|
|
1774
2068
|
}
|
|
1775
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
|
+
|
|
1776
2076
|
/* @overload __value_counts_flat__
|
|
1777
2077
|
|
|
1778
2078
|
INTERNAL (CArray#value_counts). Collect the distinct values of self in
|
|
@@ -1789,11 +2089,13 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1789
2089
|
collapses every Float NaN to one value (their counts add up, as numeric does).
|
|
1790
2090
|
*/
|
|
1791
2091
|
static VALUE
|
|
1792
|
-
|
|
2092
|
+
fz_value_counts_flat_body (VALUE arg)
|
|
1793
2093
|
{
|
|
2094
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2095
|
+
VALUE self = fr->self;
|
|
1794
2096
|
CArray *ca;
|
|
1795
2097
|
volatile VALUE face;
|
|
1796
|
-
self = fz_face_descend(self, &face);
|
|
2098
|
+
self = fz_face_descend(self, &face, "value_counts");
|
|
1797
2099
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1798
2100
|
|
|
1799
2101
|
int8_t dt = ca->data_type;
|
|
@@ -1818,11 +2120,11 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1818
2120
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
1819
2121
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
1820
2122
|
else { fz_hash_init(&h); }
|
|
1821
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1822
|
-
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);
|
|
1823
2125
|
|
|
1824
2126
|
int8_t axis = (int8_t) (ca->ndim - 1); /* one seen-set over the whole array */
|
|
1825
|
-
ca_iter_state st_in;
|
|
2127
|
+
ca_iter_state *st_in = &fr->st[0];
|
|
1826
2128
|
char *p_in;
|
|
1827
2129
|
boolean8_t *m;
|
|
1828
2130
|
ca_size_t n;
|
|
@@ -1845,20 +2147,13 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1845
2147
|
} \
|
|
1846
2148
|
} while (0)
|
|
1847
2149
|
|
|
1848
|
-
#define VC_LOOP_FLOAT(T
|
|
2150
|
+
#define VC_LOOP_FLOAT(T) \
|
|
1849
2151
|
do { \
|
|
1850
2152
|
const T *ip = (const T *) p_in; \
|
|
1851
2153
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1852
2154
|
if ( m && m[i] ) { continue; } \
|
|
1853
2155
|
T v = ip[i]; \
|
|
1854
|
-
uint64_t key;
|
|
1855
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
1856
|
-
else { \
|
|
1857
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
1858
|
-
UINT bits; \
|
|
1859
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
1860
|
-
key = (uint64_t) bits; \
|
|
1861
|
-
} \
|
|
2156
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1862
2157
|
int is_new; \
|
|
1863
2158
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
1864
2159
|
if ( is_new ) { \
|
|
@@ -1908,7 +2203,7 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1908
2203
|
} \
|
|
1909
2204
|
} while (0)
|
|
1910
2205
|
|
|
1911
|
-
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) {
|
|
1912
2207
|
switch ( dt ) {
|
|
1913
2208
|
case CA_INT8: VC_LOOP(int8_t, (int64_t)); break;
|
|
1914
2209
|
case CA_INT16: VC_LOOP(int16_t, (int64_t)); break;
|
|
@@ -1918,8 +2213,8 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1918
2213
|
case CA_UINT16: VC_LOOP(uint16_t, (uint64_t)); break;
|
|
1919
2214
|
case CA_UINT32: VC_LOOP(uint32_t, (uint64_t)); break;
|
|
1920
2215
|
case CA_UINT64: VC_LOOP(uint64_t, (uint64_t)); break;
|
|
1921
|
-
case CA_FLOAT32: VC_LOOP_FLOAT(float
|
|
1922
|
-
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;
|
|
1923
2218
|
case CA_OBJECT: VC_LOOP_OBJ; break;
|
|
1924
2219
|
case CA_FIXLEN: VC_LOOP_MEM; break;
|
|
1925
2220
|
}
|
|
@@ -1952,6 +2247,12 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1952
2247
|
return rb_ary_new3(2, fz_face_relift(vlev, face), vcnt);
|
|
1953
2248
|
}
|
|
1954
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
|
+
|
|
1955
2256
|
/* @overload __nunique__(axis, keep_axis)
|
|
1956
2257
|
|
|
1957
2258
|
INTERNAL (CArray#nunique). Count the distinct values along axis, one linear
|
|
@@ -1964,8 +2265,12 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1964
2265
|
Ruby Hash distinctness; the object lane also collapses every Float NaN to one.
|
|
1965
2266
|
*/
|
|
1966
2267
|
static VALUE
|
|
1967
|
-
|
|
2268
|
+
fz_nunique_body (VALUE arg)
|
|
1968
2269
|
{
|
|
2270
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2271
|
+
VALUE self = fr->self;
|
|
2272
|
+
VALUE vaxis = fr->a;
|
|
2273
|
+
VALUE vkeep = fr->b;
|
|
1969
2274
|
CArray *ca;
|
|
1970
2275
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1971
2276
|
|
|
@@ -2002,8 +2307,8 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2002
2307
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
2003
2308
|
else { fz_hash_init(&h); }
|
|
2004
2309
|
|
|
2005
|
-
ca_iter_state st;
|
|
2006
|
-
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);
|
|
2007
2312
|
if ( rc != CA_ITER_OK ) {
|
|
2008
2313
|
fz_hash_free(&h);
|
|
2009
2314
|
rb_raise(rb_eRuntimeError, "__nunique__: kernel_iterator init failed rc=%d", rc);
|
|
@@ -2019,17 +2324,10 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2019
2324
|
-0.0 before the bitwise key. */
|
|
2020
2325
|
#define NU_INT(WIDEN) \
|
|
2021
2326
|
do { int _n; fz_hash_intern(&h, (uint64_t) ((WIDEN) v), &_n); } while (0)
|
|
2022
|
-
#define NU_FLOAT(T
|
|
2327
|
+
#define NU_FLOAT(T) \
|
|
2023
2328
|
do { \
|
|
2024
2329
|
T _v = v; \
|
|
2025
|
-
uint64_t _key;
|
|
2026
|
-
if ( _v != _v ) { _key = (NANKEY); } \
|
|
2027
|
-
else { \
|
|
2028
|
-
if ( _v == (T) 0 ) { _v = (T) 0; } \
|
|
2029
|
-
UINT _b; \
|
|
2030
|
-
memcpy(&_b, &_v, sizeof(_b)); \
|
|
2031
|
-
_key = (uint64_t) _b; \
|
|
2032
|
-
} \
|
|
2330
|
+
uint64_t _key = FZ_FLOAT_KEY(T, _v); \
|
|
2033
2331
|
int _n; fz_hash_intern(&h, _key, &_n); \
|
|
2034
2332
|
} while (0)
|
|
2035
2333
|
/* Object: intern the VALUE via the object lane (v is bound by the macro). */
|
|
@@ -2041,43 +2339,43 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2041
2339
|
each esz-wide element via the fixlen lane. */
|
|
2042
2340
|
#define NU_MEM_WALK \
|
|
2043
2341
|
do { \
|
|
2044
|
-
int8_t K = st
|
|
2342
|
+
int8_t K = st->slab_ndim; \
|
|
2045
2343
|
ca_size_t idx[CA_RANK_MAX] = { 0 }; \
|
|
2046
|
-
ca_size_t total = st
|
|
2344
|
+
ca_size_t total = st->slab_elements; \
|
|
2047
2345
|
for ( ca_size_t e = 0; e < total; e++ ) { \
|
|
2048
2346
|
ca_size_t doff = 0, moff = 0; \
|
|
2049
2347
|
for ( int8_t kk = 0; kk < K; kk++ ) { \
|
|
2050
|
-
doff += idx[kk] * st
|
|
2051
|
-
moff += idx[kk] * st
|
|
2348
|
+
doff += idx[kk] * st->slab_strides[kk]; \
|
|
2349
|
+
moff += idx[kk] * st->slab_mask_strides[kk]; \
|
|
2052
2350
|
} \
|
|
2053
2351
|
if ( ! (m && m[moff]) ) { \
|
|
2054
2352
|
int _n; fz_hash_intern_mem(&h, p + doff, &_n); \
|
|
2055
2353
|
} \
|
|
2056
2354
|
for ( int8_t kk = (int8_t)(K - 1); kk >= 0; kk-- ) { \
|
|
2057
|
-
if ( ++idx[kk] < st
|
|
2355
|
+
if ( ++idx[kk] < st->slab_dims[kk] ) break; \
|
|
2058
2356
|
idx[kk] = 0; \
|
|
2059
2357
|
} \
|
|
2060
2358
|
} \
|
|
2061
2359
|
} while (0)
|
|
2062
2360
|
|
|
2063
|
-
while ( ca_iter_state_next_slab_axes(
|
|
2361
|
+
while ( ca_iter_state_next_slab_axes(st, &p, &m) ) {
|
|
2064
2362
|
fz_hash_reset(&h); /* independent seen-set per fiber */
|
|
2065
2363
|
switch ( dt ) {
|
|
2066
|
-
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2067
|
-
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2068
|
-
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2069
|
-
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2070
|
-
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2071
|
-
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2072
|
-
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2073
|
-
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;
|
|
2074
2372
|
case CA_FLOAT32:
|
|
2075
|
-
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));
|
|
2076
2374
|
break;
|
|
2077
2375
|
case CA_FLOAT64:
|
|
2078
|
-
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));
|
|
2079
2377
|
break;
|
|
2080
|
-
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;
|
|
2081
2379
|
case CA_FIXLEN: NU_MEM_WALK; break;
|
|
2082
2380
|
}
|
|
2083
2381
|
op[out_i++] = (int64_t) h.n;
|
|
@@ -2088,11 +2386,17 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2088
2386
|
#undef NU_MEM_WALK
|
|
2089
2387
|
(void) dummy;
|
|
2090
2388
|
|
|
2091
|
-
ca_iter_state_finish(
|
|
2389
|
+
ca_iter_state_finish(st);
|
|
2092
2390
|
fz_hash_free(&h);
|
|
2093
2391
|
return vout;
|
|
2094
2392
|
}
|
|
2095
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
|
+
|
|
2096
2400
|
/* @overload __is_mode__(axis)
|
|
2097
2401
|
|
|
2098
2402
|
INTERNAL (CArray#is_mode). Mark each cell that holds a modal value along axis
|
|
@@ -2111,8 +2415,11 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2111
2415
|
Callers pass flat input by flattening first (a single fiber over axis 0).
|
|
2112
2416
|
*/
|
|
2113
2417
|
static VALUE
|
|
2114
|
-
|
|
2418
|
+
fz_is_mode_body (VALUE arg)
|
|
2115
2419
|
{
|
|
2420
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2421
|
+
VALUE self = fr->self;
|
|
2422
|
+
VALUE vaxis = fr->a;
|
|
2116
2423
|
CArray *ca;
|
|
2117
2424
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2118
2425
|
|
|
@@ -2145,9 +2452,9 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2145
2452
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
2146
2453
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
2147
2454
|
else { fz_hash_init(&h); }
|
|
2148
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2455
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
2149
2456
|
|
|
2150
|
-
ca_iter_state st_in, st_out;
|
|
2457
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
2151
2458
|
char *p_in, *p_out;
|
|
2152
2459
|
boolean8_t *m;
|
|
2153
2460
|
ca_size_t n;
|
|
@@ -2180,7 +2487,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2180
2487
|
} while (0)
|
|
2181
2488
|
|
|
2182
2489
|
/* Float: NaN collapses to one canonical key; -0.0 / +0.0 share a key. */
|
|
2183
|
-
#define IM_BODY_FLOAT(T
|
|
2490
|
+
#define IM_BODY_FLOAT(T) \
|
|
2184
2491
|
do { \
|
|
2185
2492
|
const T *ip = (const T *) p_in; \
|
|
2186
2493
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
@@ -2195,14 +2502,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2195
2502
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
2196
2503
|
if ( m && m[i] ) { if ( pass == 1 ) { op[i] = 0; } continue; } \
|
|
2197
2504
|
T v = ip[i]; \
|
|
2198
|
-
uint64_t key;
|
|
2199
|
-
if ( v != v ) { key = (NANKEY); } \
|
|
2200
|
-
else { \
|
|
2201
|
-
if ( v == (T) 0 ) { v = (T) 0; } \
|
|
2202
|
-
UINT bits; \
|
|
2203
|
-
memcpy(&bits, &v, sizeof(bits)); \
|
|
2204
|
-
key = (uint64_t) bits; \
|
|
2205
|
-
} \
|
|
2505
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
2206
2506
|
int is_new; \
|
|
2207
2507
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
2208
2508
|
if ( pass == 0 ) { \
|
|
@@ -2266,7 +2566,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2266
2566
|
} \
|
|
2267
2567
|
} while (0)
|
|
2268
2568
|
|
|
2269
|
-
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,
|
|
2270
2570
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
2271
2571
|
fz_hash_reset(&h); /* independent frequency table per fiber */
|
|
2272
2572
|
ct.n = 0;
|
|
@@ -2279,8 +2579,8 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2279
2579
|
case CA_UINT16: IM_BODY(uint16_t, (uint64_t)); break;
|
|
2280
2580
|
case CA_UINT32: IM_BODY(uint32_t, (uint64_t)); break;
|
|
2281
2581
|
case CA_UINT64: IM_BODY(uint64_t, (uint64_t)); break;
|
|
2282
|
-
case CA_FLOAT32: IM_BODY_FLOAT(float
|
|
2283
|
-
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;
|
|
2284
2584
|
case CA_OBJECT: IM_BODY_OBJ; break;
|
|
2285
2585
|
case CA_FIXLEN: IM_BODY_MEM; break;
|
|
2286
2586
|
}
|
|
@@ -2295,6 +2595,12 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2295
2595
|
return vout;
|
|
2296
2596
|
}
|
|
2297
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
|
+
|
|
2298
2604
|
/* Ascending comparison for the modal-value sort, NaN ordered last so a
|
|
2299
2605
|
collapsed NaN key (at most one per fiber) trails the real values, matching
|
|
2300
2606
|
CArray#sort. */
|
|
@@ -2328,11 +2634,14 @@ static int mode_gt_f64 (double a, double b) { if ( a != a ) return b == b; if (
|
|
|
2328
2634
|
its sign), matching the discovery family.
|
|
2329
2635
|
*/
|
|
2330
2636
|
static VALUE
|
|
2331
|
-
|
|
2637
|
+
fz_mode_axis_body (VALUE arg)
|
|
2332
2638
|
{
|
|
2639
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2640
|
+
VALUE self = fr->self;
|
|
2641
|
+
VALUE vaxis = fr->a;
|
|
2333
2642
|
CArray *ca;
|
|
2334
2643
|
volatile VALUE face;
|
|
2335
|
-
self = fz_face_descend(self, &face);
|
|
2644
|
+
self = fz_face_descend(self, &face, "mode");
|
|
2336
2645
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2337
2646
|
|
|
2338
2647
|
int8_t dt = ca->data_type;
|
|
@@ -2366,20 +2675,21 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2366
2675
|
fz_levels mod; /* per-fiber modal values, collected then sorted (reset) */
|
|
2367
2676
|
fz_levels flat; /* all fibers' modal values concatenated, fiber order */
|
|
2368
2677
|
fz_hash_init(&h);
|
|
2369
|
-
fz_levels_init(&lv, esz);
|
|
2370
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2371
|
-
fz_levels_init(&mod, esz);
|
|
2372
|
-
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);
|
|
2373
2682
|
|
|
2374
|
-
|
|
2683
|
+
volatile VALUE hfoff = 0;
|
|
2684
|
+
ca_size_t *foff = ALLOCV_N(ca_size_t, hfoff, M + 1); /* prefix offsets into flat */
|
|
2375
2685
|
foff[0] = 0;
|
|
2376
2686
|
|
|
2377
2687
|
int8_t ax = (int8_t) axis;
|
|
2378
|
-
ca_iter_state st;
|
|
2379
|
-
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);
|
|
2380
2690
|
if ( rc != CA_ITER_OK ) {
|
|
2381
2691
|
fz_hash_free(&h); fz_levels_free(&lv); fz_levels_free(&ct);
|
|
2382
|
-
fz_levels_free(&mod); fz_levels_free(&flat);
|
|
2692
|
+
fz_levels_free(&mod); fz_levels_free(&flat); ALLOCV_END(hfoff);
|
|
2383
2693
|
rb_raise(rb_eRuntimeError, "__mode_axis__: kernel_iterator init failed rc=%d", rc);
|
|
2384
2694
|
}
|
|
2385
2695
|
|
|
@@ -2400,12 +2710,9 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2400
2710
|
fz_levels_push(&ct, &one); } \
|
|
2401
2711
|
else { ((int64_t *) ct.p)[code]++; } \
|
|
2402
2712
|
} while (0)
|
|
2403
|
-
#define MB_FLOAT(T
|
|
2713
|
+
#define MB_FLOAT(T) \
|
|
2404
2714
|
do { \
|
|
2405
|
-
|
|
2406
|
-
if ( vn != vn ) { key = (NANKEY); } \
|
|
2407
|
-
else { if ( vn == (T) 0 ) { vn = (T) 0; } \
|
|
2408
|
-
UINT bits; memcpy(&bits, &vn, sizeof(bits)); key = (uint64_t) bits; } \
|
|
2715
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
2409
2716
|
int is_new; int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
2410
2717
|
if ( is_new ) { int64_t one = 1; fz_levels_push(&lv, &v); \
|
|
2411
2718
|
fz_levels_push(&ct, &one); } \
|
|
@@ -2429,24 +2736,24 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2429
2736
|
for ( ca_size_t x = 0; x < cm; x++ ) { fz_levels_push(&flat, &dp[x]); } \
|
|
2430
2737
|
} while (0)
|
|
2431
2738
|
|
|
2432
|
-
while ( ca_iter_state_next_slab_axes(
|
|
2739
|
+
while ( ca_iter_state_next_slab_axes(st, &p, &m) ) {
|
|
2433
2740
|
fz_hash_reset(&h);
|
|
2434
2741
|
lv.n = 0; ct.n = 0; mod.n = 0;
|
|
2435
2742
|
|
|
2436
2743
|
switch ( dt ) {
|
|
2437
|
-
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2438
|
-
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2439
|
-
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2440
|
-
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2441
|
-
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2442
|
-
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2443
|
-
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2444
|
-
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;
|
|
2445
2752
|
case CA_FLOAT32:
|
|
2446
|
-
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));
|
|
2447
2754
|
break;
|
|
2448
2755
|
case CA_FLOAT64:
|
|
2449
|
-
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));
|
|
2450
2757
|
break;
|
|
2451
2758
|
}
|
|
2452
2759
|
|
|
@@ -2478,7 +2785,7 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2478
2785
|
#undef MODE_EMIT
|
|
2479
2786
|
(void) dummy;
|
|
2480
2787
|
|
|
2481
|
-
ca_iter_state_finish(
|
|
2788
|
+
ca_iter_state_finish(st);
|
|
2482
2789
|
fz_hash_free(&h);
|
|
2483
2790
|
fz_levels_free(&lv);
|
|
2484
2791
|
fz_levels_free(&ct);
|
|
@@ -2508,10 +2815,16 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2508
2815
|
}
|
|
2509
2816
|
|
|
2510
2817
|
fz_levels_free(&flat);
|
|
2511
|
-
|
|
2818
|
+
ALLOCV_END(hfoff);
|
|
2512
2819
|
return result;
|
|
2513
2820
|
}
|
|
2514
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
|
+
|
|
2515
2828
|
void
|
|
2516
2829
|
Init_carray_factorize (void)
|
|
2517
2830
|
{
|