pspp-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pspp-cvs] pspp/src/data datasheet.c casereader.c ChangeLog


From: Ben Pfaff
Subject: [Pspp-cvs] pspp/src/data datasheet.c casereader.c ChangeLog
Date: Tue, 02 Oct 2007 04:13:08 +0000

CVSROOT:        /cvsroot/pspp
Module name:    pspp
Changes by:     Ben Pfaff <blp> 07/10/02 04:13:07

Modified files:
        src/data       : datasheet.c casereader.c ChangeLog 

Log message:
        Fix bug #21192.  Thanks to John Darrington for review.
        
        * casereader.c (casereader_read): Decrement case_cnt before
        calling the casereader's "read" member function, so that we
        interact properly with lazy_casereader.
        
        * datasheet.c: Add regression test for above bug fix.
        (clone_datasheet): New function.
        (lazy_callback): New function.
        (check_datasheet_casereader): New function.
        (check_datasheet): Check datasheet contents are reported correctly
        through an ordinary casereader and a lazy casereader.
        (clone_model): Use clone_datasheet.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/datasheet.c?cvsroot=pspp&r1=1.8&r2=1.9
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.c?cvsroot=pspp&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/ChangeLog?cvsroot=pspp&r1=1.161&r2=1.162

Patches:
Index: datasheet.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/datasheet.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- datasheet.c 13 Sep 2007 12:37:09 -0000      1.8
+++ datasheet.c 2 Oct 2007 04:13:07 -0000       1.9
@@ -24,6 +24,7 @@
 #include <data/casereader-provider.h>
 #include <data/casereader.h>
 #include <data/casewriter.h>
+#include <data/lazy-casereader.h>
 #include <data/sparse-cases.h>
 #include <libpspp/array.h>
 #include <libpspp/assertion.h>
@@ -1258,6 +1259,93 @@
   return hash[0];
 }
 
+/* Clones the structure and contents of ODS into a new datasheet,
+   and returns the new datasheet. */
+static struct datasheet *
+clone_datasheet (const struct datasheet *ods)
+{
+  struct datasheet *ds;
+  struct range_map_node *r;
+
+  ds = xmalloc (sizeof *ds);
+  ds->columns = axis_clone (ods->columns);
+  ds->rows = axis_clone (ods->rows);
+  range_map_init (&ds->sources);
+  for (r = range_map_first (&ods->sources); r != NULL;
+       r = range_map_next (&ods->sources, r))
+    {
+      const struct source_info *osi = source_info_from_range_map (r);
+      struct source_info *si = xmalloc (sizeof *si);
+      si->source = source_clone (osi->source);
+      range_map_insert (&ds->sources, range_map_node_get_start (r),
+                        range_map_node_get_width (r), &si->column_range);
+    }
+  ds->column_min_alloc = ods->column_min_alloc;
+  ds->taint = taint_create ();
+
+  return ds;
+}
+
+/* lazy_casereader callback function to instantiate a casereader
+   from the datasheet. */
+static struct casereader *
+lazy_callback (void *ds_)
+{
+  struct datasheet *ds = ds_;
+  return datasheet_make_reader (ds);
+}
+
+/* Checks that READER contains the ROW_CNT rows and COLUMN_CNT
+   columns of data in ARRAY, reporting any errors via MC. */
+static void
+check_datasheet_casereader (struct mc *mc, struct casereader *reader,
+                            double array[MAX_ROWS][MAX_COLS],
+                            size_t row_cnt, size_t column_cnt)
+{
+  if (casereader_get_case_cnt (reader) != row_cnt)
+    {
+      if (casereader_get_case_cnt (reader) == CASENUMBER_MAX
+          && casereader_count_cases (reader) == row_cnt)
+        mc_error (mc, "datasheet casereader has unknown case count");
+      else
+        mc_error (mc, "casereader row count (%lu) does not match "
+                  "expected (%zu)",
+                  (unsigned long int) casereader_get_case_cnt (reader),
+                  row_cnt);
+    }
+  else if (casereader_get_value_cnt (reader) != column_cnt)
+    mc_error (mc, "casereader column count (%zu) does not match "
+              "expected (%zu)",
+              casereader_get_value_cnt (reader), column_cnt);
+  else
+    {
+      struct ccase c;
+      size_t row;
+
+      for (row = 0; row < row_cnt; row++)
+        {
+          size_t col;
+
+          if (!casereader_read (reader, &c))
+            {
+              mc_error (mc, "casereader_read failed reading row %zu of %zu "
+                        "(%zu columns)", row, row_cnt, column_cnt);
+              return;
+            }
+
+          for (col = 0; col < column_cnt; col++)
+            if (case_num_idx (&c, col) != array[row][col])
+              mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: "
+                        "%g != %g",
+                        row, col, row_cnt, column_cnt,
+                        case_num_idx (&c, col), array[row][col]);
+        }
+
+      if (casereader_read (reader, &c))
+        mc_error (mc, "casereader has extra cases (expected %zu)", row_cnt);
+    }
+}
+
 /* Checks that datasheet DS contains has ROW_CNT rows, COLUMN_CNT
    columns, and the same contents as ARRAY, reporting any
    mismatches via mc_error.  Then, adds DS to MC as a new state. */
@@ -1266,6 +1354,10 @@
                  double array[MAX_ROWS][MAX_COLS],
                  size_t row_cnt, size_t column_cnt)
 {
+  struct datasheet *ds2;
+  struct casereader *reader;
+  unsigned long int serial = 0;
+
   assert (row_cnt < MAX_ROWS);
   assert (column_cnt < MAX_COLS);
 
@@ -1277,6 +1369,7 @@
       return;
     }
 
+  /* Check contents of datasheet via datasheet functions. */
   if (row_cnt != datasheet_get_row_cnt (ds))
     mc_error (mc, "row count (%lu) does not match expected (%zu)",
               (unsigned long int) datasheet_get_row_cnt (ds), row_cnt);
@@ -1299,6 +1392,43 @@
           }
     }
 
+  /* Check that datasheet contents are correct when read through
+     casereader. */
+  ds2 = clone_datasheet (ds);
+  reader = datasheet_make_reader (ds2);
+  check_datasheet_casereader (mc, reader, array, row_cnt, column_cnt);
+  casereader_destroy (reader);
+
+  /* Check that datasheet contents are correct when read through
+     casereader with lazy_casereader wrapped around it.  This is
+     valuable because otherwise there is no non-GUI code that
+     uses the lazy_casereader. */
+  ds2 = clone_datasheet (ds);
+  reader = lazy_casereader_create (column_cnt, row_cnt,
+                                   lazy_callback, ds2, &serial);
+  check_datasheet_casereader (mc, reader, array, row_cnt, column_cnt);
+  if (lazy_casereader_destroy (reader, serial))
+    {
+      /* Lazy casereader was never instantiated.  This will
+         only happen if there are no rows (because in that case
+         casereader_read never gets called). */
+      datasheet_destroy (ds2);
+      if (row_cnt != 0)
+        mc_error (mc, "lazy casereader not instantiated, but should "
+                  "have been (size %zu,%zu)", row_cnt, column_cnt);
+    }
+  else
+    {
+      /* Lazy casereader was instantiated.  This is the common
+         case, in which some casereader operation
+         (casereader_read in this case) was performed on the
+         lazy casereader. */
+      casereader_destroy (reader);
+      if (row_cnt == 0)
+        mc_error (mc, "lazy casereader instantiated, but should not "
+                  "have been (size %zu,%zu)", row_cnt, column_cnt);
+    }
+
   mc_add_state (mc, ds);
 }
 
@@ -1326,29 +1456,9 @@
    and the contents of ODATA into DATA. */
 static void
 clone_model (const struct datasheet *ods, double odata[MAX_ROWS][MAX_COLS],
-             struct datasheet **ds_, double data[MAX_ROWS][MAX_COLS])
+             struct datasheet **ds, double data[MAX_ROWS][MAX_COLS])
 {
-  struct datasheet *ds;
-  struct range_map_node *r;
-
-  /* Clone ODS into DS. */
-  ds = *ds_ = xmalloc (sizeof *ds);
-  ds->columns = axis_clone (ods->columns);
-  ds->rows = axis_clone (ods->rows);
-  range_map_init (&ds->sources);
-  for (r = range_map_first (&ods->sources); r != NULL;
-       r = range_map_next (&ods->sources, r))
-    {
-      const struct source_info *osi = source_info_from_range_map (r);
-      struct source_info *si = xmalloc (sizeof *si);
-      si->source = source_clone (osi->source);
-      range_map_insert (&ds->sources, range_map_node_get_start (r),
-                        range_map_node_get_width (r), &si->column_range);
-    }
-  ds->column_min_alloc = ods->column_min_alloc;
-  ds->taint = taint_create ();
-
-  /* Clone ODATA into DATA. */
+  *ds = clone_datasheet (ods);
   memcpy (data, odata, MAX_ROWS * MAX_COLS * sizeof **data);
 }
 

Index: casereader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/casereader.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- casereader.c        19 Sep 2007 04:29:00 -0000      1.7
+++ casereader.c        2 Oct 2007 04:13:07 -0000       1.8
@@ -56,19 +56,30 @@
 bool
 casereader_read (struct casereader *reader, struct ccase *c)
 {
-  if (reader->case_cnt != 0 && reader->class->read (reader, reader->aux, c))
+  if (reader->case_cnt != 0)
     {
-      assert (case_get_value_cnt (c) >= reader->value_cnt);
+      /* ->read may use casereader_swap to replace itself by
+         another reader and then delegate to that reader by
+         recursively calling casereader_read.  Currently only
+         lazy_casereader does this and, with luck, nothing else
+         ever will.
+
+         To allow this to work, however, we must decrement
+         case_cnt before calling ->read.  If we decremented
+         case_cnt after calling ->read, then this would actually
+         drop two cases from case_cnt instead of one, and we'd
+         lose the last case in the casereader. */
       if (reader->case_cnt != CASENUMBER_MAX)
         reader->case_cnt--;
+      if (reader->class->read (reader, reader->aux, c))
+        {
+          assert (case_get_value_cnt (c) >= reader->value_cnt);
       return true;
     }
-  else
-    {
+    }
       reader->case_cnt = 0;
       case_nullify (c);
       return false;
-    }
 }
 
 /* Destroys READER.

Index: ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/ChangeLog,v
retrieving revision 1.161
retrieving revision 1.162
diff -u -b -r1.161 -r1.162
--- ChangeLog   25 Sep 2007 04:26:25 -0000      1.161
+++ ChangeLog   2 Oct 2007 04:13:07 -0000       1.162
@@ -1,3 +1,19 @@
+2007-10-01  Ben Pfaff  <address@hidden>
+
+       Fix bug #21192.  Thanks to John Darrington for review.
+
+       * casereader.c (casereader_read): Decrement case_cnt before
+       calling the casereader's "read" member function, so that we
+       interact properly with lazy_casereader.
+
+       * datasheet.c: Add regression test for above bug fix.
+       (clone_datasheet): New function.
+       (lazy_callback): New function.
+       (check_datasheet_casereader): New function.
+       (check_datasheet): Check datasheet contents are reported correctly
+       through an ordinary casereader and a lazy casereader.
+       (clone_model): Use clone_datasheet.
+
 2007-09-24  Ben Pfaff  <address@hidden>
 
        Patch #6210.  Reviewed by John Darrington.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]