Redesign the character re-encoding code.
[pspp] / src / data / casewriter.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2009 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/casewriter.h>
20 #include <data/casewriter-provider.h>
21
22 #include <assert.h>
23 #include <stdlib.h>
24
25 #include <data/casereader.h>
26 #include <data/casereader-provider.h>
27 #include <data/casewindow.h>
28 #include <data/settings.h>
29 #include <libpspp/compiler.h>
30 #include <libpspp/taint.h>
31
32 #include "xalloc.h"
33
34 /* A casewriter. */
35 struct casewriter
36   {
37     struct taint *taint;
38     size_t value_cnt;
39     casenumber case_cnt;
40     const struct casewriter_class *class;
41     void *aux;
42   };
43
44 static struct casewriter *create_casewriter_window (size_t value_cnt,
45                                                     casenumber max_in_core);
46
47 /* Writes case C to WRITER. */
48 void
49 casewriter_write (struct casewriter *writer, struct ccase *c)
50 {
51   assert (case_get_value_cnt (c) >= writer->value_cnt);
52   writer->class->write (writer, writer->aux, c);
53 }
54
55 /* Destroys WRITER.
56    Returns true if successful, false if an I/O error was
57    encountered on WRITER or on some object on which WRITER has a
58    dependency. */
59 bool
60 casewriter_destroy (struct casewriter *writer)
61 {
62   bool ok = true;
63   if (writer != NULL)
64     {
65       writer->class->destroy (writer, writer->aux);
66       ok = taint_destroy (writer->taint);
67       free (writer);
68     }
69   return ok;
70 }
71
72 /* Returns the number of `union value's in each case written to
73    WRITER. */
74 size_t
75 casewriter_get_value_cnt (const struct casewriter *writer)
76 {
77   return writer->value_cnt;
78 }
79
80 /* Destroys WRITER and in its place returns a casereader that can
81    be used to read back the data written to WRITER.  WRITER must
82    not be used again after calling this function, even as an
83    argument to casewriter_destroy.
84
85    Not all casewriters implement this function.  Behavior is
86    undefined if it is called on one that does not.
87
88    If an I/O error was encountered on WRITER or on some object on
89    which WRITER has a dependency, then the error will be
90    propagated to the new casereader. */
91 struct casereader *
92 casewriter_make_reader (struct casewriter *writer)
93 {
94   struct casereader *reader = writer->class->convert_to_reader (writer, writer->aux);
95   taint_propagate (writer->taint, casereader_get_taint (reader));
96   taint_destroy (writer->taint);
97   free (writer);
98   return reader;
99 }
100
101 /* Returns a copy of WRITER, which is itself destroyed.
102    Useful for taking over ownership of a casewriter, to enforce
103    preventing the original owner from accessing the casewriter
104    again. */
105 struct casewriter *
106 casewriter_rename (struct casewriter *writer)
107 {
108   struct casewriter *new = xmemdup (writer, sizeof *writer);
109   free (writer);
110   return new;
111 }
112
113 /* Returns true if an I/O error or another hard error has
114    occurred on WRITER, a clone of WRITER, or on some object on
115    which WRITER's data has a dependency, false otherwise. */
116 bool
117 casewriter_error (const struct casewriter *writer)
118 {
119   return taint_is_tainted (writer->taint);
120 }
121
122 /* Marks WRITER as having encountered an error.
123
124    Ordinarily, this function should be called by the
125    implementation of a casewriter, not by the casewriter's
126    client.  Instead, casewriter clients should usually ensure
127    that a casewriter's error state is correct by using
128    taint_propagate to propagate to the casewriter's taint
129    structure, which may be obtained via casewriter_get_taint. */
130 void
131 casewriter_force_error (struct casewriter *writer)
132 {
133   taint_set_taint (writer->taint);
134 }
135
136 /* Returns WRITER's associate taint object, for use with
137    taint_propagate and other taint functions. */
138 const struct taint *
139 casewriter_get_taint (const struct casewriter *writer)
140 {
141   return writer->taint;
142 }
143
144 /* Creates and returns a new casewriter with the given CLASS and
145    auxiliary data AUX.  The casewriter accepts cases with
146    VALUE_CNT `union value's. */
147 struct casewriter *
148 casewriter_create (size_t value_cnt,
149                    const struct casewriter_class *class, void *aux)
150 {
151   struct casewriter *writer = xmalloc (sizeof *writer);
152   writer->taint = taint_create ();
153   writer->value_cnt = value_cnt;
154   writer->case_cnt = 0;
155   writer->class = class;
156   writer->aux = aux;
157   return writer;
158 }
159
160 /* Returns a casewriter for cases with VALUE_CNT struct values
161    per case.  The cases written to the casewriter will be kept in
162    memory, unless the amount of memory used grows too large, in
163    which case they will be written to disk.
164
165    A casewriter created with this function may be passed to
166    casewriter_make_reader.
167
168    This is usually the right kind of casewriter to use. */
169 struct casewriter *
170 autopaging_writer_create (size_t value_cnt)
171 {
172   return create_casewriter_window (value_cnt, settings_get_workspace_cases (value_cnt));
173 }
174
175 /* Returns a casewriter for cases with VALUE_CNT struct values
176    per case.  The cases written to the casewriter will be kept in
177    memory.
178
179    A casewriter created with this function may be passed to
180    casewriter_make_reader. */
181 struct casewriter *
182 mem_writer_create (size_t value_cnt)
183 {
184   return create_casewriter_window (value_cnt, CASENUMBER_MAX);
185 }
186
187 /* Returns a casewriter for cases with VALUE_CNT struct values
188    per case.  The cases written to the casewriter will be written
189    to disk.
190
191    A casewriter created with this function may be passed to
192    casewriter_make_reader. */
193 struct casewriter *
194 tmpfile_writer_create (size_t value_cnt)
195 {
196   return create_casewriter_window (value_cnt, 0);
197 }
198 \f
199 static const struct casewriter_class casewriter_window_class;
200 static const struct casereader_random_class casereader_window_class;
201
202 /* Creates and returns a new casewriter based on a casewindow.
203    Each of the casewriter's cases are composed of VALUE_CNT
204    struct values.  The casewriter's cases will be maintained in
205    memory until MAX_IN_CORE_CASES have been written, at which
206    point they will be written to disk. */
207 static struct casewriter *
208 create_casewriter_window (size_t value_cnt, casenumber max_in_core_cases)
209 {
210   struct casewindow *window = casewindow_create (value_cnt, max_in_core_cases);
211   struct casewriter *writer = casewriter_create (value_cnt,
212                                                  &casewriter_window_class,
213                                                  window);
214   taint_propagate (casewindow_get_taint (window),
215                    casewriter_get_taint (writer));
216   return writer;
217 }
218
219 /* Writes case C to casewindow writer WINDOW. */
220 static void
221 casewriter_window_write (struct casewriter *writer UNUSED, void *window_,
222                          struct ccase *c)
223 {
224   struct casewindow *window = window_;
225   casewindow_push_head (window, c);
226 }
227
228 /* Destroys casewindow writer WINDOW. */
229 static void
230 casewriter_window_destroy (struct casewriter *writer UNUSED, void *window_)
231 {
232   struct casewindow *window = window_;
233   casewindow_destroy (window);
234 }
235
236 /* Converts casewindow writer WINDOW to a casereader and returns
237    the casereader. */
238 static struct casereader *
239 casewriter_window_convert_to_reader (struct casewriter *writer UNUSED,
240                                      void *window_)
241 {
242   struct casewindow *window = window_;
243   struct casereader *reader =
244     casereader_create_random (casewindow_get_value_cnt (window),
245                               casewindow_get_case_cnt (window),
246                               &casereader_window_class, window);
247
248   taint_propagate (casewindow_get_taint (window),
249                    casereader_get_taint (reader));
250   return reader;
251 }
252
253 /* Reads and returns the case at the given 0-based OFFSET from
254    the front of WINDOW into C.  Returns a null pointer if OFFSET
255    is beyond the end of file or upon I/O error.  The caller must
256    call case_unref() on the returned case when it is no longer
257    needed.*/
258 static struct ccase *
259 casereader_window_read (struct casereader *reader UNUSED, void *window_,
260                         casenumber offset)
261 {
262   struct casewindow *window = window_;
263   if (offset >= casewindow_get_case_cnt (window))
264     return NULL;
265   return casewindow_get_case (window, offset);
266 }
267
268 /* Destroys casewindow reader WINDOW. */
269 static void
270 casereader_window_destroy (struct casereader *reader UNUSED, void *window_)
271 {
272   struct casewindow *window = window_;
273   casewindow_destroy (window);
274 }
275
276 /* Discards CASE_CNT cases from the front of WINDOW. */
277 static void
278 casereader_window_advance (struct casereader *reader UNUSED, void *window_,
279                            casenumber case_cnt)
280 {
281   struct casewindow *window = window_;
282   casewindow_pop_tail (window, case_cnt);
283 }
284
285 /* Class for casewindow writer. */
286 static const struct casewriter_class casewriter_window_class =
287   {
288     casewriter_window_write,
289     casewriter_window_destroy,
290     casewriter_window_convert_to_reader,
291   };
292
293 /* Class for casewindow reader. */
294 static const struct casereader_random_class casereader_window_class =
295   {
296     casereader_window_read,
297     casereader_window_destroy,
298     casereader_window_advance,
299   };
300 \f