X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Fdata%2Fcaseinit.c;h=572f9160292e670f1a60ae99c226b2ad13b064de;hb=97f9b8ad137e333af9b3c767556d28dfda93a461;hp=7b8e6a09ce56def0e26c36a22ee878c7b21c09df;hpb=0ee6bedec2f1361e885219a9e4570f297058bd3a;p=pspp
diff --git a/src/data/caseinit.c b/src/data/caseinit.c
index 7b8e6a09ce..572f916029 100644
--- a/src/data/caseinit.c
+++ b/src/data/caseinit.c
@@ -1,20 +1,18 @@
-/* PSPP - computes sample statistics.
- Copyright (C) 2007 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2007, 2009 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 the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see . */
#include
@@ -33,47 +31,63 @@
#include
#include "xalloc.h"
+
+/* Initializer list: a set of values to write to locations within
+ a case. */
+/* Binds a value with a place to put it. */
struct init_value
{
- union value value;
size_t case_index;
+ int width;
+ union value value;
};
-struct init_list
+/* A set of values to initialize in a case. */
+struct init_list
{
struct init_value *values;
size_t cnt;
};
-enum leave_class
+/* A bitmap of the "left" status of variables. */
+enum leave_class
{
- LEAVE_REINIT = 0x001,
- LEAVE_LEFT = 0x002
+ LEAVE_REINIT = 0x001, /* Reinitalize for every case. */
+ LEAVE_LEFT = 0x002 /* Keep the value from one case to the next. */
};
+/* Initializes LIST as an empty initializer list. */
static void
-init_list_create (struct init_list *list)
+init_list_create (struct init_list *list)
{
list->values = NULL;
list->cnt = 0;
}
+/* Frees the storage associated with LIST. */
static void
-init_list_clear (struct init_list *list)
+init_list_destroy (struct init_list *list)
{
+ struct init_value *iv;
+
+ for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
+ value_destroy (&iv->value, iv->width);
free (list->values);
- init_list_create (list);
}
+/* Clears LIST, making it an empty list. */
static void
-init_list_destroy (struct init_list *list)
+init_list_clear (struct init_list *list)
{
- init_list_clear (list);
+ init_list_destroy (list);
+ init_list_create (list);
}
+/* Compares `struct init_value's A and B by case_index and
+ returns a strcmp()-type result. */
static int
-compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
+compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
{
const struct init_value *a = a_;
const struct init_value *b = b_;
@@ -81,8 +95,9 @@ compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
}
+/* Returns true if LIST includes CASE_INDEX, false otherwise. */
static bool
-init_list_includes (const struct init_list *list, size_t case_index)
+init_list_includes (const struct init_list *list, size_t case_index)
{
struct init_value value;
value.case_index = case_index;
@@ -90,85 +105,91 @@ init_list_includes (const struct init_list *list, size_t case_index)
&value, compare_init_values, NULL) != NULL;
}
+/* Marks LIST to initialize the `union value's for the variables
+ in dictionary D that both (1) fall in the leave class or
+ classes designated by INCLUDE and (2) are not in EXCLUDE. */
static void
init_list_mark (struct init_list *list, const struct init_list *exclude,
- enum leave_class include, const struct dictionary *d)
+ enum leave_class include, const struct dictionary *d)
{
size_t var_cnt = dict_get_var_cnt (d);
size_t i;
assert (list != exclude);
- list->values = xnrealloc (list->values,
- list->cnt + dict_get_next_value_idx (d),
+ list->values = xnrealloc (list->values, list->cnt + dict_get_var_cnt (d),
sizeof *list->values);
- for (i = 0; i < var_cnt; i++)
+ for (i = 0; i < var_cnt; i++)
{
struct variable *v = dict_get_var (d, i);
size_t case_index = var_get_case_index (v);
- int offset;
+ struct init_value *iv;
/* Only include the correct class. */
if (!(include & (var_get_leave (v) ? LEAVE_LEFT : LEAVE_REINIT)))
continue;
/* Don't include those to be excluded. */
- if (exclude != NULL && init_list_includes (exclude, case_index))
- continue;
-
- offset = 0;
- do
- {
- struct init_value *iv = &list->values[list->cnt++];
- iv->case_index = case_index++;
- if (var_is_numeric (v))
- iv->value.f = var_get_leave (v) ? 0 : SYSMIS;
- else
- memset (iv->value.s, ' ', sizeof iv->value.s);
-
- offset += sizeof iv->value.s;
- }
- while (offset < var_get_width (v));
+ if (exclude != NULL && init_list_includes (exclude, case_index))
+ continue;
+
+ iv = &list->values[list->cnt++];
+ iv->case_index = case_index;
+ iv->width = var_get_width (v);
+ value_init (&iv->value, iv->width);
+ if (var_is_numeric (v) && var_get_leave (v))
+ iv->value.f = 0;
+ else
+ value_set_missing (&iv->value, iv->width);
}
/* Drop duplicates. */
list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
compare_init_values, NULL);
-
}
+/* Initializes data in case C to the values in the initializer
+ LIST. */
static void
-init_list_init (const struct init_list *list, struct ccase *c)
+init_list_init (const struct init_list *list, struct ccase *c)
{
- size_t i;
+ const struct init_value *iv;
- for (i = 0; i < list->cnt; i++)
- {
- const struct init_value *value = &list->values[i];
- *case_data_rw_idx (c, value->case_index) = value->value;
- }
+ for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
+ value_copy (case_data_rw_idx (c, iv->case_index), &iv->value, iv->width);
}
+/* Updates the values in the initializer LIST from the data in
+ case C. */
static void
-init_list_update (const struct init_list *list, const struct ccase *c)
+init_list_update (const struct init_list *list, const struct ccase *c)
{
- size_t i;
-
- for (i = 0; i < list->cnt; i++)
- {
- struct init_value *value = &list->values[i];
- value->value = *case_data_idx (c, value->case_index);
- }
-}
+ struct init_value *iv;
-struct caseinit
+ for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
+ value_copy (&iv->value, case_data_idx (c, iv->case_index), iv->width);
+}
+
+/* A case initializer. */
+struct caseinit
{
+ /* Values that do not need to be initialized by the
+ procedure, because they are initialized by the data
+ source. */
struct init_list preinited_values;
+
+ /* Values that need to be initialized to SYSMIS or spaces in
+ each case. */
struct init_list reinit_values;
+
+ /* Values that need to be initialized to 0 or spaces in the
+ first case and thereafter retain their values from case to
+ case. */
struct init_list left_values;
};
+/* Creates and returns a new case initializer. */
struct caseinit *
-caseinit_create (void)
+caseinit_create (void)
{
struct caseinit *ci = xmalloc (sizeof *ci);
init_list_create (&ci->preinited_values);
@@ -177,18 +198,20 @@ caseinit_create (void)
return ci;
}
+/* Clears the contents of case initializer CI. */
void
-caseinit_clear (struct caseinit *ci)
+caseinit_clear (struct caseinit *ci)
{
init_list_clear (&ci->preinited_values);
init_list_clear (&ci->reinit_values);
init_list_clear (&ci->left_values);
}
+/* Destroys case initializer CI. */
void
-caseinit_destroy (struct caseinit *ci)
+caseinit_destroy (struct caseinit *ci)
{
- if (ci != NULL)
+ if (ci != NULL)
{
init_list_destroy (&ci->preinited_values);
init_list_destroy (&ci->reinit_values);
@@ -197,32 +220,40 @@ caseinit_destroy (struct caseinit *ci)
}
}
+/* Marks the variables from dictionary D in CI as being
+ initialized by the data source, so that the case initializer
+ need not initialize them itself. */
void
-caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
+caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
{
init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
}
+/* Marks in CI the variables from dictionary D, except for any
+ variables that were already marked with
+ caseinit_mark_as_preinited, as needing initialization
+ according to their leave status. */
void
-caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
+caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
{
init_list_mark (&ci->reinit_values, &ci->preinited_values, LEAVE_REINIT, d);
init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
}
+/* Initializes variables in *C as described by CI.
+ C must not be shared. */
void
-caseinit_init_reinit_vars (const struct caseinit *ci, struct ccase *c)
+caseinit_init_vars (const struct caseinit *ci, struct ccase *c)
{
init_list_init (&ci->reinit_values, c);
-}
-
-void caseinit_init_left_vars (const struct caseinit *ci, struct ccase *c)
-{
init_list_init (&ci->left_values, c);
}
+/* Updates the left vars in CI from the data in C, so that the
+ next call to caseinit_init_vars will store those values in the
+ next case. */
void
-caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
+caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
{
init_list_update (&ci->left_values, c);
}