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