gui: Fix behavior of print preview in psppire-output-window.
[pspp] / src / data / subcase.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008, 2009, 2011 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
19 #include "data/subcase.h"
20
21 #include <stdlib.h>
22
23 #include "data/case.h"
24 #include "data/variable.h"
25 #include "libpspp/assertion.h"
26
27 #include "gl/xalloc.h"
28
29 static void invalidate_proto (struct subcase *sc);
30
31 /* Initializes SC as a subcase that contains no fields. */
32 void
33 subcase_init_empty (struct subcase *sc)
34 {
35   sc->fields = NULL;
36   sc->n_fields = 0;
37   sc->proto = NULL;
38 }
39
40 /* Initializes SC as a subcase with fields extracted from the
41    N_VARS variables in VARS, with ascending sort order. */
42 void
43 subcase_init_vars (struct subcase *sc,
44                    const struct variable *const *vars, size_t n_vars)
45 {
46   size_t i;
47
48   sc->fields = xnmalloc (n_vars, sizeof *sc->fields);
49   sc->n_fields = n_vars;
50   sc->proto = NULL;
51   for (i = 0; i < n_vars; i++)
52     {
53       struct subcase_field *field = &sc->fields[i];
54       field->case_index = var_get_case_index (vars[i]);
55       field->width = var_get_width (vars[i]);
56       field->direction = SC_ASCEND;
57     }
58 }
59
60 /* Initializes SC as a subcase with a single field extracted
61    from VAR, with the sort order specified by DIRECTION.  */
62 void
63 subcase_init_var (struct subcase *sc, const struct variable *var,
64                   enum subcase_direction direction)
65 {
66   subcase_init_empty (sc);
67   subcase_add_var (sc, var, direction);
68 }
69
70
71 void
72 subcase_init (struct subcase *sc, int index, int width,
73                   enum subcase_direction direction)
74 {
75   subcase_init_empty (sc);
76   subcase_add (sc, index, width, direction);
77 }
78
79
80 /* Removes all the fields from SC. */
81 void
82 subcase_clear (struct subcase *sc)
83 {
84   sc->n_fields = 0;
85   invalidate_proto (sc);
86 }
87
88 /* Initializes SC with the same fields as ORIG. */
89 void
90 subcase_clone (struct subcase *sc, const struct subcase *orig)
91 {
92   sc->fields = xmemdup (orig->fields, orig->n_fields * sizeof *orig->fields);
93   sc->n_fields = orig->n_fields;
94   sc->proto = orig->proto ? caseproto_ref (orig->proto) : NULL;
95 }
96
97 /* Frees the memory owned by SC (but not SC itself). */
98 void
99 subcase_destroy (struct subcase *sc)
100 {
101   free (sc->fields);
102   caseproto_unref (sc->proto);
103 }
104
105 /* Returns true if VAR already has a field in SC,
106    false otherwise. */
107 bool
108 subcase_contains_var (const struct subcase *sc, const struct variable *var)
109 {
110   return subcase_contains (sc, var_get_case_index (var));
111 }
112
113 /* Returns true if CASE_INDEX already has a field in SC,
114    false otherwise. */
115 bool
116 subcase_contains (const struct subcase *sc, int case_index)
117 {
118   size_t i;
119
120   for (i = 0; i < sc->n_fields; i++)
121     if (sc->fields[i].case_index == case_index)
122       return true;
123
124   return false;
125 }
126
127 /* Add a field for VAR to SC, with DIRECTION as the sort order.
128    Returns true if successful, false if VAR already has a field
129    in SC. */
130 bool
131 subcase_add_var (struct subcase *sc, const struct variable *var,
132                  enum subcase_direction direction)
133 {
134   if (!subcase_contains_var (sc, var))
135     {
136       subcase_add_var_always (sc, var, direction);
137       return true;
138     }
139   else
140     return false;
141 }
142
143 /* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
144    Returns true if successful, false if CASE_INDEX already has a field
145    in SC. */
146 bool
147 subcase_add (struct subcase *sc, int case_index, int width,
148              enum subcase_direction direction)
149 {
150   if (!subcase_contains (sc, case_index))
151     {
152       subcase_add_always (sc, case_index, width, direction);
153       return true;
154     }
155   else
156     return false;
157 }
158
159 /* Add a field for VAR to SC, with DIRECTION as the sort order,
160    regardless of whether VAR already has a field in SC. */
161 void
162 subcase_add_var_always (struct subcase *sc, const struct variable *var,
163                         enum subcase_direction direction)
164 {
165   return subcase_add_always (sc, var_get_case_index (var),
166                              var_get_width (var), direction);
167 }
168
169 /* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the
170    sort order, regardless of whether CASE_INDEX already has a
171    field in SC. */
172 void
173 subcase_add_always (struct subcase *sc, int case_index, int width,
174                     enum subcase_direction direction)
175 {
176   struct subcase_field *field;
177
178   sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
179   field = &sc->fields[sc->n_fields++];
180   field->case_index = case_index;
181   field->width = width;
182   field->direction = direction;
183   invalidate_proto (sc);
184 }
185
186 /* Adds a field to SC for each column in PROTO, so that SC
187    contains all of the columns in PROTO in the same order as a
188    case conforming to PROTO.  The fields are added with
189    ascending direction. */
190 void
191 subcase_add_proto_always (struct subcase *sc, const struct caseproto *proto)
192 {
193   size_t n = caseproto_get_n_widths (proto);
194   size_t i;
195
196   sc->fields = xnrealloc (sc->fields, sc->n_fields + n, sizeof *sc->fields);
197   for (i = 0; i < n; i++)
198     {
199       struct subcase_field *field = &sc->fields[sc->n_fields++];
200       field->case_index = i;
201       field->width = caseproto_get_width (proto, i);
202       field->direction = SC_ASCEND;
203     }
204   invalidate_proto (sc);
205 }
206
207 /* Obtains a caseproto for a case described by SC.  The caller
208    must not modify or unref the returned case prototype. */
209 const struct caseproto *
210 subcase_get_proto (const struct subcase *sc_)
211 {
212   struct subcase *sc = CONST_CAST (struct subcase *, sc_);
213
214   if (sc->proto == NULL)
215     {
216       size_t i;
217
218       sc->proto = caseproto_create ();
219       for (i = 0; i < sc->n_fields; i++)
220         sc->proto = caseproto_add_width (sc->proto, sc->fields[i].width);
221     }
222   return sc->proto;
223 }
224
225 /* Returns true if and only if A and B are conformable, which
226    means that they have the same number of fields and that each
227    corresponding field in A and B have the same width. */
228 bool
229 subcase_conformable (const struct subcase *a, const struct subcase *b)
230 {
231   size_t i;
232
233   if (a == b)
234     return true;
235   if (a->n_fields != b->n_fields)
236     return false;
237   for (i = 0; i < a->n_fields; i++)
238     if (a->fields[i].width != b->fields[i].width)
239       return false;
240   return true;
241 }
242
243 /* Copies the fields represented by SC from C into VALUES.
244    VALUES must have space for at least subcase_get_n_fields(SC)
245    array elements. */
246 void
247 subcase_extract (const struct subcase *sc, const struct ccase *c,
248                  union value values[])
249 {
250   size_t i;
251
252   for (i = 0; i < sc->n_fields; i++)
253     {
254       const struct subcase_field *field = &sc->fields[i];
255       union value *value = &values[i];
256       value_copy (value, case_data_idx (c, field->case_index), field->width);
257     }
258 }
259
260 /* Copies the data in VALUES into the fields in C represented by
261    SC.  VALUES must have at least subcase_get_n_fields(SC) array
262    elements, and C must be large enough to contain all the fields
263    in SC. */
264 void
265 subcase_inject (const struct subcase *sc,
266                 const union value values[], struct ccase *c)
267 {
268   size_t i;
269
270   for (i = 0; i < sc->n_fields; i++)
271     {
272       const struct subcase_field *field = &sc->fields[i];
273       const union value *value = &values[i];
274       value_copy (case_data_rw_idx (c, field->case_index), value,
275                   field->width);
276     }
277 }
278
279 /* Copies the fields in SRC represented by SRC_SC into the
280    corresponding fields in DST respresented by DST_SC.  SRC_SC
281    and DST_SC must be conformable (as tested by
282    subcase_conformable()).
283
284    DST must not be shared. */
285 void
286 subcase_copy (const struct subcase *src_sc, const struct ccase *src,
287               const struct subcase *dst_sc, struct ccase *dst)
288 {
289   size_t i;
290
291   expensive_assert (subcase_conformable (src_sc, dst_sc));
292   for (i = 0; i < src_sc->n_fields; i++)
293     {
294       const struct subcase_field *src_field = &src_sc->fields[i];
295       const struct subcase_field *dst_field = &dst_sc->fields[i];
296       value_copy (case_data_rw_idx (dst, dst_field->case_index),
297                   case_data_idx (src, src_field->case_index),
298                   src_field->width);
299     }
300 }
301
302 /* Compares the fields in A specified in A_SC against the fields
303    in B specified in B_SC.  Returns -1, 0, or 1 if A's fields are
304    lexicographically less than, equal to, or greater than B's
305    fields, respectively.
306
307    A_SC and B_SC must be conformable (as tested by
308    subcase_conformable()). */
309 int
310 subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
311                       const struct subcase *b_sc, const struct ccase *b)
312 {
313   size_t i;
314
315   expensive_assert (subcase_conformable (a_sc, b_sc));
316   for (i = 0; i < a_sc->n_fields; i++)
317     {
318       const struct subcase_field *a_field = &a_sc->fields[i];
319       const struct subcase_field *b_field = &b_sc->fields[i];
320       int cmp = value_compare_3way (case_data_idx (a, a_field->case_index),
321                                     case_data_idx (b, b_field->case_index),
322                                     a_field->width);
323       if (cmp != 0)
324         return a_field->direction == SC_ASCEND ? cmp : -cmp;
325     }
326   return 0;
327 }
328
329 /* Compares the values in A against the values in B specified by
330    SC's fields.  Returns -1, 0, or 1 if A's values are
331    lexicographically less than, equal to, or greater than B's
332    values, respectively. */
333 int
334 subcase_compare_3way_xc (const struct subcase *sc,
335                          const union value a[], const struct ccase *b)
336 {
337   size_t i;
338
339   for (i = 0; i < sc->n_fields; i++)
340     {
341       const struct subcase_field *field = &sc->fields[i];
342       int cmp = value_compare_3way (&a[i],
343                                     case_data_idx (b, field->case_index),
344                                     field->width);
345       if (cmp != 0)
346         return field->direction == SC_ASCEND ? cmp : -cmp;
347     }
348   return 0;
349 }
350
351 /* Compares the values in A specified by SC's fields against the
352    values in B.  Returns -1, 0, or 1 if A's values are
353    lexicographically less than, equal to, or greater than B's
354    values, respectively. */
355 int
356 subcase_compare_3way_cx (const struct subcase *sc,
357                          const struct ccase *a, const union value b[])
358 {
359   return -subcase_compare_3way_xc (sc, b, a);
360 }
361
362 /* Compares the values in A against the values in B, using SC to
363    obtain the number and width of each value.  Returns -1, 0, or
364    1 if A's values are lexicographically less than, equal to, or
365    greater than B's values, respectively. */
366 int
367 subcase_compare_3way_xx (const struct subcase *sc,
368                          const union value a[], const union value b[])
369 {
370   size_t i;
371
372   for (i = 0; i < sc->n_fields; i++)
373     {
374       const struct subcase_field *field = &sc->fields[i];
375       int cmp = value_compare_3way (a++, b++, field->width);
376       if (cmp != 0)
377         return field->direction == SC_ASCEND ? cmp : -cmp;
378     }
379   return 0;
380 }
381
382 /* Compares the fields in A specified in A_SC against the fields
383    in B specified in B_SC.  Returns true if the fields' values
384    are equal, false otherwise.
385
386    A_SC and B_SC must be conformable (as tested by
387    subcase_conformable()). */
388 bool
389 subcase_equal (const struct subcase *a_sc, const struct ccase *a,
390                const struct subcase *b_sc, const struct ccase *b)
391 {
392   return subcase_compare_3way (a_sc, a, b_sc, b) == 0;
393 }
394
395 /* Compares the values in A against the values in B specified by
396    SC's fields.  Returns true if A's values are equal to B's
397    values, otherwise false. */
398 bool
399 subcase_equal_xc (const struct subcase *sc,
400                   const union value a[], const struct ccase *b)
401 {
402   return subcase_compare_3way_xc (sc, a, b) == 0;
403 }
404
405 /* Compares the values in A specified by SC's fields against the
406    values in B.  Returns true if A's values are equal to B's
407    values, otherwise false. */
408 bool
409 subcase_equal_cx (const struct subcase *sc,
410                   const struct ccase *a, const union value b[])
411 {
412   return subcase_compare_3way_cx (sc, a, b) == 0;
413 }
414
415 /* Compares the values in A against the values in B, using SC to
416    obtain the number and width of each value.  Returns true if
417    A's values are equal to B's values, otherwise false. */
418 bool
419 subcase_equal_xx (const struct subcase *sc,
420                   const union value a[], const union value b[])
421 {
422   return subcase_compare_3way_xx (sc, a, b) == 0;
423 }
424
425 /* Discards SC's case prototype.  (It will be recreated if needed
426    again later.) */
427 static void
428 invalidate_proto (struct subcase *sc)
429 {
430   caseproto_unref (sc->proto);
431   sc->proto = NULL;
432 }