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