Add casereader_create_append_numeric function.
[pspp-builds.git] / src / data / casereader-translator.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007 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.h>
20
21 #include <stdlib.h>
22
23 #include <data/casereader-provider.h>
24 #include <libpspp/taint.h>
25
26 #include "xalloc.h"
27
28 /* Casereader that applies a user-supplied function to translate
29    each case into another in an arbitrary fashion. */
30
31 /* A translating casereader. */
32 struct casereader_translator
33   {
34     struct casereader *subreader; /* Source of input cases. */
35
36     void (*translate) (struct ccase *input, struct ccase *output, void *aux);
37     bool (*destroy) (void *aux);
38     void *aux;
39   };
40
41 static const struct casereader_class casereader_translator_class;
42
43 /* Creates and returns a new casereader whose cases are produced
44    by reading from SUBREADER and passing through TRANSLATE, which
45    must create case OUTPUT, with OUTPUT_VALUE_CNT values, and
46    populate it based on INPUT and auxiliary data AUX.  TRANSLATE
47    must also destroy INPUT.
48
49    When the translating casereader is destroyed, DESTROY will be
50    called to allow any state maintained by TRANSLATE to be freed.
51
52    After this function is called, SUBREADER must not ever again
53    be referenced directly.  It will be destroyed automatically
54    when the translating casereader is destroyed. */
55 struct casereader *
56 casereader_create_translator (struct casereader *subreader,
57                               size_t output_value_cnt,
58                               void (*translate) (struct ccase *input,
59                                                  struct ccase *output,
60                                                  void *aux),
61                               bool (*destroy) (void *aux),
62                               void *aux)
63 {
64   struct casereader_translator *ct = xmalloc (sizeof *ct);
65   struct casereader *reader;
66   ct->subreader = casereader_rename (subreader);
67   ct->translate = translate;
68   ct->destroy = destroy;
69   ct->aux = aux;
70   reader = casereader_create_sequential (
71     NULL, output_value_cnt, casereader_get_case_cnt (ct->subreader),
72     &casereader_translator_class, ct);
73   taint_propagate (casereader_get_taint (ct->subreader),
74                    casereader_get_taint (reader));
75   return reader;
76 }
77
78 /* Internal read function for translating casereader. */
79 static bool
80 casereader_translator_read (struct casereader *reader UNUSED,
81                             void *ct_, struct ccase *c)
82 {
83   struct casereader_translator *ct = ct_;
84   struct ccase tmp;
85
86   if (casereader_read (ct->subreader, &tmp))
87     {
88       ct->translate (&tmp, c, ct->aux);
89       return true;
90     }
91   else
92     return false;
93 }
94
95 /* Internal destroy function for translating casereader. */
96 static void
97 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
98 {
99   struct casereader_translator *ct = ct_;
100   casereader_destroy (ct->subreader);
101   ct->destroy (ct->aux);
102   free (ct);
103 }
104
105 /* Casereader class for translating casereader. */
106 static const struct casereader_class casereader_translator_class =
107   {
108     casereader_translator_read,
109     casereader_translator_destroy,
110     NULL,
111     NULL,
112   };
113
114 \f
115
116 struct casereader_append_numeric
117 {
118   int value_ofs;
119   casenumber n;
120   new_value_func *func;
121   void *aux;
122   void (*destroy) (void *aux);
123 };
124
125 static bool can_destroy (void *can_);
126
127 static void can_translate (struct ccase *input, struct ccase *output,
128                            void *can_);
129
130 /* Creates and returns a new casereader whose cases are produced
131    by reading from SUBREADER and appending an additional value,
132    generated by FUNC.  AUX is an optional parameter which
133    gets passed to FUNC. FUNC will also receive N as it, which is
134    the ordinal number of the case in the reader.  DESTROY is an 
135    optional parameter used to destroy AUX.
136
137    After this function is called, SUBREADER must not ever again
138    be referenced directly.  It will be destroyed automatically
139    when the translating casereader is destroyed. */
140 struct casereader *
141 casereader_create_append_numeric (struct casereader *subreader,
142                                   new_value_func func, void *aux,
143                                   void (*destroy) (void *aux))
144 {
145   struct casereader_append_numeric *can = xmalloc (sizeof *can);
146   can->value_ofs = casereader_get_value_cnt (subreader);
147   can->n = 0;
148   can->aux = aux;
149   can->func = func;
150   can->destroy = destroy;
151   return casereader_create_translator (subreader, can->value_ofs + 1,
152                                        can_translate, can_destroy, can);
153 }
154
155
156 static void
157 can_translate (struct ccase *input, struct ccase *output, void *can_)
158 {
159   struct casereader_append_numeric *can = can_;
160   double new_value = can->func (input, can->n++, can->aux);
161   case_nullify (output);
162   case_move (output, input);
163   case_resize (output, can->value_ofs + 1);
164   case_data_rw_idx (output, can->value_ofs)->f = new_value;
165 }
166
167 static bool
168 can_destroy (void *can_)
169 {
170   struct casereader_append_numeric *can = can_;
171   if (can->destroy)
172     can->destroy (can->aux);
173   free (can);
174   return true;
175 }
176
177 \f
178
179 struct arithmetic_sequence
180 {
181   double first;
182   double increment;
183 };
184
185 static double
186 next_arithmetic (const struct ccase *c UNUSED,
187                  casenumber n,
188                  void *aux)
189 {
190   struct arithmetic_sequence *as = aux;
191   return n * as->increment + as->first;
192 }
193
194 /* Creates and returns a new casereader whose cases are produced
195    by reading from SUBREADER and appending an additional value,
196    which takes the value FIRST in the first case, FIRST +
197    INCREMENT in the second case, FIRST + INCREMENT * 2 in the
198    third case, and so on.
199
200    After this function is called, SUBREADER must not ever again
201    be referenced directly.  It will be destroyed automatically
202    when the translating casereader is destroyed. */
203 struct casereader *
204 casereader_create_arithmetic_sequence (struct casereader *subreader,
205                                        double first, double increment)
206 {
207   struct arithmetic_sequence *as = xzalloc (sizeof *as);
208   as->first = first;
209   as->increment = increment;
210   return casereader_create_append_numeric (subreader, next_arithmetic,
211                                            as, free);
212 }
213