1 /* PSPP - computes sample statistics.
3 Copyright (C) 2006, 2007 Free Software Foundation, Inc.
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
23 #include "flexifile.h"
25 #include <data/casefile.h>
26 #include <data/casefile-private.h>
27 #include <data/case.h>
28 #include <libpspp/compiler.h>
31 struct class_flexifile
33 struct class_casefile parent;
35 bool (*get_case) (const struct flexifile *, unsigned long, struct ccase *);
37 bool (*insert_case) (struct flexifile *, struct ccase *, int );
38 bool (*delete_cases) (struct flexifile *, int, int );
40 bool (*resize) (struct flexifile *, int, int );
43 static const struct class_flexifile class;
45 #define CLASS_FLEXIFILE(K) ((struct class_flexifile *) K)
46 #define CONST_CLASS_FLEXIFILE(K) ((const struct class_flexifile *) K)
52 struct casefile cf; /* Parent */
54 size_t value_cnt; /* Case size in `union value's. */
55 unsigned long case_cnt; /* Number of cases stored. */
59 struct ccase *cases; /* Pointer to array of cases. */
60 unsigned long capacity; /* size of array in cases */
63 struct class_flexifilereader
65 struct class_casereader parent ;
68 static const struct class_flexifilereader class_reader;
70 /* For reading out the cases in a flexifile. */
71 struct flexifilereader
73 struct casereader cr; /* Parent */
75 unsigned long case_idx; /* Case number of current case. */
76 bool destructive; /* Is this a destructive reader? */
84 impl_get_case(const struct flexifile *ff, unsigned long casenum,
87 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn);
90 impl_delete_cases (struct flexifile *ff, int n_cases, int first);
93 impl_resize (struct flexifile *ff, int n_values, int posn);
96 /* Gets a case, for which writing may not be safe */
98 flexifile_get_case(const struct flexifile *ff, unsigned long casenum,
101 const struct class_flexifile *class =
102 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
104 return class->get_case(ff, casenum, c);
108 /* Insert N_VALUES before POSN.
109 If N_VALUES is negative, then deleted -N_VALUES instead
112 flexifile_resize (struct flexifile *ff, int n_values, int posn)
114 const struct class_flexifile *class =
115 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
117 return class->resize(ff, n_values, posn);
123 flexifile_insert_case (struct flexifile *ff, struct ccase *c, int posn)
125 const struct class_flexifile *class =
126 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
128 return class->insert_case(ff, c, posn);
133 flexifile_delete_cases (struct flexifile *ff, int n_cases, int first)
135 const struct class_flexifile *class =
136 CONST_CLASS_FLEXIFILE (CONST_CASEFILE(ff)->class) ;
138 return class->delete_cases (ff, n_cases, first);
143 flexifile_get_case_cnt (const struct casefile *cf)
145 return FLEXIFILE(cf)->case_cnt;
149 flexifile_get_value_cnt (const struct casefile *cf)
151 return FLEXIFILE(cf)->value_cnt;
156 flexifile_destroy (struct casefile *cf)
159 for ( i = 0 ; i < FLEXIFILE(cf)->case_cnt; ++i )
160 case_destroy( &FLEXIFILE(cf)->cases[i]);
162 free(FLEXIFILE(cf)->cases);
166 grow(struct flexifile *ff)
168 ff->capacity += CHUNK_SIZE;
169 ff->cases = xrealloc(ff->cases, ff->capacity * sizeof ( *ff->cases) );
173 flexifile_append (struct casefile *cf, const struct ccase *c)
175 struct flexifile *ff = FLEXIFILE(cf);
177 if (ff->case_cnt >= ff->capacity)
180 case_clone (&ff->cases[ff->case_cnt++], c);
186 flexifilereader_cnum (const struct casereader *cr)
188 struct flexifilereader *ffr = FLEXIFILEREADER(cr);
190 return ffr->case_idx;
193 static struct ccase *
194 flexifilereader_get_next_case (struct casereader *cr)
196 struct flexifilereader *ffr = FLEXIFILEREADER(cr);
197 struct flexifile *ff = FLEXIFILE(casereader_get_casefile(cr));
199 if ( ffr->case_idx >= ff->case_cnt)
202 return &ff->cases[ffr->case_idx++];
206 flexifilereader_destroy(struct casereader *r)
211 static struct casereader *
212 flexifile_get_reader (const struct casefile *cf_)
214 struct casefile *cf = (struct casefile *) cf_;
215 struct flexifilereader *ffr = xzalloc (sizeof *ffr);
216 struct casereader *reader = (struct casereader *) ffr;
218 casereader_register (cf, reader, CLASS_CASEREADER(&class_reader));
224 static struct casereader *
225 flexifilereader_clone (const struct casereader *cr)
227 const struct flexifilereader *ffr = (const struct flexifilereader *) cr;
228 struct flexifilereader *new_ffr = xzalloc (sizeof *new_ffr);
229 struct casereader *new_reader = (struct casereader *) new_ffr;
230 struct casefile *cf = casereader_get_casefile (cr);
232 casereader_register (cf, new_reader, CLASS_CASEREADER(&class_reader));
234 new_ffr->case_idx = ffr->case_idx ;
235 new_ffr->destructive = ffr->destructive ;
242 flexifile_in_core(const struct casefile *cf UNUSED)
244 /* Always in memory */
249 flexifile_error (const struct casefile *cf UNUSED )
256 flexifile_create (size_t value_cnt)
258 struct flexifile *ff = xzalloc (sizeof *ff);
259 struct casefile *cf = (struct casefile *) ff;
261 casefile_register (cf, (struct class_casefile *) &class);
263 ff->value_cnt = value_cnt;
265 ff->cases = xzalloc(sizeof (struct ccase *) * CHUNK_SIZE);
266 ff->capacity = CHUNK_SIZE;
271 static const struct class_flexifile class = {
275 flexifile_get_value_cnt,
276 flexifile_get_case_cnt,
277 flexifile_get_reader,
292 static const struct class_flexifilereader class_reader =
295 flexifilereader_get_next_case,
296 flexifilereader_cnum,
297 flexifilereader_destroy,
298 flexifilereader_clone
303 /* Implementations of class methods */
306 impl_get_case(const struct flexifile *ff, unsigned long casenum,
309 if ( casenum >= ff->case_cnt)
312 case_clone (c, &ff->cases[casenum]);
321 dumpcasedata(struct ccase *c)
323 size_t value_cnt = case_get_value_cnt (c);
325 for ( i = 0 ; i < value_cnt * MAX_SHORT_STRING; ++i )
326 putchar (case_str (c, 0)[i]);
332 impl_resize (struct flexifile *ff, int n_values, int posn)
336 for( i = 0 ; i < ff->case_cnt ; ++i )
339 case_create (&c, ff->value_cnt + n_values);
341 case_copy (&c, 0, &ff->cases[i], 0, posn);
343 memset (case_data_rw_idx(&c, posn), ' ', n_values * MAX_SHORT_STRING) ;
344 case_copy (&c, posn + n_values,
345 &ff->cases[i], posn, ff->value_cnt - posn);
347 case_destroy (&ff->cases[i]);
351 ff->value_cnt += n_values;
357 impl_insert_case (struct flexifile *ff, struct ccase *c, int posn)
364 if ( posn > ff->case_cnt )
367 if ( posn >= ff->capacity )
370 case_create(&blank, ff->value_cnt);
372 flexifile_append(CASEFILE(ff), &blank);
374 case_destroy(&blank);
376 /* Shift the existing cases down one */
377 for ( i = ff->case_cnt ; i > posn; --i)
378 case_move(&ff->cases[i], &ff->cases[i-1]);
380 case_clone (&ff->cases[posn], c);
387 impl_delete_cases (struct flexifile *ff, int n_cases, int first)
391 if ( ff->case_cnt < first + n_cases )
394 for ( i = first ; i < first + n_cases; ++i )
395 case_destroy (&ff->cases[i]);
397 /* Shift the cases up by N_CASES */
398 for ( i = first; i < ff->case_cnt - n_cases; ++i )
400 case_move (&ff->cases[i], &ff->cases[i+ n_cases]);
403 ff->case_cnt -= n_cases;