1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2005, 2009, 2011, 2013 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/cast.h"
27 #include "libpspp/str.h"
29 /* Types of user-missing values.
30 Invisible--use access functions defined below instead. */
33 MVT_NONE = 0, /* No user-missing values. */
34 MVT_1 = 1, /* One user-missing value. */
35 MVT_2 = 2, /* Two user-missing values. */
36 MVT_3 = 3, /* Three user-missing values. */
37 MVT_RANGE = 4, /* A range of user-missing values. */
38 MVT_RANGE_1 = 5 /* A range plus an individual value. */
41 /* Initializes MV as a set of missing values for a variable of
42 the given WIDTH. MV should be destroyed with mv_destroy when
43 it is no longer needed. */
45 mv_init (struct missing_values *mv, int width)
49 assert (width >= 0 && width <= MAX_STRING);
52 for (i = 0; i < 3; i++)
53 value_init (&mv->values[i], width);
56 /* Initializes MV as a set of missing values for a variable of
57 the given WIDTH. MV will be automatically destroyed along
58 with POOL; it must not be passed to mv_destroy for explicit
61 mv_init_pool (struct pool *pool, struct missing_values *mv, int width)
65 assert (width >= 0 && width <= MAX_STRING);
68 for (i = 0; i < 3; i++)
69 value_init_pool (pool, &mv->values[i], width);
72 /* Frees any storage allocated by mv_init for MV. */
74 mv_destroy (struct missing_values *mv)
80 for (i = 0; i < 3; i++)
81 value_destroy (&mv->values[i], mv->width);
85 /* Removes any missing values from MV. */
87 mv_clear (struct missing_values *mv)
92 /* Initializes MV as a copy of SRC. */
94 mv_copy (struct missing_values *mv, const struct missing_values *src)
98 mv_init (mv, src->width);
100 for (i = 0; i < 3; i++)
101 value_copy (&mv->values[i], &src->values[i], mv->width);
104 /* Returns true if VALUE, of the given WIDTH, may be added to a
105 missing value set also of the given WIDTH. This is normally
106 the case, but string missing values over MV_MAX_STRING bytes
107 long must consist solely of spaces after the first
108 MV_MAX_STRING bytes. */
110 mv_is_acceptable (const union value *value, int width)
114 for (i = MV_MAX_STRING; i < width; i++)
115 if (value_str (value, width)[i] != ' ')
120 /* Returns true if MV is an empty set of missing values. */
122 mv_is_empty (const struct missing_values *mv)
124 return mv->type == MVT_NONE;
127 /* Returns the width of the missing values that MV may
130 mv_get_width (const struct missing_values *mv)
135 /* Attempts to add individual value V to the set of missing
136 values MV. Returns true if successful, false if MV has no
137 more room for missing values or if V is not an acceptable
140 mv_add_value (struct missing_values *mv, const union value *v)
142 if (!mv_is_acceptable (v, mv->width))
151 value_copy (&mv->values[mv->type & 3], v, mv->width);
162 /* Attempts to add S, which is LEN bytes long, to the set of string missing
163 values MV. 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[], size_t len)
171 assert (mv->width > 0);
172 while (len > mv->width)
176 value_init (&v, mv->width);
177 buf_copy_rpad (CHAR_CAST (char *, value_str_rw (&v, mv->width)), mv->width,
178 CHAR_CAST (char *, s), len, ' ');
179 ok = mv_add_value (mv, &v);
180 value_destroy (&v, mv->width);
185 /* Attempts to add D to the set of numeric missing values MV.
186 Returns true if successful, false if MV has no more room for
189 mv_add_num (struct missing_values *mv, double d)
194 assert (mv->width == 0);
197 ok = mv_add_value (mv, &v);
198 value_destroy (&v, 0);
203 /* Attempts to add range [LOW, HIGH] to the set of numeric
204 missing values MV. Returns true if successful, false if MV
205 has no room for a range, or if LOW > HIGH. */
207 mv_add_range (struct missing_values *mv, double low, double high)
209 assert (mv->width == 0);
210 if (low <= high && (mv->type == MVT_NONE || mv->type == MVT_1))
212 mv->values[1].f = low;
213 mv->values[2].f = high;
221 /* Returns true if MV contains an individual value,
222 false if MV is empty (or contains only a range). */
224 mv_has_value (const struct missing_values *mv)
226 return mv_n_values (mv) > 0;
229 /* Removes one individual value from MV and stores it in V, which
230 must have been initialized as a value with the same width as MV.
231 MV must contain an individual value (as determined by
234 We remove the first value from MV, not the last, because the
235 common use for this function is in iterating through a set of
236 missing values. If we remove the last value then we'll output
237 the missing values in order opposite of that in which they
238 were added, so that a GET followed by a SAVE would reverse the
239 order of missing values in the system file, a weird effect. */
241 mv_pop_value (struct missing_values *mv, union value *v)
245 assert (mv_has_value (mv));
247 value_copy (v, &mv->values[0], mv->width);
249 mv->values[0] = mv->values[1];
250 mv->values[1] = mv->values[2];
255 /* Returns MV's discrete value with index IDX. The caller must
256 not modify or free this value, or access it after MV is
258 IDX must be less than the number of discrete values in MV, as
259 reported by mv_n_values. */
261 mv_get_value (const struct missing_values *mv, int idx)
263 assert (idx >= 0 && idx < mv_n_values (mv));
264 return &mv->values[idx];
267 /* Replaces MV's discrete value with index IDX by a copy of V,
268 which must have the same width as MV.
269 IDX must be less than the number of discrete values in MV, as
270 reported by mv_n_values. */
272 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
275 assert (idx < mv_n_values(mv));
277 if (!mv_is_acceptable (v, mv->width))
280 value_copy (&mv->values[idx], v, mv->width);
284 /* Returns the number of individual (not part of a range) missing
287 mv_n_values (const struct missing_values *mv)
293 /* Returns true if MV contains a numeric range,
294 false if MV is empty (or contains only individual values). */
296 mv_has_range (const struct missing_values *mv)
298 return mv->type == MVT_RANGE || mv->type == MVT_RANGE_1;
301 /* Removes the numeric range from MV and stores it in *LOW and
302 *HIGH. MV must contain a individual range (as determined by
305 mv_pop_range (struct missing_values *mv, double *low, double *high)
307 assert (mv_has_range (mv));
308 *low = mv->values[1].f;
309 *high = mv->values[2].f;
313 /* Returns the numeric range from MV into *LOW and
314 *HIGH. MV must contain a individual range (as determined by
317 mv_get_range (const struct missing_values *mv, double *low, double *high)
319 assert (mv_has_range (mv));
320 *low = mv->values[1].f;
321 *high = mv->values[2].f;
324 /* Returns true if values[IDX] is in use when the `type' member
325 is set to TYPE (in struct missing_values),
328 using_element (unsigned type, int idx)
330 assert (idx >= 0 && idx < 3);
350 /* Returns true if MV can be resized to the given WIDTH with
351 mv_resize(), false otherwise. Resizing is possible only when
352 each value in MV (if any) is resizable from MV's current width
353 to WIDTH, as determined by value_is_resizable. */
355 mv_is_resizable (const struct missing_values *mv, int width)
359 for (i = 0; i < 3; i++)
360 if (using_element (mv->type, i)
361 && !value_is_resizable (&mv->values[i], mv->width, width))
367 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
368 explained for mv_is_resizable. */
370 mv_resize (struct missing_values *mv, int width)
374 assert (mv_is_resizable (mv, width));
375 for (i = 0; i < 3; i++)
376 if (using_element (mv->type, i))
377 value_resize (&mv->values[i], mv->width, width);
380 value_destroy (&mv->values[i], mv->width);
381 value_init (&mv->values[i], width);
386 /* Returns true if D is a missing value in MV, false otherwise.
387 MV must be a set of numeric missing values. */
389 is_num_user_missing (const struct missing_values *mv, double d)
391 const union value *v = mv->values;
392 assert (mv->width == 0);
400 return v[0].f == d || v[1].f == d;
402 return v[0].f == d || v[1].f == d || v[2].f == d;
404 return v[1].f <= d && d <= v[2].f;
406 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
411 /* Returns true if S[] is a missing value in MV, false otherwise.
412 MV must be a set of string missing values.
413 S[] must contain exactly as many characters as MV's width. */
415 is_str_user_missing (const struct missing_values *mv, const uint8_t s[])
417 const union value *v = mv->values;
418 assert (mv->width > 0);
424 return !memcmp (value_str (&v[0], mv->width), s, mv->width);
426 return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
427 || !memcmp (value_str (&v[1], mv->width), s, mv->width));
429 return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
430 || !memcmp (value_str (&v[1], mv->width), s, mv->width)
431 || !memcmp (value_str (&v[2], mv->width), s, mv->width));
439 /* Returns true if V is a missing value in the given CLASS in MV,
442 mv_is_value_missing (const struct missing_values *mv, const union value *v,
445 return (mv->width == 0
446 ? mv_is_num_missing (mv, v->f, class)
447 : mv_is_str_missing (mv, value_str (v, mv->width), class));
450 /* Returns true if D is a missing value in the given CLASS in MV,
452 MV must be a set of numeric missing values. */
454 mv_is_num_missing (const struct missing_values *mv, double d,
457 assert (mv->width == 0);
458 return ((class & MV_SYSTEM && d == SYSMIS)
459 || (class & MV_USER && is_num_user_missing (mv, d)));
462 /* Returns true if S[] is a missing value in the given CLASS in
464 MV must be a set of string missing values.
465 S[] must contain exactly as many characters as MV's width. */
467 mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
470 assert (mv->width > 0);
471 return class & MV_USER && is_str_user_missing (mv, s);