be58609693900cc5d02fff87a5d225f8a4002688
[pspp-builds.git] / src / data / subcase.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008, 2009 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18 #include <data/subcase.h>
19 #include <stdlib.h>
20 #include <data/case.h>
21 #include <data/variable.h>
22 #include <libpspp/assertion.h>
23
24 #include "xalloc.h"
25
26 static void invalidate_proto (struct subcase *sc);
27
28 /* Initializes SC as a subcase that contains no fields. */
29 void
30 subcase_init_empty (struct subcase *sc)
31 {
32   sc->fields = NULL;
33   sc->n_fields = 0;
34   sc->proto = NULL;
35 }
36
37 /* Initializes SC as a subcase with fields extracted from the
38    N_VARS variables in VARS, with ascending sort order. */
39 void
40 subcase_init_vars (struct subcase *sc,
41                    const struct variable *const *vars, size_t n_vars)
42 {
43   size_t i;
44
45   sc->fields = xnmalloc (n_vars, sizeof *sc->fields);
46   sc->n_fields = n_vars;
47   sc->proto = NULL;
48   for (i = 0; i < n_vars; i++)
49     {
50       struct subcase_field *field = &sc->fields[i];
51       field->case_index = var_get_case_index (vars[i]);
52       field->width = var_get_width (vars[i]);
53       field->direction = SC_ASCEND;
54     }
55 }
56
57 /* Initializes SC as a subcase with a single field extracted
58    from VAR, with the sort order specified by DIRECTION.  */
59 void
60 subcase_init_var (struct subcase *sc, const struct variable *var,
61                   enum subcase_direction direction)
62 {
63   subcase_init_empty (sc);
64   subcase_add_var (sc, var, direction);
65 }
66
67 /* Removes all the fields from SC. */
68 void
69 subcase_clear (struct subcase *sc)
70 {
71   sc->n_fields = 0;
72   invalidate_proto (sc);
73 }
74
75 /* Initializes SC with the same fields as ORIG. */
76 void
77 subcase_clone (struct subcase *sc, const struct subcase *orig)
78 {
79   sc->fields = xmemdup (orig->fields, orig->n_fields * sizeof *orig->fields);
80   sc->n_fields = orig->n_fields;
81   sc->proto = orig->proto ? caseproto_ref (orig->proto) : NULL;
82 }
83
84 /* Frees the memory owned by SC (but not SC itself). */
85 void
86 subcase_destroy (struct subcase *sc)
87 {
88   free (sc->fields);
89   caseproto_unref (sc->proto);
90 }
91
92 /* Add a field for VAR to SC, with DIRECTION as the sort order.
93    Returns true if successful, false if VAR already has a field
94    in SC. */
95 bool
96 subcase_add_var (struct subcase *sc, const struct variable *var,
97                  enum subcase_direction direction)
98 {
99   size_t case_index = var_get_case_index (var);
100   struct subcase_field *field;
101   size_t i;
102
103   for (i = 0; i < sc->n_fields; i++)
104     if (sc->fields[i].case_index == case_index)
105       return false;
106
107   sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
108   field = &sc->fields[sc->n_fields++];
109   field->case_index = case_index;
110   field->width = var_get_width (var);
111   field->direction = direction;
112   invalidate_proto (sc);
113   return true;
114 }
115
116 /* Obtains a caseproto for a case described by SC.  The caller
117    must not modify or unref the returned case prototype. */
118 const struct caseproto *
119 subcase_get_proto (const struct subcase *sc_)
120 {
121   struct subcase *sc = (struct subcase *) sc_;
122
123   if (sc->proto == NULL)
124     {
125       size_t i;
126
127       sc->proto = caseproto_create ();
128       for (i = 0; i < sc->n_fields; i++)
129         sc->proto = caseproto_add_width (sc->proto, sc->fields[i].width);
130     }
131   return sc->proto;
132 }
133
134 /* Returns true if and only if A and B are conformable, which
135    means that they have the same number of fields and that each
136    corresponding field in A and B have the same width. */
137 bool
138 subcase_conformable (const struct subcase *a, const struct subcase *b)
139 {
140   size_t i;
141
142   if (a == b)
143     return true;
144   if (a->n_fields != b->n_fields)
145     return false;
146   for (i = 0; i < a->n_fields; i++)
147     if (a->fields[i].width != b->fields[i].width)
148       return false;
149   return true;
150 }
151
152 /* Copies the fields represented by SC from C into VALUES.
153    VALUES must have space for at least subcase_get_n_fields(SC)
154    array elements. */
155 void
156 subcase_extract (const struct subcase *sc, const struct ccase *c,
157                  union value values[])
158 {
159   size_t i;
160
161   for (i = 0; i < sc->n_fields; i++)
162     {
163       const struct subcase_field *field = &sc->fields[i];
164       union value *value = &values[i];
165       value_copy (value, case_data_idx (c, field->case_index), field->width);
166     }
167 }
168
169 /* Copies the data in VALUES into the fields in C represented by
170    SC.  VALUES must have at least subcase_get_n_fields(SC) array
171    elements, and C must be large enough to contain all the fields
172    in SC. */
173 void
174 subcase_inject (const struct subcase *sc,
175                 const union value values[], struct ccase *c)
176 {
177   size_t i;
178
179   for (i = 0; i < sc->n_fields; i++)
180     {
181       const struct subcase_field *field = &sc->fields[i];
182       const union value *value = &values[i];
183       value_copy (case_data_rw_idx (c, field->case_index), value,
184                   field->width);
185     }
186 }
187
188 /* Copies the fields in SRC represented by SRC_SC into the
189    corresponding fields in DST respresented by DST_SC.  SRC_SC
190    and DST_SC must be conformable (as tested by
191    subcase_conformable()).
192
193    DST must not be shared. */
194 void
195 subcase_copy (const struct subcase *src_sc, const struct ccase *src,
196               const struct subcase *dst_sc, struct ccase *dst)
197 {
198   size_t i;
199
200   expensive_assert (subcase_conformable (src_sc, dst_sc));
201   for (i = 0; i < src_sc->n_fields; i++)
202     {
203       const struct subcase_field *src_field = &src_sc->fields[i];
204       const struct subcase_field *dst_field = &dst_sc->fields[i];
205       value_copy (case_data_rw_idx (dst, dst_field->case_index),
206                   case_data_idx (src, src_field->case_index),
207                   src_field->width);
208     }
209 }
210
211 /* Compares the fields in A specified in A_SC against the fields
212    in B specified in B_SC.  Returns -1, 0, or 1 if A's fields are
213    lexicographically less than, equal to, or greater than B's
214    fields, respectively.
215
216    A_SC and B_SC must be conformable (as tested by
217    subcase_conformable()). */
218 int
219 subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
220                       const struct subcase *b_sc, const struct ccase *b)
221 {
222   size_t i;
223
224   expensive_assert (subcase_conformable (a_sc, b_sc));
225   for (i = 0; i < a_sc->n_fields; i++)
226     {
227       const struct subcase_field *a_field = &a_sc->fields[i];
228       const struct subcase_field *b_field = &b_sc->fields[i];
229       int cmp = value_compare_3way (case_data_idx (a, a_field->case_index),
230                                     case_data_idx (b, b_field->case_index),
231                                     a_field->width);
232       if (cmp != 0)
233         return a_field->direction == SC_ASCEND ? cmp : -cmp;
234     }
235   return 0;
236 }
237
238 /* Compares the values in A against the values in B specified by
239    SC's fields.  Returns -1, 0, or 1 if A's values are
240    lexicographically less than, equal to, or greater than B's
241    values, respectively. */
242 int
243 subcase_compare_3way_xc (const struct subcase *sc,
244                          const union value a[], const struct ccase *b)
245 {
246   size_t i;
247
248   for (i = 0; i < sc->n_fields; i++)
249     {
250       const struct subcase_field *field = &sc->fields[i];
251       int cmp = value_compare_3way (&a[i],
252                                     case_data_idx (b, field->case_index),
253                                     field->width);
254       if (cmp != 0)
255         return field->direction == SC_ASCEND ? cmp : -cmp;
256     }
257   return 0;
258 }
259
260 /* Compares the values in A specified by SC's fields against the
261    values in B.  Returns -1, 0, or 1 if A's values are
262    lexicographically less than, equal to, or greater than B's
263    values, respectively. */
264 int
265 subcase_compare_3way_cx (const struct subcase *sc,
266                          const struct ccase *a, const union value b[])
267 {
268   return -subcase_compare_3way_xc (sc, b, a);
269 }
270
271 /* Compares the values in A against the values in B, using SC to
272    obtain the number and width of each value.  Returns -1, 0, or
273    1 if A's values are lexicographically less than, equal to, or
274    greater than B's values, respectively. */
275 int
276 subcase_compare_3way_xx (const struct subcase *sc,
277                          const union value a[], const union value b[])
278 {
279   size_t i;
280
281   for (i = 0; i < sc->n_fields; i++)
282     {
283       const struct subcase_field *field = &sc->fields[i];
284       int cmp = value_compare_3way (a++, b++, field->width);
285       if (cmp != 0)
286         return field->direction == SC_ASCEND ? cmp : -cmp;
287     }
288   return 0;
289 }
290
291 /* Compares the fields in A specified in A_SC against the fields
292    in B specified in B_SC.  Returns true if the fields' values
293    are equal, false otherwise.
294
295    A_SC and B_SC must be conformable (as tested by
296    subcase_conformable()). */
297 bool
298 subcase_equal (const struct subcase *a_sc, const struct ccase *a,
299                const struct subcase *b_sc, const struct ccase *b)
300 {
301   return subcase_compare_3way (a_sc, a, b_sc, b) == 0;
302 }
303
304 /* Compares the values in A against the values in B specified by
305    SC's fields.  Returns true if A's values are equal to B's
306    values, otherwise false. */
307 bool
308 subcase_equal_xc (const struct subcase *sc,
309                   const union value a[], const struct ccase *b)
310 {
311   return subcase_compare_3way_xc (sc, a, b) == 0;
312 }
313
314 /* Compares the values in A specified by SC's fields against the
315    values in B.  Returns true if A's values are equal to B's
316    values, otherwise false. */
317 bool
318 subcase_equal_cx (const struct subcase *sc,
319                   const struct ccase *a, const union value b[])
320 {
321   return subcase_compare_3way_cx (sc, a, b) == 0;
322 }
323
324 /* Compares the values in A against the values in B, using SC to
325    obtain the number and width of each value.  Returns true if
326    A's values are equal to B's values, otherwise false. */
327 bool
328 subcase_equal_xx (const struct subcase *sc,
329                   const union value a[], const union value b[])
330 {
331   return subcase_compare_3way_xx (sc, a, b) == 0;
332 }
333
334 /* Discards SC's case prototype.  (It will be recreated if needed
335    again later.) */
336 static void
337 invalidate_proto (struct subcase *sc)
338 {
339   caseproto_unref (sc->proto);
340   sc->proto = NULL;
341 }