Make "internal variables" part of a dictionary.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 9 Apr 2010 04:06:43 +0000 (21:06 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 12 Apr 2010 03:50:14 +0000 (20:50 -0700)
The "internal variables" created by var_create_internal() are somewhat of
a nasty corner case in the PSPP dictionary and variable implementation,
because they are the only variables that have a case index and
dictionary index but do not belong to a dictionary.  This commit fixes
that wart, by putting internal variables in a dictionary that is used just
for them.  It adds an assertion to var_set_vardict() to ensure that this
is now an invariant property.

As part of the change, var_create_internal() is renamed
dict_Create_internal_var() and moved to dictionary.c, since it fits better
there.  Also, a new function dict_destroy_internal_var() must now be used
to destroy internal variables.

The dictionary indexes of internal variables are no longer unique
process-wide.  A previous commit eliminated the dependencies on this
property.

src/data/dictionary.c
src/data/dictionary.h
src/data/variable.c
src/data/variable.h
src/language/stats/aggregate.c
src/language/stats/wilcoxon.c
src/math/interaction.c

index bca92dabe300b4c34439845c47abf485c900a778..6e6ab1edb4b1b0654390855fc2990a4599876596 100644 (file)
@@ -1474,4 +1474,52 @@ dict_var_display_width_changed (const struct variable *v)
        d->callbacks->var_display_width_changed (d, var_get_dict_index (v), d->cb_data);
     }
 }
+\f
+/* Dictionary used to contain "internal variables". */
+static struct dictionary *internal_dict;
+
+/* Create a variable of the specified WIDTH to be used for internal
+   calculations only.  The variable is assigned case index CASE_IDX. */
+struct variable *
+dict_create_internal_var (int case_idx, int width)
+{
+  if (internal_dict == NULL)
+    internal_dict = dict_create ();
+
+  for (;;)
+    {
+      static int counter = INT_MAX / 2;
+      struct variable *var;
+      char name[64];
+
+      if (++counter == INT_MAX)
+        counter = INT_MAX / 2;
+
+      sprintf (name, "$internal%d", counter);
+      var = dict_create_var (internal_dict, name, width);
+      if (var != NULL)
+        {
+          set_var_case_index (var, case_idx);
+          return var;
+        }
+    }
+}
+
+/* Destroys VAR, which must have been created with
+   dict_create_internal_var(). */
+void
+dict_destroy_internal_var (struct variable *var)
+{
+  if (var != NULL)
+    {
+      dict_delete_var (internal_dict, var);
 
+      /* Destroy internal_dict if it has no variables left, just so that
+         valgrind --leak-check --show-reachable won't show internal_dict. */
+      if (dict_get_var_cnt (internal_dict) == 0)
+        {
+          dict_destroy (internal_dict);
+          internal_dict = NULL;
+        }
+    }
+}
index 780d5a9412823d0bbf4ab3993a6d5df07f4af228..0b3c6cd273aae6e8a27357bf0a1a3104963cb0bb 100644 (file)
@@ -154,10 +154,13 @@ struct attrset *dict_get_attributes (const struct dictionary *);
 void dict_set_attributes (struct dictionary *, const struct attrset *);
 bool dict_has_attributes (const struct dictionary *);
 
-
+/* Data encoding. */
 void dict_set_encoding (struct dictionary *d, const char *enc);
 const char *dict_get_encoding (const struct dictionary *d);
 
+/* Internal variables. */
+struct variable *dict_create_internal_var (int case_idx, int width);
+void dict_destroy_internal_var (struct variable *);
 
 /* Functions to be called upon dictionary changes. */
 struct dict_callbacks
index 79925fa8cbfb00dd4c47c66e085fab1a12162fb3..dd5e6152f3f42a13bc4b7b71a848eb9caadd818b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -149,27 +149,6 @@ var_clone (const struct variable *old_var)
   return new_var;
 }
 
-/* Create a variable of the specified WIDTH to be used for
-   internal calculations only.  The variable is assigned a unique
-   dictionary index and a case index of CASE_IDX. */
-struct variable *
-var_create_internal (int case_idx, int width)
-{
-  struct variable *v = var_create ("$internal", width);
-  struct vardict_info vdi;
-  static int counter = INT_MAX / 2;
-
-  vdi.dict = NULL;
-  vdi.case_index = case_idx;
-  vdi.dict_index = counter++;
-  if (counter == INT_MAX)
-    counter = INT_MAX / 2;
-
-  var_set_vardict (v, &vdi);
-
-  return v;
-}
-
 /* Destroys variable V.
    V must not belong to a dictionary.  If it does, use
    dict_delete_var instead. */
@@ -178,11 +157,7 @@ var_destroy (struct variable *v)
 {
   if (v != NULL)
     {
-      if (var_has_vardict (v))
-       {
-         const struct vardict_info *vdi = var_get_vardict (v);
-         assert (vdi->dict == NULL);
-       }
+      assert (!var_has_vardict (v));
       mv_destroy (&v->miss);
       cat_stored_values_destroy (v->obs_vals);
       var_clear_short_names (v);
@@ -1075,6 +1050,7 @@ var_set_vardict (struct variable *v, const struct vardict_info *vardict)
 {
   assert (vardict->dict_index >= 0);
   assert (vardict->case_index >= 0);
+  assert (vardict->dict != NULL);
   v->vardict = *vardict;
 }
 
index d730768e650407fbcaff63fa6649af2e2659a1f7..f1a4c8728ad6ea75e96cbd77f90c101f21763dd1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -32,8 +32,6 @@ union value;
 struct variable *var_create (const char *name, int width);
 struct variable *var_clone (const struct variable *);
 void var_destroy (struct variable *);
-struct variable *var_create_internal (int case_idx, int width);
-
 
 /* Variable names. */
 #define VAR_NAME_LEN 64 /* Maximum length of variable name, in bytes. */
index ba0650937d93f29758b648524192fb1deaed59fe..b54ebf6376bd1500c3f0e616703f84e2c07a1026 100644 (file)
@@ -711,8 +711,8 @@ agr_destroy (struct agr_proc *agr)
       else if (iter->function == SD)
         moments1_destroy (iter->moments);
 
-      var_destroy (iter->subject);
-      var_destroy (iter->weight);
+      dict_destroy_internal_var (iter->subject);
+      dict_destroy_internal_var (iter->weight);
 
       free (iter);
     }
@@ -1105,10 +1105,10 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
             proto = caseproto_add_width (proto, 0);
 
            if ( ! iter->subject)
-             iter->subject = var_create_internal (0, 0);
+             iter->subject = dict_create_internal_var (0, 0);
 
            if ( ! iter->weight)
-             iter->weight = var_create_internal (1, 0);
+             iter->weight = dict_create_internal_var (1, 0);
 
             subcase_init_var (&ordering, iter->subject, SC_ASCEND);
            iter->writer = sort_create_writer (&ordering, proto);
index e1dab91c9ff661cbf3d64618e9f5edb7a7b703d8..197124cf6025fbe001a1763360307b80d5ddbda0 100644 (file)
@@ -1,5 +1,5 @@
 /* Pspp - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -88,7 +88,7 @@ wilcoxon_execute (const struct dataset *ds,
 
   struct wilcoxon_state *ws = xcalloc (sizeof (*ws), t2s->n_pairs);
   const struct variable *weight = dict_get_weight (dict);
-  struct variable *weightx = var_create_internal (WEIGHT_IDX, 0);
+  struct variable *weightx = dict_create_internal_var (WEIGHT_IDX, 0);
   struct caseproto *proto;
 
   input =
@@ -108,8 +108,8 @@ wilcoxon_execute (const struct dataset *ds,
       struct subcase ordering;
       variable_pair *vp = &t2s->pairs[i];
 
-      ws[i].sign = var_create_internal (0, 0);
-      ws[i].absdiff = var_create_internal (1, 0);
+      ws[i].sign = dict_create_internal_var (0, 0);
+      ws[i].absdiff = dict_create_internal_var (1, 0);
 
       r = casereader_create_filter_missing (r, *vp, 2,
                                            exclude,
@@ -195,15 +195,15 @@ wilcoxon_execute (const struct dataset *ds,
 
   casereader_destroy (input);
 
-  var_destroy (weightx);
+  dict_destroy_internal_var (weightx);
 
   show_ranks_box (ws, t2s, dict);
   show_tests_box (ws, t2s, exact, timer);
 
   for (i = 0 ; i < t2s->n_pairs; ++i )
     {
-      var_destroy (ws[i].sign);
-      var_destroy (ws[i].absdiff);
+      dict_destroy_internal_var (ws[i].sign);
+      dict_destroy_internal_var (ws[i].absdiff);
     }
 
   free (ws);
index aa8826e01ac7869c989088a9d4e9444ee07a7df9..2f8da8ccaaa1fd4619a73415a8ff888cd097d9ac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
 
 #include <config.h>
 #include <assert.h>
+#include <data/dictionary.h>
 #include <data/value.h>
 #include <data/variable.h>
 #include <gl/unistr.h>
@@ -84,14 +85,14 @@ interaction_variable_create (const struct variable **vars, int n_vars)
              width += var_get_width (vars[i]);
            }
        }
-      result->intr = var_create_internal (0, width);
+      result->intr = dict_create_internal_var (0, width);
     }
 
   return result;
 }
 void interaction_variable_destroy (struct interaction_variable *iv)
 {
-  var_destroy (iv->intr);
+  dict_destroy_internal_var (iv->intr);
   free (iv->members);
   free (iv);
 }