1 /* PSPP - computes sample statistics.
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <data/caseinit.h>
27 #include <data/case.h>
28 #include <data/dictionary.h>
29 #include <data/value.h>
30 #include <data/variable.h>
31 #include <libpspp/array.h>
32 #include <libpspp/assertion.h>
33 #include <libpspp/compiler.h>
37 /* Initializer list: a set of values to write to locations within
40 /* Binds a value with a place to put it. */
47 /* A set of values to initialize in a case. */
50 struct init_value *values;
54 /* A bitmap of the "left" status of variables. */
57 LEAVE_REINIT = 0x001, /* Reinitalize for every case. */
58 LEAVE_LEFT = 0x002 /* Keep the value from one case to the next. */
61 /* Initializes LIST as an empty initializer list. */
63 init_list_create (struct init_list *list)
69 /* Frees the storage associated with LIST. */
71 init_list_destroy (struct init_list *list)
76 /* Clears LIST, making it an empty list. */
78 init_list_clear (struct init_list *list)
80 init_list_destroy (list);
81 init_list_create (list);
84 /* Compares `struct init_value's A and B by case_index and
85 returns a strcmp()-type result. */
87 compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
89 const struct init_value *a = a_;
90 const struct init_value *b = b_;
92 return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
95 /* Returns true if LIST includes CASE_INDEX, false otherwise. */
97 init_list_includes (const struct init_list *list, size_t case_index)
99 struct init_value value;
100 value.case_index = case_index;
101 return binary_search (list->values, list->cnt, sizeof *list->values,
102 &value, compare_init_values, NULL) != NULL;
105 /* Marks LIST to initialize the `union value's for the variables
106 in dictionary D that both (1) fall in the leave class or
107 classes designated by INCLUDE and (2) are not in EXCLUDE. */
109 init_list_mark (struct init_list *list, const struct init_list *exclude,
110 enum leave_class include, const struct dictionary *d)
112 size_t var_cnt = dict_get_var_cnt (d);
115 assert (list != exclude);
116 list->values = xnrealloc (list->values,
117 list->cnt + dict_get_next_value_idx (d),
118 sizeof *list->values);
119 for (i = 0; i < var_cnt; i++)
121 struct variable *v = dict_get_var (d, i);
122 size_t case_index = var_get_case_index (v);
125 /* Only include the correct class. */
126 if (!(include & (var_get_leave (v) ? LEAVE_LEFT : LEAVE_REINIT)))
129 /* Don't include those to be excluded. */
130 if (exclude != NULL && init_list_includes (exclude, case_index))
136 struct init_value *iv = &list->values[list->cnt++];
137 iv->case_index = case_index++;
138 if (var_is_numeric (v))
139 iv->value.f = var_get_leave (v) ? 0 : SYSMIS;
141 memset (iv->value.s, ' ', sizeof iv->value.s);
143 offset += sizeof iv->value.s;
145 while (offset < var_get_width (v));
148 /* Drop duplicates. */
149 list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
150 compare_init_values, NULL);
153 /* Initializes data in case C to the values in the initializer
156 init_list_init (const struct init_list *list, struct ccase *c)
160 for (i = 0; i < list->cnt; i++)
162 const struct init_value *value = &list->values[i];
163 *case_data_rw_idx (c, value->case_index) = value->value;
167 /* Updates the values in the initializer LIST from the data in
170 init_list_update (const struct init_list *list, const struct ccase *c)
174 for (i = 0; i < list->cnt; i++)
176 struct init_value *value = &list->values[i];
177 value->value = *case_data_idx (c, value->case_index);
181 /* A case initializer. */
184 /* Values that do not need to be initialized by the
185 procedure, because they are initialized by the data
187 struct init_list preinited_values;
189 /* Values that need to be initialized to SYSMIS or spaces in
191 struct init_list reinit_values;
193 /* Values that need to be initialized to 0 or spaces in the
194 first case and thereafter retain their values from case to
196 struct init_list left_values;
199 /* Creates and returns a new case initializer. */
201 caseinit_create (void)
203 struct caseinit *ci = xmalloc (sizeof *ci);
204 init_list_create (&ci->preinited_values);
205 init_list_create (&ci->reinit_values);
206 init_list_create (&ci->left_values);
210 /* Clears the contents of case initializer CI. */
212 caseinit_clear (struct caseinit *ci)
214 init_list_clear (&ci->preinited_values);
215 init_list_clear (&ci->reinit_values);
216 init_list_clear (&ci->left_values);
219 /* Destroys case initializer CI. */
221 caseinit_destroy (struct caseinit *ci)
225 init_list_destroy (&ci->preinited_values);
226 init_list_destroy (&ci->reinit_values);
227 init_list_destroy (&ci->left_values);
232 /* Marks the variables from dictionary D in CI as being
233 initialized by the data source, so that the case initializer
234 need not initialize them itself. */
236 caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
238 init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
241 /* Marks in CI the variables from dictionary D, except for any
242 variables that were already marked with
243 caseinit_mark_as_preinited, as needing initialization
244 according to their leave status. */
246 caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
248 init_list_mark (&ci->reinit_values, &ci->preinited_values, LEAVE_REINIT, d);
249 init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
252 /* Initializes variables in C as described by CI. */
254 caseinit_init_vars (const struct caseinit *ci, struct ccase *c)
256 init_list_init (&ci->reinit_values, c);
257 init_list_init (&ci->left_values, c);
260 /* Updates the left vars in CI from the data in C, so that the
261 next call to caseinit_init_vars will store those values in the
264 caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
266 init_list_update (&ci->left_values, c);