Add new functions to define subcase orderings.
[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
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
103 /* Add a field for VAR to SC, with DIRECTION as the sort order.
104    Returns true if successful, false if VAR already has a field
105    in SC. */
106 bool
107 subcase_add_var (struct subcase *sc, const struct variable *var,
108                  enum subcase_direction direction)
109 {
110   return subcase_add (sc, var_get_case_index (var),
111                       var_get_width (var), direction);
112 }
113
114 /* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
115    Returns true if successful, false if CASE_INDEX already has a field
116    in SC. */
117 bool
118 subcase_add (struct subcase *sc, int case_index, int width,
119                  enum subcase_direction direction)
120 {
121   struct subcase_field *field;
122   size_t i;
123
124   for (i = 0; i < sc->n_fields; i++)
125     if (sc->fields[i].case_index == case_index)
126       return false;
127
128   sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
129   field = &sc->fields[sc->n_fields++];
130   field->case_index = case_index;
131   field->width = width;
132   field->direction = direction;
133   invalidate_proto (sc);
134   return true;
135 }
136
137 /* Obtains a caseproto for a case described by SC.  The caller
138    must not modify or unref the returned case prototype. */
139 const struct caseproto *
140 subcase_get_proto (const struct subcase *sc_)
141 {
142   struct subcase *sc = (struct subcase *) sc_;
143
144   if (sc->proto == NULL)
145     {
146       size_t i;
147
148       sc->proto = caseproto_create ();
149       for (i = 0; i < sc->n_fields; i++)
150         sc->proto = caseproto_add_width (sc->proto, sc->fields[i].width);
151     }
152   return sc->proto;
153 }
154
155 /* Returns true if and only if A and B are conformable, which
156    means that they have the same number of fields and that each
157    corresponding field in A and B have the same width. */
158 bool
159 subcase_conformable (const struct subcase *a, const struct subcase *b)
160 {
161   size_t i;
162
163   if (a == b)
164     return true;
165   if (a->n_fields != b->n_fields)
166     return false;
167   for (i = 0; i < a->n_fields; i++)
168     if (a->fields[i].width != b->fields[i].width)
169       return false;
170   return true;
171 }
172
173 /* Copies the fields represented by SC from C into VALUES.
174    VALUES must have space for at least subcase_get_n_fields(SC)
175    array elements. */
176 void
177 subcase_extract (const struct subcase *sc, const struct ccase *c,
178                  union value values[])
179 {
180   size_t i;
181
182   for (i = 0; i < sc->n_fields; i++)
183     {
184       const struct subcase_field *field = &sc->fields[i];
185       union value *value = &values[i];
186       value_copy (value, case_data_idx (c, field->case_index), field->width);
187     }
188 }
189
190 /* Copies the data in VALUES into the fields in C represented by
191    SC.  VALUES must have at least subcase_get_n_fields(SC) array
192    elements, and C must be large enough to contain all the fields
193    in SC. */
194 void
195 subcase_inject (const struct subcase *sc,
196                 const union value values[], struct ccase *c)
197 {
198   size_t i;
199
200   for (i = 0; i < sc->n_fields; i++)
201     {
202       const struct subcase_field *field = &sc->fields[i];
203       const union value *value = &values[i];
204       value_copy (case_data_rw_idx (c, field->case_index), value,
205                   field->width);
206     }
207 }
208
209 /* Copies the fields in SRC represented by SRC_SC into the
210    corresponding fields in DST respresented by DST_SC.  SRC_SC
211    and DST_SC must be conformable (as tested by
212    subcase_conformable()).
213
214    DST must not be shared. */
215 void
216 subcase_copy (const struct subcase *src_sc, const struct ccase *src,
217               const struct subcase *dst_sc, struct ccase *dst)
218 {
219   size_t i;
220
221   expensive_assert (subcase_conformable (src_sc, dst_sc));
222   for (i = 0; i < src_sc->n_fields; i++)
223     {
224       const struct subcase_field *src_field = &src_sc->fields[i];
225       const struct subcase_field *dst_field = &dst_sc->fields[i];
226       value_copy (case_data_rw_idx (dst, dst_field->case_index),
227                   case_data_idx (src, src_field->case_index),
228                   src_field->width);
229     }
230 }
231
232 /* Compares the fields in A specified in A_SC against the fields
233    in B specified in B_SC.  Returns -1, 0, or 1 if A's fields are
234    lexicographically less than, equal to, or greater than B's
235    fields, respectively.
236
237    A_SC and B_SC must be conformable (as tested by
238    subcase_conformable()). */
239 int
240 subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
241                       const struct subcase *b_sc, const struct ccase *b)
242 {
243   size_t i;
244
245   expensive_assert (subcase_conformable (a_sc, b_sc));
246   for (i = 0; i < a_sc->n_fields; i++)
247     {
248       const struct subcase_field *a_field = &a_sc->fields[i];
249       const struct subcase_field *b_field = &b_sc->fields[i];
250       int cmp = value_compare_3way (case_data_idx (a, a_field->case_index),
251                                     case_data_idx (b, b_field->case_index),
252                                     a_field->width);
253       if (cmp != 0)
254         return a_field->direction == SC_ASCEND ? cmp : -cmp;
255     }
256   return 0;
257 }
258
259 /* Compares the values in A against the values in B specified by
260    SC's fields.  Returns -1, 0, or 1 if A's values are
261    lexicographically less than, equal to, or greater than B's
262    values, respectively. */
263 int
264 subcase_compare_3way_xc (const struct subcase *sc,
265                          const union value a[], const struct ccase *b)
266 {
267   size_t i;
268
269   for (i = 0; i < sc->n_fields; i++)
270     {
271       const struct subcase_field *field = &sc->fields[i];
272       int cmp = value_compare_3way (&a[i],
273                                     case_data_idx (b, field->case_index),
274                                     field->width);
275       if (cmp != 0)
276         return field->direction == SC_ASCEND ? cmp : -cmp;
277     }
278   return 0;
279 }
280
281 /* Compares the values in A specified by SC's fields against the
282    values in B.  Returns -1, 0, or 1 if A's values are
283    lexicographically less than, equal to, or greater than B's
284    values, respectively. */
285 int
286 subcase_compare_3way_cx (const struct subcase *sc,
287                          const struct ccase *a, const union value b[])
288 {
289   return -subcase_compare_3way_xc (sc, b, a);
290 }
291
292 /* Compares the values in A against the values in B, using SC to
293    obtain the number and width of each value.  Returns -1, 0, or
294    1 if A's values are lexicographically less than, equal to, or
295    greater than B's values, respectively. */
296 int
297 subcase_compare_3way_xx (const struct subcase *sc,
298                          const union value a[], const union value b[])
299 {
300   size_t i;
301
302   for (i = 0; i < sc->n_fields; i++)
303     {
304       const struct subcase_field *field = &sc->fields[i];
305       int cmp = value_compare_3way (a++, b++, field->width);
306       if (cmp != 0)
307         return field->direction == SC_ASCEND ? cmp : -cmp;
308     }
309   return 0;
310 }
311
312 /* Compares the fields in A specified in A_SC against the fields
313    in B specified in B_SC.  Returns true if the fields' values
314    are equal, false otherwise.
315
316    A_SC and B_SC must be conformable (as tested by
317    subcase_conformable()). */
318 bool
319 subcase_equal (const struct subcase *a_sc, const struct ccase *a,
320                const struct subcase *b_sc, const struct ccase *b)
321 {
322   return subcase_compare_3way (a_sc, a, b_sc, b) == 0;
323 }
324
325 /* Compares the values in A against the values in B specified by
326    SC's fields.  Returns true if A's values are equal to B's
327    values, otherwise false. */
328 bool
329 subcase_equal_xc (const struct subcase *sc,
330                   const union value a[], const struct ccase *b)
331 {
332   return subcase_compare_3way_xc (sc, a, b) == 0;
333 }
334
335 /* Compares the values in A specified by SC's fields against the
336    values in B.  Returns true if A's values are equal to B's
337    values, otherwise false. */
338 bool
339 subcase_equal_cx (const struct subcase *sc,
340                   const struct ccase *a, const union value b[])
341 {
342   return subcase_compare_3way_cx (sc, a, b) == 0;
343 }
344
345 /* Compares the values in A against the values in B, using SC to
346    obtain the number and width of each value.  Returns true if
347    A's values are equal to B's values, otherwise false. */
348 bool
349 subcase_equal_xx (const struct subcase *sc,
350                   const union value a[], const union value b[])
351 {
352   return subcase_compare_3way_xx (sc, a, b) == 0;
353 }
354
355 /* Discards SC's case prototype.  (It will be recreated if needed
356    again later.) */
357 static void
358 invalidate_proto (struct subcase *sc)
359 {
360   caseproto_unref (sc->proto);
361   sc->proto = NULL;
362 }