First phase of making SORT CASES stable (PR 12035).
[pspp-builds.git] / src / dictionary.c
index 6db18670f5ed3c352f182f901261a40355195cf9..177987b59eb8585a9f72eaaaa89c17da6b9b4b93 100644 (file)
    02111-1307, USA. */
 
 #include <config.h>
-#include "error.h"
+#include "dictionary.h"
 #include <stdlib.h>
 #include "algorithm.h"
 #include "alloc.h"
+#include "case.h"
+#include "error.h"
 #include "hash.h"
 #include "misc.h"
 #include "str.h"
@@ -54,7 +56,7 @@ dict_create (void)
   
   d->var = NULL;
   d->var_cnt = d->var_cap = 0;
-  d->name_tab = hsh_create (8, compare_variables, hash_variable, NULL, NULL);
+  d->name_tab = hsh_create (8, compare_var_names, hash_var_name, NULL, NULL);
   d->next_value_idx = 0;
   d->split = NULL;
   d->split_cnt = 0;
@@ -123,6 +125,7 @@ dict_clear (struct dictionary *d)
   for (i = 0; i < d->var_cnt; i++) 
     {
       struct variable *v = d->var[i];
+      var_clear_aux (v);
       val_labs_destroy (v->val_labs);
       free (v->label);
       free (v); 
@@ -145,6 +148,19 @@ dict_clear (struct dictionary *d)
   dict_clear_vectors (d);
 }
 
+/* Destroys the aux data for every variable in D, by calling
+   var_clear_aux() for each variable. */
+void
+dict_clear_aux (struct dictionary *d) 
+{
+  int i;
+  
+  assert (d != NULL);
+  
+  for (i = 0; i < d->var_cnt; i++)
+    var_clear_aux (d->var[i]);
+}
+
 /* Clears a dictionary and destroys it. */
 void
 dict_destroy (struct dictionary *d)
@@ -253,6 +269,8 @@ dict_create_var (struct dictionary *d, const char *name, int width)
   v->write = v->print;
   v->val_labs = val_labs_create (v->width);
   v->label = NULL;
+  v->aux = NULL;
+  v->aux_dtor = NULL;
 
   /* Update dictionary. */
   if (d->var_cnt >= d->var_cap) 
@@ -374,17 +392,12 @@ dict_contains_var (const struct dictionary *d, const struct variable *v)
 /* Compares two double pointers to variables, which should point
    to elements of a struct dictionary's `var' member array. */
 static int
-compare_variable_dblptrs (const void *a_, const void *b_, void *aux UNUSED) 
+compare_var_ptrs (const void *a_, const void *b_, void *aux UNUSED) 
 {
   struct variable *const *a = a_;
   struct variable *const *b = b_;
 
-  if (a > b)
-    return 1;
-  else if (a < b)
-    return -1;
-  else
-    return 0;
+  return *a < *b ? -1 : *a > *b;
 }
 
 /* Deletes variable V from dictionary D and frees V.
@@ -409,17 +422,19 @@ dict_delete_var (struct dictionary *d, struct variable *v)
   assert (dict_contains_var (d, v));
   assert (d->var[v->index] == v);
 
-  /* Remove v from splits, weight, filter variables. */
+  /* Delete aux data. */
+  var_clear_aux (v);
+
+  /* Remove V from splits, weight, filter variables. */
   d->split_cnt = remove_equal (d->split, d->split_cnt, sizeof *d->split,
-                               &v,
-                               compare_variable_dblptrs, NULL);
+                               &v, compare_var_ptrs, NULL);
   if (d->weight == v)
     d->weight = NULL;
   if (d->filter == v)
     d->filter = NULL;
   dict_clear_vectors (d);
 
-  /* Remove v from var array. */
+  /* Remove V from var array. */
   d->var_cnt--;
   memmove (d->var + v->index, d->var + v->index + 1,
            (d->var_cnt - v->index) * sizeof *d->var);
@@ -558,11 +573,14 @@ dict_get_weight (const struct dictionary *d)
   return d->weight;
 }
 
-/* Returns the value of D's weighting variable in case C, except
-   that a negative weight is returned as 0.  Returns 1 if the
-   dictionary is unweighted. */
+/* Returns the value of D's weighting variable in case C, except that a
+   negative weight is returned as 0.  Returns 1 if the dictionary is
+   unweighted. Will warn about missing, negative, or zero values if
+   warn_on_invalid is nonzero. The function will set warn_on_invalid to zero
+   if an invalid weight is found. */
 double
-dict_get_case_weight (const struct dictionary *d, const struct ccase *c)
+dict_get_case_weight (const struct dictionary *d, const struct ccase *c, 
+                     int *warn_on_invalid)
 {
   assert (d != NULL);
   assert (c != NULL);
@@ -571,9 +589,15 @@ dict_get_case_weight (const struct dictionary *d, const struct ccase *c)
     return 1.0;
   else 
     {
-      double w = c->data[d->weight->fv].f;
-      if (w < 0.0)
+      double w = case_num (c, d->weight->fv);
+      if ( w < 0.0 || w == SYSMIS || is_num_user_missing(w, d->weight) )
         w = 0.0;
+      if ( w == 0.0 && *warn_on_invalid ) {
+         *warn_on_invalid = 0;
+         msg (SW, _("At least one case in the data file had a weight value "
+                    "that was user-missing, system-missing, zero, or "
+                    "negative.  These case(s) were ignored."));
+      }
       return w;
     }
 }
@@ -661,6 +685,7 @@ dict_compact_values (struct dictionary *d)
 {
   size_t i;
 
+  d->next_value_idx = 0;
   for (i = 0; i < d->var_cnt; )
     {
       struct variable *v = d->var[i];
@@ -676,6 +701,30 @@ dict_compact_values (struct dictionary *d)
     }
 }
 
+/* Copies values from SRC, which represents a case arranged
+   according to dictionary D, to DST, which represents a case
+   arranged according to the dictionary that will be produced by
+   dict_compact_values(D). */
+void
+dict_compact_case (const struct dictionary *d,
+                   struct ccase *dst, const struct ccase *src)
+{
+  size_t i;
+  size_t value_idx;
+
+  value_idx = 0;
+  for (i = 0; i < d->var_cnt; i++) 
+    {
+      struct variable *v = d->var[i];
+
+      if (dict_class_from_id (v->name) != DC_SCRATCH)
+        {
+          case_copy (dst, value_idx, src, v->fv, v->nv);
+          value_idx += v->nv;
+        }
+    }
+}
+
 /* Returns the number of values that would be used by a case if
    dict_compact_values() were called. */
 size_t