1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008 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/case-matcher.h>
23 #include <data/case.h>
24 #include <data/subcase.h>
25 #include <data/value.h>
26 #include <libpspp/assertion.h>
30 struct case_matcher_input
32 struct subcase by_vars;
33 const struct ccase *data;
39 struct case_matcher_input *inputs;
40 size_t n_inputs, allocated_inputs;
41 union value *by_values;
44 /* Creates and returns a new case matcher. */
46 case_matcher_create (void)
48 struct case_matcher *cm = xmalloc (sizeof *cm);
51 cm->allocated_inputs = 0;
56 /* Adds a new input file to case matcher CM.
57 case_matcher_match() will compare the variables specified in
58 BY in case DATA and set *IS_MINIMAL appropriately.
60 All of the BY subcases provided to this function for a given
61 CM must be conformable (see subcase_conformable()). */
63 case_matcher_add_input (struct case_matcher *cm, const struct subcase *by,
64 const struct ccase *data, bool *is_minimal)
66 struct case_matcher_input *input;
68 if (cm->n_inputs == 0)
69 cm->by_values = xmalloc (subcase_get_n_values (by)
70 * sizeof *cm->by_values);
72 assert (subcase_conformable (by, &cm->inputs[0].by_vars));
74 if (cm->n_inputs >= cm->allocated_inputs)
75 cm->inputs = x2nrealloc (cm->inputs, &cm->allocated_inputs,
77 input = &cm->inputs[cm->n_inputs++];
78 subcase_clone (&input->by_vars, by);
80 input->is_minimal = is_minimal;
83 /* Destroys case matcher CM. */
85 case_matcher_destroy (struct case_matcher *cm)
91 for (i = 0; i < cm->n_inputs; i++)
93 struct case_matcher_input *input = &cm->inputs[i];
94 subcase_destroy (&input->by_vars);
102 compare_BY_3way (struct case_matcher_input *a, struct case_matcher_input *b)
104 return subcase_compare_3way (&a->by_vars, a->data, &b->by_vars, b->data);
107 /* Compares the values of the BY variables in all of the nonnull
108 cases provided to case_matcher_add_input() for CM, sets
109 *IS_MINIMAL for each one to true if it has the minimum BY
110 values among those cases or to false if its BY values are
111 greater than the minimum. Also sets *IS_MINIMAL to false for
112 null cases. Sets *BY to the BY values extracted from the
113 minimum case. (The caller must not free *BY.)
115 Returns true if at least one of the cases is nonnull, false
116 if they are all null.*/
118 case_matcher_match (struct case_matcher *cm, union value **by)
120 struct case_matcher_input *file, *min;
123 for (file = cm->inputs; file < &cm->inputs[cm->n_inputs]; file++)
124 if (!case_is_null (file->data))
126 int cmp = min != NULL ? compare_BY_3way (min, file) : 1;
128 *file->is_minimal = false;
131 *file->is_minimal = true;
137 *file->is_minimal = false;
141 for (file = cm->inputs; file < min; file++)
142 *file->is_minimal = false;
143 subcase_extract (&min->by_vars, min->data, cm->by_values);