casereader: New function casereader_advance().
[pspp-builds.git] / src / data / casereader.c
index a1550ac57560e5fb623d12ede14b7e1a65ca661b..77278851e6c90c324ae455e248fb114ac16d8401 100644 (file)
@@ -108,7 +108,7 @@ casereader_destroy (struct casereader *reader)
 struct casereader *
 casereader_clone (const struct casereader *reader_)
 {
-  struct casereader *reader = (struct casereader *) reader_;
+  struct casereader *reader = CONST_CAST (struct casereader *, reader_);
   struct casereader *clone;
   if ( reader == NULL ) 
     return NULL;
@@ -257,6 +257,19 @@ casereader_get_case_cnt (struct casereader *reader)
   return reader->case_cnt;
 }
 
+static casenumber
+casereader_count_cases__ (struct casereader *reader, casenumber max_cases)
+{
+  struct casereader *clone;
+  casenumber n_cases;
+
+  clone = casereader_clone (reader);
+  n_cases = casereader_advance (clone, max_cases);
+  casereader_destroy (clone);
+
+  return n_cases;
+}
+
 /* 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
@@ -270,22 +283,24 @@ casenumber
 casereader_count_cases (struct casereader *reader)
 {
   if (reader->case_cnt == CASENUMBER_MAX)
-    {
-      casenumber n_cases = 0;
-      struct ccase *c;
-
-      struct casereader *clone = casereader_clone (reader);
-
-      for (; (c = casereader_read (clone)) != NULL; case_unref (c))
-        n_cases++;
-
-      casereader_destroy (clone);
-      reader->case_cnt = n_cases;
-    }
-
+    reader->case_cnt = casereader_count_cases__ (reader, CASENUMBER_MAX);
   return reader->case_cnt;
 }
 
+/* Truncates READER to at most N cases. */
+void
+casereader_truncate (struct casereader *reader, casenumber n)
+{
+  /* This could be optimized, if it ever becomes too expensive, by adding a
+     "max_cases" member to struct casereader.  We could also add a "truncate"
+     function to the casereader implementation, to allow the casereader to
+     throw away data that cannot ever be read. */
+  if (reader->case_cnt == CASENUMBER_MAX)
+    reader->case_cnt = casereader_count_cases__ (reader, n);
+  if (reader->case_cnt > n)
+    reader->case_cnt = n;
+}
+
 /* Returns the prototype for the cases in READER.  The caller
    must not unref the returned prototype. */
 const struct caseproto *
@@ -294,6 +309,26 @@ casereader_get_proto (const struct casereader *reader)
   return reader->proto;
 }
 
+/* Skips past N cases in READER, stopping when the last case in
+   READER has been read or on an input error.  Returns the number
+   of cases successfully skipped. */
+casenumber
+casereader_advance (struct casereader *reader, casenumber n)
+{
+  casenumber i;
+
+  for (i = 0; i < n; i++)
+    {
+      struct ccase *c = casereader_read (reader);
+      if (c == NULL)
+        break;
+      case_unref (c);
+    }
+
+  return i;
+}
+
+
 /* Copies all the cases in READER to WRITER, propagating errors
    appropriately. */
 void