1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009 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;
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.
59 (The caller may change the case that *DATA points to from one
62 All of the BY subcases provided to this function for a given
63 CM must be conformable (see subcase_conformable()). */
65 case_matcher_add_input (struct case_matcher *cm, const struct subcase *by,
66 struct ccase **data, bool *is_minimal)
68 struct case_matcher_input *input;
70 if (cm->n_inputs == 0)
71 cm->by_values = xmalloc (subcase_get_n_values (by)
72 * sizeof *cm->by_values);
74 assert (subcase_conformable (by, &cm->inputs[0].by_vars));
76 if (cm->n_inputs >= cm->allocated_inputs)
77 cm->inputs = x2nrealloc (cm->inputs, &cm->allocated_inputs,
79 input = &cm->inputs[cm->n_inputs++];
80 subcase_clone (&input->by_vars, by);
82 input->is_minimal = is_minimal;
85 /* Destroys case matcher CM. */
87 case_matcher_destroy (struct case_matcher *cm)
93 for (i = 0; i < cm->n_inputs; i++)
95 struct case_matcher_input *input = &cm->inputs[i];
96 subcase_destroy (&input->by_vars);
104 compare_BY_3way (struct case_matcher_input *a, struct case_matcher_input *b)
106 return subcase_compare_3way (&a->by_vars, *a->data, &b->by_vars, *b->data);
109 /* Compares the values of the BY variables in all of the nonnull
110 cases provided to case_matcher_add_input() for CM, sets
111 *IS_MINIMAL for each one to true if it has the minimum BY
112 values among those cases or to false if its BY values are
113 greater than the minimum. Also sets *IS_MINIMAL to false for
114 null cases. Sets *BY to the BY values extracted from the
115 minimum case. (The caller must not free *BY.)
117 Returns true if at least one of the cases is nonnull, false
118 if they are all null.*/
120 case_matcher_match (struct case_matcher *cm, union value **by)
122 struct case_matcher_input *file, *min;
125 for (file = cm->inputs; file < &cm->inputs[cm->n_inputs]; file++)
126 if (*file->data != NULL)
128 int cmp = min != NULL ? compare_BY_3way (min, file) : 1;
130 *file->is_minimal = false;
133 *file->is_minimal = true;
139 *file->is_minimal = false;
143 for (file = cm->inputs; file < min; file++)
144 *file->is_minimal = false;
145 subcase_extract (&min->by_vars, *min->data, cm->by_values);