X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=inline;f=src%2Fdata%2Fmissing-values.c;h=9aba57e0e05fb6249764d2c5f778fb6337275a82;hb=refs%2Fbuilds%2F20140123030505%2Fpspp;hp=07ebb77a17312a388ced25b3f04e2ae4f4f0fea5;hpb=a9acce47d67e0ab35ce1690e4f1b1ac0121c2d78;p=pspp
diff --git a/src/data/missing-values.c b/src/data/missing-values.c
index 07ebb77a17..9aba57e0e0 100644
--- a/src/data/missing-values.c
+++ b/src/data/missing-values.c
@@ -1,5 +1,5 @@
/* PSPP - a program for statistical analysis.
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2009, 2011, 2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,13 +15,16 @@
along with this program. If not, see . */
#include
-#include "missing-values.h"
+
+#include "data/missing-values.h"
+
#include
#include
-#include
-#include
-#include "variable.h"
-#include
+
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
/* Types of user-missing values.
Invisible--use access functions defined below instead. */
@@ -36,15 +39,47 @@ enum mv_type
};
/* Initializes MV as a set of missing values for a variable of
- the given WIDTH. Although only numeric variables and short
- string variables may have missing values, WIDTH may be any
- valid variable width. */
+ the given WIDTH. MV should be destroyed with mv_destroy when
+ it is no longer needed. */
void
mv_init (struct missing_values *mv, int width)
{
+ int i;
+
assert (width >= 0 && width <= MAX_STRING);
mv->type = MVT_NONE;
mv->width = width;
+ for (i = 0; i < 3; i++)
+ value_init (&mv->values[i], width);
+}
+
+/* Initializes MV as a set of missing values for a variable of
+ the given WIDTH. MV will be automatically destroyed along
+ with POOL; it must not be passed to mv_destroy for explicit
+ destruction. */
+void
+mv_init_pool (struct pool *pool, struct missing_values *mv, int width)
+{
+ int i;
+
+ assert (width >= 0 && width <= MAX_STRING);
+ mv->type = MVT_NONE;
+ mv->width = width;
+ for (i = 0; i < 3; i++)
+ value_init_pool (pool, &mv->values[i], width);
+}
+
+/* Frees any storage allocated by mv_init for MV. */
+void
+mv_destroy (struct missing_values *mv)
+{
+ if (mv != NULL)
+ {
+ int i;
+
+ for (i = 0; i < 3; i++)
+ value_destroy (&mv->values[i], mv->width);
+ }
}
/* Removes any missing values from MV. */
@@ -54,13 +89,32 @@ mv_clear (struct missing_values *mv)
mv->type = MVT_NONE;
}
-/* Copies SRC to MV. */
+/* Initializes MV as a copy of SRC. */
void
mv_copy (struct missing_values *mv, const struct missing_values *src)
{
- assert(src);
+ int i;
+
+ mv_init (mv, src->width);
+ mv->type = src->type;
+ for (i = 0; i < 3; i++)
+ value_copy (&mv->values[i], &src->values[i], mv->width);
+}
+
+/* Returns true if VALUE, of the given WIDTH, may be added to a
+ missing value set also of the given WIDTH. This is normally
+ the case, but string missing values over MV_MAX_STRING bytes
+ long must consist solely of spaces after the first
+ MV_MAX_STRING bytes. */
+bool
+mv_is_acceptable (const union value *value, int width)
+{
+ int i;
- *mv = *src;
+ for (i = MV_MAX_STRING; i < width; i++)
+ if (value_str (value, width)[i] != ' ')
+ return false;
+ return true;
}
/* Returns true if MV is an empty set of missing values. */
@@ -80,20 +134,21 @@ mv_get_width (const struct missing_values *mv)
/* Attempts to add individual value V to the set of missing
values MV. Returns true if successful, false if MV has no
- more room for missing values. (Long string variables never
- accept missing values.) */
+ more room for missing values or if V is not an acceptable
+ missing value. */
bool
mv_add_value (struct missing_values *mv, const union value *v)
{
- if (mv->width > MAX_SHORT_STRING)
+ if (!mv_is_acceptable (v, mv->width))
return false;
+
switch (mv->type)
{
case MVT_NONE:
case MVT_1:
case MVT_2:
case MVT_RANGE:
- mv->values[mv->type & 3] = *v;
+ value_copy (&mv->values[mv->type & 3], v, mv->width);
mv->type++;
return true;
@@ -104,16 +159,27 @@ mv_add_value (struct missing_values *mv, const union value *v)
NOT_REACHED ();
}
-/* Attempts to add S to the set of string missing values MV. S
- must contain exactly as many characters as MV's width.
- Returns true if successful, false if MV has no more room for
- missing values. (Long string variables never accept missing
- values.) */
+/* Attempts to add S, which is LEN bytes long, to the set of string missing
+ values MV. Returns true if successful, false if MV has no more room for
+ missing values or if S is not an acceptable missing value. */
bool
-mv_add_str (struct missing_values *mv, const char s[])
+mv_add_str (struct missing_values *mv, const uint8_t s[], size_t len)
{
+ union value v;
+ bool ok;
+
assert (mv->width > 0);
- return mv_add_value (mv, (union value *) s);
+ while (len > mv->width)
+ if (s[--len] != ' ')
+ return false;
+
+ value_init (&v, mv->width);
+ buf_copy_rpad (CHAR_CAST (char *, value_str_rw (&v, mv->width)), mv->width,
+ CHAR_CAST (char *, s), len, ' ');
+ ok = mv_add_value (mv, &v);
+ value_destroy (&v, mv->width);
+
+ return ok;
}
/* Attempts to add D to the set of numeric missing values MV.
@@ -122,8 +188,16 @@ mv_add_str (struct missing_values *mv, const char s[])
bool
mv_add_num (struct missing_values *mv, double d)
{
+ union value v;
+ bool ok;
+
assert (mv->width == 0);
- return mv_add_value (mv, (union value *) &d);
+ value_init (&v, 0);
+ v.f = d;
+ ok = mv_add_value (mv, &v);
+ value_destroy (&v, 0);
+
+ return ok;
}
/* Attempts to add range [LOW, HIGH] to the set of numeric
@@ -152,7 +226,8 @@ mv_has_value (const struct missing_values *mv)
return mv_n_values (mv) > 0;
}
-/* Removes one individual value from MV and stores it in *V.
+/* Removes one individual value from MV and stores it in V, which
+ must have been initialized as a value with the same width as MV.
MV must contain an individual value (as determined by
mv_has_value()).
@@ -165,32 +240,46 @@ mv_has_value (const struct missing_values *mv)
void
mv_pop_value (struct missing_values *mv, union value *v)
{
+ union value tmp;
+
assert (mv_has_value (mv));
- *v = mv->values[0];
- remove_element (mv->values, mv->type & 3, sizeof *mv->values, 0);
+ value_copy (v, &mv->values[0], mv->width);
+ tmp = mv->values[0];
+ mv->values[0] = mv->values[1];
+ mv->values[1] = mv->values[2];
+ mv->values[2] = tmp;
mv->type--;
}
-/* Stores MV's value with index IDX in *V.
+/* Returns MV's discrete value with index IDX. The caller must
+ not modify or free this value, or access it after MV is
+ modified or freed.
IDX must be less than the number of discrete values in MV, as
- reported by mv_n_values(MV). */
-void
-mv_get_value (const struct missing_values *mv, union value *v, int idx)
+ reported by mv_n_values. */
+const union value *
+mv_get_value (const struct missing_values *mv, int idx)
{
assert (idx >= 0 && idx < mv_n_values (mv));
- *v = mv->values[idx];
+ return &mv->values[idx];
}
-void
+/* Replaces MV's discrete value with index IDX by a copy of V,
+ which must have the same width as MV.
+ IDX must be less than the number of discrete values in MV, as
+ reported by mv_n_values. */
+bool
mv_replace_value (struct missing_values *mv, const union value *v, int idx)
{
assert (idx >= 0) ;
assert (idx < mv_n_values(mv));
- mv->values[idx] = *v;
-}
+ if (!mv_is_acceptable (v, mv->width))
+ return false;
+ value_copy (&mv->values[idx], v, mv->width);
+ return true;
+}
/* Returns the number of individual (not part of a range) missing
values in MV. */
@@ -232,7 +321,6 @@ mv_get_range (const struct missing_values *mv, double *low, double *high)
*high = mv->values[2].f;
}
-
/* Returns true if values[IDX] is in use when the `type' member
is set to TYPE (in struct missing_values),
false otherwise. */
@@ -262,17 +350,12 @@ using_element (unsigned type, int idx)
/* Returns true if MV can be resized to the given WIDTH with
mv_resize(), false otherwise. Resizing is possible only when
each value in MV (if any) is resizable from MV's current width
- to WIDTH, as determined by value_is_resizable. In addition,
- resizing must not produce a non-empty set of long string
- missing values. */
+ to WIDTH, as determined by value_is_resizable. */
bool
mv_is_resizable (const struct missing_values *mv, int width)
{
int i;
- if (width > MAX_SHORT_STRING && mv->type != MVT_NONE)
- return false;
-
for (i = 0; i < 3; i++)
if (using_element (mv->type, i)
&& !value_is_resizable (&mv->values[i], mv->width, width))
@@ -292,6 +375,11 @@ mv_resize (struct missing_values *mv, int width)
for (i = 0; i < 3; i++)
if (using_element (mv->type, i))
value_resize (&mv->values[i], mv->width, width);
+ else
+ {
+ value_destroy (&mv->values[i], mv->width);
+ value_init (&mv->values[i], width);
+ }
mv->width = width;
}
@@ -324,8 +412,7 @@ is_num_user_missing (const struct missing_values *mv, double d)
MV must be a set of string missing values.
S[] must contain exactly as many characters as MV's width. */
static bool
-is_str_user_missing (const struct missing_values *mv,
- const char s[])
+is_str_user_missing (const struct missing_values *mv, const uint8_t s[])
{
const union value *v = mv->values;
assert (mv->width > 0);
@@ -334,14 +421,14 @@ is_str_user_missing (const struct missing_values *mv,
case MVT_NONE:
return false;
case MVT_1:
- return !memcmp (v[0].s, s, mv->width);
+ return !memcmp (value_str (&v[0], mv->width), s, mv->width);
case MVT_2:
- return (!memcmp (v[0].s, s, mv->width)
- || !memcmp (v[1].s, s, mv->width));
+ return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
+ || !memcmp (value_str (&v[1], mv->width), s, mv->width));
case MVT_3:
- return (!memcmp (v[0].s, s, mv->width)
- || !memcmp (v[1].s, s, mv->width)
- || !memcmp (v[2].s, s, mv->width));
+ return (!memcmp (value_str (&v[0], mv->width), s, mv->width)
+ || !memcmp (value_str (&v[1], mv->width), s, mv->width)
+ || !memcmp (value_str (&v[2], mv->width), s, mv->width));
case MVT_RANGE:
case MVT_RANGE_1:
NOT_REACHED ();
@@ -357,7 +444,7 @@ mv_is_value_missing (const struct missing_values *mv, const union value *v,
{
return (mv->width == 0
? mv_is_num_missing (mv, v->f, class)
- : mv_is_str_missing (mv, v->s, class));
+ : mv_is_str_missing (mv, value_str (v, mv->width), class));
}
/* Returns true if D is a missing value in the given CLASS in MV,
@@ -377,7 +464,7 @@ mv_is_num_missing (const struct missing_values *mv, double d,
MV must be a set of string missing values.
S[] must contain exactly as many characters as MV's width. */
bool
-mv_is_str_missing (const struct missing_values *mv, const char s[],
+mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
enum mv_class class)
{
assert (mv->width > 0);