subcase
[pspp] / src / data / subcase.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008, 2009, 2010 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
68 void
69 subcase_init (struct subcase *sc, int index, int width,
70                   enum subcase_direction direction)
71 {
72   subcase_init_empty (sc);
73   subcase_add (sc, index, width, direction);
74 }
75
76
77 /* Removes all the fields from SC. */
78 void
79 subcase_clear (struct subcase *sc)
80 {
81   sc->n_fields = 0;
82   invalidate_proto (sc);
83 }
84
85 /* Initializes SC with the same fields as ORIG. */
86 void
87 subcase_clone (struct subcase *sc, const struct subcase *orig)
88 {
89   sc->fields = xmemdup (orig->fields, orig->n_fields * sizeof *orig->fields);
90   sc->n_fields = orig->n_fields;
91   sc->proto = orig->proto ? caseproto_ref (orig->proto) : NULL;
92 }
93
94 /* Frees the memory owned by SC (but not SC itself). */
95 void
96 subcase_destroy (struct subcase *sc)
97 {
98   free (sc->fields);
99   caseproto_unref (sc->proto);
100 }
101
102 /* Returns true if VAR already has a field in SC,
103    false otherwise. */
104 bool
105 subcase_contains_var (const struct subcase *sc, const struct variable *var)
106 {
107   return subcase_contains (sc, var_get_case_index (var));
108 }
109
110 /* Returns true if CASE_INDEX already has a field in SC,
111    false otherwise. */
112 bool
113 subcase_contains (const struct subcase *sc, int case_index)
114 {
115   size_t i;
116
117   for (i = 0; i < sc->n_fields; i++)
118     if (sc->fields[i].case_index == case_index)
119       return true;
120
121   return false;
122 }
123
124 /* Add a field for VAR to SC, with DIRECTION as the sort order.
125    Returns true if successful, false if VAR already has a field
126    in SC. */
127 bool
128 subcase_add_var (struct subcase *sc, const struct variable *var,
129                  enum subcase_direction direction)
130 {
131   if (!subcase_contains_var (sc, var))
132     {
133       subcase_add_var_always (sc, var, direction);
134       return true;
135     }
136   else
137     return false;
138 }
139
140 /* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
141    Returns true if successful, false if CASE_INDEX already has a field
142    in SC. */
143 bool
144 subcase_add (struct subcase *sc, int case_index, int width,
145              enum subcase_direction direction)
146 {
147   if (!subcase_contains (sc, case_index))
148     {
149       subcase_add_always (sc, case_index, width, direction);
150       return true;
151     }
152   else
153     return false;
154 }
155
156 /* Add a field for VAR to SC, with DIRECTION as the sort order,
157    regardless of whether VAR already has a field in SC. */
158 void
159 subcase_add_var_always (struct subcase *sc, const struct variable *var,
160                         enum subcase_direction direction)
161 {
162   return subcase_add_always (sc, var_get_case_index (var),
163                              var_get_width (var), direction);
164 }
165
166 void
167 subcase_add_vars_always (struct subcase *sc,
168                          const struct variable *const *vars, size_t n_vars,
169                          enum subcase_direction direction)
170 {
171   size_t i;
172
173   for (i = 0; i < n_vars; i++)
174     subcase_add_var_always (sc, vars[i], direction);
175 }
176
177 /* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the
178    sort order, regardless of whether CASE_INDEX already has a
179    field in SC. */
180 void
181 subcase_add_always (struct subcase *sc, int case_index, int width,
182                     enum subcase_direction direction)
183 {
184   struct subcase_field *field;
185
186   sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
187   field = &sc->fields[sc->n_fields++];
188   field->case_index = case_index;
189   field->width = width;
190   field->direction = direction;
191   invalidate_proto (sc);
192 }
193
194 /* Adds a field to SC for each column in PROTO, so that SC
195    contains all of the columns in PROTO in the same order as a
196    case conforming to PROTO.  The fields are added with
197    ascending direction. */
198 void
199 subcase_add_proto_always (struct subcase *sc, const struct caseproto *proto)
200 {
201   size_t n = caseproto_get_n_widths (proto);
202   size_t i;
203
204   sc->fields = xnrealloc (sc->fields, sc->n_fields + n, sizeof *sc->fields);
205   for (i = 0; i < n; i++)
206     {
207       struct subcase_field *field = &sc->fields[sc->n_fields++];
208       field->case_index = i;
209       field->width = caseproto_get_width (proto, i);
210       field->direction = SC_ASCEND;
211     }
212   invalidate_proto (sc);
213 }
214
215 void
216 subcase_concat (struct subcase *sc, const struct subcase *other)
217 {
218   size_t i;
219
220   for (i = 0; i < other->n_fields; i++)
221     {
222       const struct subcase_field *f = &other->fields[i];
223       subcase_add (sc, f->case_index, f->width, f->direction);
224     }
225 }
226
227 void
228 subcase_concat_always (struct subcase *sc, const struct subcase *other)
229 {
230   size_t i;
231
232   for (i = 0; i < other->n_fields; i++)
233     {
234       const struct subcase_field *f = &other->fields[i];
235       subcase_add_always (sc, f->case_index, f->width, f->direction);
236     }
237 }
238
239 void
240 subcase_project (struct subcase *sc, size_t offset)
241 {
242   size_t i;
243
244   for (i = 0; i < sc->n_fields; i++)
245     sc->fields[i].case_index = i + offset;
246 }
247
248 /* Obtains a caseproto for a case described by SC.  The caller
249    must not modify or unref the returned case prototype. */
250 const struct caseproto *
251 subcase_get_proto (const struct subcase *sc_)
252 {
253   struct subcase *sc = CONST_CAST (struct subcase *, sc_);
254
255   if (sc->proto == NULL)
256     {
257       size_t i;
258
259       sc->proto = caseproto_create ();
260       for (i = 0; i < sc->n_fields; i++)
261         sc->proto = caseproto_add_width (sc->proto, sc->fields[i].width);
262     }
263   return sc->proto;
264 }
265
266 /* Returns true if and only if A and B are conformable, which
267    means that they have the same number of fields and that each
268    corresponding field in A and B have the same width. */
269 bool
270 subcase_conformable (const struct subcase *a, const struct subcase *b)
271 {
272   size_t i;
273
274   if (a == b)
275     return true;
276   if (a->n_fields != b->n_fields)
277     return false;
278   for (i = 0; i < a->n_fields; i++)
279     if (a->fields[i].width != b->fields[i].width)
280       return false;
281   return true;
282 }
283
284 /* Copies the fields represented by SC from C into VALUES.
285    VALUES must have space for at least subcase_get_n_fields(SC)
286    array elements. */
287 void
288 subcase_extract (const struct subcase *sc, const struct ccase *c,
289                  union value values[])
290 {
291   size_t i;
292
293   for (i = 0; i < sc->n_fields; i++)
294     {
295       const struct subcase_field *field = &sc->fields[i];
296       union value *value = &values[i];
297       value_copy (value, case_data_idx (c, field->case_index), field->width);
298     }
299 }
300
301 /* Copies the data in VALUES into the fields in C represented by
302    SC.  VALUES must have at least subcase_get_n_fields(SC) array
303    elements, and C must be large enough to contain all the fields
304    in SC. */
305 void
306 subcase_inject (const struct subcase *sc,
307                 const union value values[], struct ccase *c)
308 {
309   size_t i;
310
311   for (i = 0; i < sc->n_fields; i++)
312     {
313       const struct subcase_field *field = &sc->fields[i];
314       const union value *value = &values[i];
315       value_copy (case_data_rw_idx (c, field->case_index), value,
316                   field->width);
317     }
318 }
319
320 /* Copies the fields in SRC represented by SRC_SC into the
321    corresponding fields in DST respresented by DST_SC.  SRC_SC
322    and DST_SC must be conformable (as tested by
323    subcase_conformable()).
324
325    DST must not be shared. */
326 void
327 subcase_copy (const struct subcase *src_sc, const struct ccase *src,
328               const struct subcase *dst_sc, struct ccase *dst)
329 {
330   size_t i;
331
332   expensive_assert (subcase_conformable (src_sc, dst_sc));
333   for (i = 0; i < src_sc->n_fields; i++)
334     {
335       const struct subcase_field *src_field = &src_sc->fields[i];
336       const struct subcase_field *dst_field = &dst_sc->fields[i];
337       value_copy (case_data_rw_idx (dst, dst_field->case_index),
338                   case_data_idx (src, src_field->case_index),
339                   src_field->width);
340     }
341 }
342
343 /* Compares the fields in A specified in A_SC against the fields
344    in B specified in B_SC.  Returns -1, 0, or 1 if A's fields are
345    lexicographically less than, equal to, or greater than B's
346    fields, respectively.
347
348    A_SC and B_SC must be conformable (as tested by
349    subcase_conformable()). */
350 int
351 subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
352                       const struct subcase *b_sc, const struct ccase *b)
353 {
354   size_t i;
355
356   expensive_assert (subcase_conformable (a_sc, b_sc));
357   for (i = 0; i < a_sc->n_fields; i++)
358     {
359       const struct subcase_field *a_field = &a_sc->fields[i];
360       const struct subcase_field *b_field = &b_sc->fields[i];
361       int cmp = value_compare_3way (case_data_idx (a, a_field->case_index),
362                                     case_data_idx (b, b_field->case_index),
363                                     a_field->width);
364       if (cmp != 0)
365         return a_field->direction == SC_ASCEND ? cmp : -cmp;
366     }
367   return 0;
368 }
369
370 /* Compares the values in A against the values in B specified by
371    SC's fields.  Returns -1, 0, or 1 if A's values are
372    lexicographically less than, equal to, or greater than B's
373    values, respectively. */
374 int
375 subcase_compare_3way_xc (const struct subcase *sc,
376                          const union value a[], const struct ccase *b)
377 {
378   size_t i;
379
380   for (i = 0; i < sc->n_fields; i++)
381     {
382       const struct subcase_field *field = &sc->fields[i];
383       int cmp = value_compare_3way (&a[i],
384                                     case_data_idx (b, field->case_index),
385                                     field->width);
386       if (cmp != 0)
387         return field->direction == SC_ASCEND ? cmp : -cmp;
388     }
389   return 0;
390 }
391
392 /* Compares the values in A specified by SC's fields against the
393    values in B.  Returns -1, 0, or 1 if A's values are
394    lexicographically less than, equal to, or greater than B's
395    values, respectively. */
396 int
397 subcase_compare_3way_cx (const struct subcase *sc,
398                          const struct ccase *a, const union value b[])
399 {
400   return -subcase_compare_3way_xc (sc, b, a);
401 }
402
403 /* Compares the values in A against the values in B, using SC to
404    obtain the number and width of each value.  Returns -1, 0, or
405    1 if A's values are lexicographically less than, equal to, or
406    greater than B's values, respectively. */
407 int
408 subcase_compare_3way_xx (const struct subcase *sc,
409                          const union value a[], const union value b[])
410 {
411   size_t i;
412
413   for (i = 0; i < sc->n_fields; i++)
414     {
415       const struct subcase_field *field = &sc->fields[i];
416       int cmp = value_compare_3way (a++, b++, field->width);
417       if (cmp != 0)
418         return field->direction == SC_ASCEND ? cmp : -cmp;
419     }
420   return 0;
421 }
422
423 /* Compares the fields in A specified in A_SC against the fields
424    in B specified in B_SC.  Returns true if the fields' values
425    are equal, false otherwise.
426
427    A_SC and B_SC must be conformable (as tested by
428    subcase_conformable()). */
429 bool
430 subcase_equal (const struct subcase *a_sc, const struct ccase *a,
431                const struct subcase *b_sc, const struct ccase *b)
432 {
433   return subcase_compare_3way (a_sc, a, b_sc, b) == 0;
434 }
435
436 /* Compares the values in A against the values in B specified by
437    SC's fields.  Returns true if A's values are equal to B's
438    values, otherwise false. */
439 bool
440 subcase_equal_xc (const struct subcase *sc,
441                   const union value a[], const struct ccase *b)
442 {
443   return subcase_compare_3way_xc (sc, a, b) == 0;
444 }
445
446 /* Compares the values in A specified by SC's fields against the
447    values in B.  Returns true if A's values are equal to B's
448    values, otherwise false. */
449 bool
450 subcase_equal_cx (const struct subcase *sc,
451                   const struct ccase *a, const union value b[])
452 {
453   return subcase_compare_3way_cx (sc, a, b) == 0;
454 }
455
456 /* Compares the values in A against the values in B, using SC to
457    obtain the number and width of each value.  Returns true if
458    A's values are equal to B's values, otherwise false. */
459 bool
460 subcase_equal_xx (const struct subcase *sc,
461                   const union value a[], const union value b[])
462 {
463   return subcase_compare_3way_xx (sc, a, b) == 0;
464 }
465
466 /* Discards SC's case prototype.  (It will be recreated if needed
467    again later.) */
468 static void
469 invalidate_proto (struct subcase *sc)
470 {
471   caseproto_unref (sc->proto);
472   sc->proto = NULL;
473 }