1 /* PSPP - computes sample statistics.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include "missing-values.h"
24 #include <libpspp/assertion.h>
25 #include <libpspp/str.h>
28 /* Initializes MV as a set of missing values for a variable of
29 the given WIDTH. Although only numeric variables and short
30 string variables may have missing values, WIDTH may be any
31 valid variable width. */
33 mv_init (struct missing_values *mv, int width)
35 assert (width >= 0 && width <= MAX_STRING);
41 mv_set_type(struct missing_values *mv, enum mv_type type)
47 /* Copies SRC to MV. */
49 mv_copy (struct missing_values *mv, const struct missing_values *src)
56 /* Returns true if MV is an empty set of missing values. */
58 mv_is_empty (const struct missing_values *mv)
60 return mv->type == MV_NONE;
63 /* Returns the width of the missing values that MV may
66 mv_get_width (const struct missing_values *mv)
71 /* Attempts to add individual value V to the set of missing
72 values MV. Returns true if successful, false if MV has no
73 more room for missing values. (Long string variables never
74 accept missing values.) */
76 mv_add_value (struct missing_values *mv, const union value *v)
78 if (mv->width > MAX_SHORT_STRING)
86 mv->values[mv->type & 3] = *v;
97 /* Attempts to add S to the set of string missing values MV. S
98 must contain exactly as many characters as MV's width.
99 Returns true if successful, false if MV has no more room for
100 missing values. (Long string variables never accept missing
103 mv_add_str (struct missing_values *mv, const char s[])
105 assert (mv->width > 0);
106 return mv_add_value (mv, (union value *) s);
109 /* Attempts to add D to the set of numeric missing values MV.
110 Returns true if successful, false if MV has no more room for
113 mv_add_num (struct missing_values *mv, double d)
115 assert (mv->width == 0);
116 return mv_add_value (mv, (union value *) &d);
119 /* Attempts to add range [LOW, HIGH] to the set of numeric
120 missing values MV. Returns true if successful, false if MV
121 has no room for a range, or if LOW > HIGH. */
123 mv_add_num_range (struct missing_values *mv, double low, double high)
125 assert (mv->width == 0);
132 mv->values[1].f = low;
133 mv->values[2].f = high;
146 /* Returns true if MV contains an individual value,
147 false if MV is empty (or contains only a range). */
149 mv_has_value (const struct missing_values *mv)
166 /* Removes one individual value from MV and stores it in *V.
167 MV must contain an individual value (as determined by
170 mv_pop_value (struct missing_values *mv, union value *v)
172 assert (mv_has_value (mv));
174 *v = mv->values[mv->type & 3];
177 /* Stores a value in *V.
178 MV must contain an individual value (as determined by
180 IDX is the zero based index of the value to get
183 mv_peek_value (const struct missing_values *mv, union value *v, int idx)
188 assert (mv_has_value (mv));
189 *v = mv->values[idx];
193 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
196 assert (idx < mv_n_values(mv));
198 mv->values[idx] = *v;
204 mv_n_values (const struct missing_values *mv)
206 assert(mv_has_value(mv));
211 /* Returns true if MV contains a numeric range,
212 false if MV is empty (or contains only individual values). */
214 mv_has_range (const struct missing_values *mv)
231 /* Removes the numeric range from MV and stores it in *LOW and
232 *HIGH. MV must contain a individual range (as determined by
235 mv_pop_range (struct missing_values *mv, double *low, double *high)
237 assert (mv_has_range (mv));
238 *low = mv->values[1].f;
239 *high = mv->values[2].f;
244 /* Returns the numeric range from MV into *LOW and
245 *HIGH. MV must contain a individual range (as determined by
248 mv_peek_range (const struct missing_values *mv, double *low, double *high)
250 assert (mv_has_range (mv));
251 *low = mv->values[1].f;
252 *high = mv->values[2].f;
256 /* Returns true if values[IDX] is in use when the `type' member
257 is set to TYPE (in struct missing_values),
260 using_element (unsigned type, int idx)
262 assert (idx >= 0 && idx < 3);
282 /* Returns true if S contains only spaces between indexes
283 NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
286 can_resize_string (const char *s, int old_width, int new_width)
290 assert (new_width < old_width);
291 for (i = new_width; i < old_width; i++)
297 /* Returns true if MV can be resized to the given WIDTH with
298 mv_resize(), false otherwise. Resizing to the same width is
299 always possible. Resizing to a long string WIDTH is only
300 possible if MV is an empty set of missing values; otherwise,
301 resizing to a larger WIDTH is always possible. Resizing to a
302 shorter width is possible only when each missing value
303 contains only spaces in the characters that will be
306 mv_is_resizable (struct missing_values *mv, int width)
308 assert ((width == 0) == (mv->width == 0));
309 if (width > MAX_SHORT_STRING && mv->type != MV_NONE)
311 else if (width >= mv->width)
317 for (i = 0; i < 3; i++)
318 if (using_element (mv->type, i)
319 && !can_resize_string (mv->values[i].s, mv->width, width))
325 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
326 explained for mv_is_resizable(). */
328 mv_resize (struct missing_values *mv, int width)
330 assert (mv_is_resizable (mv, width));
331 if (width > mv->width)
335 for (i = 0; i < 3; i++)
336 memset (mv->values[i].s + mv->width, ' ', width - mv->width);
341 /* Returns true if V is system missing or a missing value in MV,
344 mv_is_value_missing (const struct missing_values *mv, const union value *v)
346 return (mv->width == 0
347 ? mv_is_num_missing (mv, v->f)
348 : mv_is_str_missing (mv, v->s));
351 /* Returns true if D is system missing or a missing value in MV,
353 MV must be a set of numeric missing values. */
355 mv_is_num_missing (const struct missing_values *mv, double d)
357 assert (mv->width == 0);
358 return d == SYSMIS || mv_is_num_user_missing (mv, d);
361 /* Returns true if S[] is a missing value in MV, false otherwise.
362 MV must be a set of string missing values.
363 S[] must contain exactly as many characters as MV's width. */
365 mv_is_str_missing (const struct missing_values *mv, const char s[])
367 return mv_is_str_user_missing (mv, s);
370 /* Returns true if V is a missing value in MV, false otherwise. */
372 mv_is_value_user_missing (const struct missing_values *mv,
373 const union value *v)
375 return (mv->width == 0
376 ? mv_is_num_user_missing (mv, v->f)
377 : mv_is_str_user_missing (mv, v->s));
380 /* Returns true if D is a missing value in MV, false otherwise.
381 MV must be a set of numeric missing values. */
383 mv_is_num_user_missing (const struct missing_values *mv, double d)
385 const union value *v = mv->values;
386 assert (mv->width == 0);
394 return v[0].f == d || v[1].f == d;
396 return v[0].f == d || v[1].f == d || v[2].f == d;
398 return v[1].f <= d && d <= v[2].f;
400 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
405 /* Returns true if S[] is a missing value in MV, false otherwise.
406 MV must be a set of string missing values.
407 S[] must contain exactly as many characters as MV's width. */
409 mv_is_str_user_missing (const struct missing_values *mv,
412 const union value *v = mv->values;
413 assert (mv->width > 0);
419 return !memcmp (v[0].s, s, mv->width);
421 return (!memcmp (v[0].s, s, mv->width)
422 || !memcmp (v[1].s, s, mv->width));
424 return (!memcmp (v[0].s, s, mv->width)
425 || !memcmp (v[1].s, s, mv->width)
426 || !memcmp (v[2].s, s, mv->width));
434 /* Returns true if MV is a set of numeric missing values and V is
435 the system missing value. */
437 mv_is_value_system_missing (const struct missing_values *mv,
438 const union value *v)
440 return mv->width == 0 ? v->f == SYSMIS : false;