X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fcaseinit.c;h=69a0f01869fb7a66c97522d0a86243b9f523dfaf;hb=81579d9e9f994fb2908f50af41c3eb033d216e58;hp=7b8e6a09ce56def0e26c36a22ee878c7b21c09df;hpb=0ee6bedec2f1361e885219a9e4570f297058bd3a;p=pspp-builds.git diff --git a/src/data/caseinit.c b/src/data/caseinit.c index 7b8e6a09..69a0f018 100644 --- a/src/data/caseinit.c +++ b/src/data/caseinit.c @@ -1,79 +1,93 @@ -/* PSPP - computes sample statistics. - Copyright (C) 2007 Free Software Foundation, Inc. +/* PSPP - a program for statistical analysis. + Copyright (C) 2007, 2009, 2011 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 -#include +#include "data/caseinit.h" #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include "data/case.h" +#include "data/dictionary.h" +#include "data/value.h" +#include "data/variable.h" +#include "libpspp/array.h" +#include "libpspp/assertion.h" +#include "libpspp/compiler.h" -#include "xalloc.h" +#include "gl/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); }