wokr on docs
[pspp] / src / output / pivot-table.c
index 75c7158e11ad115fe7d0cd9bd4effb32c85487fb..93dc74c2d86e8299cbbe3e03e2d6de8a790ef799 100644 (file)
@@ -2374,8 +2374,15 @@ get_text_from_markup (const char *markup, struct string *out)
   xmlFreeParserCtxt (parser);
 }
 
-/* Appends a text representation of the body of VALUE to OUT.  Settings on
-   PT control whether variable and value labels are included.
+static const struct pivot_table pivot_value_format_defaults = {
+  .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
+  .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
+  .settings = FMT_SETTINGS_INIT,
+};
+
+/* Appends a text representation of the body of VALUE to OUT.  Settings on PT
+   control whether variable and value labels are included (pass NULL for PT to
+   get default formatting in the absence of a pivot table).
 
    The "body" omits subscripts and superscripts and footnotes.
 
@@ -2383,9 +2390,10 @@ get_text_from_markup (const char *markup, struct string *out)
    otherwise.  */
 bool
 pivot_value_format_body (const struct pivot_value *value,
-                         const struct pivot_table *pt,
+                         const struct pivot_table *pt_,
                          struct string *out)
 {
+  const struct pivot_table *pt = pt_ ? pt_ : &pivot_value_format_defaults;
   enum settings_value_show show;
   bool numeric = false;
 
@@ -2476,8 +2484,9 @@ pivot_value_format_body (const struct pivot_value *value,
   return numeric;
 }
 
-/* Appends a text representation of VALUE to OUT.  Settings on
-   PT control whether variable and value labels are included.
+/* Appends a text representation of VALUE to OUT.  Settings on PT control
+   whether variable and value labels are included (pass NULL for PT to get
+   default formatting in the absence of a pivot table).
 
    Subscripts and footnotes are included.
 
@@ -2485,9 +2494,10 @@ pivot_value_format_body (const struct pivot_value *value,
    otherwise.  */
 bool
 pivot_value_format (const struct pivot_value *value,
-                    const struct pivot_table *pt,
+                    const struct pivot_table *pt_,
                     struct string *out)
 {
+  const struct pivot_table *pt = pt_ ? pt_ : &pivot_value_format_defaults;
   bool numeric = pivot_value_format_body (value, pt, out);
 
   const struct pivot_value_ex *ex = value->ex;
@@ -2515,7 +2525,9 @@ pivot_value_format (const struct pivot_value *value,
 }
 
 /* Returns a text representation of VALUE.  The caller must free the string,
-   with free(). */
+   with free().  Settings on PT control whether variable and value labels are
+   included (pass NULL for PT to get default formatting in the absence of a
+   pivot table). */
 char *
 pivot_value_to_string (const struct pivot_value *value,
                        const struct pivot_table *pt)
@@ -2525,17 +2537,6 @@ pivot_value_to_string (const struct pivot_value *value,
   return ds_steal_cstr (&s);
 }
 
-char *
-pivot_value_to_string_defaults (const struct pivot_value *value)
-{
-  static const struct pivot_table pt = {
-    .show_values = SETTINGS_VALUE_SHOW_DEFAULT,
-    .show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
-    .settings = FMT_SETTINGS_INIT,
-  };
-  return pivot_value_to_string (value, &pt);
-}
-
 struct pivot_value *
 pivot_value_clone (const struct pivot_value *old)
 {
@@ -3048,12 +3049,20 @@ struct pivot_splits_var
     struct hmap values;
   };
 
+struct pivot_splits_dup
+  {
+    struct hmap_node hmap_node;
+    union value *values;
+  };
+
 struct pivot_splits
   {
     struct pivot_splits_var *vars;
     size_t n;
     char *encoding;
 
+    struct hmap dups;
+
     size_t dindexes[MAX_SPLITS];
 
     int warnings_left;
@@ -3101,6 +3110,7 @@ pivot_splits_create (struct pivot_table *pt,
     .vars = psvars,
     .n = n,
     .encoding = xstrdup (dict_get_encoding (dict)),
+    .dups = HMAP_INITIALIZER (ps->dups),
     .dindexes = { [0] = SIZE_MAX },
     .warnings_left = 5,
   };
@@ -3121,6 +3131,17 @@ pivot_splits_destroy (struct pivot_splits *ps)
                        "split values.", -ps->warnings_left),
          -ps->warnings_left);
 
+  struct pivot_splits_dup *dup, *next_dup;
+  HMAP_FOR_EACH_SAFE (dup, next_dup, struct pivot_splits_dup, hmap_node,
+                      &ps->dups)
+    {
+      for (size_t i = 0; i < ps->n; i++)
+        value_destroy (&dup->values[i], ps->vars[i].width);
+      free (dup->values);
+      free (dup);
+    }
+  hmap_destroy (&ps->dups);
+
   for (size_t i = 0; i < ps->n; i++)
     {
       struct pivot_splits_var *psvar = &ps->vars[i];
@@ -3135,6 +3156,7 @@ pivot_splits_destroy (struct pivot_splits *ps)
       hmap_destroy (&psvar->values);
     }
   free (ps->vars);
+
   free (ps->encoding);
   free (ps);
 }
@@ -3151,6 +3173,45 @@ pivot_splits_value_find (struct pivot_splits_var *psvar,
   return NULL;
 }
 
+static bool
+pivot_splits_find_dup (struct pivot_splits *ps, const struct ccase *example)
+{
+  unsigned int hash = 0;
+  for (size_t i = 0; i < ps->n; i++)
+    {
+      struct pivot_splits_var *psvar = &ps->vars[i];
+      const union value *value = case_data (example, psvar->var);
+      hash = value_hash (value, psvar->width, hash);
+    }
+  struct pivot_splits_dup *dup;
+  HMAP_FOR_EACH_WITH_HASH (dup, struct pivot_splits_dup, hmap_node, hash,
+                           &ps->dups)
+    {
+      bool equal = true;
+      for (size_t i = 0; i < ps->n && equal; i++)
+        {
+          struct pivot_splits_var *psvar = &ps->vars[i];
+          const union value *value = case_data (example, psvar->var);
+          equal = value_equal (value, &dup->values[i], psvar->width);
+        }
+      if (equal)
+        return true;
+    }
+
+  union value *values = xmalloc (ps->n * sizeof *values);
+  for (size_t i = 0; i < ps->n; i++)
+    {
+      struct pivot_splits_var *psvar = &ps->vars[i];
+      const union value *value = case_data (example, psvar->var);
+      value_clone (&values[i], value, psvar->width);
+    }
+
+  dup = xmalloc (sizeof *dup);
+  dup->values = values;
+  hmap_insert (&ps->dups, &dup->hmap_node, hash);
+  return false;
+}
+
 /* Begins adding data for a new split file group to the pivot table associated
    with PS.  EXAMPLE should be a case from the new split file group.
 
@@ -3164,7 +3225,6 @@ pivot_splits_new_split (struct pivot_splits *ps, const struct ccase *example)
   if (!ps)
     return;
 
-  size_t n_new = 0;
   for (size_t i = 0; i < ps->n; i++)
     {
       struct pivot_splits_var *psvar = &ps->vars[i];
@@ -3179,13 +3239,12 @@ pivot_splits_new_split (struct pivot_splits *ps, const struct ccase *example)
           psval->leaf = pivot_category_create_leaf (
             psvar->dimension->root,
             pivot_value_new_var_value (psvar->var, value));
-          n_new++;
         }
 
       ps->dindexes[i] = psval->leaf;
     }
 
-  if (!n_new)
+  if (pivot_splits_find_dup (ps, example))
     {
       if (ps->warnings_left-- > 0)
         {
@@ -3230,7 +3289,7 @@ pivot_splits_get_dindexes (const struct pivot_splits *ps, size_t *dindexes)
 
   assert (ps->dindexes[0] != SIZE_MAX);
   for (size_t i = 0; i < ps->n; i++)
-    dindexes[i] = ps->dindexes[i];
+    dindexes[ps->n - i - 1] = ps->dindexes[i];
   return ps->n;
 }