pxd: initial work
[pspp] / src / data / attributes.c
index c4ae97c285928ed6e701cc6594fe0fefed5824c7..b04ebf0693ebe354be103a48c00b4f2ee0c37cc2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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
 #include <string.h>
 
 #include "libpspp/array.h"
+#include "libpspp/compiler.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/i18n.h"
+#include "libpspp/pxd.h"
 
 #include "gl/xalloc.h"
 
    set. */
 struct attribute
   {
+    struct attrset *set;        /* Containing set, if any. */
     struct hmap_node node;      /* Used by attrset. */
+
     char *name;                 /* Name. */
     char **values;              /* Each value. */
     size_t n_values;            /* Number of values. */
     size_t allocated_values;    /* Amount of allocated space for values. */
   };
 
+static void attrset_uncache__ (struct attrset *);
+
 /* Creates and returns a new attribute with the given NAME.  The
    attribute initially has no values.  (Attributes with no values
    cannot be saved to system files, so at least one value should
@@ -52,6 +58,7 @@ struct attribute *
 attribute_create (const char *name)
 {
   struct attribute *attr = xmalloc (sizeof *attr);
+  attr->set = NULL;
   attr->name = xstrdup (name);
   attr->values = NULL;
   attr->n_values = 0;
@@ -84,6 +91,8 @@ attribute_destroy (struct attribute *attr)
     {
       size_t i;
 
+      assert (attr->set == NULL);
+
       for (i = 0; i < attr->n_values; i++)
         free (attr->values[i]);
       free (attr->values);
@@ -122,6 +131,8 @@ attribute_get_n_values (const struct attribute *attrs)
 void
 attribute_add_value (struct attribute *attr, const char *value)
 {
+  attrset_uncache__ (attr->set);
+
   if (attr->n_values >= attr->allocated_values)
     attr->values = x2nrealloc (attr->values, &attr->allocated_values,
                                sizeof *attr->values);
@@ -138,6 +149,8 @@ attribute_add_value (struct attribute *attr, const char *value)
 void
 attribute_set_value (struct attribute *attr, size_t index, const char *value)
 {
+  attrset_uncache__ (attr->set);
+
   if (index < attr->n_values)
     {
       /* Replace existing value. */
@@ -162,6 +175,8 @@ attribute_set_value (struct attribute *attr, size_t index, const char *value)
 void
 attribute_del_value (struct attribute *attr, size_t index)
 {
+  attrset_uncache__ (attr->set);
+
   if (index < attr->n_values)
     {
       free (attr->values[index]);
@@ -170,6 +185,49 @@ attribute_del_value (struct attribute *attr, size_t index)
       attr->n_values--;
     }
 }
+
+struct pxd_object *
+attribute_save (const struct attribute *attr, struct pxd *pxd)
+{
+  struct pxd_builder b;
+  size_t i;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_string (&b, attr->name);
+  pxd_builder_put_size_t (&b, attr->n_values);
+  for (i = 0; i < attr->n_values; i++)
+    pxd_builder_put_string (&b, attr->values[i]);
+
+  return pxd_builder_commit (&b);
+}
+
+struct attribute *
+attribute_load (struct pxd_object *object, const struct pxd *pxd)
+{
+  struct attribute *attr;
+  struct pxd_parser p;
+  size_t n, i;
+  char *name;
+
+  pxd_parser_init (&p, object, pxd);
+
+  name = pxd_parser_get_string (&p);
+  attr = attribute_create (name);
+  free (name);
+
+  n = pxd_parser_get_size_t (&p);
+  for (i = 0; i < n; i++)
+    {
+      char *value = pxd_parser_get_string (&p);
+      attribute_add_value (attr, value);
+      free (value);
+    }
+
+  pxd_parser_destroy (&p);
+
+  return attr;
+}
 \f
 /* Initializes SET as a new, initially empty attibute set. */
 void
@@ -203,8 +261,13 @@ attrset_destroy (struct attrset *set)
     {
       struct attribute *attr, *next;
 
+      attrset_uncache__ (set);
+
       HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
-        attribute_destroy (attr);
+        {
+          attr->set = NULL;
+          attribute_destroy (attr);
+        }
       hmap_destroy (&set->map);
     }
 }
@@ -237,7 +300,13 @@ void
 attrset_add (struct attrset *set, struct attribute *attr)
 {
   const char *name = attribute_get_name (attr);
+
   assert (attrset_lookup (set, name) == NULL);
+  assert (attr->set == NULL);
+
+  attrset_uncache__ (set);
+
+  attr->set = set;
   hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
 }
 
@@ -249,7 +318,9 @@ attrset_delete (struct attrset *set, const char *name)
   struct attribute *attr = attrset_lookup (set, name);
   if (attr != NULL)
     {
+      attrset_uncache__ (set);
       hmap_delete (&set->map, &attr->node);
+      attr->set = NULL;
       attribute_destroy (attr);
     }
 }
@@ -258,8 +329,45 @@ attrset_delete (struct attrset *set, const char *name)
 void
 attrset_clear (struct attrset *set)
 {
-  attrset_destroy (set);
+  if (!hmap_is_empty (&set->map))
+    {
+      attrset_destroy (set);
+      attrset_init (set);
+    }
+}
+
+struct pxd_object *
+attrset_save (const struct attrset *set, struct pxd *pxd)
+{
+  struct attribute *attr;
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+
+  HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
+    pxd_builder_put_link (&b, attribute_save (attr, pxd));
+
+  return pxd_builder_commit (&b);
+}
+
+void
+attrset_load (struct attrset *set,
+              struct pxd_object *object, const struct pxd *pxd)
+{
+  struct pxd_parser p;
+  unsigned int i;
+
+  pxd_parser_init (&p, object, pxd);
+
   attrset_init (set);
+  for (i = 0; i < pxd_object_get_n_links (object); i++)
+    {
+      struct pxd_object *attr_obj = pxd_object_get_link (object, i, pxd);
+      struct attribute *attr = attribute_load (attr_obj, pxd);
+      attrset_add (set, attr);
+    }
+
+  pxd_parser_destroy (&p);
 }
 
 static struct attribute *iterator_data (struct attrset_iterator *iterator)
@@ -335,3 +443,10 @@ attrset_sorted (const struct attrset *set)
   else
     return NULL;
 }
+
+static void
+attrset_uncache__ (struct attrset *set UNUSED)
+{
+  /* XXX */
+}
+