struct ctables_chisq *chisq;
struct ctables_pairwise *pairwise;
-
};
struct ctables_var
};
};
+static const struct ctables_cat_value *ctables_categories_match (
+ const struct ctables_categories *, const union value *,
+ const struct variable *);
+
static void
ctables_cat_value_uninit (struct ctables_cat_value *cv)
{
for (size_t i = 0; i < va->n; i++)
if (i != va->scale_idx)
{
- int cmp = value_compare_3way (&a->axes[aux->a].values[i],
- &b->axes[aux->a].values[i],
- var_get_width (va->vars[i]));
- if (cmp)
+ const struct variable *var = va->vars[i];
+ const union value *val_a = &a->axes[aux->a].values[i];
+ const union value *val_b = &b->axes[aux->a].values[i];
+ int cmp = value_compare_3way (val_a, val_b, var_get_width (var));
+ if (!cmp)
+ continue;
+
+ const struct ctables_categories *cats = aux->t->categories[var_get_dict_index (var)];
+ if (!cats)
return cmp;
+ else if (cats->n_values)
+ {
+ const struct ctables_cat_value *a_cv = ctables_categories_match (cats, val_a, var);
+ const struct ctables_cat_value *b_cv = ctables_categories_match (cats, val_b, var);
+ assert (a_cv && b_cv);
+ return (a_cv == b_cv ? cmp
+ : a_cv > b_cv ? 1
+ : -1);
+ }
+ else
+ {
+ switch (cats->key)
+ {
+ case CTCS_VALUE:
+ /* Nothing to do. */
+ break;
+
+ case CTCS_LABEL:
+ {
+ const char *a_label = var_lookup_value_label (var, val_a);
+ const char *b_label = var_lookup_value_label (var, val_b);
+ int label_cmp = (a_label
+ ? (b_label ? strcmp (a_label, b_label) : 1)
+ : (b_label ? -1 : 0));
+ if (label_cmp)
+ cmp = label_cmp;
+ }
+ break;
+
+ case CTCS_FUNCTION:
+ NOT_REACHED ();
+ }
+
+ return cats->sort_ascending ? cmp : -cmp;
+ }
}
return 0;
}
return d;
}
+static const struct ctables_cat_value *
+ctables_categories_match (const struct ctables_categories *cats,
+ const union value *v, const struct variable *var)
+{
+ const struct ctables_cat_value *othernm = NULL;
+ for (size_t i = cats->n_values; i-- > 0; )
+ {
+ const struct ctables_cat_value *cv = &cats->values[i];
+ switch (cv->type)
+ {
+ case CCVT_NUMBER:
+ if (cv->number == v->f)
+ return cv;
+ break;
+
+ case CCVT_STRING:
+ NOT_REACHED ();
+
+ case CCVT_RANGE:
+ if ((cv->range[0] == -DBL_MAX || v->f >= cv->range[0])
+ && (cv->range[1] == DBL_MAX || v->f <= cv->range[1]))
+ return cv;
+ break;
+
+ case CCVT_MISSING:
+ if (var_is_value_missing (var, v))
+ return cv;
+ break;
+
+ case CCVT_OTHERNM:
+ if (!othernm)
+ othernm = cv;
+ break;
+
+ case CCVT_SUBTOTAL:
+ case CCVT_HSUBTOTAL:
+ break;
+ }
+ }
+
+ return var_is_value_missing (var, v) ? NULL : othernm;
+}
+
static void
ctables_freqtab_insert (struct ctables_table *t,
const struct ccase *c,
};
const struct var_array *ss = &t->vaas[t->summary_axis].vas[ix[t->summary_axis]];
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ const struct var_array *va = &t->vaas[a].vas[ix[a]];
+ for (size_t i = 0; i < va->n; i++)
+ {
+ if (i == va->scale_idx)
+ continue;
+
+ const struct variable *var = va->vars[i];
+ const union value *value = case_data (c, var);
+
+ enum mv_class missing = var_is_value_missing (var, value);
+ if (missing == MV_SYSTEM)
+ return;
+
+ const struct ctables_categories *cats = t->categories[var_get_dict_index (var)];
+ if (!cats)
+ {
+ if (missing)
+ return;
+ }
+ else if (cats->n_values)
+ {
+ if (!ctables_categories_match (cats, value, var))
+ return;
+ }
+ else
+ {
+ if (missing && !cats->include_missing)
+ return;
+ }
+ }
+ }
+
size_t hash = 0;
for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
{