bug-recutils
[Top][All Lists]
Advanced

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

[bug-recutils] [PATCH 01/13] src,torture: imple ment abstract record ite


From: Michał Masłowski
Subject: [bug-recutils] [PATCH 01/13] src,torture: imple ment abstract record iterators.
Date: Mon, 20 Aug 2012 18:21:22 +0200

The query planner will provide an iterator of a superset of records to
be returned by the query.  Simpler solutions would use a different API
for iterating msets (from the database) or records found in an index
search.
---
 ChangeLog                          |  14 ++++
 src/Makefile.am                    |   3 +-
 src/rec-iter.c                     | 140 +++++++++++++++++++++++++++++++++++++
 src/rec.h                          |  43 ++++++++++++
 torture/Makefile.am                |   6 +-
 torture/rec-iter/rec-iter-mset.c   |  87 +++++++++++++++++++++++
 torture/rec-iter/tsuite-rec-iter.c |  42 +++++++++++
 torture/runtests.c                 |   2 +
 8 files changed, 335 insertions(+), 2 deletions(-)
 create mode 100644 src/rec-iter.c
 create mode 100644 torture/rec-iter/rec-iter-mset.c
 create mode 100644 torture/rec-iter/tsuite-rec-iter.c

diff --git a/ChangeLog b/ChangeLog
index 019829e..8946498 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2012-07-18  Michał Masłowski  <address@hidden>
+
+       src,torture: implement abstract record iterators.
+       * src/Makefile.am (librec_la_SOURCES): Add rec-iter.c
+       * src/rec-iter.c: New file.
+       * src/rec.h: Add prototypes and documentation for record
+       iterators.
+
+       * torture/Makefile.am (REC_ITER_TSUITE): New variable.
+       (runtests_SOURCES): Add $(REC_ITER_TSUITE).
+       * torture/rec-iter/rec-iter-mset.c: New file.
+       * torture/rec-iter/tsuite-rec-iter.c: Likewise.
+       * torture/runtests.c (main): Add the tsuite_rec_iter test suite.
+
 2012-07-11  Michał Masłowski  <address@hidden>
 
        doc: mention index files and their building.
diff --git a/src/Makefile.am b/src/Makefile.am
index 26dedd1..9a30fa1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,7 +44,8 @@ librec_la_SOURCES = rec.c \
                     rec-types.c \
                     rec-buf.c \
                     rec-aggregate.c \
-                    rec-idx-file.c
+                    rec-idx-file.c \
+                    rec-iter.c
 
 if CRYPT
    librec_la_SOURCES += rec-crypt.c
diff --git a/src/rec-iter.c b/src/rec-iter.c
new file mode 100644
index 0000000..3088d27
--- /dev/null
+++ b/src/rec-iter.c
@@ -0,0 +1,140 @@
+/* -*- mode: C -*-
+ *
+ *       File:         rec-iter.c
+ *       Date:         Wed Jul 18 14:35:05 2012
+ *
+ *       GNU recutils - Record iterators.
+ *
+ */
+
+/* Copyright (C) 2012 Michał Masłowski */
+
+/* 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rec.h>
+
+/*
+ * Data structures.
+ */
+
+/* An iterator. */
+struct rec_iter_s
+{
+  void *data;
+  rec_iter_next_fn_t next;
+  rec_iter_dispose_fn_t dispose;
+};
+
+/* Static functions defined in this file.  */
+
+static bool rec_iter_next_mset (void *data, rec_record_t *record);
+static void rec_iter_dispose_mset (void *data);
+
+/*
+ * Public functions.
+ */
+
+rec_iter_t
+rec_iter_new (void *data,
+              rec_iter_next_fn_t next,
+              rec_iter_dispose_fn_t dispose)
+{
+  rec_iter_t res;
+
+  res = malloc (sizeof (struct rec_iter_s));
+  if (!res)
+    {
+      return NULL;
+    }
+
+  res->data = data;
+  res->next = next;
+  res->dispose = dispose;
+
+  return res;
+}
+
+rec_iter_t
+rec_iter_for_mset (rec_mset_t mset)
+{
+  rec_mset_iterator_t iterator;
+  rec_mset_iterator_t *iter;
+  rec_iter_t res;
+
+  /* More complex due to mset iterators being passed by value.  */
+  iter = malloc (sizeof (rec_mset_iterator_t));
+  if (!iter)
+    {
+      return NULL;
+    }
+
+  iterator = rec_mset_iterator (mset);
+  memcpy (iter, &iterator, sizeof (rec_mset_iterator_t));
+
+  res = rec_iter_new (iter, rec_iter_next_mset, rec_iter_dispose_mset);
+  if (!res)
+    {
+      rec_iter_dispose_mset (iter);
+    }
+  return res;
+}
+
+bool
+rec_iter_next (rec_iter_t iterator, rec_record_t *record)
+{
+  if (iterator->next)
+    {
+      return iterator->next (iterator->data, record);
+    }
+  return false;
+}
+
+void
+rec_iter_destroy (rec_iter_t iterator)
+{
+  if (iterator->dispose)
+    {
+      iterator->dispose (iterator->data);
+    }
+
+  free (iterator);
+}
+
+/*
+ * Private functions.
+ */
+
+static bool
+rec_iter_next_mset (void *data, rec_record_t *record)
+{
+  return rec_mset_iterator_next ((rec_mset_iterator_t *) data,
+                                 MSET_RECORD, (const void **) record, NULL);
+}
+
+static void
+rec_iter_dispose_mset (void *data)
+{
+  /* Other implementations would also free the record, this doesn't
+     since it doesn't copy it.  */
+  rec_mset_iterator_free ((rec_mset_iterator_t *) data);
+  free (data);
+}
+
+/* End of rec-iter.c */
diff --git a/src/rec.h b/src/rec.h
index dd652ec..3ee12e2 100644
--- a/src/rec.h
+++ b/src/rec.h
@@ -2399,6 +2399,49 @@ bool rec_idx_get_time_size (FILE *recfile, int64_t 
*time, size_t *size);
 
 char *rec_idx_get_file_name (const char *recfile_name);
 
+/*
+ * RECORD ITERATORS
+ *
+ * The following datatype and routines provide abstract record
+ * iterators that can be used to access records from an mset or an
+ * index search.
+ */
+
+/* Opaque data type representing a record iterator.  */
+
+typedef struct rec_iter_s *rec_iter_t;
+
+/* Types of arguments for rec_iter_new. */
+
+typedef bool (*rec_iter_next_fn_t) (void *data, rec_record_t *record);
+typedef void (*rec_iter_dispose_fn_t) (void *data);
+
+/* Create and return an iterator using a custom rec_iter_next
+   implementation.  DATA is passed to NEXT and DISPOSE as first
+   argument.  NEXT implements rec_iter_next.  DISPOSE is called when
+   freeing the iterator.  Passing NULL as one of the function pointers
+   makes it a no-op, in case of NEXT not iterating any records.  */
+
+rec_iter_t rec_iter_new (void *data, rec_iter_next_fn_t next, 
rec_iter_dispose_fn_t dispose);
+
+/* Create and return an iterator traversing records in an mset.  The
+   mset contents must not be modified while the iterator is in
+   use.  */
+
+rec_iter_t rec_iter_for_mset (rec_mset_t mset);
+
+/* Advance the iterator to the next record which is stored in *RECORD.
+   The function returns true if there is a next element to which
+   iterate to, and false otherwise.  If a new record is allocated, it
+   will be deallocated by the next call to rec_iter_next or
+   rec_iter_destroy.  */
+
+bool rec_iter_next (rec_iter_t iterator, rec_record_t *record);
+
+/* Destroy an iterator and free resources it uses.  */
+
+void rec_iter_destroy (rec_iter_t iterator);
+
 #endif /* !GNU_REC_H */
 
 /* End of rec.h */
diff --git a/torture/Makefile.am b/torture/Makefile.am
index 87a84f8..6b3fa3e 100644
--- a/torture/Makefile.am
+++ b/torture/Makefile.am
@@ -144,6 +144,9 @@ REC_IDX_FILE_TSUITE = rec-idx-file/rec-idx-file-new-mem.c \
                       rec-idx-file/rec-idx-get-file-name.c \
                       rec-idx-file/tsuite-rec-idx-file.c
 
+REC_ITER_TSUITE = rec-iter/rec-iter-mset.c \
+                  rec-iter/tsuite-rec-iter.c
+
 runtests_SOURCES = runtests.c \
                    $(REC_MSET_TSUITE) \
                    $(REC_COMMENT_TSUITE) \
@@ -156,7 +159,8 @@ runtests_SOURCES = runtests.c \
                    $(REC_PARSER_TSUITE) \
                    $(REC_WRITER_TSUITE) \
                    $(REC_SEX_TSUITE) \
-                   $(REC_IDX_FILE_TSUITE)
+                   $(REC_IDX_FILE_TSUITE) \
+                   $(REC_ITER_TSUITE)
 
 AM_CPPFLAGS = -I$(top_srcdir)/src \
               -I$(top_srcdir)/torture
diff --git a/torture/rec-iter/rec-iter-mset.c b/torture/rec-iter/rec-iter-mset.c
new file mode 100644
index 0000000..d2c2f56
--- /dev/null
+++ b/torture/rec-iter/rec-iter-mset.c
@@ -0,0 +1,87 @@
+/* -*- mode: C -*-
+ *
+ *       File:         rec-iter-mset.c
+ *       Date:         Wed Jul 18 16:48:38 2012
+ *
+ *       GNU recutils - rec_iter unit tests using mset iterators.
+ *
+ */
+
+/* Copyright (C) 2012 Michał Masłowski */
+
+/* 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <check.h>
+
+#include <rec.h>
+
+/*-
+ * Test: rec_iter_mset_nominal
+ * Unit: rec_ter
+ * Description:
+ * + Check that an iterator for an mset can be used.
+ */
+START_TEST(rec_iter_mset_nominal)
+{
+  const char string[] = "id: foo\n\nid: bar\n\nid: baz\n\n";
+  rec_parser_t parser;
+  rec_rset_t rset;
+  rec_iter_t iter;
+  rec_record_t record;
+
+  /* Make an rset. */
+  parser = rec_parser_new_str (string, "dummy");
+  fail_if (!parser);
+  fail_if (!rec_parse_rset (parser, &rset));
+  rec_parser_destroy (parser);
+
+  /* Make an iterator. */
+  iter = rec_iter_for_mset (rec_rset_mset (rset));
+  fail_if (!iter);
+
+  /* Check that records with correct ids are returned. */
+  fail_if (!rec_iter_next (iter, &record));
+  fail_if (!rec_record_contains_field (record, "id", "foo"));
+  fail_if (!rec_iter_next (iter, &record));
+  fail_if (!rec_record_contains_field (record, "id", "bar"));
+  fail_if (!rec_iter_next (iter, &record));
+  fail_if (!rec_record_contains_field (record, "id", "baz"));
+
+  /* Check that no more records are iterated. */
+  fail_if (rec_iter_next (iter, &record));
+
+  rec_iter_destroy (iter);
+  rec_rset_destroy (rset);
+}
+END_TEST
+
+/*
+ * Test creation function
+ */
+TCase *
+test_rec_iter_mset (void)
+{
+  TCase *tc = tcase_create ("rec_iter_mset");
+  tcase_add_test (tc, rec_iter_mset_nominal);
+
+  return tc;
+}
+
+/* End of rec-iter-mset.c */
diff --git a/torture/rec-iter/tsuite-rec-iter.c 
b/torture/rec-iter/tsuite-rec-iter.c
new file mode 100644
index 0000000..09a1fb7
--- /dev/null
+++ b/torture/rec-iter/tsuite-rec-iter.c
@@ -0,0 +1,42 @@
+/* -*- mode: C -*-
+ *
+ *       File:         tsuite-rec-iter.c
+ *       Date:         Wed Jul 18 16:47:19 2012
+ *
+ *       GNU recutils - rec_iter test suite
+ *
+ */
+
+/* Copyright (C) 2012 Michał Masłowski */
+
+/* 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <check.h>
+
+extern TCase *test_rec_iter_mset (void);
+
+Suite *
+tsuite_rec_iter ()
+{
+  Suite *s;
+
+  s = suite_create ("rec-iter");
+  suite_add_tcase (s, test_rec_iter_mset ());
+
+  return s;
+}
+
+/* End of tsuite-rec-iter.c */
diff --git a/torture/runtests.c b/torture/runtests.c
index de97979..35c81b1 100644
--- a/torture/runtests.c
+++ b/torture/runtests.c
@@ -40,6 +40,7 @@ extern Suite *tsuite_rec_parser (void);
 extern Suite *tsuite_rec_writer (void);
 extern Suite *tsuite_rec_sex (void);
 extern Suite *tsuite_rec_idx_file (void);
+extern Suite *tsuite_rec_iter (void);
 
 int
 main (int argc, char **argv)
@@ -61,6 +62,7 @@ main (int argc, char **argv)
   srunner_add_suite (sr, tsuite_rec_writer ());
   srunner_add_suite (sr, tsuite_rec_sex ());
   srunner_add_suite (sr, tsuite_rec_idx_file ());
+  srunner_add_suite (sr, tsuite_rec_iter ());
 
   srunner_set_log (sr, "tests.log");
 
-- 
1.7.11.4




reply via email to

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