1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "data/casereader-shim.h"
23 #include "data/casereader.h"
24 #include "data/casereader-provider.h"
25 #include "data/casewindow.h"
26 #include "data/settings.h"
27 #include "libpspp/taint.h"
29 #include "gl/xalloc.h"
31 /* A buffering shim casereader. */
32 struct casereader_shim
34 struct casewindow
*window
; /* Window of buffered cases. */
35 struct casereader
*subreader
; /* Subordinate casereader. */
38 static const struct casereader_random_class shim_class
;
40 static bool buffer_case (struct casereader_shim
*s
);
42 /* Interposes a buffering shim on READER.
44 Returns the new shim. The only legitimate use of the returned
45 casereader_shim is for calling casereader_shim_slurp(). If READER has no
46 clones already (which the caller should ensure, if it plans to use the
47 return value), then the returned casreader_shim is valid for that purpose
48 until, and only until, the READER's 'destroy' function is called. */
49 struct casereader_shim
*
50 casereader_shim_insert (struct casereader
*reader
)
52 const struct caseproto
*proto
= casereader_get_proto (reader
);
53 casenumber case_cnt
= casereader_get_case_cnt (reader
);
54 struct casereader_shim
*s
= xmalloc (sizeof *s
);
55 s
->window
= casewindow_create (proto
, settings_get_workspace_cases (proto
));
56 s
->subreader
= casereader_create_random (proto
, case_cnt
, &shim_class
, s
);
57 casereader_swap (reader
, s
->subreader
);
58 taint_propagate (casewindow_get_taint (s
->window
),
59 casereader_get_taint (reader
));
60 taint_propagate (casereader_get_taint (s
->subreader
),
61 casereader_get_taint (reader
));
65 /* Reads all of the cases from S's subreader into S's buffer and destroys S's
66 subreader. (This is a no-op if the subreader has already been
69 Refer to the comment on casereader_shim_insert() for information on when
70 this function may be used. */
72 casereader_shim_slurp (struct casereader_shim
*s
)
74 while (buffer_case (s
))
78 /* Reads a case from S's subreader and appends it to S's window. Returns true
79 if successful, false at the end of S's subreader or upon an I/O error. */
81 buffer_case (struct casereader_shim
*s
)
85 if (s
->subreader
== NULL
)
88 tmp
= casereader_read (s
->subreader
);
91 casereader_destroy (s
->subreader
);
96 casewindow_push_head (s
->window
, tmp
);
100 /* Reads the case at the given 0-based OFFSET from the front of the window into
101 C. Returns the case if successful, or a null pointer if OFFSET is beyond
102 the end of file or upon I/O error. The caller must call case_unref() on the
103 returned case when it is no longer needed. */
104 static struct ccase
*
105 casereader_shim_read (struct casereader
*reader UNUSED
, void *s_
,
108 struct casereader_shim
*s
= s_
;
110 while (casewindow_get_case_cnt (s
->window
) <= offset
)
111 if (!buffer_case (s
))
114 return casewindow_get_case (s
->window
, offset
);
119 casereader_shim_destroy (struct casereader
*reader UNUSED
, void *s_
)
121 struct casereader_shim
*s
= s_
;
122 casewindow_destroy (s
->window
);
123 casereader_destroy (s
->subreader
);
127 /* Discards CNT cases from the front of S's window. */
129 casereader_shim_advance (struct casereader
*reader UNUSED
, void *s_
,
132 struct casereader_shim
*s
= s_
;
133 casewindow_pop_tail (s
->window
, case_cnt
);
136 /* Class for the buffered reader. */
137 static const struct casereader_random_class shim_class
=
139 casereader_shim_read
,
140 casereader_shim_destroy
,
141 casereader_shim_advance
,