treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp.git] / src / data / caseinit.c
blobc93de348728c08ab096ae8f41fae0b543769114a
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/>. */
17 #include <config.h>
19 #include "data/caseinit.h"
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "data/case.h"
26 #include "data/dictionary.h"
27 #include "data/value.h"
28 #include "data/variable.h"
29 #include "libpspp/array.h"
30 #include "libpspp/assertion.h"
31 #include "libpspp/compiler.h"
33 #include "gl/xalloc.h"
35 /* Initializer list: a set of values to write to locations within
36 a case. */
38 /* Binds a value with a place to put it. */
39 struct init_value
41 size_t case_index;
42 int width;
43 union value value;
46 /* A set of values to initialize in a case. */
47 struct init_list
49 struct init_value *values;
50 size_t cnt;
53 /* A bitmap of the "left" status of variables. */
54 enum leave_class
56 LEAVE_REINIT = 0x001, /* Reinitialize for every case. */
57 LEAVE_LEFT = 0x002 /* Keep the value from one case to the next. */
60 /* Initializes LIST as an empty initializer list. */
61 static void
62 init_list_create (struct init_list *list)
64 list->values = NULL;
65 list->cnt = 0;
68 /* Initializes NEW as a copy of OLD. */
69 static void
70 init_list_clone (struct init_list *new, const struct init_list *old)
72 size_t i;
74 new->values = xmemdup (old->values, old->cnt * sizeof *old->values);
75 new->cnt = old->cnt;
77 for (i = 0; i < new->cnt; i++)
79 struct init_value *iv = &new->values[i];
80 value_clone (&iv->value, &iv->value, iv->width);
84 /* Frees the storage associated with LIST. */
85 static void
86 init_list_destroy (struct init_list *list)
88 struct init_value *iv;
90 for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
91 value_destroy (&iv->value, iv->width);
92 free (list->values);
95 /* Clears LIST, making it an empty list. */
96 static void
97 init_list_clear (struct init_list *list)
99 init_list_destroy (list);
100 init_list_create (list);
103 /* Compares `struct init_value's A and B by case_index and
104 returns a strcmp()-type result. */
105 static int
106 compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
108 const struct init_value *a = a_;
109 const struct init_value *b = b_;
111 return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
114 /* Returns true if LIST includes CASE_INDEX, false otherwise. */
115 static bool
116 init_list_includes (const struct init_list *list, size_t case_index)
118 struct init_value value;
119 value.case_index = case_index;
120 return binary_search (list->values, list->cnt, sizeof *list->values,
121 &value, compare_init_values, NULL) != NULL;
124 /* Marks LIST to initialize the `union value's for the variables
125 in dictionary D that both (1) fall in the leave class or
126 classes designated by INCLUDE and (2) are not in EXCLUDE. */
127 static void
128 init_list_mark (struct init_list *list, const struct init_list *exclude,
129 enum leave_class include, const struct dictionary *d)
131 size_t n_vars = dict_get_n_vars (d);
133 assert (list != exclude);
134 list->values = xnrealloc (list->values, list->cnt + dict_get_n_vars (d),
135 sizeof *list->values);
136 for (size_t i = 0; i < n_vars; i++)
138 struct variable *v = dict_get_var (d, i);
139 size_t case_index = var_get_case_index (v);
140 struct init_value *iv;
142 /* Only include the correct class. */
143 if (!(include & (var_get_leave (v) ? LEAVE_LEFT : LEAVE_REINIT)))
144 continue;
146 /* Don't include those to be excluded. */
147 if (exclude != NULL && init_list_includes (exclude, case_index))
148 continue;
150 iv = &list->values[list->cnt++];
151 iv->case_index = case_index;
152 iv->width = var_get_width (v);
153 value_init (&iv->value, iv->width);
154 if (var_is_numeric (v) && var_get_leave (v))
155 iv->value.f = 0;
156 else
157 value_set_missing (&iv->value, iv->width);
160 /* Drop duplicates. */
161 list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
162 compare_init_values, NULL);
165 /* Initializes data in case C to the values in the initializer
166 LIST. */
167 static void
168 init_list_init (const struct init_list *list, struct ccase *c)
170 const struct init_value *iv;
172 for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
173 value_copy (case_data_rw_idx (c, iv->case_index), &iv->value, iv->width);
176 /* Updates the values in the initializer LIST from the data in
177 case C. */
178 static void
179 init_list_update (const struct init_list *list, const struct ccase *c)
181 struct init_value *iv;
183 for (iv = &list->values[0]; iv < &list->values[list->cnt]; iv++)
184 value_copy (&iv->value, case_data_idx (c, iv->case_index), iv->width);
187 /* A case initializer. */
188 struct caseinit
190 /* Values that do not need to be initialized by the
191 procedure, because they are initialized by the data
192 source. */
193 struct init_list preinited_values;
195 /* Values that need to be initialized to SYSMIS or spaces in
196 each case. */
197 struct init_list reinit_values;
199 /* Values that need to be initialized to 0 or spaces in the
200 first case and thereafter retain their values from case to
201 case. */
202 struct init_list left_values;
205 /* Creates and returns a new case initializer. */
206 struct caseinit *
207 caseinit_create (void)
209 struct caseinit *ci = xmalloc (sizeof *ci);
210 init_list_create (&ci->preinited_values);
211 init_list_create (&ci->reinit_values);
212 init_list_create (&ci->left_values);
213 return ci;
216 /* Creates and returns a copy of OLD. */
217 struct caseinit *
218 caseinit_clone (struct caseinit *old)
220 struct caseinit *new = xmalloc (sizeof *new);
221 init_list_clone (&new->preinited_values, &old->preinited_values);
222 init_list_clone (&new->reinit_values, &old->reinit_values);
223 init_list_clone (&new->left_values, &old->left_values);
224 return new;
227 /* Clears the contents of case initializer CI. */
228 void
229 caseinit_clear (struct caseinit *ci)
231 init_list_clear (&ci->preinited_values);
232 init_list_clear (&ci->reinit_values);
233 init_list_clear (&ci->left_values);
236 /* Destroys case initializer CI. */
237 void
238 caseinit_destroy (struct caseinit *ci)
240 if (ci != NULL)
242 init_list_destroy (&ci->preinited_values);
243 init_list_destroy (&ci->reinit_values);
244 init_list_destroy (&ci->left_values);
245 free (ci);
249 /* Marks the variables from dictionary D in CI as being
250 initialized by the data source, so that the case initializer
251 need not initialize them itself. */
252 void
253 caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
255 init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
258 /* Marks in CI the variables from dictionary D, except for any
259 variables that were already marked with
260 caseinit_mark_as_preinited, as needing initialization
261 according to their leave status. */
262 void
263 caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
265 init_list_mark (&ci->reinit_values, &ci->preinited_values, LEAVE_REINIT, d);
266 init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
269 /* Initializes variables in *C as described by CI.
270 C must not be shared. */
271 void
272 caseinit_init_vars (const struct caseinit *ci, struct ccase *c)
274 init_list_init (&ci->reinit_values, c);
275 init_list_init (&ci->left_values, c);
278 /* Updates the left vars in CI from the data in C, so that the
279 next call to caseinit_init_vars will store those values in the
280 next case. */
281 void
282 caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
284 init_list_update (&ci->left_values, c);