dictionary: Always compact immediately upon deletion of a variable.
[pspp] / src / data / dictionary.c
index 7a4d094e78994d45f81cfa14836b4dd2e4e85f7b..2c4633f7f9804b93b87570598481d813fad77488 100644 (file)
@@ -65,7 +65,6 @@ struct dictionary
     struct caseproto *proto;    /* Prototype for dictionary cases
                                    (updated lazily). */
     struct hmap name_map;      /* Variable index by name. */
-    int next_value_idx;         /* Index of next `union value' to allocate. */
     const struct variable **split;    /* SPLIT FILE vars. */
     size_t n_splits;            /* SPLIT FILE count. */
     enum split_type split_type;
@@ -293,12 +292,6 @@ dict_create (const char *encoding)
 /* Creates and returns a (deep) copy of an existing
    dictionary.
 
-   The new dictionary's case indexes are copied from the old
-   dictionary.  If the new dictionary won't be used to access
-   cases produced with the old dictionary, then the new
-   dictionary's case indexes should be compacted with
-   dict_compact_values to save space.
-
    Callbacks are not cloned. */
 struct dictionary *
 dict_clone (const struct dictionary *s)
@@ -317,8 +310,6 @@ dict_clone (const struct dictionary *s)
       var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index;
     }
 
-  d->next_value_idx = s->next_value_idx;
-
   d->n_splits = s->n_splits;
   if (d->n_splits > 0)
     {
@@ -487,7 +478,6 @@ static void
 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
 {
   int dict_index = var_get_dict_index (v);
-  const int case_index = var_get_case_index (v);
 
   assert (dict_contains_var (d, v));
 
@@ -517,8 +507,8 @@ dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks
   if (! skip_callbacks)
     {
       if (d->changed) d->changed (d, d->changed_data);
-      if (d->callbacks &&  d->callbacks->var_deleted)
-        d->callbacks->var_deleted (d, v, dict_index, case_index, d->cb_data);
+      if (d->callbacks &&  d->callbacks->vars_deleted)
+        d->callbacks->vars_deleted (d, dict_index, 1, d->cb_data);
     }
 
   invalidate_proto (d);
@@ -542,6 +532,7 @@ void
 dict_delete_var (struct dictionary *d, struct variable *v)
 {
   dict_delete_var__ (d, v, false);
+  dict_compact_values (d);
 }
 
 
@@ -557,6 +548,7 @@ dict_delete_vars (struct dictionary *d,
 
   while (count-- > 0)
     dict_delete_var (d, *vars++);
+  dict_compact_values (d);
 }
 
 /* Deletes the COUNT variables in D starting at index IDX.  This
@@ -578,7 +570,6 @@ dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
   struct delvar {
     struct ll ll;
     struct variable *var;
-    int case_index;
   };
   struct ll_list list = LL_INITIALIZER (list);
 
@@ -599,7 +590,6 @@ dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
        dict_set_filter (d, NULL);
 
       dv->var = v;
-      dv->case_index = var_get_case_index (v);
       ll_push_tail (&list, (struct ll *)dv);
     }
 
@@ -620,15 +610,17 @@ dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
      the variables. The vardict is not valid at this point
      anymore. That is the reason why we stored the
      caseindex before reindexing. */
+  if (d->callbacks &&  d->callbacks->vars_deleted)
+    d->callbacks->vars_deleted (d, idx, count, d->cb_data);
   for (size_t vi = idx; vi < idx + count; vi++)
     {
       struct delvar *dv = (struct delvar *) ll_pop_head (&list);
       var_clear_vardict (dv->var);
-      if (d->callbacks &&  d->callbacks->var_deleted)
-        d->callbacks->var_deleted (d, dv->var, vi, dv->case_index, d->cb_data);
       var_unref (dv->var);
       free (dv);
     }
+
+  dict_compact_values (d);
 }
 
 /* Deletes scratch variables from dictionary D. */
@@ -644,6 +636,8 @@ dict_delete_scratch_vars (struct dictionary *d)
       dict_delete_var (d, d->vars[i].var);
     else
       i++;
+
+  dict_compact_values (d);
 }
 
 \f
@@ -665,7 +659,6 @@ dict_clear__ (struct dictionary *d, bool skip_callbacks)
   d->n_vars = d->allocated_vars = 0;
   invalidate_proto (d);
   hmap_clear (&d->name_map);
-  d->next_value_idx = 0;
   dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
 
   if (skip_callbacks)
@@ -799,8 +792,6 @@ add_var_with_case_index (struct dictionary *d, struct variable *v,
 {
   struct vardict_info *vardict;
 
-  assert (case_index >= d->next_value_idx);
-
   /* Update dictionary. */
   if (d->n_vars >= d->allocated_vars)
     {
@@ -829,7 +820,6 @@ add_var_with_case_index (struct dictionary *d, struct variable *v,
     d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
 
   invalidate_proto (d);
-  d->next_value_idx = case_index + 1;
 
   return v;
 }
@@ -837,7 +827,7 @@ add_var_with_case_index (struct dictionary *d, struct variable *v,
 static struct variable *
 add_var (struct dictionary *d, struct variable *v)
 {
-  return add_var_with_case_index (d, v, d->next_value_idx);
+  return add_var_with_case_index (d, v, dict_get_n_vars (d));
 }
 
 /* Creates and returns a new variable in D with the given NAME
@@ -1418,35 +1408,15 @@ dict_get_proto (const struct dictionary *d_)
   return d->proto;
 }
 
-/* Returns the case index of the next value to be added to D.
-   This value is the number of `union value's that need to be
-   allocated to store a case for dictionary D. */
-int
-dict_get_next_value_idx (const struct dictionary *d)
-{
-  return d->next_value_idx;
-}
-
-/* Returns the number of bytes needed to store a case for
-   dictionary D. */
-size_t
-dict_get_case_size (const struct dictionary *d)
-{
-  return sizeof (union value) * dict_get_next_value_idx (d);
-}
-
 /* Reassigns values in dictionary D so that fragmentation is
    eliminated. */
 void
 dict_compact_values (struct dictionary *d)
 {
-  size_t i;
-
-  d->next_value_idx = 0;
-  for (i = 0; i < d->n_vars; i++)
+  for (size_t i = 0; i < d->n_vars; i++)
     {
       struct variable *v = d->vars[i].var;
-      set_var_case_index (v, d->next_value_idx++);
+      set_var_case_index (v, i);
     }
   invalidate_proto (d);
 }
@@ -1454,12 +1424,7 @@ dict_compact_values (struct dictionary *d)
 /* Returns the number of values occupied by the variables in
    dictionary D.  All variables are considered if EXCLUDE_CLASSES
    is 0, or it may contain one or more of DC_ORDINARY, DC_SYSTEM,
-   or DC_SCRATCH to exclude the corresponding type of variable.
-
-   The return value may be less than the number of values in one
-   of dictionary D's cases (as returned by
-   dict_get_next_value_idx) even if E is 0, because there may be
-   gaps in D's cases due to deleted variables. */
+   or DC_SCRATCH to exclude the corresponding type of variable. */
 size_t
 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
 {
@@ -1475,31 +1440,6 @@ dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
   return n;
 }
 
-/* Returns the case prototype that would result after deleting
-   all variables from D that are not in one of the
-   EXCLUDE_CLASSES and compacting the dictionary with
-   dict_compact().
-
-   The caller must unref the returned caseproto when it is no
-   longer needed. */
-struct caseproto *
-dict_get_compacted_proto (const struct dictionary *d,
-                          unsigned int exclude_classes)
-{
-  struct caseproto *proto;
-  size_t i;
-
-  assert (!(exclude_classes & ~DC_ALL));
-
-  proto = caseproto_create ();
-  for (i = 0; i < d->n_vars; i++)
-    {
-      struct variable *v = d->vars[i].var;
-      if (!(exclude_classes & var_get_dict_class (v)))
-        proto = caseproto_add_width (proto, var_get_width (v));
-    }
-  return proto;
-}
 /* Returns the file label for D, or a null pointer if D is
    unlabeled (see cmd_file_label()). */
 const char *
@@ -1966,55 +1906,6 @@ dict_var_changed (const struct variable *v, unsigned int what, struct variable *
 }
 
 
-\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 ("UTF-8");
-
-  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_n_vars (internal_dict) == 0)
-        {
-          dict_unref (internal_dict);
-          internal_dict = NULL;
-        }
-    }
-}
 \f
 int
 vardict_get_dict_index (const struct vardict_info *vardict)