[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Pspp-cvs] pspp/src ui/gui/val-labs-dialog.h math/sort.c d... [simpler-p
From: |
Ben Pfaff |
Subject: |
[Pspp-cvs] pspp/src ui/gui/val-labs-dialog.h math/sort.c d... [simpler-proc] |
Date: |
Sun, 06 May 2007 22:48:28 +0000 |
CVSROOT: /cvsroot/pspp
Module name: pspp
Branch: simpler-proc
Changes by: Ben Pfaff <blp> 07/05/06 22:48:28
Modified files:
src/ui/gui : val-labs-dialog.h
src/math : sort.c
src/data : procedure.h casewriter.c casewindow.c
casereader.h casereader.c case-tmpfile.h
case-tmpfile.c automake.mk
Added files:
src/data : casereader-translator.c casereader-filter.c
Log message:
Start cleaning up code.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/val-labs-dialog.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.6&r2=1.6.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/sort.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.23.2.2&r2=1.23.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/procedure.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.12.2.2&r2=1.12.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewriter.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.3&r2=1.1.2.4
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewindow.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.4&r2=1.1.2.5
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.3&r2=1.1.2.4
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.5&r2=1.1.2.6
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case-tmpfile.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.2&r2=1.1.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case-tmpfile.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.4&r2=1.1.2.5
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.15.2.2&r2=1.15.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader-translator.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader-filter.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
Patches:
Index: ui/gui/val-labs-dialog.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/val-labs-dialog.h,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -b -r1.6 -r1.6.2.1
--- ui/gui/val-labs-dialog.h 24 Dec 2006 23:50:59 -0000 1.6
+++ ui/gui/val-labs-dialog.h 6 May 2007 22:48:27 -0000 1.6.2.1
@@ -29,6 +29,7 @@
#include <gtk/gtk.h>
#include <glade/glade.h>
+#include <data/variable.h>
struct val_labs;
Index: math/sort.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/sort.c,v
retrieving revision 1.23.2.2
retrieving revision 1.23.2.3
diff -u -b -r1.23.2.2 -r1.23.2.3
--- math/sort.c 4 May 2007 03:48:48 -0000 1.23.2.2
+++ math/sort.c 6 May 2007 22:48:27 -0000 1.23.2.3
@@ -139,9 +139,6 @@
casenumber min_run_id;
pqueue_pop (sort->pqueue, &min_case, &min_run_id);
-#if 0
- printf ("\toutput: %f to run %d\n", case_num_idx (&min_case, 0), min_run_id);
-#endif
if (sort->run_id != min_run_id && sort->run != NULL)
{
Index: data/procedure.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/procedure.h,v
retrieving revision 1.12.2.2
retrieving revision 1.12.2.3
diff -u -b -r1.12.2.2 -r1.12.2.3
--- data/procedure.h 4 May 2007 03:48:47 -0000 1.12.2.2
+++ data/procedure.h 6 May 2007 22:48:27 -0000 1.12.2.3
@@ -72,7 +72,7 @@
struct casereader *proc_open (struct dataset *);
bool proc_is_open (const struct dataset *);
-bool proc_commit (struct dataset *) WARN_UNUSED_RESULT;
+bool proc_commit (struct dataset *);
bool dataset_end_of_command (struct dataset *);
Index: data/casewriter.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casewriter.c,v
retrieving revision 1.1.2.3
retrieving revision 1.1.2.4
diff -u -b -r1.1.2.3 -r1.1.2.4
--- data/casewriter.c 4 May 2007 03:48:47 -0000 1.1.2.3
+++ data/casewriter.c 6 May 2007 22:48:27 -0000 1.1.2.4
@@ -54,11 +54,10 @@
}
struct casewriter *
-casewriter_rename (struct casewriter *old)
+casewriter_rename (struct casewriter *writer)
{
- struct casewriter *new = xmalloc (sizeof *old);
- *new = *old;
- free (old);
+ struct casewriter *new = xmemdup (writer, sizeof *writer);
+ free (writer);
return new;
}
Index: data/casewindow.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casewindow.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -u -b -r1.1.2.4 -r1.1.2.5
--- data/casewindow.c 4 May 2007 03:48:47 -0000 1.1.2.4
+++ data/casewindow.c 6 May 2007 22:48:27 -0000 1.1.2.5
@@ -42,10 +42,10 @@
struct casewindow_class
{
- void *(*create) (size_t value_cnt);
- bool (*destroy) (void *aux);
- bool (*push_head) (void *aux, struct ccase *);
- bool (*pop_tail) (void *aux, casenumber cnt);
+ void *(*create) (struct taint *, size_t value_cnt);
+ void (*destroy) (void *aux);
+ void (*push_head) (void *aux, struct ccase *);
+ void (*pop_tail) (void *aux, casenumber cnt);
bool (*get_case) (void *aux, casenumber ofs, struct ccase *);
casenumber (*get_case_cnt) (const void *aux);
};
@@ -61,7 +61,7 @@
cw->class = (max_in_core_cases
? &casewindow_memory_class
: &casewindow_file_class);
- cw->aux = cw->class->create (value_cnt);
+ cw->aux = cw->class->create (taint, value_cnt);
cw->value_cnt = value_cnt;
cw->max_in_core_cases = max_in_core_cases;
cw->taint = taint;
@@ -80,8 +80,8 @@
bool ok = true;
if (cw != NULL)
{
- ok = cw->class->destroy (cw->aux);
- ok = taint_destroy (cw->taint) && ok;
+ cw->class->destroy (cw->aux);
+ ok = taint_destroy (cw->taint);
free (cw);
}
return ok;
@@ -117,15 +117,14 @@
{
if (!casewindow_error (cw))
{
- if (cw->class->push_head (cw->aux, c))
+ cw->class->push_head (cw->aux, c);
+ if (!casewindow_error (cw))
{
casenumber case_cnt = cw->class->get_case_cnt (cw->aux);
if (case_cnt > cw->max_in_core_cases
&& cw->class == &casewindow_memory_class)
casewindow_to_disk (cw);
}
- else
- casewindow_force_error (cw);
}
else
case_destroy (c);
@@ -135,8 +134,7 @@
casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt)
{
if (!casewindow_error (cw))
- if (!cw->class->pop_tail (cw->aux, case_cnt))
- casewindow_force_error (cw);
+ cw->class->pop_tail (cw->aux, case_cnt);
}
bool
@@ -146,11 +144,10 @@
struct casewindow *cw = (struct casewindow *) cw_;
assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw));
- if (!casewindow_error (cw) && cw->class->get_case (cw->aux, case_idx, c))
- return true;
+ if (!casewindow_error (cw))
+ return cw->class->get_case (cw->aux, case_idx, c);
else
{
- casewindow_force_error (cw);
case_nullify (c);
return false;
}
@@ -193,14 +190,14 @@
};
static void *
-casewindow_memory_create (size_t value_cnt UNUSED)
+casewindow_memory_create (struct taint *taint UNUSED, size_t value_cnt UNUSED)
{
struct casewindow_memory *cwm = xmalloc (sizeof *cwm);
cwm->cases = deque_init (&cwm->deque, 4, sizeof *cwm->cases);
return cwm;
}
-static bool
+static void
casewindow_memory_destroy (void *cwm_)
{
struct casewindow_memory *cwm = cwm_;
@@ -208,27 +205,24 @@
case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]);
free (cwm->cases);
free (cwm);
- return true;
}
-static bool
+static void
casewindow_memory_push_head (void *cwm_, struct ccase *c)
{
struct casewindow_memory *cwm = cwm_;
if (deque_is_full (&cwm->deque))
cwm->cases = deque_expand (&cwm->deque, cwm->cases, sizeof *cwm->cases);
case_move (&cwm->cases[deque_push_back (&cwm->deque)], c);
- return true;
}
-static bool
+static void
casewindow_memory_pop_tail (void *cwm_, casenumber case_cnt)
{
struct casewindow_memory *cwm = cwm_;
assert (deque_count (&cwm->deque) >= case_cnt);
while (case_cnt-- > 0)
case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]);
- return true;
}
static bool
@@ -263,37 +257,32 @@
};
static void *
-casewindow_file_create (size_t value_cnt)
+casewindow_file_create (struct taint *taint, size_t value_cnt)
{
struct casewindow_file *cwf = xmalloc (sizeof *cwf);
cwf->file = case_tmpfile_create (value_cnt);
cwf->head = cwf->tail = 0;
+ taint_propagate (case_tmpfile_get_taint (cwf->file), taint);
return cwf;
}
-static bool
+static void
casewindow_file_destroy (void *cwf_)
{
struct casewindow_file *cwf = cwf_;
- bool ok = case_tmpfile_destroy (cwf->file);
+ case_tmpfile_destroy (cwf->file);
free (cwf);
- return ok;
}
-static bool
+static void
casewindow_file_push_head (void *cwf_, struct ccase *c)
{
struct casewindow_file *cwf = cwf_;
if (case_tmpfile_put_case (cwf->file, cwf->head, c))
- {
cwf->head++;
- return true;
- }
- else
- return false;
}
-static bool
+static void
casewindow_file_pop_tail (void *cwf_, casenumber cnt)
{
struct casewindow_file *cwf = cwf_;
@@ -301,7 +290,6 @@
cwf->tail += cnt;
if (cwf->head == cwf->tail)
cwf->head = cwf->tail = 0;
- return true;
}
static bool
Index: data/casereader.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casereader.h,v
retrieving revision 1.1.2.3
retrieving revision 1.1.2.4
diff -u -b -r1.1.2.3 -r1.1.2.4
--- data/casereader.h 4 May 2007 03:48:47 -0000 1.1.2.3
+++ data/casereader.h 6 May 2007 22:48:27 -0000 1.1.2.4
@@ -34,6 +34,7 @@
void casereader_split (struct casereader *,
struct casereader **, struct casereader **);
struct casereader *casereader_rename (struct casereader *);
+void casereader_swap (struct casereader *, struct casereader *);
bool casereader_peek (struct casereader *, casenumber, struct ccase *)
WARN_UNUSED_RESULT;
Index: data/casereader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casereader.c,v
retrieving revision 1.1.2.5
retrieving revision 1.1.2.6
diff -u -b -r1.1.2.5 -r1.1.2.6
--- data/casereader.c 4 May 2007 03:48:47 -0000 1.1.2.5
+++ data/casereader.c 6 May 2007 22:48:27 -0000 1.1.2.6
@@ -21,58 +21,77 @@
#include <data/casereader.h>
#include <data/casereader-private.h>
-#include <assert.h>
#include <stdlib.h>
#include <data/buffered-reader.h>
#include <data/casewindow.h>
#include <data/casewriter.h>
-#include <data/dictionary.h>
#include <data/settings.h>
-#include <data/variable.h>
-#include <libpspp/message.h>
+#include <libpspp/assertion.h>
#include <libpspp/taint.h>
#include "xalloc.h"
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
+/* A casereader. */
struct casereader
{
- struct taint *taint;
- size_t value_cnt;
- casenumber case_cnt;
- const struct casereader_class *class;
- void *aux;
+ struct taint *taint; /* Corrupted? */
+ size_t value_cnt; /* Values per case. */
+ casenumber case_cnt; /* Number of cases,
+ CASENUMBER_MAX if unknown. */
+ const struct casereader_class *class; /* Class. */
+ void *aux; /* Auxiliary data for class. */
};
static void insert_casereader_buffer (struct casereader *);
-struct casereader *
-casereader_rename (struct casereader *old)
+/* Creates a new case in C and reads the next case from READER
+ into it. The caller owns C and must destroy C when its data
+ is no longer needed. Return true if successful, false when
+ cases have been exhausted or upon detection of an I/O error.
+ In the latter case, C is set to the null case.
+
+ The case returned is effectively consumed: it can never be
+ read again through READER. If this is inconvenient, READER
+ may be cloned in advance with casereader_clone, or
+ casereader_peek may be used instead. */
+bool
+casereader_read (struct casereader *reader, struct ccase *c)
{
- struct casereader *new = xmalloc (sizeof *old);
- *new = *old;
- free (old);
- return new;
+ if (reader->case_cnt != 0 && reader->class->read (reader, reader->aux, c))
+ {
+ assert (case_get_value_cnt (c) == reader->value_cnt);
+ if (reader->case_cnt != CASENUMBER_MAX)
+ reader->case_cnt--;
+ return true;
+ }
+ else
+ {
+ reader->case_cnt = 0;
+ case_nullify (c);
+ return false;
+ }
}
-struct casereader *
-casereader_create (const struct taint *taint,
- size_t value_cnt, casenumber case_cnt,
- const struct casereader_class *class, void *aux)
+/* Destroys READER.
+ Returns false if an I/O error was detected on READER, true
+ otherwise. */
+bool
+casereader_destroy (struct casereader *reader)
{
- struct casereader *reader = xmalloc (sizeof *reader);
- assert (class->destroy != NULL);
- reader->taint = taint != NULL ? taint_clone (taint) : taint_create ();
- reader->value_cnt = value_cnt;
- reader->case_cnt = case_cnt;
- reader->class = class;
- reader->aux = aux;
- return reader;
+ bool ok = true;
+ if (reader != NULL)
+ {
+ reader->class->destroy (reader, reader->aux);
+ ok = taint_destroy (reader->taint);
+ free (reader);
+ }
+ return ok;
}
+/* Returns a clone of READER. READER and its clone may be used
+ to read the same sequence of cases in the same order, barring
+ I/O errors. */
struct casereader *
casereader_clone (const struct casereader *reader_)
{
@@ -87,17 +106,8 @@
return clone;
}
-static void
-casereader_swap (struct casereader *a, struct casereader *b)
-{
- if (a != b)
- {
- struct casereader tmp = *a;
- *a = *b;
- *b = tmp;
- }
-}
-
+/* Makes a copy of ORIGINAL into *NEW1 (if NEW1 is non-null) and
+ *NEW2 (if NEW2 is non-null), then destroys ORIGINAL. */
void
casereader_split (struct casereader *original,
struct casereader **new1, struct casereader **new2)
@@ -115,71 +125,107 @@
casereader_destroy (original);
}
-bool
-casereader_destroy (struct casereader *reader)
+/* Returns a copy of READER, which is itself destroyed.
+ Useful for taking over ownership of a casereader, to enforce
+ preventing the original owner from accessing the casereader
+ again. */
+struct casereader *
+casereader_rename (struct casereader *reader)
{
- bool ok = true;
- if (reader != NULL)
- {
- reader->class->destroy (reader, reader->aux);
- ok = taint_destroy (reader->taint);
+ struct casereader *new = xmemdup (reader, sizeof *reader);
free (reader);
- }
- return ok;
+ return new;
}
-bool
-casereader_read (struct casereader *reader, struct ccase *c)
+/* Exchanges the casereaders referred to by A and B. */
+void
+casereader_swap (struct casereader *a, struct casereader *b)
{
- if (reader->case_cnt != 0 && reader->class->read (reader, reader->aux, c))
- {
- //assert (case_get_value_cnt (c) == reader->value_cnt);
- if (reader->case_cnt != CASENUMBER_MAX)
- reader->case_cnt--;
- return true;
- }
- else
+ if (a != b)
{
- reader->case_cnt = 0;
- case_nullify (c);
- return false;
+ struct casereader tmp = *a;
+ *a = *b;
+ *b = tmp;
}
}
+/* Creates a new case in C and reads the (IDX + 1)'th case from
+ READER into it. The caller owns C and must destroy C when its
+ data is no longer needed. Return true if successful, false
+ when cases have been exhausted or upon detection of an I/O
+ error. In the latter case, C is set to the null case. */
bool
casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c)
{
- if (idx >= reader->case_cnt)
- return NULL;
+ if (idx < reader->case_cnt)
+ {
if (reader->class->peek == NULL)
insert_casereader_buffer (reader);
- return reader->class->peek (reader, reader->aux, idx, c);
+ if (reader->class->peek (reader, reader->aux, idx, c))
+ return true;
+ }
+ if (reader->case_cnt > idx)
+ reader->case_cnt = idx;
+ case_nullify (c);
+ return false;
}
+/* Returns true if an I/O error or another hard error has
+ occurred on READER, a clone of READER, or on some object on
+ which READER's data has a dependency, false otherwise. */
bool
casereader_error (const struct casereader *reader)
{
return taint_is_tainted (reader->taint);
}
+/* Marks READER as having encountered an error.
+
+ Ordinarily, this function should be called by the
+ implementation of a casereader, not by the casereader's
+ client. Instead, casereader clients should usually ensure
+ that a casereader's error state is correct by using
+ taint_propagate to propagate to the casereader's taint
+ structure, which may be obtained via casereader_get_taint. */
void
casereader_force_error (struct casereader *reader)
{
taint_set_taint (reader->taint);
}
+/* Returns READER's associate taint object, for use with
+ taint_propagate and other taint functions. */
const struct taint *
casereader_get_taint (const struct casereader *reader)
{
return reader->taint;
}
+/* Returns the number of cases that will be read by successive
+ calls to casereader_read for READER, assuming that no errors
+ occur. Upon an error condition, the case count drops to 0, so
+ that no more cases can be obtained.
+
+ Not all casereaders can predict the number of cases that they
+ will produce without actually reading all of them. In that
+ case, this function returns CASENUMBER_MAX. To obtain the
+ actual number of cases in such a casereader, use
+ casereader_count_cases. */
casenumber
casereader_get_case_cnt (struct casereader *reader)
{
return reader->case_cnt;
}
+/* Returns the number of cases that will be read by successive
+ calls to casereader_read for READER, assuming that no errors
+ occur. Upon an error condition, the case count drops to 0, so
+ that no more cases can be obtained.
+
+ For a casereader that cannot predict the number of cases it
+ will produce, this function actually reads (and discards) all
+ of the contents of a clone of READER. Thus, the return value
+ is always correct in the absence of I/O errors. */
casenumber
casereader_count_cases (struct casereader *reader)
{
@@ -198,12 +244,15 @@
return reader->case_cnt;
}
+/* Returns the number of struct values in each case in READER. */
size_t
casereader_get_value_cnt (struct casereader *reader)
{
return reader->value_cnt;
}
+/* Copies all the cases in READER to WRITER, propagating errors
+ appropriately. */
void
casereader_transfer (struct casereader *reader, struct casewriter *writer)
{
@@ -216,205 +265,76 @@
casereader_destroy (reader);
}
-struct casereader_filter
- {
- struct casereader *subreader;
- bool (*include) (const struct ccase *, void *aux);
- bool (*destroy) (void *aux);
- void *aux;
- struct casewriter *exclude;
- };
-
-static struct casereader_class casereader_filter_class;
-
+/* Creates and returns a new casereader. This function is
+ intended for use by casereader implementations, not be
+ casereader clients.
+
+ Ordinarily, specify a null pointer for TAINT, in which case
+ the new casereader will have a new, unique taint object. If
+ the new casereader should have a clone of an existing taint
+ object, specify that object as TAINT. (This is most commonly
+ useful in an implementation of the "clone" casereader_class
+ function, in which case the cloned casereader should have the
+ same taint object as the original casereader.)
+
+ VALUE_CNT must be the number of struct values per case read
+ from the casereader.
+
+ CASE_CNT should be the number of cases that casereader_read
+ will return from the casereader in successive calls. If the
+ number of cases cannot be predicted in advance, specify
+ CASENUMBER_MAX.
+
+ CLASS and AUX are a set of casereader implementation-specific
+ member functions and auxiliary data to pass to those member
+ functions, respectively. */
struct casereader *
-casereader_create_filter_func (struct casereader *subreader,
- bool (*include) (const struct ccase *,
- void *aux),
- bool (*destroy) (void *aux),
- void *aux,
- struct casewriter *exclude)
-{
- struct casereader_filter *filter = xmalloc (sizeof *filter);
- struct casereader *reader;
- filter->subreader = casereader_rename (subreader);
- filter->include = include;
- filter->destroy = destroy;
- filter->aux = aux;
- filter->exclude = exclude;
- reader = casereader_create (NULL,
- casereader_get_value_cnt (filter->subreader),
- CASENUMBER_MAX,
- &casereader_filter_class, filter);
- taint_propagate (casereader_get_taint (filter->subreader),
- casereader_get_taint (reader));
- return reader;
-}
-
-static bool
-casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
- struct ccase *c)
-
-{
- struct casereader_filter *filter = filter_;
- for (;;)
- {
- if (!casereader_read (filter->subreader, c))
- return false;
- else if (filter->include (c, filter->aux))
- return true;
- else if (filter->exclude != NULL)
- casewriter_write (filter->exclude, c);
- else
- case_destroy (c);
- }
-}
-
-static void
-casereader_filter_destroy (struct casereader *reader, void *filter_)
-{
- struct casereader_filter *filter = filter_;
- casereader_destroy (filter->subreader);
- if (filter->destroy != NULL && !filter->destroy (filter->aux))
- casereader_force_error (reader);
- free (filter);
-}
-
-static struct casereader_class casereader_filter_class =
- {
- casereader_filter_read,
- casereader_filter_destroy,
-
- /* We could in fact delegate clone to the subreader, if the
- filter function is required to have no memory and if we
- added reference counting. But it might be useful to have
- filter functions with memory and in any case this would
- require a little extra work. */
- NULL,
- };
-
-struct casereader_filter_weight
- {
- const struct variable *weight_var;
- bool *warn_on_invalid;
- bool local_warn_on_invalid;
- };
-
-static bool
-casereader_filter_weight_include (const struct ccase *c, void *cfw_)
-{
- struct casereader_filter_weight *cfw = cfw_;
- double value = case_num (c, cfw->weight_var);
- if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
- return true;
- else
- {
- if (*cfw->warn_on_invalid)
- {
- msg (SW, _("At least one case in the data read had a weight value "
- "that was user-missing, system-missing, zero, or "
- "negative. These case(s) were ignored."));
- *cfw->warn_on_invalid = false;
- }
- return false;
- }
-}
-
-static bool
-casereader_filter_weight_destroy (void *cfw_)
+casereader_create (const struct taint *taint,
+ size_t value_cnt, casenumber case_cnt,
+ const struct casereader_class *class, void *aux)
{
- struct casereader_filter_weight *cfw = cfw_;
- free (cfw);
- return true;
-}
-
-struct casereader *
-casereader_create_filter_weight (struct casereader *reader,
- const struct dictionary *dict,
- bool *warn_on_invalid,
- struct casewriter *exclude)
-{
- struct variable *weight_var = dict_get_weight (dict);
- if (weight_var != NULL)
- {
- struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
- cfw->weight_var = weight_var;
- cfw->warn_on_invalid = (warn_on_invalid
- ? warn_on_invalid
- : &cfw->local_warn_on_invalid);
- cfw->local_warn_on_invalid = true;
- reader = casereader_create_filter_func (reader,
- casereader_filter_weight_include,
- casereader_filter_weight_destroy,
- cfw, exclude);
- }
- else
- reader = casereader_rename (reader);
+ struct casereader *reader = xmalloc (sizeof *reader);
+ reader->taint = taint != NULL ? taint_clone (taint) : taint_create ();
+ reader->value_cnt = value_cnt;
+ reader->case_cnt = case_cnt;
+ reader->class = class;
+ reader->aux = aux;
return reader;
}
-struct casereader_filter_missing
- {
- struct variable **vars;
- size_t var_cnt;
- enum mv_class class;
- };
-
-static bool
-casereader_filter_missing_include (const struct ccase *c, void *cfm_)
-{
- const struct casereader_filter_missing *cfm = cfm_;
- size_t i;
-
- for (i = 0; i < cfm->var_cnt; i++)
- {
- struct variable *var = cfm->vars[i];
- const union value *value = case_data (c, var);
- if (var_is_value_missing (var, value, cfm->class))
- return false;
- }
- return true;
-}
-
-static bool
-casereader_filter_missing_destroy (void *cfm_)
-{
- struct casereader_filter_missing *cfm = cfm_;
- free (cfm->vars);
- free (cfm);
- return true;
-}
+/* Buffered casereader.
-struct casereader *
-casereader_create_filter_missing (struct casereader *reader,
- struct variable **vars, size_t var_cnt,
- enum mv_class class,
- struct casewriter *exclude)
-{
- if (var_cnt > 0 && class != MV_NEVER)
- {
- struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
- cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
- cfm->var_cnt = var_cnt;
- cfm->class = class;
- return casereader_create_filter_func (reader,
- casereader_filter_missing_include,
- casereader_filter_missing_destroy,
- cfm,
- exclude);
- }
- else
- return casereader_rename (reader);
-}
+ The "clone" and "peek" operations aren't implemented by all
+ types of casereaders, but we have to expose a uniform
+ interface anyhow. We do this by interposing a buffering
+ casereader on top of the existing casereader on the first call
+ to "clone" or "peek". The buffering casereader maintains a
+ window of cases that spans the positions of the original
+ casereader and all of its clones (the "clone set"), from the
+ position of the casereader that has read the fewest cases to
+ the position of the casereader that has read the most.
+
+ Thus, if all of the casereaders in the clone set are at
+ approximately the same position, only a few cases are buffered
+ and there is little inefficiency. If, on the other hand, one
+ casereader is not used to read any cases at all, but another
+ one is used to read all of the cases, the entire contents of
+ the casereader is copied into the buffer. This still might
+ not be so inefficient, given that case data in memory is
+ shared across multiple identical copies, but in the worst case
+ the window implementation will write cases to disk instead of
+ maintaining them in-memory. */
+/* A buffered casereader. */
struct casereader_buffer
{
- struct casewindow *window;
- struct casereader *subreader;
+ struct casewindow *window; /* Window of buffered cases. */
+ struct casereader *subreader; /* Subordinate casereader. */
};
static struct buffered_reader_class casereader_buffer_class;
+/* Interposes a buffered casereader atop of READER. */
static void
insert_casereader_buffer (struct casereader *reader)
{
@@ -425,14 +345,15 @@
b->subreader = buffered_reader_create (NULL, value_cnt, case_cnt,
&casereader_buffer_class, b);
casereader_swap (reader, b->subreader);
- /* Should we do these propagations or should we clone one of
- them and pass it to buffered_reader_create? */
taint_propagate (casewindow_get_taint (b->window),
casereader_get_taint (reader));
taint_propagate (casereader_get_taint (b->subreader),
casereader_get_taint (reader));
}
+/* Ensures that B's window contains at least CASE_CNT cases.
+ Return true if successful, false upon reaching the end of B's
+ subreader or an I/O error. */
static bool
prime_casereader_buffer (struct casereader_buffer *b, casenumber case_cnt)
{
@@ -446,6 +367,9 @@
return true;
}
+/* Reads the case at the given 0-based OFFSET from the front of
+ the window into C. Returns true if successful, false if
+ OFFSET is beyond the end of file or upon I/O error. */
static bool
casereader_buffer_read (void *b_, casenumber offset, struct ccase *c)
{
@@ -454,6 +378,7 @@
&& casewindow_get_case (b->window, offset, c));
}
+/* Destroys B. */
static void
casereader_buffer_destroy (void *b_)
{
@@ -463,6 +388,7 @@
free (b);
}
+/* Discards CNT cases from the front of B's window. */
static void
casereader_buffer_advance (void *b_, casenumber cnt)
{
@@ -470,92 +396,10 @@
casewindow_pop_tail (b->window, cnt);
}
+/* Class for the buffered reader. */
static struct buffered_reader_class casereader_buffer_class =
{
casereader_buffer_read,
casereader_buffer_destroy,
casereader_buffer_advance,
};
-
-static bool
-casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
-{
- casenumber *counter = counter_;
- ++*counter;
- return true;
-}
-
-struct casereader *
-casereader_create_counter (struct casereader *reader, casenumber *counter,
- casenumber initial_value)
-{
- *counter = initial_value;
- return casereader_create_filter_func (reader, casereader_counter_include,
- NULL, counter, NULL);
-}
-
-struct casereader_translator
- {
- struct casereader *subreader;
-
- void (*translate) (const struct ccase *input, struct ccase *output,
- void *aux);
- bool (*destroy) (void *aux);
- void *aux;
- };
-
-static struct casereader_class casereader_translator_class;
-
-struct casereader *
-casereader_create_translator (struct casereader *subreader,
- size_t output_value_cnt,
- void (*translate) (const struct ccase *input,
- struct ccase *output,
- void *aux),
- bool (*destroy) (void *aux),
- void *aux)
-{
- struct casereader_translator *ct = xmalloc (sizeof *ct);
- struct casereader *reader;
- ct->subreader = casereader_rename (subreader);
- ct->translate = translate;
- ct->destroy = destroy;
- ct->aux = aux;
- reader = casereader_create (NULL, output_value_cnt,
- casereader_get_case_cnt (ct->subreader),
- &casereader_translator_class, ct);
- taint_propagate (casereader_get_taint (ct->subreader),
- casereader_get_taint (reader));
- return reader;
-}
-
-static bool
-casereader_translator_read (struct casereader *reader UNUSED,
- void *ct_, struct ccase *c)
-{
- struct casereader_translator *ct = ct_;
- struct ccase tmp;
-
- if (casereader_read (ct->subreader, &tmp))
- {
- ct->translate (&tmp, c, ct->aux);
- return true;
- }
- else
- return false;
-}
-
-static void
-casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
-{
- struct casereader_translator *ct = ct_;
- casereader_destroy (ct->subreader);
- ct->destroy (ct->aux);
- free (ct);
-}
-
-static struct casereader_class casereader_translator_class =
- {
- casereader_translator_read,
- casereader_translator_destroy,
- };
Index: data/case-tmpfile.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/case-tmpfile.h,v
retrieving revision 1.1.2.2
retrieving revision 1.1.2.3
diff -u -b -r1.1.2.2 -r1.1.2.3
--- data/case-tmpfile.h 14 Apr 2007 05:04:23 -0000 1.1.2.2
+++ data/case-tmpfile.h 6 May 2007 22:48:27 -0000 1.1.2.3
@@ -23,7 +23,10 @@
struct case_tmpfile *case_tmpfile_create (size_t value_cnt);
bool case_tmpfile_destroy (struct case_tmpfile *);
+
bool case_tmpfile_error (const struct case_tmpfile *);
+void case_tmpfile_force_error (struct case_tmpfile *);
+const struct taint *case_tmpfile_get_taint (const struct case_tmpfile *);
bool case_tmpfile_get_values (const struct case_tmpfile *,
casenumber, size_t start_value,
Index: data/case-tmpfile.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/case-tmpfile.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -u -b -r1.1.2.4 -r1.1.2.5
--- data/case-tmpfile.c 5 May 2007 21:55:48 -0000 1.1.2.4
+++ data/case-tmpfile.c 6 May 2007 22:48:27 -0000 1.1.2.5
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <libpspp/assertion.h>
+#include <libpspp/taint.h>
#include "error.h"
#include "xalloc.h"
@@ -42,6 +43,7 @@
struct case_tmpfile
{
+ struct taint *taint;
FILE *file;
size_t value_cnt;
off_t position;
@@ -51,9 +53,13 @@
case_tmpfile_create (size_t value_cnt)
{
struct case_tmpfile *ctf = xmalloc (sizeof *ctf);
+ ctf->taint = taint_create ();
ctf->file = tmpfile ();
if (ctf->file == NULL)
+ {
error (0, errno, _("failed to create temporary file"));
+ taint_set_taint (ctf->taint);
+ }
ctf->value_cnt = value_cnt;
ctf->position = 0;
return ctf;
@@ -62,33 +68,34 @@
bool
case_tmpfile_destroy (struct case_tmpfile *ctf)
{
+ bool ok = true;
if (ctf != NULL)
{
- bool ok = !case_tmpfile_error (ctf);
+ struct taint *taint = ctf->taint;
if (ctf->file != NULL)
fclose (ctf->file);
free (ctf);
- return ok;
+ ok = taint_destroy (taint);
}
- else
- return true;
+ return ok;
}
bool
case_tmpfile_error (const struct case_tmpfile *ctf)
{
- return ctf->file == NULL;
+ return taint_is_tainted (ctf->taint);
}
-static void
-mark_error (const struct case_tmpfile *ctf_)
+void
+case_tmpfile_force_error (struct case_tmpfile *ctf)
{
- struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
- if (ctf->file != NULL)
- {
- fclose (ctf->file);
- ctf->file = NULL;
- }
+ taint_set_taint (ctf->taint);
+}
+
+const struct taint *
+case_tmpfile_get_taint (const struct case_tmpfile *ctf)
+{
+ return ctf->taint;
}
static bool
@@ -112,7 +119,7 @@
else
{
error (0, errno, _("seeking in temporary file"));
- mark_error (ctf);
+ case_tmpfile_force_error (ctf);
}
}
@@ -127,7 +134,7 @@
assert (!case_tmpfile_error (ctf));
if (fread (buffer, bytes, 1, ctf->file) != 1)
{
- mark_error (ctf);
+ case_tmpfile_force_error (ctf);
if (ferror (ctf->file))
error (0, errno, _("reading temporary file"));
else if (feof (ctf->file))
@@ -146,7 +153,7 @@
assert (!case_tmpfile_error (ctf));
if (fwrite (buffer, bytes, 1, ctf->file) != 1)
{
- mark_error (ctf);
+ case_tmpfile_force_error (ctf);
error (0, errno, _("writing to temporary file"));
return false;
}
Index: data/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/automake.mk,v
retrieving revision 1.15.2.2
retrieving revision 1.15.2.3
diff -u -b -r1.15.2.2 -r1.15.2.3
--- data/automake.mk 14 Apr 2007 05:04:23 -0000 1.15.2.2
+++ data/automake.mk 6 May 2007 22:48:27 -0000 1.15.2.3
@@ -18,6 +18,8 @@
src/data/caseinit.c \
src/data/caseinit.h \
src/data/casereader.c \
+ src/data/casereader-filter.c \
+ src/data/casereader-translator.c \
src/data/casereader.h \
src/data/casereader-private.h \
src/data/case-tmpfile.c \
Index: data/casereader-translator.c
===================================================================
RCS file: data/casereader-translator.c
diff -N data/casereader-translator.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ data/casereader-translator.c 6 May 2007 22:48:27 -0000 1.1.2.1
@@ -0,0 +1,94 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casereader.h>
+
+#include <stdlib.h>
+
+#include <data/casereader-private.h>
+#include <libpspp/taint.h>
+
+#include "xalloc.h"
+
+struct casereader_translator
+ {
+ struct casereader *subreader;
+
+ void (*translate) (const struct ccase *input, struct ccase *output,
+ void *aux);
+ bool (*destroy) (void *aux);
+ void *aux;
+ };
+
+static struct casereader_class casereader_translator_class;
+
+struct casereader *
+casereader_create_translator (struct casereader *subreader,
+ size_t output_value_cnt,
+ void (*translate) (const struct ccase *input,
+ struct ccase *output,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux)
+{
+ struct casereader_translator *ct = xmalloc (sizeof *ct);
+ struct casereader *reader;
+ ct->subreader = casereader_rename (subreader);
+ ct->translate = translate;
+ ct->destroy = destroy;
+ ct->aux = aux;
+ reader = casereader_create (NULL, output_value_cnt,
+ casereader_get_case_cnt (ct->subreader),
+ &casereader_translator_class, ct);
+ taint_propagate (casereader_get_taint (ct->subreader),
+ casereader_get_taint (reader));
+ return reader;
+}
+
+static bool
+casereader_translator_read (struct casereader *reader UNUSED,
+ void *ct_, struct ccase *c)
+{
+ struct casereader_translator *ct = ct_;
+ struct ccase tmp;
+
+ if (casereader_read (ct->subreader, &tmp))
+ {
+ ct->translate (&tmp, c, ct->aux);
+ return true;
+ }
+ else
+ return false;
+}
+
+static void
+casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
+{
+ struct casereader_translator *ct = ct_;
+ casereader_destroy (ct->subreader);
+ ct->destroy (ct->aux);
+ free (ct);
+}
+
+static struct casereader_class casereader_translator_class =
+ {
+ casereader_translator_read,
+ casereader_translator_destroy,
+ };
Index: data/casereader-filter.c
===================================================================
RCS file: data/casereader-filter.c
diff -N data/casereader-filter.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ data/casereader-filter.c 6 May 2007 22:48:27 -0000 1.1.2.1
@@ -0,0 +1,244 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casereader.h>
+
+#include <stdlib.h>
+
+#include <data/casereader-private.h>
+#include <data/casewriter.h>
+#include <data/variable.h>
+#include <data/dictionary.h>
+#include <libpspp/taint.h>
+#include <libpspp/message.h>
+
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct casereader_filter
+ {
+ struct casereader *subreader;
+ bool (*include) (const struct ccase *, void *aux);
+ bool (*destroy) (void *aux);
+ void *aux;
+ struct casewriter *exclude;
+ };
+
+static struct casereader_class casereader_filter_class;
+
+struct casereader *
+casereader_create_filter_func (struct casereader *subreader,
+ bool (*include) (const struct ccase *,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux,
+ struct casewriter *exclude)
+{
+ struct casereader_filter *filter = xmalloc (sizeof *filter);
+ struct casereader *reader;
+ filter->subreader = casereader_rename (subreader);
+ filter->include = include;
+ filter->destroy = destroy;
+ filter->aux = aux;
+ filter->exclude = exclude;
+ reader = casereader_create (NULL,
+ casereader_get_value_cnt (filter->subreader),
+ CASENUMBER_MAX,
+ &casereader_filter_class, filter);
+ taint_propagate (casereader_get_taint (filter->subreader),
+ casereader_get_taint (reader));
+ return reader;
+}
+
+static bool
+casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
+ struct ccase *c)
+
+{
+ struct casereader_filter *filter = filter_;
+ for (;;)
+ {
+ if (!casereader_read (filter->subreader, c))
+ return false;
+ else if (filter->include (c, filter->aux))
+ return true;
+ else if (filter->exclude != NULL)
+ casewriter_write (filter->exclude, c);
+ else
+ case_destroy (c);
+ }
+}
+
+static void
+casereader_filter_destroy (struct casereader *reader, void *filter_)
+{
+ struct casereader_filter *filter = filter_;
+ casereader_destroy (filter->subreader);
+ if (filter->destroy != NULL && !filter->destroy (filter->aux))
+ casereader_force_error (reader);
+ free (filter);
+}
+
+static struct casereader_class casereader_filter_class =
+ {
+ casereader_filter_read,
+ casereader_filter_destroy,
+
+ /* We could in fact delegate clone to the subreader, if the
+ filter function is required to have no memory and if we
+ added reference counting. But it might be useful to have
+ filter functions with memory and in any case this would
+ require a little extra work. */
+ NULL,
+ };
+
+struct casereader_filter_weight
+ {
+ const struct variable *weight_var;
+ bool *warn_on_invalid;
+ bool local_warn_on_invalid;
+ };
+
+static bool
+casereader_filter_weight_include (const struct ccase *c, void *cfw_)
+{
+ struct casereader_filter_weight *cfw = cfw_;
+ double value = case_num (c, cfw->weight_var);
+ if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
+ return true;
+ else
+ {
+ if (*cfw->warn_on_invalid)
+ {
+ msg (SW, _("At least one case in the data read had a weight value "
+ "that was user-missing, system-missing, zero, or "
+ "negative. These case(s) were ignored."));
+ *cfw->warn_on_invalid = false;
+ }
+ return false;
+ }
+}
+
+static bool
+casereader_filter_weight_destroy (void *cfw_)
+{
+ struct casereader_filter_weight *cfw = cfw_;
+ free (cfw);
+ return true;
+}
+
+struct casereader *
+casereader_create_filter_weight (struct casereader *reader,
+ const struct dictionary *dict,
+ bool *warn_on_invalid,
+ struct casewriter *exclude)
+{
+ struct variable *weight_var = dict_get_weight (dict);
+ if (weight_var != NULL)
+ {
+ struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
+ cfw->weight_var = weight_var;
+ cfw->warn_on_invalid = (warn_on_invalid
+ ? warn_on_invalid
+ : &cfw->local_warn_on_invalid);
+ cfw->local_warn_on_invalid = true;
+ reader = casereader_create_filter_func (reader,
+ casereader_filter_weight_include,
+ casereader_filter_weight_destroy,
+ cfw, exclude);
+ }
+ else
+ reader = casereader_rename (reader);
+ return reader;
+}
+
+struct casereader_filter_missing
+ {
+ struct variable **vars;
+ size_t var_cnt;
+ enum mv_class class;
+ };
+
+static bool
+casereader_filter_missing_include (const struct ccase *c, void *cfm_)
+{
+ const struct casereader_filter_missing *cfm = cfm_;
+ size_t i;
+
+ for (i = 0; i < cfm->var_cnt; i++)
+ {
+ struct variable *var = cfm->vars[i];
+ const union value *value = case_data (c, var);
+ if (var_is_value_missing (var, value, cfm->class))
+ return false;
+ }
+ return true;
+}
+
+static bool
+casereader_filter_missing_destroy (void *cfm_)
+{
+ struct casereader_filter_missing *cfm = cfm_;
+ free (cfm->vars);
+ free (cfm);
+ return true;
+}
+
+struct casereader *
+casereader_create_filter_missing (struct casereader *reader,
+ struct variable **vars, size_t var_cnt,
+ enum mv_class class,
+ struct casewriter *exclude)
+{
+ if (var_cnt > 0 && class != MV_NEVER)
+ {
+ struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
+ cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
+ cfm->var_cnt = var_cnt;
+ cfm->class = class;
+ return casereader_create_filter_func (reader,
+ casereader_filter_missing_include,
+ casereader_filter_missing_destroy,
+ cfm,
+ exclude);
+ }
+ else
+ return casereader_rename (reader);
+}
+
+
+static bool
+casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
+{
+ casenumber *counter = counter_;
+ ++*counter;
+ return true;
+}
+
+struct casereader *
+casereader_create_counter (struct casereader *reader, casenumber *counter,
+ casenumber initial_value)
+{
+ *counter = initial_value;
+ return casereader_create_filter_func (reader, casereader_counter_include,
+ NULL, counter, NULL);
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Pspp-cvs] pspp/src ui/gui/val-labs-dialog.h math/sort.c d... [simpler-proc],
Ben Pfaff <=