Add casereader_create_append_numeric function.
[pspp-builds.git] / src / data / casereader-translator.c
index 5a717da8252a15de221728734e39e0d6f4210aab..0557b65e8d6336452b4b88c4881d901fc289c7f2 100644 (file)
@@ -38,7 +38,7 @@ struct casereader_translator
     void *aux;
   };
 
-static struct casereader_class casereader_translator_class;
+static const 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
@@ -103,10 +103,111 @@ casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
 }
 
 /* Casereader class for translating casereader. */
-static struct casereader_class casereader_translator_class =
+static const struct casereader_class casereader_translator_class =
   {
     casereader_translator_read,
     casereader_translator_destroy,
     NULL,
     NULL,
   };
+
+\f
+
+struct casereader_append_numeric
+{
+  int value_ofs;
+  casenumber n;
+  new_value_func *func;
+  void *aux;
+  void (*destroy) (void *aux);
+};
+
+static bool can_destroy (void *can_);
+
+static void can_translate (struct ccase *input, struct ccase *output,
+                          void *can_);
+
+/* Creates and returns a new casereader whose cases are produced
+   by reading from SUBREADER and appending an additional value,
+   generated by FUNC.  AUX is an optional parameter which
+   gets passed to FUNC. FUNC will also receive N as it, which is
+   the ordinal number of the case in the reader.  DESTROY is an 
+   optional parameter used to destroy AUX.
+
+   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_append_numeric (struct casereader *subreader,
+                                 new_value_func func, void *aux,
+                                 void (*destroy) (void *aux))
+{
+  struct casereader_append_numeric *can = xmalloc (sizeof *can);
+  can->value_ofs = casereader_get_value_cnt (subreader);
+  can->n = 0;
+  can->aux = aux;
+  can->func = func;
+  can->destroy = destroy;
+  return casereader_create_translator (subreader, can->value_ofs + 1,
+                                       can_translate, can_destroy, can);
+}
+
+
+static void
+can_translate (struct ccase *input, struct ccase *output, void *can_)
+{
+  struct casereader_append_numeric *can = can_;
+  double new_value = can->func (input, can->n++, can->aux);
+  case_nullify (output);
+  case_move (output, input);
+  case_resize (output, can->value_ofs + 1);
+  case_data_rw_idx (output, can->value_ofs)->f = new_value;
+}
+
+static bool
+can_destroy (void *can_)
+{
+  struct casereader_append_numeric *can = can_;
+  if (can->destroy)
+    can->destroy (can->aux);
+  free (can);
+  return true;
+}
+
+\f
+
+struct arithmetic_sequence
+{
+  double first;
+  double increment;
+};
+
+static double
+next_arithmetic (const struct ccase *c UNUSED,
+                casenumber n,
+                void *aux)
+{
+  struct arithmetic_sequence *as = aux;
+  return n * as->increment + as->first;
+}
+
+/* Creates and returns a new casereader whose cases are produced
+   by reading from SUBREADER and appending an additional value,
+   which takes the value FIRST in the first case, FIRST +
+   INCREMENT in the second case, FIRST + INCREMENT * 2 in the
+   third case, and so on.
+
+   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_arithmetic_sequence (struct casereader *subreader,
+                                       double first, double increment)
+{
+  struct arithmetic_sequence *as = xzalloc (sizeof *as);
+  as->first = first;
+  as->increment = increment;
+  return casereader_create_append_numeric (subreader, next_arithmetic,
+                                          as, free);
+}
+