Change "union value" to dynamically allocate long strings.
[pspp-builds.git] / src / data / casewriter.c
index 4461d85e84cfc191821746df34e44b02dfc0f4ef..f7760eca04a5ae5d1b78bf45c46c92676b63a0c7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
 
    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
@@ -26,6 +26,7 @@
 #include <data/casereader-provider.h>
 #include <data/casewindow.h>
 #include <data/settings.h>
 #include <data/casereader-provider.h>
 #include <data/casewindow.h>
 #include <data/settings.h>
+#include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
 #include <libpspp/taint.h>
 
 #include <libpspp/compiler.h>
 #include <libpspp/taint.h>
 
 struct casewriter
   {
     struct taint *taint;
 struct casewriter
   {
     struct taint *taint;
-    size_t value_cnt;
+    struct caseproto *proto;
     casenumber case_cnt;
     const struct casewriter_class *class;
     void *aux;
   };
 
     casenumber case_cnt;
     const struct casewriter_class *class;
     void *aux;
   };
 
-static struct casewriter *create_casewriter_window (size_t value_cnt,
+static struct casewriter *create_casewriter_window (const struct caseproto *,
                                                     casenumber max_in_core);
 
                                                     casenumber max_in_core);
 
-/* Writes case C to WRITER. */
+/* Writes case C to WRITER.  Ownership of C is transferred to
+   WRITER. */
 void
 casewriter_write (struct casewriter *writer, struct ccase *c)
 {
 void
 casewriter_write (struct casewriter *writer, struct ccase *c)
 {
-  assert (case_get_value_cnt (c) >= writer->value_cnt);
+  size_t n_widths UNUSED = caseproto_get_n_widths (writer->proto);
+  assert (case_get_value_cnt (c) >= n_widths);
+  expensive_assert (caseproto_equal (case_get_proto (c), 0,
+                                     writer->proto, 0, n_widths));
   writer->class->write (writer, writer->aux, c);
 }
 
   writer->class->write (writer, writer->aux, c);
 }
 
@@ -64,17 +69,18 @@ casewriter_destroy (struct casewriter *writer)
     {
       writer->class->destroy (writer, writer->aux);
       ok = taint_destroy (writer->taint);
     {
       writer->class->destroy (writer, writer->aux);
       ok = taint_destroy (writer->taint);
+      caseproto_unref (writer->proto);
       free (writer);
     }
   return ok;
 }
 
       free (writer);
     }
   return ok;
 }
 
-/* Returns the number of `union value's in each case written to
-   WRITER. */
-size_t
-casewriter_get_value_cnt (const struct casewriter *writer)
+/* Returns the prototype for that cases written to WRITER must
+   follow. */
+const struct caseproto *
+casewriter_get_proto (const struct casewriter *writer)
 {
 {
-  return writer->value_cnt;
+  return writer->proto;
 }
 
 /* Destroys WRITER and in its place returns a casereader that can
 }
 
 /* Destroys WRITER and in its place returns a casereader that can
@@ -142,23 +148,24 @@ casewriter_get_taint (const struct casewriter *writer)
 }
 
 /* Creates and returns a new casewriter with the given CLASS and
 }
 
 /* Creates and returns a new casewriter with the given CLASS and
-   auxiliary data AUX.  The casewriter accepts cases with
-   VALUE_CNT `union value's. */
+   auxiliary data AUX.  The casewriter accepts cases that match
+   case prototype PROTO, of which the caller retains
+   ownership. */
 struct casewriter *
 struct casewriter *
-casewriter_create (size_t value_cnt,
+casewriter_create (const struct caseproto *proto,
                    const struct casewriter_class *class, void *aux)
 {
   struct casewriter *writer = xmalloc (sizeof *writer);
   writer->taint = taint_create ();
                    const struct casewriter_class *class, void *aux)
 {
   struct casewriter *writer = xmalloc (sizeof *writer);
   writer->taint = taint_create ();
-  writer->value_cnt = value_cnt;
+  writer->proto = caseproto_ref (proto);
   writer->case_cnt = 0;
   writer->class = class;
   writer->aux = aux;
   return writer;
 }
 
   writer->case_cnt = 0;
   writer->class = class;
   writer->aux = aux;
   return writer;
 }
 
-/* Returns a casewriter for cases with VALUE_CNT struct values
-   per case.  The cases written to the casewriter will be kept in
+/* Returns a casewriter for cases that match case prototype
+   PROTO.  The cases written to the casewriter will be kept in
    memory, unless the amount of memory used grows too large, in
    which case they will be written to disk.
 
    memory, unless the amount of memory used grows too large, in
    which case they will be written to disk.
 
@@ -167,33 +174,34 @@ casewriter_create (size_t value_cnt,
 
    This is usually the right kind of casewriter to use. */
 struct casewriter *
 
    This is usually the right kind of casewriter to use. */
 struct casewriter *
-autopaging_writer_create (size_t value_cnt)
+autopaging_writer_create (const struct caseproto *proto)
 {
 {
-  return create_casewriter_window (value_cnt, settings_get_workspace_cases (value_cnt));
+  return create_casewriter_window (proto,
+                                   settings_get_workspace_cases (proto));
 }
 
 }
 
-/* Returns a casewriter for cases with VALUE_CNT struct values
-   per case.  The cases written to the casewriter will be kept in
+/* Returns a casewriter for cases that match case prototype
+   PROTO.  The cases written to the casewriter will be kept in
    memory.
 
    A casewriter created with this function may be passed to
    casewriter_make_reader. */
 struct casewriter *
    memory.
 
    A casewriter created with this function may be passed to
    casewriter_make_reader. */
 struct casewriter *
-mem_writer_create (size_t value_cnt)
+mem_writer_create (const struct caseproto *proto)
 {
 {
-  return create_casewriter_window (value_cnt, CASENUMBER_MAX);
+  return create_casewriter_window (proto, CASENUMBER_MAX);
 }
 
 }
 
-/* Returns a casewriter for cases with VALUE_CNT struct values
-   per case.  The cases written to the casewriter will be written
+/* Returns a casewriter for cases that match case prototype
+   PROTO.  The cases written to the casewriter will be written
    to disk.
 
    A casewriter created with this function may be passed to
    casewriter_make_reader. */
 struct casewriter *
    to disk.
 
    A casewriter created with this function may be passed to
    casewriter_make_reader. */
 struct casewriter *
-tmpfile_writer_create (size_t value_cnt)
+tmpfile_writer_create (const struct caseproto *proto)
 {
 {
-  return create_casewriter_window (value_cnt, 0);
+  return create_casewriter_window (proto, 0);
 }
 \f
 static const struct casewriter_class casewriter_window_class;
 }
 \f
 static const struct casewriter_class casewriter_window_class;
@@ -205,10 +213,11 @@ static const struct casereader_random_class casereader_window_class;
    memory until MAX_IN_CORE_CASES have been written, at which
    point they will be written to disk. */
 static struct casewriter *
    memory until MAX_IN_CORE_CASES have been written, at which
    point they will be written to disk. */
 static struct casewriter *
-create_casewriter_window (size_t value_cnt, casenumber max_in_core_cases)
+create_casewriter_window (const struct caseproto *proto,
+                          casenumber max_in_core_cases)
 {
 {
-  struct casewindow *window = casewindow_create (value_cnt, max_in_core_cases);
-  struct casewriter *writer = casewriter_create (value_cnt,
+  struct casewindow *window = casewindow_create (proto, max_in_core_cases);
+  struct casewriter *writer = casewriter_create (proto,
                                                  &casewriter_window_class,
                                                  window);
   taint_propagate (casewindow_get_taint (window),
                                                  &casewriter_window_class,
                                                  window);
   taint_propagate (casewindow_get_taint (window),
@@ -241,7 +250,7 @@ casewriter_window_convert_to_reader (struct casewriter *writer UNUSED,
 {
   struct casewindow *window = window_;
   struct casereader *reader =
 {
   struct casewindow *window = window_;
   struct casereader *reader =
-    casereader_create_random (casewindow_get_value_cnt (window),
+    casereader_create_random (casewindow_get_proto (window),
                              casewindow_get_case_cnt (window),
                              &casereader_window_class, window);
 
                              casewindow_get_case_cnt (window),
                              &casereader_window_class, window);
 
@@ -250,18 +259,19 @@ casewriter_window_convert_to_reader (struct casewriter *writer UNUSED,
   return reader;
 }
 
   return reader;
 }
 
-/* Reads the case at the given 0-based OFFSET from the front of
-   WINDOW into C.  Returns true if successful, false if
-   OFFSET is beyond the end of file or upon I/O error. */
-static bool
+/* Reads and returns the case at the given 0-based OFFSET from
+   the front of WINDOW into C.  Returns a null pointer if OFFSET
+   is beyond the end of file or upon I/O error.  The caller must
+   call case_unref() on the returned case when it is no longer
+   needed.*/
+static struct ccase *
 casereader_window_read (struct casereader *reader UNUSED, void *window_,
 casereader_window_read (struct casereader *reader UNUSED, void *window_,
-                        casenumber offset, struct ccase *c)
+                        casenumber offset)
 {
   struct casewindow *window = window_;
   if (offset >= casewindow_get_case_cnt (window))
 {
   struct casewindow *window = window_;
   if (offset >= casewindow_get_case_cnt (window))
-    return false;
-  else
-    return casewindow_get_case (window, offset, c);
+    return NULL;
+  return casewindow_get_case (window, offset);
 }
 
 /* Destroys casewindow reader WINDOW. */
 }
 
 /* Destroys casewindow reader WINDOW. */