1 /* PSPP - computes sample statistics.
2 Copyright (C) 2004, 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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
28 #include "casefile-private.h"
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.
38 Use casefile_append or casefile_append_xfer to append a case to a
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.
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.
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.
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. */
58 static struct ll_list all_casefiles = LL_INITIALIZER (all_casefiles);
60 static struct casefile *
61 ll_to_casefile (const struct ll *ll)
63 return ll_data (ll, struct casefile, ll);
66 static struct casereader *
67 ll_to_casereader (const struct ll *ll)
69 return ll_data (ll, struct casereader, ll);
73 /* atexit() handler that closes and deletes our temporary
78 while (!ll_is_empty (&all_casefiles))
79 casefile_destroy (ll_to_casefile (ll_head (&all_casefiles)));
82 /* Insert CF into the global list of casefiles */
84 casefile_register (struct casefile *cf, const struct class_casefile *class)
86 static bool initialised ;
89 atexit (exit_handler);
94 ll_push_head (&all_casefiles, &cf->ll);
95 ll_init (&cf->reader_list);
98 /* Remove CF from the global list */
100 casefile_unregister(struct casefile *cf)
105 /* Return the casefile corresponding to this reader */
107 casereader_get_casefile (const struct casereader *r)
112 /* Return the case number of the current case */
114 casereader_cnum(const struct casereader *r)
116 return r->class->cnum(r);
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. */
124 casereader_read (struct casereader *reader, struct ccase *c)
126 struct casefile *cf = casereader_get_casefile (reader);
128 struct ccase *read_case = NULL;
130 if ( casefile_error (cf) )
133 read_case = reader->class->get_next_case (reader);
134 if ( ! read_case ) return false;
136 case_clone (c, read_case );
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
147 casereader_read_xfer (struct casereader *ffr, struct ccase *c)
149 struct casefile *cf = casereader_get_casefile (ffr);
151 struct ccase *read_case = NULL ;
153 if ( casefile_error (cf) )
156 read_case = ffr->class->get_next_case (ffr);
157 if ( ! read_case ) return false;
159 if ( ffr->destructive && casefile_in_core (cf) )
162 case_move (c, read_case);
165 case_clone (c, read_case);
172 casereader_destroy (struct casereader *r)
176 r->class->destroy(r);
179 /* Creates a copy of R and returns it */
181 casereader_clone(const struct casereader *r)
183 /* Would we ever want to clone a destructive reader ?? */
184 assert ( ! r->destructive ) ;
186 return r->class->clone (r);
189 /* Destroys casefile CF. */
191 casefile_destroy(struct casefile *cf)
195 assert(cf->class->destroy);
197 while (!ll_is_empty (&cf->reader_list))
198 casereader_destroy (ll_to_casereader (ll_head (&cf->reader_list)));
200 casefile_unregister(cf);
202 cf->class->destroy(cf);
205 /* Returns true if an I/O error has occurred in casefile CF. */
207 casefile_error (const struct casefile *cf)
209 return cf->class->error(cf);
212 /* Returns the number of cases in casefile CF. */
214 casefile_get_case_cnt (const struct casefile *cf)
216 return cf->class->get_case_cnt(cf);
219 /* Returns the number of `union value's in a case for CF. */
221 casefile_get_value_cnt (const struct casefile *cf)
223 return cf->class->get_value_cnt(cf);
226 /* Creates and returns a casereader for CF. A casereader can be used to
227 sequentially read the cases in a casefile. */
229 casefile_get_reader (const struct casefile *cf)
231 struct casereader *r = cf->class->get_reader(cf);
232 r->cf = (struct casefile *) cf;
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.) */
246 casefile_get_destructive_reader (struct casefile *cf)
248 struct casereader *r = cf->class->get_reader (cf);
250 r->destructive = true;
251 cf->being_destroyed = true;
256 /* Appends a copy of case C to casefile CF.
257 Returns true if successful, false if an I/O error occurred. */
259 casefile_append (struct casefile *cf, const struct ccase *c)
261 assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
263 return cf->class->append(cf, c);
266 /* Appends case C to casefile CF, which takes over ownership of
268 Returns true if successful, false if an I/O error occurred. */
270 casefile_append_xfer (struct casefile *cf, struct ccase *c)
272 assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
274 cf->class->append (cf, c);
277 return cf->class->error (cf);
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
289 Implementations may choose to silently ignore this function.
291 Returns true if successful, false if an I/O error occurred. */
293 casefile_sleep (const struct casefile *cf)
295 return cf->class->sleep ? cf->class->sleep(cf) : true;
298 /* Returns true only if casefile CF is stored in memory (instead of on
299 disk), false otherwise.
302 casefile_in_core (const struct casefile *cf)
304 return cf->class->in_core(cf);
307 /* If CF is currently stored in memory, writes it to disk. Readers, if any,
308 retain their current positions.
310 Implementations may choose to silently ignore this function.
312 Returns true if successful, false if an I/O error occurred. */
314 casefile_to_disk (const struct casefile *cf)
316 return cf->class->to_disk ? cf->class->to_disk(cf) : true;
320 casereader_register(struct casefile *cf,
321 struct casereader *reader,
322 const struct class_casereader *class)
324 reader->class = class;
327 ll_push_head (&cf->reader_list, &reader->ll);