+/* Algorithm:
+
+ For each row:
+ For each ctables_table:
+ For each combination of row vars:
+ For each combination of column vars:
+ For each combination of layer vars:
+ Add entry
+ Make a table of row values:
+ Sort entries by row values
+ Assign a 0-based index to each actual value
+ Construct a dimension
+ Make a table of column values
+ Make a table of layer values
+ For each entry:
+ Fill the table entry using the indexes from before.
+ */
+
+static void
+ctables_freqtab_insert (struct ctables_table *t,
+ const struct ccase *c,
+ size_t ir, size_t ic, size_t il,
+ double weight)
+{
+ size_t ix[PIVOT_N_AXES] = {
+ [PIVOT_AXIS_ROW] = ir,
+ [PIVOT_AXIS_COLUMN] = ic,
+ [PIVOT_AXIS_LAYER] = il,
+ };
+
+ size_t hash = 0;
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ const struct var_array *va = &t->vaas[a].vas[ix[a]];
+ hash = hash_int (ix[a], hash);
+ for (size_t i = 0; i < va->n; i++)
+ hash = value_hash (case_data (c, va->vars[i]),
+ var_get_width (va->vars[i]), hash);
+ }
+
+ struct ctables_freq *f;
+ HMAP_FOR_EACH_WITH_HASH (f, struct ctables_freq, node, hash, &t->ft)
+ {
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ const struct var_array *va = &t->vaas[a].vas[ix[a]];
+ if (f->axes[a].vaa_idx != ix[a])
+ goto not_equal;
+ for (size_t i = 0; i < va->n; i++)
+ if (!value_equal (case_data (c, va->vars[i]),
+ &f->axes[a].values[i],
+ var_get_width (va->vars[i])))
+ goto not_equal;
+ }
+
+ f->count += weight;
+ return;
+
+ not_equal: ;
+ }
+
+ f = xmalloc (sizeof *f);
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ const struct var_array *va = &t->vaas[a].vas[ix[a]];
+ f->axes[a].vaa_idx = ix[a];
+ f->axes[a].values = (va->n
+ ? xnmalloc (va->n, sizeof *f->axes[a].values)
+ : NULL);
+ for (size_t i = 0; i < va->n; i++)
+ value_clone (&f->axes[a].values[i], case_data (c, va->vars[i]),
+ var_get_width (va->vars[i]));
+ }
+ f->count = weight;
+ hmap_insert (&t->ft, &f->node, hash);
+}
+