564d35342981623d58940968854f6fc80cba3e43
[pspp-builds.git] / src / data / caseinit.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
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.
8
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.
13
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
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include <data/caseinit.h>
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <string.h>
26
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>
34
35 #include "xalloc.h"
36
37 struct init_value
38   {
39     union value value;
40     size_t case_index;
41   };
42
43 struct init_list
44   {
45     struct init_value *values;
46     size_t cnt;
47   };
48
49 enum leave_class
50   {
51     LEAVE_REINIT = 0x001,
52     LEAVE_LEFT = 0x002
53   };
54
55 static void
56 init_list_create (struct init_list *list)
57 {
58   list->values = NULL;
59   list->cnt = 0;
60 }
61
62 static void
63 init_list_clear (struct init_list *list)
64 {
65   free (list->values);
66   init_list_create (list);
67 }
68
69 static void
70 init_list_destroy (struct init_list *list)
71 {
72   init_list_clear (list);
73 }
74
75 static int
76 compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
77 {
78   const struct init_value *a = a_;
79   const struct init_value *b = b_;
80
81   return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
82 }
83
84 static bool
85 init_list_includes (const struct init_list *list, size_t case_index)
86 {
87   struct init_value value;
88   value.case_index = case_index;
89   return binary_search (list->values, list->cnt, sizeof *list->values,
90                         &value, compare_init_values, NULL) != NULL;
91 }
92
93 static void
94 init_list_mark (struct init_list *list, const struct init_list *exclude,
95                 enum leave_class include, const struct dictionary *d)
96 {
97   size_t var_cnt = dict_get_var_cnt (d);
98   size_t i;
99
100   assert (list != exclude);
101   list->values = xnrealloc (list->values,
102                             list->cnt + dict_get_next_value_idx (d),
103                             sizeof *list->values);
104   for (i = 0; i < var_cnt; i++)
105     {
106       struct variable *v = dict_get_var (d, i);
107       size_t case_index = var_get_case_index (v);
108       int offset;
109
110       /* Only include the correct class. */
111       if (!(include & (var_get_leave (v) ? LEAVE_LEFT : LEAVE_REINIT)))
112         continue;
113
114       /* Don't include those to be excluded. */
115       if (exclude != NULL && init_list_includes (exclude, case_index))
116         continue;
117
118       offset = 0;
119       do
120         {
121           struct init_value *iv = &list->values[list->cnt++];
122           iv->case_index = case_index++;
123           if (var_is_numeric (v))
124             iv->value.f = var_get_leave (v) ? 0 : SYSMIS;
125           else
126             memset (iv->value.s, ' ', sizeof iv->value.s);
127
128           offset += sizeof iv->value.s;
129         }
130       while (offset < var_get_width (v));
131     }
132
133   /* Drop duplicates. */
134   list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
135                            compare_init_values, NULL);
136
137 }
138
139 static void
140 init_list_init (const struct init_list *list, struct ccase *c)
141 {
142   size_t i;
143
144   for (i = 0; i < list->cnt; i++)
145     {
146       const struct init_value *value = &list->values[i];
147       *case_data_rw_idx (c, value->case_index) = value->value;
148     }
149 }
150
151 static void
152 init_list_update (const struct init_list *list, const struct ccase *c)
153 {
154   size_t i;
155
156   for (i = 0; i < list->cnt; i++)
157     {
158       struct init_value *value = &list->values[i];
159       value->value = *case_data_idx (c, value->case_index);
160     }
161 }
162
163 struct caseinit
164   {
165     struct init_list preinited_values;
166     struct init_list reinit_values;
167     struct init_list left_values;
168   };
169
170 struct caseinit *
171 caseinit_create (void)
172 {
173   struct caseinit *ci = xmalloc (sizeof *ci);
174   init_list_create (&ci->preinited_values);
175   init_list_create (&ci->reinit_values);
176   init_list_create (&ci->left_values);
177   return ci;
178 }
179
180 void
181 caseinit_clear (struct caseinit *ci)
182 {
183   init_list_clear (&ci->preinited_values);
184   init_list_clear (&ci->reinit_values);
185   init_list_clear (&ci->left_values);
186 }
187
188 void
189 caseinit_destroy (struct caseinit *ci)
190 {
191   if (ci != NULL)
192     {
193       init_list_destroy (&ci->preinited_values);
194       init_list_destroy (&ci->reinit_values);
195       init_list_destroy (&ci->left_values);
196       free (ci);
197     }
198 }
199
200 void
201 caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
202 {
203   init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
204 }
205
206 void
207 caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
208 {
209   init_list_mark (&ci->reinit_values, &ci->preinited_values, LEAVE_REINIT, d);
210   init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
211 }
212
213 void
214 caseinit_init_reinit_vars (const struct caseinit *ci, struct ccase *c)
215 {
216   init_list_init (&ci->reinit_values, c);
217 }
218
219 void caseinit_init_left_vars (const struct caseinit *ci, struct ccase *c)
220 {
221   init_list_init (&ci->left_values, c);
222 }
223
224 void
225 caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
226 {
227   init_list_update (&ci->left_values, c);
228 }
229