1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "data/caseinit.h"
25 #include "data/case.h"
26 #include "data/casereader.h"
27 #include "data/dictionary.h"
28 #include "data/value.h"
29 #include "data/variable.h"
30 #include "libpspp/array.h"
31 #include "libpspp/assertion.h"
32 #include "libpspp/compiler.h"
34 #include "gl/xalloc.h"
36 /* Initializer list: a set of values to write to locations within
39 /* 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, /* Reinitialize 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 /* Initializes NEW as a copy of OLD. */
70 static struct init_list
71 init_list_clone (const struct init_list *old)
73 struct init_value *values = xmemdup (old->values,
74 old->n * sizeof *old->values);
75 for (size_t i = 0; i < old->n; i++)
77 struct init_value *iv = &values[i];
78 value_clone (&iv->value, &iv->value, iv->width);
80 return (struct init_list) { .values = values, .n = old->n };
83 /* Frees the storage associated with LIST. */
85 init_list_destroy (struct init_list *list)
87 struct init_value *iv;
89 for (iv = &list->values[0]; iv < &list->values[list->n]; iv++)
90 value_destroy (&iv->value, iv->width);
94 /* Clears LIST, making it an empty list. */
96 init_list_clear (struct init_list *list)
98 init_list_destroy (list);
99 init_list_create (list);
102 /* Compares `struct init_value's A and B by case_index and
103 returns a strcmp()-type result. */
105 compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
107 const struct init_value *a = a_;
108 const struct init_value *b = b_;
110 return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
113 /* Returns true if LIST includes CASE_INDEX, false otherwise. */
115 init_list_includes (const struct init_list *list, size_t case_index)
117 struct init_value value;
118 value.case_index = case_index;
119 return binary_search (list->values, list->n, sizeof *list->values,
120 &value, compare_init_values, NULL) != NULL;
123 /* Marks LIST to initialize the `union value's for the variables
124 in dictionary D that both (1) fall in the leave class or
125 classes designated by INCLUDE and (2) are not in EXCLUDE. */
127 init_list_mark (struct init_list *list, const struct init_list *exclude,
128 enum leave_class include, const struct dictionary *d)
130 size_t n_vars = dict_get_n_vars (d);
132 assert (list != exclude);
133 list->values = xnrealloc (list->values, list->n + dict_get_n_vars (d),
134 sizeof *list->values);
135 for (size_t i = 0; i < n_vars; i++)
137 struct variable *v = dict_get_var (d, i);
138 size_t case_index = var_get_case_index (v);
139 struct init_value *iv;
141 /* Only include the correct class. */
142 if (!(include & (var_get_leave (v) ? LEAVE_LEFT : LEAVE_REINIT)))
145 /* Don't include those to be excluded. */
146 if (exclude != NULL && init_list_includes (exclude, case_index))
149 iv = &list->values[list->n++];
150 iv->case_index = case_index;
151 iv->width = var_get_width (v);
152 value_init (&iv->value, iv->width);
153 if (var_is_numeric (v) && var_get_leave (v))
156 value_set_missing (&iv->value, iv->width);
159 /* Drop duplicates. */
160 list->n = sort_unique (list->values, list->n, sizeof *list->values,
161 compare_init_values, NULL);
164 /* Initializes data in case C to the values in the initializer
167 init_list_init (const struct init_list *list, struct ccase *c)
169 const struct init_value *iv;
171 for (iv = &list->values[0]; iv < &list->values[list->n]; iv++)
172 value_copy (case_data_rw_idx (c, iv->case_index), &iv->value, iv->width);
175 /* Updates the values in the initializer LIST from the data in
178 init_list_update (const struct init_list *list, const struct ccase *c)
180 struct init_value *iv;
182 for (iv = &list->values[0]; iv < &list->values[list->n]; iv++)
183 value_copy (&iv->value, case_data_idx (c, iv->case_index), iv->width);
186 /* A case initializer. */
189 /* Values that do not need to be initialized by the
190 procedure, because they are initialized by the data
192 struct init_list preinited_values;
194 /* Values that need to be initialized to SYSMIS or spaces in
196 struct init_list reinit_values;
198 /* Values that need to be initialized to 0 or spaces in the
199 first case and thereafter retain their values from case to
201 struct init_list left_values;
204 /* Creates and returns a new case initializer. */
206 caseinit_create (void)
208 struct caseinit *ci = xmalloc (sizeof *ci);
209 init_list_create (&ci->preinited_values);
210 init_list_create (&ci->reinit_values);
211 init_list_create (&ci->left_values);
215 /* Creates and returns a copy of OLD. */
217 caseinit_clone (struct caseinit *old)
219 struct caseinit *new = xmalloc (sizeof *new);
220 *new = (struct caseinit) {
221 .preinited_values = init_list_clone (&old->preinited_values),
222 .reinit_values = init_list_clone (&old->reinit_values),
223 .left_values = init_list_clone (&old->left_values),
228 /* Clears the contents of case initializer CI. */
230 caseinit_clear (struct caseinit *ci)
232 init_list_clear (&ci->preinited_values);
233 init_list_clear (&ci->reinit_values);
234 init_list_clear (&ci->left_values);
237 /* Destroys case initializer CI. */
239 caseinit_destroy (struct caseinit *ci)
243 init_list_destroy (&ci->preinited_values);
244 init_list_destroy (&ci->reinit_values);
245 init_list_destroy (&ci->left_values);
250 /* Marks the variables from dictionary D in CI as being
251 initialized by the data source, so that the case initializer
252 need not initialize them itself. */
254 caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
256 init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
259 /* Marks in CI the variables from dictionary D, except for any
260 variables that were already marked with
261 caseinit_mark_as_preinited, as needing initialization
262 according to their leave status. */
264 caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
266 init_list_mark (&ci->reinit_values, &ci->preinited_values, LEAVE_REINIT, d);
267 init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
270 /* Initializes variables in *C as described by CI.
271 C must not be shared. */
273 caseinit_init_vars (const struct caseinit *ci, struct ccase *c)
275 init_list_init (&ci->reinit_values, c);
278 /* Copies the left vars from CI into C. */
280 caseinit_restore_left_vars (struct caseinit *ci, struct ccase *c)
282 init_list_init (&ci->left_values, c);
285 /* Copies the left vars from C into CI. */
287 caseinit_save_left_vars (struct caseinit *ci, const struct ccase *c)
289 init_list_update (&ci->left_values, c);
292 struct caseinit_translator
294 struct init_list reinit_values;
295 struct caseproto *proto;
298 static struct ccase *
299 translate_caseinit (struct ccase *c, void *cit_)
301 const struct caseinit_translator *cit = cit_;
303 c = case_unshare_and_resize (c, cit->proto);
304 init_list_init (&cit->reinit_values, c);
309 translate_destroy (void *cit_)
311 struct caseinit_translator *cit = cit_;
313 init_list_destroy (&cit->reinit_values);
314 caseproto_unref (cit->proto);
320 /* Returns a new casereader that yields each case from R, resized to match
321 OUTPUT_PROTO and initialized from CI as if with caseinit_init_vars(). Takes
324 OUTPUT_PROTO must be conformable with R's prototype. */
326 caseinit_translate_casereader_to_init_vars (struct caseinit *ci,
327 const struct caseproto *output_proto,
328 struct casereader *r)
330 assert (caseproto_is_conformable (casereader_get_proto (r), output_proto));
331 if (caseproto_equal (output_proto, casereader_get_proto (r))
332 && ci->reinit_values.n == 0)
333 return casereader_rename (r);
335 struct caseinit_translator *cit = xmalloc (sizeof *cit);
336 *cit = (struct caseinit_translator) {
337 .reinit_values = init_list_clone (&ci->reinit_values),
338 .proto = caseproto_ref (output_proto),
341 static const struct casereader_translator_class class = {
342 .translate = translate_caseinit,
343 .destroy = translate_destroy,
345 return casereader_translate_stateless (r, output_proto, &class, cit);