1 /* PSPP - a program for statistical analysis. 2 Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc. 3 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. 8 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. 13 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/>. */ 16 17 #include <config.h> 18 19 #include "data/casereader-shim.h" 20 21 #include <stdlib.h> 22 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" 28 29 #include "gl/xalloc.h" casereader_select_include(const struct ccase * c UNUSED,void * cs_)30 31 /* A buffering shim casereader. */ 32 struct casereader_shim 33 { 34 struct casewindow *window; /* Window of buffered cases. */ 35 struct casereader *subreader; /* Subordinate casereader. */ 36 }; 37 38 static const struct casereader_random_class shim_class; 39 40 static bool buffer_case (struct casereader_shim *s); 41 42 /* Interposes a buffering shim on READER. casereader_select_destroy(void * cs_)43 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) 51 { 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)); 62 return s; 63 } 64 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 67 destroyed.) 68 69 Refer to the comment on casereader_shim_insert() for information on when 70 this function may be used. */ 71 void 72 casereader_shim_slurp (struct casereader_shim *s) 73 { 74 while (buffer_case (s)) 75 continue; 76 } 77 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. */ 80 static bool 81 buffer_case (struct casereader_shim *s) 82 { 83 struct ccase *tmp; 84 85 if (s->subreader == NULL) 86 return false; 87 88 tmp = casereader_read (s->subreader); 89 if (tmp == NULL) 90 { 91 casereader_destroy (s->subreader); 92 s->subreader = NULL; 93 return false; 94 } 95 96 casewindow_push_head (s->window, tmp); 97 return true; 98 } 99 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_, 106 casenumber offset) 107 { 108 struct casereader_shim *s = s_; 109 110 while (casewindow_get_case_cnt (s->window) <= offset) 111 if (!buffer_case (s)) 112 return false; 113 114 return casewindow_get_case (s->window, offset); 115 } 116 117 /* Destroys S. */ 118 static void 119 casereader_shim_destroy (struct casereader *reader UNUSED, void *s_) 120 { 121 struct casereader_shim *s = s_; 122 casewindow_destroy (s->window); 123 casereader_destroy (s->subreader); 124 free (s); 125 } 126 127 /* Discards CNT cases from the front of S's window. */ 128 static void 129 casereader_shim_advance (struct casereader *reader UNUSED, void *s_, 130 casenumber case_cnt) 131 { 132 struct casereader_shim *s = s_; 133 casewindow_pop_tail (s->window, case_cnt); 134 } 135 136 /* Class for the buffered reader. */ 137 static const struct casereader_random_class shim_class = 138 { 139 casereader_shim_read, 140 casereader_shim_destroy, 141 casereader_shim_advance, 142 }; 143