/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 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 "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 *
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. */
{
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)
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);
}
}
}
}
+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)
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);
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);
}
return (vls == NULL ? NULL
: val_labs_lookup__ (vls, value, value_hash (value, vls->width, 0)));
}
+
+/* Searches VLS for a value label whose label is exactly LABEL. If successful,
+ returns the corresponding value. Otherwise, returns a null pointer.
+
+ Returns a null pointer if VLS is null.
+
+ This function is O(n) in the number of labels in VLS. */
+const union value *
+val_labs_find_value (const struct val_labs *vls, const char *label_)
+{
+ const union value *value = NULL;
+
+ if (vls != NULL)
+ {
+ const struct val_lab *vl;
+ const char *label;
+
+ label = intern_new (label_);
+ HMAP_FOR_EACH (vl, struct val_lab, node, &vls->labels)
+ if (vl->label == label)
+ {
+ value = &vl->value;
+ break;
+ }
+ intern_unref (label);
+ }
+
+ return value;
+}
\f
/* Returns the first value label in VLS, in arbitrary order, or a
null pointer if VLS is empty or if VLS is a null pointer. If
{
const struct val_lab *label;
- if (val_labs_count (a) != val_labs_count (b) || a->width != b->width)
+ if (val_labs_count (a) != val_labs_count (b))
+ return false;
+
+ if (a == NULL || b == NULL)
+ return true;
+
+ if (a->width != b->width)
return false;
HMAP_FOR_EACH (label, struct val_lab, node, &a->labels)