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