1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009, 2011, 2013 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "data/subcase.h"
23 #include "data/case.h"
24 #include "data/variable.h"
25 #include "libpspp/assertion.h"
27 #include "gl/xalloc.h"
29 static void invalidate_proto (struct subcase *sc);
31 /* Initializes SC as a subcase that contains no fields. */
33 subcase_init_empty (struct subcase *sc)
40 /* Initializes SC as a subcase with fields extracted from the
41 N_VARS variables in VARS, with ascending sort order. */
43 subcase_init_vars (struct subcase *sc,
44 const struct variable *const *vars, size_t n_vars)
46 subcase_init_empty (sc);
47 subcase_add_vars_always (sc, vars, n_vars);
50 /* Initializes SC as a subcase with a single field extracted
51 from VAR, with the sort order specified by DIRECTION. */
53 subcase_init_var (struct subcase *sc, const struct variable *var,
54 enum subcase_direction direction)
56 subcase_init_empty (sc);
57 subcase_add_var (sc, var, direction);
62 subcase_init (struct subcase *sc, int index, int width,
63 enum subcase_direction direction)
65 subcase_init_empty (sc);
66 subcase_add (sc, index, width, direction);
70 /* Removes all the fields from SC. */
72 subcase_clear (struct subcase *sc)
75 invalidate_proto (sc);
78 /* Initializes SC with the same fields as ORIG. */
80 subcase_clone (struct subcase *sc, const struct subcase *orig)
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;
87 /* Frees the memory owned by SC (but not SC itself). */
89 subcase_destroy (struct subcase *sc)
92 caseproto_unref (sc->proto);
95 /* Returns true if VAR already has a field in SC,
98 subcase_contains_var (const struct subcase *sc, const struct variable *var)
100 return subcase_contains (sc, var_get_case_index (var));
103 /* Returns true if CASE_INDEX already has a field in SC,
106 subcase_contains (const struct subcase *sc, int case_index)
110 for (i = 0; i < sc->n_fields; i++)
111 if (sc->fields[i].case_index == case_index)
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
121 subcase_add_var (struct subcase *sc, const struct variable *var,
122 enum subcase_direction direction)
124 if (!subcase_contains_var (sc, var))
126 subcase_add_var_always (sc, var, direction);
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
137 subcase_add (struct subcase *sc, int case_index, int width,
138 enum subcase_direction direction)
140 if (!subcase_contains (sc, case_index))
142 subcase_add_always (sc, case_index, width, direction);
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. */
152 subcase_add_var_always (struct subcase *sc, const struct variable *var,
153 enum subcase_direction direction)
155 return subcase_add_always (sc, var_get_case_index (var),
156 var_get_width (var), direction);
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. */
163 subcase_add_vars_always (struct subcase *sc,
164 const struct variable *const *vars, size_t n_vars)
168 sc->fields = xnrealloc (sc->fields,
169 sc->n_fields + n_vars, sizeof *sc->fields);
170 for (i = 0; i < n_vars; i++)
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;
177 invalidate_proto (sc);
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
184 subcase_add_always (struct subcase *sc, int case_index, int width,
185 enum subcase_direction direction)
187 struct subcase_field *field;
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);
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. */
202 subcase_add_proto_always (struct subcase *sc, const struct caseproto *proto)
204 size_t n = caseproto_get_n_widths (proto);
207 sc->fields = xnrealloc (sc->fields, sc->n_fields + n, sizeof *sc->fields);
208 for (i = 0; i < n; i++)
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;
215 invalidate_proto (sc);
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_)
223 struct subcase *sc = CONST_CAST (struct subcase *, sc_);
225 if (sc->proto == NULL)
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);
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. */
240 subcase_conformable (const struct subcase *a, const struct subcase *b)
246 if (a->n_fields != b->n_fields)
248 for (i = 0; i < a->n_fields; i++)
249 if (a->fields[i].width != b->fields[i].width)
254 /* Copies the fields represented by SC from C into VALUES.
255 VALUES must have space for at least subcase_get_n_fields(SC)
258 subcase_extract (const struct subcase *sc, const struct ccase *c,
259 union value values[])
263 for (i = 0; i < sc->n_fields; i++)
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);
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
276 subcase_inject (const struct subcase *sc,
277 const union value values[], struct ccase *c)
281 for (i = 0; i < sc->n_fields; i++)
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,
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()).
295 DST must not be shared. */
297 subcase_copy (const struct subcase *src_sc, const struct ccase *src,
298 const struct subcase *dst_sc, struct ccase *dst)
302 expensive_assert (subcase_conformable (src_sc, dst_sc));
303 for (i = 0; i < src_sc->n_fields; i++)
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),
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.
318 A_SC and B_SC must be conformable (as tested by
319 subcase_conformable()). */
321 subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
322 const struct subcase *b_sc, const struct ccase *b)
326 expensive_assert (subcase_conformable (a_sc, b_sc));
327 for (i = 0; i < a_sc->n_fields; i++)
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),
335 return a_field->direction == SC_ASCEND ? cmp : -cmp;
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. */
345 subcase_compare_3way_xc (const struct subcase *sc,
346 const union value a[], const struct ccase *b)
350 for (i = 0; i < sc->n_fields; i++)
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),
357 return field->direction == SC_ASCEND ? cmp : -cmp;
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. */
367 subcase_compare_3way_cx (const struct subcase *sc,
368 const struct ccase *a, const union value b[])
370 return -subcase_compare_3way_xc (sc, b, a);
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. */
378 subcase_compare_3way_xx (const struct subcase *sc,
379 const union value a[], const union value b[])
383 for (i = 0; i < sc->n_fields; i++)
385 const struct subcase_field *field = &sc->fields[i];
386 int cmp = value_compare_3way (a++, b++, field->width);
388 return field->direction == SC_ASCEND ? cmp : -cmp;
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.
397 A_SC and B_SC must be conformable (as tested by
398 subcase_conformable()). */
400 subcase_equal (const struct subcase *a_sc, const struct ccase *a,
401 const struct subcase *b_sc, const struct ccase *b)
403 return subcase_compare_3way (a_sc, a, b_sc, b) == 0;
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. */
410 subcase_equal_xc (const struct subcase *sc,
411 const union value a[], const struct ccase *b)
413 return subcase_compare_3way_xc (sc, a, b) == 0;
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. */
420 subcase_equal_cx (const struct subcase *sc,
421 const struct ccase *a, const union value b[])
423 return subcase_compare_3way_cx (sc, a, b) == 0;
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. */
430 subcase_equal_xx (const struct subcase *sc,
431 const union value a[], const union value b[])
433 return subcase_compare_3way_xx (sc, a, b) == 0;
436 /* Discards SC's case prototype. (It will be recreated if needed
439 invalidate_proto (struct subcase *sc)
441 caseproto_unref (sc->proto);