/* -*- c++ -*- */ /* llist.h: Functional (Lisp-style) lists */ /* Copyright (C) 1996, Paul N. Hilfinger. All Rights Reserved. */ #ifndef _LLIST_H_ #define _LLIST_H_ #include "utils.h" #include "debug_memory.h" #if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ <= 8 # define CONS_TEMPLATES_INSIDE #endif /* An llist is essentially an element of a Lisp-style list whose */ /* head (`car' in Lisp terminology) has type T. One always */ /* manipulates llists by pointers; to prevent accidents, the */ /* constructors are private. */ #define generic template generic class llist; generic llist* copylist (const llist* L); generic llist *cons(T const &, llist *); generic llist *cons(T const &); generic class llist { public: /* Constructor */ #ifdef CONS_TEMPLATES_INSIDE /* NOTE: Due to a bug in versions of G++ up to 2.7.2 (at least), */ /* we must put the definition here. */ /* Constructor for llist. */ friend llist* cons(T const& head, llist* tail) { return new llist (head, tail); } /* Same as cons(head, NULL) */ friend llist* cons(T const& head) { return new llist (head, NULL); } #else /* Constructor for llist. */ friend llist* cons(T const& head, llist* tail); /* Same as cons(head, NULL) */ friend llist* cons(T const& head); #endif /* Standard Types */ typedef T value_type; typedef T& reference; typedef T const& const_reference; /* Iterators */ class iterator { public: #if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ == 97 /* work-around for a buggy g++ release on Tru64 */ typedef T value_type; typedef T& reference; typedef T* pointer; typedef T difference_type; typedef void iterator_category; #endif iterator () : p (NULL) {} iterator (llist* p0) : p (p0) {} iterator (void*) : p (NULL) {} bool operator== (const iterator& x) const { return x.p == p; } bool operator!= (const iterator& x) const { return !(*this == x); } iterator& operator++ () { p = p->tail(); return *this; } iterator operator++ (int) { iterator r = p; p = p->tail(); return r; } reference operator* () { return p->front(); } llist* _list_element () const { return p; } private: llist* p; }; class const_iterator { public: const_iterator () : p (NULL) {} const_iterator (const llist* p0) : p (p0) {} const_iterator (void*) : p (NULL) {} const_iterator (const iterator& x) : p(x._list_element ()) {} bool operator== (const const_iterator& x) const { return x.p == p; } bool operator== (const iterator& x) const { return x._list_element() == p; } bool operator!= (const const_iterator& x) const { return !(*this == x); } bool operator!= (const iterator& x) const { return !(*this == x); } const_iterator& operator++ () { p = p->tail(); return *this; } const_iterator operator++ (int) { const_iterator r = p; p = p->tail(); return r; } const_reference operator* () { return p->front(); } private: const llist* p; }; iterator begin () { return this; } const_iterator begin () const { return this; } iterator end () { return iterator(); } const_iterator end () const { return iterator(); } /* Accessors */ /* cons(x,y)->front() yields x. It is assignable when called on a */ /* non-const object. */ reference front () { return head; } const_reference front () const { return head; } /* cons(x,y)->tail() yields y. It is assignable when called on a */ /* non-const object. */ llist*& tail () { return rest; } const llist* tail () const { return rest; } reference last() { return (rest == NULL) ? head : rest->last(); } const_reference last() const { const_reference q = (rest == NULL) ? head : rest->last(); return q; } const_reference operator[](size_t i) const { const llist* p; for (p = this; i != 0; --i, p = p->rest) ; return p->head; } reference operator[](size_t i) { llist* p; for (p = this; i != 0; --i, p = p->rest) ; return p->head; } size_t size () const { const llist* p; size_t n; for (p = this, n = 0; p != NULL; p = p->rest, ++n) ; return n; } llist * copy() { return copylist(this); } /* Other mutation */ /* Swap the fronts and the tails of *this and x. */ void swap (llist& x) { T htmp = head; head = x.head; x.head = htmp; llist* ttmp = rest; rest = x.rest; x.rest = ttmp; } /* Storage management */ /* Release storage for *this, returning the value of tail. */ llist* free () { llist* t = rest; delete this; return t; } /* Remove (and release storage for) the i'th cons cell from a list. i counts from 0. */ llist * excise(int i) { if (i == 0) return free(); else rest = rest->excise(i - 1); return this; } T * to_array() const { T * result = new T [size()]; int j = 0; for (const_iterator i = begin(); i != end(); i++, j++) result[j] = *i; return result; } private: llist (const T& head0, llist* tail0) : head (head0), rest (tail0) {} T head; llist* rest; }; generic void free_all (llist* x) { while (x != NULL) x = x->free (); } generic void free_list_and_delete_elements (llist* x) { while (x != NULL) { delete x->front(); x = x->free(); } } /* Result of appending L0 and L1 non-destructively. */ generic llist* append (llist* L0, llist* L1) { if (L0 == NULL) return L1; else if (L1 == NULL) return L0; else { llist* first = cons (L0->front ()); llist* last; last = first; foreach (p, TYPENAME llist, *(L0->tail ())) { last = last->tail () = cons (*p); } last->tail () = L1; return first; } } generic llist* copylist (const llist* L) { llist* result = NULL; foreach_const (p, TYPENAME llist, *L) result = cons(*p, result); return dreverse(result); } /* Result of appending L0 and L1 destructively. */ generic llist* extend (llist* L0, llist* L1) { if (L0 == NULL) return L1; else if (L1 == NULL) return L0; else { llist* p; for (p = L0; p->tail () != NULL; p = p->tail ()) ; p->tail () = L1; return L0; } } /* Destructively append a single element. */ generic llist* extend (llist* L, T const & x) { return extend(L, cons(x)); } /* Result of reversing L non-destructively */ generic llist* reverse (const llist* L) { llist* result = NULL; if (L == NULL) return NULL; foreach_const (p, TYPENAME llist, *L) result = cons (*p, result); return result; } generic llist* nthcdr (llist* L, size_t k) { while (k > 0) { L = L->tail(); k--; } return L; } /* Result of reversing L destructively */ generic llist* dreverse (llist* L) { llist* p; if (L == NULL) return NULL; p = NULL; while (L->tail () != NULL) { llist* next = L->tail (); L->tail () = p; p = L; L = next; } L->tail () = p; return L; } generic llist< llist * > * map_cons(T const & x, llist< llist * > *l) { llist< llist * > * result = NULL; while (l != NULL) { result = cons(cons(x, l->front()), result); l = l->tail(); } return dreverse(result); } generic llist< llist * > * powerset(llist *l) { if (l == NULL) return cons((llist *) NULL); else { llist< llist * > * result = powerset(l->tail()); return extend(map_cons(l->front(), result), result); } } generic llist* find(T const & x, llist *l) { while (l != NULL) if (l->front() == x) return l; else l = l->tail(); return NULL; } generic bool find(bool f(T const & x), llist *l) { while (l != NULL) if (f(l->front())) return true; else l = l->tail(); return false; } generic bool contains(llist *l, T const & x) { return (find(x, l) != NULL); } generic bool contains_any(llist *l1, llist *l2) { return l2 != NULL && (contains(l1, l2->front()) || contains_any(l1, l2->tail())); } template< class T, class F > llist * filter( F f, llist *l) { llist *result = 0; for ( ; l; l = l->tail()) if (f(l->front())) push(result, l->front()); return result; } template< class T, class F > llist * destructive_filter(F f, llist *l) { llist *orig_l = l; while (orig_l && !f(orig_l->front())) orig_l = orig_l->free(); if (orig_l == NULL) return orig_l; l = orig_l; while (l->tail()) { if (f(l->tail()->front())) l = l->tail(); else l->tail() = l->tail()->free(); } return orig_l; } /* Destructive delete on the first matching element found. Returns -1 if the element was not found. */ generic llist* remove(T const & x, llist* l) { llist *orig_l = l; if (l->front() == x) return l->free(); while (l->tail()) { if (l->tail()->front() == x) { l->tail() = l->tail()->free(); return orig_l; } l = l->tail(); } return (llist*)-1; } #ifndef CONS_TEMPLATES_INSIDE generic llist* cons (T const& head, llist* tail) { return new PASS_RETADR llist(head, tail); } generic llist* cons(T const& head) { return new PASS_RETADR llist (head, NULL); } #endif template< class T, class U > inline llist* push(llist *& list, const U &element) { const T &addend = element; list = cons( addend, list ); return list; } generic T* llist_to_array(llist *list) { return list->to_array(); } /* Hilfinger Standard Iterators */ generic class ListIterator { public: ListIterator () {} ListIterator (llist* L) : p (L) {} bool isDone () const { return p == NULL; } void next () { p = p->tail (); } T& operator* () const { return p->front(); } T* operator-> () const { return &p->front(); } private: llist* p; }; generic ListIterator elements (llist* L) { return L; } #undef generic #endif