pxd: initial work
[pspp] / src / data / value-labels.c
index c405961f29d69b29a24b767b0095c5029932425d..c1dee054ac8318d9c94dc1387b88e5af46aa9ad9 100644 (file)
 #include "libpspp/hmap.h"
 #include "libpspp/intern.h"
 #include "libpspp/message.h"
+#include "libpspp/pxd.h"
 #include "libpspp/str.h"
 
 #include "gl/xalloc.h"
 
+static void val_labs_uncache__ (struct val_labs *);
+static void val_lab_uncache__ (struct val_lab *);
+
 /* Creates and returns a new, empty set of value labels with the
    given WIDTH. */
 struct val_labs *
@@ -88,7 +92,11 @@ val_labs_set_width (struct val_labs *vls, int new_width)
       HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
         value_resize (&label->value, vls->width, new_width);
     }
-  vls->width = new_width;
+  if (vls->width != new_width)
+    {
+      vls->width = new_width;
+      val_labs_uncache__ (vls);
+    }
 }
 
 /* Destroys VLS. */
@@ -97,12 +105,21 @@ val_labs_destroy (struct val_labs *vls)
 {
   if (vls != NULL)
     {
+      val_labs_uncache__ (vls);
       val_labs_clear (vls);
       hmap_destroy (&vls->labels);
       free (vls);
     }
 }
 
+static void
+val_lab_clear (struct val_lab *lab, int width)
+{
+  val_lab_uncache__ (lab);
+  value_destroy (&lab->value, width);
+  intern_unref (lab->label);
+}
+
 /* Removes all the value labels from VLS. */
 void
 val_labs_clear (struct val_labs *vls)
@@ -111,10 +128,8 @@ val_labs_clear (struct val_labs *vls)
 
   HMAP_FOR_EACH_SAFE (label, next, struct val_lab, node, &vls->labels)
     {
+      val_lab_clear (label, vls->width);
       hmap_delete (&vls->labels, &label->node);
-      value_destroy (&label->value, vls->width);
-      intern_unref (label->label);
-      intern_unref (label->escaped_label);
       free (label);
     }
 }
@@ -162,6 +177,86 @@ set_label (struct val_lab *lab, const char *escaped_label)
     }
 }
 
+static void
+val_labs_uncache__ (struct val_labs *vls UNUSED)
+{
+}
+
+static void
+val_lab_uncache__ (struct val_lab *vl UNUSED)
+{
+}
+
+static struct pxd_object *
+val_lab_save (const struct val_lab *vl, int width, struct pxd *pxd)
+{
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_value (&b, &vl->value, width);
+  pxd_builder_put_interned_string (&b, vl->label);
+
+  return pxd_builder_commit (&b);
+}
+
+struct pxd_object *
+val_labs_save (const struct val_labs *vls, struct pxd *pxd)
+{
+  struct val_lab *label;
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_u32 (&b, vls->width);
+  HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
+    pxd_builder_put_link (&b, val_lab_save (label, vls->width, pxd));
+
+  return pxd_builder_commit (&b);
+}
+
+static struct val_lab *
+val_lab_load (struct pxd_object *object, const struct pxd *pxd, int width)
+{
+  struct pxd_parser p;
+  struct val_lab *vl;
+
+  pxd_parser_init (&p, object, pxd);
+
+  vl = xmalloc (sizeof *vl);
+  pxd_parser_get_value (&p, &vl->value, width);
+  vl->label = pxd_parser_get_interned_string (&p);
+
+  pxd_parser_destroy (&p);
+
+  return vl;
+}
+
+struct val_labs *
+val_labs_load (struct pxd_object *object, const struct pxd *pxd)
+{
+  struct val_labs *vls;
+  struct pxd_parser p;
+  unsigned int i;
+  int width;
+
+  pxd_parser_init (&p, object, pxd);
+  width = pxd_parser_get_u32 (&p);
+
+  vls = val_labs_create (width);
+  for (i = 0; i < pxd_object_get_n_links (object); i++)
+    {
+      struct pxd_object *lab_obj = pxd_object_get_link (object, i, pxd);
+      struct val_lab *lab = val_lab_load (lab_obj, pxd, width);
+      hmap_insert (&vls->labels, &lab->node,
+                   value_hash (&lab->value, width, 0));
+    }
+
+  pxd_parser_destroy (&p);
+
+  return vls;
+}
+\f
 static void
 do_add_val_lab (struct val_labs *vls, const union value *value,
                 const char *escaped_label)
@@ -201,6 +296,7 @@ val_labs_replace (struct val_labs *vls, const union value *value,
   struct val_lab *vl = val_labs_lookup (vls, value);
   if (vl != NULL)
     {
+      val_lab_uncache__ (vl);
       intern_unref (vl->label);
       intern_unref (vl->escaped_label);
       set_label (vl, label);
@@ -213,10 +309,8 @@ val_labs_replace (struct val_labs *vls, const union value *value,
 void
 val_labs_remove (struct val_labs *vls, struct val_lab *label)
 {
+  val_lab_clear (label, vls->width);
   hmap_delete (&vls->labels, &label->node);
-  value_destroy (&label->value, vls->width);
-  intern_unref (label->label);
-  intern_unref (label->escaped_label);
   free (label);
 }