better tests
[pspp] / src / data / casereader-project.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 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/casereader-provider.h"
20 #include "data/subcase.h"
21
22 #include "gl/xalloc.h"
23
24 static bool
25 projection_is_no_op (const struct casereader *reader, const struct subcase *sc)
26 {
27   size_t n = subcase_get_n_fields (sc);
28   size_t i;
29
30   if (n != caseproto_get_n_widths (casereader_get_proto (reader)))
31     return false;
32
33   for (i = 0; i < n; i++)
34     if (subcase_get_case_index (sc, i) != i)
35       return false;
36
37   return true;
38 }
39
40 struct casereader_project
41   {
42     struct subcase old_sc;
43     struct subcase new_sc;
44   };
45
46 static struct ccase *
47 project_case (struct ccase *old, casenumber idx UNUSED, const void *project_)
48 {
49   const struct casereader_project *project = project_;
50   struct ccase *new = case_create (subcase_get_proto (&project->new_sc));
51   subcase_copy (&project->old_sc, old, &project->new_sc, new);
52   case_unref (old);
53   return new;
54 }
55
56 static bool
57 destroy_projection (void *project_)
58 {
59   struct casereader_project *project = project_;
60   subcase_destroy (&project->old_sc);
61   subcase_destroy (&project->new_sc);
62   free (project);
63   return true;
64 }
65
66 /* Returns a casereader in which each row is obtained by extracting the subcase
67    SC from the corresponding row of SUBREADER. */
68 struct casereader *
69 casereader_project (struct casereader *subreader, const struct subcase *sc)
70 {
71   if (projection_is_no_op (subreader, sc))
72     return casereader_rename (subreader);
73   else
74     {
75       struct casereader_project *project = xmalloc (sizeof *project);
76       const struct caseproto *proto;
77
78       subcase_clone (&project->old_sc, sc);
79       proto = subcase_get_proto (&project->old_sc);
80
81       subcase_init_empty (&project->new_sc);
82       subcase_add_proto_always (&project->new_sc, proto);
83
84       return casereader_translate_stateless (subreader, proto,
85                                              project_case, destroy_projection,
86                                              project);
87     }
88 }
89
90 /* Returns a casereader in which each row is obtained by extracting the value
91    with index COLUMN from the corresponding row of SUBREADER. */
92 struct casereader *
93 casereader_project_1 (struct casereader *subreader, int column)
94 {
95   const struct caseproto *subproto = casereader_get_proto (subreader);
96   struct casereader *reader;
97   struct subcase sc;
98
99   subcase_init (&sc, column, caseproto_get_width (subproto, column),
100                 SC_ASCEND);
101   reader = casereader_project (subreader, &sc);
102   subcase_destroy (&sc);
103
104   return reader;
105 }
106