Added casereader_clone function.
[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   if ( casefile_error (cf) )
154     return false;
155
156   read_case = ffr->class->get_next_case (ffr);
157   if ( ! read_case ) return false;
158
159   if ( ffr->destructive && casefile_in_core (cf) )
160     {
161       case_nullify (c);
162     case_move (c, read_case);
163     }
164   else
165     case_clone (c, read_case);
166
167   return true;
168 }
169
170 /* Destroys R. */
171 void 
172 casereader_destroy (struct casereader *r)
173 {
174   ll_remove (&r->ll);
175
176   r->class->destroy(r);
177 }
178
179 /* Creates a copy of R and returns it */
180 struct casereader *
181 casereader_clone(const struct casereader *r)
182 {
183   /* Would we ever want to clone a destructive reader ?? */
184   assert ( ! r->destructive ) ;
185
186   return r->class->clone (r);
187 }
188
189 /* Destroys casefile CF. */
190 void
191 casefile_destroy(struct casefile *cf)
192 {
193   if (!cf) return;
194   
195   assert(cf->class->destroy);
196
197   while (!ll_is_empty (&cf->reader_list))
198     casereader_destroy (ll_to_casereader (ll_head (&cf->reader_list)));
199       
200   casefile_unregister(cf);
201
202   cf->class->destroy(cf);
203 }
204
205 /* Returns true if an I/O error has occurred in casefile CF. */
206 bool 
207 casefile_error (const struct casefile *cf)
208 {
209   return cf->class->error(cf);
210 }
211
212 /* Returns the number of cases in casefile CF. */
213 unsigned long 
214 casefile_get_case_cnt (const struct casefile *cf)
215 {
216   return cf->class->get_case_cnt(cf);
217 }
218
219 /* Returns the number of `union value's in a case for CF. */
220 size_t 
221 casefile_get_value_cnt (const struct casefile *cf)
222 {
223   return cf->class->get_value_cnt(cf);
224 }
225
226 /* Creates and returns a casereader for CF.  A casereader can be used to
227    sequentially read the cases in a casefile. */
228 struct casereader *
229 casefile_get_reader (const struct casefile *cf)
230 {
231   struct casereader *r = cf->class->get_reader(cf);
232   r->cf = (struct casefile *) cf;
233
234   assert (r->class);
235   
236   return r;
237 }
238
239 /* Creates and returns a destructive casereader for CF.  Like a
240    normal casereader, a destructive casereader sequentially reads
241    the cases in a casefile.  Unlike a normal casereader, a
242    destructive reader cannot operate concurrently with any other
243    reader.  (This restriction could be relaxed in a few ways, but
244    it is so far unnecessary for other code.) */
245 struct casereader *
246 casefile_get_destructive_reader (struct casefile *cf) 
247 {
248   struct casereader *r = cf->class->get_reader (cf);
249   r->cf = cf;
250   r->destructive = true;
251   cf->being_destroyed = true;
252
253   return r;
254 }
255
256 /* Appends a copy of case C to casefile CF. 
257    Returns true if successful, false if an I/O error occurred. */
258 bool 
259 casefile_append (struct casefile *cf, const struct ccase *c)
260 {
261   assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
262
263   return cf->class->append(cf, c);
264 }
265
266 /* Appends case C to casefile CF, which takes over ownership of
267    C.  
268    Returns true if successful, false if an I/O error occurred. */
269 bool 
270 casefile_append_xfer (struct casefile *cf, struct ccase *c)
271 {
272   assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
273
274   cf->class->append (cf, c);
275   case_destroy (c);
276
277   return cf->class->error (cf);
278 }
279
280
281
282
283 /* Puts a casefile to "sleep", that is, minimizes the resources
284    needed for it by closing its file descriptor and freeing its
285    buffer.  This is useful if we need so many casefiles that we
286    might not have enough memory and file descriptors to go
287    around.
288   
289    Implementations may choose to silently ignore this function.
290
291    Returns true if successful, false if an I/O error occurred. */
292 bool
293 casefile_sleep (const struct casefile *cf)
294 {
295   return cf->class->sleep ? cf->class->sleep(cf) : true;
296 }
297
298 /* Returns true only if casefile CF is stored in memory (instead of on
299    disk), false otherwise. 
300 */
301 bool
302 casefile_in_core (const struct casefile *cf)
303 {
304   return cf->class->in_core(cf);
305 }
306
307 /* If CF is currently stored in memory, writes it to disk.  Readers, if any,
308    retain their current positions.
309
310    Implementations may choose to silently ignore this function.
311
312    Returns true if successful, false if an I/O error occurred. */
313 bool 
314 casefile_to_disk (const struct casefile *cf)
315 {
316   return cf->class->to_disk ? cf->class->to_disk(cf) : true;
317 }
318
319 void
320 casereader_register(struct casefile *cf, 
321                     struct casereader *reader, 
322                     const struct class_casereader *class)
323 {
324   reader->class = class;
325   reader->cf = cf;
326       
327   ll_push_head (&cf->reader_list, &reader->ll);
328 }