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 ;
154 if ( casefile_error (cf) )
157 read_case = ffr->class->get_next_case (ffr);
158 if ( ! read_case ) return false;
160 if ( ffr->destructive && casefile_in_core (cf) )
161 case_move (c, read_case);
163 case_clone (c, read_case);
170 casereader_destroy (struct casereader *r)
174 r->class->destroy(r);
177 /* Creates a copy of R and returns it */
179 casereader_clone(const struct casereader *r)
181 /* Would we ever want to clone a destructive reader ?? */
182 assert ( ! r->destructive ) ;
184 return r->class->clone (r);
187 /* Destroys casefile CF. */
189 casefile_destroy(struct casefile *cf)
193 assert(cf->class->destroy);
195 while (!ll_is_empty (&cf->reader_list))
196 casereader_destroy (ll_to_casereader (ll_head (&cf->reader_list)));
198 casefile_unregister(cf);
200 cf->class->destroy(cf);
203 /* Returns true if an I/O error has occurred in casefile CF. */
205 casefile_error (const struct casefile *cf)
207 return cf->class->error(cf);
210 /* Returns the number of cases in casefile CF. */
212 casefile_get_case_cnt (const struct casefile *cf)
214 return cf->class->get_case_cnt(cf);
217 /* Returns the number of `union value's in a case for CF. */
219 casefile_get_value_cnt (const struct casefile *cf)
221 return cf->class->get_value_cnt(cf);
224 /* Creates and returns a casereader for CF. A casereader can be used to
225 sequentially read the cases in a casefile. */
227 casefile_get_reader (const struct casefile *cf)
229 struct casereader *r = cf->class->get_reader(cf);
230 r->cf = (struct casefile *) cf;
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.) */
244 casefile_get_destructive_reader (struct casefile *cf)
246 struct casereader *r = cf->class->get_reader (cf);
248 r->destructive = true;
249 cf->being_destroyed = true;
254 /* Appends a copy of case C to casefile CF.
255 Returns true if successful, false if an I/O error occurred. */
257 casefile_append (struct casefile *cf, const struct ccase *c)
259 assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
261 return cf->class->append(cf, c);
264 /* Appends case C to casefile CF, which takes over ownership of
266 Returns true if successful, false if an I/O error occurred. */
268 casefile_append_xfer (struct casefile *cf, struct ccase *c)
270 assert (c->case_data->value_cnt >= casefile_get_value_cnt (cf));
272 cf->class->append (cf, c);
275 return cf->class->error (cf);
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
287 Implementations may choose to silently ignore this function.
289 Returns true if successful, false if an I/O error occurred. */
291 casefile_sleep (const struct casefile *cf)
293 return cf->class->sleep ? cf->class->sleep(cf) : true;
296 /* Returns true only if casefile CF is stored in memory (instead of on
297 disk), false otherwise.
300 casefile_in_core (const struct casefile *cf)
302 return cf->class->in_core(cf);
305 /* If CF is currently stored in memory, writes it to disk. Readers, if any,
306 retain their current positions.
308 Implementations may choose to silently ignore this function.
310 Returns true if successful, false if an I/O error occurred. */
312 casefile_to_disk (const struct casefile *cf)
314 return cf->class->to_disk ? cf->class->to_disk(cf) : true;
318 casereader_register(struct casefile *cf,
319 struct casereader *reader,
320 const struct class_casereader *class)
322 reader->class = class;
325 ll_push_head (&cf->reader_list, &reader->ll);