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/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
38 /* Binds a value with a place to put it. */
46 /* A set of values to initialize in a case. */
49 struct init_value
*values
;
53 /* A bitmap of the "left" status of variables. */
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. */
62 init_list_create (struct init_list
*list
)
68 /* Initializes NEW as a copy of OLD. */
70 init_list_clone (struct init_list
*new, const struct init_list
*old
)
74 new->values
= xmemdup (old
->values
, old
->cnt
* sizeof *old
->values
);
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. */
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
);
95 /* Clears LIST, making it an empty list. */
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. */
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. */
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. */
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
)))
146 /* Don't include those to be excluded. */
147 if (exclude
!= NULL
&& init_list_includes (exclude
, case_index
))
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
))
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
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
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. */
190 /* Values that do not need to be initialized by the
191 procedure, because they are initialized by the data
193 struct init_list preinited_values
;
195 /* Values that need to be initialized to SYSMIS or spaces in
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
202 struct init_list left_values
;
205 /* Creates and returns a new case initializer. */
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
);
216 /* Creates and returns a copy of OLD. */
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
);
227 /* Clears the contents of case initializer CI. */
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. */
238 caseinit_destroy (struct caseinit
*ci
)
242 init_list_destroy (&ci
->preinited_values
);
243 init_list_destroy (&ci
->reinit_values
);
244 init_list_destroy (&ci
->left_values
);
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. */
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. */
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. */
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
282 caseinit_update_left_vars (struct caseinit
*ci
, const struct ccase
*c
)
284 init_list_update (&ci
->left_values
, c
);