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) )
160 case_move (c, read_case);
162 case_clone (c, read_case);
169 casereader_destroy (struct casereader *r)
173 r->class->destroy(r);
176 /* Destroys casefile CF. */
178 casefile_destroy(struct casefile *cf)
182 assert(cf->class->destroy);
184 while (!ll_is_empty (&cf->reader_list))
185 casereader_destroy (ll_to_casereader (ll_head (&cf->reader_list)));
187 casefile_unregister(cf);
189 cf->class->destroy(cf);
192 /* Returns true if an I/O error has occurred in casefile CF. */
194 casefile_error (const struct casefile *cf)
196 return cf->class->error(cf);
199 /* Returns the number of cases in casefile CF. */
201 casefile_get_case_cnt (const struct casefile *cf)
203 return cf->class->get_case_cnt(cf);
206 /* Returns the number of `union value's in a case for CF. */
208 casefile_get_value_cnt (const struct casefile *cf)
210 return cf->class->get_value_cnt(cf);
213 /* Creates and returns a casereader for CF. A casereader can be used to
214 sequentially read the cases in a casefile. */
216 casefile_get_reader (const struct casefile *cf)
218 struct casereader *r = cf->class->get_reader(cf);
219 r->cf = (struct casefile *) cf;
226 /* Creates and returns a destructive casereader for CF. Like a
227 normal casereader, a destructive casereader sequentially reads
228 the cases in a casefile. Unlike a normal casereader, a
229 destructive reader cannot operate concurrently with any other
230 reader. (This restriction could be relaxed in a few ways, but
231 it is so far unnecessary for other code.) */
233 casefile_get_destructive_reader (struct casefile *cf)
235 struct casereader *r = cf->class->get_reader (cf);
237 r->destructive = true;
238 cf->being_destroyed = true;
243 /* Appends a copy of case C to casefile CF.
244 Returns true if successful, false if an I/O error occurred. */
246 casefile_append (struct casefile *cf, const struct ccase *c)
248 assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
250 return cf->class->append(cf, c);
253 /* Appends case C to casefile CF, which takes over ownership of
255 Returns true if successful, false if an I/O error occurred. */
257 casefile_append_xfer (struct casefile *cf, struct ccase *c)
259 assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
261 cf->class->append (cf, c);
264 return cf->class->error (cf);
270 /* Puts a casefile to "sleep", that is, minimizes the resources
271 needed for it by closing its file descriptor and freeing its
272 buffer. This is useful if we need so many casefiles that we
273 might not have enough memory and file descriptors to go
276 Implementations may choose to silently ignore this function.
278 Returns true if successful, false if an I/O error occurred. */
280 casefile_sleep (const struct casefile *cf)
282 return cf->class->sleep ? cf->class->sleep(cf) : true;
285 /* Returns true only if casefile CF is stored in memory (instead of on
286 disk), false otherwise.
289 casefile_in_core (const struct casefile *cf)
291 return cf->class->in_core(cf);
294 /* If CF is currently stored in memory, writes it to disk. Readers, if any,
295 retain their current positions.
297 Implementations may choose to silently ignore this function.
299 Returns true if successful, false if an I/O error occurred. */
301 casefile_to_disk (const struct casefile *cf)
303 return cf->class->to_disk ? cf->class->to_disk(cf) : true;
307 casereader_register(struct casefile *cf,
308 struct casereader *reader,
309 const struct class_casereader *class)
311 reader->class = class;
314 ll_push_head (&cf->reader_list, &reader->ll);