Add linked list library to PSPP.
[pspp-builds.git] / src / libpspp / llx.h
diff --git a/src/libpspp/llx.h b/src/libpspp/llx.h
new file mode 100644 (file)
index 0000000..7523636
--- /dev/null
@@ -0,0 +1,312 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+/* Circular doubly linked lists.
+
+   This header (llx.h) supplies "external" circular doubly linked
+   lists.  Its companion header (ll.h) supplies "embedded"
+   circular doubly linked lists.  The two variants are described
+   briefly here.  The external variant, for which this is the
+   header, is described in slightly more detail below.  Each
+   function also has a detailed usage comment at its point of
+   definition.
+
+   The "ll" embedded linked list implementation puts the linked
+   list node within the data structure that the list contains.
+   This makes allocation efficient, in space and time.  It also
+   makes it easy to find the list node associated with a given
+   object.  However, it's difficult to include a given object in
+   an arbitrary number of lists, or to include a single object in
+   a single list in multiple positions.
+
+   The "llx" external linked list implementation allocates linked
+   list nodes separately from the objects in the list.  Adding
+   and removing linked list nodes requires dynamic allocation, so
+   it is normally slower and takes more memory than the embedded
+   implementation.  It also requires searching the list to find
+   the list node associated with a given object.  However, it's
+   easy to include a given object in an arbitrary number of
+   lists, or to include a single object more than once within a
+   single list.  It's also possible to create an external linked
+   list without adding a member to the data structure that the
+   list contains. */
+
+#ifndef LLX_H
+#define LLX_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <libpspp/ll.h>
+
+/* External, circular doubly linked list.
+
+   Each list contains a single "null" element that separates the
+   head and the tail of the list.  The null element is both
+   before the head and after the tail of the list.  An empty list
+   contains just the null element.
+
+   An external linked list is represented as `struct llx_list'.
+   Each node in the list consists of a `struct llx' that contains
+   a `void *' pointer to the node's data.  Use the llx_data()
+   function to extract the data pointer from a node.
+
+   Many list functions take ranges of nodes as arguments.  Ranges
+   are "half-open"; that is, R0...R1 includes R0 but not R1.  A
+   range whose endpoints are the same (e.g. R0...R0) contains no
+   nodes at all.
+
+   Consider the following declarations:
+
+     struct llx_list list;
+
+     struct foo
+       {
+         int x;                   // Data member.
+       };
+
+   Here's an example of iteration from head to tail:
+
+     struct llx *llx;
+     for (llx = llx_head (&list); llx != llx_null (&list); 
+          llx = llx_next (llx))
+       {
+         struct foo *foo = llx_data (llx);
+         ...do something with foo->x...
+       }
+
+   Here's another way to do it:
+
+     struct llx *llx = llx_null (&list);
+     while ((llx = llx_next (llx)) != llx_null (&list))
+       {
+         struct foo *foo = llx_data (llx);
+         ...do something with foo->x...
+       }
+*/
+
+/* External linked list node. */
+struct llx
+  {
+    struct ll ll;               /* Node. */
+    void *data;                 /* Member data. */
+  };
+
+/* Linked list. */
+struct llx_list
+  {
+    struct ll_list ll_list;     /* The list. */
+  };
+
+/* Memory manager. */
+struct llx_manager 
+  {
+    /* Allocates and returns memory for a new struct llx.
+       If space is unavailable, returns a null pointer. */
+    struct llx *(*allocate) (void *aux);
+
+    /* Releases a previously allocated struct llx. */
+    void (*release) (struct llx *, void *aux);
+
+    /* Auxiliary data passed to allocate and release
+       functions. */
+    void *aux;
+  };
+
+/* Manager that uses the standard malloc and free routines. */
+extern const struct llx_manager llx_malloc_mgr;
+
+/* Returns negative if A < B, zero if A == B, positive if A > B. */
+typedef int llx_compare_func (const void *a, const void *b, void *aux);
+
+/* Returns true or false depending on properties of DATA. */
+typedef bool llx_predicate_func (const void *data, void *aux);
+
+/* Takes some action on DATA. */
+typedef void llx_action_func (void *data, void *aux);
+
+/* Basics. */
+static inline void llx_init (struct llx_list *);
+void llx_destroy (struct llx_list *, llx_action_func *destructor, void *aux,
+                  const struct llx_manager *manager);
+static inline bool llx_is_empty (const struct llx_list *);
+size_t llx_count (const struct llx_list *);
+
+/* Iteration. */
+static inline struct llx *llx_head (const struct llx_list *);
+static inline struct llx *llx_tail (const struct llx_list *);
+static inline struct llx *llx_null (const struct llx_list *);
+static inline struct llx *llx_next (const struct llx *);
+static inline struct llx *llx_prev (const struct llx *);
+static inline void *llx_data (const struct llx *);
+
+/* Stack- and queue-like behavior. */
+struct llx *llx_push_head (struct llx_list *, void *,
+                           const struct llx_manager *);
+struct llx *llx_push_tail (struct llx_list *, void *,
+                           const struct llx_manager *);
+void *llx_pop_head (struct llx_list *, const struct llx_manager *);
+void *llx_pop_tail (struct llx_list *, const struct llx_manager *);
+
+/* Insertion. */
+struct llx *llx_insert (struct llx *before, void *,
+                        const struct llx_manager *);
+void llx_splice (struct llx *before, struct llx *r0, struct llx *r1);
+void llx_swap (struct llx *a, struct llx *b);
+void llx_swap_range (struct llx *a0, struct llx *a1,
+                     struct llx *b0, struct llx *b1);
+
+/* Removal. */
+struct llx *llx_remove (struct llx *, const struct llx_manager *);
+void llx_remove_range (struct llx *r0, struct llx *r1,
+                       const struct llx_manager *);
+size_t llx_remove_equal (struct llx *r0, struct llx *r1, const void *target,
+                         llx_compare_func *, void *aux,
+                         const struct llx_manager *);
+size_t llx_remove_if (struct llx *r0, struct llx *r1,
+                      llx_predicate_func *, void *aux,
+                      const struct llx_manager *);
+
+/* Non-mutating algorithms. */
+struct llx *llx_find_equal (const struct llx *r0, const struct llx *r1,
+                            const void *target,
+                            llx_compare_func *, void *aux);
+struct llx *llx_find_if (const struct llx *r0, const struct llx *r1,
+                         llx_predicate_func *, void *aux);
+struct llx *llx_find_adjacent_equal (const struct llx *r0,
+                                     const struct llx *r1,
+                                     llx_compare_func *, void *aux);
+size_t llx_count_range (const struct llx *r0, const struct llx *r1);
+size_t llx_count_equal (const struct llx *r0, const struct llx *r1,
+                        const void *target,
+                        llx_compare_func *, void *aux);
+size_t llx_count_if (const struct llx *r0, const struct llx *r1,
+                     llx_predicate_func *, void *aux);
+struct llx *llx_max (const struct llx *r0, const struct llx *r1,
+                     llx_compare_func *, void *aux);
+struct llx *llx_min (const struct llx *r0, const struct llx *r1,
+                     llx_compare_func *, void *aux);
+int llx_lexicographical_compare_3way (const struct llx *a0,
+                                      const struct llx *a1, 
+                                      const struct llx *b0,
+                                      const struct llx *b1, 
+                                      llx_compare_func *, void *aux);
+
+/* Mutating algorithms. */
+void llx_apply (struct llx *r0, struct llx *r1, llx_action_func *, void *aux);
+void llx_reverse (struct llx *r0, struct llx *r1);
+bool llx_next_permutation (struct llx *r0, struct llx *r1,
+                           llx_compare_func *, void *aux);
+bool llx_prev_permutation (struct llx *r0, struct llx *r1,
+                           llx_compare_func *, void *aux);
+
+/* Sorted list functions. */
+void llx_sort (struct llx *r0, struct llx *r1, llx_compare_func *, void *aux);
+struct llx *llx_find_run (const struct llx *r0, const struct llx *r1,
+                          llx_compare_func *, void *aux);
+bool llx_is_sorted (const struct llx *r0, const struct llx *r1,
+                    llx_compare_func *, void *aux);
+struct llx *llx_merge (struct llx *a0, struct llx *a1,
+                       struct llx *b0, struct llx *b1,
+                       llx_compare_func *, void *aux);
+size_t llx_unique (struct llx *r0, struct llx *r1, struct llx *dups,
+                   llx_compare_func *, void *aux,
+                   const struct llx_manager *);
+void llx_sort_unique (struct llx *r0, struct llx *r1, struct llx *dups,
+                      llx_compare_func *, void *aux,
+                      const struct llx_manager *);
+struct llx *llx_insert_ordered (struct llx *r0, struct llx *r1, void *data,
+                                llx_compare_func *, void *aux,
+                                const struct llx_manager *);
+struct llx *llx_partition (struct llx *r0, struct llx *r1,
+                           llx_predicate_func *, void *aux);
+struct llx *llx_find_partition (const struct llx *r0, const struct llx *r1,
+                                llx_predicate_func *, void *aux);
+
+/* Returns the llx within which LL is embedded. */
+static struct llx *
+llx_from_ll (struct ll *ll) 
+{
+  return ll_data (ll, struct llx, ll);
+}
+
+/* Initializes LIST as an empty list. */
+static inline void
+llx_init (struct llx_list *list) 
+{
+  ll_init (&list->ll_list);
+}
+
+/* Returns true if LIST is empty (contains just the null node),
+   false if LIST is not empty (has at least one other node).
+   Executes in O(1) time. */
+static inline bool
+llx_is_empty (const struct llx_list *list) 
+{
+  return ll_is_empty (&list->ll_list);
+}
+
+/* Returns the first node in LIST,
+   or the null node if LIST is empty. */
+static inline struct llx *
+llx_head (const struct llx_list *list) 
+{
+  return llx_from_ll (ll_head (&list->ll_list));
+}
+
+/* Returns the last node in LIST,
+   or the null node if LIST is empty. */
+static inline struct llx *
+llx_tail (const struct llx_list *list) 
+{
+  return llx_from_ll (ll_tail (&list->ll_list));
+}
+
+/* Returns LIST's null node. */
+static inline struct llx *
+llx_null (const struct llx_list *list) 
+{
+  return llx_from_ll (ll_null (&list->ll_list));
+}
+
+/* Returns the node following LLX in its list,
+   or the null node if LLX is at the end of its list.
+   (In an empty list, the null node follows itself.) */
+static inline struct llx *
+llx_next (const struct llx *llx) 
+{
+  return llx_from_ll (ll_next (&llx->ll));
+}
+
+/* Returns the node preceding LLX in its list,
+   or the null node if LLX is the first node in its list.
+   (In an empty list, the null node precedes itself.) */
+static inline struct llx *
+llx_prev (const struct llx *llx)
+{
+  return llx_from_ll (ll_prev (&llx->ll));
+}
+
+/* Returns the data in node LLX. */
+static inline void *
+llx_data (const struct llx *llx) 
+{
+  return llx->data;
+}
+
+#endif /* llx.h */