9aba57e0e05fb6249764d2c5f778fb6337275a82
[pspp] / src / data / missing-values.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2005, 2009, 2011, 2013 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "data/missing-values.h"
20
21 #include <assert.h>
22 #include <stdlib.h>
23
24 #include "data/variable.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/cast.h"
27 #include "libpspp/str.h"
28
29 /* Types of user-missing values.
30    Invisible--use access functions defined below instead. */
31 enum mv_type
32   {
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. */
39   };
40
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. */
44 void
45 mv_init (struct missing_values *mv, int width)
46 {
47   int i;
48
49   assert (width >= 0 && width <= MAX_STRING);
50   mv->type = MVT_NONE;
51   mv->width = width;
52   for (i = 0; i < 3; i++)
53     value_init (&mv->values[i], width);
54 }
55
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
59    destruction. */
60 void
61 mv_init_pool (struct pool *pool, struct missing_values *mv, int width)
62 {
63   int i;
64
65   assert (width >= 0 && width <= MAX_STRING);
66   mv->type = MVT_NONE;
67   mv->width = width;
68   for (i = 0; i < 3; i++)
69     value_init_pool (pool, &mv->values[i], width);
70 }
71
72 /* Frees any storage allocated by mv_init for MV. */
73 void
74 mv_destroy (struct missing_values *mv)
75 {
76   if (mv != NULL)
77     {
78       int i;
79
80       for (i = 0; i < 3; i++)
81         value_destroy (&mv->values[i], mv->width);
82     }
83 }
84
85 /* Removes any missing values from MV. */
86 void
87 mv_clear (struct missing_values *mv)
88 {
89   mv->type = MVT_NONE;
90 }
91
92 /* Initializes MV as a copy of SRC. */
93 void
94 mv_copy (struct missing_values *mv, const struct missing_values *src)
95 {
96   int i;
97
98   mv_init (mv, src->width);
99   mv->type = src->type;
100   for (i = 0; i < 3; i++)
101     value_copy (&mv->values[i], &src->values[i], mv->width);
102 }
103
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.  */
109 bool
110 mv_is_acceptable (const union value *value, int width)
111 {
112   int i;
113
114   for (i = MV_MAX_STRING; i < width; i++)
115     if (value_str (value, width)[i] != ' ')
116       return false;
117   return true;
118 }
119
120 /* Returns true if MV is an empty set of missing values. */
121 bool
122 mv_is_empty (const struct missing_values *mv)
123 {
124   return mv->type == MVT_NONE;
125 }
126
127 /* Returns the width of the missing values that MV may
128    contain. */
129 int
130 mv_get_width (const struct missing_values *mv)
131 {
132   return mv->width;
133 }
134
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
138    missing value. */
139 bool
140 mv_add_value (struct missing_values *mv, const union value *v)
141 {
142   if (!mv_is_acceptable (v, mv->width))
143     return false;
144
145   switch (mv->type)
146     {
147     case MVT_NONE:
148     case MVT_1:
149     case MVT_2:
150     case MVT_RANGE:
151       value_copy (&mv->values[mv->type & 3], v, mv->width);
152       mv->type++;
153       return true;
154
155     case MVT_3:
156     case MVT_RANGE_1:
157       return false;
158     }
159   NOT_REACHED ();
160 }
161
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. */
165 bool
166 mv_add_str (struct missing_values *mv, const uint8_t s[], size_t len)
167 {
168   union value v;
169   bool ok;
170
171   assert (mv->width > 0);
172   while (len > mv->width)
173     if (s[--len] != ' ')
174       return false;
175
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);
181
182   return ok;
183 }
184
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
187    missing values.  */
188 bool
189 mv_add_num (struct missing_values *mv, double d)
190 {
191   union value v;
192   bool ok;
193
194   assert (mv->width == 0);
195   value_init (&v, 0);
196   v.f = d;
197   ok = mv_add_value (mv, &v);
198   value_destroy (&v, 0);
199
200   return ok;
201 }
202
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. */
206 bool
207 mv_add_range (struct missing_values *mv, double low, double high)
208 {
209   assert (mv->width == 0);
210   if (low <= high && (mv->type == MVT_NONE || mv->type == MVT_1))
211     {
212       mv->values[1].f = low;
213       mv->values[2].f = high;
214       mv->type |= 4;
215       return true;
216     }
217   else
218     return false;
219 }
220
221 /* Returns true if MV contains an individual value,
222    false if MV is empty (or contains only a range). */
223 bool
224 mv_has_value (const struct missing_values *mv)
225 {
226   return mv_n_values (mv) > 0;
227 }
228
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
232    mv_has_value()).
233
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. */
240 void
241 mv_pop_value (struct missing_values *mv, union value *v)
242 {
243   union value tmp;
244
245   assert (mv_has_value (mv));
246
247   value_copy (v, &mv->values[0], mv->width);
248   tmp = mv->values[0];
249   mv->values[0] = mv->values[1];
250   mv->values[1] = mv->values[2];
251   mv->values[2] = tmp;
252   mv->type--;
253 }
254
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
257    modified or freed.
258    IDX must be less than the number of discrete values in MV, as
259    reported by mv_n_values. */
260 const union value *
261 mv_get_value (const struct missing_values *mv, int idx)
262 {
263   assert (idx >= 0 && idx < mv_n_values (mv));
264   return &mv->values[idx];
265 }
266
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. */
271 bool
272 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
273 {
274   assert (idx >= 0) ;
275   assert (idx < mv_n_values(mv));
276
277   if (!mv_is_acceptable (v, mv->width))
278     return false;
279
280   value_copy (&mv->values[idx], v, mv->width);
281   return true;
282 }
283
284 /* Returns the number of individual (not part of a range) missing
285    values in MV. */
286 int
287 mv_n_values (const struct missing_values *mv)
288 {
289   return mv->type & 3;
290 }
291
292
293 /* Returns true if MV contains a numeric range,
294    false if MV is empty (or contains only individual values). */
295 bool
296 mv_has_range (const struct missing_values *mv)
297 {
298   return mv->type == MVT_RANGE || mv->type == MVT_RANGE_1;
299 }
300
301 /* Removes the numeric range from MV and stores it in *LOW and
302    *HIGH.  MV must contain a individual range (as determined by
303    mv_has_range()). */
304 void
305 mv_pop_range (struct missing_values *mv, double *low, double *high)
306 {
307   assert (mv_has_range (mv));
308   *low = mv->values[1].f;
309   *high = mv->values[2].f;
310   mv->type &= 3;
311 }
312
313 /* Returns the numeric range from MV  into *LOW and
314    *HIGH.  MV must contain a individual range (as determined by
315    mv_has_range()). */
316 void
317 mv_get_range (const struct missing_values *mv, double *low, double *high)
318 {
319   assert (mv_has_range (mv));
320   *low = mv->values[1].f;
321   *high = mv->values[2].f;
322 }
323
324 /* Returns true if values[IDX] is in use when the `type' member
325    is set to TYPE (in struct missing_values),
326    false otherwise. */
327 static bool
328 using_element (unsigned type, int idx)
329 {
330   assert (idx >= 0 && idx < 3);
331
332   switch (type)
333     {
334     case MVT_NONE:
335       return false;
336     case MVT_1:
337       return idx < 1;
338     case MVT_2:
339       return idx < 2;
340     case MVT_3:
341       return true;
342     case MVT_RANGE:
343       return idx > 0;
344     case MVT_RANGE_1:
345       return true;
346     }
347   NOT_REACHED ();
348 }
349
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. */
354 bool
355 mv_is_resizable (const struct missing_values *mv, int width)
356 {
357   int i;
358
359   for (i = 0; i < 3; i++)
360     if (using_element (mv->type, i)
361         && !value_is_resizable (&mv->values[i], mv->width, width))
362       return false;
363
364   return true;
365 }
366
367 /* Resizes MV to the given WIDTH.  WIDTH must fit the constraints
368    explained for mv_is_resizable. */
369 void
370 mv_resize (struct missing_values *mv, int width)
371 {
372   int i;
373
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);
378     else
379       {
380         value_destroy (&mv->values[i], mv->width);
381         value_init (&mv->values[i], width);
382       }
383   mv->width = width;
384 }
385
386 /* Returns true if D is a missing value in MV, false otherwise.
387    MV must be a set of numeric missing values. */
388 static bool
389 is_num_user_missing (const struct missing_values *mv, double d)
390 {
391   const union value *v = mv->values;
392   assert (mv->width == 0);
393   switch (mv->type)
394     {
395     case MVT_NONE:
396       return false;
397     case MVT_1:
398       return v[0].f == d;
399     case MVT_2:
400       return v[0].f == d || v[1].f == d;
401     case MVT_3:
402       return v[0].f == d || v[1].f == d || v[2].f == d;
403     case MVT_RANGE:
404       return v[1].f <= d && d <= v[2].f;
405     case MVT_RANGE_1:
406       return v[0].f == d || (v[1].f <= d && d <= v[2].f);
407     }
408   NOT_REACHED ();
409 }
410
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. */
414 static bool
415 is_str_user_missing (const struct missing_values *mv, const uint8_t s[])
416 {
417   const union value *v = mv->values;
418   assert (mv->width > 0);
419   switch (mv->type)
420     {
421     case MVT_NONE:
422       return false;
423     case MVT_1:
424       return !memcmp (value_str (&v[0], mv->width), s, mv->width);
425     case MVT_2:
426       return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
427               || !memcmp (value_str (&v[1], mv->width), s, mv->width));
428     case MVT_3:
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));
432     case MVT_RANGE:
433     case MVT_RANGE_1:
434       NOT_REACHED ();
435     }
436   NOT_REACHED ();
437 }
438
439 /* Returns true if V is a missing value in the given CLASS in MV,
440    false otherwise. */
441 bool
442 mv_is_value_missing (const struct missing_values *mv, const union value *v,
443                      enum mv_class class)
444 {
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));
448 }
449
450 /* Returns true if D is a missing value in the given CLASS in MV,
451    false otherwise.
452    MV must be a set of numeric missing values. */
453 bool
454 mv_is_num_missing (const struct missing_values *mv, double d,
455                    enum mv_class class)
456 {
457   assert (mv->width == 0);
458   return ((class & MV_SYSTEM && d == SYSMIS)
459           || (class & MV_USER && is_num_user_missing (mv, d)));
460 }
461
462 /* Returns true if S[] is a missing value in the given CLASS in
463    MV, false otherwise.
464    MV must be a set of string missing values.
465    S[] must contain exactly as many characters as MV's width. */
466 bool
467 mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
468                    enum mv_class class)
469 {
470   assert (mv->width > 0);
471   return class & MV_USER && is_str_user_missing (mv, s);
472 }