1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2005, 2009 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/>. */
18 #include <data/missing-values.h>
21 #include <data/variable.h>
22 #include <libpspp/assertion.h>
23 #include <libpspp/str.h>
25 /* Types of user-missing values.
26 Invisible--use access functions defined below instead. */
29 MVT_NONE = 0, /* No user-missing values. */
30 MVT_1 = 1, /* One user-missing value. */
31 MVT_2 = 2, /* Two user-missing values. */
32 MVT_3 = 3, /* Three user-missing values. */
33 MVT_RANGE = 4, /* A range of user-missing values. */
34 MVT_RANGE_1 = 5 /* A range plus an individual value. */
37 /* Initializes MV as a set of missing values for a variable of
38 the given WIDTH. MV should be destroyed with mv_destroy when
39 it is no longer needed. */
41 mv_init (struct missing_values *mv, int width)
45 assert (width >= 0 && width <= MAX_STRING);
48 for (i = 0; i < 3; i++)
49 value_init (&mv->values[i], width);
52 /* Initializes MV as a set of missing values for a variable of
53 the given WIDTH. MV will be automatically destroyed along
54 with POOL; it must not be passed to mv_destroy for explicit
57 mv_init_pool (struct pool *pool, struct missing_values *mv, int width)
61 assert (width >= 0 && width <= MAX_STRING);
64 for (i = 0; i < 3; i++)
65 value_init_pool (pool, &mv->values[i], width);
68 /* Frees any storage allocated by mv_init for MV. */
70 mv_destroy (struct missing_values *mv)
76 for (i = 0; i < 3; i++)
77 value_destroy (&mv->values[i], mv->width);
81 /* Removes any missing values from MV. */
83 mv_clear (struct missing_values *mv)
88 /* Initializes MV as a copy of SRC. */
90 mv_copy (struct missing_values *mv, const struct missing_values *src)
94 mv_init (mv, src->width);
96 for (i = 0; i < 3; i++)
97 value_copy (&mv->values[i], &src->values[i], mv->width);
100 /* Returns true if VALUE, of the given WIDTH, may be added to a
101 missing value set also of the given WIDTH. This is normally
102 the case, but string missing values over MV_MAX_STRING bytes
103 long must consist solely of spaces after the first
104 MV_MAX_STRING bytes. */
106 mv_is_acceptable (const union value *value, int width)
110 for (i = MV_MAX_STRING; i < width; i++)
111 if (value_str (value, width)[i] != ' ')
116 /* Returns true if MV is an empty set of missing values. */
118 mv_is_empty (const struct missing_values *mv)
120 return mv->type == MVT_NONE;
123 /* Returns the width of the missing values that MV may
126 mv_get_width (const struct missing_values *mv)
131 /* Attempts to add individual value V to the set of missing
132 values MV. Returns true if successful, false if MV has no
133 more room for missing values or if V is not an acceptable
136 mv_add_value (struct missing_values *mv, const union value *v)
138 if (!mv_is_acceptable (v, mv->width))
147 value_copy (&mv->values[mv->type & 3], v, mv->width);
158 /* Attempts to add S to the set of string missing values MV. S
159 must contain exactly as many characters as MV's width.
160 Returns true if successful, false if MV has no more room for
161 missing values or if S is not an acceptable missing value. */
163 mv_add_str (struct missing_values *mv, const uint8_t s[])
168 assert (mv->width > 0);
169 value_init (&v, mv->width);
170 memcpy (value_str_rw (&v, mv->width), s, mv->width);
171 ok = mv_add_value (mv, &v);
172 value_destroy (&v, mv->width);
177 /* Attempts to add D to the set of numeric missing values MV.
178 Returns true if successful, false if MV has no more room for
181 mv_add_num (struct missing_values *mv, double d)
186 assert (mv->width == 0);
189 ok = mv_add_value (mv, &v);
190 value_destroy (&v, 0);
195 /* Attempts to add range [LOW, HIGH] to the set of numeric
196 missing values MV. Returns true if successful, false if MV
197 has no room for a range, or if LOW > HIGH. */
199 mv_add_range (struct missing_values *mv, double low, double high)
201 assert (mv->width == 0);
202 if (low <= high && (mv->type == MVT_NONE || mv->type == MVT_1))
204 mv->values[1].f = low;
205 mv->values[2].f = high;
213 /* Returns true if MV contains an individual value,
214 false if MV is empty (or contains only a range). */
216 mv_has_value (const struct missing_values *mv)
218 return mv_n_values (mv) > 0;
221 /* Removes one individual value from MV and stores it in V, which
222 must have been initialized as a value with the same width as MV.
223 MV must contain an individual value (as determined by
226 We remove the first value from MV, not the last, because the
227 common use for this function is in iterating through a set of
228 missing values. If we remove the last value then we'll output
229 the missing values in order opposite of that in which they
230 were added, so that a GET followed by a SAVE would reverse the
231 order of missing values in the system file, a weird effect. */
233 mv_pop_value (struct missing_values *mv, union value *v)
237 assert (mv_has_value (mv));
239 value_copy (v, &mv->values[0], mv->width);
241 mv->values[0] = mv->values[1];
242 mv->values[1] = mv->values[2];
247 /* Returns MV's discrete value with index IDX. The caller must
248 not modify or free this value, or access it after MV is
250 IDX must be less than the number of discrete values in MV, as
251 reported by mv_n_values. */
253 mv_get_value (const struct missing_values *mv, int idx)
255 assert (idx >= 0 && idx < mv_n_values (mv));
256 return &mv->values[idx];
259 /* Replaces MV's discrete value with index IDX by a copy of V,
260 which must have the same width as MV.
261 IDX must be less than the number of discrete values in MV, as
262 reported by mv_n_values. */
264 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
267 assert (idx < mv_n_values(mv));
269 if (!mv_is_acceptable (v, mv->width))
272 value_copy (&mv->values[idx], v, mv->width);
276 /* Returns the number of individual (not part of a range) missing
279 mv_n_values (const struct missing_values *mv)
285 /* Returns true if MV contains a numeric range,
286 false if MV is empty (or contains only individual values). */
288 mv_has_range (const struct missing_values *mv)
290 return mv->type == MVT_RANGE || mv->type == MVT_RANGE_1;
293 /* Removes the numeric range from MV and stores it in *LOW and
294 *HIGH. MV must contain a individual range (as determined by
297 mv_pop_range (struct missing_values *mv, double *low, double *high)
299 assert (mv_has_range (mv));
300 *low = mv->values[1].f;
301 *high = mv->values[2].f;
305 /* Returns the numeric range from MV into *LOW and
306 *HIGH. MV must contain a individual range (as determined by
309 mv_get_range (const struct missing_values *mv, double *low, double *high)
311 assert (mv_has_range (mv));
312 *low = mv->values[1].f;
313 *high = mv->values[2].f;
316 /* Returns true if values[IDX] is in use when the `type' member
317 is set to TYPE (in struct missing_values),
320 using_element (unsigned type, int idx)
322 assert (idx >= 0 && idx < 3);
342 /* Returns true if MV can be resized to the given WIDTH with
343 mv_resize(), false otherwise. Resizing is possible only when
344 each value in MV (if any) is resizable from MV's current width
345 to WIDTH, as determined by value_is_resizable. */
347 mv_is_resizable (const struct missing_values *mv, int width)
351 for (i = 0; i < 3; i++)
352 if (using_element (mv->type, i)
353 && !value_is_resizable (&mv->values[i], mv->width, width))
359 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
360 explained for mv_is_resizable. */
362 mv_resize (struct missing_values *mv, int width)
366 assert (mv_is_resizable (mv, width));
367 for (i = 0; i < 3; i++)
368 if (using_element (mv->type, i))
369 value_resize (&mv->values[i], mv->width, width);
372 value_destroy (&mv->values[i], mv->width);
373 value_init (&mv->values[i], width);
378 /* Returns true if D is a missing value in MV, false otherwise.
379 MV must be a set of numeric missing values. */
381 is_num_user_missing (const struct missing_values *mv, double d)
383 const union value *v = mv->values;
384 assert (mv->width == 0);
392 return v[0].f == d || v[1].f == d;
394 return v[0].f == d || v[1].f == d || v[2].f == d;
396 return v[1].f <= d && d <= v[2].f;
398 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
403 /* Returns true if S[] is a missing value in MV, false otherwise.
404 MV must be a set of string missing values.
405 S[] must contain exactly as many characters as MV's width. */
407 is_str_user_missing (const struct missing_values *mv, const uint8_t s[])
409 const union value *v = mv->values;
410 assert (mv->width > 0);
416 return !memcmp (value_str (&v[0], mv->width), s, mv->width);
418 return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
419 || !memcmp (value_str (&v[1], mv->width), s, mv->width));
421 return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
422 || !memcmp (value_str (&v[1], mv->width), s, mv->width)
423 || !memcmp (value_str (&v[2], mv->width), s, mv->width));
431 /* Returns true if V is a missing value in the given CLASS in MV,
434 mv_is_value_missing (const struct missing_values *mv, const union value *v,
437 return (mv->width == 0
438 ? mv_is_num_missing (mv, v->f, class)
439 : mv_is_str_missing (mv, value_str (v, mv->width), class));
442 /* Returns true if D is a missing value in the given CLASS in MV,
444 MV must be a set of numeric missing values. */
446 mv_is_num_missing (const struct missing_values *mv, double d,
449 assert (mv->width == 0);
450 return ((class & MV_SYSTEM && d == SYSMIS)
451 || (class & MV_USER && is_num_user_missing (mv, d)));
454 /* Returns true if S[] is a missing value in the given CLASS in
456 MV must be a set of string missing values.
457 S[] must contain exactly as many characters as MV's width. */
459 mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
462 assert (mv->width > 0);
463 return class & MV_USER && is_str_user_missing (mv, s);