e6c6fa676baa35e3315f94c9a080f9f9fbced1f2
[pspp-builds.git] / src / data / casefile.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2004, 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include <stddef.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <assert.h>
25
26 #include "case.h"
27 #include "casefile.h"
28 #include "casefile-private.h"
29
30
31 struct ccase;
32
33 /* A casefile is an abstract class representing an array of cases.  In
34    general, cases are accessible sequentially,  and are immutable once
35    appended to the casefile.  However some implementations may provide
36    special methods for  case mutation or random access.
37
38    Use casefile_append or casefile_append_xfer to append a case to a
39    casefile. 
40
41    The casefile may be read sequentially,
42    starting from the beginning, by "casereaders".  Any
43    number of casereaders may be created, at any time.
44    Each casereader has an independent position in the casefile.
45
46    Casereaders may only move forward.  They cannot move backward to
47    arbitrary records or seek randomly.  Cloning casereaders is
48    possible, but it is not yet implemented.
49
50    Use casereader_read() or casereader_read_xfer() to read
51    a case from a casereader.  Use casereader_destroy() to
52    discard a casereader when it is no longer needed.
53
54    When a casefile is no longer needed, it may be destroyed with
55    casefile_destroy().  This function will also destroy any
56    remaining casereaders. */
57
58 static struct ll_list all_casefiles = LL_INITIALIZER (all_casefiles);
59
60 static struct casefile *
61 ll_to_casefile (const struct ll *ll)
62 {
63   return ll_data (ll, struct casefile, ll);
64 }
65
66 static struct casereader *
67 ll_to_casereader (const struct ll *ll)
68 {
69   return ll_data (ll, struct casereader, ll);
70 }
71
72
73 /* atexit() handler that closes and deletes our temporary
74    files. */
75 static void
76 exit_handler (void) 
77 {
78   while (!ll_is_empty (&all_casefiles))
79     casefile_destroy (ll_to_casefile (ll_head (&all_casefiles)));
80 }
81
82 /* Insert CF into the global list of casefiles */
83 void
84 casefile_register (struct casefile *cf, const struct class_casefile *class)
85 {
86   static bool initialised ;
87   if ( !initialised ) 
88     {
89       atexit (exit_handler);
90       initialised = true;
91     }
92
93   cf->class = class;
94   ll_push_head (&all_casefiles, &cf->ll);
95   ll_init (&cf->reader_list);
96 }
97
98 /* Remove CF from the global list */
99 static void
100 casefile_unregister(struct casefile *cf)
101 {
102   ll_remove (&cf->ll);
103 }
104
105 /* Return the casefile corresponding to this reader */
106 struct casefile *
107 casereader_get_casefile (const struct casereader *r)
108 {
109   return r->cf;
110 }
111
112 /* Return the case number of the current case */
113 unsigned long
114 casereader_cnum(const struct casereader *r)
115 {
116   return r->class->cnum(r);
117 }
118
119
120 /* Reads a copy of the next case from READER into C.
121    Caller is responsible for destroying C.
122    Returns true if successful, false at end of file. */
123 bool
124 casereader_read (struct casereader *reader, struct ccase *c)
125 {
126   struct casefile *cf = casereader_get_casefile (reader);
127
128   struct ccase *read_case = NULL;
129
130   if ( casefile_error (cf) )
131     return false;
132
133   read_case = reader->class->get_next_case (reader);
134   if ( ! read_case ) return false;
135
136   case_clone (c, read_case );
137
138   return true;
139 }
140
141
142 /* Reads the next case from READER into C and transfers ownership
143    to the caller.  Caller is responsible for destroying C.
144    Returns true if successful, false at end of file or on I/O
145    error. */
146 bool
147 casereader_read_xfer (struct casereader *ffr, struct ccase *c)
148 {
149   struct casefile *cf = casereader_get_casefile (ffr);
150
151   struct ccase *read_case = NULL ;
152
153   case_nullify (c);
154   if ( casefile_error (cf) )
155     return false;
156
157   read_case = ffr->class->get_next_case (ffr);
158   if ( ! read_case ) return false;
159
160   if ( ffr->destructive && casefile_in_core (cf) )
161     case_move (c, read_case);
162   else
163     case_clone (c, read_case);
164
165   return true;
166 }
167
168 /* Destroys R. */
169 void 
170 casereader_destroy (struct casereader *r)
171 {
172   ll_remove (&r->ll);
173
174   r->class->destroy(r);
175 }
176
177 /* Creates a copy of R and returns it */
178 struct casereader *
179 casereader_clone(const struct casereader *r)
180 {
181   /* Would we ever want to clone a destructive reader ?? */
182   assert ( ! r->destructive ) ;
183
184   return r->class->clone (r);
185 }
186
187 /* Destroys casefile CF. */
188 void
189 casefile_destroy(struct casefile *cf)
190 {
191   if (!cf) return;
192   
193   assert(cf->class->destroy);
194
195   while (!ll_is_empty (&cf->reader_list))
196     casereader_destroy (ll_to_casereader (ll_head (&cf->reader_list)));
197       
198   casefile_unregister(cf);
199
200   cf->class->destroy(cf);
201 }
202
203 /* Returns true if an I/O error has occurred in casefile CF. */
204 bool 
205 casefile_error (const struct casefile *cf)
206 {
207   return cf->class->error(cf);
208 }
209
210 /* Returns the number of cases in casefile CF. */
211 unsigned long 
212 casefile_get_case_cnt (const struct casefile *cf)
213 {
214   return cf->class->get_case_cnt(cf);
215 }
216
217 /* Returns the number of `union value's in a case for CF. */
218 size_t 
219 casefile_get_value_cnt (const struct casefile *cf)
220 {
221   return cf->class->get_value_cnt(cf);
222 }
223
224 /* Creates and returns a casereader for CF.  A casereader can be used to
225    sequentially read the cases in a casefile. */
226 struct casereader *
227 casefile_get_reader (const struct casefile *cf)
228 {
229   struct casereader *r = cf->class->get_reader(cf);
230   r->cf = (struct casefile *) cf;
231
232   assert (r->class);
233   
234   return r;
235 }
236
237 /* Creates and returns a destructive casereader for CF.  Like a
238    normal casereader, a destructive casereader sequentially reads
239    the cases in a casefile.  Unlike a normal casereader, a
240    destructive reader cannot operate concurrently with any other
241    reader.  (This restriction could be relaxed in a few ways, but
242    it is so far unnecessary for other code.) */
243 struct casereader *
244 casefile_get_destructive_reader (struct casefile *cf) 
245 {
246   struct casereader *r = cf->class->get_reader (cf);
247   r->cf = cf;
248   r->destructive = true;
249   cf->being_destroyed = true;
250
251   return r;
252 }
253
254 /* Appends a copy of case C to casefile CF. 
255    Returns true if successful, false if an I/O error occurred. */
256 bool 
257 casefile_append (struct casefile *cf, const struct ccase *c)
258 {
259   assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
260
261   return cf->class->append(cf, c);
262 }
263
264 /* Appends case C to casefile CF, which takes over ownership of
265    C.  
266    Returns true if successful, false if an I/O error occurred. */
267 bool 
268 casefile_append_xfer (struct casefile *cf, struct ccase *c)
269 {
270   assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
271
272   cf->class->append (cf, c);
273   case_destroy (c);
274
275   return cf->class->error (cf);
276 }
277
278
279
280
281 /* Puts a casefile to "sleep", that is, minimizes the resources
282    needed for it by closing its file descriptor and freeing its
283    buffer.  This is useful if we need so many casefiles that we
284    might not have enough memory and file descriptors to go
285    around.
286   
287    Implementations may choose to silently ignore this function.
288
289    Returns true if successful, false if an I/O error occurred. */
290 bool
291 casefile_sleep (const struct casefile *cf)
292 {
293   return cf->class->sleep ? cf->class->sleep(cf) : true;
294 }
295
296 /* Returns true only if casefile CF is stored in memory (instead of on
297    disk), false otherwise. 
298 */
299 bool
300 casefile_in_core (const struct casefile *cf)
301 {
302   return cf->class->in_core(cf);
303 }
304
305 /* If CF is currently stored in memory, writes it to disk.  Readers, if any,
306    retain their current positions.
307
308    Implementations may choose to silently ignore this function.
309
310    Returns true if successful, false if an I/O error occurred. */
311 bool 
312 casefile_to_disk (const struct casefile *cf)
313 {
314   return cf->class->to_disk ? cf->class->to_disk(cf) : true;
315 }
316
317 void
318 casereader_register(struct casefile *cf, 
319                     struct casereader *reader, 
320                     const struct class_casereader *class)
321 {
322   reader->class = class;
323   reader->cf = cf;
324       
325   ll_push_head (&cf->reader_list, &reader->ll);
326 }