Add lots of comments. Some minor substantive changes too:
authorBen Pfaff <blp@gnu.org>
Mon, 11 Jun 2007 04:03:19 +0000 (04:03 +0000)
committerBen Pfaff <blp@gnu.org>
Mon, 11 Jun 2007 04:03:19 +0000 (04:03 +0000)
* casereader-filter.c (casereader_filter_destroy): Make sure to
write all the remaining excluded cases to the casewriter, if any.

* caseinit.c (init_list_destroy): Rewrite.
(init_list_clear): Ditto.

* casegrouper.c (casegrouper_get_next_group): Always set *reader
to null when returning false.

src/data/ChangeLog
src/data/case-ordering.c
src/data/case-ordering.h
src/data/casegrouper.c
src/data/casegrouper.h
src/data/caseinit.c
src/data/caseinit.h
src/data/casereader-filter.c
src/data/casereader-translator.c
src/data/datasheet.c
src/data/procedure.c

index 913249f3bb0df1abbf4caff3c50c654bbe41e378..45564a95debc89a67597c56b5f5bbc52c6e67b62 100644 (file)
@@ -1,3 +1,14 @@
+2007-06-10  Ben Pfaff  <blp@gnu.org>
+
+       * casereader-filter.c (casereader_filter_destroy): Make sure to
+       write all the remaining excluded cases to the casewriter, if any.
+
+       * caseinit.c (init_list_destroy): Rewrite.
+       (init_list_clear): Ditto.
+
+       * casegrouper.c (casegrouper_get_next_group): Always set *reader
+       to null when returning false.
+
 2007-06-06  Ben Pfaff  <blp@gnu.org>
 
        Actually implement the new procedure code and adapt all of its
 2007-06-06  Ben Pfaff  <blp@gnu.org>
 
        Actually implement the new procedure code and adapt all of its
index 910a9ea66ad7facb55a2c4a5740d636845e52b11..e9e7095ead9fc1a5916356e87cd4f018cb023c10 100644 (file)
@@ -46,6 +46,10 @@ struct case_ordering
     size_t key_cnt;
   };
 
     size_t key_cnt;
   };
 
+/* Creates and returns a new case ordering for comparing cases
+   that represent dictionary DICT.  The case ordering initially
+   contains no variables, so that all cases will compare as
+   equal. */
 struct case_ordering *
 case_ordering_create (const struct dictionary *dict)
 {
 struct case_ordering *
 case_ordering_create (const struct dictionary *dict)
 {
@@ -56,6 +60,7 @@ case_ordering_create (const struct dictionary *dict)
   return co;
 }
 
   return co;
 }
 
+/* Creates and returns a clone of case ordering ORIG. */
 struct case_ordering *
 case_ordering_clone (const struct case_ordering *orig)
 {
 struct case_ordering *
 case_ordering_clone (const struct case_ordering *orig)
 {
@@ -66,6 +71,7 @@ case_ordering_clone (const struct case_ordering *orig)
   return co;
 }
 
   return co;
 }
 
+/* Destroys case ordering CO. */
 void
 case_ordering_destroy (struct case_ordering *co)
 {
 void
 case_ordering_destroy (struct case_ordering *co)
 {
@@ -76,12 +82,17 @@ case_ordering_destroy (struct case_ordering *co)
     }
 }
 
     }
 }
 
+/* Returns the number of `union value's in the cases that case
+   ordering CO compares (taken from the dictionary used to
+   construct it). */
 size_t
 case_ordering_get_value_cnt (const struct case_ordering *co)
 {
   return co->value_cnt;
 }
 
 size_t
 case_ordering_get_value_cnt (const struct case_ordering *co)
 {
   return co->value_cnt;
 }
 
+/* Compares cases A and B given case ordering CO and returns a
+   strcmp()-type result. */
 int
 case_ordering_compare_cases (const struct ccase *a, const struct ccase *b,
                              const struct case_ordering *co)
 int
 case_ordering_compare_cases (const struct ccase *a, const struct ccase *b,
                              const struct case_ordering *co)
@@ -116,6 +127,9 @@ case_ordering_compare_cases (const struct ccase *a, const struct ccase *b,
   return 0;
 }
 
   return 0;
 }
 
+/* Adds VAR to case ordering CO as an additional sort key in sort
+   direction DIR.  Returns true if successful, false if VAR was
+   already part of the ordering for CO. */
 bool
 case_ordering_add_var (struct case_ordering *co,
                        const struct variable *var, enum sort_direction dir)
 bool
 case_ordering_add_var (struct case_ordering *co,
                        const struct variable *var, enum sort_direction dir)
@@ -134,12 +148,18 @@ case_ordering_add_var (struct case_ordering *co,
   return true;
 }
 
   return true;
 }
 
+/* Returns the number of variables used for ordering within
+   CO. */
 size_t
 case_ordering_get_var_cnt (const struct case_ordering *co)
 {
   return co->key_cnt;
 }
 
 size_t
 case_ordering_get_var_cnt (const struct case_ordering *co)
 {
   return co->key_cnt;
 }
 
+/* Returns sort variable IDX within CO.  An IDX of 0 returns the
+   primary sort key (the one added first), an IDX of 1 returns
+   the secondary sort key, and so on.  IDX must be less than the
+   number of sort variables. */
 const struct variable *
 case_ordering_get_var (const struct case_ordering *co, size_t idx)
 {
 const struct variable *
 case_ordering_get_var (const struct case_ordering *co, size_t idx)
 {
@@ -147,6 +167,7 @@ case_ordering_get_var (const struct case_ordering *co, size_t idx)
   return co->keys[idx].var;
 }
 
   return co->keys[idx].var;
 }
 
+/* Returns the sort direction for sort variable IDX within CO. */
 enum sort_direction
 case_ordering_get_direction (const struct case_ordering *co, size_t idx)
 {
 enum sort_direction
 case_ordering_get_direction (const struct case_ordering *co, size_t idx)
 {
@@ -154,6 +175,10 @@ case_ordering_get_direction (const struct case_ordering *co, size_t idx)
   return co->keys[idx].dir;
 }
 
   return co->keys[idx].dir;
 }
 
+/* Stores an array listing all of the variables used for sorting
+   within CO into *VARS and the number of variables into
+   *VAR_CNT.  The caller is responsible for freeing *VARS when it
+   is no longer needed. */
 void
 case_ordering_get_vars (const struct case_ordering *co,
                         const struct variable ***vars, size_t *var_cnt)
 void
 case_ordering_get_vars (const struct case_ordering *co,
                         const struct variable ***vars, size_t *var_cnt)
index f537829d9cc80ae0c22c6c4b6011118c8bc91bb0..841d943f48c30277ab70c6b11aada08899c4120f 100644 (file)
@@ -16,6 +16,8 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA. */
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA. */
 
+/* Sort order for comparing cases. */
+
 #ifndef DATA_CASE_ORDERING_H
 #define DATA_CASE_ORDERING_H 1
 
 #ifndef DATA_CASE_ORDERING_H
 #define DATA_CASE_ORDERING_H 1
 
@@ -31,18 +33,24 @@ enum sort_direction
     SRT_DESCEND                        /* Z, Y, X, ..., C, B, A. */
   };
 
     SRT_DESCEND                        /* Z, Y, X, ..., C, B, A. */
   };
 
+/* Creation and destruction. */
 struct case_ordering *case_ordering_create (const struct dictionary *);
 struct case_ordering *case_ordering_clone (const struct case_ordering *);
 void case_ordering_destroy (struct case_ordering *);
 
 struct case_ordering *case_ordering_create (const struct dictionary *);
 struct case_ordering *case_ordering_clone (const struct case_ordering *);
 void case_ordering_destroy (struct case_ordering *);
 
-size_t case_ordering_get_value_cnt (const struct case_ordering *);
+/* Modification. */
+bool case_ordering_add_var (struct case_ordering *,
+                            const struct variable *, enum sort_direction);
+
+/* Comparing cases. */
 int case_ordering_compare_cases (const struct ccase *, const struct ccase *,
                                  const struct case_ordering *);
 
 int case_ordering_compare_cases (const struct ccase *, const struct ccase *,
                                  const struct case_ordering *);
 
-bool case_ordering_add_var (struct case_ordering *,
-                            const struct variable *, enum sort_direction);
+/* Inspection. */
+size_t case_ordering_get_value_cnt (const struct case_ordering *);
 size_t case_ordering_get_var_cnt (const struct case_ordering *);
 size_t case_ordering_get_var_cnt (const struct case_ordering *);
-const struct variable *case_ordering_get_var (const struct case_ordering *, size_t);
+const struct variable *case_ordering_get_var (const struct case_ordering *,
+                                              size_t);
 enum sort_direction case_ordering_get_direction (const struct case_ordering *,
                                                  size_t);
 void case_ordering_get_vars (const struct case_ordering *,
 enum sort_direction case_ordering_get_direction (const struct case_ordering *,
                                                  size_t);
 void case_ordering_get_vars (const struct case_ordering *,
index f2815106ea6330bac01609c40ae310be8cc808da..8a392afbab8be62531b68c9f3890818e88df4630 100644 (file)
 
 #include "xalloc.h"
 
 
 #include "xalloc.h"
 
+/* A casegrouper. */
 struct casegrouper
   {
 struct casegrouper
   {
-    struct casereader *reader;
-    struct taint *taint;
+    struct casereader *reader;  /* Source of input cases. */
+    struct taint *taint;        /* Error status for casegrouper. */
 
 
+    /* Functions for grouping cases. */
     bool (*same_group) (const struct ccase *, const struct ccase *, void *aux);
     void (*destroy) (void *aux);
     void *aux;
   };
 
     bool (*same_group) (const struct ccase *, const struct ccase *, void *aux);
     void (*destroy) (void *aux);
     void *aux;
   };
 
+/* Creates and returns a new casegrouper that takes its input
+   from READER.  SAME_GROUP is used to decide which cases are in
+   a group: it returns true if the pair of cases provided are in
+   the same group, false otherwise.  DESTROY will be called when
+   the casegrouper is destroyed and should free any storage
+   needed by SAME_GROUP.
+
+   SAME_GROUP may be a null pointer.  If so, READER's entire
+   contents is considered to be a single group. */
 struct casegrouper *
 casegrouper_create_func (struct casereader *reader,
                          bool (*same_group) (const struct ccase *,
 struct casegrouper *
 casegrouper_create_func (struct casereader *reader,
                          bool (*same_group) (const struct ccase *,
@@ -57,13 +68,17 @@ casegrouper_create_func (struct casereader *reader,
   return grouper;
 }
 
   return grouper;
 }
 
-/* FIXME: we really shouldn't need a temporary casewriter for the
-   common case where we read an entire group's data before going
-   on to the next. */
+/* Obtains the next group of cases from GROUPER.  Returns true if
+   successful, false if no groups remain.  If successful, *READER
+   is set to the casereader for the new group; otherwise, it is
+   set to NULL. */
 bool
 casegrouper_get_next_group (struct casegrouper *grouper,
                             struct casereader **reader)
 {
 bool
 casegrouper_get_next_group (struct casegrouper *grouper,
                             struct casereader **reader)
 {
+  /* FIXME: we really shouldn't need a temporary casewriter for
+     the common case where we read an entire group's data before
+     going on to the next. */
   if (grouper->same_group != NULL)
     {
       struct casewriter *writer;
   if (grouper->same_group != NULL)
     {
       struct casewriter *writer;
@@ -102,10 +117,17 @@ casegrouper_get_next_group (struct casegrouper *grouper,
           return true;
         }
       else
           return true;
         }
       else
-        return false;
+        {
+          *reader = NULL;
+          return false;
+        }
     }
 }
 
     }
 }
 
+/* Destroys GROUPER.  Returns false if GROUPER's input casereader
+   or any state derived from it had become tainted, which means
+   that an I/O error or other serious error occurred in
+   processing data derived from GROUPER; otherwise, return true. */
 bool
 casegrouper_destroy (struct casegrouper *grouper)
 {
 bool
 casegrouper_destroy (struct casegrouper *grouper)
 {
@@ -126,29 +148,26 @@ casegrouper_destroy (struct casegrouper *grouper)
   else
     return true;
 }
   else
     return true;
 }
+\f
+/* Casegrouper based on equal values of variables from case to
+   case. */
 
 
+/* Casegrouper based on equal variables. */
 struct casegrouper_vars
   {
 struct casegrouper_vars
   {
-    const struct variable **vars;
-    size_t var_cnt;
+    const struct variable **vars; /* Variables to compare. */
+    size_t var_cnt;               /* Number of variables. */
   };
 
   };
 
-static bool
-casegrouper_vars_same_group (const struct ccase *a, const struct ccase *b,
-                             void *cv_)
-{
-  struct casegrouper_vars *cv = cv_;
-  return case_compare (a, b, cv->vars, cv->var_cnt) == 0;
-}
-
-static void
-casegrouper_vars_destroy (void *cv_)
-{
-  struct casegrouper_vars *cv = cv_;
-  free (cv->vars);
-  free (cv);
-}
+static bool casegrouper_vars_same_group (const struct ccase *,
+                                         const struct ccase *,
+                                         void *);
+static void casegrouper_vars_destroy (void *);
 
 
+/* Creates and returns a casegrouper that reads data from READER
+   and breaks it into contiguous groups of cases that have equal
+   values for the VAR_CNT variables in VARS.  If VAR_CNT is 0,
+   then all the cases will be put in a single group. */
 struct casegrouper *
 casegrouper_create_vars (struct casereader *reader,
                          const struct variable *const *vars,
 struct casegrouper *
 casegrouper_create_vars (struct casereader *reader,
                          const struct variable *const *vars,
@@ -168,6 +187,11 @@ casegrouper_create_vars (struct casereader *reader,
     return casegrouper_create_func (reader, NULL, NULL, NULL);
 }
 
     return casegrouper_create_func (reader, NULL, NULL, NULL);
 }
 
+/* Creates and returns a casegrouper that reads data from READER
+   and breaks it into contiguous groups of cases that have equal
+   values for the SPLIT FILE variables in DICT.  If DICT has no
+   SPLIT FILE variables, then all the cases will be put into a
+   single group. */
 struct casegrouper *
 casegrouper_create_splits (struct casereader *reader,
                            const struct dictionary *dict)
 struct casegrouper *
 casegrouper_create_splits (struct casereader *reader,
                            const struct dictionary *dict)
@@ -177,6 +201,11 @@ casegrouper_create_splits (struct casereader *reader,
                                   dict_get_split_cnt (dict));
 }
 
                                   dict_get_split_cnt (dict));
 }
 
+/* Creates and returns a casegrouper that reads data from READER
+   and breaks it into contiguous groups of cases that have equal
+   values for the variables used for sorting in CO.  If CO is
+   empty (contains no sort keys), then all the cases will be put
+   into a single group. */
 struct casegrouper *
 casegrouper_create_case_ordering (struct casereader *reader,
                                   const struct case_ordering *co)
 struct casegrouper *
 casegrouper_create_case_ordering (struct casereader *reader,
                                   const struct case_ordering *co)
@@ -191,3 +220,22 @@ casegrouper_create_case_ordering (struct casereader *reader,
 
   return grouper;
 }
 
   return grouper;
 }
+
+/* "same_group" function for an equal-variables casegrouper. */
+static bool
+casegrouper_vars_same_group (const struct ccase *a, const struct ccase *b,
+                             void *cv_)
+{
+  struct casegrouper_vars *cv = cv_;
+  return case_compare (a, b, cv->vars, cv->var_cnt) == 0;
+}
+
+/* "destroy" for an equal-variables casegrouper. */
+static void
+casegrouper_vars_destroy (void *cv_)
+{
+  struct casegrouper_vars *cv = cv_;
+  free (cv->vars);
+  free (cv);
+}
+
index 3d9c6a89dc41fc1805ecf0623e8590972655dd8e..5f686ff99027b814c6bef09ec91789aec29a033a 100644 (file)
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA. */
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA. */
 
+/* Casegrouper.
+
+   Breaks up the cases from a casereader into sets of contiguous
+   cases based on some criteria, e.g. sets of cases that all have
+   the same values for some subset of variables.  Each set of
+   cases is made available to the client as a casereader. */
+
 #ifndef DATA_CASEGROUPER_H
 #define DATA_CASEGROUPER_H 1
 
 #ifndef DATA_CASEGROUPER_H
 #define DATA_CASEGROUPER_H 1
 
index 564d35342981623d58940968854f6fc80cba3e43..496ea9b2ce29d26c8fa3a3a3ce304dc0fec6b2fc 100644 (file)
 #include <libpspp/compiler.h>
 
 #include "xalloc.h"
 #include <libpspp/compiler.h>
 
 #include "xalloc.h"
+\f
+/* Initializer list: a set of values to write to locations within
+   a case. */
 
 
+/* Binds a value with a place to put it. */
 struct init_value
   {
     union value value;
     size_t case_index;
   };
 
 struct init_value
   {
     union value value;
     size_t case_index;
   };
 
+/* A set of values to initialize in a case. */
 struct init_list
   {
     struct init_value *values;
     size_t cnt;
   };
 
 struct init_list
   {
     struct init_value *values;
     size_t cnt;
   };
 
+/* A bitmap of the "left" status of variables. */
 enum leave_class
   {
 enum leave_class
   {
-    LEAVE_REINIT = 0x001,
-    LEAVE_LEFT = 0x002
+    LEAVE_REINIT = 0x001,       /* Reinitalize for every case. */
+    LEAVE_LEFT = 0x002          /* Keep the value from one case to the next. */
   };
 
   };
 
+/* Initializes LIST as an empty initializer list. */
 static void
 init_list_create (struct init_list *list)
 {
 static void
 init_list_create (struct init_list *list)
 {
@@ -59,19 +66,23 @@ init_list_create (struct init_list *list)
   list->cnt = 0;
 }
 
   list->cnt = 0;
 }
 
+/* Frees the storage associated with LIST. */
 static void
 static void
-init_list_clear (struct init_list *list)
+init_list_destroy (struct init_list *list)
 {
   free (list->values);
 {
   free (list->values);
-  init_list_create (list);
 }
 
 }
 
+/* Clears LIST, making it an empty list. */
 static void
 static void
-init_list_destroy (struct init_list *list)
+init_list_clear (struct init_list *list)
 {
 {
-  init_list_clear (list);
+  init_list_destroy (list);
+  init_list_create (list);
 }
 
 }
 
+/* Compares `struct init_value's A and B by case_index and
+   returns a strcmp()-type result. */
 static int
 compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
 {
 static int
 compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
 {
@@ -81,6 +92,7 @@ compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
   return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
 }
 
   return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
 }
 
+/* Returns true if LIST includes CASE_INDEX, false otherwise. */
 static bool
 init_list_includes (const struct init_list *list, size_t case_index)
 {
 static bool
 init_list_includes (const struct init_list *list, size_t case_index)
 {
@@ -90,6 +102,9 @@ init_list_includes (const struct init_list *list, size_t case_index)
                         &value, compare_init_values, NULL) != NULL;
 }
 
                         &value, compare_init_values, NULL) != NULL;
 }
 
+/* Marks LIST to initialize the `union value's for the variables
+   in dictionary D that both (1) fall in the leave class or
+   classes designated by INCLUDE and (2) are not in EXCLUDE. */
 static void
 init_list_mark (struct init_list *list, const struct init_list *exclude,
                 enum leave_class include, const struct dictionary *d)
 static void
 init_list_mark (struct init_list *list, const struct init_list *exclude,
                 enum leave_class include, const struct dictionary *d)
@@ -133,9 +148,10 @@ init_list_mark (struct init_list *list, const struct init_list *exclude,
   /* Drop duplicates. */
   list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
                            compare_init_values, NULL);
   /* Drop duplicates. */
   list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
                            compare_init_values, NULL);
-
 }
 
 }
 
+/* Initializes data in case C to the values in the initializer
+   LIST. */
 static void
 init_list_init (const struct init_list *list, struct ccase *c)
 {
 static void
 init_list_init (const struct init_list *list, struct ccase *c)
 {
@@ -148,6 +164,8 @@ init_list_init (const struct init_list *list, struct ccase *c)
     }
 }
 
     }
 }
 
+/* Updates the values in the initializer LIST from the data in
+   case C. */
 static void
 init_list_update (const struct init_list *list, const struct ccase *c)
 {
 static void
 init_list_update (const struct init_list *list, const struct ccase *c)
 {
@@ -159,14 +177,26 @@ init_list_update (const struct init_list *list, const struct ccase *c)
       value->value = *case_data_idx (c, value->case_index);
     }
 }
       value->value = *case_data_idx (c, value->case_index);
     }
 }
-
+\f
+/* A case initializer. */
 struct caseinit
   {
 struct caseinit
   {
+    /* Values that do not need to be initialized by the
+       procedure, because they are initialized by the data
+       source. */
     struct init_list preinited_values;
     struct init_list preinited_values;
+
+    /* Values that need to be initialized to SYSMIS or spaces in
+       each case. */
     struct init_list reinit_values;
     struct init_list reinit_values;
+
+    /* Values that need to be initialized to 0 or spaces in the
+       first case and thereafter retain their values from case to
+       case. */
     struct init_list left_values;
   };
 
     struct init_list left_values;
   };
 
+/* Creates and returns a new case initializer. */
 struct caseinit *
 caseinit_create (void)
 {
 struct caseinit *
 caseinit_create (void)
 {
@@ -177,6 +207,7 @@ caseinit_create (void)
   return ci;
 }
 
   return ci;
 }
 
+/* Clears the contents of case initializer CI. */
 void
 caseinit_clear (struct caseinit *ci)
 {
 void
 caseinit_clear (struct caseinit *ci)
 {
@@ -185,6 +216,7 @@ caseinit_clear (struct caseinit *ci)
   init_list_clear (&ci->left_values);
 }
 
   init_list_clear (&ci->left_values);
 }
 
+/* Destroys case initializer CI. */
 void
 caseinit_destroy (struct caseinit *ci)
 {
 void
 caseinit_destroy (struct caseinit *ci)
 {
@@ -197,12 +229,19 @@ caseinit_destroy (struct caseinit *ci)
     }
 }
 
     }
 }
 
+/* Marks the variables from dictionary D in CI as being
+   initialized by the data source, so that the case initializer
+   need not initialize them itself. */
 void
 caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
 {
   init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
 }
 
 void
 caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
 {
   init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
 }
 
+/* Marks in CI the variables from dictionary D, except for any
+   variables that were already marked with
+   caseinit_mark_as_preinited, as needing initialization
+   according to their leave status. */
 void
 caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
 {
 void
 caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
 {
@@ -210,17 +249,17 @@ caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
   init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
 }
 
   init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
 }
 
+/* Initializes variables in C as described by CI. */
 void
 void
-caseinit_init_reinit_vars (const struct caseinit *ci, struct ccase *c)
+caseinit_init_vars (const struct caseinit *ci, struct ccase *c)
 {
   init_list_init (&ci->reinit_values, c);
 {
   init_list_init (&ci->reinit_values, c);
-}
-
-void caseinit_init_left_vars (const struct caseinit *ci, struct ccase *c)
-{
   init_list_init (&ci->left_values, c);
 }
 
   init_list_init (&ci->left_values, c);
 }
 
+/* Updates the left vars in CI from the data in C, so that the
+   next call to caseinit_init_vars will store those values in the
+   next case. */
 void
 caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
 {
 void
 caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
 {
index 7c7f1c69e7d7288a98d7c6da07b03e1cf1eba350..3c849805a69a8fc2c518f5e9d13264fa1412507c 100644 (file)
@@ -26,7 +26,9 @@
    save the values of "left" variables to copy into the next case
    read from the active file.
 
    save the values of "left" variables to copy into the next case
    read from the active file.
 
-   The caseinit code helps with this. */
+   The caseinit data structure provides a little help for
+   tracking what data to initialize or to copy from case to
+   case. */
 
 #ifndef DATA_CASEINIT_H
 #define DATA_CASEINIT_H 1
 
 #ifndef DATA_CASEINIT_H
 #define DATA_CASEINIT_H 1
 struct dictionary;
 struct ccase;
 
 struct dictionary;
 struct ccase;
 
+/* Creation and destruction. */
 struct caseinit *caseinit_create (void);
 void caseinit_clear (struct caseinit *);
 void caseinit_destroy (struct caseinit *);
 
 struct caseinit *caseinit_create (void);
 void caseinit_clear (struct caseinit *);
 void caseinit_destroy (struct caseinit *);
 
+/* Track data to be initialized. */
 void caseinit_mark_as_preinited (struct caseinit *, const struct dictionary *);
 void caseinit_mark_for_init (struct caseinit *, const struct dictionary *);
 
 void caseinit_mark_as_preinited (struct caseinit *, const struct dictionary *);
 void caseinit_mark_for_init (struct caseinit *, const struct dictionary *);
 
-void caseinit_init_reinit_vars (const struct caseinit *, struct ccase *);
-void caseinit_init_left_vars (const struct caseinit *, struct ccase *);
+/* Initialize data and copy data from case to case. */
+void caseinit_init_vars (const struct caseinit *, struct ccase *);
 void caseinit_update_left_vars (struct caseinit *, const struct ccase *);
 
 #endif /* data/caseinit.h */
 void caseinit_update_left_vars (struct caseinit *, const struct ccase *);
 
 #endif /* data/caseinit.h */
index 36ff62acec9c1cf3bc4ace2a109a41cccc03e115..afb72cca1434e7a40dea2a723ba5b7a68bcd8e69 100644 (file)
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
+/* A casereader that filters data coming from another
+   casereader. */
 struct casereader_filter
   {
 struct casereader_filter
   {
-    struct casereader *subreader;
+    struct casereader *subreader; /* The reader to filter. */
     bool (*include) (const struct ccase *, void *aux);
     bool (*destroy) (void *aux);
     void *aux;
     bool (*include) (const struct ccase *, void *aux);
     bool (*destroy) (void *aux);
     void *aux;
-    struct casewriter *exclude;
+    struct casewriter *exclude; /* Writer that gets filtered cases, or NULL. */
   };
 
 static struct casereader_class casereader_filter_class;
 
   };
 
 static struct casereader_class casereader_filter_class;
 
+/* Creates and returns a casereader whose content is a filtered
+   version of the data in SUBREADER.  Only the cases for which
+   INCLUDE returns true will appear in the returned casereader,
+   in the original order.
+
+   If EXCLUDE is non-null, then cases for which INCLUDE returns
+   false are written to EXCLUDE.  These cases will not
+   necessarily be fully written to EXCLUDE until the filtering casereader's
+   cases have been fully read or, if that never occurs, until the
+   filtering casereader is destroyed.
+
+   When the filtering casereader is destroyed, DESTROY will be
+   called to allow any state maintained by INCLUDE to be freed.
+
+   After this function is called, SUBREADER must not ever again
+   be referenced directly.  It will be destroyed automatically
+   when the filtering casereader is destroyed. */
 struct casereader *
 casereader_create_filter_func (struct casereader *subreader,
                                bool (*include) (const struct ccase *,
 struct casereader *
 casereader_create_filter_func (struct casereader *subreader,
                                bool (*include) (const struct ccase *,
@@ -68,6 +87,7 @@ casereader_create_filter_func (struct casereader *subreader,
   return reader;
 }
 
   return reader;
 }
 
+/* Internal read function for filtering casereader. */
 static bool
 casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
                         struct ccase *c)
 static bool
 casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
                         struct ccase *c)
@@ -87,16 +107,31 @@ casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
     }
 }
 
     }
 }
 
+/* Internal destruction function for filtering casereader. */
 static void
 casereader_filter_destroy (struct casereader *reader, void *filter_)
 {
   struct casereader_filter *filter = filter_;
 static void
 casereader_filter_destroy (struct casereader *reader, void *filter_)
 {
   struct casereader_filter *filter = filter_;
+
+  /* Make sure we've written everything to the excluded cases
+     casewriter, if there is one. */
+  if (filter->exclude != NULL)
+    {
+      struct ccase c;
+      while (casereader_read (filter->subreader, &c))
+        if (filter->include (&c, filter->aux))
+          case_destroy (&c);
+        else
+          casewriter_write (filter->exclude, &c);
+    }
+
   casereader_destroy (filter->subreader);
   if (filter->destroy != NULL && !filter->destroy (filter->aux))
     casereader_force_error (reader);
   free (filter);
 }
 
   casereader_destroy (filter->subreader);
   if (filter->destroy != NULL && !filter->destroy (filter->aux))
     casereader_force_error (reader);
   free (filter);
 }
 
+/* Filtering casereader class. */
 static struct casereader_class casereader_filter_class =
   {
     casereader_filter_read,
 static struct casereader_class casereader_filter_class =
   {
     casereader_filter_read,
@@ -111,41 +146,42 @@ static struct casereader_class casereader_filter_class =
     NULL,
   };
 
     NULL,
   };
 
+\f
+/* Casereader for filtering valid weights. */
+
+/* Weight-filtering data. */
 struct casereader_filter_weight
   {
 struct casereader_filter_weight
   {
-    const struct variable *weight_var;
-    bool *warn_on_invalid;
-    bool local_warn_on_invalid;
+    const struct variable *weight_var; /* Weight variable. */
+    bool *warn_on_invalid;      /* Have we already issued an error? */
+    bool local_warn_on_invalid; /* warn_on_invalid might point here. */
   };
 
   };
 
-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_include (const struct ccase *, void *);
+static bool casereader_filter_weight_destroy (void *);
 
 
-static bool
-casereader_filter_weight_destroy (void *cfw_)
-{
-  struct casereader_filter_weight *cfw = cfw_;
-  free (cfw);
-  return true;
-}
+/* Creates and returns a casereader that filters cases from
+   READER by valid weights, that is, any cases with user- or
+   system-missing, zero, or negative weights are dropped.  The
+   weight variable's information is taken from DICT.  If DICT
+   does not have a weight variable, then no cases are filtered
+   out.
+
+   When a case with an invalid weight is encountered,
+   *WARN_ON_INVALID is checked.  If it is true, then an error
+   message is issued and *WARN_ON_INVALID is set false.  If
+   WARN_ON_INVALID is a null pointer, then an internal bool that
+   is initially true is used instead of a caller-supplied bool.
 
 
+   If EXCLUDE is non-null, then dropped cases are written to
+   EXCLUDE.  These cases will not necessarily be fully written to
+   EXCLUDE until the filtering casereader's cases have been fully
+   read or, if that never occurs, until the filtering casereader
+   is destroyed.
+
+   After this function is called, READER must not ever again be
+   referenced directly.  It will be destroyed automatically when
+   the filtering casereader is destroyed. */
 struct casereader *
 casereader_create_filter_weight (struct casereader *reader,
                                  const struct dictionary *dict,
 struct casereader *
 casereader_create_filter_weight (struct casereader *reader,
                                  const struct dictionary *dict,
@@ -170,39 +206,69 @@ casereader_create_filter_weight (struct casereader *reader,
     reader = casereader_rename (reader);
   return reader;
 }
     reader = casereader_rename (reader);
   return reader;
 }
-\f
-struct casereader_filter_missing
-  {
-    struct variable **vars;
-    size_t var_cnt;
-    enum mv_class class;
-  };
 
 
+/* Internal "include" function for weight-filtering
+   casereader. */
 static bool
 static bool
-casereader_filter_missing_include (const struct ccase *c, void *cfm_)
+casereader_filter_weight_include (const struct ccase *c, void *cfw_)
 {
 {
-  const struct casereader_filter_missing *cfm = cfm_;
-  size_t i;
-
-  for (i = 0; i < cfm->var_cnt; i++)
+  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
     {
     {
-      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;
+      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;
     }
     }
-  return true;
 }
 
 }
 
+/* Internal "destroy" function for weight-filtering
+   casereader. */
 static bool
 static bool
-casereader_filter_missing_destroy (void *cfm_)
+casereader_filter_weight_destroy (void *cfw_)
 {
 {
-  struct casereader_filter_missing *cfm = cfm_;
-  free (cfm->vars);
-  free (cfm);
+  struct casereader_filter_weight *cfw = cfw_;
+  free (cfw);
   return true;
 }
   return true;
 }
+\f
+/* Casereader for filtering missing values. */
+
+/* Missing-value filtering data. */
+struct casereader_filter_missing
+  {
+    struct variable **vars;     /* Variables whose values to filter. */
+    size_t var_cnt;             /* Number of variables. */
+    enum mv_class class;        /* Types of missing values to filter. */
+  };
+
+static bool casereader_filter_missing_include (const struct ccase *, void *);
+static bool casereader_filter_missing_destroy (void *);
+
+/* Creates and returns a casereader that filters out cases from
+   READER that have a missing value in the given CLASS for any of
+   the VAR_CNT variables in VARS.  Only cases that have
+   non-missing values for all of these variables are passed
+   through.
 
 
+   Ownership of VARS is retained by the caller.
+
+   If EXCLUDE is non-null, then dropped cases are written to
+   EXCLUDE.  These cases will not necessarily be fully written to
+   EXCLUDE until the filtering casereader's cases have been fully
+   read or, if that never occurs, until the filtering casereader
+   is destroyed.
+
+   After this function is called, READER must not ever again
+   be referenced directly.  It will be destroyed automatically
+   when the filtering casereader is destroyed. */
 struct casereader *
 casereader_create_filter_missing (struct casereader *reader,
                                   const struct variable **vars, size_t var_cnt,
 struct casereader *
 casereader_create_filter_missing (struct casereader *reader,
                                   const struct variable **vars, size_t var_cnt,
@@ -224,16 +290,58 @@ casereader_create_filter_missing (struct casereader *reader,
   else
     return casereader_rename (reader);
 }
   else
     return casereader_rename (reader);
 }
-\f
-\f
+
+/* Internal "include" function for missing value-filtering
+   casereader. */
 static bool
 static bool
-casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
+casereader_filter_missing_include (const struct ccase *c, void *cfm_)
 {
 {
-  casenumber *counter = counter_;
-  ++*counter;
+  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;
+}
+
+/* Internal "destroy" function for missing value-filtering
+   casereader. */
+static bool
+casereader_filter_missing_destroy (void *cfm_)
+{
+  struct casereader_filter_missing *cfm = cfm_;
+  free (cfm->vars);
+  free (cfm);
   return true;
 }
   return true;
 }
+\f
+/* Case-counting casereader. */
+
+static bool casereader_counter_include (const struct ccase *, void *);
 
 
+/* Creates and returns a new casereader that counts the number of
+   cases that have been read from it.  *COUNTER is initially set
+   to INITIAL_VALUE, then incremented by 1 each time a case is read.
+
+   Counting casereaders must be used very cautiously: if a
+   counting casereader is cloned or if the casereader_peek
+   function is used on it, then the counter's value can be higher
+   than expected because of the buffering that goes on behind the
+   scenes.
+
+   The counter is only incremented as cases are actually read
+   from the casereader.  In particular, if the casereader is
+   destroyed before all cases have been read from the casereader,
+   cases never read will not be included in the count.
+
+   After this function is called, READER must not ever again
+   be referenced directly.  It will be destroyed automatically
+   when the filtering casereader is destroyed. */
 struct casereader *
 casereader_create_counter (struct casereader *reader, casenumber *counter,
                            casenumber initial_value)
 struct casereader *
 casereader_create_counter (struct casereader *reader, casenumber *counter,
                            casenumber initial_value)
@@ -242,3 +350,12 @@ casereader_create_counter (struct casereader *reader, casenumber *counter,
   return casereader_create_filter_func (reader, casereader_counter_include,
                                         NULL, counter, NULL);
 }
   return casereader_create_filter_func (reader, casereader_counter_include,
                                         NULL, counter, NULL);
 }
+
+/* Internal "include" function for counting casereader. */
+static bool
+casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
+{
+  casenumber *counter = counter_;
+  ++*counter;
+  return true;
+}
index b409beeb1c166541b7d4f98469303f904b6ad40c..28b9c180a18d7b433a8e8e20ae364f41ee8690bd 100644 (file)
 
 #include "xalloc.h"
 
 
 #include "xalloc.h"
 
+/* Casereader that applies a user-supplied function to translate
+   each case into another in an arbitrary fashion. */
+
+/* A translating casereader. */
 struct casereader_translator
   {
 struct casereader_translator
   {
-    struct casereader *subreader;
+    struct casereader *subreader; /* Source of input cases. */
 
     void (*translate) (const struct ccase *input, struct ccase *output,
                        void *aux);
 
     void (*translate) (const struct ccase *input, struct ccase *output,
                        void *aux);
@@ -39,6 +43,18 @@ struct casereader_translator
 
 static struct casereader_class casereader_translator_class;
 
 
 static struct casereader_class casereader_translator_class;
 
+/* Creates and returns a new casereader whose cases are produced
+   by reading from SUBREADER and passing through TRANSLATE, which
+   must create case OUTPUT, with OUTPUT_VALUE_CNT values, and
+   populate it based on INPUT and auxiliary data AUX.  TRANSLATE
+   must also destroy INPUT.
+
+   When the translating casereader is destroyed, DESTROY will be
+   called to allow any state maintained by TRANSLATE to be freed.
+
+   After this function is called, SUBREADER must not ever again
+   be referenced directly.  It will be destroyed automatically
+   when the translating casereader is destroyed. */
 struct casereader *
 casereader_create_translator (struct casereader *subreader,
                               size_t output_value_cnt,
 struct casereader *
 casereader_create_translator (struct casereader *subreader,
                               size_t output_value_cnt,
@@ -62,6 +78,7 @@ casereader_create_translator (struct casereader *subreader,
   return reader;
 }
 
   return reader;
 }
 
+/* Internal read function for translating casereader. */
 static bool
 casereader_translator_read (struct casereader *reader UNUSED,
                             void *ct_, struct ccase *c)
 static bool
 casereader_translator_read (struct casereader *reader UNUSED,
                             void *ct_, struct ccase *c)
@@ -78,6 +95,7 @@ casereader_translator_read (struct casereader *reader UNUSED,
     return false;
 }
 
     return false;
 }
 
+/* Internal destroy function for translating casereader. */
 static void
 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
 {
 static void
 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
 {
@@ -87,6 +105,7 @@ casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
   free (ct);
 }
 
   free (ct);
 }
 
+/* Casereader class for translating casereader. */
 static struct casereader_class casereader_translator_class =
   {
     casereader_translator_read,
 static struct casereader_class casereader_translator_class =
   {
     casereader_translator_read,
index 4a3eda32cc7700a030adc96b624f1bd444935aa3..1fc1e98b08aba877620733f90a12a225a0be4f36 100644 (file)
@@ -229,20 +229,23 @@ datasheet_rename (struct datasheet *ds)
   return new;
 }
 
   return new;
 }
 
-/* Returns true if a I/O error has occurred while processing a
-   datasheet operation. */
+/* Returns true if datasheet DS is tainted.
+   A datasheet is tainted by an I/O error or by taint
+   propagation to the datasheet. */
 bool
 datasheet_error (const struct datasheet *ds)
 {
   return taint_is_tainted (ds->taint);
 }
 
 bool
 datasheet_error (const struct datasheet *ds)
 {
   return taint_is_tainted (ds->taint);
 }
 
+/* Marks datasheet DS tainted. */
 void
 datasheet_force_error (struct datasheet *ds)
 {
   taint_set_taint (ds->taint);
 }
 
 void
 datasheet_force_error (struct datasheet *ds)
 {
   taint_set_taint (ds->taint);
 }
 
+/* Returns datasheet DS's taint object. */
 const struct taint *
 datasheet_get_taint (const struct datasheet *ds)
 {
 const struct taint *
 datasheet_get_taint (const struct datasheet *ds)
 {
@@ -535,6 +538,7 @@ datasheet_make_reader (struct datasheet *ds)
   return reader;
 }
 
   return reader;
 }
 
+/* "read" function for the datasheet random casereader. */
 static bool
 datasheet_reader_read (struct casereader *reader UNUSED, void *ds_,
                        casenumber case_idx, struct ccase *c)
 static bool
 datasheet_reader_read (struct casereader *reader UNUSED, void *ds_,
                        casenumber case_idx, struct ccase *c)
@@ -551,6 +555,7 @@ datasheet_reader_read (struct casereader *reader UNUSED, void *ds_,
     }
 }
 
     }
 }
 
+/* "destroy" function for the datasheet random casereader. */
 static void
 datasheet_reader_destroy (struct casereader *reader UNUSED, void *ds_)
 {
 static void
 datasheet_reader_destroy (struct casereader *reader UNUSED, void *ds_)
 {
@@ -558,6 +563,7 @@ datasheet_reader_destroy (struct casereader *reader UNUSED, void *ds_)
   datasheet_destroy (ds);
 }
 
   datasheet_destroy (ds);
 }
 
+/* "advance" function for the datasheet random casereader. */
 static void
 datasheet_reader_advance (struct casereader *reader UNUSED, void *ds_,
                           casenumber case_cnt)
 static void
 datasheet_reader_advance (struct casereader *reader UNUSED, void *ds_,
                           casenumber case_cnt)
@@ -566,6 +572,7 @@ datasheet_reader_advance (struct casereader *reader UNUSED, void *ds_,
   datasheet_delete_rows (ds, 0, case_cnt);
 }
 
   datasheet_delete_rows (ds, 0, case_cnt);
 }
 
+/* Random casereader class for a datasheet. */
 static const struct casereader_random_class datasheet_reader_class =
   {
     datasheet_reader_read,
 static const struct casereader_random_class datasheet_reader_class =
   {
     datasheet_reader_read,
index 55fe5a48ad8b8ea69d66f5234549af61444325df..0741b1cc944ce479b6214aba0933d624cb8611c8 100644 (file)
@@ -86,9 +86,10 @@ struct dataset {
   /* Procedure data. */
   enum
     {
   /* Procedure data. */
   enum
     {
-      PROC_COMMITTED,
-      PROC_OPEN,
-      PROC_CLOSED
+      PROC_COMMITTED,           /* No procedure in progress. */
+      PROC_OPEN,                /* proc_open called, casereader still open. */
+      PROC_CLOSED               /* casereader from proc_open destroyed,
+                                   but proc_commit not yet called. */
     }
   proc_state;
   size_t cases_written;       /* Cases output so far. */
     }
   proc_state;
   size_t cases_written;       /* Cases output so far. */
@@ -193,18 +194,15 @@ proc_open (struct dataset *ds)
                                        &proc_casereader_class, ds);
 }
 
                                        &proc_casereader_class, ds);
 }
 
+/* Returns true if a procedure is in progress, that is, if
+   proc_open has been called but proc_commit has not. */
 bool
 proc_is_open (const struct dataset *ds)
 {
   return ds->proc_state != PROC_COMMITTED;
 }
 
 bool
 proc_is_open (const struct dataset *ds)
 {
   return ds->proc_state != PROC_COMMITTED;
 }
 
-/* Reads the next case from dataset DS, which must have been
-   opened for reading with proc_open.
-   Returns true if successful, in which case a pointer to the
-   case is stored in *C.
-   Return false at end of file or if a read error occurs.  In
-   this case a null pointer is stored in *C. */
+/* "read" function for procedure casereader. */
 static bool
 proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
                       struct ccase *c)
 static bool
 proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
                       struct ccase *c)
@@ -227,8 +225,7 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
       if (!casereader_read (ds->source, c))
         return false;
       case_resize (c, dict_get_next_value_idx (ds->dict));
       if (!casereader_read (ds->source, c))
         return false;
       case_resize (c, dict_get_next_value_idx (ds->dict));
-      caseinit_init_reinit_vars (ds->caseinit, c);
-      caseinit_init_left_vars (ds->caseinit, c);
+      caseinit_init_vars (ds->caseinit, c);
 
       /* Execute permanent transformations.  */
       case_nr = ds->cases_written + 1;
 
       /* Execute permanent transformations.  */
       case_nr = ds->cases_written + 1;
@@ -280,11 +277,7 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
     }
 }
 
     }
 }
 
-/* Closes dataset DS for reading.
-   Returns true if successful, false if an I/O error occurred
-   while reading or closing the data set.
-   If DS has not been opened, returns true without doing
-   anything else. */
+/* "destroy" function for procedure casereader. */
 static void
 proc_casereader_destroy (struct casereader *reader, void *ds_)
 {
 static void
 proc_casereader_destroy (struct casereader *reader, void *ds_)
 {
@@ -352,6 +345,7 @@ proc_commit (struct dataset *ds)
   return proc_cancel_all_transformations (ds) && ds->ok;
 }
 
   return proc_cancel_all_transformations (ds) && ds->ok;
 }
 
+/* Casereader class for procedure execution. */
 static struct casereader_class proc_casereader_class =
   {
     proc_casereader_read,
 static struct casereader_class proc_casereader_class =
   {
     proc_casereader_read,