1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2005, 2009, 2011 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 "data/missing-values.h"
24 #include "data/variable.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/str.h"
28 /* Types of user-missing values.
29 Invisible--use access functions defined below instead. */
32 MVT_NONE = 0, /* No user-missing values. */
33 MVT_1 = 1, /* One user-missing value. */
34 MVT_2 = 2, /* Two user-missing values. */
35 MVT_3 = 3, /* Three user-missing values. */
36 MVT_RANGE = 4, /* A range of user-missing values. */
37 MVT_RANGE_1 = 5 /* A range plus an individual value. */
40 /* Initializes MV as a set of missing values for a variable of
41 the given WIDTH. MV should be destroyed with mv_destroy when
42 it is no longer needed. */
44 mv_init (struct missing_values *mv, int width)
48 assert (width >= 0 && width <= MAX_STRING);
51 for (i = 0; i < 3; i++)
52 value_init (&mv->values[i], width);
55 /* Initializes MV as a set of missing values for a variable of
56 the given WIDTH. MV will be automatically destroyed along
57 with POOL; it must not be passed to mv_destroy for explicit
60 mv_init_pool (struct pool *pool, struct missing_values *mv, int width)
64 assert (width >= 0 && width <= MAX_STRING);
67 for (i = 0; i < 3; i++)
68 value_init_pool (pool, &mv->values[i], width);
71 /* Frees any storage allocated by mv_init for MV. */
73 mv_destroy (struct missing_values *mv)
79 for (i = 0; i < 3; i++)
80 value_destroy (&mv->values[i], mv->width);
84 /* Removes any missing values from MV. */
86 mv_clear (struct missing_values *mv)
91 /* Initializes MV as a copy of SRC. */
93 mv_copy (struct missing_values *mv, const struct missing_values *src)
97 mv_init (mv, src->width);
99 for (i = 0; i < 3; i++)
100 value_copy (&mv->values[i], &src->values[i], mv->width);
103 /* Returns true if VALUE, of the given WIDTH, may be added to a
104 missing value set also of the given WIDTH. This is normally
105 the case, but string missing values over MV_MAX_STRING bytes
106 long must consist solely of spaces after the first
107 MV_MAX_STRING bytes. */
109 mv_is_acceptable (const union value *value, int width)
113 for (i = MV_MAX_STRING; i < width; i++)
114 if (value_str (value, width)[i] != ' ')
119 /* Returns true if MV is an empty set of missing values. */
121 mv_is_empty (const struct missing_values *mv)
123 return mv->type == MVT_NONE;
126 /* Returns the width of the missing values that MV may
129 mv_get_width (const struct missing_values *mv)
134 /* Attempts to add individual value V to the set of missing
135 values MV. Returns true if successful, false if MV has no
136 more room for missing values or if V is not an acceptable
139 mv_add_value (struct missing_values *mv, const union value *v)
141 if (!mv_is_acceptable (v, mv->width))
150 value_copy (&mv->values[mv->type & 3], v, mv->width);
161 /* Attempts to add S to the set of string missing values MV. S
162 must contain exactly as many characters as MV's width.
163 Returns true if successful, false if MV has no more room for
164 missing values or if S is not an acceptable missing value. */
166 mv_add_str (struct missing_values *mv, const uint8_t s[])
171 assert (mv->width > 0);
172 value_init (&v, mv->width);
173 memcpy (value_str_rw (&v, mv->width), s, mv->width);
174 ok = mv_add_value (mv, &v);
175 value_destroy (&v, mv->width);
180 /* Attempts to add D to the set of numeric missing values MV.
181 Returns true if successful, false if MV has no more room for
184 mv_add_num (struct missing_values *mv, double d)
189 assert (mv->width == 0);
192 ok = mv_add_value (mv, &v);
193 value_destroy (&v, 0);
198 /* Attempts to add range [LOW, HIGH] to the set of numeric
199 missing values MV. Returns true if successful, false if MV
200 has no room for a range, or if LOW > HIGH. */
202 mv_add_range (struct missing_values *mv, double low, double high)
204 assert (mv->width == 0);
205 if (low <= high && (mv->type == MVT_NONE || mv->type == MVT_1))
207 mv->values[1].f = low;
208 mv->values[2].f = high;
216 /* Returns true if MV contains an individual value,
217 false if MV is empty (or contains only a range). */
219 mv_has_value (const struct missing_values *mv)
221 return mv_n_values (mv) > 0;
224 /* Removes one individual value from MV and stores it in V, which
225 must have been initialized as a value with the same width as MV.
226 MV must contain an individual value (as determined by
229 We remove the first value from MV, not the last, because the
230 common use for this function is in iterating through a set of
231 missing values. If we remove the last value then we'll output
232 the missing values in order opposite of that in which they
233 were added, so that a GET followed by a SAVE would reverse the
234 order of missing values in the system file, a weird effect. */
236 mv_pop_value (struct missing_values *mv, union value *v)
240 assert (mv_has_value (mv));
242 value_copy (v, &mv->values[0], mv->width);
244 mv->values[0] = mv->values[1];
245 mv->values[1] = mv->values[2];
250 /* Returns MV's discrete value with index IDX. The caller must
251 not modify or free this value, or access it after MV is
253 IDX must be less than the number of discrete values in MV, as
254 reported by mv_n_values. */
256 mv_get_value (const struct missing_values *mv, int idx)
258 assert (idx >= 0 && idx < mv_n_values (mv));
259 return &mv->values[idx];
262 /* Replaces MV's discrete value with index IDX by a copy of V,
263 which must have the same width as MV.
264 IDX must be less than the number of discrete values in MV, as
265 reported by mv_n_values. */
267 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
270 assert (idx < mv_n_values(mv));
272 if (!mv_is_acceptable (v, mv->width))
275 value_copy (&mv->values[idx], v, mv->width);
279 /* Returns the number of individual (not part of a range) missing
282 mv_n_values (const struct missing_values *mv)
288 /* Returns true if MV contains a numeric range,
289 false if MV is empty (or contains only individual values). */
291 mv_has_range (const struct missing_values *mv)
293 return mv->type == MVT_RANGE || mv->type == MVT_RANGE_1;
296 /* Removes the numeric range from MV and stores it in *LOW and
297 *HIGH. MV must contain a individual range (as determined by
300 mv_pop_range (struct missing_values *mv, double *low, double *high)
302 assert (mv_has_range (mv));
303 *low = mv->values[1].f;
304 *high = mv->values[2].f;
308 /* Returns the numeric range from MV into *LOW and
309 *HIGH. MV must contain a individual range (as determined by
312 mv_get_range (const struct missing_values *mv, double *low, double *high)
314 assert (mv_has_range (mv));
315 *low = mv->values[1].f;
316 *high = mv->values[2].f;
319 /* Returns true if values[IDX] is in use when the `type' member
320 is set to TYPE (in struct missing_values),
323 using_element (unsigned type, int idx)
325 assert (idx >= 0 && idx < 3);
345 /* Returns true if MV can be resized to the given WIDTH with
346 mv_resize(), false otherwise. Resizing is possible only when
347 each value in MV (if any) is resizable from MV's current width
348 to WIDTH, as determined by value_is_resizable. */
350 mv_is_resizable (const struct missing_values *mv, int width)
354 for (i = 0; i < 3; i++)
355 if (using_element (mv->type, i)
356 && !value_is_resizable (&mv->values[i], mv->width, width))
362 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
363 explained for mv_is_resizable. */
365 mv_resize (struct missing_values *mv, int width)
369 assert (mv_is_resizable (mv, width));
370 for (i = 0; i < 3; i++)
371 if (using_element (mv->type, i))
372 value_resize (&mv->values[i], mv->width, width);
375 value_destroy (&mv->values[i], mv->width);
376 value_init (&mv->values[i], width);
381 /* Returns true if D is a missing value in MV, false otherwise.
382 MV must be a set of numeric missing values. */
384 is_num_user_missing (const struct missing_values *mv, double d)
386 const union value *v = mv->values;
387 assert (mv->width == 0);
395 return v[0].f == d || v[1].f == d;
397 return v[0].f == d || v[1].f == d || v[2].f == d;
399 return v[1].f <= d && d <= v[2].f;
401 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
406 /* Returns true if S[] is a missing value in MV, false otherwise.
407 MV must be a set of string missing values.
408 S[] must contain exactly as many characters as MV's width. */
410 is_str_user_missing (const struct missing_values *mv, const uint8_t s[])
412 const union value *v = mv->values;
413 assert (mv->width > 0);
419 return !memcmp (value_str (&v[0], 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));
424 return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
425 || !memcmp (value_str (&v[1], mv->width), s, mv->width)
426 || !memcmp (value_str (&v[2], mv->width), s, mv->width));
434 /* Returns true if V is a missing value in the given CLASS in MV,
437 mv_is_value_missing (const struct missing_values *mv, const union value *v,
440 return (mv->width == 0
441 ? mv_is_num_missing (mv, v->f, class)
442 : mv_is_str_missing (mv, value_str (v, mv->width), class));
445 /* Returns true if D is a missing value in the given CLASS in MV,
447 MV must be a set of numeric missing values. */
449 mv_is_num_missing (const struct missing_values *mv, double d,
452 assert (mv->width == 0);
453 return ((class & MV_SYSTEM && d == SYSMIS)
454 || (class & MV_USER && is_num_user_missing (mv, d)));
457 /* Returns true if S[] is a missing value in the given CLASS in
459 MV must be a set of string missing values.
460 S[] must contain exactly as many characters as MV's width. */
462 mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
465 assert (mv->width > 0);
466 return class & MV_USER && is_str_user_missing (mv, s);