give CTABLES its own freq structure
[pspp] / src / language / stats / ctables.c
index 96d12e03fcd4d94c4c5dbddbdf3547b315e560cf..7a18ac5f134e4768f1cc6fdb939d5c16b4f95ee6 100644 (file)
@@ -24,7 +24,6 @@
 #include "language/lexer/format-parser.h"
 #include "language/lexer/lexer.h"
 #include "language/lexer/variable-parser.h"
-#include "language/stats/freq.h"
 #include "libpspp/array.h"
 #include "libpspp/assertion.h"
 #include "libpspp/hmap.h"
 
 enum ctables_vlabel
   {
-    CTVL_DEFAULT = SETTINGS_VALUE_SHOW_DEFAULT,
+    CTVL_NONE = SETTINGS_VALUE_SHOW_DEFAULT,
     CTVL_NAME = SETTINGS_VALUE_SHOW_VALUE,
     CTVL_LABEL = SETTINGS_VALUE_SHOW_LABEL,
     CTVL_BOTH = SETTINGS_VALUE_SHOW_BOTH,
-    CTVL_NONE,
   };
-static void UNUSED
-ctables_vlabel_unique (enum ctables_vlabel vlabel)
-{
-  /* This ensures that all of the values are unique. */
-  switch (vlabel)
-    {
-    case CTVL_DEFAULT:
-    case CTVL_NAME:
-    case CTVL_LABEL:
-    case CTVL_BOTH:
-    case CTVL_NONE:
-      abort ();
-    }
-}
 
 /* XXX:
    - unweighted summaries (U*)
@@ -1354,19 +1338,33 @@ enumerate_fts (const struct ctables_axis *a)
   NOT_REACHED ();
 }
 
+struct ctables_freq
+  {
+    struct hmap_node node;      /* Element in hash table. */
+    double count;
+    union value values[];      /* The value. */
+  };
+
+static struct ctables_freq *
+ctables_freq_allocate (size_t n_values)
+{
+  struct ctables_freq *f;
+  return xmalloc (sizeof *f + n_values * sizeof *f->values);
+}
+
 struct ctables_freqtab
   {
     struct var_array vars;
-    struct hmap data;           /* Contains "struct freq"s. */
-    struct freq **sorted;
+    struct hmap data;           /* Contains "struct ctables_freq"s. */
+    struct ctables_freq **sorted;
   };
 
 static int
-compare_freq_3way (const void *a_, const void *b_, const void *vars_)
+ctables_freq_compare_3way (const void *a_, const void *b_, const void *vars_)
 {
   const struct var_array *vars = vars_;
-  struct freq *const *a = a_;
-  struct freq *const *b = b_;
+  struct ctables_freq *const *a = a_;
+  struct ctables_freq *const *b = b_;
 
   for (size_t i = 0; i < vars->n; i++)
     {
@@ -1375,7 +1373,6 @@ compare_freq_3way (const void *a_, const void *b_, const void *vars_)
       if (cmp)
         return cmp;
     }
-  
   return 0;
 }
 
@@ -1457,8 +1454,8 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
                   hash = value_hash (case_data (c, var), var_get_width (var), hash);
                 }
 
-              struct freq *f;
-              HMAP_FOR_EACH_WITH_HASH (f, struct freq, node, hash, &ft->data)
+              struct ctables_freq *f;
+              HMAP_FOR_EACH_WITH_HASH (f, struct ctables_freq, node, hash, &ft->data)
                 {
                   for (size_t k = 0; k < ft->vars.n; k++)
                     {
@@ -1474,7 +1471,7 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
                 next_hash_node: ;
                 }
 
-              f = xmalloc (table_entry_size (ft->vars.n));
+              f = ctables_freq_allocate (ft->vars.n);
               f->count = weight;
               for (size_t k = 0; k < ft->vars.n; k++)
                 {
@@ -1502,20 +1499,20 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
           struct ctables_freqtab *ft = t->fts[j];
           ft->sorted = xnmalloc (ft->data.count, sizeof *ft->sorted);
 
-          struct freq *f;
+          struct ctables_freq *f;
           size_t n = 0;
-          HMAP_FOR_EACH (f, struct freq, node, &ft->data)
+          HMAP_FOR_EACH (f, struct ctables_freq, node, &ft->data)
             ft->sorted[n++] = f;
           assert (n == ft->data.count);
           sort (ft->sorted, n, sizeof *ft->sorted,
-                compare_freq_3way, &ft->vars);
+                ctables_freq_compare_3way, &ft->vars);
 
           struct pivot_category **groups = xnmalloc (ft->vars.n,
                                                      sizeof *groups);
           for (size_t k = 0; k < n; k++)
             {
-              struct freq *prev = k > 0 ? ft->sorted[k - 1] : NULL;
-              struct freq *f = ft->sorted[k];
+              struct ctables_freq *prev = k > 0 ? ft->sorted[k - 1] : NULL;
+              struct ctables_freq *f = ft->sorted[k];
 
               size_t n_common = 0;
               if (prev)
@@ -1525,23 +1522,31 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
                                     var_get_type (ft->vars.vars[n_common])))
                     break;
 
-              for (size_t m = n_common; m + 1 < ft->vars.n; m++)
+              for (size_t m = n_common; m < ft->vars.n; m++)
                 {
                   struct pivot_category *parent = m > 0 ? groups[m - 1] : d->root;
-                  if (true)
+                  const struct variable *var = ft->vars.vars[m];
+                  enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (var)];
+
+                  if (vlabel != CTVL_NONE)
                     parent = pivot_category_create_group__ (
                       parent, pivot_value_new_variable (ft->vars.vars[m]));
-                  groups[m] = pivot_category_create_group__ (
-                    parent,
-                    pivot_value_new_var_value (ft->vars.vars[m], &f->values[m]));
-                }
 
-              int leaf = pivot_category_create_leaf (
-                ft->vars.n > 1 ? groups[ft->vars.n - 2] : d->root,
-                pivot_value_new_var_value (ft->vars.vars[ft->vars.n - 1],
-                                           &f->values[ft->vars.n - 1]));
+                  if (m + 1 < ft->vars.n)
+                    parent = pivot_category_create_group__ (
+                      parent,
+                      pivot_value_new_var_value (ft->vars.vars[m], &f->values[m]));
+                  groups[m] = parent;
 
-              pivot_table_put1 (pt, leaf, pivot_value_new_number (f->count));
+                  if (m == ft->vars.n - 1)
+                    {
+                      int leaf = pivot_category_create_leaf (
+                        parent,
+                        pivot_value_new_var_value (ft->vars.vars[ft->vars.n - 1],
+                                                   &f->values[ft->vars.n - 1]));
+                      pivot_table_put1 (pt, leaf, pivot_value_new_number (f->count));
+                    }
+                }
             }
           free (groups);
         }
@@ -1555,8 +1560,8 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
       for (size_t j = 0; j < t->n_fts; j++)
         {
           struct ctables_freqtab *ft = t->fts[j];
-          struct freq *f, *next;
-          HMAP_FOR_EACH_SAFE (f, next, struct freq, node, &ft->data)
+          struct ctables_freq *f, *next;
+          HMAP_FOR_EACH_SAFE (f, next, struct ctables_freq, node, &ft->data)
             {
               hmap_delete (&ft->data, &f->node);
               for (size_t k = 0; k < ft->vars.n; k++)
@@ -1582,8 +1587,9 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds)
 {
   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
+  enum settings_value_show tvars = settings_get_show_variables ();
   for (size_t i = 0; i < n_vars; i++)
-    vlabels[i] = CTVL_DEFAULT;
+    vlabels[i] = (enum ctables_vlabel) tvars;
 
   struct ctables *ct = xmalloc (sizeof *ct);
   *ct = (struct ctables) {
@@ -1707,7 +1713,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds)
 
           enum ctables_vlabel vlabel;
           if (lex_match_id (lexer, "DEFAULT"))
-            vlabel = CTVL_DEFAULT;
+            vlabel = (enum ctables_vlabel) settings_get_show_variables ();
           else if (lex_match_id (lexer, "NAME"))
             vlabel = CTVL_NAME;
           else if (lex_match_id (lexer, "LABEL"))