1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "value-labels.h"
23 #include <data/data-out.h>
24 #include <data/value.h>
25 #include <data/variable.h>
26 #include <libpspp/array.h>
27 #include <libpspp/cast.h>
28 #include <libpspp/compiler.h>
29 #include <libpspp/hash-functions.h>
30 #include <libpspp/hmap.h>
31 #include <libpspp/intern.h>
32 #include <libpspp/message.h>
33 #include <libpspp/str.h>
37 /* Creates and returns a new, empty set of value labels with the
40 val_labs_create (int width)
42 struct val_labs *vls = xmalloc (sizeof *vls);
44 hmap_init (&vls->labels);
48 /* Creates and returns a new set of value labels identical to
49 VLS. Returns a null pointer if VLS is null. */
51 val_labs_clone (const struct val_labs *vls)
53 struct val_labs *copy;
54 struct val_lab *label;
59 copy = val_labs_create (vls->width);
60 HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
61 val_labs_add (copy, &label->value, label->label);
65 /* Determines whether VLS's width can be changed to NEW_WIDTH,
66 using the rules checked by value_is_resizable. */
68 val_labs_can_set_width (const struct val_labs *vls, int new_width)
70 struct val_lab *label;
72 HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
73 if (!value_is_resizable (&label->value, vls->width, new_width))
79 /* Changes the width of VLS to NEW_WIDTH. The original and new
80 width must be both numeric or both string. */
82 val_labs_set_width (struct val_labs *vls, int new_width)
84 assert (val_labs_can_set_width (vls, new_width));
85 if (value_needs_resize (vls->width, new_width))
87 struct val_lab *label;
88 HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
89 value_resize (&label->value, vls->width, new_width);
91 vls->width = new_width;
96 val_labs_destroy (struct val_labs *vls)
100 val_labs_clear (vls);
101 hmap_destroy (&vls->labels);
106 /* Removes all the value labels from VLS. */
108 val_labs_clear (struct val_labs *vls)
110 struct val_lab *label, *next;
112 HMAP_FOR_EACH_SAFE (label, next, struct val_lab, node, &vls->labels)
114 hmap_delete (&vls->labels, &label->node);
115 value_destroy (&label->value, vls->width);
116 intern_unref (label->label);
121 /* Returns the width of VLS. */
123 val_labs_get_width (const struct val_labs *vls)
128 /* Returns the number of value labels in VLS.
129 Returns 0 if VLS is null. */
131 val_labs_count (const struct val_labs *vls)
133 return vls == NULL ? 0 : hmap_count (&vls->labels);
137 do_add_val_lab (struct val_labs *vls, const union value *value,
140 struct val_lab *lab = xmalloc (sizeof *lab);
141 value_clone (&lab->value, value, vls->width);
142 lab->label = intern_new (label);
143 hmap_insert (&vls->labels, &lab->node, value_hash (value, vls->width, 0));
146 /* If VLS does not already contain a value label for VALUE, adds
147 LABEL for it and returns true. Otherwise, returns false. */
149 val_labs_add (struct val_labs *vls, const union value *value,
152 const struct val_lab *lab = val_labs_lookup (vls, value);
155 do_add_val_lab (vls, value, label);
162 /* Sets LABEL as the value label for VALUE in VLS, replacing any
163 existing label for VALUE. */
165 val_labs_replace (struct val_labs *vls, const union value *value,
168 struct val_lab *vl = val_labs_lookup (vls, value);
171 intern_unref (vl->label);
172 vl->label = intern_new (label);
175 do_add_val_lab (vls, value, label);
178 /* Removes LABEL from VLS. */
180 val_labs_remove (struct val_labs *vls, struct val_lab *label)
182 hmap_delete (&vls->labels, &label->node);
183 value_destroy (&label->value, vls->width);
184 intern_unref (label->label);
188 /* Searches VLS for a value label for VALUE. If successful,
189 returns the string used as the label; otherwise, returns a
190 null pointer. Returns a null pointer if VLS is null. */
192 val_labs_find (const struct val_labs *vls, const union value *value)
194 const struct val_lab *label = val_labs_lookup (vls, value);
195 return label ? label->label : NULL;
198 /* Searches VLS for a value label for VALUE. If successful,
199 returns the value label; otherwise, returns a null pointer.
200 Returns a null pointer if VLS is null. */
202 val_labs_lookup (const struct val_labs *vls, const union value *value)
206 struct val_lab *label;
207 HMAP_FOR_EACH_WITH_HASH (label, struct val_lab, node,
208 value_hash (value, vls->width, 0), &vls->labels)
209 if (value_equal (&label->value, value, vls->width))
215 /* Returns the first value label in VLS, in arbitrary order, or a
216 null pointer if VLS is empty or if VLS is a null pointer. If
217 the return value is non-null, then val_labs_next() may be used
218 to continue iterating. */
219 const struct val_lab *
220 val_labs_first (const struct val_labs *vls)
222 return vls ? HMAP_FIRST (struct val_lab, node, &vls->labels) : NULL;
225 /* Returns the next value label in an iteration begun by
226 val_labs_first(). If the return value is non-null, then
227 val_labs_next() may be used to continue iterating. */
228 const struct val_lab *
229 val_labs_next (const struct val_labs *vls, const struct val_lab *label)
231 return HMAP_NEXT (label, struct val_lab, node, &vls->labels);
235 compare_labels_by_value_3way (const void *a_, const void *b_, const void *vls_)
237 const struct val_lab *const *a = a_;
238 const struct val_lab *const *b = b_;
239 const struct val_labs *vls = vls_;
240 return value_compare_3way (&(*a)->value, &(*b)->value, vls->width);
243 /* Allocates and returns an array of pointers to value labels
244 that is sorted in increasing order by value. The array has
245 val_labs_count(VLS) elements. The caller is responsible for
246 freeing the array. */
247 const struct val_lab **
248 val_labs_sorted (const struct val_labs *vls)
252 const struct val_lab *label;
253 const struct val_lab **labels;
256 labels = xmalloc (val_labs_count (vls) * sizeof *labels);
258 HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
260 assert (i == val_labs_count (vls));
261 sort (labels, val_labs_count (vls), sizeof *labels,
262 compare_labels_by_value_3way, vls);