carray 3.0.2 → 3.0.4
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 +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- 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 +104 -81
- 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 +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- 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/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -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 +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_factorize.c
CHANGED
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
(Float#eql? treats them equal). The object lane adds one deviation from Ruby
|
|
51
51
|
Hash, aligning it with the numeric lane: every Float NaN collapses to one
|
|
52
52
|
distinct value (a NaN takes a fixed canonical key and matches any stored Float
|
|
53
|
-
NaN), where Ruby Hash would keep distinct NaN objects apart
|
|
53
|
+
NaN), where Ruby Hash would keep distinct NaN objects apart, and a Complex
|
|
54
|
+
with a NaN part is one value with any Complex whose parts match it that way.
|
|
54
55
|
__factorize_appearance__ and the discovery members (unique, value_counts,
|
|
55
56
|
mask_duplicates) all cover the numeric / object / fixlen lanes.
|
|
56
57
|
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
|
|
78
79
|
#include "carray.h"
|
|
79
80
|
#include "ca_obj_face.h"
|
|
81
|
+
#include "carray_internal.h" /* ca_object_cells_clear */
|
|
80
82
|
#include <string.h>
|
|
81
83
|
#include <math.h>
|
|
82
84
|
|
|
@@ -102,44 +104,133 @@
|
|
|
102
104
|
discovery surface rather than this gate (see
|
|
103
105
|
devel/PROPOSAL_DISCOVERY_FAMILY_FACE_GATE.md §4). */
|
|
104
106
|
|
|
107
|
+
/* The value-hash family decides whether two cells hold the same value: every
|
|
108
|
+
NaN is one value, and -0.0 is the same value as +0.0. A float cell's key
|
|
109
|
+
is the bytes of its canonical form (one NaN, +0.0 for a zero), so equal
|
|
110
|
+
values have equal keys; fz_canonical_* writes that form back as a value. */
|
|
111
|
+
#define FZ_NAN_KEY_DOUBLE 0x7ff8000000000000ULL
|
|
112
|
+
#define FZ_NAN_KEY_FLOAT 0x7fc00000UL
|
|
113
|
+
|
|
114
|
+
static inline uint64_t
|
|
115
|
+
fz_key_double (double v)
|
|
116
|
+
{
|
|
117
|
+
uint64_t b;
|
|
118
|
+
if ( v != v ) return FZ_NAN_KEY_DOUBLE;
|
|
119
|
+
if ( v == 0.0 ) v = 0.0;
|
|
120
|
+
memcpy(&b, &v, sizeof(b));
|
|
121
|
+
return b;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static inline uint64_t
|
|
125
|
+
fz_key_float (float v)
|
|
126
|
+
{
|
|
127
|
+
uint32_t b;
|
|
128
|
+
if ( v != v ) return FZ_NAN_KEY_FLOAT;
|
|
129
|
+
if ( v == 0.0f ) v = 0.0f;
|
|
130
|
+
memcpy(&b, &v, sizeof(b));
|
|
131
|
+
return (uint64_t) b;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static inline double
|
|
135
|
+
fz_canonical_double (double v)
|
|
136
|
+
{
|
|
137
|
+
uint64_t b = fz_key_double(v);
|
|
138
|
+
memcpy(&v, &b, sizeof(v));
|
|
139
|
+
return v;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static inline float
|
|
143
|
+
fz_canonical_float (float v)
|
|
144
|
+
{
|
|
145
|
+
uint32_t b = (uint32_t) fz_key_float(v);
|
|
146
|
+
memcpy(&v, &b, sizeof(v));
|
|
147
|
+
return v;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* For the kernel macros, which take the cell type T. */
|
|
151
|
+
#define FZ_FLOAT_KEY(T, v) \
|
|
152
|
+
_Generic((T) 0, float: fz_key_float, double: fz_key_double)(v)
|
|
153
|
+
|
|
154
|
+
/* A complex array as hash keys: its cells as fixlen blobs of the same
|
|
155
|
+
width, each component written so that equal values have equal bytes
|
|
156
|
+
(-0.0 as 0.0, every NaN as one NaN), with the mask kept. The fixlen lane
|
|
157
|
+
then answers equality for complex values. */
|
|
158
|
+
static VALUE
|
|
159
|
+
fz_complex_key (VALUE self)
|
|
160
|
+
{
|
|
161
|
+
volatile VALUE out;
|
|
162
|
+
CArray *ca, *co;
|
|
163
|
+
ca_size_t i, n;
|
|
164
|
+
GetCArray(self, ca);
|
|
165
|
+
out = rb_carray_new(CA_FIXLEN, ca->ndim, ca->dim, ca->bytes, NULL);
|
|
166
|
+
GetCArray(out, co);
|
|
167
|
+
ca_copy_data(ca, co->ptr);
|
|
168
|
+
n = 2 * ca->elements;
|
|
169
|
+
if ( ca->data_type == CA_CMPLX128 ) {
|
|
170
|
+
double *p = (double *) co->ptr;
|
|
171
|
+
for ( i = 0; i < n; i++ ) p[i] = fz_canonical_double(p[i]);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
float *p = (float *) co->ptr;
|
|
175
|
+
for ( i = 0; i < n; i++ ) p[i] = fz_canonical_float(p[i]);
|
|
176
|
+
}
|
|
177
|
+
if ( ca_has_mask(ca) ) {
|
|
178
|
+
ca_copy_mask(co, ca);
|
|
179
|
+
}
|
|
180
|
+
RB_GC_GUARD(self); /* read through ca after rb_carray_new allocates */
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* The members whose output carries no values (a mask, a count) read a
|
|
185
|
+
complex array through its keys and need nothing back. */
|
|
186
|
+
static VALUE
|
|
187
|
+
fz_complex_as_key (VALUE self)
|
|
188
|
+
{
|
|
189
|
+
CArray *ca;
|
|
190
|
+
GetCArray(self, ca);
|
|
191
|
+
if ( ! ca_is_face(ca) && ca_is_complex_type(ca) ) {
|
|
192
|
+
return fz_complex_key(self);
|
|
193
|
+
}
|
|
194
|
+
return self;
|
|
195
|
+
}
|
|
196
|
+
|
|
105
197
|
/* 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).
|
|
198
|
+
for the re-lift (Qnil when there is nothing to put back). A complex array
|
|
199
|
+
is turned into hash keys (fz_complex_key) and *pface keeps it, so the
|
|
200
|
+
re-lift reads the values back as complex. */
|
|
107
201
|
static VALUE
|
|
108
202
|
fz_face_descend (VALUE self, volatile VALUE *pface, const char *name)
|
|
109
203
|
{
|
|
110
204
|
CArray *ca;
|
|
111
205
|
GetCArray(self, ca);
|
|
206
|
+
if ( ! ca_is_face(ca) && ca_is_complex_type(ca) ) {
|
|
207
|
+
*pface = self;
|
|
208
|
+
return fz_complex_key(self);
|
|
209
|
+
}
|
|
112
210
|
if ( ca_is_face(ca) ) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
211
|
+
/* A record is its bytes: two records are the same value exactly when
|
|
212
|
+
their bytes are, so the fixlen lane answers for it. Any other Face
|
|
213
|
+
is descended only when ORDERABLE. One that cannot be descended must
|
|
214
|
+
not flow on undescended: whatever reads it next reads its storage
|
|
215
|
+
anyway, which is the encoding rather than the values. A Face in this
|
|
216
|
+
position normally never arrives -- CAConstString and CACategorical
|
|
217
|
+
define their own members in Ruby -- but the overrides only fire when
|
|
218
|
+
the Face is the receiver, and this same helper descends the
|
|
219
|
+
*reference* for locate_addr, where it is the argument. */
|
|
220
|
+
if ( ca->obj_type != CA_OBJ_RECORD ) {
|
|
221
|
+
ca_face_require_orderable(self, name, "compare");
|
|
116
222
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
than the values. A Face in this position normally never arrives --
|
|
120
|
-
CAConstString and CACategorical define their own members in Ruby -- but
|
|
121
|
-
the overrides only fire when the Face is the receiver, and this same
|
|
122
|
-
helper descends the *reference* for locate_addr, where it is the
|
|
123
|
-
argument. */
|
|
124
|
-
rb_raise(rb_eArgError,
|
|
125
|
-
"%s: %s is not orderable by storage (a cell encodes the value "
|
|
126
|
-
"rather than being it); convert it first -- #to_string for a "
|
|
127
|
-
"string Face -- or pass .parent to work in storage space",
|
|
128
|
-
name, rb_obj_classname(self));
|
|
223
|
+
*pface = self;
|
|
224
|
+
return rb_ca_strip_face_value(self);
|
|
129
225
|
}
|
|
130
226
|
*pface = Qnil;
|
|
131
227
|
return self;
|
|
132
228
|
}
|
|
133
229
|
|
|
134
230
|
/* 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. */
|
|
231
|
+
descend it, so both sides hash in one storage space
|
|
232
|
+
(ca_face_reconcile_operand). A complex reference instead turns the
|
|
233
|
+
operand into keys of its own complex type. */
|
|
143
234
|
static VALUE
|
|
144
235
|
fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
145
236
|
{
|
|
@@ -148,22 +239,38 @@ fz_face_reconcile (VALUE reference, VALUE operand, const char *name)
|
|
|
148
239
|
return operand;
|
|
149
240
|
}
|
|
150
241
|
GetCArray(reference, ca);
|
|
151
|
-
if ( !
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
242
|
+
if ( ! ca_is_face(ca) ) {
|
|
243
|
+
/* A complex reference: the operand becomes keys of the same kind, in the
|
|
244
|
+
reference's complex type. */
|
|
245
|
+
CArray *op;
|
|
246
|
+
if ( ! rb_obj_is_carray(operand) ) {
|
|
247
|
+
return operand;
|
|
248
|
+
}
|
|
249
|
+
GetCArray(operand, op);
|
|
250
|
+
if ( op->data_type != ca->data_type ) {
|
|
251
|
+
/* coerce: the callers have met both sides at result_type already */
|
|
252
|
+
operand = rb_ca_to_type(operand, INT2NUM(ca->data_type), Qnil);
|
|
253
|
+
}
|
|
254
|
+
return fz_complex_key(operand);
|
|
156
255
|
}
|
|
157
|
-
return
|
|
256
|
+
return ca_face_reconcile_operand(reference, operand, name);
|
|
158
257
|
}
|
|
159
258
|
|
|
160
|
-
/* Put the Face back on a value-carrying output
|
|
259
|
+
/* Put the Face back on a value-carrying output, or read complex keys back
|
|
260
|
+
as complex values. */
|
|
161
261
|
static VALUE
|
|
162
262
|
fz_face_relift (VALUE out, VALUE face)
|
|
163
263
|
{
|
|
264
|
+
CArray *cf, *co;
|
|
164
265
|
if ( NIL_P(face) ) {
|
|
165
266
|
return out;
|
|
166
267
|
}
|
|
268
|
+
GetCArray(face, cf);
|
|
269
|
+
if ( ! ca_is_face(cf) ) {
|
|
270
|
+
GetCArray(out, co);
|
|
271
|
+
return rb_ca_copy(rb_ca_refer_new(out, cf->data_type, co->ndim, co->dim,
|
|
272
|
+
cf->bytes, 0));
|
|
273
|
+
}
|
|
167
274
|
return ca_face_lift(out, face);
|
|
168
275
|
}
|
|
169
276
|
|
|
@@ -176,16 +283,95 @@ typedef struct {
|
|
|
176
283
|
VALUE *val; /* object lane only: the interned VALUE, kept for an eql? re-check
|
|
177
284
|
on a hash collision (NULL in the numeric lane, where the widened
|
|
178
285
|
key is lossless so a key match already proves value equality).
|
|
179
|
-
|
|
180
|
-
|
|
286
|
+
A receiver that computes its cells (a CAObject, a lazy
|
|
287
|
+
expression) hands each fiber over in a scratch that is refilled,
|
|
288
|
+
so the owner marks this array (fz_tmp_values). */
|
|
181
289
|
char *raw; /* fixlen lane only: cap*esz bytes, the interned element bytes kept
|
|
182
290
|
for a memcmp re-check on a hash collision (NULL otherwise). */
|
|
183
291
|
int esz; /* fixlen lane: element width in bytes (0 otherwise) */
|
|
292
|
+
int has_val; /* object lane: val is kept (0 otherwise) */
|
|
184
293
|
ca_size_t cap; /* power of two */
|
|
185
294
|
ca_size_t n; /* distinct keys interned so far */
|
|
186
295
|
int shift; /* 64 - log2(cap); the home slot is the top log2(cap) bits */
|
|
296
|
+
VALUE hbuf; /* owner of the tables, one block (fz_tmp_alloc) */
|
|
187
297
|
} fz_hash;
|
|
188
298
|
|
|
299
|
+
/* The tables live in buffers owned by hidden Ruby objects rather than bare
|
|
300
|
+
xmalloc. The object lane calls #hash and #eql? for every cell, and a raise
|
|
301
|
+
there leaves the tables with nothing to free them; the owner is reclaimed
|
|
302
|
+
by the GC once the frame holding it is gone, and frees its buffer then.
|
|
303
|
+
An owner whose buffer keeps VALUEs (fz_tmp_values) marks them: the object
|
|
304
|
+
lane's cells come from a scratch the walk refills, not only from the
|
|
305
|
+
receiver, so nothing else holds the ones already interned. */
|
|
306
|
+
typedef struct {
|
|
307
|
+
char *buf;
|
|
308
|
+
ca_size_t voff; /* byte offset of the VALUE run in buf */
|
|
309
|
+
ca_size_t nvals; /* VALUEs in the run (0: nothing to mark) */
|
|
310
|
+
} fz_buffer;
|
|
311
|
+
|
|
312
|
+
static void
|
|
313
|
+
fz_buffer_mark (void *ptr)
|
|
314
|
+
{
|
|
315
|
+
fz_buffer *b = (fz_buffer *) ptr;
|
|
316
|
+
if ( b->buf && b->nvals > 0 ) {
|
|
317
|
+
VALUE *v = (VALUE *) (b->buf + b->voff);
|
|
318
|
+
ca_size_t i;
|
|
319
|
+
for ( i = 0; i < b->nvals; i++ ) rb_gc_mark(v[i]);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
static void
|
|
324
|
+
fz_buffer_free (void *ptr)
|
|
325
|
+
{
|
|
326
|
+
fz_buffer *b = (fz_buffer *) ptr;
|
|
327
|
+
xfree(b->buf);
|
|
328
|
+
xfree(b);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
static const rb_data_type_t fz_buffer_type = {
|
|
332
|
+
"carray_factorize_buffer",
|
|
333
|
+
{ fz_buffer_mark, fz_buffer_free, NULL, },
|
|
334
|
+
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY,
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
static void *
|
|
338
|
+
fz_tmp_alloc (VALUE *store, size_t bytes)
|
|
339
|
+
{
|
|
340
|
+
fz_buffer *b;
|
|
341
|
+
*store = TypedData_Make_Struct(0, fz_buffer, &fz_buffer_type, b);
|
|
342
|
+
b->buf = (char *) xmalloc(bytes);
|
|
343
|
+
return b->buf;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
static void *
|
|
347
|
+
fz_tmp_realloc (VALUE store, size_t bytes)
|
|
348
|
+
{
|
|
349
|
+
fz_buffer *b = (fz_buffer *) DATA_PTR(store);
|
|
350
|
+
b->buf = (char *) xrealloc(b->buf, bytes);
|
|
351
|
+
return b->buf;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/* Mark the n VALUEs at vals (inside store's buffer); they must be valid. */
|
|
355
|
+
static void
|
|
356
|
+
fz_tmp_values (VALUE store, void *vals, ca_size_t n)
|
|
357
|
+
{
|
|
358
|
+
fz_buffer *b = (fz_buffer *) DATA_PTR(store);
|
|
359
|
+
b->voff = (ca_size_t) ((char *) vals - b->buf);
|
|
360
|
+
b->nvals = n;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
static void
|
|
364
|
+
fz_tmp_free (VALUE *store)
|
|
365
|
+
{
|
|
366
|
+
if ( *store ) {
|
|
367
|
+
fz_buffer *b = (fz_buffer *) DATA_PTR(*store);
|
|
368
|
+
b->nvals = 0;
|
|
369
|
+
xfree(b->buf);
|
|
370
|
+
b->buf = NULL;
|
|
371
|
+
*store = 0;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
189
375
|
/* Multiplicative hashing (Knuth, TAOCP vol. 3 sec. 6.4): multiply by
|
|
190
376
|
2^64 / golden-ratio and take the TOP log2(cap) bits of the product -- the
|
|
191
377
|
high bits are where a multiply mixes best (the low bits carry little
|
|
@@ -195,19 +381,48 @@ typedef struct {
|
|
|
195
381
|
#define FZ_GOLDEN 0x9E3779B97F4A7C15ULL
|
|
196
382
|
#define FZ_HOME(h, key) ((ca_size_t) (((uint64_t)(key) * FZ_GOLDEN) >> (h)->shift))
|
|
197
383
|
|
|
384
|
+
/* Points the tables of h at one new block for cap slots: key, then the
|
|
385
|
+
object lane's val, code, used, and the fixlen lane's raw bytes. */
|
|
198
386
|
static void
|
|
199
|
-
|
|
387
|
+
fz_hash_alloc (fz_hash *h, ca_size_t cap)
|
|
388
|
+
{
|
|
389
|
+
int has_val = h->has_val;
|
|
390
|
+
size_t nkey = sizeof(uint64_t) * (size_t) cap;
|
|
391
|
+
size_t nval = has_val ? sizeof(VALUE) * (size_t) cap : 0;
|
|
392
|
+
size_t ncode = sizeof(int32_t) * (size_t) cap;
|
|
393
|
+
size_t nused = sizeof(uint8_t) * (size_t) cap;
|
|
394
|
+
size_t nraw = (size_t) cap * (size_t) h->esz;
|
|
395
|
+
char *b = fz_tmp_alloc(&h->hbuf, nkey + nval + ncode + nused + nraw);
|
|
396
|
+
h->key = (uint64_t *) b; b += nkey;
|
|
397
|
+
h->val = has_val ? (VALUE *) b : NULL; b += nval;
|
|
398
|
+
h->code = (int32_t *) b; b += ncode;
|
|
399
|
+
h->used = (uint8_t *) b; b += nused;
|
|
400
|
+
h->raw = h->esz ? b : NULL;
|
|
401
|
+
h->cap = cap;
|
|
402
|
+
MEMZERO(h->used, uint8_t, cap);
|
|
403
|
+
if ( has_val ) {
|
|
404
|
+
ca_object_cells_clear(h->val, cap);
|
|
405
|
+
fz_tmp_values(h->hbuf, h->val, cap);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* has_val: the object lane (a slot keeps its VALUE); esz > 0: the fixlen
|
|
410
|
+
lane (a slot keeps esz bytes). */
|
|
411
|
+
static void
|
|
412
|
+
fz_hash_setup (fz_hash *h, int has_val, int esz)
|
|
200
413
|
{
|
|
201
|
-
h->cap = 1024;
|
|
202
414
|
h->shift = 64 - 10; /* log2(1024) = 10 */
|
|
203
415
|
h->n = 0;
|
|
204
|
-
h->
|
|
205
|
-
h->
|
|
206
|
-
h->
|
|
207
|
-
h
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
416
|
+
h->hbuf = 0;
|
|
417
|
+
h->has_val = has_val;
|
|
418
|
+
h->esz = esz;
|
|
419
|
+
fz_hash_alloc(h, 1024);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
static void
|
|
423
|
+
fz_hash_init (fz_hash *h)
|
|
424
|
+
{
|
|
425
|
+
fz_hash_setup(h, 0, 0); /* numeric lane: no re-check needed */
|
|
211
426
|
}
|
|
212
427
|
|
|
213
428
|
/* Object lane: the widened key is `rb_hash` (lossy), so a slot also stores the
|
|
@@ -216,8 +431,7 @@ fz_hash_init (fz_hash *h)
|
|
|
216
431
|
static void
|
|
217
432
|
fz_hash_init_obj (fz_hash *h)
|
|
218
433
|
{
|
|
219
|
-
|
|
220
|
-
h->val = ALLOC_N(VALUE, h->cap);
|
|
434
|
+
fz_hash_setup(h, 1, 0);
|
|
221
435
|
}
|
|
222
436
|
|
|
223
437
|
/* Fixlen lane: the key is a byte-hash of the esz-wide element (lossy), so a slot
|
|
@@ -227,19 +441,18 @@ fz_hash_init_obj (fz_hash *h)
|
|
|
227
441
|
static void
|
|
228
442
|
fz_hash_init_mem (fz_hash *h, int esz)
|
|
229
443
|
{
|
|
230
|
-
|
|
231
|
-
h->esz = esz;
|
|
232
|
-
h->raw = ALLOC_N(char, h->cap * esz);
|
|
444
|
+
fz_hash_setup(h, 0, esz);
|
|
233
445
|
}
|
|
234
446
|
|
|
235
447
|
static void
|
|
236
448
|
fz_hash_free (fz_hash *h)
|
|
237
449
|
{
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
450
|
+
fz_tmp_free(&h->hbuf);
|
|
451
|
+
h->key = NULL;
|
|
452
|
+
h->code = NULL;
|
|
453
|
+
h->used = NULL;
|
|
454
|
+
h->val = NULL;
|
|
455
|
+
h->raw = NULL;
|
|
243
456
|
}
|
|
244
457
|
|
|
245
458
|
/* FNV-1a over esz bytes: a lossy 64-bit key for the fixlen lane. */
|
|
@@ -272,14 +485,10 @@ fz_hash_grow (fz_hash *h)
|
|
|
272
485
|
VALUE *ov = h->val;
|
|
273
486
|
char *orw = h->raw;
|
|
274
487
|
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);
|
|
488
|
+
VALUE hold = h->hbuf; /* keeps the old block until it is freed below */
|
|
489
|
+
h->hbuf = 0;
|
|
490
|
+
h->shift -= 1; /* log2(cap) grew by one */
|
|
491
|
+
fz_hash_alloc(h, newcap);
|
|
283
492
|
ca_size_t mask = newcap - 1;
|
|
284
493
|
for ( ca_size_t s = 0; s < oldcap; s++ ) {
|
|
285
494
|
if ( ! ou[s] ) { continue; }
|
|
@@ -291,9 +500,7 @@ fz_hash_grow (fz_hash *h)
|
|
|
291
500
|
if ( ov ) { h->val[slot] = ov[s]; }
|
|
292
501
|
if ( orw ) { memcpy(h->raw + slot * esz, orw + s * esz, esz); }
|
|
293
502
|
}
|
|
294
|
-
|
|
295
|
-
if ( ov ) { xfree(ov); }
|
|
296
|
-
if ( orw ) { xfree(orw); }
|
|
503
|
+
fz_tmp_free(&hold);
|
|
297
504
|
}
|
|
298
505
|
|
|
299
506
|
/* True when v is a Float holding NaN (any bit pattern). */
|
|
@@ -303,25 +510,84 @@ fz_is_float_nan (VALUE v)
|
|
|
303
510
|
return RB_FLOAT_TYPE_P(v) && isnan(RFLOAT_VALUE(v));
|
|
304
511
|
}
|
|
305
512
|
|
|
513
|
+
/* True when v holds a NaN that eql? would keep apart from an equal value:
|
|
514
|
+
a Float NaN, or a Complex with a Float NaN part. */
|
|
515
|
+
static int
|
|
516
|
+
fz_obj_has_nan (VALUE v)
|
|
517
|
+
{
|
|
518
|
+
if ( fz_is_float_nan(v) ) {
|
|
519
|
+
return 1;
|
|
520
|
+
}
|
|
521
|
+
return RB_TYPE_P(v, T_COMPLEX)
|
|
522
|
+
&& ( fz_is_float_nan(rb_complex_real(v))
|
|
523
|
+
|| fz_is_float_nan(rb_complex_imag(v)) );
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* A part of a NaN-bearing value: every NaN is one value, the rest go by
|
|
527
|
+
eql?, as in Ruby Hash. */
|
|
528
|
+
static uint64_t
|
|
529
|
+
fz_obj_part_key (VALUE v)
|
|
530
|
+
{
|
|
531
|
+
return fz_is_float_nan(v) ? FZ_NAN_KEY_DOUBLE : (uint64_t) NUM2LL(rb_hash(v));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static int
|
|
535
|
+
fz_obj_part_eql (VALUE a, VALUE b)
|
|
536
|
+
{
|
|
537
|
+
if ( fz_is_float_nan(a) || fz_is_float_nan(b) ) {
|
|
538
|
+
return fz_is_float_nan(a) && fz_is_float_nan(b);
|
|
539
|
+
}
|
|
540
|
+
return rb_eql(a, b);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/* The hash key of an object cell. A NaN-bearing value is keyed part by
|
|
544
|
+
part with every NaN as one value, so it matches the numeric lane: all
|
|
545
|
+
NaN are one value, and a complex value is one value when its parts are. */
|
|
546
|
+
static uint64_t
|
|
547
|
+
fz_obj_key (VALUE v, int has_nan)
|
|
548
|
+
{
|
|
549
|
+
if ( ! has_nan ) {
|
|
550
|
+
return (uint64_t) NUM2LL(rb_hash(v));
|
|
551
|
+
}
|
|
552
|
+
if ( RB_TYPE_P(v, T_COMPLEX) ) {
|
|
553
|
+
return fz_obj_part_key(rb_complex_real(v)) * 31u
|
|
554
|
+
^ fz_obj_part_key(rb_complex_imag(v)) ^ 0x9e3779b97f4a7c15ULL;
|
|
555
|
+
}
|
|
556
|
+
return FZ_NAN_KEY_DOUBLE;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* Whether a stored cell is the same value as v (has_nan from fz_obj_has_nan). */
|
|
560
|
+
static int
|
|
561
|
+
fz_obj_same (VALUE stored, VALUE v, int has_nan)
|
|
562
|
+
{
|
|
563
|
+
if ( ! has_nan ) {
|
|
564
|
+
return rb_eql(stored, v);
|
|
565
|
+
}
|
|
566
|
+
if ( RB_TYPE_P(v, T_COMPLEX) ) {
|
|
567
|
+
return RB_TYPE_P(stored, T_COMPLEX)
|
|
568
|
+
&& fz_obj_part_eql(rb_complex_real(stored), rb_complex_real(v))
|
|
569
|
+
&& fz_obj_part_eql(rb_complex_imag(stored), rb_complex_imag(v));
|
|
570
|
+
}
|
|
571
|
+
return fz_is_float_nan(stored);
|
|
572
|
+
}
|
|
573
|
+
|
|
306
574
|
/* Object-lane intern: key = rb_hash(v) (lossy), collision re-check via rb_eql.
|
|
307
575
|
Matches Ruby Hash distinctness (`hash` + `eql?`) element for element, with one
|
|
308
576
|
value-based exception aligning with the numeric lane: every Float NaN collapses
|
|
309
577
|
to a single distinct value (Ruby Hash keeps distinct NaN objects apart via
|
|
310
|
-
eql?, but the discovery family unifies them)
|
|
311
|
-
|
|
312
|
-
into the first. */
|
|
578
|
+
eql?, but the discovery family unifies them), and so does a Complex whose
|
|
579
|
+
parts are the same with every NaN as one (fz_obj_key / fz_obj_same). */
|
|
313
580
|
static int32_t
|
|
314
581
|
fz_hash_intern_obj (fz_hash *h, VALUE v, int *is_new)
|
|
315
582
|
{
|
|
316
583
|
if ( (h->n + 1) * 10 >= h->cap * 7 ) { fz_hash_grow(h); } /* load factor 0.7 */
|
|
317
|
-
int v_nan =
|
|
318
|
-
uint64_t key = v_nan
|
|
319
|
-
: (uint64_t) NUM2LL(rb_hash(v));
|
|
584
|
+
int v_nan = fz_obj_has_nan(v);
|
|
585
|
+
uint64_t key = fz_obj_key(v, v_nan);
|
|
320
586
|
ca_size_t mask = h->cap - 1;
|
|
321
587
|
ca_size_t slot = FZ_HOME(h, key);
|
|
322
588
|
while ( h->used[slot] ) {
|
|
323
589
|
if ( h->key[slot] == key &&
|
|
324
|
-
(
|
|
590
|
+
fz_obj_same(h->val[slot], v, v_nan) ) {
|
|
325
591
|
*is_new = 0; return h->code[slot];
|
|
326
592
|
}
|
|
327
593
|
slot = (slot + 1) & mask;
|
|
@@ -412,14 +678,13 @@ fz_hash_lookup (fz_hash *h, uint64_t key, int32_t *code_out)
|
|
|
412
678
|
static int
|
|
413
679
|
fz_hash_lookup_obj (fz_hash *h, VALUE v, int32_t *code_out)
|
|
414
680
|
{
|
|
415
|
-
int v_nan =
|
|
416
|
-
uint64_t key = v_nan
|
|
417
|
-
: (uint64_t) NUM2LL(rb_hash(v));
|
|
681
|
+
int v_nan = fz_obj_has_nan(v);
|
|
682
|
+
uint64_t key = fz_obj_key(v, v_nan);
|
|
418
683
|
ca_size_t mask = h->cap - 1;
|
|
419
684
|
ca_size_t slot = FZ_HOME(h, key);
|
|
420
685
|
while ( h->used[slot] ) {
|
|
421
686
|
if ( h->key[slot] == key &&
|
|
422
|
-
(
|
|
687
|
+
fz_obj_same(h->val[slot], v, v_nan) ) {
|
|
423
688
|
if ( code_out ) { *code_out = h->code[slot]; }
|
|
424
689
|
return 1;
|
|
425
690
|
}
|
|
@@ -452,23 +717,42 @@ typedef struct {
|
|
|
452
717
|
ca_size_t cap; /* capacity in elements */
|
|
453
718
|
ca_size_t n; /* elements stored */
|
|
454
719
|
int esz; /* element bytes */
|
|
720
|
+
VALUE hp; /* owner of p (see fz_tmp_alloc) */
|
|
721
|
+
int obj; /* p holds VALUEs, marked by hp */
|
|
455
722
|
} fz_levels;
|
|
456
723
|
|
|
724
|
+
/* Fill the VALUE slots from..cap with Qnil and mark all cap of them. */
|
|
457
725
|
static void
|
|
458
|
-
|
|
726
|
+
fz_levels_values (fz_levels *l, ca_size_t from)
|
|
727
|
+
{
|
|
728
|
+
ca_object_cells_clear((VALUE *) l->p + from, l->cap - from);
|
|
729
|
+
fz_tmp_values(l->hp, l->p, l->cap);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
static void
|
|
733
|
+
fz_levels_init (fz_levels *l, int esz, int obj)
|
|
459
734
|
{
|
|
460
735
|
l->esz = esz;
|
|
461
736
|
l->cap = 16;
|
|
462
737
|
l->n = 0;
|
|
463
|
-
l->
|
|
738
|
+
l->hp = 0;
|
|
739
|
+
l->obj = obj;
|
|
740
|
+
l->p = fz_tmp_alloc(&l->hp, (size_t) l->cap * esz);
|
|
741
|
+
if ( obj ) {
|
|
742
|
+
fz_levels_values(l, 0);
|
|
743
|
+
}
|
|
464
744
|
}
|
|
465
745
|
|
|
466
746
|
static void
|
|
467
747
|
fz_levels_push (fz_levels *l, const void *e)
|
|
468
748
|
{
|
|
469
749
|
if ( l->n == l->cap ) {
|
|
750
|
+
ca_size_t old = l->cap;
|
|
470
751
|
l->cap <<= 1;
|
|
471
|
-
|
|
752
|
+
l->p = fz_tmp_realloc(l->hp, (size_t) l->cap * l->esz);
|
|
753
|
+
if ( l->obj ) {
|
|
754
|
+
fz_levels_values(l, old);
|
|
755
|
+
}
|
|
472
756
|
}
|
|
473
757
|
memcpy(l->p + l->n * l->esz, e, l->esz);
|
|
474
758
|
l->n++;
|
|
@@ -477,7 +761,41 @@ fz_levels_push (fz_levels *l, const void *e)
|
|
|
477
761
|
static void
|
|
478
762
|
fz_levels_free (fz_levels *l)
|
|
479
763
|
{
|
|
480
|
-
|
|
764
|
+
fz_tmp_free(&l->hp);
|
|
765
|
+
l->p = NULL;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/* ---- the frame a discovery method runs in ---------------------------------
|
|
769
|
+
|
|
770
|
+
The object lane calls #hash and #eql? for every cell, and either can raise
|
|
771
|
+
in the middle of a walk. The walks' states live in this frame, outside the
|
|
772
|
+
method's body, and ca_iter_ensure finishes them however the body leaves;
|
|
773
|
+
the tables have owners the unwind collects (fz_tmp_alloc). Slots 0
|
|
774
|
+
and 1 hold a method's own walks, slot 2 the walk of fz_intern_all.
|
|
775
|
+
|
|
776
|
+
A body that replaces self or an operand with an array it made (complex
|
|
777
|
+
keys, a Face's storage, an operand brought into self's space) writes the
|
|
778
|
+
new VALUE back into the frame. The walks read it only through its
|
|
779
|
+
CArray *, so a C local alone would leave it to the collector halfway
|
|
780
|
+
through. */
|
|
781
|
+
|
|
782
|
+
typedef struct {
|
|
783
|
+
ca_iter_state st[3];
|
|
784
|
+
VALUE self;
|
|
785
|
+
VALUE a;
|
|
786
|
+
VALUE b;
|
|
787
|
+
int i;
|
|
788
|
+
} fz_frame;
|
|
789
|
+
|
|
790
|
+
static VALUE
|
|
791
|
+
fz_run (VALUE (*body)(VALUE), VALUE self, VALUE a, VALUE b, int i)
|
|
792
|
+
{
|
|
793
|
+
fz_frame fr;
|
|
794
|
+
fr.self = self;
|
|
795
|
+
fr.a = a;
|
|
796
|
+
fr.b = b;
|
|
797
|
+
fr.i = i;
|
|
798
|
+
return ca_iter_ensure(3, fr.st, body, (VALUE) &fr);
|
|
481
799
|
}
|
|
482
800
|
|
|
483
801
|
/* @overload __factorize_appearance__
|
|
@@ -497,11 +815,13 @@ fz_levels_free (fz_levels *l)
|
|
|
497
815
|
(row-major flatten) order.
|
|
498
816
|
*/
|
|
499
817
|
static VALUE
|
|
500
|
-
|
|
818
|
+
fz_factorize_appearance_body (VALUE arg)
|
|
501
819
|
{
|
|
820
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
821
|
+
VALUE self = fr->self;
|
|
502
822
|
CArray *ca;
|
|
503
823
|
volatile VALUE face;
|
|
504
|
-
self = fz_face_descend(self, &face, "categorize");
|
|
824
|
+
fr->self = self = fz_face_descend(self, &face, "categorize");
|
|
505
825
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
506
826
|
|
|
507
827
|
int8_t dt = ca->data_type;
|
|
@@ -532,11 +852,11 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
532
852
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
533
853
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
534
854
|
else { fz_hash_init(&h); }
|
|
535
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
855
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
536
856
|
|
|
537
857
|
int8_t axis = (int8_t) (ca->ndim - 1); /* innermost fiber = row-major flatten */
|
|
538
858
|
|
|
539
|
-
ca_iter_state st_in, st_out;
|
|
859
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
540
860
|
char *p_in, *p_out;
|
|
541
861
|
boolean8_t *m;
|
|
542
862
|
ca_size_t n;
|
|
@@ -558,25 +878,18 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
558
878
|
} while (0)
|
|
559
879
|
|
|
560
880
|
/* Float lane: reproduce `==` with two value-based exceptions matching the
|
|
561
|
-
discovery family -- all NaN collapse to one canonical key (
|
|
881
|
+
discovery family -- all NaN collapse to one canonical key (FZ_FLOAT_KEY),
|
|
562
882
|
and -0.0 == +0.0 (a zero normalizes to +0.0 before the bitwise key). The
|
|
563
883
|
level pushed is the raw first-seen element (an appearance-first NaN / -0.0 is
|
|
564
884
|
kept as-is), so masked source cells store the sentinel. */
|
|
565
|
-
#define FZ_LOOP_FLOAT(T
|
|
885
|
+
#define FZ_LOOP_FLOAT(T) \
|
|
566
886
|
do { \
|
|
567
887
|
const T *ip = (const T *) p_in; \
|
|
568
888
|
uint32_t *op = (uint32_t *) p_out; \
|
|
569
889
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
570
890
|
if ( m && m[i] ) { op[i] = 0xFFFFFFFFu; continue; } \
|
|
571
891
|
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
|
-
} \
|
|
892
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
580
893
|
int is_new; \
|
|
581
894
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
582
895
|
if ( is_new ) { fz_levels_push(&lv, &ip[i]); } \
|
|
@@ -615,7 +928,7 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
615
928
|
} \
|
|
616
929
|
} while (0)
|
|
617
930
|
|
|
618
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cu32, axis,
|
|
931
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cu32, axis,
|
|
619
932
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
620
933
|
switch ( dt ) {
|
|
621
934
|
case CA_INT8: FZ_LOOP(int8_t, (int64_t)); break;
|
|
@@ -626,8 +939,8 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
626
939
|
case CA_UINT16: FZ_LOOP(uint16_t, (uint64_t)); break;
|
|
627
940
|
case CA_UINT32: FZ_LOOP(uint32_t, (uint64_t)); break;
|
|
628
941
|
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
|
|
942
|
+
case CA_FLOAT32: FZ_LOOP_FLOAT(float); break;
|
|
943
|
+
case CA_FLOAT64: FZ_LOOP_FLOAT(double); break;
|
|
631
944
|
case CA_OBJECT: FZ_LOOP_OBJ; break;
|
|
632
945
|
case CA_FIXLEN: FZ_LOOP_MEM; break;
|
|
633
946
|
}
|
|
@@ -686,6 +999,12 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
686
999
|
return rb_ary_new3(2, vcodes, fz_face_relift(vlev, face));
|
|
687
1000
|
}
|
|
688
1001
|
|
|
1002
|
+
static VALUE
|
|
1003
|
+
rb_ca_factorize_appearance (VALUE self)
|
|
1004
|
+
{
|
|
1005
|
+
return fz_run(fz_factorize_appearance_body, self, Qnil, Qnil, 0);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
689
1008
|
/* @overload __mask_duplicates__(axis)
|
|
690
1009
|
|
|
691
1010
|
INTERNAL (mask_duplicates). Mark each cell whose value duplicates an
|
|
@@ -706,8 +1025,11 @@ rb_ca_factorize_appearance (VALUE self)
|
|
|
706
1025
|
value (so the second and later NaN are duplicates, as in the numeric lane).
|
|
707
1026
|
*/
|
|
708
1027
|
static VALUE
|
|
709
|
-
|
|
1028
|
+
fz_mask_duplicates_body (VALUE arg)
|
|
710
1029
|
{
|
|
1030
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1031
|
+
VALUE self = fr->self;
|
|
1032
|
+
VALUE vaxis = fr->a;
|
|
711
1033
|
CArray *ca;
|
|
712
1034
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
713
1035
|
|
|
@@ -741,7 +1063,7 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
741
1063
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
742
1064
|
else { fz_hash_init(&h); }
|
|
743
1065
|
|
|
744
|
-
ca_iter_state st_in, st_out;
|
|
1066
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
745
1067
|
char *p_in, *p_out;
|
|
746
1068
|
boolean8_t *m;
|
|
747
1069
|
ca_size_t n;
|
|
@@ -764,24 +1086,17 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
764
1086
|
|
|
765
1087
|
/* Float variant: reproduce `==` with two value-based exceptions so the
|
|
766
1088
|
distinct-value judgement matches uniq / the discovery family. All NaN
|
|
767
|
-
collapse to one canonical key (
|
|
1089
|
+
collapse to one canonical key (FZ_FLOAT_KEY), so the second and later
|
|
768
1090
|
NaN in a fiber are duplicates; -0.0 == +0.0, so a zero normalizes to +0.0
|
|
769
1091
|
before the bitwise key. */
|
|
770
|
-
#define MD_LOOP_FLOAT(T
|
|
1092
|
+
#define MD_LOOP_FLOAT(T) \
|
|
771
1093
|
do { \
|
|
772
1094
|
const T *ip = (const T *) p_in; \
|
|
773
1095
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
774
1096
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
775
1097
|
if ( m && m[i] ) { op[i] = 0; continue; } \
|
|
776
1098
|
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
|
-
} \
|
|
1099
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
785
1100
|
int is_new; \
|
|
786
1101
|
fz_hash_intern(&h, key, &is_new); \
|
|
787
1102
|
op[i] = is_new ? 0 : 1; \
|
|
@@ -814,7 +1129,7 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
814
1129
|
} \
|
|
815
1130
|
} while (0)
|
|
816
1131
|
|
|
817
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cout, (int8_t) axis,
|
|
1132
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cout, (int8_t) axis,
|
|
818
1133
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
819
1134
|
fz_hash_reset(&h); /* independent seen-set per fiber */
|
|
820
1135
|
switch ( dt ) {
|
|
@@ -826,8 +1141,8 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
826
1141
|
case CA_UINT16: MD_LOOP(uint16_t, (uint64_t)); break;
|
|
827
1142
|
case CA_UINT32: MD_LOOP(uint32_t, (uint64_t)); break;
|
|
828
1143
|
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
|
|
1144
|
+
case CA_FLOAT32: MD_LOOP_FLOAT(float); break;
|
|
1145
|
+
case CA_FLOAT64: MD_LOOP_FLOAT(double); break;
|
|
831
1146
|
case CA_OBJECT: MD_LOOP_OBJ; break;
|
|
832
1147
|
case CA_FIXLEN: MD_LOOP_MEM; break;
|
|
833
1148
|
}
|
|
@@ -841,6 +1156,12 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
841
1156
|
return vout;
|
|
842
1157
|
}
|
|
843
1158
|
|
|
1159
|
+
static VALUE
|
|
1160
|
+
rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
1161
|
+
{
|
|
1162
|
+
return fz_run(fz_mask_duplicates_body, fz_complex_as_key(self), vaxis, Qnil, 0);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
844
1165
|
/* @overload __unique_flat__
|
|
845
1166
|
|
|
846
1167
|
INTERNAL (CArray#unique). Collect the distinct values of self in
|
|
@@ -865,11 +1186,13 @@ rb_ca_mask_duplicates (VALUE self, VALUE vaxis)
|
|
|
865
1186
|
uniform-width binary cells the fixlen seen-set used.
|
|
866
1187
|
*/
|
|
867
1188
|
static VALUE
|
|
868
|
-
|
|
1189
|
+
fz_unique_flat_body (VALUE arg)
|
|
869
1190
|
{
|
|
1191
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1192
|
+
VALUE self = fr->self;
|
|
870
1193
|
CArray *ca;
|
|
871
1194
|
volatile VALUE face;
|
|
872
|
-
self = fz_face_descend(self, &face, "unique");
|
|
1195
|
+
fr->self = self = fz_face_descend(self, &face, "unique");
|
|
873
1196
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
874
1197
|
|
|
875
1198
|
int8_t dt = ca->data_type;
|
|
@@ -893,11 +1216,9 @@ rb_ca_unique_flat (VALUE self)
|
|
|
893
1216
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
894
1217
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
895
1218
|
else { fz_hash_init(&h); }
|
|
896
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1219
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
897
1220
|
|
|
898
|
-
|
|
899
|
-
one seen-set over the whole array */
|
|
900
|
-
ca_iter_state st_in;
|
|
1221
|
+
ca_iter_state *st_in = &fr->st[0];
|
|
901
1222
|
char *p_in;
|
|
902
1223
|
boolean8_t *m;
|
|
903
1224
|
ca_size_t n;
|
|
@@ -916,20 +1237,13 @@ rb_ca_unique_flat (VALUE self)
|
|
|
916
1237
|
|
|
917
1238
|
/* Float: NaN collapses to one canonical key; -0.0 / +0.0 share a key. The
|
|
918
1239
|
pushed level is the raw first-seen element. */
|
|
919
|
-
#define UQ_LOOP_FLOAT(T
|
|
1240
|
+
#define UQ_LOOP_FLOAT(T) \
|
|
920
1241
|
do { \
|
|
921
1242
|
const T *ip = (const T *) p_in; \
|
|
922
1243
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
923
1244
|
if ( m && m[i] ) { continue; } \
|
|
924
1245
|
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
|
-
} \
|
|
1246
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
933
1247
|
int is_new; \
|
|
934
1248
|
fz_hash_intern(&h, key, &is_new); \
|
|
935
1249
|
if ( is_new ) { fz_levels_push(&lv, &ip[i]); } \
|
|
@@ -964,7 +1278,7 @@ rb_ca_unique_flat (VALUE self)
|
|
|
964
1278
|
} \
|
|
965
1279
|
} while (0)
|
|
966
1280
|
|
|
967
|
-
|
|
1281
|
+
CA_FOR_EACH_WHOLE_MASKED(*st_in, ca, CA_KERNEL_READ, p_in, n, m) {
|
|
968
1282
|
switch ( dt ) {
|
|
969
1283
|
case CA_INT8: UQ_LOOP(int8_t, (int64_t)); break;
|
|
970
1284
|
case CA_INT16: UQ_LOOP(int16_t, (int64_t)); break;
|
|
@@ -974,8 +1288,8 @@ rb_ca_unique_flat (VALUE self)
|
|
|
974
1288
|
case CA_UINT16: UQ_LOOP(uint16_t, (uint64_t)); break;
|
|
975
1289
|
case CA_UINT32: UQ_LOOP(uint32_t, (uint64_t)); break;
|
|
976
1290
|
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
|
|
1291
|
+
case CA_FLOAT32: UQ_LOOP_FLOAT(float); break;
|
|
1292
|
+
case CA_FLOAT64: UQ_LOOP_FLOAT(double); break;
|
|
979
1293
|
case CA_OBJECT: UQ_LOOP_OBJ; break;
|
|
980
1294
|
case CA_FIXLEN: UQ_LOOP_MEM; break;
|
|
981
1295
|
}
|
|
@@ -1002,8 +1316,14 @@ rb_ca_unique_flat (VALUE self)
|
|
|
1002
1316
|
return fz_face_relift(vlev, face); /* distinct *values*: give the Face back */
|
|
1003
1317
|
}
|
|
1004
1318
|
|
|
1319
|
+
static VALUE
|
|
1320
|
+
rb_ca_unique_flat (VALUE self)
|
|
1321
|
+
{
|
|
1322
|
+
return fz_run(fz_unique_flat_body, self, Qnil, Qnil, 0);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1005
1325
|
/* Intern every non-masked cell of cv into h, one seen-set over the whole array
|
|
1006
|
-
|
|
1326
|
+
walked in row-major order. When lv is non-NULL, the first-seen
|
|
1007
1327
|
raw element of each distinct value is pushed to it (appearance order), so the
|
|
1008
1328
|
same pass builds both a probe set and the distinct-value list. Dispatches the
|
|
1009
1329
|
three key lanes exactly as the discovery family: numeric widen with all NaN
|
|
@@ -1011,11 +1331,9 @@ rb_ca_unique_flat (VALUE self)
|
|
|
1011
1331
|
fixlen byte-hash + memcmp. Used to build the probe set (is_in, set relations)
|
|
1012
1332
|
and to accumulate distinct values (union). */
|
|
1013
1333
|
static void
|
|
1014
|
-
fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
1334
|
+
fz_intern_all (ca_iter_state *st_v, fz_hash *h, CArray *cv, fz_levels *lv)
|
|
1015
1335
|
{
|
|
1016
1336
|
int8_t dt = cv->data_type;
|
|
1017
|
-
int8_t vaxis = (int8_t) (cv->ndim - 1);
|
|
1018
|
-
ca_iter_state st_v;
|
|
1019
1337
|
char *p_v;
|
|
1020
1338
|
boolean8_t *mv;
|
|
1021
1339
|
ca_size_t nv;
|
|
@@ -1032,20 +1350,13 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1032
1350
|
} \
|
|
1033
1351
|
} while (0)
|
|
1034
1352
|
|
|
1035
|
-
#define FZ_IA_FLOAT(T
|
|
1353
|
+
#define FZ_IA_FLOAT(T) \
|
|
1036
1354
|
do { \
|
|
1037
1355
|
const T *ip = (const T *) p_v; \
|
|
1038
1356
|
for ( ca_size_t i = 0; i < nv; i++ ) { \
|
|
1039
1357
|
if ( mv && mv[i] ) { continue; } \
|
|
1040
1358
|
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
|
-
} \
|
|
1359
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1049
1360
|
int is_new; \
|
|
1050
1361
|
fz_hash_intern(h, key, &is_new); \
|
|
1051
1362
|
if ( is_new && lv ) { fz_levels_push(lv, &ip[i]); } \
|
|
@@ -1075,7 +1386,7 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1075
1386
|
} \
|
|
1076
1387
|
} while (0)
|
|
1077
1388
|
|
|
1078
|
-
|
|
1389
|
+
CA_FOR_EACH_WHOLE_MASKED(*st_v, cv, CA_KERNEL_READ, p_v, nv, mv) {
|
|
1079
1390
|
switch ( dt ) {
|
|
1080
1391
|
case CA_INT8: FZ_IA(int8_t, (int64_t)); break;
|
|
1081
1392
|
case CA_INT16: FZ_IA(int16_t, (int64_t)); break;
|
|
@@ -1085,8 +1396,8 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1085
1396
|
case CA_UINT16: FZ_IA(uint16_t, (uint64_t)); break;
|
|
1086
1397
|
case CA_UINT32: FZ_IA(uint32_t, (uint64_t)); break;
|
|
1087
1398
|
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
|
|
1399
|
+
case CA_FLOAT32: FZ_IA_FLOAT(float); break;
|
|
1400
|
+
case CA_FLOAT64: FZ_IA_FLOAT(double); break;
|
|
1090
1401
|
case CA_OBJECT: FZ_IA_OBJ; break;
|
|
1091
1402
|
case CA_FIXLEN: FZ_IA_MEM; break;
|
|
1092
1403
|
}
|
|
@@ -1115,12 +1426,15 @@ fz_intern_all (fz_hash *h, CArray *cv, fz_levels *lv)
|
|
|
1115
1426
|
fixlen byte equality (byte-hash + memcmp).
|
|
1116
1427
|
*/
|
|
1117
1428
|
static VALUE
|
|
1118
|
-
|
|
1429
|
+
fz_is_in_body (VALUE arg)
|
|
1119
1430
|
{
|
|
1431
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1432
|
+
VALUE self = fr->self;
|
|
1433
|
+
VALUE rvalues = fr->a;
|
|
1120
1434
|
CArray *ca, *cv;
|
|
1121
1435
|
volatile VALUE face;
|
|
1122
|
-
self
|
|
1123
|
-
rvalues
|
|
1436
|
+
fr->self = self = fz_face_descend(self, &face, "is_in");
|
|
1437
|
+
fr->a = rvalues = fz_face_reconcile(face, rvalues, "is_in");
|
|
1124
1438
|
GetCArray(self, ca);
|
|
1125
1439
|
|
|
1126
1440
|
int8_t dt = ca->data_type;
|
|
@@ -1145,12 +1459,12 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1145
1459
|
GetCArray(rvalues, cv);
|
|
1146
1460
|
if ( cv->data_type != dt ) {
|
|
1147
1461
|
rb_raise(rb_eCADataTypeError,
|
|
1148
|
-
"
|
|
1462
|
+
"is_in: values data type (%s) must match self (%s)",
|
|
1149
1463
|
ca_type_name[cv->data_type], ca_type_name[dt]);
|
|
1150
1464
|
}
|
|
1151
1465
|
if ( dt == CA_FIXLEN && cv->bytes != ca->bytes ) {
|
|
1152
1466
|
rb_raise(rb_eCADataTypeError,
|
|
1153
|
-
"
|
|
1467
|
+
"is_in: a fixlen value is a cell-width blob, so the values "
|
|
1154
1468
|
"must be %ld bytes wide like self, not %ld",
|
|
1155
1469
|
(long) ca->bytes, (long) cv->bytes);
|
|
1156
1470
|
}
|
|
@@ -1164,14 +1478,14 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1164
1478
|
else { fz_hash_init(&h); }
|
|
1165
1479
|
|
|
1166
1480
|
/* ---- Phase 1: build the seen-set from every non-masked cell of `values`. */
|
|
1167
|
-
fz_intern_all(&h, cv, NULL);
|
|
1481
|
+
fz_intern_all(&fr->st[2], &h, cv, NULL);
|
|
1168
1482
|
|
|
1169
1483
|
/* ---- Phase 2: probe every cell of self, writing the boolean membership. */
|
|
1170
1484
|
VALUE vout = rb_carray_new(CA_BOOLEAN, ca->ndim, ca->dim, 0, NULL);
|
|
1171
1485
|
CArray *cout;
|
|
1172
1486
|
GetCArray(vout, cout);
|
|
1173
1487
|
{
|
|
1174
|
-
ca_iter_state st_in, st_out;
|
|
1488
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
1175
1489
|
char *p_in, *p_out;
|
|
1176
1490
|
boolean8_t *m;
|
|
1177
1491
|
ca_size_t n;
|
|
@@ -1188,21 +1502,14 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1188
1502
|
} \
|
|
1189
1503
|
} while (0)
|
|
1190
1504
|
|
|
1191
|
-
#define IN_PROBE_FLOAT(T
|
|
1505
|
+
#define IN_PROBE_FLOAT(T) \
|
|
1192
1506
|
do { \
|
|
1193
1507
|
const T *ip = (const T *) p_in; \
|
|
1194
1508
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
1195
1509
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1196
1510
|
if ( m && m[i] ) { op[i] = 0; continue; } \
|
|
1197
1511
|
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
|
-
} \
|
|
1512
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1206
1513
|
op[i] = (boolean8_t) fz_hash_lookup(&h, key, NULL); \
|
|
1207
1514
|
} \
|
|
1208
1515
|
} while (0)
|
|
@@ -1227,7 +1534,7 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1227
1534
|
} \
|
|
1228
1535
|
} while (0)
|
|
1229
1536
|
|
|
1230
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cout, axis,
|
|
1537
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cout, axis,
|
|
1231
1538
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
1232
1539
|
switch ( dt ) {
|
|
1233
1540
|
case CA_INT8: IN_PROBE(int8_t, (int64_t)); break;
|
|
@@ -1238,8 +1545,8 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1238
1545
|
case CA_UINT16: IN_PROBE(uint16_t, (uint64_t)); break;
|
|
1239
1546
|
case CA_UINT32: IN_PROBE(uint32_t, (uint64_t)); break;
|
|
1240
1547
|
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
|
|
1548
|
+
case CA_FLOAT32: IN_PROBE_FLOAT(float); break;
|
|
1549
|
+
case CA_FLOAT64: IN_PROBE_FLOAT(double); break;
|
|
1243
1550
|
case CA_OBJECT: IN_PROBE_OBJ; break;
|
|
1244
1551
|
case CA_FIXLEN: IN_PROBE_MEM; break;
|
|
1245
1552
|
}
|
|
@@ -1259,6 +1566,12 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1259
1566
|
return vout;
|
|
1260
1567
|
}
|
|
1261
1568
|
|
|
1569
|
+
static VALUE
|
|
1570
|
+
rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
1571
|
+
{
|
|
1572
|
+
return fz_run(fz_is_in_body, self, rvalues, Qnil, 0);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1262
1575
|
/* @overload __locate_addr__(ref)
|
|
1263
1576
|
|
|
1264
1577
|
INTERNAL (CArray#locate_addr, exact hash lane). For each cell of self, the
|
|
@@ -1276,16 +1589,19 @@ rb_ca_is_in (VALUE self, VALUE rvalues)
|
|
|
1276
1589
|
appearance order (matching the discovery family); on a `ref` with duplicate
|
|
1277
1590
|
values this is the earliest address, which can differ from the bsearch lane. */
|
|
1278
1591
|
static VALUE
|
|
1279
|
-
|
|
1592
|
+
fz_locate_addr_body (VALUE arg)
|
|
1280
1593
|
{
|
|
1594
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1595
|
+
VALUE self = fr->self;
|
|
1596
|
+
VALUE rref = fr->a;
|
|
1281
1597
|
CArray *ca, *cr;
|
|
1282
1598
|
/* Here the *reference* is the argument (self is the query being placed on
|
|
1283
1599
|
rref), so the gate runs the other way round: rref reconciles self. The
|
|
1284
1600
|
output is an address, so nothing is lifted back. */
|
|
1285
1601
|
{
|
|
1286
1602
|
volatile VALUE ref_face;
|
|
1287
|
-
rref = fz_face_descend(rref, &ref_face, "locate_addr");
|
|
1288
|
-
self = fz_face_reconcile(ref_face, self, "locate_addr");
|
|
1603
|
+
fr->a = rref = fz_face_descend(rref, &ref_face, "locate_addr");
|
|
1604
|
+
fr->self = self = fz_face_reconcile(ref_face, self, "locate_addr");
|
|
1289
1605
|
}
|
|
1290
1606
|
GetCArray(self, ca);
|
|
1291
1607
|
|
|
@@ -1308,9 +1624,16 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1308
1624
|
rb_raise(rb_eArgError, "__locate_addr__: ref must be a CArray");
|
|
1309
1625
|
}
|
|
1310
1626
|
GetCArray(rref, cr);
|
|
1311
|
-
if ( cr->data_type != dt
|
|
1627
|
+
if ( cr->data_type != dt ) {
|
|
1312
1628
|
rb_raise(rb_eCADataTypeError,
|
|
1313
|
-
"
|
|
1629
|
+
"locate_addr: ref data type (%s) must match self (%s)",
|
|
1630
|
+
ca_type_name[cr->data_type], ca_type_name[dt]);
|
|
1631
|
+
}
|
|
1632
|
+
if ( dt == CA_FIXLEN && cr->bytes != ca->bytes ) {
|
|
1633
|
+
rb_raise(rb_eCADataTypeError,
|
|
1634
|
+
"locate_addr: a fixlen value is a cell-width blob, so ref "
|
|
1635
|
+
"must be %ld bytes wide like self, not %ld",
|
|
1636
|
+
(long) ca->bytes, (long) cr->bytes);
|
|
1314
1637
|
}
|
|
1315
1638
|
if ( cr->ndim < 1 ) {
|
|
1316
1639
|
rb_raise(rb_eRuntimeError, "__locate_addr__: ref need ndim >= 1");
|
|
@@ -1325,11 +1648,11 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1325
1648
|
the ref value carrying dense code `code`. Codes are assigned 0,1,2,... in
|
|
1326
1649
|
insertion order, so pushing on is_new fills addr.p in code order. */
|
|
1327
1650
|
fz_levels addr;
|
|
1328
|
-
fz_levels_init(&addr, (int) sizeof(int64_t));
|
|
1651
|
+
fz_levels_init(&addr, (int) sizeof(int64_t), 0);
|
|
1329
1652
|
|
|
1330
1653
|
/* ---- Phase 1: build value -> first-address map from ref (row-major). ----- */
|
|
1331
1654
|
{
|
|
1332
|
-
ca_iter_state st_r;
|
|
1655
|
+
ca_iter_state *st_r = &fr->st[0];
|
|
1333
1656
|
char *p_r;
|
|
1334
1657
|
boolean8_t *mr;
|
|
1335
1658
|
ca_size_t nr;
|
|
@@ -1349,20 +1672,13 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1349
1672
|
} \
|
|
1350
1673
|
} while (0)
|
|
1351
1674
|
|
|
1352
|
-
#define LOC_BUILD_FLOAT(T
|
|
1675
|
+
#define LOC_BUILD_FLOAT(T) \
|
|
1353
1676
|
do { \
|
|
1354
1677
|
const T *ip = (const T *) p_r; \
|
|
1355
1678
|
for ( ca_size_t i = 0; i < nr; i++ ) { \
|
|
1356
1679
|
if ( mr && mr[i] ) { continue; } \
|
|
1357
1680
|
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
|
-
} \
|
|
1681
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1366
1682
|
int is_new; \
|
|
1367
1683
|
fz_hash_intern(&h, key, &is_new); \
|
|
1368
1684
|
if ( is_new ) { int64_t a = (int64_t) (base + i); \
|
|
@@ -1394,7 +1710,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1394
1710
|
} \
|
|
1395
1711
|
} while (0)
|
|
1396
1712
|
|
|
1397
|
-
CA_FOR_EACH_FIBER_MASKED(st_r, cr, raxis, CA_KERNEL_READ, p_r, nr, mr) {
|
|
1713
|
+
CA_FOR_EACH_FIBER_MASKED(*st_r, cr, raxis, CA_KERNEL_READ, p_r, nr, mr) {
|
|
1398
1714
|
switch ( dt ) {
|
|
1399
1715
|
case CA_INT8: LOC_BUILD(int8_t, (int64_t)); break;
|
|
1400
1716
|
case CA_INT16: LOC_BUILD(int16_t, (int64_t)); break;
|
|
@@ -1404,8 +1720,8 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1404
1720
|
case CA_UINT16: LOC_BUILD(uint16_t, (uint64_t)); break;
|
|
1405
1721
|
case CA_UINT32: LOC_BUILD(uint32_t, (uint64_t)); break;
|
|
1406
1722
|
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
|
|
1723
|
+
case CA_FLOAT32: LOC_BUILD_FLOAT(float); break;
|
|
1724
|
+
case CA_FLOAT64: LOC_BUILD_FLOAT(double); break;
|
|
1409
1725
|
case CA_OBJECT: LOC_BUILD_OBJ; break;
|
|
1410
1726
|
case CA_FIXLEN: LOC_BUILD_MEM; break;
|
|
1411
1727
|
}
|
|
@@ -1422,10 +1738,11 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1422
1738
|
CArray *cout;
|
|
1423
1739
|
GetCArray(vout, cout);
|
|
1424
1740
|
int64_t *out = (int64_t *) cout->ptr;
|
|
1425
|
-
|
|
1741
|
+
volatile VALUE hum = 0;
|
|
1742
|
+
boolean8_t *um = ALLOCV_N(boolean8_t, hum, ca->elements); /* undef flags scratch */
|
|
1426
1743
|
ca_size_t n_undef = 0;
|
|
1427
1744
|
{
|
|
1428
|
-
ca_iter_state st_in;
|
|
1745
|
+
ca_iter_state *st_in = &fr->st[1];
|
|
1429
1746
|
char *p_in;
|
|
1430
1747
|
boolean8_t *m;
|
|
1431
1748
|
ca_size_t n;
|
|
@@ -1446,7 +1763,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1446
1763
|
} \
|
|
1447
1764
|
} while (0)
|
|
1448
1765
|
|
|
1449
|
-
#define LOC_PROBE_FLOAT(T
|
|
1766
|
+
#define LOC_PROBE_FLOAT(T) \
|
|
1450
1767
|
do { \
|
|
1451
1768
|
const T *ip = (const T *) p_in; \
|
|
1452
1769
|
const int64_t *ab = (const int64_t *) addr.p; \
|
|
@@ -1454,14 +1771,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1454
1771
|
ca_size_t o = base + i; \
|
|
1455
1772
|
if ( m && m[i] ) { out[o] = 0; um[o] = 1; n_undef++; continue; } \
|
|
1456
1773
|
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
|
-
} \
|
|
1774
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1465
1775
|
int32_t code; \
|
|
1466
1776
|
if ( fz_hash_lookup(&h, key, &code) ) { out[o] = ab[code]; um[o] = 0; } \
|
|
1467
1777
|
else { out[o] = 0; um[o] = 1; n_undef++; } \
|
|
@@ -1494,7 +1804,7 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1494
1804
|
} \
|
|
1495
1805
|
} while (0)
|
|
1496
1806
|
|
|
1497
|
-
CA_FOR_EACH_FIBER_MASKED(st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1807
|
+
CA_FOR_EACH_FIBER_MASKED(*st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1498
1808
|
switch ( dt ) {
|
|
1499
1809
|
case CA_INT8: LOC_PROBE(int8_t, (int64_t)); break;
|
|
1500
1810
|
case CA_INT16: LOC_PROBE(int16_t, (int64_t)); break;
|
|
@@ -1504,8 +1814,8 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1504
1814
|
case CA_UINT16: LOC_PROBE(uint16_t, (uint64_t)); break;
|
|
1505
1815
|
case CA_UINT32: LOC_PROBE(uint32_t, (uint64_t)); break;
|
|
1506
1816
|
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
|
|
1817
|
+
case CA_FLOAT32: LOC_PROBE_FLOAT(float); break;
|
|
1818
|
+
case CA_FLOAT64: LOC_PROBE_FLOAT(double); break;
|
|
1509
1819
|
case CA_OBJECT: LOC_PROBE_OBJ; break;
|
|
1510
1820
|
case CA_FIXLEN: LOC_PROBE_MEM; break;
|
|
1511
1821
|
}
|
|
@@ -1526,11 +1836,17 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1526
1836
|
ca_create_mask(cout);
|
|
1527
1837
|
memcpy(cout->mask->ptr, um, (size_t) ca->elements);
|
|
1528
1838
|
}
|
|
1529
|
-
|
|
1839
|
+
ALLOCV_END(hum);
|
|
1530
1840
|
|
|
1531
1841
|
return vout;
|
|
1532
1842
|
}
|
|
1533
1843
|
|
|
1844
|
+
static VALUE
|
|
1845
|
+
rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
1846
|
+
{
|
|
1847
|
+
return fz_run(fz_locate_addr_body, self, rref, Qnil, 0);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1534
1850
|
/* Shared body of __intersection__ (keep_when_hit = 1) and __difference__
|
|
1535
1851
|
(keep_when_hit = 0): the distinct values of self that are (resp. are not)
|
|
1536
1852
|
present in `other`, in self's first-appearance order, as a 1-D CArray of
|
|
@@ -1540,12 +1856,16 @@ rb_ca_locate_addr (VALUE self, VALUE rref)
|
|
|
1540
1856
|
lane (numeric `==` + NaN collapse + -0.0 == +0.0, object hash/eql? + NaN
|
|
1541
1857
|
collapse, fixlen byte equality). */
|
|
1542
1858
|
static VALUE
|
|
1543
|
-
|
|
1859
|
+
fz_set_relation_body (VALUE arg)
|
|
1544
1860
|
{
|
|
1861
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
1862
|
+
VALUE self = fr->self;
|
|
1863
|
+
VALUE rother = fr->a;
|
|
1864
|
+
int keep_when_hit = fr->i;
|
|
1545
1865
|
CArray *ca, *co;
|
|
1546
1866
|
volatile VALUE face;
|
|
1547
|
-
self = fz_face_descend(self, &face, "set relation");
|
|
1548
|
-
rother = fz_face_reconcile(face, rother, "set relation");
|
|
1867
|
+
fr->self = self = fz_face_descend(self, &face, "set relation");
|
|
1868
|
+
fr->a = rother = fz_face_reconcile(face, rother, "set relation");
|
|
1549
1869
|
GetCArray(self, ca);
|
|
1550
1870
|
|
|
1551
1871
|
int8_t dt = ca->data_type;
|
|
@@ -1594,15 +1914,15 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1594
1914
|
}
|
|
1595
1915
|
|
|
1596
1916
|
fz_levels lv;
|
|
1597
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1917
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1598
1918
|
|
|
1599
1919
|
/* Build the probe set from every non-masked cell of other. */
|
|
1600
|
-
fz_intern_all(&hoth, co, NULL);
|
|
1920
|
+
fz_intern_all(&fr->st[2], &hoth, co, NULL);
|
|
1601
1921
|
|
|
1602
1922
|
/* Walk self: hself dedups, so each distinct self value is decided once; keep
|
|
1603
1923
|
it when its membership in other equals keep_when_hit. */
|
|
1604
1924
|
int8_t axis = (int8_t) (ca->ndim - 1);
|
|
1605
|
-
ca_iter_state st;
|
|
1925
|
+
ca_iter_state *st = &fr->st[0];
|
|
1606
1926
|
char *p;
|
|
1607
1927
|
boolean8_t *m;
|
|
1608
1928
|
ca_size_t n;
|
|
@@ -1621,20 +1941,13 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1621
1941
|
} \
|
|
1622
1942
|
} while (0)
|
|
1623
1943
|
|
|
1624
|
-
#define SR_FLOAT(T
|
|
1944
|
+
#define SR_FLOAT(T) \
|
|
1625
1945
|
do { \
|
|
1626
1946
|
const T *ip = (const T *) p; \
|
|
1627
1947
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1628
1948
|
if ( m && m[i] ) { continue; } \
|
|
1629
1949
|
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
|
-
} \
|
|
1950
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1638
1951
|
int is_new; \
|
|
1639
1952
|
fz_hash_intern(&hself, key, &is_new); \
|
|
1640
1953
|
if ( is_new && fz_hash_lookup(&hoth, key, NULL) == keep_when_hit ) { \
|
|
@@ -1670,7 +1983,7 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1670
1983
|
} \
|
|
1671
1984
|
} while (0)
|
|
1672
1985
|
|
|
1673
|
-
CA_FOR_EACH_FIBER_MASKED(st, ca, axis, CA_KERNEL_READ, p, n, m) {
|
|
1986
|
+
CA_FOR_EACH_FIBER_MASKED(*st, ca, axis, CA_KERNEL_READ, p, n, m) {
|
|
1674
1987
|
switch ( dt ) {
|
|
1675
1988
|
case CA_INT8: SR(int8_t, (int64_t)); break;
|
|
1676
1989
|
case CA_INT16: SR(int16_t, (int64_t)); break;
|
|
@@ -1680,8 +1993,8 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1680
1993
|
case CA_UINT16: SR(uint16_t, (uint64_t)); break;
|
|
1681
1994
|
case CA_UINT32: SR(uint32_t, (uint64_t)); break;
|
|
1682
1995
|
case CA_UINT64: SR(uint64_t, (uint64_t)); break;
|
|
1683
|
-
case CA_FLOAT32: SR_FLOAT(float
|
|
1684
|
-
case CA_FLOAT64: SR_FLOAT(double
|
|
1996
|
+
case CA_FLOAT32: SR_FLOAT(float); break;
|
|
1997
|
+
case CA_FLOAT64: SR_FLOAT(double); break;
|
|
1685
1998
|
case CA_OBJECT: SR_OBJ; break;
|
|
1686
1999
|
case CA_FIXLEN: SR_MEM; break;
|
|
1687
2000
|
}
|
|
@@ -1708,6 +2021,12 @@ fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
|
1708
2021
|
return fz_face_relift(vlev, face); /* set *values*: give the Face back */
|
|
1709
2022
|
}
|
|
1710
2023
|
|
|
2024
|
+
static VALUE
|
|
2025
|
+
fz_set_relation (VALUE self, VALUE rother, int keep_when_hit)
|
|
2026
|
+
{
|
|
2027
|
+
return fz_run(fz_set_relation_body, self, rother, Qnil, keep_when_hit);
|
|
2028
|
+
}
|
|
2029
|
+
|
|
1711
2030
|
/* @overload __intersection__(other)
|
|
1712
2031
|
INTERNAL (CArray#intersection). 1-D CArray of the distinct values present in
|
|
1713
2032
|
both self and other, in self's first-appearance order. */
|
|
@@ -1733,12 +2052,15 @@ rb_ca_difference (VALUE self, VALUE rother)
|
|
|
1733
2052
|
distinct values first, then other's not-yet-seen ones). Masked cells of
|
|
1734
2053
|
either array do not participate. */
|
|
1735
2054
|
static VALUE
|
|
1736
|
-
|
|
2055
|
+
fz_set_union_body (VALUE arg)
|
|
1737
2056
|
{
|
|
2057
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2058
|
+
VALUE self = fr->self;
|
|
2059
|
+
VALUE rother = fr->a;
|
|
1738
2060
|
CArray *ca, *co;
|
|
1739
2061
|
volatile VALUE face;
|
|
1740
|
-
self = fz_face_descend(self, &face, "union");
|
|
1741
|
-
rother = fz_face_reconcile(face, rother, "union");
|
|
2062
|
+
fr->self = self = fz_face_descend(self, &face, "union");
|
|
2063
|
+
fr->a = rother = fz_face_reconcile(face, rother, "union");
|
|
1742
2064
|
GetCArray(self, ca);
|
|
1743
2065
|
|
|
1744
2066
|
int8_t dt = ca->data_type;
|
|
@@ -1760,8 +2082,16 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1760
2082
|
rb_raise(rb_eArgError, "__union__: other must be a CArray");
|
|
1761
2083
|
}
|
|
1762
2084
|
GetCArray(rother, co);
|
|
1763
|
-
if ( co->data_type != dt
|
|
1764
|
-
rb_raise(rb_eCADataTypeError,
|
|
2085
|
+
if ( co->data_type != dt ) {
|
|
2086
|
+
rb_raise(rb_eCADataTypeError,
|
|
2087
|
+
"union: other data type (%s) must match self (%s)",
|
|
2088
|
+
ca_type_name[co->data_type], ca_type_name[dt]);
|
|
2089
|
+
}
|
|
2090
|
+
if ( dt == CA_FIXLEN && co->bytes != ca->bytes ) {
|
|
2091
|
+
rb_raise(rb_eCADataTypeError,
|
|
2092
|
+
"union: a fixlen value is a cell-width blob, so other "
|
|
2093
|
+
"must be %ld bytes wide like self, not %ld",
|
|
2094
|
+
(long) ca->bytes, (long) co->bytes);
|
|
1765
2095
|
}
|
|
1766
2096
|
if ( co->ndim < 1 ) {
|
|
1767
2097
|
rb_raise(rb_eRuntimeError, "__union__: other need ndim >= 1");
|
|
@@ -1773,10 +2103,10 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1773
2103
|
else { fz_hash_init(&h); }
|
|
1774
2104
|
|
|
1775
2105
|
fz_levels lv;
|
|
1776
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
2106
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
1777
2107
|
|
|
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 */
|
|
2108
|
+
fz_intern_all(&fr->st[2], &h, ca, &lv); /* self's distinct values, appearance order */
|
|
2109
|
+
fz_intern_all(&fr->st[2], &h, co, &lv); /* + other's not-yet-seen distinct values */
|
|
1780
2110
|
|
|
1781
2111
|
ca_size_t k = lv.n;
|
|
1782
2112
|
fz_hash_free(&h);
|
|
@@ -1794,6 +2124,12 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1794
2124
|
return fz_face_relift(vlev, face); /* set *values*: give the Face back */
|
|
1795
2125
|
}
|
|
1796
2126
|
|
|
2127
|
+
static VALUE
|
|
2128
|
+
rb_ca_set_union (VALUE self, VALUE rother)
|
|
2129
|
+
{
|
|
2130
|
+
return fz_run(fz_set_union_body, self, rother, Qnil, 0);
|
|
2131
|
+
}
|
|
2132
|
+
|
|
1797
2133
|
/* @overload __value_counts_flat__
|
|
1798
2134
|
|
|
1799
2135
|
INTERNAL (CArray#value_counts). Collect the distinct values of self in
|
|
@@ -1810,11 +2146,13 @@ rb_ca_set_union (VALUE self, VALUE rother)
|
|
|
1810
2146
|
collapses every Float NaN to one value (their counts add up, as numeric does).
|
|
1811
2147
|
*/
|
|
1812
2148
|
static VALUE
|
|
1813
|
-
|
|
2149
|
+
fz_value_counts_flat_body (VALUE arg)
|
|
1814
2150
|
{
|
|
2151
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2152
|
+
VALUE self = fr->self;
|
|
1815
2153
|
CArray *ca;
|
|
1816
2154
|
volatile VALUE face;
|
|
1817
|
-
self = fz_face_descend(self, &face, "value_counts");
|
|
2155
|
+
fr->self = self = fz_face_descend(self, &face, "value_counts");
|
|
1818
2156
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1819
2157
|
|
|
1820
2158
|
int8_t dt = ca->data_type;
|
|
@@ -1839,11 +2177,11 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1839
2177
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
1840
2178
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
1841
2179
|
else { fz_hash_init(&h); }
|
|
1842
|
-
fz_levels_init(&lv, (int) ca->bytes);
|
|
1843
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2180
|
+
fz_levels_init(&lv, (int) ca->bytes, ca->data_type == CA_OBJECT);
|
|
2181
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
1844
2182
|
|
|
1845
2183
|
int8_t axis = (int8_t) (ca->ndim - 1); /* one seen-set over the whole array */
|
|
1846
|
-
ca_iter_state st_in;
|
|
2184
|
+
ca_iter_state *st_in = &fr->st[0];
|
|
1847
2185
|
char *p_in;
|
|
1848
2186
|
boolean8_t *m;
|
|
1849
2187
|
ca_size_t n;
|
|
@@ -1866,20 +2204,13 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1866
2204
|
} \
|
|
1867
2205
|
} while (0)
|
|
1868
2206
|
|
|
1869
|
-
#define VC_LOOP_FLOAT(T
|
|
2207
|
+
#define VC_LOOP_FLOAT(T) \
|
|
1870
2208
|
do { \
|
|
1871
2209
|
const T *ip = (const T *) p_in; \
|
|
1872
2210
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
1873
2211
|
if ( m && m[i] ) { continue; } \
|
|
1874
2212
|
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
|
-
} \
|
|
2213
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
1883
2214
|
int is_new; \
|
|
1884
2215
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
1885
2216
|
if ( is_new ) { \
|
|
@@ -1929,7 +2260,7 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1929
2260
|
} \
|
|
1930
2261
|
} while (0)
|
|
1931
2262
|
|
|
1932
|
-
CA_FOR_EACH_FIBER_MASKED(st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
2263
|
+
CA_FOR_EACH_FIBER_MASKED(*st_in, ca, axis, CA_KERNEL_READ, p_in, n, m) {
|
|
1933
2264
|
switch ( dt ) {
|
|
1934
2265
|
case CA_INT8: VC_LOOP(int8_t, (int64_t)); break;
|
|
1935
2266
|
case CA_INT16: VC_LOOP(int16_t, (int64_t)); break;
|
|
@@ -1939,8 +2270,8 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1939
2270
|
case CA_UINT16: VC_LOOP(uint16_t, (uint64_t)); break;
|
|
1940
2271
|
case CA_UINT32: VC_LOOP(uint32_t, (uint64_t)); break;
|
|
1941
2272
|
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
|
|
2273
|
+
case CA_FLOAT32: VC_LOOP_FLOAT(float); break;
|
|
2274
|
+
case CA_FLOAT64: VC_LOOP_FLOAT(double); break;
|
|
1944
2275
|
case CA_OBJECT: VC_LOOP_OBJ; break;
|
|
1945
2276
|
case CA_FIXLEN: VC_LOOP_MEM; break;
|
|
1946
2277
|
}
|
|
@@ -1973,20 +2304,30 @@ rb_ca_value_counts_flat (VALUE self)
|
|
|
1973
2304
|
return rb_ary_new3(2, fz_face_relift(vlev, face), vcnt);
|
|
1974
2305
|
}
|
|
1975
2306
|
|
|
2307
|
+
static VALUE
|
|
2308
|
+
rb_ca_value_counts_flat (VALUE self)
|
|
2309
|
+
{
|
|
2310
|
+
return fz_run(fz_value_counts_flat_body, self, Qnil, Qnil, 0);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
1976
2313
|
/* @overload __nunique__(axis, keep_axis)
|
|
1977
2314
|
|
|
1978
|
-
INTERNAL (CArray#nunique). Count the distinct values along axis
|
|
1979
|
-
pass per fiber with an independent
|
|
1980
|
-
CA_INT64 CArray of self.shape with
|
|
1981
|
-
keep_axis). Masked cells do not participate; an all-masked fiber counts 0
|
|
2315
|
+
INTERNAL (CArray#nunique). Count the distinct values along axis (an Integer
|
|
2316
|
+
or an Array of them), one linear pass per fiber with an independent
|
|
2317
|
+
seen-set. Returns a reduced CA_INT64 CArray of self.shape with the axes
|
|
2318
|
+
removed (or kept as length-1 when keep_axis). Masked cells do not participate; an all-masked fiber counts 0
|
|
1982
2319
|
(an empty set has zero distinct values, not UNDEF -- nunique has identity 0).
|
|
1983
2320
|
Numeric distinctness collapses all NaN to one value and treats -0.0 == +0.0;
|
|
1984
2321
|
object keys on rb_hash + rb_eql and fixlen on a byte-hash + memcmp, reproducing
|
|
1985
2322
|
Ruby Hash distinctness; the object lane also collapses every Float NaN to one.
|
|
1986
2323
|
*/
|
|
1987
2324
|
static VALUE
|
|
1988
|
-
|
|
2325
|
+
fz_nunique_body (VALUE arg)
|
|
1989
2326
|
{
|
|
2327
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2328
|
+
VALUE self = fr->self;
|
|
2329
|
+
VALUE vaxis = fr->a;
|
|
2330
|
+
VALUE vkeep = fr->b;
|
|
1990
2331
|
CArray *ca;
|
|
1991
2332
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1992
2333
|
|
|
@@ -2006,14 +2347,11 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2006
2347
|
rb_raise(rb_eRuntimeError, "__nunique__: need ndim >= 1");
|
|
2007
2348
|
}
|
|
2008
2349
|
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
rb_raise(rb_eArgError, "__nunique__: axis %d out of range", axis);
|
|
2012
|
-
}
|
|
2350
|
+
int8_t axes[CA_RANK_MAX];
|
|
2351
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw_ctx(vaxis, ca, axes, "nunique");
|
|
2013
2352
|
int keep_axis = RTEST(vkeep);
|
|
2014
2353
|
|
|
2015
|
-
|
|
2016
|
-
VALUE vout = rb_ca_new_reduced(self, &ax, 1, CA_INT64, keep_axis);
|
|
2354
|
+
VALUE vout = rb_ca_new_reduced(self, axes, naxes, CA_INT64, keep_axis);
|
|
2017
2355
|
CArray *cout;
|
|
2018
2356
|
TypedData_Get_Struct(vout, CArray, &carray_data_type, cout);
|
|
2019
2357
|
int64_t *op = (int64_t *) cout->ptr;
|
|
@@ -2023,8 +2361,8 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2023
2361
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
2024
2362
|
else { fz_hash_init(&h); }
|
|
2025
2363
|
|
|
2026
|
-
ca_iter_state st;
|
|
2027
|
-
int rc = ca_iter_state_init_l2(
|
|
2364
|
+
ca_iter_state *st = &fr->st[0];
|
|
2365
|
+
int rc = ca_iter_state_init_l2(st, ca, CA_SLAB_AXES, axes, naxes, 0);
|
|
2028
2366
|
if ( rc != CA_ITER_OK ) {
|
|
2029
2367
|
fz_hash_free(&h);
|
|
2030
2368
|
rb_raise(rb_eRuntimeError, "__nunique__: kernel_iterator init failed rc=%d", rc);
|
|
@@ -2040,17 +2378,10 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2040
2378
|
-0.0 before the bitwise key. */
|
|
2041
2379
|
#define NU_INT(WIDEN) \
|
|
2042
2380
|
do { int _n; fz_hash_intern(&h, (uint64_t) ((WIDEN) v), &_n); } while (0)
|
|
2043
|
-
#define NU_FLOAT(T
|
|
2381
|
+
#define NU_FLOAT(T) \
|
|
2044
2382
|
do { \
|
|
2045
2383
|
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
|
-
} \
|
|
2384
|
+
uint64_t _key = FZ_FLOAT_KEY(T, _v); \
|
|
2054
2385
|
int _n; fz_hash_intern(&h, _key, &_n); \
|
|
2055
2386
|
} while (0)
|
|
2056
2387
|
/* Object: intern the VALUE via the object lane (v is bound by the macro). */
|
|
@@ -2062,43 +2393,43 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2062
2393
|
each esz-wide element via the fixlen lane. */
|
|
2063
2394
|
#define NU_MEM_WALK \
|
|
2064
2395
|
do { \
|
|
2065
|
-
int8_t K = st
|
|
2396
|
+
int8_t K = st->slab_ndim; \
|
|
2066
2397
|
ca_size_t idx[CA_RANK_MAX] = { 0 }; \
|
|
2067
|
-
ca_size_t total = st
|
|
2398
|
+
ca_size_t total = st->slab_elements; \
|
|
2068
2399
|
for ( ca_size_t e = 0; e < total; e++ ) { \
|
|
2069
2400
|
ca_size_t doff = 0, moff = 0; \
|
|
2070
2401
|
for ( int8_t kk = 0; kk < K; kk++ ) { \
|
|
2071
|
-
doff += idx[kk] * st
|
|
2072
|
-
moff += idx[kk] * st
|
|
2402
|
+
doff += idx[kk] * st->slab_strides[kk]; \
|
|
2403
|
+
moff += idx[kk] * st->slab_mask_strides[kk]; \
|
|
2073
2404
|
} \
|
|
2074
2405
|
if ( ! (m && m[moff]) ) { \
|
|
2075
2406
|
int _n; fz_hash_intern_mem(&h, p + doff, &_n); \
|
|
2076
2407
|
} \
|
|
2077
2408
|
for ( int8_t kk = (int8_t)(K - 1); kk >= 0; kk-- ) { \
|
|
2078
|
-
if ( ++idx[kk] < st
|
|
2409
|
+
if ( ++idx[kk] < st->slab_dims[kk] ) break; \
|
|
2079
2410
|
idx[kk] = 0; \
|
|
2080
2411
|
} \
|
|
2081
2412
|
} \
|
|
2082
2413
|
} while (0)
|
|
2083
2414
|
|
|
2084
|
-
while ( ca_iter_state_next_slab_axes(
|
|
2415
|
+
while ( ca_iter_state_next_slab_axes(st, &p, &m) ) {
|
|
2085
2416
|
fz_hash_reset(&h); /* independent seen-set per fiber */
|
|
2086
2417
|
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;
|
|
2418
|
+
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2419
|
+
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2420
|
+
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2421
|
+
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, *st, p, m, dummy, 0, NU_INT(int64_t)); break;
|
|
2422
|
+
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2423
|
+
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2424
|
+
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2425
|
+
case CA_UINT64: CA_SLAB_REDUCE_T(uint64_t, *st, p, m, dummy, 0, NU_INT(uint64_t)); break;
|
|
2095
2426
|
case CA_FLOAT32:
|
|
2096
|
-
CA_SLAB_REDUCE_T(float, st, p, m, dummy, 0, NU_FLOAT(float
|
|
2427
|
+
CA_SLAB_REDUCE_T(float, *st, p, m, dummy, 0, NU_FLOAT(float));
|
|
2097
2428
|
break;
|
|
2098
2429
|
case CA_FLOAT64:
|
|
2099
|
-
CA_SLAB_REDUCE_T(double, st, p, m, dummy, 0, NU_FLOAT(double
|
|
2430
|
+
CA_SLAB_REDUCE_T(double, *st, p, m, dummy, 0, NU_FLOAT(double));
|
|
2100
2431
|
break;
|
|
2101
|
-
case CA_OBJECT: CA_SLAB_REDUCE_T(VALUE, st, p, m, dummy, 0, NU_OBJ); break;
|
|
2432
|
+
case CA_OBJECT: CA_SLAB_REDUCE_T(VALUE, *st, p, m, dummy, 0, NU_OBJ); break;
|
|
2102
2433
|
case CA_FIXLEN: NU_MEM_WALK; break;
|
|
2103
2434
|
}
|
|
2104
2435
|
op[out_i++] = (int64_t) h.n;
|
|
@@ -2109,11 +2440,17 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2109
2440
|
#undef NU_MEM_WALK
|
|
2110
2441
|
(void) dummy;
|
|
2111
2442
|
|
|
2112
|
-
ca_iter_state_finish(
|
|
2443
|
+
ca_iter_state_finish(st);
|
|
2113
2444
|
fz_hash_free(&h);
|
|
2114
2445
|
return vout;
|
|
2115
2446
|
}
|
|
2116
2447
|
|
|
2448
|
+
static VALUE
|
|
2449
|
+
rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
2450
|
+
{
|
|
2451
|
+
return fz_run(fz_nunique_body, fz_complex_as_key(self), vaxis, vkeep, 0);
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2117
2454
|
/* @overload __is_mode__(axis)
|
|
2118
2455
|
|
|
2119
2456
|
INTERNAL (CArray#is_mode). Mark each cell that holds a modal value along axis
|
|
@@ -2132,8 +2469,11 @@ rb_ca_nunique (VALUE self, VALUE vaxis, VALUE vkeep)
|
|
|
2132
2469
|
Callers pass flat input by flattening first (a single fiber over axis 0).
|
|
2133
2470
|
*/
|
|
2134
2471
|
static VALUE
|
|
2135
|
-
|
|
2472
|
+
fz_is_mode_body (VALUE arg)
|
|
2136
2473
|
{
|
|
2474
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2475
|
+
VALUE self = fr->self;
|
|
2476
|
+
VALUE vaxis = fr->a;
|
|
2137
2477
|
CArray *ca;
|
|
2138
2478
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2139
2479
|
|
|
@@ -2166,9 +2506,9 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2166
2506
|
if ( dt == CA_OBJECT ) { fz_hash_init_obj(&h); }
|
|
2167
2507
|
else if ( dt == CA_FIXLEN ) { fz_hash_init_mem(&h, (int) ca->bytes); }
|
|
2168
2508
|
else { fz_hash_init(&h); }
|
|
2169
|
-
fz_levels_init(&ct, (int) sizeof(int64_t));
|
|
2509
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
2170
2510
|
|
|
2171
|
-
ca_iter_state st_in, st_out;
|
|
2511
|
+
ca_iter_state *st_in = &fr->st[0], *st_out = &fr->st[1];
|
|
2172
2512
|
char *p_in, *p_out;
|
|
2173
2513
|
boolean8_t *m;
|
|
2174
2514
|
ca_size_t n;
|
|
@@ -2201,7 +2541,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2201
2541
|
} while (0)
|
|
2202
2542
|
|
|
2203
2543
|
/* Float: NaN collapses to one canonical key; -0.0 / +0.0 share a key. */
|
|
2204
|
-
#define IM_BODY_FLOAT(T
|
|
2544
|
+
#define IM_BODY_FLOAT(T) \
|
|
2205
2545
|
do { \
|
|
2206
2546
|
const T *ip = (const T *) p_in; \
|
|
2207
2547
|
boolean8_t *op = (boolean8_t *) p_out; \
|
|
@@ -2216,14 +2556,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2216
2556
|
for ( ca_size_t i = 0; i < n; i++ ) { \
|
|
2217
2557
|
if ( m && m[i] ) { if ( pass == 1 ) { op[i] = 0; } continue; } \
|
|
2218
2558
|
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
|
-
} \
|
|
2559
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
2227
2560
|
int is_new; \
|
|
2228
2561
|
int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
2229
2562
|
if ( pass == 0 ) { \
|
|
@@ -2287,7 +2620,7 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2287
2620
|
} \
|
|
2288
2621
|
} while (0)
|
|
2289
2622
|
|
|
2290
|
-
CA_FOR_EACH_FIBER_INOUT_MASKED(st_in, st_out, ca, cout, (int8_t) axis,
|
|
2623
|
+
CA_FOR_EACH_FIBER_INOUT_MASKED(*st_in, *st_out, ca, cout, (int8_t) axis,
|
|
2291
2624
|
CA_KERNEL_READ, p_in, p_out, n, m) {
|
|
2292
2625
|
fz_hash_reset(&h); /* independent frequency table per fiber */
|
|
2293
2626
|
ct.n = 0;
|
|
@@ -2300,8 +2633,8 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2300
2633
|
case CA_UINT16: IM_BODY(uint16_t, (uint64_t)); break;
|
|
2301
2634
|
case CA_UINT32: IM_BODY(uint32_t, (uint64_t)); break;
|
|
2302
2635
|
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
|
|
2636
|
+
case CA_FLOAT32: IM_BODY_FLOAT(float); break;
|
|
2637
|
+
case CA_FLOAT64: IM_BODY_FLOAT(double); break;
|
|
2305
2638
|
case CA_OBJECT: IM_BODY_OBJ; break;
|
|
2306
2639
|
case CA_FIXLEN: IM_BODY_MEM; break;
|
|
2307
2640
|
}
|
|
@@ -2316,6 +2649,12 @@ rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
|
2316
2649
|
return vout;
|
|
2317
2650
|
}
|
|
2318
2651
|
|
|
2652
|
+
static VALUE
|
|
2653
|
+
rb_ca_is_mode (VALUE self, VALUE vaxis)
|
|
2654
|
+
{
|
|
2655
|
+
return fz_run(fz_is_mode_body, fz_complex_as_key(self), vaxis, Qnil, 0);
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2319
2658
|
/* Ascending comparison for the modal-value sort, NaN ordered last so a
|
|
2320
2659
|
collapsed NaN key (at most one per fiber) trails the real values, matching
|
|
2321
2660
|
CArray#sort. */
|
|
@@ -2349,11 +2688,14 @@ static int mode_gt_f64 (double a, double b) { if ( a != a ) return b == b; if (
|
|
|
2349
2688
|
its sign), matching the discovery family.
|
|
2350
2689
|
*/
|
|
2351
2690
|
static VALUE
|
|
2352
|
-
|
|
2691
|
+
fz_mode_axis_body (VALUE arg)
|
|
2353
2692
|
{
|
|
2693
|
+
fz_frame *fr = (fz_frame *) arg;
|
|
2694
|
+
VALUE self = fr->self;
|
|
2695
|
+
VALUE vaxis = fr->a;
|
|
2354
2696
|
CArray *ca;
|
|
2355
2697
|
volatile VALUE face;
|
|
2356
|
-
self = fz_face_descend(self, &face, "mode");
|
|
2698
|
+
fr->self = self = fz_face_descend(self, &face, "mode");
|
|
2357
2699
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
2358
2700
|
|
|
2359
2701
|
int8_t dt = ca->data_type;
|
|
@@ -2387,20 +2729,21 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2387
2729
|
fz_levels mod; /* per-fiber modal values, collected then sorted (reset) */
|
|
2388
2730
|
fz_levels flat; /* all fibers' modal values concatenated, fiber order */
|
|
2389
2731
|
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);
|
|
2732
|
+
fz_levels_init(&lv, esz, 0);
|
|
2733
|
+
fz_levels_init(&ct, (int) sizeof(int64_t), 0);
|
|
2734
|
+
fz_levels_init(&mod, esz, 0);
|
|
2735
|
+
fz_levels_init(&flat, esz, 0);
|
|
2394
2736
|
|
|
2395
|
-
|
|
2737
|
+
volatile VALUE hfoff = 0;
|
|
2738
|
+
ca_size_t *foff = ALLOCV_N(ca_size_t, hfoff, M + 1); /* prefix offsets into flat */
|
|
2396
2739
|
foff[0] = 0;
|
|
2397
2740
|
|
|
2398
2741
|
int8_t ax = (int8_t) axis;
|
|
2399
|
-
ca_iter_state st;
|
|
2400
|
-
int rc = ca_iter_state_init_l2(
|
|
2742
|
+
ca_iter_state *st = &fr->st[0];
|
|
2743
|
+
int rc = ca_iter_state_init_l2(st, ca, CA_SLAB_AXES, &ax, 1, 0);
|
|
2401
2744
|
if ( rc != CA_ITER_OK ) {
|
|
2402
2745
|
fz_hash_free(&h); fz_levels_free(&lv); fz_levels_free(&ct);
|
|
2403
|
-
fz_levels_free(&mod); fz_levels_free(&flat);
|
|
2746
|
+
fz_levels_free(&mod); fz_levels_free(&flat); ALLOCV_END(hfoff);
|
|
2404
2747
|
rb_raise(rb_eRuntimeError, "__mode_axis__: kernel_iterator init failed rc=%d", rc);
|
|
2405
2748
|
}
|
|
2406
2749
|
|
|
@@ -2421,12 +2764,9 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2421
2764
|
fz_levels_push(&ct, &one); } \
|
|
2422
2765
|
else { ((int64_t *) ct.p)[code]++; } \
|
|
2423
2766
|
} while (0)
|
|
2424
|
-
#define MB_FLOAT(T
|
|
2767
|
+
#define MB_FLOAT(T) \
|
|
2425
2768
|
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; } \
|
|
2769
|
+
uint64_t key = FZ_FLOAT_KEY(T, v); \
|
|
2430
2770
|
int is_new; int32_t code = fz_hash_intern(&h, key, &is_new); \
|
|
2431
2771
|
if ( is_new ) { int64_t one = 1; fz_levels_push(&lv, &v); \
|
|
2432
2772
|
fz_levels_push(&ct, &one); } \
|
|
@@ -2450,24 +2790,24 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2450
2790
|
for ( ca_size_t x = 0; x < cm; x++ ) { fz_levels_push(&flat, &dp[x]); } \
|
|
2451
2791
|
} while (0)
|
|
2452
2792
|
|
|
2453
|
-
while ( ca_iter_state_next_slab_axes(
|
|
2793
|
+
while ( ca_iter_state_next_slab_axes(st, &p, &m) ) {
|
|
2454
2794
|
fz_hash_reset(&h);
|
|
2455
2795
|
lv.n = 0; ct.n = 0; mod.n = 0;
|
|
2456
2796
|
|
|
2457
2797
|
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;
|
|
2798
|
+
case CA_INT8: CA_SLAB_REDUCE_T(int8_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2799
|
+
case CA_INT16: CA_SLAB_REDUCE_T(int16_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2800
|
+
case CA_INT32: CA_SLAB_REDUCE_T(int32_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2801
|
+
case CA_INT64: CA_SLAB_REDUCE_T(int64_t, *st, p, m, dummy, 0, MB_INT(int64_t)); break;
|
|
2802
|
+
case CA_BOOLEAN: case CA_UINT8: CA_SLAB_REDUCE_T(uint8_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2803
|
+
case CA_UINT16: CA_SLAB_REDUCE_T(uint16_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2804
|
+
case CA_UINT32: CA_SLAB_REDUCE_T(uint32_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2805
|
+
case CA_UINT64: CA_SLAB_REDUCE_T(uint64_t, *st, p, m, dummy, 0, MB_INT(uint64_t)); break;
|
|
2466
2806
|
case CA_FLOAT32:
|
|
2467
|
-
CA_SLAB_REDUCE_T(float, st, p, m, dummy, 0, MB_FLOAT(float
|
|
2807
|
+
CA_SLAB_REDUCE_T(float, *st, p, m, dummy, 0, MB_FLOAT(float));
|
|
2468
2808
|
break;
|
|
2469
2809
|
case CA_FLOAT64:
|
|
2470
|
-
CA_SLAB_REDUCE_T(double, st, p, m, dummy, 0, MB_FLOAT(double
|
|
2810
|
+
CA_SLAB_REDUCE_T(double, *st, p, m, dummy, 0, MB_FLOAT(double));
|
|
2471
2811
|
break;
|
|
2472
2812
|
}
|
|
2473
2813
|
|
|
@@ -2499,7 +2839,7 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2499
2839
|
#undef MODE_EMIT
|
|
2500
2840
|
(void) dummy;
|
|
2501
2841
|
|
|
2502
|
-
ca_iter_state_finish(
|
|
2842
|
+
ca_iter_state_finish(st);
|
|
2503
2843
|
fz_hash_free(&h);
|
|
2504
2844
|
fz_levels_free(&lv);
|
|
2505
2845
|
fz_levels_free(&ct);
|
|
@@ -2529,10 +2869,16 @@ rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
|
2529
2869
|
}
|
|
2530
2870
|
|
|
2531
2871
|
fz_levels_free(&flat);
|
|
2532
|
-
|
|
2872
|
+
ALLOCV_END(hfoff);
|
|
2533
2873
|
return result;
|
|
2534
2874
|
}
|
|
2535
2875
|
|
|
2876
|
+
static VALUE
|
|
2877
|
+
rb_ca_mode_axis (VALUE self, VALUE vaxis)
|
|
2878
|
+
{
|
|
2879
|
+
return fz_run(fz_mode_axis_body, self, vaxis, Qnil, 0);
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2536
2882
|
void
|
|
2537
2883
|
Init_carray_factorize (void)
|
|
2538
2884
|
{
|