Reworked very long string support for better encapsulation.
[pspp] / src / data / dictionary.c
index e0afe9bce22b88bdbb7ce62ad949abce9478474b..bf467440aa7ce294cb4f5a9aa7d0fdfef590d01a 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
+
 #include "dictionary.h"
+
 #include <stdlib.h>
 #include <ctype.h>
-#include "array.h"
-#include "alloc.h"
+
 #include "case.h"
-#include "category.h"
 #include "cat-routines.h"
-#include "message.h"
-#include "hash.h"
-#include "misc.h"
+#include "category.h"
 #include "settings.h"
-#include "str.h"
 #include "value-labels.h"
 #include "variable.h"
+#include <libpspp/alloc.h>
+#include <libpspp/array.h>
+#include <libpspp/compiler.h>
+#include <libpspp/hash.h>
+#include <libpspp/message.h>
+#include <libpspp/misc.h>
+#include <libpspp/str.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -48,16 +52,13 @@ struct dictionary
     size_t split_cnt;           /* SPLIT FILE count. */
     struct variable *weight;    /* WEIGHT variable. */
     struct variable *filter;    /* FILTER variable. */
-    int case_limit;             /* Current case limit (N command). */
+    size_t case_limit;          /* Current case limit (N command). */
     char *label;               /* File label. */
     char *documents;           /* Documents, as a string. */
     struct vector **vector;     /* Vectors of variables. */
     size_t vector_cnt;          /* Number of vectors. */
   };
 
-/* Active file dictionary. */
-struct dictionary *default_dict;
-
 /* Creates and returns a new dictionary. */
 struct dictionary *
 dict_create (void) 
@@ -223,9 +224,10 @@ dict_get_var (const struct dictionary *d, size_t idx)
 }
 
 /* Sets *VARS to an array of pointers to variables in D and *CNT
-   to the number of variables in *D.  By default all variables
-   are returned, but bits may be set in EXCLUDE_CLASSES to
-   exclude ordinary, system, and/or scratch variables. */
+   to the number of variables in *D.  All variables are returned
+   if EXCLUDE_CLASSES is 0, or it may contain one or more of (1u
+   << DC_ORDINARY), (1u << DC_SYSTEM), or (1u << DC_SCRATCH) to
+   exclude the corresponding type of variable. */
 void
 dict_get_vars (const struct dictionary *d, struct variable ***vars,
                size_t *cnt, unsigned exclude_classes)
@@ -265,9 +267,9 @@ dict_create_var (struct dictionary *d, const char *name, int width)
   assert (d != NULL);
   assert (name != NULL);
 
-  assert (width >= 0 && width < 256);
+  assert (width >= 0 && width <= MAX_STRING);
 
-  assert (var_is_valid_name(name,0));
+  assert (var_is_plausible_name(name,0));
     
   /* Make sure there's not already a variable by that name. */
   if (dict_lookup_var (d, name) != NULL)
@@ -279,9 +281,8 @@ dict_create_var (struct dictionary *d, const char *name, int width)
   v->type = width == 0 ? NUMERIC : ALPHA;
   v->width = width;
   v->fv = d->next_value_idx;
-  v->nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
-  v->init = 1;
-  v->reinit = dict_class_from_id (v->name) != DC_SCRATCH;
+  v->nv = width == 0 ? 1 : DIV_RND_UP (width, MAX_SHORT_STRING);
+  v->leave = dict_class_from_id (v->name) == DC_SCRATCH;
   v->index = d->var_cnt;
   mv_init (&v->miss, width);
   if (v->type == NUMERIC)
@@ -357,8 +358,7 @@ dict_clone_var (struct dictionary *d, const struct variable *ov,
      short_name[] is intentionally not copied, because there is
      no reason to give a new variable with potentially a new name
      the same short name. */
-  nv->init = 1;
-  nv->reinit = ov->reinit;
+  nv->leave = ov->leave;
   mv_copy (&nv->miss, &ov->miss);
   nv->print = ov->print;
   nv->write = ov->write;
@@ -583,7 +583,7 @@ dict_rename_var (struct dictionary *d, struct variable *v,
   assert (d != NULL);
   assert (v != NULL);
   assert (new_name != NULL);
-  assert (var_is_valid_name (new_name, false));
+  assert (var_is_plausible_name (new_name, false));
   assert (dict_contains_var (d, v));
   assert (!compare_var_names (v->name, new_name, NULL)
           || dict_lookup_var (d, new_name) == NULL);
@@ -621,7 +621,7 @@ dict_rename_vars (struct dictionary *d,
   for (i = 0; i < count; i++) 
     {
       assert (d->var[vars[i]->index] == vars[i]);
-      assert (var_is_valid_name (new_names[i], false));
+      assert (var_is_plausible_name (new_names[i], false));
       hsh_force_delete (d->name_tab, vars[i]);
       old_names[i] = xstrdup (vars[i]->name);
       strcpy (vars[i]->name, new_names[i]);
@@ -748,8 +748,8 @@ dict_set_filter (struct dictionary *d, struct variable *v)
 }
 
 /* Returns the case limit for dictionary D, or zero if the number
-   of cases is unlimited (see cmd_n()). */
-int
+   of cases is unlimited. */
+size_t
 dict_get_case_limit (const struct dictionary *d) 
 {
   assert (d != NULL);
@@ -757,13 +757,12 @@ dict_get_case_limit (const struct dictionary *d)
   return d->case_limit;
 }
 
-/* Sets CASE_LIMIT as the case limit for dictionary D.  Zero for
-   CASE_LIMIT indicates no limit. */
+/* Sets CASE_LIMIT as the case limit for dictionary D.  Use
+   0 for CASE_LIMIT to indicate no limit. */
 void
-dict_set_case_limit (struct dictionary *d, int case_limit) 
+dict_set_case_limit (struct dictionary *d, size_t case_limit) 
 {
   assert (d != NULL);
-  assert (case_limit >= 0);
 
   d->case_limit = case_limit;
 }
@@ -856,19 +855,44 @@ dict_get_compacted_idx_to_fv (const struct dictionary *d)
 }
 
 /* Returns true if a case for dictionary D would be smaller after
-   compaction, false otherwise.  Compacting a case eliminates
+   compacting, false otherwise.  Compacting a case eliminates
    "holes" between values and after the last value.  Holes are
    created by deleting variables (or by scratch variables).
 
    The return value may differ from whether compacting a case
-   from dictionary D would *change* the case: compaction could
+   from dictionary D would *change* the case: compacting could
    rearrange values even if it didn't reduce space
    requirements. */
 bool
-dict_needs_compaction (const struct dictionary *d) 
+dict_compacting_would_shrink (const struct dictionary *d) 
 {
   return dict_get_compacted_value_cnt (d) < dict_get_next_value_idx (d);
 }
+
+/* Returns true if a case for dictionary D would be smaller after
+   compacting, false otherwise.  Compacting a case eliminates
+   "holes" between values and after the last value.  Holes are
+   created by deleting variables (or by scratch variables).
+
+   The return value may differ from whether compacting a case
+   from dictionary D would *shrink* the case: compacting could
+   rearrange values without reducing space requirements. */
+bool
+dict_compacting_would_change (const struct dictionary *d) 
+{
+  size_t case_idx;
+  size_t i;
+
+  case_idx = 0;
+  for (i = 0; i < dict_get_var_cnt (d); i++) 
+    {
+      struct variable *v = dict_get_var (d, i);
+      if (v->fv != case_idx)
+        return true;
+      case_idx += v->nv;
+    }
+  return false;
+}
 \f
 /* How to copy a contiguous range of values between cases. */
 struct copy_map
@@ -1062,7 +1086,7 @@ dict_create_vector (struct dictionary *d,
 
   assert (d != NULL);
   assert (name != NULL);
-  assert (var_is_valid_name (name, false));
+  assert (var_is_plausible_name (name, false));
   assert (var != NULL);
   assert (cnt > 0);