+
+ return (ctables_check_label_position (t, PIVOT_AXIS_ROW)
+ && ctables_check_label_position (t, PIVOT_AXIS_COLUMN));
+}
+
+static void
+ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
+ enum pivot_axis_type a)
+{
+ struct ctables_stack *stack = &t->stacks[a];
+ for (size_t i = 0; i < stack->n; i++)
+ {
+ const struct ctables_nest *nest = &stack->nests[i];
+ const struct variable *var = nest->vars[nest->n - 1];
+ int width = var_get_width (var);
+ const union value *value = case_data (c, var);
+
+ if (var_is_numeric (var) && value->f == SYSMIS)
+ continue;
+
+ if (!ctables_categories_match (t->categories [var_get_dict_index (var)],
+ value, var))
+ continue;
+
+ unsigned int hash = value_hash (value, width, 0);
+
+ struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
+ if (!clv)
+ {
+ clv = xmalloc (sizeof *clv);
+ value_clone (&clv->value, value, width);
+ hmap_insert (&t->clabels_values_map, &clv->node, hash);
+ }
+ }
+}
+
+static int
+compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
+{
+ const struct ctables_value *const *ap = a_;
+ const struct ctables_value *const *bp = b_;
+ const struct ctables_value *a = *ap;
+ const struct ctables_value *b = *bp;
+ const int *width = width_;
+ return value_compare_3way (&a->value, &b->value, *width);
+}
+
+static void
+ctables_sort_clabels_values (struct ctables_table *t)
+{
+ int width = var_get_width (t->clabels_example);
+
+ size_t n = hmap_count (&t->clabels_values_map);
+ t->clabels_values = xnmalloc (n, sizeof *t->clabels_values);
+
+ struct ctables_value *clv;
+ size_t i = 0;
+ HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
+ t->clabels_values[i++] = clv;
+ t->n_clabels_values = n;
+ assert (i == n);
+
+ sort (t->clabels_values, n, sizeof *t->clabels_values,
+ compare_clabels_values_3way, &width);
+
+ for (size_t i = 0; i < n; i++)
+ t->clabels_values[i]->leaf = i;